├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── android ├── android.iml ├── app │ ├── .DS_Store │ ├── app.iml │ ├── build.gradle │ ├── key.keystore │ ├── release │ │ ├── .DS_Store │ │ └── output.json │ └── src │ │ ├── .DS_Store │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── .DS_Store │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ ├── com │ │ │ │ └── example │ │ │ │ │ └── ncov_2019 │ │ │ │ │ └── MainActivity.java │ │ │ └── io │ │ │ │ └── flutter │ │ │ │ └── plugins │ │ │ │ └── GeneratedPluginRegistrant.java │ │ └── res │ │ │ ├── .DS_Store │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── .DS_Store │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ ├── .DS_Store │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── .DS_Store │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── .DS_Store │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── .DS_Store │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ └── styles.xml │ │ │ └── xml │ │ │ └── network_security_config.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── ncov_2019_android.iml ├── settings.gradle └── settings_aar.gradle ├── assets ├── .DS_Store ├── git │ ├── download.png │ ├── home.png │ ├── left_group.png │ ├── lore.png │ ├── protect1.png │ ├── protect2.png │ ├── protect3.png │ ├── rumor1.png │ ├── rumor2.png │ └── rumor3.png └── images │ ├── a.jpg │ ├── bottom_home.png │ ├── bottom_lore.png │ ├── bottom_protect.png │ ├── bottom_rumor.png │ ├── entries_1.png │ ├── entries_2.png │ ├── entries_3.png │ ├── entries_4.png │ └── entries_5.png ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Flutter.framework │ │ ├── Flutter │ │ ├── Headers │ │ │ ├── Flutter.h │ │ │ ├── FlutterAppDelegate.h │ │ │ ├── FlutterBinaryMessenger.h │ │ │ ├── FlutterCallbackCache.h │ │ │ ├── FlutterChannels.h │ │ │ ├── FlutterCodecs.h │ │ │ ├── FlutterDartProject.h │ │ │ ├── FlutterEngine.h │ │ │ ├── FlutterHeadlessDartRunner.h │ │ │ ├── FlutterMacros.h │ │ │ ├── FlutterPlatformViews.h │ │ │ ├── FlutterPlugin.h │ │ │ ├── FlutterPluginAppLifeCycleDelegate.h │ │ │ ├── FlutterTexture.h │ │ │ └── FlutterViewController.h │ │ ├── Info.plist │ │ ├── Modules │ │ │ └── module.modulemap │ │ ├── _CodeSignature │ │ │ └── CodeResources │ │ └── icudtl.dat │ ├── Flutter.podspec │ ├── Generated.xcconfig │ ├── Release.xcconfig │ └── flutter_export_environment.sh ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata ├── Runner │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── GeneratedPluginRegistrant.h │ ├── GeneratedPluginRegistrant.m │ ├── Info.plist │ └── main.m └── ServiceDefinitions.json ├── lib ├── api │ ├── area_model.dart │ ├── area_view_model.dart │ ├── entries_model.dart │ ├── entries_view_model.dart │ ├── lore_model.dart │ ├── lore_view_model.dart │ ├── news_model.dart │ ├── news_view_model.dart │ ├── protect_model.dart │ ├── protect_view_model.dart │ ├── rumor_model.dart │ ├── rumor_view_model.dart │ ├── statistics_model.dart │ ├── statistics_view_model.dart │ ├── version_model.dart │ └── version_view_model.dart ├── app.dart ├── commom │ ├── check.dart │ ├── commom.dart │ ├── data │ │ ├── data.dart │ │ ├── notice.dart │ │ └── store.dart │ ├── date.dart │ ├── file_util.dart │ ├── shared_util.dart │ ├── ui.dart │ └── win_media.dart ├── config │ ├── api.dart │ ├── config.dart │ ├── const.dart │ ├── keys.dart │ └── storage_manager.dart ├── http │ ├── req_model.dart │ └── view_model.dart ├── main.dart ├── pages │ ├── home │ │ └── home_page.dart │ ├── lore │ │ └── lore_page.dart │ ├── protect │ │ └── protect_page.dart │ ├── root │ │ └── root_page.dart │ └── rumor │ │ └── rumor_page.dart └── widget │ ├── bar │ └── commom_bar.dart │ ├── card │ ├── lore_card.dart │ ├── news_card.dart │ ├── protect_card.dart │ └── rumor_card.dart │ ├── dialog │ └── update_dialog.dart │ ├── flutter │ ├── my_expansion_tile.dart │ └── my_list_tile.dart │ ├── item │ ├── entries.dart │ └── statics.dart │ ├── orther │ └── turn_box.dart │ ├── root_tabbar.dart │ ├── scroll │ └── my_behavior.dart │ └── view │ ├── loading_view.dart │ ├── pull.dart │ ├── title_view.dart │ └── web_view_page.dart └── pubspec.yaml /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.lock 4 | *.log 5 | *.pyc 6 | *.swp 7 | .DS_Store 8 | .atom/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # Visual Studio Code related 20 | .classpath 21 | .project 22 | .settings/ 23 | .vscode/ 24 | 25 | # Flutter repo-specific 26 | /bin/cache/ 27 | /bin/mingit/ 28 | /dev/benchmarks/mega_gallery/ 29 | /dev/bots/.recipe_deps 30 | /dev/bots/android_tools/ 31 | /dev/docs/doc/ 32 | /dev/docs/flutter.docs.zip 33 | /dev/docs/lib/ 34 | /dev/docs/pubspec.yaml 35 | /dev/integration_tests/**/xcuserdata 36 | /dev/integration_tests/**/Pods 37 | /packages/flutter/coverage/ 38 | version 39 | 40 | # packages file containing multi-root paths 41 | .packages.generated 42 | 43 | # Flutter/Dart/Pub related 44 | **/doc/api/ 45 | .dart_tool/ 46 | .flutter-plugins 47 | .flutter-plugins-dependencies 48 | .packages 49 | .pub-cache/ 50 | .pub/ 51 | build/ 52 | flutter_*.png 53 | linked_*.ds 54 | unlinked.ds 55 | unlinked_spec.ds 56 | 57 | # Android related 58 | **/android/**/gradle-wrapper.jar 59 | **/android/.gradle 60 | **/android/captures/ 61 | **/android/local.properties 62 | **/android/**/GeneratedPluginRegistrant.java 63 | **/android/key.properties 64 | *.jks 65 | 66 | # iOS/XCode related 67 | **/ios/**/*.mode1v3 68 | **/ios/**/*.mode2v3 69 | **/ios/**/*.moved-aside 70 | **/ios/**/*.pbxuser 71 | **/ios/**/*.perspectivev3 72 | **/ios/**/*sync/ 73 | **/ios/**/.sconsign.dblite 74 | **/ios/**/.tags* 75 | **/ios/**/.vagrant/ 76 | **/ios/**/DerivedData/ 77 | **/ios/**/Icon? 78 | **/ios/**/Pods/ 79 | **/ios/**/.symlinks/ 80 | **/ios/**/profile 81 | **/ios/**/xcuserdata 82 | **/ios/.generated/ 83 | **/ios/Flutter/App.framework 84 | **/ios/Flutter/Flutter.framework 85 | **/ios/Flutter/Flutter.podspec 86 | **/ios/Flutter/Generated.xcconfig 87 | **/ios/Flutter/app.flx 88 | **/ios/Flutter/app.zip 89 | **/ios/Flutter/flutter_assets/ 90 | **/ios/Flutter/flutter_export_environment.sh 91 | **/ios/ServiceDefinitions.json 92 | **/ios/Runner/GeneratedPluginRegistrant.* 93 | 94 | # macOS 95 | **/macos/Flutter/GeneratedPluginRegistrant.swift 96 | **/macos/Flutter/Flutter-Debug.xcconfig 97 | **/macos/Flutter/Flutter-Release.xcconfig 98 | **/macos/Flutter/Flutter-Profile.xcconfig 99 | 100 | # Coverage 101 | coverage/ 102 | 103 | # Symbols 104 | app.*.symbols 105 | 106 | # Exceptions to above rules. 107 | !**/ios/**/default.mode1v3 108 | !**/ios/**/default.mode2v3 109 | !**/ios/**/default.pbxuser 110 | !**/ios/**/default.perspectivev3 111 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 112 | !/dev/ci/**/Gemfile.lock 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHub stars](https://img.shields.io/github/stars/fluttercandies/ncov_2019)](https://github.com/fluttercandies/ncov_2019/stargazers) 2 | [![GitHub forks](https://img.shields.io/github/forks/fluttercandies/ncov_2019)](https://github.com/fluttercandies/ncov_2019/network) 3 | [![GitHub issues](https://img.shields.io/github/issues/fluttercandies/ncov_2019)](https://github.com/fluttercandies/ncov_2019/issues) 4 | 5 | > 如果产生其他依赖无法编译的问题,可以尝试将`pubspec.yaml`中的`dependencies`中的所有依赖的"^"去掉,重新编译尝试。 6 | 7 | # nCoV_2019 8 | 9 | 获取新肺炎实时动态App,支持Android和IOS。 10 | 11 | # Log 12 | * 2020.09.03 - 适配Flutter 1.20 13 | 14 | * 2020.07.04 - 适配Flutter 1.17 15 | 16 | * 2020.02.16 - 修复统计图不能展示问题。(16:45) 17 | 18 | * 2020.02.16 - 辟谣卡片标题最大行数调整为2行,统计数据布局优化。(16:32) 19 | 20 | * 2020.02.16 - 完美适配Flutter1.12.13和Androidx(13:21) 21 | 22 | * 2020.02.06 - 修复了统计信息出错和诊疗无图标和对齐问题。 23 | 24 | * 2020.02.02 - 修复了统计的分隔符导致统计数据无法正常显示。 25 | 26 | # 项目相关文章 27 | 28 | * [Flutter Candies又添一成员,为抗击疫情贡献一份技术力量](https://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650829796&idx=1&sn=7811875471dcabd0cfec788adc27306a&chksm=80b7a77ab7c02e6cfc9726c61be31cbd616c5593d0b9388776f15fd255ccc619be7df38341b3&mpshare=1&scene=23&srcid&sharer_sharetime=1582430519570&sharer_shareid=bdfd1967c1c7dae7e61a030ea5b2b235%23rd) 29 | 30 | 31 | # App体验 32 | ##### Android 下载地址: 33 | [http://www.flutterj.com/nCoV-2019.apk](http://www.flutterj.com/nCoV-2019.apk) 34 | 35 | ##### Android(二维码下载): 36 | 37 | ![download.png](assets/git/download.png) 38 | 39 | IOS: 40 | 41 | 拉下代码直接跑即可 42 | 43 | # App效果图 44 | |![home.png](assets/git/home.png)| ![rumor1.png](assets/git/rumor1.png) | ![rumor2.png](assets/git/rumor2.png) | ![rumor3.png](assets/git/rumor3.png) | 45 | | --- | --- | --- | --- | 46 | |![protect1.png](assets/git/protect1.png)| ![protect2.png](assets/git/protect2.png) | ![protect3.png](assets/git/protect3.png) | ![lore.png](assets/git/lore.png) | 47 | 48 | # 使用须知 49 | * cached_network_image 50 | 51 | 在`pubspec.yaml`文件中,关于flutter版本使用`cached_network_image`插件问题,默认使用2.0.0, 52 | 因为你们刚安装上flutter为最新版本flutter。 53 | ```yaml 54 | # cached_network_image: 1.1.1 # 1.9.0左右flutter版本的用这个 55 | cached_network_image: 2.0.0 # 2.0.0左右flutter版本直接用这个 56 | ``` 57 | 58 | # 使用教程 59 | 60 | * 使用命令(拉取项目):$ git clone https://github.com/fluttercandies/ncov_2019.git 61 | * 然后命令(获取依赖):$ flutter packages get (IOS执行IOS部分再执行下一步) 62 | * 最后命令(运行):$ flutter run 63 | 64 | IOS 65 | * 进入项目IOS目录:$ cd ios/ 66 | * 更新Pod(非必须):$ pod update 67 | * 安装Pod:$ pod install 68 | 69 | # 我的Flutter环境 70 | ``` 71 | q1deMacBook-Pro:ncov_2019 q1$ flutter doctor -v 72 | [✓] Flutter (Channel stable, 1.20.2, on Mac OS X 10.14.5 18F2059, locale zh-Hans-CN) 73 | • Flutter version 1.20.2 at /Users/q1/flutter 74 | • Framework revision bbfbf1770c (3 weeks ago), 2020-08-13 08:33:09 -0700 75 | • Engine revision 9d5b21729f 76 | • Dart version 2.9.1 77 | • Pub download mirror https://pub.flutter-io.cn 78 | • Flutter download mirror https://storage.flutter-io.cn 79 | 80 | 81 | [✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3) 82 | • Android SDK at /Users/q1/Library/Android/sdk 83 | • Platform android-29, build-tools 29.0.3 84 | • ANDROID_HOME = /Users/q1/Library/Android/sdk 85 | • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java 86 | • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) 87 | • All Android licenses accepted. 88 | 89 | [✓] Xcode - develop for iOS and macOS (Xcode 11.3) 90 | • Xcode at /Applications/Xcode.app/Contents/Developer 91 | • Xcode 11.3, Build version 11C29 92 | • CocoaPods version 1.8.4 93 | 94 | [✓] Android Studio (version 4.0) 95 | • Android Studio at /Applications/Android Studio.app/Contents 96 | • Flutter plugin version 48.1.2 97 | • Dart plugin version 193.7361 98 | • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) 99 | 100 | [✓] VS Code (version 1.47.3) 101 | • VS Code at /Applications/Visual Studio Code.app/Contents 102 | • Flutter extension version 3.12.2 103 | 104 | [✓] Connected device (1 available) 105 | • sdk gphone x86 arm (mobile) • emulator-5554 • android-x86 • Android 11 (API 30) (emulator) 106 | 107 | • No issues found! 108 | ``` 109 | 110 | # 意见反馈 111 | 如果大家有好的意见或者有好的设计图的话可以群内找我。 112 | 113 | Flutter交流QQ群:[874592746](https://jq.qq.com/?_wv=1027&k=5coTYqE) 114 | 115 | Flutter交流微信群: 116 | 117 | 118 | 119 | [上图无法显示点我](http://www.flutterj.com/left_group.png) 120 | 121 | 122 | ### LICENSE 123 | ``` 124 | fluttercandies/ncov_2019 is licensed under the 125 | Apache License 2.0 126 | 127 | A permissive license whose main conditions require preservation of copyright and license notices. 128 | Contributors provide an express grant of patent rights. 129 | Licensed works, modifications, and larger works may be distributed under different terms and without source code. 130 | ``` 131 | -------------------------------------------------------------------------------- /android/android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/.DS_Store -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.example.ncov_2019" 37 | minSdkVersion 16 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | signingConfigs { 45 | release { 46 | keyAlias "key.keystore" 47 | keyPassword "123456" 48 | storeFile file("key.keystore") 49 | storePassword "123456" 50 | } 51 | } 52 | 53 | buildTypes { 54 | release { 55 | minifyEnabled true 56 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 57 | signingConfig signingConfigs.release 58 | } 59 | debug { 60 | signingConfig signingConfigs.release 61 | } 62 | } 63 | } 64 | 65 | flutter { 66 | source '../..' 67 | } 68 | 69 | dependencies { 70 | testImplementation 'junit:junit:4.12' 71 | androidTestImplementation 'androidx.test:runner:1.1.1' 72 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 73 | } 74 | -------------------------------------------------------------------------------- /android/app/key.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/key.keystore -------------------------------------------------------------------------------- /android/app/release/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/release/.DS_Store -------------------------------------------------------------------------------- /android/app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":10,"versionName":"0.0.10","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] -------------------------------------------------------------------------------- /android/app/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/.DS_Store -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/.DS_Store -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | 11 | 12 | 17 | 24 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/example/ncov_2019/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.ncov_2019; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java: -------------------------------------------------------------------------------- 1 | package io.flutter.plugins; 2 | 3 | import io.flutter.plugin.common.PluginRegistry; 4 | import io.flutter.plugins.connectivity.ConnectivityPlugin; 5 | import io.flutter.plugins.deviceinfo.DeviceInfoPlugin; 6 | import com.example.nav_router.NavRouterPlugin; 7 | import com.crazecoder.openfile.OpenFilePlugin; 8 | import io.flutter.plugins.packageinfo.PackageInfoPlugin; 9 | import io.flutter.plugins.pathprovider.PathProviderPlugin; 10 | import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin; 11 | import com.tekartik.sqflite.SqflitePlugin; 12 | import io.flutter.plugins.urllauncher.UrlLauncherPlugin; 13 | import io.flutter.plugins.webviewflutter.WebViewFlutterPlugin; 14 | 15 | /** 16 | * Generated file. Do not edit. 17 | */ 18 | public final class GeneratedPluginRegistrant { 19 | public static void registerWith(PluginRegistry registry) { 20 | if (alreadyRegisteredWith(registry)) { 21 | return; 22 | } 23 | ConnectivityPlugin.registerWith(registry.registrarFor("io.flutter.plugins.connectivity.ConnectivityPlugin")); 24 | DeviceInfoPlugin.registerWith(registry.registrarFor("io.flutter.plugins.deviceinfo.DeviceInfoPlugin")); 25 | NavRouterPlugin.registerWith(registry.registrarFor("com.example.nav_router.NavRouterPlugin")); 26 | OpenFilePlugin.registerWith(registry.registrarFor("com.crazecoder.openfile.OpenFilePlugin")); 27 | PackageInfoPlugin.registerWith(registry.registrarFor("io.flutter.plugins.packageinfo.PackageInfoPlugin")); 28 | PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin")); 29 | SharedPreferencesPlugin.registerWith(registry.registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin")); 30 | SqflitePlugin.registerWith(registry.registrarFor("com.tekartik.sqflite.SqflitePlugin")); 31 | UrlLauncherPlugin.registerWith(registry.registrarFor("io.flutter.plugins.urllauncher.UrlLauncherPlugin")); 32 | WebViewFlutterPlugin.registerWith(registry.registrarFor("io.flutter.plugins.webviewflutter.WebViewFlutterPlugin")); 33 | } 34 | 35 | private static boolean alreadyRegisteredWith(PluginRegistry registry) { 36 | final String key = GeneratedPluginRegistrant.class.getCanonicalName(); 37 | if (registry.hasPlugin(key)) { 38 | return true; 39 | } 40 | registry.registrarFor(key); 41 | return false; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /android/app/src/main/res/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/.DS_Store -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-hdpi/.DS_Store -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-mdpi/.DS_Store -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-xhdpi/.DS_Store -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-xxhdpi/.DS_Store -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-xxxhdpi/.DS_Store -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | subprojects { 28 | project.configurations.all { 29 | resolutionStrategy.eachDependency { details -> 30 | if (details.requested.group == 'androidx.lifecycle' && 31 | !details.requested.name.contains('androidx')) { 32 | details.useVersion "2.0.0" 33 | } 34 | if (details.requested.group == 'androidx.slidingpanelayout' && 35 | !details.requested.name.contains('androidx')) { 36 | details.useVersion "1.0.0" 37 | } 38 | if (details.requested.group == 'androidx.legacy' && 39 | !details.requested.name.contains('androidx')) { 40 | details.useVersion "1.0.0" 41 | } 42 | if (details.requested.group == 'androidx.fragment' && 43 | !details.requested.name.contains('androidx')) { 44 | details.useVersion "1.0.0" 45 | } 46 | if (details.requested.group == 'androidx.annotation' && 47 | !details.requested.name.contains('androidx')) { 48 | details.useVersion "1.0.0" 49 | } 50 | } 51 | } 52 | } 53 | 54 | task clean(type: Delete) { 55 | delete rootProject.buildDir 56 | } 57 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/ncov_2019_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/.DS_Store -------------------------------------------------------------------------------- /assets/git/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/download.png -------------------------------------------------------------------------------- /assets/git/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/home.png -------------------------------------------------------------------------------- /assets/git/left_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/left_group.png -------------------------------------------------------------------------------- /assets/git/lore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/lore.png -------------------------------------------------------------------------------- /assets/git/protect1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/protect1.png -------------------------------------------------------------------------------- /assets/git/protect2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/protect2.png -------------------------------------------------------------------------------- /assets/git/protect3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/protect3.png -------------------------------------------------------------------------------- /assets/git/rumor1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/rumor1.png -------------------------------------------------------------------------------- /assets/git/rumor2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/rumor2.png -------------------------------------------------------------------------------- /assets/git/rumor3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/git/rumor3.png -------------------------------------------------------------------------------- /assets/images/a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/a.jpg -------------------------------------------------------------------------------- /assets/images/bottom_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/bottom_home.png -------------------------------------------------------------------------------- /assets/images/bottom_lore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/bottom_lore.png -------------------------------------------------------------------------------- /assets/images/bottom_protect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/bottom_protect.png -------------------------------------------------------------------------------- /assets/images/bottom_rumor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/bottom_rumor.png -------------------------------------------------------------------------------- /assets/images/entries_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/entries_1.png -------------------------------------------------------------------------------- /assets/images/entries_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/entries_2.png -------------------------------------------------------------------------------- /assets/images/entries_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/entries_3.png -------------------------------------------------------------------------------- /assets/images/entries_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/entries_4.png -------------------------------------------------------------------------------- /assets/images/entries_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/assets/images/entries_5.png -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Flutter: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Flutter/Flutter.framework/Flutter -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/Flutter.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTER_H_ 6 | #define FLUTTER_FLUTTER_H_ 7 | 8 | /** 9 | BREAKING CHANGES: 10 | 11 | December 17, 2018: 12 | - Changed designated initializer on FlutterEngine 13 | 14 | October 5, 2018: 15 | - Removed FlutterNavigationController.h/.mm 16 | - Changed return signature of `FlutterDartHeadlessCodeRunner.run*` from void 17 | to bool 18 | - Removed HeadlessPlatformViewIOS 19 | - Marked FlutterDartHeadlessCodeRunner deprecated 20 | 21 | August 31, 2018: Marked -[FlutterDartProject 22 | initFromDefaultSourceForConfiguration] and FlutterStandardBigInteger as 23 | unavailable. 24 | 25 | July 26, 2018: Marked -[FlutterDartProject 26 | initFromDefaultSourceForConfiguration] deprecated. 27 | 28 | February 28, 2018: Removed "initWithFLXArchive" and 29 | "initWithFLXArchiveWithScriptSnapshot". 30 | 31 | January 15, 2018: Marked "initWithFLXArchive" and 32 | "initWithFLXArchiveWithScriptSnapshot" as unavailable following the 33 | deprecation from December 11, 2017. Scheduled to be removed on February 34 | 19, 2018. 35 | 36 | January 09, 2018: Deprecated "FlutterStandardBigInteger" and its use in 37 | "FlutterStandardMessageCodec" and "FlutterStandardMethodCodec". Scheduled to 38 | be marked as unavailable once the deprecation has been available on the 39 | flutter/flutter alpha branch for four weeks. "FlutterStandardBigInteger" was 40 | needed because the Dart 1.0 int type had no size limit. With Dart 2.0, the 41 | int type is a fixed-size, 64-bit signed integer. If you need to communicate 42 | larger integers, use NSString encoding instead. 43 | 44 | December 11, 2017: Deprecated "initWithFLXArchive" and 45 | "initWithFLXArchiveWithScriptSnapshot" and scheculed the same to be marked as 46 | unavailable on January 15, 2018. Instead, "initWithFlutterAssets" and 47 | "initWithFlutterAssetsWithScriptSnapshot" should be used. The reason for this 48 | change is that the FLX archive will be deprecated and replaced with a flutter 49 | assets directory containing the same files as the FLX did. 50 | 51 | November 29, 2017: Added a BREAKING CHANGES section. 52 | */ 53 | 54 | #include "FlutterAppDelegate.h" 55 | #include "FlutterBinaryMessenger.h" 56 | #include "FlutterCallbackCache.h" 57 | #include "FlutterChannels.h" 58 | #include "FlutterCodecs.h" 59 | #include "FlutterDartProject.h" 60 | #include "FlutterEngine.h" 61 | #include "FlutterHeadlessDartRunner.h" 62 | #include "FlutterMacros.h" 63 | #include "FlutterPlatformViews.h" 64 | #include "FlutterPlugin.h" 65 | #include "FlutterPluginAppLifeCycleDelegate.h" 66 | #include "FlutterTexture.h" 67 | #include "FlutterViewController.h" 68 | 69 | #endif // FLUTTER_FLUTTER_H_ 70 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/FlutterAppDelegate.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTERAPPDELEGATE_H_ 6 | #define FLUTTER_FLUTTERAPPDELEGATE_H_ 7 | 8 | #import 9 | 10 | #include "FlutterMacros.h" 11 | #include "FlutterPlugin.h" 12 | 13 | /** 14 | * `UIApplicationDelegate` subclass for simple apps that want default behavior. 15 | * 16 | * This class implements the following behaviors: 17 | * * Status bar touches are forwarded to the key window's root view 18 | * `FlutterViewController`, in order to trigger scroll to top. 19 | * * Keeps the Flutter connection open in debug mode when the phone screen 20 | * locks. 21 | * 22 | * App delegates for Flutter applications are *not* required to inherit from 23 | * this class. Developers of custom app delegate classes should copy and paste 24 | * code as necessary from FlutterAppDelegate.mm. 25 | */ 26 | FLUTTER_EXPORT 27 | @interface FlutterAppDelegate 28 | : UIResponder 29 | 30 | @property(strong, nonatomic) UIWindow* window; 31 | 32 | /** 33 | * Handle StatusBar touches. 34 | * 35 | * Call this from your AppDelegate's `touchesBegan:withEvent:` to have Flutter respond to StatusBar 36 | * touches. For example, to enable scroll-to-top behavior. FlutterAppDelegate already calls it so 37 | * you only need to manually call it if you aren't using a FlutterAppDelegate. 38 | */ 39 | + (void)handleStatusBarTouches:(NSSet*)touches withEvent:(UIEvent*)event; 40 | 41 | @end 42 | 43 | #endif // FLUTTER_FLUTTERDARTPROJECT_H_ 44 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/FlutterBinaryMessenger.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTERBINARYMESSENGER_H_ 6 | #define FLUTTER_FLUTTERBINARYMESSENGER_H_ 7 | 8 | #import 9 | 10 | #include "FlutterMacros.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | /** 14 | * A message reply callback. 15 | * 16 | * Used for submitting a binary reply back to a Flutter message sender. Also used 17 | * in for handling a binary message reply received from Flutter. 18 | * 19 | * @param reply The reply. 20 | */ 21 | typedef void (^FlutterBinaryReply)(NSData* _Nullable reply); 22 | 23 | /** 24 | * A strategy for handling incoming binary messages from Flutter and to send 25 | * asynchronous replies back to Flutter. 26 | * 27 | * @param message The message. 28 | * @param reply A callback for submitting an asynchronous reply to the sender. 29 | */ 30 | typedef void (^FlutterBinaryMessageHandler)(NSData* _Nullable message, FlutterBinaryReply reply); 31 | 32 | /** 33 | * A facility for communicating with the Flutter side using asynchronous message 34 | * passing with binary messages. 35 | * 36 | * Implementated by: 37 | * - `FlutterBasicMessageChannel`, which supports communication using structured 38 | * messages. 39 | * - `FlutterMethodChannel`, which supports communication using asynchronous 40 | * method calls. 41 | * - `FlutterEventChannel`, which supports commuication using event streams. 42 | */ 43 | FLUTTER_EXPORT 44 | @protocol FlutterBinaryMessenger 45 | /** 46 | * Sends a binary message to the Flutter side on the specified channel, expecting 47 | * no reply. 48 | * 49 | * @param channel The channel name. 50 | * @param message The message. 51 | */ 52 | - (void)sendOnChannel:(NSString*)channel message:(NSData* _Nullable)message; 53 | 54 | /** 55 | * Sends a binary message to the Flutter side on the specified channel, expecting 56 | * an asynchronous reply. 57 | * 58 | * @param channel The channel name. 59 | * @param message The message. 60 | * @param callback A callback for receiving a reply. 61 | */ 62 | - (void)sendOnChannel:(NSString*)channel 63 | message:(NSData* _Nullable)message 64 | binaryReply:(FlutterBinaryReply _Nullable)callback; 65 | 66 | /** 67 | * Registers a message handler for incoming binary messages from the Flutter side 68 | * on the specified channel. 69 | * 70 | * Replaces any existing handler. Use a `nil` handler for unregistering the 71 | * existing handler. 72 | * 73 | * @param channel The channel name. 74 | * @param handler The message handler. 75 | */ 76 | - (void)setMessageHandlerOnChannel:(NSString*)channel 77 | binaryMessageHandler:(FlutterBinaryMessageHandler _Nullable)handler; 78 | @end 79 | NS_ASSUME_NONNULL_END 80 | #endif // FLUTTER_FLUTTERBINARYMESSENGER_H_ 81 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/FlutterCallbackCache.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTERCALLBACKCACHE_H_ 6 | #define FLUTTER_FLUTTERCALLBACKCACHE_H_ 7 | 8 | #import 9 | 10 | #include "FlutterMacros.h" 11 | 12 | /** 13 | * An object containing the result of `FlutterCallbackCache`'s `lookupCallbackInformation` 14 | * method. 15 | */ 16 | FLUTTER_EXPORT 17 | @interface FlutterCallbackInformation : NSObject 18 | /** 19 | * The name of the callback. 20 | */ 21 | @property(retain) NSString* callbackName; 22 | /** 23 | * The class name of the callback. 24 | */ 25 | @property(retain) NSString* callbackClassName; 26 | /** 27 | * The library path of the callback. 28 | */ 29 | @property(retain) NSString* callbackLibraryPath; 30 | @end 31 | 32 | /** 33 | * The cache containing callback information for spawning a 34 | * `FlutterHeadlessDartRunner`. 35 | */ 36 | FLUTTER_EXPORT 37 | @interface FlutterCallbackCache : NSObject 38 | /** 39 | * Returns the callback information for the given callback handle. 40 | * This callback information can be used when spawning a 41 | * `FlutterHeadlessDartRunner`. 42 | * 43 | * @param handle The handle for a callback, provided by the 44 | * Dart method `PluginUtilities.getCallbackHandle`. 45 | * @return A `FlutterCallbackInformation` object which contains the name of the 46 | * callback, the name of the class in which the callback is defined, and the 47 | * path of the library which contains the callback. If the provided handle is 48 | * invalid, nil is returned. 49 | */ 50 | + (FlutterCallbackInformation*)lookupCallbackInformation:(int64_t)handle; 51 | 52 | @end 53 | 54 | #endif // FLUTTER_FLUTTERCALLBACKCACHE_H_ 55 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/FlutterDartProject.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTERDARTPROJECT_H_ 6 | #define FLUTTER_FLUTTERDARTPROJECT_H_ 7 | 8 | #import 9 | 10 | #include "FlutterMacros.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /** 15 | * A set of Flutter and Dart assets used by a `FlutterEngine` to initialize execution. 16 | */ 17 | FLUTTER_EXPORT 18 | @interface FlutterDartProject : NSObject 19 | 20 | /** 21 | * Initializes a Flutter Dart project from a bundle. 22 | */ 23 | - (instancetype)initWithPrecompiledDartBundle:(nullable NSBundle*)bundle NS_DESIGNATED_INITIALIZER; 24 | 25 | /** 26 | * Unavailable - use `init` instead. 27 | */ 28 | - (instancetype)initFromDefaultSourceForConfiguration FLUTTER_UNAVAILABLE("Use -init instead."); 29 | 30 | /** 31 | * Returns the file name for the given asset. If the bundle with the identifier 32 | * "io.flutter.flutter.app" exists, it will try use that bundle; otherwise, it 33 | * will use the main bundle. To specify a different bundle, use 34 | * `-lookupKeyForAsset:asset:fromBundle`. 35 | * 36 | * @param asset The name of the asset. The name can be hierarchical. 37 | * @return the file name to be used for lookup in the main bundle. 38 | */ 39 | + (NSString*)lookupKeyForAsset:(NSString*)asset; 40 | 41 | /** 42 | * Returns the file name for the given asset. 43 | * The returned file name can be used to access the asset in the supplied bundle. 44 | * 45 | * @param asset The name of the asset. The name can be hierarchical. 46 | * @param bundle The `NSBundle` to use for looking up the asset. 47 | * @return the file name to be used for lookup in the main bundle. 48 | */ 49 | + (NSString*)lookupKeyForAsset:(NSString*)asset fromBundle:(nullable NSBundle*)bundle; 50 | 51 | /** 52 | * Returns the file name for the given asset which originates from the specified package. 53 | * The returned file name can be used to access the asset in the application's main bundle. 54 | * 55 | * @param asset The name of the asset. The name can be hierarchical. 56 | * @param package The name of the package from which the asset originates. 57 | * @return the file name to be used for lookup in the main bundle. 58 | */ 59 | + (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package; 60 | 61 | /** 62 | * Returns the file name for the given asset which originates from the specified package. 63 | * The returned file name can be used to access the asset in the specified bundle. 64 | * 65 | * @param asset The name of the asset. The name can be hierarchical. 66 | * @param package The name of the package from which the asset originates. 67 | * @param bundle The bundle to use when doing the lookup. 68 | * @return the file name to be used for lookup in the main bundle. 69 | */ 70 | + (NSString*)lookupKeyForAsset:(NSString*)asset 71 | fromPackage:(NSString*)package 72 | fromBundle:(nullable NSBundle*)bundle; 73 | 74 | /** 75 | * Returns the default identifier for the bundle where we expect to find the Flutter Dart 76 | * application. 77 | */ 78 | + (NSString*)defaultBundleIdentifier; 79 | 80 | @end 81 | 82 | NS_ASSUME_NONNULL_END 83 | 84 | #endif // FLUTTER_FLUTTERDARTPROJECT_H_ 85 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/FlutterHeadlessDartRunner.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTERHEADLESSDARTRUNNER_H_ 6 | #define FLUTTER_FLUTTERHEADLESSDARTRUNNER_H_ 7 | 8 | #import 9 | 10 | #include "FlutterBinaryMessenger.h" 11 | #include "FlutterDartProject.h" 12 | #include "FlutterEngine.h" 13 | #include "FlutterMacros.h" 14 | 15 | /** 16 | * A callback for when FlutterHeadlessDartRunner has attempted to start a Dart 17 | * Isolate in the background. 18 | * 19 | * @param success YES if the Isolate was started and run successfully, NO 20 | * otherwise. 21 | */ 22 | typedef void (^FlutterHeadlessDartRunnerCallback)(BOOL success); 23 | 24 | /** 25 | * The FlutterHeadlessDartRunner runs Flutter Dart code with a null rasterizer, 26 | * and no native drawing surface. It is appropriate for use in running Dart 27 | * code e.g. in the background from a plugin. 28 | * 29 | * Most callers should prefer using `FlutterEngine` directly; this interface exists 30 | * for legacy support. 31 | */ 32 | FLUTTER_EXPORT 33 | FLUTTER_DEPRECATED("FlutterEngine should be used rather than FlutterHeadlessDartRunner") 34 | @interface FlutterHeadlessDartRunner : FlutterEngine 35 | 36 | /** 37 | * Iniitalize this FlutterHeadlessDartRunner with a `FlutterDartProject`. 38 | * 39 | * If the FlutterDartProject is not specified, the FlutterHeadlessDartRunner will attempt to locate 40 | * the project in a default location. 41 | * 42 | * A newly initialized engine will not run the `FlutterDartProject` until either 43 | * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is called. 44 | * 45 | * @param labelPrefix The label prefix used to identify threads for this instance. Should 46 | * be unique across FlutterEngine instances 47 | * @param projectOrNil The `FlutterDartProject` to run. 48 | */ 49 | - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil; 50 | 51 | /** 52 | * Iniitalize this FlutterHeadlessDartRunner with a `FlutterDartProject`. 53 | * 54 | * If the FlutterDartProject is not specified, the FlutterHeadlessDartRunner will attempt to locate 55 | * the project in a default location. 56 | * 57 | * A newly initialized engine will not run the `FlutterDartProject` until either 58 | * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is called. 59 | * 60 | * @param labelPrefix The label prefix used to identify threads for this instance. Should 61 | * be unique across FlutterEngine instances 62 | * @param projectOrNil The `FlutterDartProject` to run. 63 | * @param allowHeadlessExecution Must be set to `YES`. 64 | */ 65 | - (instancetype)initWithName:(NSString*)labelPrefix 66 | project:(FlutterDartProject*)projectOrNil 67 | allowHeadlessExecution:(BOOL)allowHeadlessExecution NS_DESIGNATED_INITIALIZER; 68 | 69 | /** 70 | * Not recommended for use - will initialize with a default label ("io.flutter.headless") 71 | * and the default FlutterDartProject. 72 | */ 73 | - (instancetype)init; 74 | 75 | @end 76 | 77 | #endif // FLUTTER_FLUTTERHEADLESSDARTRUNNER_H_ 78 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/FlutterMacros.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTERMACROS_H_ 6 | #define FLUTTER_FLUTTERMACROS_H_ 7 | 8 | #if defined(FLUTTER_FRAMEWORK) 9 | 10 | #define FLUTTER_EXPORT __attribute__((visibility("default"))) 11 | 12 | #else // defined(FLUTTER_SDK) 13 | 14 | #define FLUTTER_EXPORT 15 | 16 | #endif // defined(FLUTTER_SDK) 17 | 18 | #ifndef NS_ASSUME_NONNULL_BEGIN 19 | #define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin") 20 | #define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end") 21 | #endif // defined(NS_ASSUME_NONNULL_BEGIN) 22 | 23 | /** 24 | * Indicates that the API has been deprecated for the specified reason. Code 25 | * that uses the deprecated API will continue to work as before. However, the 26 | * API will soon become unavailable and users are encouraged to immediately take 27 | * the appropriate action mentioned in the deprecation message and the BREAKING 28 | * CHANGES section present in the Flutter.h umbrella header. 29 | */ 30 | #define FLUTTER_DEPRECATED(msg) __attribute__((__deprecated__(msg))) 31 | 32 | /** 33 | * Indicates that the previously deprecated API is now unavailable. Code that 34 | * uses the API will not work and the declaration of the API is only a stub 35 | * meant to display the given message detailing the actions for the user to take 36 | * immediately. 37 | */ 38 | #define FLUTTER_UNAVAILABLE(msg) __attribute__((__unavailable__(msg))) 39 | 40 | #if __has_feature(objc_arc) 41 | #define FLUTTER_ASSERT_ARC 42 | #define FLUTTER_ASSERT_NOT_ARC #error ARC must be disabled! 43 | #else 44 | #define FLUTTER_ASSERT_ARC #error ARC must be enabled! 45 | #define FLUTTER_ASSERT_NOT_ARC 46 | #endif 47 | 48 | #endif // FLUTTER_FLUTTERMACROS_H_ 49 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/FlutterPlatformViews.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTERPLATFORMVIEWS_H_ 6 | #define FLUTTER_FLUTTERPLATFORMVIEWS_H_ 7 | 8 | #import 9 | 10 | #import "FlutterCodecs.h" 11 | #import "FlutterMacros.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | /** 16 | * Wraps a `UIView` for embedding in the Flutter hierarchy 17 | */ 18 | @protocol FlutterPlatformView 19 | /** 20 | * Returns a reference to the `UIView` that is wrapped by this `FlutterPlatformView`. 21 | */ 22 | - (UIView*)view; 23 | @end 24 | 25 | FLUTTER_EXPORT 26 | @protocol FlutterPlatformViewFactory 27 | /** 28 | * Create a `FlutterPlatformView`. 29 | * 30 | * Implemented by iOS code that expose a `UIView` for embedding in a Flutter app. 31 | * 32 | * The implementation of this method should create a new `UIView` and return it. 33 | * 34 | * @param frame The rectangle for the newly created `UIView` measued in points. 35 | * @param viewId A unique identifier for this `UIView`. 36 | * @param args Parameters for creating the `UIView` sent from the Dart side of the Flutter app. 37 | * If `createArgsCodec` is not implemented, or if no creation arguments were sent from the Dart 38 | * code, this will be null. Otherwise this will be the value sent from the Dart code as decoded by 39 | * `createArgsCodec`. 40 | */ 41 | - (NSObject*)createWithFrame:(CGRect)frame 42 | viewIdentifier:(int64_t)viewId 43 | arguments:(id _Nullable)args; 44 | 45 | /** 46 | * Returns the `FlutterMessageCodec` for decoding the args parameter of `createWithFrame`. 47 | * 48 | * Only needs to be implemented if `createWithFrame` needs an arguments parameter. 49 | */ 50 | @optional 51 | - (NSObject*)createArgsCodec; 52 | @end 53 | 54 | NS_ASSUME_NONNULL_END 55 | 56 | #endif // FLUTTER_FLUTTERPLATFORMVIEWS_H_ 57 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/FlutterPluginAppLifeCycleDelegate.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ 6 | #define FLUTTER_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ 7 | 8 | #include "FlutterPlugin.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | /** 13 | * Propagates `UIAppDelegate` callbacks to registered plugins. 14 | */ 15 | FLUTTER_EXPORT 16 | @interface FlutterPluginAppLifeCycleDelegate : NSObject 17 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 18 | 19 | #endif 20 | 21 | /** 22 | * Registers `delegate` to receive life cycle callbacks via this FlutterPluginAppLifecycleDelegate 23 | * as long as it is alive. 24 | * 25 | * `delegate` will only referenced weakly. 26 | */ 27 | - (void)addDelegate:(NSObject*)delegate; 28 | 29 | /** 30 | * Calls all plugins registered for `UIApplicationDelegate` callbacks. 31 | * 32 | * @return `NO` if any plugin vetoes application launch. 33 | */ 34 | - (BOOL)application:(UIApplication*)application 35 | didFinishLaunchingWithOptions:(NSDictionary*)launchOptions; 36 | 37 | /** 38 | * Calls all plugins registered for `UIApplicationDelegate` callbacks. 39 | * 40 | * @return `NO` if any plugin vetoes application launch. 41 | */ 42 | - (BOOL)application:(UIApplication*)application 43 | willFinishLaunchingWithOptions:(NSDictionary*)launchOptions; 44 | 45 | /** 46 | * Called if this plugin has been registered for `UIApplicationDelegate` callbacks. 47 | */ 48 | - (void)application:(UIApplication*)application 49 | didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings 50 | API_DEPRECATED( 51 | "See -[UIApplicationDelegate application:didRegisterUserNotificationSettings:] deprecation", 52 | ios(8.0, 10.0)); 53 | 54 | /** 55 | * Calls all plugins registered for `UIApplicationDelegate` callbacks. 56 | */ 57 | - (void)application:(UIApplication*)application 58 | didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; 59 | 60 | /** 61 | * Calls all plugins registered for `UIApplicationDelegate` callbacks. 62 | */ 63 | - (void)application:(UIApplication*)application 64 | didReceiveRemoteNotification:(NSDictionary*)userInfo 65 | fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; 66 | 67 | /** 68 | * Calls all plugins registered for `UIApplicationDelegate` callbacks. 69 | */ 70 | - (void)application:(UIApplication*)application 71 | didReceiveLocalNotification:(UILocalNotification*)notification 72 | API_DEPRECATED( 73 | "See -[UIApplicationDelegate application:didReceiveLocalNotification:] deprecation", 74 | ios(4.0, 10.0)); 75 | 76 | /** 77 | * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until 78 | * some plugin handles the request. 79 | * 80 | * @return `YES` if any plugin handles the request. 81 | */ 82 | - (BOOL)application:(UIApplication*)application 83 | openURL:(NSURL*)url 84 | options:(NSDictionary*)options; 85 | 86 | /** 87 | * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until 88 | * some plugin handles the request. 89 | * 90 | * @return `YES` if any plugin handles the request. 91 | */ 92 | - (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url; 93 | 94 | /** 95 | * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until 96 | * some plugin handles the request. 97 | * 98 | * @return `YES` if any plugin handles the request. 99 | */ 100 | - (BOOL)application:(UIApplication*)application 101 | openURL:(NSURL*)url 102 | sourceApplication:(NSString*)sourceApplication 103 | annotation:(id)annotation; 104 | 105 | /** 106 | * Calls all plugins registered for `UIApplicationDelegate` callbacks. 107 | */ 108 | - (void)application:(UIApplication*)application 109 | performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem 110 | completionHandler:(void (^)(BOOL succeeded))completionHandler 111 | API_AVAILABLE(ios(9.0)); 112 | 113 | /** 114 | * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until 115 | * some plugin handles the request. 116 | * 117 | * @return `YES` if any plugin handles the request. 118 | */ 119 | - (BOOL)application:(UIApplication*)application 120 | handleEventsForBackgroundURLSession:(nonnull NSString*)identifier 121 | completionHandler:(nonnull void (^)(void))completionHandler; 122 | 123 | /** 124 | * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until 125 | * some plugin handles the request. 126 | * 127 | * @returns `YES` if any plugin handles the request. 128 | */ 129 | - (BOOL)application:(UIApplication*)application 130 | performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; 131 | 132 | /** 133 | * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until 134 | * some plugin handles the request. 135 | * 136 | * @return `YES` if any plugin handles the request. 137 | */ 138 | - (BOOL)application:(UIApplication*)application 139 | continueUserActivity:(NSUserActivity*)userActivity 140 | restorationHandler:(void (^)(NSArray*))restorationHandler; 141 | @end 142 | 143 | NS_ASSUME_NONNULL_END 144 | 145 | #endif // FLUTTER_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ 146 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Headers/FlutterTexture.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef FLUTTER_FLUTTERTEXTURE_H_ 6 | #define FLUTTER_FLUTTERTEXTURE_H_ 7 | 8 | #import 9 | #import 10 | 11 | #include "FlutterMacros.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | FLUTTER_EXPORT 16 | @protocol FlutterTexture 17 | - (CVPixelBufferRef _Nullable)copyPixelBuffer; 18 | 19 | /** 20 | * Called when the texture is unregistered. 21 | * 22 | * Called on the GPU thread. 23 | */ 24 | @optional 25 | - (void)onTextureUnregistered:(NSObject*)texture; 26 | @end 27 | 28 | FLUTTER_EXPORT 29 | @protocol FlutterTextureRegistry 30 | - (int64_t)registerTexture:(NSObject*)texture; 31 | - (void)textureFrameAvailable:(int64_t)textureId; 32 | - (void)unregisterTexture:(int64_t)textureId; 33 | @end 34 | 35 | NS_ASSUME_NONNULL_END 36 | 37 | #endif // FLUTTER_FLUTTERTEXTURE_H_ 38 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | Flutter 9 | CFBundleIdentifier 10 | io.flutter.flutter 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | Flutter 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | FlutterEngine 26 | b6b54fd60631a3828c2e2c9b079b5d1d2d8c8c37 27 | ClangVersion 28 | Apple LLVM version 10.0.1 (clang-1001.0.46.3) 29 | 30 | 31 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module Flutter { 2 | umbrella header "Flutter.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.framework/icudtl.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Flutter/Flutter.framework/icudtl.dat -------------------------------------------------------------------------------- /ios/Flutter/Flutter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: This podspec is NOT to be published. It is only used as a local source! 3 | # 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'Flutter' 7 | s.version = '1.0.0' 8 | s.summary = 'High-performance, high-fidelity mobile apps.' 9 | s.description = <<-DESC 10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. 11 | DESC 12 | s.homepage = 'https://flutter.io' 13 | s.license = { :type => 'MIT' } 14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } 15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } 16 | s.ios.deployment_target = '8.0' 17 | s.vendored_frameworks = 'Flutter.framework' 18 | end 19 | -------------------------------------------------------------------------------- /ios/Flutter/Generated.xcconfig: -------------------------------------------------------------------------------- 1 | // This is a generated file; do not edit or check into version control. 2 | FLUTTER_ROOT=/Users/q1/flutterNew/flutter 3 | FLUTTER_APPLICATION_PATH=/Users/q1/Documents/gitPro/ahyangnb/ncov_2019 4 | FLUTTER_TARGET=lib/main.dart 5 | FLUTTER_BUILD_DIR=build 6 | SYMROOT=${SOURCE_ROOT}/../build/ios 7 | OTHER_LDFLAGS=$(inherited) -framework Flutter 8 | FLUTTER_FRAMEWORK_DIR=/Users/q1/flutterNew/flutter/bin/cache/artifacts/engine/ios 9 | FLUTTER_BUILD_NAME=0.0.10 10 | FLUTTER_BUILD_NUMBER=10 11 | DART_OBFUSCATION=false 12 | TRACK_WIDGET_CREATION=false 13 | TREE_SHAKE_ICONS=false 14 | PACKAGE_CONFIG=.packages 15 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/Users/q1/flutterNew/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/Users/q1/Documents/gitPro/ahyangnb/ncov_2019" 5 | export "FLUTTER_TARGET=lib/main.dart" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios" 8 | export "OTHER_LDFLAGS=$(inherited) -framework Flutter" 9 | export "FLUTTER_FRAMEWORK_DIR=/Users/q1/flutterNew/flutter/bin/cache/artifacts/engine/ios" 10 | export "FLUTTER_BUILD_NAME=0.0.10" 11 | export "FLUTTER_BUILD_NUMBER=10" 12 | export "DART_OBFUSCATION=false" 13 | export "TRACK_WIDGET_CREATION=false" 14 | export "TREE_SHAKE_ICONS=false" 15 | export "PACKAGE_CONFIG=.packages" 16 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | pods_ary = [] 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) { |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | pods_ary.push({:name => podname, :path => podpath}); 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | } 32 | return pods_ary 33 | end 34 | 35 | target 'Runner' do 36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 37 | # referring to absolute paths on developers' machines. 38 | system('rm -rf .symlinks') 39 | system('mkdir -p .symlinks/plugins') 40 | 41 | # Flutter Pods 42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 43 | if generated_xcode_build_settings.empty? 44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first." 45 | end 46 | generated_xcode_build_settings.map { |p| 47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 48 | symlink = File.join('.symlinks', 'flutter') 49 | File.symlink(File.dirname(p[:path]), symlink) 50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 51 | end 52 | } 53 | 54 | # Plugin Pods 55 | plugin_pods = parse_KV_file('../.flutter-plugins') 56 | plugin_pods.map { |p| 57 | symlink = File.join('.symlinks', 'plugins', p[:name]) 58 | File.symlink(p[:path], symlink) 59 | pod p[:name], :path => File.join(symlink, 'ios') 60 | } 61 | end 62 | 63 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 64 | install! 'cocoapods', :disable_input_output_paths => true 65 | 66 | post_install do |installer| 67 | installer.pods_project.targets.each do |target| 68 | target.build_configurations.each do |config| 69 | config.build_settings['ENABLE_BITCODE'] = 'NO' 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - connectivity (0.0.1): 3 | - Flutter 4 | - Reachability 5 | - device_info (0.0.1): 6 | - Flutter 7 | - Flutter (1.0.0) 8 | - FMDB (2.7.5): 9 | - FMDB/standard (= 2.7.5) 10 | - FMDB/standard (2.7.5) 11 | - nav_router (0.0.1): 12 | - Flutter 13 | - open_file (0.0.1): 14 | - Flutter 15 | - package_info (0.0.1): 16 | - Flutter 17 | - path_provider (0.0.1): 18 | - Flutter 19 | - Reachability (3.2) 20 | - shared_preferences (0.0.1): 21 | - Flutter 22 | - sqflite (0.0.1): 23 | - Flutter 24 | - FMDB (~> 2.7.2) 25 | - url_launcher (0.0.1): 26 | - Flutter 27 | - webview_flutter (0.0.1): 28 | - Flutter 29 | 30 | DEPENDENCIES: 31 | - connectivity (from `.symlinks/plugins/connectivity/ios`) 32 | - device_info (from `.symlinks/plugins/device_info/ios`) 33 | - Flutter (from `.symlinks/flutter/ios`) 34 | - nav_router (from `.symlinks/plugins/nav_router/ios`) 35 | - open_file (from `.symlinks/plugins/open_file/ios`) 36 | - package_info (from `.symlinks/plugins/package_info/ios`) 37 | - path_provider (from `.symlinks/plugins/path_provider/ios`) 38 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) 39 | - sqflite (from `.symlinks/plugins/sqflite/ios`) 40 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`) 41 | - webview_flutter (from `.symlinks/plugins/webview_flutter/ios`) 42 | 43 | SPEC REPOS: 44 | trunk: 45 | - FMDB 46 | - Reachability 47 | 48 | EXTERNAL SOURCES: 49 | connectivity: 50 | :path: ".symlinks/plugins/connectivity/ios" 51 | device_info: 52 | :path: ".symlinks/plugins/device_info/ios" 53 | Flutter: 54 | :path: ".symlinks/flutter/ios" 55 | nav_router: 56 | :path: ".symlinks/plugins/nav_router/ios" 57 | open_file: 58 | :path: ".symlinks/plugins/open_file/ios" 59 | package_info: 60 | :path: ".symlinks/plugins/package_info/ios" 61 | path_provider: 62 | :path: ".symlinks/plugins/path_provider/ios" 63 | shared_preferences: 64 | :path: ".symlinks/plugins/shared_preferences/ios" 65 | sqflite: 66 | :path: ".symlinks/plugins/sqflite/ios" 67 | url_launcher: 68 | :path: ".symlinks/plugins/url_launcher/ios" 69 | webview_flutter: 70 | :path: ".symlinks/plugins/webview_flutter/ios" 71 | 72 | SPEC CHECKSUMS: 73 | connectivity: 6e94255659cc86dcbef1d452ad3e0491bb1b3e75 74 | device_info: 3ebad48f726348f69abd802f3334a8d1ed795fbd 75 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 76 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 77 | nav_router: a4bf0af66c082e6db0c3c895e6dfeba6f19777ff 78 | open_file: 02eb5cb6b21264bd3a696876f5afbfb7ca4f4b7d 79 | package_info: 78cabb3c322943c55d39676f4a5bfc748c01d055 80 | path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d 81 | Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 82 | shared_preferences: 1feebfa37bb57264736e16865e7ffae7fc99b523 83 | sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 84 | url_launcher: a1c0cc845906122c4784c542523d8cacbded5626 85 | webview_flutter: 1aa7604e6cdb451a9b7ed2c37d5454c0b440246b 86 | 87 | PODFILE CHECKSUM: 7fb83752f59ead6285236625b82473f90b1cb932 88 | 89 | COCOAPODS: 1.8.4 90 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/ncov_2019/ced6ba775426956e752ca6adbc41314014d14009/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | 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. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/GeneratedPluginRegistrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #ifndef GeneratedPluginRegistrant_h 6 | #define GeneratedPluginRegistrant_h 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface GeneratedPluginRegistrant : NSObject 13 | + (void)registerWithRegistry:(NSObject*)registry; 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | #endif /* GeneratedPluginRegistrant_h */ 18 | -------------------------------------------------------------------------------- /ios/Runner/GeneratedPluginRegistrant.m: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #import "GeneratedPluginRegistrant.h" 6 | 7 | #if __has_include() 8 | #import 9 | #else 10 | @import connectivity; 11 | #endif 12 | 13 | #if __has_include() 14 | #import 15 | #else 16 | @import device_info; 17 | #endif 18 | 19 | #if __has_include() 20 | #import 21 | #else 22 | @import nav_router; 23 | #endif 24 | 25 | #if __has_include() 26 | #import 27 | #else 28 | @import open_file; 29 | #endif 30 | 31 | #if __has_include() 32 | #import 33 | #else 34 | @import package_info; 35 | #endif 36 | 37 | #if __has_include() 38 | #import 39 | #else 40 | @import path_provider; 41 | #endif 42 | 43 | #if __has_include() 44 | #import 45 | #else 46 | @import shared_preferences; 47 | #endif 48 | 49 | #if __has_include() 50 | #import 51 | #else 52 | @import sqflite; 53 | #endif 54 | 55 | #if __has_include() 56 | #import 57 | #else 58 | @import url_launcher; 59 | #endif 60 | 61 | #if __has_include() 62 | #import 63 | #else 64 | @import webview_flutter; 65 | #endif 66 | 67 | @implementation GeneratedPluginRegistrant 68 | 69 | + (void)registerWithRegistry:(NSObject*)registry { 70 | [FLTConnectivityPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTConnectivityPlugin"]]; 71 | [FLTDeviceInfoPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTDeviceInfoPlugin"]]; 72 | [NavRouterPlugin registerWithRegistrar:[registry registrarForPlugin:@"NavRouterPlugin"]]; 73 | [OpenFilePlugin registerWithRegistrar:[registry registrarForPlugin:@"OpenFilePlugin"]]; 74 | [FLTPackageInfoPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTPackageInfoPlugin"]]; 75 | [FLTPathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTPathProviderPlugin"]]; 76 | [FLTSharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTSharedPreferencesPlugin"]]; 77 | [SqflitePlugin registerWithRegistrar:[registry registrarForPlugin:@"SqflitePlugin"]]; 78 | [FLTUrlLauncherPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTUrlLauncherPlugin"]]; 79 | [FLTWebViewFlutterPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTWebViewFlutterPlugin"]]; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ncov_2019 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | io.flutter.embedded_views_preview 45 | 46 | NSAppTransportSecurity 47 | 48 | NSAllowsArbitraryLoads 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ios/ServiceDefinitions.json: -------------------------------------------------------------------------------- 1 | {"services":[]} -------------------------------------------------------------------------------- /lib/api/area_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/config/api.dart'; 2 | import 'package:ncov_2019/http/req_model.dart'; 3 | 4 | /* 5 | * 获取省份信息 - 请求 6 | * */ 7 | class AreaReqModel extends ReqModel { 8 | @override 9 | String url() => API.getAreaStat; 10 | 11 | @override 12 | Map params() => {}; 13 | 14 | Future data() => get(); 15 | } 16 | 17 | class AreaModel { 18 | int confirmedCount; 19 | int curedCount; 20 | List cities; 21 | String provinceShortName; 22 | String comment; 23 | String provinceName; 24 | int deadCount; 25 | int suspectedCount; 26 | 27 | AreaModel({this.confirmedCount, this.curedCount, this.cities, this.provinceShortName, this.comment, this.provinceName, this.deadCount, this.suspectedCount}); 28 | 29 | AreaModel.fromJson(Map json) { 30 | confirmedCount = json['confirmedCount']; 31 | curedCount = json['curedCount']; 32 | if (json['cities'] != null) { 33 | cities = new List();(json['cities'] as List).forEach((v) { cities.add(new AreaModelCity.fromJson(v)); }); 34 | } 35 | provinceShortName = json['provinceShortName']; 36 | comment = json['comment']; 37 | provinceName = json['provinceName']; 38 | deadCount = json['deadCount']; 39 | suspectedCount = json['suspectedCount']; 40 | } 41 | 42 | Map toJson() { 43 | final Map data = new Map(); 44 | data['confirmedCount'] = this.confirmedCount; 45 | data['curedCount'] = this.curedCount; 46 | if (this.cities != null) { 47 | data['cities'] = this.cities.map((v) => v.toJson()).toList(); 48 | } 49 | data['provinceShortName'] = this.provinceShortName; 50 | data['comment'] = this.comment; 51 | data['provinceName'] = this.provinceName; 52 | data['deadCount'] = this.deadCount; 53 | data['suspectedCount'] = this.suspectedCount; 54 | return data; 55 | } 56 | } 57 | 58 | class AreaModelCity { 59 | int confirmedCount; 60 | int curedCount; 61 | String cityName; 62 | int deadCount; 63 | int suspectedCount; 64 | 65 | AreaModelCity({this.confirmedCount, this.curedCount, this.cityName, this.deadCount, this.suspectedCount}); 66 | 67 | AreaModelCity.fromJson(Map json) { 68 | confirmedCount = json['confirmedCount']; 69 | curedCount = json['curedCount']; 70 | cityName = json['cityName']; 71 | deadCount = json['deadCount']; 72 | suspectedCount = json['suspectedCount']; 73 | } 74 | 75 | Map toJson() { 76 | final Map data = new Map(); 77 | data['confirmedCount'] = this.confirmedCount; 78 | data['curedCount'] = this.curedCount; 79 | data['cityName'] = this.cityName; 80 | data['deadCount'] = this.deadCount; 81 | data['suspectedCount'] = this.suspectedCount; 82 | return data; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/api/area_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/api/area_model.dart'; 2 | import 'package:ncov_2019/commom/commom.dart'; 3 | export 'package:ncov_2019/api/area_model.dart'; 4 | import 'package:ncov_2019/http/view_model.dart'; 5 | 6 | AreaViewModel areaViewModel = new AreaViewModel(); 7 | 8 | class AreaViewModel extends ViewModel { 9 | /* 10 | * 获取省份信息 11 | * */ 12 | Future getData() async { 13 | final data = await AreaReqModel().data(); 14 | 15 | 16 | List list = new List(); 17 | 18 | if (listNoEmpty(data)) { 19 | data.forEach((json) => list.add(AreaModel.fromJson(json))); 20 | } 21 | 22 | return Future.value(list); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/api/entries_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/config/api.dart'; 2 | import 'package:ncov_2019/http/req_model.dart'; 3 | 4 | /* 5 | * 诊疗信息 - 请求 6 | * */ 7 | class EntriesReqModel extends ReqModel { 8 | @override 9 | String url() => API.getEntries; 10 | 11 | @override 12 | Map params() => {}; 13 | 14 | Future data() => get(); 15 | } 16 | 17 | /* 18 | * 诊疗信息 - 响应 19 | * */ 20 | class EntriesModel { 21 | String configName; 22 | String imgUrl; 23 | int configNo; 24 | String linkUrl; 25 | String icon; 26 | int id; 27 | 28 | EntriesModel( 29 | {this.configName, this.imgUrl, this.configNo, this.linkUrl, this.id}); 30 | 31 | EntriesModel.fromJson(Map json) { 32 | configName = json['configName']; 33 | imgUrl = json['imgUrl']; 34 | configNo = json['configNo']; 35 | linkUrl = json['linkUrl']; 36 | id = json['id']; 37 | icon = 'assets/images/entries_$id.png'; 38 | } 39 | 40 | Map toJson() { 41 | final Map data = new Map(); 42 | data['configName'] = this.configName; 43 | data['imgUrl'] = this.imgUrl; 44 | data['configNo'] = this.configNo; 45 | data['linkUrl'] = this.linkUrl; 46 | data['id'] = this.id; 47 | return data; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/api/entries_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/api/entries_model.dart'; 2 | export 'package:ncov_2019/api/entries_model.dart'; 3 | import 'package:ncov_2019/commom/commom.dart'; 4 | import 'package:ncov_2019/http/view_model.dart'; 5 | 6 | EntriesViewModel entriesViewModel = new EntriesViewModel(); 7 | 8 | class EntriesViewModel extends ViewModel { 9 | /* 10 | * 诊疗信息 11 | * */ 12 | Future getData() async { 13 | final data = await EntriesReqModel().data(); 14 | 15 | List list = new List(); 16 | 17 | if (listNoEmpty(data)) { 18 | data.forEach((json) => list.add(EntriesModel.fromJson(json))); 19 | } 20 | 21 | return Future.value(list); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/api/lore_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/config/api.dart'; 2 | import 'package:ncov_2019/http/req_model.dart'; 3 | 4 | /* 5 | * 最新知识百科 - 请求 6 | * */ 7 | class LoreReqModel extends ReqModel { 8 | @override 9 | String url() => API.getWikiList; 10 | 11 | @override 12 | Map params() => {}; 13 | 14 | Future data() => get(); 15 | } 16 | 17 | class LoreModel { 18 | String imgUrl; 19 | String linkUrl; 20 | String description; 21 | int id; 22 | int sort; 23 | String title; 24 | 25 | LoreModel({this.imgUrl, this.linkUrl, this.description, this.id, this.sort, this.title}); 26 | 27 | LoreModel.fromJson(Map json) { 28 | imgUrl = json['imgUrl']; 29 | linkUrl = json['linkUrl']; 30 | description = json['description']; 31 | id = json['id']; 32 | sort = json['sort']; 33 | title = json['title']; 34 | } 35 | 36 | Map toJson() { 37 | final Map data = new Map(); 38 | data['imgUrl'] = this.imgUrl; 39 | data['linkUrl'] = this.linkUrl; 40 | data['description'] = this.description; 41 | data['id'] = this.id; 42 | data['sort'] = this.sort; 43 | data['title'] = this.title; 44 | return data; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/api/lore_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/api/lore_model.dart'; 2 | export 'package:ncov_2019/api/lore_model.dart'; 3 | import 'package:ncov_2019/commom/check.dart'; 4 | import 'package:ncov_2019/http/view_model.dart'; 5 | 6 | LoreViewModel loreViewModel = new LoreViewModel(); 7 | 8 | class LoreViewModel extends ViewModel { 9 | /* 10 | * 最新知识百科 11 | * */ 12 | Future getLore() async { 13 | Map map = await LoreReqModel().data(); 14 | 15 | List data = map['result']; 16 | 17 | List list = new List(); 18 | 19 | if (listNoEmpty(data)) { 20 | data.forEach((json) => list.add(LoreModel.fromJson(json))); 21 | } 22 | 23 | return Future.value(list); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/api/news_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/config/api.dart'; 2 | import 'package:ncov_2019/http/req_model.dart'; 3 | 4 | /* 5 | * 按时间线获取事件 - 请求 6 | * */ 7 | class TimeNewsReqModel extends ReqModel { 8 | @override 9 | String url() => API.timelineService; 10 | 11 | @override 12 | Map params() => {}; 13 | 14 | Future data() => get(); 15 | } 16 | 17 | /* 18 | * 按时间线获取事件 - 响应 19 | * 20 | * @param summary 概要 21 | * @param sourceUrl 原文Url 22 | * @param modifyTime 更新时间 23 | * @param createTime 创建时间 24 | * @param id 事件Id 25 | * @param provinceName 省份名称 26 | * @param title 标题 27 | * @param pubDate 发布日期时间戳 28 | * @param pubDateStr 发布日期文本 29 | * @param provinceId 地区编号 30 | * @param infoSource 信息来源 31 | * */ 32 | class TimeNewsModel { 33 | String summary; 34 | String sourceUrl; 35 | int modifyTime; 36 | int createTime; 37 | int id; 38 | String provinceName; 39 | String title; 40 | int pubDate; 41 | String pubDateStr; 42 | String provinceId; 43 | String infoSource; 44 | 45 | TimeNewsModel({ 46 | this.summary, 47 | this.sourceUrl, 48 | this.modifyTime, 49 | this.createTime, 50 | this.id, 51 | this.provinceName, 52 | this.title, 53 | this.pubDate, 54 | this.pubDateStr, 55 | this.provinceId, 56 | this.infoSource, 57 | }); 58 | 59 | TimeNewsModel.fromJson(Map json) { 60 | summary = json['summary']; 61 | sourceUrl = json['sourceUrl']; 62 | modifyTime = json['modifyTime']; 63 | createTime = json['createTime']; 64 | id = json['id']; 65 | provinceName = json['provinceName']; 66 | title = json['title']; 67 | pubDate = json['pubDate']; 68 | pubDateStr = json['pubDateStr']; 69 | provinceId = json['provinceId']; 70 | infoSource = json['infoSource']; 71 | } 72 | 73 | Map toJson() { 74 | final Map data = new Map(); 75 | data['summary'] = this.summary; 76 | data['sourceUrl'] = this.sourceUrl; 77 | data['modifyTime'] = this.modifyTime; 78 | data['createTime'] = this.createTime; 79 | data['id'] = this.id; 80 | data['provinceName'] = this.provinceName; 81 | data['title'] = this.title; 82 | data['pubDate'] = this.pubDate; 83 | data['pubDateStr'] = this.pubDateStr; 84 | data['provinceId'] = this.provinceId; 85 | data['infoSource'] = this.infoSource; 86 | return data; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/api/news_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/api/news_model.dart'; 2 | import 'package:ncov_2019/commom/check.dart'; 3 | import 'package:ncov_2019/http/view_model.dart'; 4 | 5 | TimeNewsViewModel timeNewsViewModel = new TimeNewsViewModel(); 6 | 7 | class TimeNewsViewModel extends ViewModel { 8 | /* 9 | * 按时间线获取事件 10 | * */ 11 | Future getTimeNews() async { 12 | final data = await TimeNewsReqModel().data(); 13 | 14 | List list = new List(); 15 | 16 | if (listNoEmpty(data)) { 17 | data.forEach((json) => list.add(TimeNewsModel.fromJson(json))); 18 | } 19 | 20 | return Future.value(list); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/api/protect_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/config/api.dart'; 2 | import 'package:ncov_2019/http/req_model.dart'; 3 | 4 | /* 5 | * 最新防护知识 - 请求 6 | * */ 7 | class ProtectReqModel extends ReqModel { 8 | @override 9 | String url() => API.getIndexRecommendList; 10 | 11 | @override 12 | Map params() => {}; 13 | 14 | Future data() => get(); 15 | } 16 | 17 | /* 18 | * 最新防护知识 - 响应 19 | * 20 | * @param imgUrl 封面图片 21 | * @param modifyTime 修改时间 22 | * @param recordStatus 记录状态 23 | * @param createTime 创建时间 24 | * @param id 事件Id 25 | * @param linkUrl 链接url 26 | * @param title 标题 27 | * @param sort 分类 28 | * @param contentType 内容类型 29 | * @param xOperator X操作符 30 | * */ 31 | class ProtectModel { 32 | String imgUrl; 33 | int modifyTime; 34 | int recordStatus; 35 | int createTime; 36 | String linkUrl; 37 | int id; 38 | int sort; 39 | String title; 40 | int contentType; 41 | String xOperator; 42 | 43 | ProtectModel({this.imgUrl, this.modifyTime, this.recordStatus, this.createTime, this.linkUrl, this.id, this.sort, this.title, this.contentType, this.xOperator}); 44 | 45 | ProtectModel.fromJson(Map json) { 46 | imgUrl = json['imgUrl']; 47 | modifyTime = json['modifyTime']; 48 | recordStatus = json['recordStatus']; 49 | createTime = json['createTime']; 50 | linkUrl = json['linkUrl']; 51 | id = json['id']; 52 | sort = json['sort']; 53 | title = json['title']; 54 | contentType = json['contentType']; 55 | xOperator = json['operator']; 56 | } 57 | 58 | Map toJson() { 59 | final Map data = new Map(); 60 | data['imgUrl'] = this.imgUrl; 61 | data['modifyTime'] = this.modifyTime; 62 | data['recordStatus'] = this.recordStatus; 63 | data['createTime'] = this.createTime; 64 | data['linkUrl'] = this.linkUrl; 65 | data['id'] = this.id; 66 | data['sort'] = this.sort; 67 | data['title'] = this.title; 68 | data['contentType'] = this.contentType; 69 | data['operator'] = this.xOperator; 70 | return data; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/api/protect_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/api/protect_model.dart'; 2 | import 'package:ncov_2019/commom/check.dart'; 3 | export 'package:ncov_2019/api/protect_model.dart'; 4 | import 'package:ncov_2019/http/view_model.dart'; 5 | 6 | ProtectViewModel protectViewModel = new ProtectViewModel(); 7 | 8 | class ProtectViewModel extends ViewModel { 9 | /* 10 | * 最新防护知识 11 | * */ 12 | Future getData() async { 13 | final data = await ProtectReqModel().data(); 14 | 15 | List list = new List(); 16 | 17 | if (listNoEmpty(data)) { 18 | data.forEach((json) => list.add(ProtectModel.fromJson(json))); 19 | } 20 | 21 | return Future.value(list); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/api/rumor_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/config/api.dart'; 2 | import 'package:ncov_2019/http/req_model.dart'; 3 | 4 | /* 5 | * 最新辟谣 - 请求 6 | * */ 7 | class RumorListReqModel extends ReqModel { 8 | @override 9 | String url() => API.getIndexRumorList; 10 | 11 | @override 12 | Map params() => {}; 13 | 14 | Future data() => get(); 15 | } 16 | 17 | /* 18 | * 最新辟谣 - 响应 19 | * 20 | * @param id 事件Id 21 | * @param title 标题 22 | * @param mainSummary 辟谣方 23 | * @param summary 概要 24 | * @param sourceUrl 原文Url 25 | * @param body 详情 26 | * @param rumorType 谣言类型 27 | * */ 28 | class RumorListModel { 29 | String summary; 30 | String sourceUrl; 31 | int score; 32 | int rumorType; 33 | int id; 34 | String mainSummary; 35 | String title; 36 | String body; 37 | bool isOpen; 38 | 39 | RumorListModel({ 40 | this.summary, 41 | this.sourceUrl, 42 | this.score, 43 | this.rumorType, 44 | this.id, 45 | this.mainSummary, 46 | this.title, 47 | this.body, 48 | this.isOpen = false, 49 | }); 50 | 51 | RumorListModel.fromJson(Map json) { 52 | summary = json['summary']; 53 | sourceUrl = json['sourceUrl']; 54 | score = json['score']; 55 | rumorType = json['rumorType']; 56 | id = json['id']; 57 | mainSummary = json['mainSummary']; 58 | title = json['title']; 59 | body = json['body']; 60 | isOpen = false; 61 | } 62 | 63 | Map toJson() { 64 | final Map data = new Map(); 65 | data['summary'] = this.summary; 66 | data['sourceUrl'] = this.sourceUrl; 67 | data['score'] = this.score; 68 | data['rumorType'] = this.rumorType; 69 | data['id'] = this.id; 70 | data['mainSummary'] = this.mainSummary; 71 | data['title'] = this.title; 72 | data['body'] = this.body; 73 | return data; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/api/rumor_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/api/rumor_model.dart'; 2 | export 'package:ncov_2019/api/rumor_model.dart'; 3 | import 'package:ncov_2019/http/view_model.dart'; 4 | import 'package:ncov_2019/commom/commom.dart'; 5 | 6 | RumorListReqViewModel rumorListReqViewModel = new RumorListReqViewModel(); 7 | 8 | class RumorListReqViewModel extends ViewModel { 9 | /* 10 | * 最新辟谣 11 | * */ 12 | Future getRumor() async { 13 | final data = await RumorListReqModel().data(); 14 | 15 | List list = new List(); 16 | 17 | if (listNoEmpty(data)){ 18 | data.forEach((json) => list.add(RumorListModel.fromJson(json))); 19 | } 20 | 21 | return Future.value(list); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/api/statistics_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/config/api.dart'; 2 | import 'package:ncov_2019/http/req_model.dart'; 3 | 4 | /* 5 | * 获取整体统计信息 - 请求 6 | * */ 7 | class StatisticsReqModel extends ReqModel { 8 | @override 9 | String url() => API.getStatisticsService; 10 | 11 | @override 12 | Map params() => {}; 13 | 14 | Future data() => get(); 15 | } 16 | 17 | /* 18 | * 获取整体统计信息 - 响应 19 | * */ 20 | class StatisticsModel { 21 | String summary; 22 | String generalRemark; 23 | int curedCount; 24 | String abroadRemark; 25 | String virus; 26 | int suspectedCount; 27 | String imgUrl; 28 | int confirmedCount; 29 | String infectSource; 30 | int modifyTime; 31 | bool deleted; 32 | String passWay; 33 | int createTime; 34 | String remark5; 35 | String dailyPic; 36 | List dailyPics; 37 | String remark4; 38 | int id; 39 | String countRemark; 40 | int deadCount; 41 | String remark1; 42 | String remark3; 43 | String remark2; 44 | String note1; 45 | String note3; 46 | String note2; 47 | 48 | StatisticsModel({ 49 | this.summary, 50 | this.generalRemark, 51 | this.curedCount, 52 | this.abroadRemark, 53 | this.virus, 54 | this.suspectedCount, 55 | this.imgUrl, 56 | this.confirmedCount, 57 | this.infectSource, 58 | this.modifyTime, 59 | this.deleted, 60 | this.passWay, 61 | this.createTime, 62 | this.remark5, 63 | this.dailyPic, 64 | this.dailyPics, 65 | this.remark4, 66 | this.id, 67 | this.countRemark, 68 | this.deadCount, 69 | this.remark1 = '', 70 | this.remark3, 71 | this.remark2, 72 | this.note1, 73 | this.note2, 74 | this.note3, 75 | }); 76 | 77 | StatisticsModel.fromJson(Map json) { 78 | summary = json['summary']; 79 | generalRemark = json['generalRemark']; 80 | curedCount = json['curedCount']; 81 | abroadRemark = json['abroadRemark']; 82 | virus = json['virus']; 83 | suspectedCount = json['suspectedCount']; 84 | imgUrl = json['imgUrl']; 85 | confirmedCount = json['confirmedCount']; 86 | infectSource = json['infectSource']; 87 | modifyTime = json['modifyTime']; 88 | deleted = json['deleted']; 89 | passWay = json['passWay']; 90 | createTime = json['createTime']; 91 | remark5 = json['remark5']; 92 | dailyPic = json['dailyPic']; 93 | remark4 = json['remark4']; 94 | id = json['id']; 95 | countRemark = json['countRemark']; 96 | deadCount = json['deadCount']; 97 | remark1 = json['remark1']; 98 | remark3 = json['remark3']; 99 | remark2 = json['remark2']; 100 | note1 = json['note1']; 101 | note3 = json['note3']; 102 | note2 = json['note2']; 103 | dailyPics = json['dailyPics']; 104 | } 105 | 106 | Map toJson() { 107 | final Map data = new Map(); 108 | data['summary'] = this.summary; 109 | data['generalRemark'] = this.generalRemark; 110 | data['curedCount'] = this.curedCount; 111 | data['abroadRemark'] = this.abroadRemark; 112 | data['virus'] = this.virus; 113 | data['suspectedCount'] = this.suspectedCount; 114 | data['imgUrl'] = this.imgUrl; 115 | data['confirmedCount'] = this.confirmedCount; 116 | data['infectSource'] = this.infectSource; 117 | data['modifyTime'] = this.modifyTime; 118 | data['deleted'] = this.deleted; 119 | data['passWay'] = this.passWay; 120 | data['createTime'] = this.createTime; 121 | data['remark5'] = this.remark5; 122 | data['dailyPic'] = this.dailyPic; 123 | data['remark4'] = this.remark4; 124 | data['id'] = this.id; 125 | data['countRemark'] = this.countRemark; 126 | data['deadCount'] = this.deadCount; 127 | data['remark1'] = this.remark1; 128 | data['remark3'] = this.remark3; 129 | data['remark2'] = this.remark2; 130 | data['note1'] = this.note1; 131 | data['note3'] = this.note3; 132 | data['note2'] = this.note2; 133 | return data; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /lib/api/statistics_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/api/statistics_model.dart'; 2 | export 'package:ncov_2019/api/statistics_model.dart'; 3 | import 'package:ncov_2019/http/view_model.dart'; 4 | 5 | StatisticsViewModel statisticsViewModel = new StatisticsViewModel(); 6 | 7 | class StatisticsViewModel extends ViewModel { 8 | /* 9 | * 获取整体统计信息 10 | * */ 11 | Future getData() async { 12 | final Map data = await StatisticsReqModel().data(); 13 | 14 | if (data != null && data.isNotEmpty) { 15 | return StatisticsModel.fromJson(data); 16 | } 17 | 18 | return Future.value({}); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/api/version_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/config/api.dart'; 2 | import 'package:ncov_2019/http/req_model.dart'; 3 | 4 | /* 5 | * 版本更新 - 请求 6 | * */ 7 | class VersionReqModel extends ReqModel { 8 | @override 9 | String url() => API.update; 10 | 11 | @override 12 | Map params() => {}; 13 | 14 | Future data() => get(); 15 | } 16 | 17 | /* 18 | * 版本更新 - 响应 19 | * */ 20 | class VersionModel { 21 | String updateInfo; 22 | String appVersion; 23 | String appName; 24 | String appId; 25 | String downloadUrl; 26 | bool force; 27 | int appVersionCode; 28 | 29 | VersionModel({this.updateInfo, this.appVersion, this.appName, this.appId, this.downloadUrl, this.force, this.appVersionCode}); 30 | 31 | VersionModel.fromJson(Map json) { 32 | updateInfo = json['updateInfo']; 33 | appVersion = json['appVersion']; 34 | appName = json['appName']; 35 | appId = json['appId']; 36 | downloadUrl = json['downloadUrl']; 37 | force = json['force']; 38 | appVersionCode = json['appVersionCode']; 39 | } 40 | 41 | Map toJson() { 42 | final Map data = new Map(); 43 | data['updateInfo'] = this.updateInfo; 44 | data['appVersion'] = this.appVersion; 45 | data['appName'] = this.appName; 46 | data['appId'] = this.appId; 47 | data['downloadUrl'] = this.downloadUrl; 48 | data['force'] = this.force; 49 | data['appVersionCode'] = this.appVersionCode; 50 | return data; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/api/version_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/api/version_model.dart'; 2 | import 'package:ncov_2019/http/view_model.dart'; 3 | 4 | VersionViewModel versionViewModel = new VersionViewModel(); 5 | 6 | class VersionViewModel extends ViewModel { 7 | /* 8 | * 版本更新 9 | * */ 10 | Future getData() async { 11 | final Map data = await VersionReqModel().data(); 12 | 13 | if (data != null && data.isNotEmpty) { 14 | return VersionModel.fromJson(data); 15 | } 16 | 17 | return Future.value(null); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:nav_router/nav_router.dart'; 3 | import 'package:ncov_2019/config/config.dart'; 4 | import 'package:ncov_2019/config/const.dart'; 5 | import 'package:ncov_2019/pages/root/root_page.dart'; 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | debugShowCheckedModeBanner: false, 12 | title: title, 13 | navigatorKey: navGK, 14 | theme: ThemeData( 15 | indicatorColor: appBarColor, 16 | scaffoldBackgroundColor: bgColor, 17 | hintColor: Colors.grey.withOpacity(0.3), 18 | splashColor: Colors.transparent, 19 | canvasColor: Colors.transparent, 20 | ), 21 | home: new RootPage(), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/commom/check.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 手机号正则表达式->true匹配 4 | bool isMobilePhoneNumber(String value) { 5 | RegExp mobile = new RegExp(r"(0|86|17951)?(1[0-9][0-9])[0-9]{8}"); 6 | 7 | return mobile.hasMatch(value); 8 | } 9 | 10 | ///验证网页URl 11 | bool isUrl(String value) { 12 | RegExp url = new RegExp(r"^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+"); 13 | 14 | return url.hasMatch(value); 15 | } 16 | 17 | ///校验身份证 18 | bool isIdCard(String value) { 19 | RegExp identity = new RegExp(r"\d{17}[\d|x]|\d{15}"); 20 | 21 | return identity.hasMatch(value); 22 | } 23 | 24 | ///正浮点数 25 | bool isMoney(String value) { 26 | RegExp identity = new RegExp( 27 | r"^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$"); 28 | return identity.hasMatch(value); 29 | } 30 | 31 | ///校验中文 32 | bool isChinese(String value) { 33 | RegExp identity = new RegExp(r"[\u4e00-\u9fa5]"); 34 | 35 | return identity.hasMatch(value); 36 | } 37 | 38 | ///校验支付宝名称 39 | bool isAliPayName(String value) { 40 | RegExp identity = new RegExp(r"[\u4e00-\u9fa5_a-zA-Z]"); 41 | 42 | return identity.hasMatch(value); 43 | } 44 | 45 | /// 字符串不为空 46 | bool strNoEmpty(String value) { 47 | if (value == null) return false; 48 | 49 | return value.trim().isNotEmpty; 50 | } 51 | 52 | /// 字符串不为空 53 | bool mapNoEmpty(Map value) { 54 | if (value == null) return false; 55 | return value.isNotEmpty; 56 | } 57 | 58 | ///判断List是否为空 59 | bool listNoEmpty(List list) { 60 | if (list == null) return false; 61 | 62 | if (list.length == 0) return false; 63 | 64 | return true; 65 | } 66 | 67 | /// 判断是否网络 68 | bool isNetWorkImg(String img) { 69 | return img.startsWith('http') || img.startsWith('https'); 70 | } 71 | 72 | /// 判断是否资源图片 73 | bool isAssetsImg(String img) { 74 | return img.startsWith('asset') || img.startsWith('assets'); 75 | } 76 | 77 | double getMemoryImageCashe() { 78 | return PaintingBinding.instance.imageCache.maximumSize / 1000; 79 | } 80 | 81 | void clearMemoryImageCache() { 82 | PaintingBinding.instance.imageCache.clear(); 83 | } 84 | 85 | String stringAsFixed(value, num) { 86 | double v = double.parse(value.toString()); 87 | String str = ((v * 100).floor() / 100).toStringAsFixed(2); 88 | return str; 89 | } 90 | 91 | String hiddenPhone(String phone){ 92 | String result = ''; 93 | 94 | if(phone != null && phone.length >= 11){ 95 | String sub = phone.substring(0,3); 96 | String end = phone.substring(8,11); 97 | result = '$sub****$end'; 98 | } 99 | 100 | return result; 101 | } 102 | 103 | ///去除后面的0 104 | String stringDisposeWithDouble(v, [fix = 2]) { 105 | double b = double.parse(v.toString()); 106 | String vStr = b.toStringAsFixed(fix); 107 | int len = vStr.length; 108 | for (int i = 0; i < len; i++) { 109 | if (vStr.contains('.') && vStr.endsWith('0')) { 110 | vStr = vStr.substring(0, vStr.length - 1); 111 | } else { 112 | break; 113 | } 114 | } 115 | 116 | if (vStr.endsWith('.')) { 117 | vStr = vStr.substring(0, vStr.length - 1); 118 | } 119 | 120 | return vStr; 121 | } 122 | 123 | ///去除小数点 124 | String removeDot(v) { 125 | String vStr = v.toString().replaceAll('.', ''); 126 | 127 | return vStr; 128 | } -------------------------------------------------------------------------------- /lib/commom/commom.dart: -------------------------------------------------------------------------------- 1 | /// comMom 2 | export 'check.dart'; 3 | export 'ui.dart'; 4 | export 'win_media.dart'; 5 | export 'data/data.dart'; 6 | export 'check.dart'; 7 | export 'date.dart'; 8 | export 'file_util.dart'; 9 | 10 | /// config 11 | export 'package:ncov_2019/config/api.dart'; 12 | export 'package:ncov_2019/config/config.dart'; 13 | export 'package:ncov_2019/config/const.dart'; 14 | export 'package:ncov_2019/config/keys.dart'; 15 | 16 | /// widget 17 | export 'package:ncov_2019/widget/bar/commom_bar.dart'; 18 | export 'package:ncov_2019/widget/view/title_view.dart'; 19 | export 'package:ncov_2019/widget/view/loading_view.dart'; 20 | 21 | /// other 22 | export 'package:nav_router/nav_router.dart'; 23 | export 'package:ncov_2019/widget/view/web_view_page.dart'; 24 | export 'package:cached_network_image/cached_network_image.dart'; 25 | export 'package:connectivity/connectivity.dart'; 26 | import 'package:connectivity/connectivity.dart'; 27 | export 'package:ncov_2019/commom/shared_util.dart'; 28 | 29 | 30 | var subscription = Connectivity(); 31 | -------------------------------------------------------------------------------- /lib/commom/data/data.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/commom/data/store.dart'; 2 | export 'package:ncov_2019/commom/data/store.dart'; 3 | 4 | class NCOVActions { 5 | static String msg() => 'msg'; 6 | 7 | static String voiceImg() => 'voiceImg'; 8 | 9 | static String toTabBarIndex() => 'toTabBarIndex'; 10 | } 11 | 12 | class Data { 13 | static String msg() => Store(NCOVActions.msg()).value = ''; 14 | 15 | static String voiceImg() => Store(NCOVActions.voiceImg()).value = ''; 16 | } 17 | -------------------------------------------------------------------------------- /lib/commom/data/notice.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | typedef Callback(data); 4 | 5 | class Notice { 6 | Notice._(); 7 | 8 | static final _eventMap = >{}; 9 | 10 | static Callback addListener(String event, Callback call) { 11 | var callList = _eventMap[event]; 12 | if (callList == null) { 13 | callList = new List(); 14 | _eventMap[event] = callList; 15 | } 16 | 17 | callList.add(call); 18 | 19 | return call; 20 | } 21 | 22 | static removeListenerByEvent(String event) { 23 | _eventMap.remove(event); 24 | } 25 | 26 | static removeListener(Callback call) { 27 | final keys = _eventMap.keys.toList(growable: false); 28 | for (final k in keys) { 29 | final v = _eventMap[k]; 30 | 31 | final remove = v.remove(call); 32 | if (remove && v.isEmpty) { 33 | _eventMap.remove(k); 34 | } 35 | } 36 | } 37 | 38 | static once(String event, {data}) { 39 | final callList = _eventMap[event]; 40 | 41 | if (callList != null) { 42 | for (final item in new List.from(callList, growable: false)) { 43 | removeListener(item); 44 | 45 | _errorWrap(event, item, data); 46 | } 47 | } 48 | } 49 | 50 | static send(String event, [data]) { 51 | var callList = _eventMap[event]; 52 | 53 | if (callList != null) { 54 | for (final item in callList) { 55 | _errorWrap(event, item, data); 56 | } 57 | } 58 | } 59 | 60 | static _errorWrap(String event, Callback call, data) { 61 | try { 62 | // xlog(() => 'Bus>>>$event>>>$data'); 63 | call(data); 64 | } catch (e) { 65 | // xlog(() => 'Bus>>>$event>>>$e'); 66 | // xlog(() => 'Bus>>>$event>>>$s'); 67 | } 68 | } 69 | } 70 | 71 | mixin BusStateMixin on State { 72 | List _listeners; 73 | 74 | void bus(String event, Callback call) { 75 | _listeners ??= new List(); 76 | _listeners.add(Notice.addListener(event, call)); 77 | } 78 | 79 | void busDel(Callback call) { 80 | if (_listeners.remove(call)) { 81 | Notice.removeListener(call); 82 | } 83 | } 84 | 85 | void busDelAll() { 86 | _listeners?.forEach(Notice.removeListener); 87 | _listeners?.clear(); 88 | } 89 | 90 | @override 91 | void dispose() { 92 | busDelAll(); 93 | 94 | super.dispose(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lib/commom/data/store.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ncov_2019/commom/data/notice.dart'; 3 | export 'package:ncov_2019/commom/data/notice.dart'; 4 | import 'dart:async'; 5 | import 'package:shared_preferences/shared_preferences.dart'; 6 | 7 | typedef Widget StoreBuilder(T item); 8 | 9 | final _storeMap = {}; 10 | 11 | class Store { 12 | final String _action; 13 | 14 | const Store(this._action); 15 | 16 | T get value => _storeMap[_action]; 17 | 18 | set value(T v) { 19 | if (!(v is List) && !(v is Set) && !(v is Map) && v == _storeMap[_action]) 20 | return; 21 | 22 | _storeMap[_action] = v; 23 | 24 | Notice.send('Store::$_action', v); 25 | } 26 | 27 | clear() => dispose(_action); 28 | 29 | notifyListeners() => Notice.send('Store::$_action', _storeMap[_action]); 30 | 31 | static dispose(String action) { 32 | for (final key in _storeMap.keys.toList(growable: false)) { 33 | if (key.startsWith(action)) { 34 | 35 | final v = _storeMap.remove(key); 36 | 37 | Notice.send('Store::$key', null); 38 | Notice.send('Store::$key::dispose', v); 39 | } 40 | } 41 | } 42 | } 43 | 44 | class CacheWidget extends StatefulWidget { 45 | final String action; 46 | final StoreBuilder builder; 47 | final data; 48 | 49 | CacheWidget(this.action, this.builder, {Key key,this.data}) : super(key: key); 50 | 51 | @override 52 | _CacheWidgetState createState() => new _CacheWidgetState(); 53 | } 54 | 55 | class _CacheWidgetState extends State> 56 | with BusStateMixin { 57 | T item; 58 | 59 | void init() { 60 | final action = widget.action; 61 | 62 | item = _storeMap[action] as T; 63 | 64 | bus('Store::$action', onData); 65 | } 66 | 67 | @override 68 | void initState() { 69 | super.initState(); 70 | init(); 71 | widget.builder(item); 72 | } 73 | 74 | @override 75 | void didUpdateWidget(CacheWidget oldWidget) { 76 | super.didUpdateWidget(oldWidget); 77 | busDel(onData); 78 | 79 | init(); 80 | } 81 | 82 | void onData(_) { 83 | if (mounted) Timer.run(() => setState(() => item = _)); 84 | } 85 | 86 | @override 87 | Widget build(BuildContext context) => widget.builder(item); 88 | } 89 | 90 | storeString(String k,v) async { 91 | SharedPreferences prefs = await SharedPreferences.getInstance(); 92 | prefs.setString(k, v); 93 | } 94 | 95 | Future getStoreValue(String k) async { 96 | SharedPreferences prefs = await SharedPreferences.getInstance(); 97 | return prefs.get(k); 98 | } 99 | -------------------------------------------------------------------------------- /lib/commom/date.dart: -------------------------------------------------------------------------------- 1 | import 'package:intl/intl.dart'; 2 | import 'package:ncov_2019/commom/check.dart'; 3 | 4 | class DateTimeForMater { 5 | static String full = "yyyy-MM-dd HH:mm:ss"; 6 | 7 | static String formatDateV(DateTime dateTime, {bool isUtc, String format}) { 8 | if (dateTime == null) return ""; 9 | format = format ?? full; 10 | if (format.contains("yy")) { 11 | String year = dateTime.year.toString(); 12 | if (format.contains("yyyy")) { 13 | format = format.replaceAll("yyyy", year); 14 | } else { 15 | format = format.replaceAll( 16 | "yy", year.substring(year.length - 2, year.length)); 17 | } 18 | } 19 | 20 | format = _comFormat(dateTime.month, format, 'M', 'MM'); 21 | format = _comFormat(dateTime.day, format, 'd', 'dd'); 22 | format = _comFormat(dateTime.hour, format, 'H', 'HH'); 23 | format = _comFormat(dateTime.minute, format, 'm', 'mm'); 24 | format = _comFormat(dateTime.second, format, 's', 'ss'); 25 | format = _comFormat(dateTime.millisecond, format, 'S', 'SSS'); 26 | 27 | return format; 28 | } 29 | 30 | static String _comFormat( 31 | int value, String format, String single, String full) { 32 | if (format.contains(single)) { 33 | if (format.contains(full)) { 34 | format = 35 | format.replaceAll(full, value < 10 ? '0$value' : value.toString()); 36 | } else { 37 | format = format.replaceAll(single, value.toString()); 38 | } 39 | } 40 | return format; 41 | } 42 | } 43 | 44 | String formatTimeStampToString(timestamp, [format]) { 45 | assert(timestamp != null); 46 | 47 | int time = 0; 48 | 49 | if (timestamp is int) { 50 | time = timestamp; 51 | } else { 52 | time = int.parse(timestamp.toString()); 53 | } 54 | 55 | if (format == null) { 56 | format = 'yyyy-MM-dd HH:mm:ss'; 57 | } 58 | 59 | DateFormat dateFormat = new DateFormat(format); 60 | 61 | var date = new DateTime.fromMillisecondsSinceEpoch(time * 1000); 62 | 63 | return dateFormat.format(date); 64 | } 65 | 66 | String timeHandle(int time) { 67 | double createTimeDouble = strNoEmpty('$time') ? time / 1000 : 0; 68 | int createTime = int.parse('${stringDisposeWithDouble(createTimeDouble)}'); 69 | return '${formatTimeStampToString(createTime) ?? '未知'}'; 70 | } 71 | -------------------------------------------------------------------------------- /lib/commom/file_util.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:ncov_2019/config/api.dart'; 6 | import 'package:ncov_2019/config/config.dart'; 7 | import 'package:path_provider/path_provider.dart'; 8 | 9 | class FileUtil { 10 | static FileUtil _instance; 11 | 12 | static FileUtil getInstance() { 13 | if (_instance == null) { 14 | _instance = FileUtil._internal(); 15 | } 16 | return _instance; 17 | } 18 | 19 | FileUtil._internal(); 20 | 21 | Future getSavePath(String endPath) async { 22 | Directory tempDir = await getApplicationDocumentsDirectory(); 23 | String path = tempDir.path + endPath; 24 | Directory directory = Directory(path); 25 | if (!directory.existsSync()) { 26 | directory.createSync(recursive: true); 27 | } 28 | return path; 29 | } 30 | 31 | void copyFile(String oldPath, String newPath) { 32 | File file = File(oldPath); 33 | if (file.existsSync()) { 34 | file.copy(newPath); 35 | } 36 | } 37 | 38 | Future> getDirChildren(String path) async { 39 | Directory directory = Directory(path); 40 | final childrenDir = directory.listSync(); 41 | List pathList = []; 42 | for (var o in childrenDir) { 43 | final filename = o.path.split("/").last; 44 | if (filename.contains(".")) { 45 | pathList.add(o.path); 46 | } 47 | } 48 | return pathList; 49 | } 50 | 51 | ///[assetPath] 例子 'images/' 52 | ///[assetName] 例子 '1.jpg' 53 | ///[filePath] 例子:'/myFile/' 54 | ///[fileName] 例子 'girl.jpg' 55 | Future copyAssetToFile(String assetPath, String assetName, 56 | String filePath, String fileName) async { 57 | String newPath = await FileUtil.getInstance().getSavePath(filePath); 58 | String name = fileName; 59 | bool exists = await new File(newPath + name).exists(); 60 | if (!exists) { 61 | var data = await rootBundle.load(assetPath + assetName); 62 | List bytes = 63 | data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); 64 | await File(newPath + name).writeAsBytes(bytes); 65 | return newPath + name; 66 | } else 67 | return newPath + name; 68 | } 69 | 70 | void downloadFile( 71 | {String url, 72 | String filePath, 73 | String fileName, 74 | Function onComplete}) async { 75 | final path = await FileUtil.getInstance().getSavePath(filePath); 76 | String name = fileName ?? url.split("/").last; 77 | 78 | Dio _client; 79 | if (_client == null) { 80 | BaseOptions options = new BaseOptions(); 81 | options.connectTimeout = connectTimeOut; 82 | options.receiveTimeout = receiveTimeOut; 83 | options.headers = const {'Content-Type': 'application/json'}; 84 | options.baseUrl = API.reqUrl; 85 | _client = new Dio(options); 86 | } 87 | 88 | if (_client != null) 89 | _client.download( 90 | url, 91 | path + name, 92 | onReceiveProgress: (int count, int total) { 93 | final downloadProgress = ((count / total) * 100).toInt(); 94 | if (downloadProgress == 100) { 95 | if (onComplete != null) onComplete(path + name); 96 | } 97 | }, 98 | options: Options(sendTimeout: 15 * 1000, receiveTimeout: 360 * 1000), 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /lib/commom/shared_util.dart: -------------------------------------------------------------------------------- 1 | import 'package:ncov_2019/config/keys.dart'; 2 | export 'package:ncov_2019/config/keys.dart'; 3 | import 'package:ncov_2019/config/storage_manager.dart'; 4 | 5 | class SharedUtil { 6 | factory SharedUtil() => _getInstance(); 7 | 8 | static SharedUtil get instance => _getInstance(); 9 | static SharedUtil _instance; 10 | 11 | SharedUtil._internal() { 12 | //初始化 13 | //init 14 | } 15 | 16 | static SharedUtil _getInstance() { 17 | if (_instance == null) { 18 | _instance = new SharedUtil._internal(); 19 | } 20 | return _instance; 21 | } 22 | 23 | 24 | /// save 25 | Future saveString(String key, String value) async { 26 | if (key == Keys.account) { 27 | await StorageManager.sp.setString(key, value); 28 | return; 29 | } 30 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 31 | await StorageManager.sp.setString(key + account, value); 32 | } 33 | 34 | Future saveInt(String key, int value) async { 35 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 36 | await StorageManager.sp.setInt(key + account, value); 37 | } 38 | 39 | Future saveDouble(String key, double value) async { 40 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 41 | await StorageManager.sp.setDouble(key + account, value); 42 | } 43 | 44 | Future saveBoolean(String key, bool value) async { 45 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 46 | await StorageManager.sp.setBool(key + account, value); 47 | } 48 | 49 | Future saveStringList(String key, List list) async { 50 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 51 | await StorageManager.sp.setStringList(key + account, list); 52 | } 53 | 54 | Future readAndSaveList(String key, String data) async { 55 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 56 | List strings = StorageManager.sp.getStringList(key + account) ?? []; 57 | if (strings.length >= 10) return false; 58 | strings.add(data); 59 | await StorageManager.sp.setStringList(key + account, strings); 60 | return true; 61 | } 62 | 63 | void readAndExchangeList(String key, String data, int index) async { 64 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 65 | List strings = StorageManager.sp.getStringList(key + account) ?? []; 66 | strings[index] = data; 67 | await StorageManager.sp.setStringList(key + account, strings); 68 | } 69 | 70 | void readAndRemoveList(String key, int index) async { 71 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 72 | List strings = StorageManager.sp.getStringList(key + account) ?? []; 73 | strings.removeAt(index); 74 | await StorageManager.sp.setStringList(key + account, strings); 75 | } 76 | 77 | /// get 78 | Future getString(String key) async { 79 | if (key == Keys.account) { 80 | return StorageManager.sp.getString(key); 81 | } 82 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 83 | return StorageManager.sp.getString(key + account); 84 | } 85 | 86 | Future getInt(String key) async { 87 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 88 | return StorageManager.sp.getInt(key + account); 89 | } 90 | 91 | Future getDouble(String key) async { 92 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 93 | return StorageManager.sp.getDouble(key + account); 94 | } 95 | 96 | Future getBoolean(String key) async { 97 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 98 | return StorageManager.sp.getBool(key + account) ?? false; 99 | } 100 | 101 | Future> getStringList(String key) async { 102 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 103 | return StorageManager.sp.getStringList(key + account); 104 | } 105 | 106 | Future> readList(String key) async { 107 | String account = StorageManager.sp.getString(Keys.account) ?? "default"; 108 | List strings = StorageManager.sp.getStringList(key + account) ?? []; 109 | return strings; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /lib/commom/ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class HorizontalLine extends StatelessWidget { 4 | final double height; 5 | final Color color; 6 | final double horizontal; 7 | 8 | HorizontalLine({ 9 | this.height = 0.5, 10 | this.color = const Color(0xFFEEEEEE), 11 | this.horizontal = 0.0, 12 | }); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return new Container( 17 | height: height, 18 | color: color, 19 | margin: new EdgeInsets.symmetric(horizontal: horizontal), 20 | ); 21 | } 22 | } 23 | 24 | class VerticalLine extends StatelessWidget { 25 | final double width; 26 | final double height; 27 | final Color color; 28 | final double vertical; 29 | 30 | VerticalLine({ 31 | this.width = 1.0, 32 | this.height = 25, 33 | this.color = const Color.fromRGBO(209, 209, 209, 0.5), 34 | this.vertical = 0.0, 35 | }); 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return new Container( 40 | width: width, 41 | color: Color(0xffDCE0E5), 42 | margin: new EdgeInsets.symmetric(vertical: vertical), 43 | height: height, 44 | ); 45 | } 46 | } 47 | 48 | class Space extends StatelessWidget { 49 | final double width; 50 | final double height; 51 | 52 | Space({this.width = 10.0, this.height = 10.0}); 53 | 54 | @override 55 | Widget build(BuildContext context) { 56 | return new Container(width: width, height: height); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/commom/win_media.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | double winWidth(BuildContext context) { 6 | return MediaQuery.of(context).size.width; 7 | } 8 | 9 | double winHeight(BuildContext context) { 10 | return MediaQuery.of(context).size.height; 11 | } 12 | 13 | double winTop(BuildContext context) { 14 | return MediaQuery.of(context).padding.top; 15 | } 16 | 17 | double winBottom(BuildContext context) { 18 | return MediaQuery.of(context).padding.bottom; 19 | } 20 | 21 | double winLeft(BuildContext context) { 22 | return MediaQuery.of(context).padding.left; 23 | } 24 | 25 | double winRight(BuildContext context) { 26 | return MediaQuery.of(context).padding.right; 27 | } 28 | 29 | double winKeyHeight(BuildContext context) { 30 | return MediaQuery.of(context).viewInsets.bottom; 31 | } 32 | 33 | double statusBarHeight(BuildContext context) { 34 | return MediaQueryData.fromWindow(window).padding.top; 35 | } 36 | 37 | double navigationBarHeight(BuildContext context) { 38 | return kToolbarHeight; 39 | } 40 | 41 | double topBarHeight(BuildContext context) { 42 | return kToolbarHeight + MediaQueryData.fromWindow(window).padding.top; 43 | } 44 | -------------------------------------------------------------------------------- /lib/config/api.dart: -------------------------------------------------------------------------------- 1 | class API { 2 | // 请求的url 3 | static const reqUrl = 'http://49.232.173.220:3001'; 4 | 5 | // 按时间线获取事件 6 | static const timelineService = '/data/getTimelineService'; 7 | 8 | // 最新辟谣 9 | static const getIndexRumorList = '/data/getIndexRumorList'; 10 | 11 | // 最新防护知识 12 | static const getIndexRecommendList = '/data/getIndexRecommendList'; 13 | 14 | // 最新知识百科 15 | static const getWikiList = '/data/getWikiList'; 16 | 17 | // 获取整体统计信息 18 | static const getStatisticsService = '/data/getStatisticsService'; 19 | 20 | // 获取省份信息 21 | static const getAreaStat = '/data/getAreaStat'; 22 | 23 | // 诊疗信息 24 | static const getEntries = '/data/getEntries'; 25 | 26 | // 版本更新 27 | static const update = '/app/update'; 28 | } 29 | -------------------------------------------------------------------------------- /lib/config/config.dart: -------------------------------------------------------------------------------- 1 | /// app名字 2 | const String title = 'ncov-2019'; 3 | 4 | ///连接超时时间为5秒 5 | const int connectTimeOut = 5 * 1000; 6 | 7 | ///响应超时时间为7秒 8 | const int receiveTimeOut = 7 * 1000; -------------------------------------------------------------------------------- /lib/config/const.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | const appBarColor = Color(0xff4169e2); 4 | 5 | const Color fixedColor = Colors.blue; 6 | 7 | const bgColor = Color(0xfff7f7f7); 8 | 9 | const mainSpace = 10.0; 10 | 11 | const mainLineWidth = 0.3; 12 | 13 | const lineColor = Colors.grey; 14 | 15 | const mainTextColor = Color.fromRGBO(115, 115, 115, 1.0); 16 | 17 | const defImg = 'http://www.flutterj.com/content/templates/emlog_dux/images/random/1.jpg'; -------------------------------------------------------------------------------- /lib/config/keys.dart: -------------------------------------------------------------------------------- 1 | class Keys { 2 | static final String account = "account"; 3 | } 4 | -------------------------------------------------------------------------------- /lib/config/storage_manager.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | class StorageManager { 4 | /// app全局配置 5 | static SharedPreferences sp; 6 | 7 | /// 网络连接 8 | var connect; 9 | 10 | /// 必备数据的初始化操作 11 | static init() async { 12 | // async 异步操作 13 | // sync 同步操作 14 | sp = await SharedPreferences.getInstance(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/http/req_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:ncov_2019/commom/commom.dart'; 5 | import 'package:ncov_2019/config/api.dart'; 6 | import 'package:ncov_2019/config/config.dart'; 7 | 8 | // 请求计数 9 | var _id = 0; 10 | 11 | /* 12 | * 请求类型枚举 13 | * */ 14 | enum RequestType { GET, POST } 15 | 16 | class ReqModel { 17 | // 请求url路径 18 | String url() => null; 19 | 20 | // 请求参数 21 | Map params() => {}; 22 | 23 | /* 24 | * get请求 25 | * */ 26 | Future get() async { 27 | return this._request( 28 | url: url(), 29 | method: RequestType.GET, 30 | params: params(), 31 | ); 32 | } 33 | 34 | /* 35 | * post请求 36 | * */ 37 | Future post() async { 38 | return this._request( 39 | url: url(), 40 | method: RequestType.POST, 41 | params: params(), 42 | ); 43 | } 44 | 45 | /* 46 | * post请求-文件上传方式 47 | * */ 48 | Future postUpload( 49 | ProgressCallback progressCallBack, { 50 | FormData formData, 51 | }) async { 52 | return this._request( 53 | url: url(), 54 | method: RequestType.POST, 55 | formData: formData, 56 | progressCallBack: progressCallBack, 57 | params: params(), 58 | ); 59 | } 60 | 61 | /* 62 | * 请求方法 63 | * */ 64 | Future _request({ 65 | String url, 66 | RequestType method, 67 | Map params, 68 | FormData formData, 69 | ProgressCallback progressCallBack, 70 | }) async { 71 | Dio _client; 72 | 73 | final httpUrl = '${API.reqUrl}$url'; 74 | 75 | if (_client == null) { 76 | BaseOptions options = new BaseOptions(); 77 | options.connectTimeout = connectTimeOut; 78 | options.receiveTimeout = receiveTimeOut; 79 | options.headers = const {'Content-Type': 'application/json'}; 80 | options.baseUrl = API.reqUrl; 81 | _client = new Dio(options); 82 | } 83 | 84 | final id = _id++; 85 | int statusCode; 86 | try { 87 | Response response; 88 | if (method == RequestType.GET) { 89 | ///组合GET请求的参数 90 | if (mapNoEmpty(params)) { 91 | response = await _client.get( 92 | url, 93 | queryParameters: params, 94 | ); 95 | } else { 96 | response = await _client.get( 97 | url, 98 | ); 99 | } 100 | } else { 101 | if (mapNoEmpty(params) && formData != null) { 102 | response = await _client.post( 103 | url, 104 | data: formData ?? params, 105 | onSendProgress: progressCallBack, 106 | ); 107 | } else { 108 | response = await _client.post( 109 | url, 110 | ); 111 | } 112 | } 113 | 114 | statusCode = response.statusCode; 115 | 116 | if (response != null) { 117 | print('HTTP_REQUEST_URL::[$id]::$httpUrl'); 118 | if (mapNoEmpty(params)) { 119 | print('HTTP_REQUEST_BODY::[$id]::${json.encode(params)}'); 120 | } 121 | print('HTTP_RESPONSE_BODY::[$id]::${json.encode(response.data)}'); 122 | return response.data; 123 | } 124 | 125 | ///处理错误部分 126 | if (statusCode < 0) { 127 | return _handError(statusCode); 128 | } 129 | } catch (e) { 130 | return _handError(statusCode); 131 | } 132 | } 133 | 134 | ///处理异常 135 | static Future _handError(int statusCode) { 136 | String errorMsg = 'Network request error'; 137 | Map errorMap = {"errorMsg": errorMsg, "errorCode": statusCode}; 138 | 139 | print("HTTP_RESPONSE_ERROR::$errorMsg code:$statusCode"); 140 | return Future.value(errorMap); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /lib/http/view_model.dart: -------------------------------------------------------------------------------- 1 | class ViewModel { 2 | List dataListToModel(List data, model) { 3 | List list = new List(); 4 | 5 | data.forEach((json) => list.add(model.fromJson(json))); 6 | 7 | return list; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:ncov_2019/app.dart'; 6 | import 'package:ncov_2019/config/storage_manager.dart'; 7 | 8 | /* 9 | * App入口 10 | * */ 11 | void main() async { 12 | /// 确保初始化 13 | WidgetsFlutterBinding.ensureInitialized(); 14 | 15 | /// 配置初始化 16 | await StorageManager.init(); 17 | 18 | /// App入口 19 | runApp( 20 | new ColorFiltered( 21 | colorFilter: ColorFilter.mode(Colors.transparent, BlendMode.color), 22 | child: new MyApp(), 23 | ), 24 | ); 25 | 26 | /// 自定义报错页面 27 | ErrorWidget.builder = (FlutterErrorDetails flutterErrorDetails) { 28 | debugPrint(flutterErrorDetails.toString()); 29 | return new Center(child: new Text("App错误,快去反馈给作者!")); 30 | }; 31 | 32 | /// Android状态栏透明 33 | if (Platform.isAndroid) { 34 | SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle( 35 | statusBarColor: Colors.transparent, 36 | statusBarBrightness: Brightness.light, 37 | ); 38 | SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/pages/home/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:ncov_2019/api/entries_view_model.dart'; 4 | import 'package:ncov_2019/api/news_model.dart'; 5 | import 'package:ncov_2019/api/news_view_model.dart'; 6 | import 'package:ncov_2019/api/statistics_view_model.dart'; 7 | import 'package:ncov_2019/commom/commom.dart'; 8 | import 'package:ncov_2019/widget/card/news_card.dart'; 9 | import 'package:ncov_2019/widget/item/entries.dart'; 10 | import 'package:ncov_2019/widget/item/statics.dart'; 11 | import 'package:pull_to_refresh/pull_to_refresh.dart'; 12 | 13 | class HomePage extends StatefulWidget { 14 | @override 15 | _HomePageState createState() => _HomePageState(); 16 | } 17 | 18 | class _HomePageState extends State 19 | with AutomaticKeepAliveClientMixin { 20 | RefreshController _refreshController = 21 | RefreshController(initialRefresh: false); 22 | 23 | bool isReq = false; 24 | 25 | List data = new List(); 26 | 27 | // List entriesData = new List(); 28 | // 29 | // StatisticsModel statisticsModel = new StatisticsModel(); 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | Notice.addListener(NCOVActions.toTabBarIndex(), (index) { 35 | if (!listNoEmpty(data)) getData(); 36 | }); 37 | getData(); 38 | } 39 | 40 | @override 41 | bool get wantKeepAlive => true; 42 | 43 | getData() { 44 | timeNewsViewModel.getTimeNews().then((v) { 45 | setState(() { 46 | data = v; 47 | isReq = true; 48 | }); 49 | }); 50 | // statisticsViewModel.getData().then((v) { 51 | // setState(() => statisticsModel = v); 52 | // }); 53 | // entriesViewModel.getData().then((v) { 54 | // setState(() => entriesData = v); 55 | // }); 56 | } 57 | 58 | Future _refreshData() async { 59 | final Completer completer = new Completer(); 60 | 61 | getData(); 62 | 63 | new Future.delayed(new Duration(seconds: 2), () { 64 | completer.complete(null); 65 | _refreshController.refreshCompleted(); 66 | }); 67 | 68 | return completer.future; 69 | } 70 | 71 | Widget buildItem(item) { 72 | TimeNewsModel model = item; 73 | bool isNew = model.id == data[0].id; 74 | return new NewsCard( 75 | model, 76 | padding: EdgeInsets.only( 77 | left: 20.0, 78 | right: 20.0, 79 | top: isNew ? 10.0 : 10, 80 | bottom: model.id == data[data.length - 1].id ? 20.0 : 10, 81 | ), 82 | isNew: isNew, 83 | ); 84 | } 85 | 86 | @override 87 | Widget build(BuildContext context) { 88 | super.build(context); 89 | return new Scaffold( 90 | body: new SmartRefresher( 91 | controller: _refreshController, 92 | onRefresh: _refreshData, 93 | child: isReq 94 | ? listNoEmpty(data) 95 | ? new ListView.builder( 96 | itemBuilder: (context, index) { 97 | TimeNewsModel model = data[index]; 98 | bool isNew = model.id == data[0].id; 99 | return new NewsCard( 100 | model, 101 | padding: EdgeInsets.only( 102 | left: 20.0, 103 | right: 20.0, 104 | top: isNew ? 10.0 : 10, 105 | bottom: 106 | model.id == data[data.length - 1].id ? 20.0 : 10, 107 | ), 108 | isNew: isNew, 109 | ); 110 | }, 111 | itemCount: data.length, 112 | ) 113 | : new Center( 114 | child: new Text( 115 | '暂无数据', 116 | style: Theme.of(context).textTheme.display1, 117 | ), 118 | ) 119 | : new LoadingView(), 120 | // child: new ListView( 121 | // children: [ 122 | // new Space(), 123 | // new TitleView( 124 | // '全国统计', 125 | // subTitle: '${timeHandle(statisticsModel?.modifyTime ?? 0)}', 126 | // ), 127 | // new Statics(statisticsModel), 128 | // new Divider(), 129 | // new Space(height: mainSpace / 2), 130 | // new Visibility( 131 | // visible: strNoEmpty(statisticsModel?.imgUrl ?? ''), 132 | // child: new TitleView('疫情地图', subTitle: '数据来源:国家及各省市地区卫健委'), 133 | // ), 134 | // new Visibility( 135 | // visible: strNoEmpty(statisticsModel?.imgUrl ?? ''), 136 | // child: new Padding( 137 | // padding: EdgeInsets.only(top: 10.0), 138 | // child: new CachedNetworkImage( 139 | // imageUrl: statisticsModel?.imgUrl ?? defImg), 140 | // ), 141 | // ), 142 | // new Visibility( 143 | // visible: strNoEmpty(statisticsModel?.dailyPic ?? ''), 144 | // child: new Padding( 145 | // padding: EdgeInsets.only(bottom: 10.0), 146 | // child: new CachedNetworkImage( 147 | // imageUrl: statisticsModel?.dailyPic ?? defImg), 148 | // ), 149 | // ), 150 | // new Space(), 151 | // new TitleView('诊疗'), 152 | // new Container( 153 | // margin: EdgeInsets.symmetric(horizontal: 10.0), 154 | // child: new Wrap( 155 | // children: entriesData.map((item) { 156 | // EntriesModel model = item; 157 | // return Entries(model); 158 | // }).toList(), 159 | // ), 160 | // ), 161 | // new TitleView('最新消息', subTitle: '消息数量:${data.length}'), 162 | // listNoEmpty(data) 163 | // ? new Column(children: data.map(buildItem).toList()) 164 | // : new Center( 165 | // child: new Text( 166 | // '暂无数据', 167 | // style: Theme.of(context).textTheme.display1, 168 | // ), 169 | // ) 170 | // ], 171 | // ), 172 | ), 173 | ); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /lib/pages/lore/lore_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:ncov_2019/api/lore_view_model.dart'; 5 | import 'package:ncov_2019/commom/commom.dart'; 6 | import 'package:ncov_2019/widget/card/lore_card.dart'; 7 | import 'package:pull_to_refresh/pull_to_refresh.dart'; 8 | 9 | class LorePage extends StatefulWidget { 10 | @override 11 | _LorePageState createState() => _LorePageState(); 12 | } 13 | 14 | class _LorePageState extends State 15 | with AutomaticKeepAliveClientMixin { 16 | RefreshController _refreshController = 17 | RefreshController(initialRefresh: false); 18 | 19 | List data = new List(); 20 | 21 | bool isReq = false; 22 | 23 | @override 24 | void initState() { 25 | super.initState(); 26 | Notice.addListener(NCOVActions.toTabBarIndex(), (index) { 27 | if (!listNoEmpty(data)) getData(); 28 | }); 29 | getData(); 30 | } 31 | 32 | @override 33 | bool get wantKeepAlive => true; 34 | 35 | getData() { 36 | loreViewModel.getLore().then((v) { 37 | setState(() { 38 | data = v; 39 | isReq = true; 40 | }); 41 | }); 42 | } 43 | 44 | Future _refreshData() async { 45 | final Completer completer = new Completer(); 46 | 47 | getData(); 48 | 49 | new Future.delayed(new Duration(seconds: 2), () { 50 | completer.complete(null); 51 | _refreshController.refreshCompleted(); 52 | }); 53 | 54 | return completer.future; 55 | } 56 | 57 | Widget buildItem(context, index) { 58 | LoreModel model = data[index]; 59 | return new LoreCard( 60 | model, 61 | margin: EdgeInsets.only( 62 | left: 10.0, 63 | right: 10.0, 64 | top: model.id == data[0].id ? 10.0 : 0, 65 | bottom: model.id == data[data.length - 1].id ? 10.0 : 0, 66 | ), 67 | ); 68 | } 69 | 70 | @override 71 | Widget build(BuildContext context) { 72 | super.build(context); 73 | return new Scaffold( 74 | body: new SmartRefresher( 75 | controller: _refreshController, 76 | onRefresh: _refreshData, 77 | child: isReq 78 | ? listNoEmpty(data) 79 | ? new ListView.builder( 80 | itemBuilder: buildItem, 81 | itemCount: data.length, 82 | ) 83 | : new Center( 84 | child: new Text( 85 | '暂无数据', 86 | style: Theme.of(context).textTheme.display1, 87 | ), 88 | ) 89 | : new LoadingView(), 90 | ), 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/pages/protect/protect_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:ncov_2019/api/area_view_model.dart'; 5 | import 'package:ncov_2019/api/protect_view_model.dart'; 6 | import 'package:ncov_2019/api/statistics_view_model.dart'; 7 | import 'package:ncov_2019/commom/commom.dart'; 8 | import 'package:ncov_2019/widget/card/protect_card.dart'; 9 | import 'package:ncov_2019/widget/flutter/my_expansion_tile.dart'; 10 | import 'package:ncov_2019/widget/item/statics.dart'; 11 | import 'package:ncov_2019/widget/view/title_view.dart'; 12 | import 'package:pull_to_refresh/pull_to_refresh.dart'; 13 | 14 | class ProtectPage extends StatefulWidget { 15 | @override 16 | _ProtectPageState createState() => _ProtectPageState(); 17 | } 18 | 19 | class _ProtectPageState extends State 20 | with AutomaticKeepAliveClientMixin { 21 | RefreshController _refreshController = 22 | RefreshController(initialRefresh: false); 23 | 24 | List data = new List(); 25 | List areaData = new List(); 26 | 27 | bool isReq = false; 28 | 29 | @override 30 | void initState() { 31 | super.initState(); 32 | Notice.addListener(NCOVActions.toTabBarIndex(), (index) { 33 | if (!listNoEmpty(data)) getData(); 34 | }); 35 | getData(); 36 | } 37 | 38 | @override 39 | bool get wantKeepAlive => true; 40 | 41 | getData() { 42 | protectViewModel.getData().then((v) { 43 | setState(() { 44 | data = v; 45 | isReq = true; 46 | }); 47 | }); 48 | areaViewModel.getData().then((v) { 49 | setState(() => areaData = v); 50 | }); 51 | } 52 | 53 | Future _refreshData() async { 54 | final Completer completer = new Completer(); 55 | 56 | getData(); 57 | 58 | new Future.delayed(new Duration(seconds: 2), () { 59 | completer.complete(null); 60 | _refreshController.refreshCompleted(); 61 | }); 62 | 63 | return completer.future; 64 | } 65 | 66 | Widget buildItem(item) { 67 | ProtectModel model = item; 68 | return new ProtectCard( 69 | model, 70 | margin: EdgeInsets.only( 71 | left: 10.0, 72 | right: 10.0, 73 | top: model.id == data[0].id ? 0.0 : 0, 74 | bottom: model.id == data[data.length - 1].id ? 10.0 : 0, 75 | ), 76 | ); 77 | } 78 | 79 | Widget _buildCity(item) { 80 | AreaModelCity model = item; 81 | return new Padding( 82 | padding: EdgeInsets.symmetric(horizontal: 20.0), 83 | child: new Row( 84 | children: [ 85 | '${model?.cityName ?? '未知'}', 86 | '${model?.confirmedCount ?? 0}', 87 | '${model?.deadCount ?? 0}', 88 | '${model?.curedCount ?? 0}' 89 | ].map((item) { 90 | return new Container( 91 | padding: EdgeInsets.only(right: 10.0), 92 | width: (winWidth(context) - 80) / 4, 93 | child: 94 | new Text(item, style: TextStyle(fontWeight: FontWeight.w600)), 95 | ); 96 | }).toList(), 97 | ), 98 | ); 99 | } 100 | 101 | Widget areaBuild(item) { 102 | AreaModel model = item; 103 | return new MyExpansionTile( 104 | title: new Row( 105 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 106 | children: [ 107 | '${model?.provinceName ?? '未知'}', 108 | '${model?.confirmedCount ?? 0}', 109 | '${model?.deadCount ?? 0}', 110 | '${model?.curedCount ?? 0}' 111 | ].map((item) { 112 | return new Container( 113 | padding: EdgeInsets.only(right: 10.0), 114 | width: (winWidth(context) - 80) / 4, 115 | child: 116 | new Text(item, style: TextStyle(fontWeight: FontWeight.w600)), 117 | ); 118 | }).toList(), 119 | ), 120 | children: model.cities.map(_buildCity).toList(), 121 | ); 122 | } 123 | 124 | @override 125 | Widget build(BuildContext context) { 126 | super.build(context); 127 | return new Scaffold( 128 | body: new SmartRefresher( 129 | controller: _refreshController, 130 | onRefresh: _refreshData, 131 | child: new SingleChildScrollView( 132 | child: new Column( 133 | crossAxisAlignment: CrossAxisAlignment.start, 134 | children: [ 135 | new Space(), 136 | new TitleView('地区统计'), 137 | new Space(), 138 | new Container( 139 | margin: EdgeInsets.symmetric(horizontal: 20.0), 140 | padding: EdgeInsets.only(right: 40), 141 | child: new Row( 142 | mainAxisAlignment: MainAxisAlignment.spaceAround, 143 | children: ['地区', '确诊', '死亡', '治愈'].map((item) { 144 | return new SizedBox( 145 | width: (winWidth(context) - 80) / 4, 146 | child: new Text( 147 | item, 148 | style: TextStyle(fontWeight: FontWeight.w600), 149 | ), 150 | ); 151 | }).toList(), 152 | ), 153 | ), 154 | new Column(children: areaData.map(areaBuild).toList()), 155 | new Divider(), 156 | new Space(height: mainSpace / 2), 157 | new TitleView('防护知识'), 158 | isReq 159 | ? listNoEmpty(data) 160 | ? new Column(children: data.map(buildItem).toList()) 161 | : new Center( 162 | child: new Text( 163 | '暂无数据', 164 | style: Theme.of(context).textTheme.display1, 165 | ), 166 | ) 167 | : new LoadingView(), 168 | ], 169 | ), 170 | ), 171 | ), 172 | ); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /lib/pages/root/root_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:ncov_2019/api/version_model.dart'; 5 | import 'package:ncov_2019/api/version_view_model.dart'; 6 | import 'package:ncov_2019/commom/commom.dart'; 7 | import 'package:ncov_2019/pages/home/home_page.dart'; 8 | import 'package:ncov_2019/pages/lore/lore_page.dart'; 9 | import 'package:ncov_2019/pages/protect/protect_page.dart'; 10 | import 'package:ncov_2019/pages/rumor/rumor_page.dart'; 11 | import 'package:ncov_2019/widget/dialog/update_dialog.dart'; 12 | import 'package:ncov_2019/widget/root_tabbar.dart'; 13 | import 'package:package_info/package_info.dart'; 14 | 15 | class RootPage extends StatefulWidget { 16 | @override 17 | _RootPageState createState() => _RootPageState(); 18 | } 19 | 20 | class _RootPageState extends State { 21 | @override 22 | void initState() { 23 | super.initState(); 24 | checkVersion(); 25 | } 26 | 27 | /// 检查更新 [check update] 28 | checkVersion() async { 29 | if (Platform.isIOS) return; 30 | 31 | final packageInfo = await PackageInfo.fromPlatform(); 32 | 33 | VersionModel model = await versionViewModel.getData(); 34 | 35 | int currentVersion = int.parse(removeDot(packageInfo.version)); 36 | 37 | int netVersion = int.parse(removeDot(model.appVersion)); 38 | 39 | if (currentVersion >= netVersion) { 40 | debugPrint('当前版本是最新版本'); 41 | return; 42 | } 43 | 44 | showDialog( 45 | context: context, 46 | builder: (ctx2) { 47 | return UpdateDialog( 48 | version: model.appVersion, 49 | updateUrl: model.downloadUrl, 50 | updateInfo: model.updateInfo, 51 | isForce: model.force, 52 | ); 53 | }, 54 | ); 55 | } 56 | 57 | @override 58 | Widget build(BuildContext context) { 59 | List pages = [ 60 | new TabBarModel( 61 | title: '首页', 62 | icon: new LoadImage("assets/images/bottom_home.png", false), 63 | selectIcon: new LoadImage("assets/images/bottom_home.png", true), 64 | page: new HomePage(), 65 | ), 66 | new TabBarModel( 67 | title: '辟谣', 68 | icon: new LoadImage("assets/images/bottom_rumor.png", false), 69 | selectIcon: new LoadImage("assets/images/bottom_rumor.png", true), 70 | page: new RumorPage(), 71 | ), 72 | new TabBarModel( 73 | title: '防护合辑', 74 | icon: new LoadImage("assets/images/bottom_protect.png", false), 75 | selectIcon: new LoadImage("assets/images/bottom_protect.png", true), 76 | page: new ProtectPage(), 77 | ), 78 | new TabBarModel( 79 | title: '疾病知识', 80 | icon: new LoadImage("assets/images/bottom_lore.png", false), 81 | selectIcon: new LoadImage("assets/images/bottom_lore.png", true), 82 | page: new LorePage(), 83 | ), 84 | ]; 85 | return new RootTabBar(pages: pages, currentIndex: 0); 86 | } 87 | } 88 | 89 | class LoadImage extends StatelessWidget { 90 | final String img; 91 | final bool isSelect; 92 | 93 | LoadImage(this.img, [this.isSelect = false]); 94 | 95 | @override 96 | Widget build(BuildContext context) { 97 | return new Container( 98 | margin: EdgeInsets.only(bottom: 2.0), 99 | width: 30.0, 100 | height: 30.0, 101 | child: new Image.asset( 102 | img, 103 | fit: BoxFit.cover, 104 | gaplessPlayback: true, 105 | color: isSelect ? fixedColor : mainTextColor, 106 | ), 107 | ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /lib/pages/rumor/rumor_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:ncov_2019/api/entries_view_model.dart'; 5 | import 'package:ncov_2019/api/rumor_view_model.dart'; 6 | import 'package:ncov_2019/api/statistics_view_model.dart'; 7 | import 'package:ncov_2019/commom/commom.dart'; 8 | import 'package:ncov_2019/widget/card/rumor_card.dart'; 9 | import 'package:ncov_2019/widget/item/entries.dart'; 10 | import 'package:ncov_2019/widget/item/statics.dart'; 11 | import 'package:pull_to_refresh/pull_to_refresh.dart'; 12 | 13 | class RumorPage extends StatefulWidget { 14 | @override 15 | _RumorPageState createState() => _RumorPageState(); 16 | } 17 | 18 | class _RumorPageState extends State 19 | with AutomaticKeepAliveClientMixin { 20 | List data = new List(); 21 | 22 | bool isReq = false; 23 | 24 | List entriesData = new List(); 25 | 26 | StatisticsModel statisticsModel = new StatisticsModel(); 27 | 28 | RefreshController _refreshController = 29 | RefreshController(initialRefresh: false); 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | Notice.addListener(NCOVActions.toTabBarIndex(), (index) { 35 | if (!listNoEmpty(data)) getData(); 36 | }); 37 | getData(); 38 | } 39 | 40 | @override 41 | bool get wantKeepAlive => true; 42 | 43 | getData() { 44 | rumorListReqViewModel.getRumor().then((v) { 45 | setState(() { 46 | data = v; 47 | isReq = true; 48 | }); 49 | }); 50 | statisticsViewModel.getData().then((v) { 51 | setState(() => statisticsModel = v); 52 | }); 53 | entriesViewModel.getData().then((v) { 54 | setState(() => entriesData = v); 55 | }); 56 | } 57 | 58 | Future _refreshData() async { 59 | final Completer completer = new Completer(); 60 | 61 | getData(); 62 | 63 | new Future.delayed(new Duration(seconds: 2), () { 64 | completer.complete(null); 65 | _refreshController.refreshCompleted(); 66 | }); 67 | 68 | return completer.future; 69 | } 70 | 71 | Widget buildItem(item) { 72 | RumorListModel model = item; 73 | return new RumorCard( 74 | model, 75 | margin: EdgeInsets.only( 76 | left: 20.0, 77 | right: 20.0, 78 | top: model.id == data[0].id ? 20.0 : 10, 79 | bottom: model.id == data[data.length - 1].id ? 20.0 : 10, 80 | ), 81 | onTap: () { 82 | setState(() => model.isOpen = !model.isOpen); 83 | }, 84 | ); 85 | } 86 | 87 | @override 88 | Widget build(BuildContext context) { 89 | super.build(context); 90 | return new Scaffold( 91 | body: new SmartRefresher( 92 | controller: _refreshController, 93 | onRefresh: _refreshData, 94 | child: new ListView( 95 | children: [ 96 | new Space(), 97 | new TitleView( 98 | '全国统计', 99 | subTitle: '${timeHandle(statisticsModel?.modifyTime ?? 0)}', 100 | ), 101 | new Statics(statisticsModel ?? null), 102 | new Divider(), 103 | new Space(height: mainSpace / 2), 104 | new Visibility( 105 | visible: strNoEmpty(statisticsModel?.imgUrl ?? ''), 106 | child: new TitleView('疫情地图', subTitle: '数据来源:国家及各省市地区卫健委'), 107 | ), 108 | new Visibility( 109 | visible: strNoEmpty(statisticsModel?.imgUrl ?? ''), 110 | child: new Padding( 111 | padding: EdgeInsets.only(top: 10.0), 112 | child: new CachedNetworkImage( 113 | imageUrl: statisticsModel?.imgUrl ?? defImg), 114 | ), 115 | ), 116 | new Visibility( 117 | visible: listNoEmpty(statisticsModel?.dailyPics), 118 | child: new Column( 119 | children: listNoEmpty(statisticsModel?.dailyPics) 120 | ? statisticsModel.dailyPics.map((pics) { 121 | return new CachedNetworkImage(imageUrl: pics); 122 | }).toList() 123 | : [], 124 | ), 125 | ), 126 | new Space(), 127 | new TitleView('诊疗'), 128 | new Container( 129 | margin: EdgeInsets.symmetric(horizontal: 10.0), 130 | child: new Wrap( 131 | children: entriesData.map((item) { 132 | EntriesModel model = item; 133 | return Entries(model); 134 | }).toList(), 135 | ), 136 | ), 137 | new TitleView('辟谣', subTitle: '消息数量:${data.length}'), 138 | isReq 139 | ? listNoEmpty(data) 140 | ? new Column( 141 | children: data.map(buildItem).toList(), 142 | ) 143 | : new Center( 144 | child: new Text( 145 | '暂无数据', 146 | style: Theme.of(context).textTheme.display1, 147 | ), 148 | ) 149 | : new LoadingView(), 150 | ], 151 | ), 152 | ), 153 | ); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /lib/widget/bar/commom_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:ncov_2019/config/const.dart'; 4 | 5 | class ComMomBar extends StatelessWidget implements PreferredSizeWidget { 6 | const ComMomBar({ 7 | this.title = '', 8 | this.showShadow = false, 9 | this.rightDMActions, 10 | this.backgroundColor = appBarColor, 11 | this.mainColor = Colors.white, 12 | this.titleW, 13 | this.bottom, 14 | this.leadingImg = '', 15 | this.leadingW, 16 | }); 17 | 18 | final String title; 19 | final bool showShadow; 20 | final List rightDMActions; 21 | final Color backgroundColor; 22 | final Color mainColor; 23 | final Widget titleW; 24 | final Widget leadingW; 25 | final PreferredSizeWidget bottom; 26 | final String leadingImg; 27 | 28 | @override 29 | Size get preferredSize => new Size(100, 50); 30 | 31 | Widget leading(BuildContext context) { 32 | final bool isShow = Navigator.canPop(context); 33 | if (isShow) { 34 | return new InkWell( 35 | child: new Container( 36 | width: 15, 37 | height: 28, 38 | child: leadingImg != '' 39 | ? new Image.asset(leadingImg) 40 | : new Icon(CupertinoIcons.back, color: mainColor), 41 | ), 42 | onTap: () { 43 | if (Navigator.canPop(context)) { 44 | FocusScope.of(context).requestFocus(new FocusNode()); 45 | Navigator.pop(context); 46 | } 47 | }, 48 | ); 49 | } else { 50 | return null; 51 | } 52 | } 53 | 54 | @override 55 | Widget build(BuildContext context) { 56 | return showShadow 57 | ? new Container( 58 | decoration: BoxDecoration( 59 | border: Border( 60 | bottom: new BorderSide( 61 | color: Colors.grey, width: showShadow ? 0.5 : 0.0))), 62 | child: new AppBar( 63 | title: titleW == null 64 | ? new Text( 65 | title, 66 | style: new TextStyle( 67 | color: mainColor, 68 | fontSize: 17.0, 69 | fontWeight: FontWeight.w500), 70 | ) 71 | : titleW, 72 | backgroundColor: mainColor, 73 | elevation: 0.0, 74 | brightness: Brightness.dark, 75 | leading: leadingW ?? leading(context), 76 | centerTitle: true, 77 | actions: rightDMActions ?? [new Center()], 78 | bottom: bottom != null ? bottom : null, 79 | ), 80 | ) 81 | : new AppBar( 82 | title: titleW == null 83 | ? new Text( 84 | title, 85 | style: new TextStyle( 86 | color: mainColor, 87 | fontSize: 17.0, 88 | fontWeight: FontWeight.w500), 89 | ) 90 | : titleW, 91 | backgroundColor: backgroundColor, 92 | elevation: 0.0, 93 | brightness: Brightness.dark, 94 | leading: leadingW ?? leading(context), 95 | centerTitle: false, 96 | bottom: bottom != null ? bottom : null, 97 | actions: rightDMActions ?? [new Center()], 98 | ); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /lib/widget/card/lore_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ncov_2019/api/lore_view_model.dart'; 3 | import 'package:ncov_2019/commom/commom.dart'; 4 | 5 | class LoreCard extends StatelessWidget { 6 | final LoreModel model; 7 | final EdgeInsetsGeometry margin; 8 | 9 | LoreCard(this.model, {@required this.margin}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | decoration: BoxDecoration( 15 | border: Border(bottom: BorderSide(color: lineColor, width: 0.2)), 16 | ), 17 | margin: margin, 18 | child: new FlatButton( 19 | onPressed: () => routePush( 20 | new WebViewPage(model?.linkUrl ?? 'http://book.flutterj.com/', 21 | '${model?.title ?? '未知'}'), 22 | ), 23 | child: new Row( 24 | children: [ 25 | new Visibility( 26 | visible: strNoEmpty(model?.imgUrl), 27 | child: new ClipRRect( 28 | borderRadius: BorderRadius.all(Radius.circular(5.0)), 29 | child: new CachedNetworkImage( 30 | imageUrl: '${model.imgUrl}', 31 | height: 102.0, 32 | width: 102.0, 33 | fit: BoxFit.cover, 34 | ), 35 | ), 36 | ), 37 | new Space(), 38 | new Expanded( 39 | child: new Container( 40 | padding: EdgeInsets.symmetric(vertical: 25.0), 41 | child: new Column( 42 | crossAxisAlignment: CrossAxisAlignment.start, 43 | children: [ 44 | new Text( 45 | '${model?.title ?? '未知'}', 46 | style: TextStyle( 47 | fontSize: 16.0, fontWeight: FontWeight.w600), 48 | ), 49 | new Space(height: 15.0), 50 | new Text( 51 | '${model?.description ?? '未知'}', 52 | style: TextStyle(color: mainTextColor), 53 | ), 54 | ], 55 | ), 56 | ), 57 | ), 58 | ], 59 | ), 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/widget/card/news_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ncov_2019/api/news_model.dart'; 3 | import 'package:ncov_2019/commom/commom.dart'; 4 | 5 | class NewsCard extends StatelessWidget { 6 | final TimeNewsModel model; 7 | final EdgeInsetsGeometry padding; 8 | final bool isNew; 9 | 10 | NewsCard( 11 | this.model, { 12 | @required this.padding, 13 | this.isNew = false, 14 | }); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | double pubDateDouble = 19 | strNoEmpty('${model?.pubDate}') ? model.pubDate / 1000 : 0; 20 | int pubDate = int.parse('${stringDisposeWithDouble(pubDateDouble)}'); 21 | 22 | bool isTimeStr = 23 | DateTime.now().millisecondsSinceEpoch - model?.pubDate < 43200000; 24 | return Container( 25 | padding: padding, 26 | alignment: Alignment.centerLeft, 27 | width: winWidth(context), 28 | child: new FlatButton( 29 | onPressed: () => routePush( 30 | new WebViewPage(model?.sourceUrl ?? 'http://book.flutterj.com/', 31 | '${model?.title ?? '未知'}'), 32 | ), 33 | color: Colors.white, 34 | padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), 35 | shape: RoundedRectangleBorder( 36 | borderRadius: BorderRadius.all(Radius.circular(5.0)), 37 | ), 38 | child: new Column( 39 | crossAxisAlignment: CrossAxisAlignment.start, 40 | children: [ 41 | new Row( 42 | children: [ 43 | new Visibility( 44 | visible: isNew, 45 | child: new Container( 46 | decoration: BoxDecoration( 47 | color: Colors.redAccent, 48 | borderRadius: BorderRadius.all(Radius.circular(5.0))), 49 | alignment: Alignment.center, 50 | padding: EdgeInsets.symmetric(horizontal: 3.0, vertical: 2), 51 | margin: EdgeInsets.only(right: 5.0), 52 | child: new Text( 53 | '最新', 54 | style: TextStyle(color: Colors.white), 55 | ), 56 | ), 57 | ), 58 | new SizedBox( 59 | width: 60 | isNew ? winWidth(context) - 120 : winWidth(context) - 70, 61 | child: new Text( 62 | '${model?.title ?? '未知'}', 63 | style: 64 | TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600), 65 | maxLines: 1, 66 | overflow: TextOverflow.ellipsis, 67 | ), 68 | ) 69 | ], 70 | ), 71 | new Padding( 72 | padding: EdgeInsets.symmetric(vertical: 10.0), 73 | child: new Text( 74 | '${model?.summary ?? '未知'}', 75 | maxLines: 5, 76 | overflow: TextOverflow.ellipsis, 77 | style: TextStyle(color: Color(0xff999999), fontSize: 12.0), 78 | ), 79 | ), 80 | new Row( 81 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 82 | children: [ 83 | new Text( 84 | '时间:${isTimeStr ? model?.pubDateStr ?? '未知' : formatTimeStampToString(pubDate) ?? '未知'}', 85 | style: TextStyle(color: Color(0xff999999), fontSize: 13.0), 86 | ), 87 | new Text( 88 | '来源:${model?.infoSource ?? '未知'}', 89 | style: TextStyle(color: Color(0xff999999), fontSize: 13.0), 90 | ), 91 | ], 92 | ) 93 | ], 94 | ), 95 | ), 96 | ); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /lib/widget/card/protect_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ncov_2019/api/protect_view_model.dart'; 3 | import 'package:ncov_2019/commom/commom.dart'; 4 | 5 | class ProtectCard extends StatelessWidget { 6 | final ProtectModel model; 7 | final EdgeInsetsGeometry margin; 8 | 9 | ProtectCard(this.model, {@required this.margin}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | decoration: BoxDecoration( 15 | border: Border(bottom: BorderSide(color: lineColor, width: 0.2)), 16 | ), 17 | margin: margin, 18 | child: new FlatButton( 19 | onPressed: () => routePush( 20 | new WebViewPage(model?.linkUrl ?? 'http://book.flutterj.com/', 21 | '${model?.title ?? '未知'}'), 22 | ), 23 | child: new Row( 24 | children: [ 25 | new Expanded( 26 | child: new Container( 27 | padding: EdgeInsets.symmetric(vertical: 25.0), 28 | child: new Column( 29 | crossAxisAlignment: CrossAxisAlignment.start, 30 | children: [ 31 | new Text( 32 | '${model?.title ?? '未知'}', 33 | style: TextStyle( 34 | fontSize: 16.0, fontWeight: FontWeight.w600), 35 | ), 36 | new Space(height: 15.0), 37 | new Text( 38 | '${timeHandle(model?.createTime ?? 0)}', 39 | style: TextStyle(color: mainTextColor), 40 | ), 41 | ], 42 | ), 43 | ), 44 | ), 45 | new ClipRRect( 46 | borderRadius: BorderRadius.all(Radius.circular(5.0)), 47 | child: new CachedNetworkImage( 48 | imageUrl: 49 | '${strNoEmpty(model?.imgUrl) ? model.imgUrl : defImg}', 50 | height: 68.0, 51 | width: 91.0, 52 | fit: BoxFit.cover, 53 | ), 54 | ) 55 | ], 56 | ), 57 | ), 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/widget/card/rumor_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ncov_2019/api/rumor_view_model.dart'; 3 | import 'package:ncov_2019/commom/commom.dart'; 4 | 5 | class RumorCard extends StatelessWidget { 6 | final RumorListModel model; 7 | final EdgeInsetsGeometry margin; 8 | final GestureTapCallback onTap; 9 | 10 | RumorCard(this.model, {@required this.margin, this.onTap}); 11 | 12 | static TextStyle defStyle = TextStyle( 13 | color: Color(0xff999999), fontSize: 16.0, fontWeight: FontWeight.w600); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return new Container( 18 | margin: margin, 19 | padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), 20 | decoration: BoxDecoration( 21 | borderRadius: BorderRadius.all(Radius.circular(5.0)), 22 | gradient: LinearGradient( 23 | colors: [Color(0xff68869e), Color(0xff292f4b)], 24 | ), 25 | ), 26 | child: new Column( 27 | crossAxisAlignment: CrossAxisAlignment.start, 28 | children: [ 29 | new Text( 30 | '${model?.title ?? '未知'}', 31 | style: TextStyle( 32 | fontSize: 20.0, 33 | fontWeight: FontWeight.w600, 34 | color: Colors.white, 35 | ), 36 | maxLines: 2, 37 | overflow: TextOverflow.ellipsis, 38 | ), 39 | new Container( 40 | padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), 41 | decoration: BoxDecoration( 42 | color: Colors.white, 43 | borderRadius: BorderRadius.all(Radius.circular(5.0)), 44 | ), 45 | margin: EdgeInsets.symmetric(vertical: 10.0), 46 | child: new Column( 47 | crossAxisAlignment: CrossAxisAlignment.start, 48 | children: [ 49 | new Text('${model?.mainSummary ?? '未知'}', style: defStyle), 50 | new Text('${model?.summary ?? '未知'}', style: defStyle), 51 | new Space(), 52 | new Visibility( 53 | visible: model.isOpen, 54 | child: new Text( 55 | '${model?.body ?? '未知'}', 56 | style: TextStyle(color: Color(0xff999999), fontSize: 16.0), 57 | ), 58 | ), 59 | new GestureDetector( 60 | child: new Padding( 61 | padding: EdgeInsets.all(3.0), 62 | child: new Row( 63 | mainAxisAlignment: MainAxisAlignment.end, 64 | children: [ 65 | new Text( 66 | '${model.isOpen ? '收起' : '展开'}详情', 67 | style: TextStyle( 68 | color: Color(0xff999999), 69 | fontSize: 12.0, 70 | fontWeight: FontWeight.w600, 71 | ), 72 | ), 73 | new Icon( 74 | model.isOpen 75 | ? Icons.keyboard_arrow_up 76 | : Icons.keyboard_arrow_down, 77 | color: Color(0xff999999), 78 | ) 79 | ], 80 | ), 81 | ), 82 | onTap: () { 83 | if (onTap != null) { 84 | onTap(); 85 | } 86 | }, 87 | ), 88 | ], 89 | ), 90 | ) 91 | ], 92 | ), 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/widget/item/entries.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ncov_2019/api/entries_view_model.dart'; 3 | import 'package:ncov_2019/commom/commom.dart'; 4 | 5 | class Entries extends StatelessWidget { 6 | final EntriesModel model; 7 | 8 | Entries(this.model); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return new Container( 13 | width: (winWidth(context) - 20) / 3, 14 | padding: EdgeInsets.symmetric(vertical: 10.0), 15 | child: new FlatButton( 16 | onPressed: () => routePush( 17 | new WebViewPage(model?.linkUrl ?? 'http://book.flutterj.com/', 18 | '${model?.configName ?? '未知'}'), 19 | ), 20 | child: new Padding( 21 | padding: EdgeInsets.symmetric(vertical: 5.0), 22 | child: new Column( 23 | children: [ 24 | new Image.asset('${model.icon}', width: 50.0, height: 50.0), 25 | new Padding( 26 | padding: EdgeInsets.only(top: 2.0), 27 | child: new Text( 28 | '${model.configName}', 29 | overflow: TextOverflow.ellipsis, 30 | style: TextStyle(fontSize: 12.0, color: mainTextColor), 31 | ), 32 | ), 33 | ], 34 | ), 35 | ), 36 | ), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/widget/item/statics.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ncov_2019/api/statistics_view_model.dart'; 3 | import 'package:ncov_2019/commom/commom.dart'; 4 | 5 | class Statics extends StatelessWidget { 6 | final StatisticsModel statisticsModel; 7 | 8 | Statics(this.statisticsModel); 9 | 10 | Color strColor(name) { 11 | switch (name) { 12 | case '全国确诊': 13 | return Colors.red; 14 | break; 15 | case '疑似病例': 16 | return Colors.amber; 17 | break; 18 | case '治愈人数': 19 | return Colors.green; 20 | break; 21 | case '死亡人数': 22 | return Colors.grey; 23 | break; 24 | } 25 | return Colors.black; 26 | } 27 | 28 | static TextStyle defStyle = 29 | TextStyle(fontSize: 15.0, fontWeight: FontWeight.w600); 30 | 31 | Color iconColor(String label) { 32 | switch (label) { 33 | case '传染源': 34 | return Colors.blueAccent; 35 | break; 36 | case '病毒': 37 | return Colors.blueAccent; 38 | break; 39 | case '传播途径': 40 | return Colors.blueAccent; 41 | break; 42 | default: 43 | return Colors.red; 44 | break; 45 | } 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | if (statisticsModel == null) { 51 | return LinearProgressIndicator(); 52 | } 53 | 54 | List personInfo = [ 55 | {'label': '全国确诊', 'value': '${statisticsModel?.confirmedCount ?? 0}'}, 56 | {'label': '疑似病例', 'value': '${statisticsModel?.suspectedCount ?? 0}'}, 57 | {'label': '治愈人数', 'value': '${statisticsModel?.curedCount ?? 0}'}, 58 | {'label': '死亡人数', 'value': '${statisticsModel?.deadCount ?? 0}'}, 59 | ]; 60 | 61 | bool contains1Big = statisticsModel.remark1.contains(':'); 62 | bool contains1Small = statisticsModel.remark1.contains(':'); 63 | bool containsOr = contains1Big || contains1Small; 64 | Pattern splitStr = contains1Big ? ':' : ':'; 65 | 66 | List note1 = strNoEmpty(statisticsModel?.note1) && containsOr 67 | ? statisticsModel.note1.split(splitStr) 68 | : ['未知', '未知']; 69 | List note2 = strNoEmpty(statisticsModel?.note2) && containsOr 70 | ? statisticsModel.note2.split(splitStr) 71 | : ['未知', '未知']; 72 | List note3 = strNoEmpty(statisticsModel?.note3) && containsOr 73 | ? statisticsModel.note3.split(splitStr) 74 | : ['未知', '未知']; 75 | List remark1 = strNoEmpty(statisticsModel?.remark1) && containsOr 76 | ? statisticsModel.remark1.split(splitStr) 77 | : ['未知', '未知']; 78 | List remark2 = strNoEmpty(statisticsModel?.remark2) && containsOr 79 | ? statisticsModel.remark2.split(splitStr) 80 | : ['未知', '未知']; 81 | 82 | List staticsInfo = [ 83 | {'label': '${note1[0]}', 'value': '${note1[1]}'}, 84 | {'label': '${note2[0]}', 'value': '${note2[1]}'}, 85 | {'label': '${note3[0]}', 'value': '${note3[1]}'}, 86 | {'label': '${remark1[0]}', 'value': '${remark1[1]}'}, 87 | {'label': '${remark2[0]}', 'value': '${remark2[1]}'}, 88 | ]; 89 | 90 | Widget itemBuild(item) { 91 | PersonInfoModel model = PersonInfoModel(item); 92 | return FlatButton( 93 | onPressed: () {}, 94 | padding: EdgeInsets.symmetric(vertical: 10.0), 95 | child: new SizedBox( 96 | width: (winWidth(context) - 20) / 4, 97 | child: new Column( 98 | children: [ 99 | new Text( 100 | '${model.value}', 101 | style: TextStyle( 102 | fontSize: 22.0, 103 | fontWeight: FontWeight.w600, 104 | color: strColor(model.label), 105 | ), 106 | ), 107 | new Text( 108 | '${model.label}', 109 | style: TextStyle(fontSize: 13.0), 110 | ), 111 | ], 112 | ), 113 | ), 114 | ); 115 | } 116 | 117 | Widget _staticsBuild(item) { 118 | PersonInfoModel model = PersonInfoModel(item); 119 | 120 | return new SizedBox( 121 | width: winWidth(context) - 20, 122 | child: new Column( 123 | crossAxisAlignment: CrossAxisAlignment.start, 124 | children: [ 125 | new Visibility( 126 | visible: model.label != '病毒', 127 | child: new Space(), 128 | ), 129 | new SizedBox( 130 | width: 120, 131 | child: new Row( 132 | children: [ 133 | new Icon( 134 | Icons.insert_chart, 135 | color: iconColor(model.label), 136 | ), 137 | new Space(width: mainSpace / 2), 138 | new Text('${model.label}:', style: defStyle), 139 | ], 140 | ), 141 | ), 142 | new Text( 143 | ' · ${model.value}', 144 | style: defStyle, 145 | maxLines: 5, 146 | overflow: TextOverflow.ellipsis, 147 | ), 148 | ], 149 | ), 150 | ); 151 | } 152 | 153 | return new Column( 154 | children: [ 155 | new Container( 156 | padding: EdgeInsets.symmetric(horizontal: 10.0), 157 | margin: EdgeInsets.only(top: 10.0), 158 | child: new Row( 159 | children: personInfo.map(itemBuild).toList(), 160 | ), 161 | ), 162 | new Divider(), 163 | new Container( 164 | padding: EdgeInsets.symmetric(horizontal: 10.0), 165 | margin: EdgeInsets.symmetric(vertical: 10.0), 166 | child: new Column( 167 | children: staticsInfo.map(_staticsBuild).toList(), 168 | ), 169 | ) 170 | ], 171 | ); 172 | } 173 | } 174 | 175 | class PersonInfoModel { 176 | String label; 177 | String value; 178 | 179 | PersonInfoModel(Map value) { 180 | this.label = value['label']; 181 | this.value = value['value']; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /lib/widget/orther/turn_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | /// Animates the rotation of a widget when [turns] is changed. 4 | 5 | class TurnBox extends StatefulWidget { 6 | const TurnBox({ 7 | Key key, 8 | this.turns = .0, 9 | this.speed = 200, 10 | this.child, 11 | }) : super(key: key); 12 | 13 | /// Controls the rotation of the child. 14 | /// 15 | /// If the current value of the turns is v, the child will be 16 | /// rotated v * 2 * pi radians before being painted. 17 | final double turns; 18 | 19 | /// Animation duration in milliseconds 20 | final int speed; 21 | 22 | final Widget child; 23 | 24 | @override 25 | _TurnBoxState createState() => new _TurnBoxState(); 26 | } 27 | 28 | class _TurnBoxState extends State with SingleTickerProviderStateMixin { 29 | AnimationController _controller; 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | _controller = new AnimationController( 35 | vsync: this, lowerBound: -double.infinity, upperBound: double.infinity); 36 | _controller.value = widget.turns; 37 | } 38 | 39 | @override 40 | void dispose() { 41 | _controller.dispose(); 42 | super.dispose(); 43 | } 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | return RotationTransition( 48 | turns: _controller, 49 | child: widget.child, 50 | ); 51 | } 52 | 53 | @override 54 | void didUpdateWidget(TurnBox oldWidget) { 55 | super.didUpdateWidget(oldWidget); 56 | if (oldWidget.turns != widget.turns) { 57 | _controller.animateTo( 58 | widget.turns, 59 | duration: Duration(milliseconds: widget.speed ?? 200), 60 | curve: Curves.easeOut, 61 | ); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/widget/root_tabbar.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:ncov_2019/commom/commom.dart'; 6 | import 'package:ncov_2019/config/const.dart'; 7 | import 'package:ncov_2019/widget/scroll/my_behavior.dart'; 8 | import 'package:url_launcher/url_launcher.dart'; 9 | 10 | class RootTabBar extends StatefulWidget { 11 | RootTabBar({this.pages, this.currentIndex = 0}); 12 | 13 | final List pages; 14 | final int currentIndex; 15 | 16 | @override 17 | State createState() => new RootTabBarState(); 18 | } 19 | 20 | class RootTabBarState extends State { 21 | var pages = new List(); 22 | int currentIndex; 23 | var contents = new List(); 24 | PageController pageController; 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | currentIndex = widget.currentIndex; 30 | pageController = PageController(initialPage: currentIndex); 31 | for (int i = 0; i < widget.pages.length; i++) { 32 | TabBarModel model = widget.pages[i]; 33 | pages.add( 34 | new BottomNavigationBarItem( 35 | icon: model.icon, 36 | activeIcon: model.selectIcon, 37 | title: new Text(model.title, style: new TextStyle(fontSize: 12.0)), 38 | ), 39 | ); 40 | } 41 | } 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | final BottomNavigationBar bottomNavigationBar = new BottomNavigationBar( 46 | items: pages, 47 | type: BottomNavigationBarType.fixed, 48 | currentIndex: currentIndex, 49 | unselectedItemColor: mainTextColor, 50 | fixedColor: fixedColor, 51 | onTap: (int index) { 52 | setState(() => currentIndex = index); 53 | pageController.jumpToPage(currentIndex); 54 | Notice.send(NCOVActions.toTabBarIndex(), index); 55 | }, 56 | unselectedFontSize: 18.0, 57 | selectedFontSize: 18.0, 58 | elevation: 0, 59 | ); 60 | 61 | String title() { 62 | if (currentIndex == 0) { 63 | return '首页'; 64 | } else if (currentIndex == 1) { 65 | return '辟谣'; 66 | } else if (currentIndex == 2) { 67 | return '防护'; 68 | } else { 69 | return '知识'; 70 | } 71 | } 72 | 73 | return new Scaffold( 74 | bottomNavigationBar: new Theme( 75 | data: new ThemeData( 76 | canvasColor: Colors.grey[50], 77 | highlightColor: Colors.transparent, 78 | splashColor: Colors.transparent, 79 | ), 80 | child: new Container( 81 | decoration: BoxDecoration( 82 | border: Border(top: BorderSide(color: lineColor, width: 0.2))), 83 | child: bottomNavigationBar, 84 | ), 85 | ), 86 | appBar: new ComMomBar( 87 | titleW: new AnimatedSwitcher( 88 | duration: Duration(milliseconds: 400), 89 | transitionBuilder: (Widget child, Animation animation) { 90 | var tween = Tween(begin: 0, end: 1); 91 | return FadeTransition( 92 | child: child, 93 | opacity: tween.animate(animation), 94 | ); 95 | }, 96 | child: new Text( 97 | title() ?? '', 98 | key: ValueKey(title() ?? ''), 99 | style: TextStyle(color: Colors.white, fontSize: 20.0), 100 | ), 101 | ), 102 | rightDMActions: [ 103 | new MaterialButton( 104 | onPressed: () => launch('https://github.com/ahyangnb/ncov_2019'), 105 | padding: EdgeInsets.symmetric(horizontal: 10.0), 106 | child: new Text( 107 | '开源地址', 108 | style: TextStyle(color: Colors.white), 109 | ), 110 | ) 111 | ], 112 | ), 113 | body: new ScrollConfiguration( 114 | behavior: MyBehavior(), 115 | child: new PageView.builder( 116 | itemBuilder: (BuildContext context, int index) => 117 | widget.pages[index].page, 118 | controller: pageController, 119 | itemCount: pages.length, 120 | physics: Platform.isAndroid 121 | ? new ClampingScrollPhysics() 122 | : new NeverScrollableScrollPhysics(), 123 | onPageChanged: (int index) { 124 | setState(() => currentIndex = index); 125 | }, 126 | ), 127 | ), 128 | ); 129 | } 130 | } 131 | 132 | class TabBarModel { 133 | const TabBarModel({this.title, this.page, this.icon, this.selectIcon}); 134 | 135 | final String title; 136 | final Widget icon; 137 | final Widget selectIcon; 138 | final Widget page; 139 | } 140 | -------------------------------------------------------------------------------- /lib/widget/scroll/my_behavior.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class MyBehavior extends ScrollBehavior { 5 | @override 6 | Widget buildViewportChrome( 7 | BuildContext context, Widget child, AxisDirection axisDirection) { 8 | if (Platform.isAndroid || Platform.isFuchsia) { 9 | return child; 10 | } else { 11 | return super.buildViewportChrome(context, child, axisDirection); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/widget/view/loading_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ncov_2019/commom/commom.dart'; 3 | 4 | class LoadingView extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return new SizedBox( 8 | width: winWidth(context), 9 | child: new Column( 10 | mainAxisAlignment: MainAxisAlignment.center, 11 | children: [ 12 | new CircularProgressIndicator(), 13 | new Space(), 14 | new Text( 15 | '加载中', 16 | style: TextStyle(color: mainTextColor), 17 | ), 18 | ], 19 | ), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/widget/view/title_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ncov_2019/commom/commom.dart'; 3 | 4 | class TitleView extends StatelessWidget { 5 | final String title; 6 | final String subTitle; 7 | 8 | TitleView(this.title, {this.subTitle = ''}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return new Row( 13 | children: [ 14 | new Container( 15 | margin: EdgeInsets.only(left: 10.0), 16 | decoration: BoxDecoration( 17 | color: appBarColor, 18 | borderRadius: BorderRadius.all(Radius.circular(2.0)), 19 | ), 20 | width: 5.0, 21 | height: 15.0, 22 | ), 23 | new Space(width: 10.0), 24 | new Text( 25 | '$title', 26 | style: TextStyle(fontSize: 17.0, fontWeight: FontWeight.w600), 27 | ), 28 | new Spacer(), 29 | new Text( 30 | strNoEmpty(subTitle) ? '$subTitle' : '', 31 | style: TextStyle(color: mainTextColor), 32 | ), 33 | new Space(), 34 | ], 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/widget/view/web_view_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:webview_flutter/webview_flutter.dart'; 5 | import 'package:ncov_2019/commom/commom.dart'; 6 | 7 | class WebViewPage extends StatefulWidget { 8 | final String url; 9 | final String title; 10 | 11 | WebViewPage(this.url, this.title); 12 | 13 | @override 14 | State createState() => new WebViewPageState(); 15 | } 16 | 17 | class WebViewPageState extends State { 18 | final Completer _controller = 19 | new Completer(); 20 | WebViewController _webViewController; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Scaffold( 25 | backgroundColor: Colors.white, 26 | appBar: new ComMomBar(title: widget.title ?? ''), 27 | body: new WillPopScope( 28 | child: new Builder(builder: (BuildContext context) { 29 | return new WebView( 30 | initialUrl: widget.url, 31 | javascriptMode: JavascriptMode.unrestricted, 32 | onWebViewCreated: (WebViewController webViewController) { 33 | _controller.complete(webViewController); 34 | _webViewController = webViewController; 35 | }, 36 | javascriptChannels: [ 37 | _toasterJavascriptChannel(context), 38 | ].toSet(), 39 | navigationDelegate: (NavigationRequest request) { 40 | if (request.url 41 | .startsWith('https://github.com/ahyangnb/ncov_2019')) { 42 | print('blocking navigation to $request}'); 43 | return NavigationDecision.prevent; 44 | } 45 | print('allowing navigation to $request'); 46 | return NavigationDecision.navigate; 47 | }, 48 | onPageFinished: (String url) { 49 | print('Page finished loading: $url'); 50 | }, 51 | ); 52 | }), 53 | onWillPop: () => pop(), 54 | ), 55 | ); 56 | } 57 | 58 | Future pop() async { 59 | bool canGoBack = await _webViewController.canGoBack(); 60 | 61 | if (canGoBack) { 62 | _webViewController.goBack(); 63 | 64 | return false; 65 | } else { 66 | return true; 67 | } 68 | } 69 | 70 | JavascriptChannel _toasterJavascriptChannel(BuildContext context) { 71 | return new JavascriptChannel( 72 | name: 'Toaster', 73 | onMessageReceived: (JavascriptMessage message) { 74 | Scaffold.of(context).showSnackBar( 75 | new SnackBar(content: Text(message.message)), 76 | ); 77 | }, 78 | ); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ncov_2019 2 | description: A new Flutter project. 3 | 4 | version: 0.0.10+10 5 | 6 | environment: 7 | sdk: ">=2.1.0 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | cupertino_icons: ^0.1.2 13 | # dio: 2.2.2 #低于Flutter-1.17使用此版本 14 | dio: ^3.0.9 15 | nav_router: ^0.0.5 16 | webview_flutter: ^0.3.12 17 | device_info: ^0.4.0+1 18 | package_info: ^0.4.0+6 19 | pull_to_refresh: ^1.5.6 20 | flutter_swiper: ^1.1.6 21 | # cached_network_image: ^1.1.1 # ^1.9.0左右flutter版本的用这个 22 | cached_network_image: ^2.0.0 # ^2.0.0左右flutter版本直接用这个 23 | shared_preferences: ^0.5.2+2 24 | intl: ^0.16.1 25 | open_file: ^2.1.1 26 | url_launcher: ^5.2.7 27 | connectivity: ^0.4.6 28 | 29 | dev_dependencies: 30 | flutter_test: 31 | sdk: flutter 32 | 33 | 34 | flutter: 35 | 36 | uses-material-design: true 37 | 38 | assets: 39 | - assets/images/bottom_home.png 40 | - assets/images/bottom_rumor.png 41 | - assets/images/bottom_protect.png 42 | - assets/images/bottom_lore.png 43 | - assets/images/entries_1.png 44 | - assets/images/entries_2.png 45 | - assets/images/entries_3.png 46 | - assets/images/entries_4.png 47 | - assets/images/entries_5.png 48 | --------------------------------------------------------------------------------