├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── libraries │ ├── Dart_Packages.xml │ ├── Dart_SDK.xml │ ├── Flutter_Plugins.xml │ └── Flutter_for_Android.xml ├── misc.xml ├── modules.xml ├── runConfigurations │ └── main_dart.xml ├── vcs.xml └── workspace.xml ├── .metadata ├── .vscode └── launch.json ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── ninghaoflutter │ │ │ └── MainActivity.java │ │ └── res │ │ ├── drawable │ │ └── launch_background.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── flutter_export_environment.sh ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── WorkspaceSettings.xcsettings └── 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 │ ├── Info.plist │ └── main.m ├── lib ├── demo │ ├── alert_dialog_demo.dart │ ├── animation │ │ └── animation_demo.dart │ ├── basic_demo.dart │ ├── bloc │ │ ├── bloc_demo.dart │ │ └── counter_bloc_demo.dart │ ├── bottom_navigation_bar_demo.dart │ ├── bottom_sheet_demo.dart │ ├── button_demo.dart │ ├── card_demo.dart │ ├── checkbox_demo.dart │ ├── chip_demo.dart │ ├── data_table_demo.dart │ ├── datetime_demo.dart │ ├── drawer_demo.dart │ ├── expansion_panel_demo.dart │ ├── floating_action_button_demo.dart │ ├── form_demo.dart │ ├── hello_demo.dart │ ├── http │ │ └── http_demo.dart │ ├── i18n │ │ ├── i18n_demo.dart │ │ ├── intl │ │ │ ├── intl_en.arb │ │ │ ├── intl_messages.arb │ │ │ ├── intl_zh.arb │ │ │ ├── ninghao_demo_localizations.dart │ │ │ ├── ninghao_demo_messages_all.dart │ │ │ ├── ninghao_demo_messages_en.dart │ │ │ ├── ninghao_demo_messages_messages.dart │ │ │ └── ninghao_demo_messages_zh.dart │ │ └── map │ │ │ └── ninghao_demo_localizations.dart │ ├── layout_demo.dart │ ├── listview_demo.dart │ ├── material_components.dart │ ├── navigator_demo.dart │ ├── paginated_data_table_demo.dart │ ├── popup_menu_button_demo.dart │ ├── post_show.dart │ ├── radio_demo.dart │ ├── rxdart │ │ └── rxdart_demo.dart │ ├── simple_dialog_demo.dart │ ├── slider_demo.dart │ ├── sliver_demo.dart │ ├── snack_bar_demo.dart │ ├── state │ │ └── state_management_demo.dart │ ├── stepper_demo.dart │ ├── stream │ │ └── stream_demo.dart │ ├── switch_demo.dart │ ├── test │ │ └── test_demo.dart │ └── view_demo.dart ├── main.dart └── model │ └── post.dart ├── ninghao_flutter.iml ├── ninghao_flutter_android.iml ├── pubspec.lock ├── pubspec.yaml ├── test └── ninghao_demo_test.dart └── test_driver ├── app.dart └── app_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | 9 | .flutter-plugins 10 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/libraries/Dart_SDK.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/libraries/Flutter_Plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/libraries/Flutter_for_Android.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/main_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 86 | 87 | 88 | 89 | 90 | 91 | 105 | 106 | 107 | 108 | 109 | 110 | 122 | 123 | 129 | 130 | 131 | 132 | 150 | 156 | 157 | 165 | 166 | 171 | 172 | 174 | 175 | 176 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 1533729618709 185 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 66091f969653fd3535b265ddcd87436901858a1d 8 | channel: dev 9 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter", 9 | "request": "launch", 10 | "type": "dart" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ninghao_flutter 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.io/). 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.class 3 | .gradle 4 | /local.properties 5 | /.idea/workspace.xml 6 | /.idea/libraries 7 | .DS_Store 8 | /build 9 | /captures 10 | GeneratedPluginRegistrant.java 11 | -------------------------------------------------------------------------------- /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 | throw new GradleException("versionCode not found. Define flutter.versionCode in the local.properties file.") 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | throw new GradleException("versionName not found. Define flutter.versionName in the local.properties file.") 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 27 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.ninghaoflutter" 37 | minSdkVersion 16 38 | targetSdkVersion 27 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/example/ninghaoflutter/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.ninghaoflutter; 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/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.1.2' 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 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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.4-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/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 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/app.flx 37 | /Flutter/app.zip 38 | /Flutter/flutter_assets/ 39 | /Flutter/App.framework 40 | /Flutter/Flutter.framework 41 | /Flutter/Generated.xcconfig 42 | /ServiceDefinitions.json 43 | 44 | Pods/ 45 | .symlinks/ 46 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /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=/Applications/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/Users/wanghao/Desktop/ninghao_flutter" 5 | export "FLUTTER_TARGET=/Users/wanghao/Desktop/ninghao_flutter/lib/main.dart" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios" 8 | export "FLUTTER_FRAMEWORK_DIR=/Applications/flutter/bin/cache/artifacts/engine/ios" 9 | export "FLUTTER_BUILD_NAME=1.0.0" 10 | export "FLUTTER_BUILD_NUMBER=1" 11 | export "TRACK_WIDGET_CREATION=true" 12 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ninghao/ninghao_flutter/2bb8ee8d96fb33d90d2cc8538d79df3a9b070ff2/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/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ninghao_flutter 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 | CFBundleLocalizations 45 | 46 | en 47 | zh_CN 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/demo/alert_dialog_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:async'; 3 | 4 | enum Action { 5 | Ok, 6 | Cancel 7 | } 8 | 9 | class AlertDialogDemo extends StatefulWidget { 10 | @override 11 | _AlertDialogDemoState createState() => _AlertDialogDemoState(); 12 | } 13 | 14 | class _AlertDialogDemoState extends State { 15 | String _choice = 'Nothing'; 16 | 17 | Future _openAlertDialog() async { 18 | final action = await showDialog( 19 | context: context, 20 | barrierDismissible: false, 21 | builder: (BuildContext context) { 22 | return AlertDialog( 23 | title: Text('AlertDialog'), 24 | content: Text('Are you sure about this?'), 25 | actions: [ 26 | FlatButton( 27 | child: Text('Cancel'), 28 | onPressed: () { 29 | Navigator.pop(context, Action.Cancel); 30 | }, 31 | ), 32 | FlatButton( 33 | child: Text('Ok'), 34 | onPressed: () { 35 | Navigator.pop(context, Action.Ok); 36 | }, 37 | ), 38 | ], 39 | ); 40 | }, 41 | ); 42 | 43 | switch (action) { 44 | case Action.Ok: 45 | setState(() { 46 | _choice = 'Ok'; 47 | }); 48 | break; 49 | case Action.Cancel: 50 | setState(() { 51 | _choice = 'Cancel'; 52 | }); 53 | break; 54 | default: 55 | } 56 | } 57 | 58 | @override 59 | Widget build(BuildContext context) { 60 | return Scaffold( 61 | appBar: AppBar( 62 | title: Text('AlertDialogDemo'), 63 | elevation: 0.0, 64 | ), 65 | body: Container( 66 | padding: EdgeInsets.all(16.0), 67 | child: Column( 68 | mainAxisAlignment: MainAxisAlignment.center, 69 | children: [ 70 | Text('Your choice is: $_choice'), 71 | SizedBox(height: 16.0,), 72 | Row( 73 | mainAxisAlignment: MainAxisAlignment.center, 74 | children: [ 75 | RaisedButton( 76 | child: Text('Open AlertDialog'), 77 | onPressed: _openAlertDialog, 78 | ), 79 | ], 80 | ), 81 | ], 82 | ), 83 | ), 84 | ); 85 | } 86 | } -------------------------------------------------------------------------------- /lib/demo/animation/animation_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AnimationDemo extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Scaffold( 7 | appBar: AppBar( 8 | title: Text('AnimationDemo'), 9 | elevation: 0.0, 10 | ), 11 | body: AnimationDemoHome()); 12 | } 13 | } 14 | 15 | class AnimationDemoHome extends StatefulWidget { 16 | @override 17 | _AnimationDemoHomeState createState() => _AnimationDemoHomeState(); 18 | } 19 | 20 | class _AnimationDemoHomeState extends State 21 | with TickerProviderStateMixin { 22 | AnimationController animationDemoController; 23 | Animation animation; 24 | Animation animationColor; 25 | CurvedAnimation curve; 26 | 27 | @override 28 | void initState() { 29 | super.initState(); 30 | 31 | animationDemoController = AnimationController( 32 | // value: 32.0, 33 | // lowerBound: 32.0, 34 | // upperBound: 100.0, 35 | duration: Duration(milliseconds: 1000), 36 | vsync: this, 37 | ); 38 | 39 | curve = CurvedAnimation( 40 | parent: animationDemoController, curve: Curves.bounceOut); 41 | 42 | animation = Tween(begin: 32.0, end: 100.0).animate(curve); 43 | animationColor = 44 | ColorTween(begin: Colors.red, end: Colors.red[900]).animate(curve); 45 | 46 | // animationDemoController.addListener(() { 47 | // // print('${animationDemoController.value}'); 48 | // setState(() {}); 49 | // }); 50 | 51 | animationDemoController.addStatusListener((AnimationStatus status) { 52 | print(status); 53 | }); 54 | 55 | // animationDemoController.forward(); 56 | } 57 | 58 | @override 59 | void dispose() { 60 | super.dispose(); 61 | 62 | animationDemoController.dispose(); 63 | } 64 | 65 | @override 66 | Widget build(BuildContext context) { 67 | return Center( 68 | child: AnimatedHeart( 69 | animations: [ 70 | animation, 71 | animationColor, 72 | ], 73 | controller: animationDemoController, 74 | ), 75 | ); 76 | } 77 | } 78 | 79 | class AnimatedHeart extends AnimatedWidget { 80 | final List animations; 81 | final AnimationController controller; 82 | 83 | AnimatedHeart({ 84 | this.animations, 85 | this.controller, 86 | }) : super(listenable: controller); 87 | 88 | @override 89 | Widget build(BuildContext context) { 90 | return IconButton( 91 | icon: Icon(Icons.favorite), 92 | iconSize: animations[0].value, 93 | color: animations[1].value, 94 | onPressed: () { 95 | switch (controller.status) { 96 | case AnimationStatus.completed: 97 | controller.reverse(); 98 | break; 99 | default: 100 | controller.forward(); 101 | } 102 | }, 103 | ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/demo/basic_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BasicDemo extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return ContainerBoxDecorationDemo(); 7 | } 8 | } 9 | 10 | class ContainerBoxDecorationDemo extends StatelessWidget { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | // color: Colors.grey[100], 15 | decoration: BoxDecoration( 16 | image: DecorationImage( 17 | image: NetworkImage('https://resources.ninghao.org/images/say-hello-to-barry.jpg'), 18 | alignment: Alignment.topCenter, 19 | // repeat: ImageRepeat.repeatY, 20 | fit: BoxFit.cover, 21 | colorFilter: ColorFilter.mode( 22 | Colors.indigoAccent[400].withOpacity(0.5), 23 | BlendMode.hardLight, 24 | ), 25 | ), 26 | ), 27 | child: Row( 28 | mainAxisAlignment: MainAxisAlignment.center, 29 | children: [ 30 | Container( 31 | child: Icon(Icons.pool, size: 32.0, color: Colors.white), 32 | // color: Color.fromRGBO(3, 54, 255, 1.0), 33 | padding: EdgeInsets.all(16.0), 34 | margin: EdgeInsets.all(8.0), 35 | width: 90.0, 36 | height: 90.0, 37 | decoration: BoxDecoration( 38 | color: Color.fromRGBO(3, 54, 255, 1.0), 39 | border: Border.all( 40 | color: Colors.indigoAccent[100], 41 | width: 3.0, 42 | style: BorderStyle.solid, 43 | ), 44 | // borderRadius: BorderRadius.circular(16.0), 45 | boxShadow: [ 46 | BoxShadow( 47 | offset: Offset(0.0, 16.0), 48 | color: Color.fromRGBO(16, 20, 188, 1.0), 49 | blurRadius: 25.0, 50 | spreadRadius: -9.0, 51 | ), 52 | ], 53 | shape: BoxShape.circle, 54 | // gradient: RadialGradient( 55 | // colors: [ 56 | // Color.fromRGBO(7, 102, 255, 1.0), 57 | // Color.fromRGBO(3, 28, 128, 1.0), 58 | // ], 59 | // ), 60 | gradient: LinearGradient( 61 | colors: [ 62 | Color.fromRGBO(7, 102, 255, 1.0), 63 | Color.fromRGBO(3, 28, 128, 1.0), 64 | ], 65 | begin: Alignment.topCenter, 66 | end: Alignment.bottomCenter, 67 | ), 68 | ), 69 | ), 70 | ], 71 | ), 72 | ); 73 | } 74 | } 75 | 76 | class RichTextDemo extends StatelessWidget { 77 | @override 78 | Widget build(BuildContext context) { 79 | return RichText( 80 | text: TextSpan( 81 | text: 'ninghao', 82 | style: TextStyle( 83 | color: Colors.deepPurpleAccent, 84 | fontSize: 34.0, 85 | fontStyle: FontStyle.italic, 86 | fontWeight: FontWeight.w100, 87 | ), 88 | children: [ 89 | TextSpan( 90 | text: '.net', 91 | style: TextStyle( 92 | fontSize: 17.0, 93 | color: Colors.grey, 94 | ), 95 | ) 96 | ], 97 | ), 98 | ); 99 | } 100 | } 101 | 102 | class TextDemo extends StatelessWidget { 103 | final TextStyle _textStyle = TextStyle( 104 | fontSize: 16.0, 105 | ); 106 | 107 | final String _author = '李白'; 108 | final String _title = '将进酒'; 109 | 110 | @override 111 | Widget build(BuildContext context) { 112 | // TODO: implement build 113 | return Text( 114 | '《 $_title 》—— $_author。君不见黄河之水天上来,奔流到海不复回。君不见高堂明镜悲白发,朝如青丝暮成雪。人生得意须尽欢,莫使金樽空对月。天生我材必有用,千金散尽还复来。烹羊宰牛且为乐,会须一饮三百杯。', 115 | textAlign: TextAlign.left, 116 | style: _textStyle, 117 | maxLines: 3, 118 | overflow: TextOverflow.ellipsis, 119 | ); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /lib/demo/bloc/bloc_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ninghao_flutter/demo/bloc/counter_bloc_demo.dart'; 3 | 4 | class BlocDemo extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return CounterProvider( 8 | bloc: CounterBloc(), 9 | child: Scaffold( 10 | appBar: AppBar( 11 | title: Text('BlocDemo'), 12 | elevation: 0.0, 13 | ), 14 | body: CounterHome(), 15 | floatingActionButton: CounterActionButton(), 16 | ), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/demo/bloc/counter_bloc_demo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class CounterHome extends StatelessWidget { 6 | @override 7 | Widget build(BuildContext context) { 8 | CounterBloc _counterBloc = CounterProvider.of(context).bloc; 9 | 10 | return Center( 11 | child: StreamBuilder( 12 | initialData: 0, 13 | stream: _counterBloc.count, 14 | builder: (context, snapshot) { 15 | return ActionChip( 16 | label: Text('${snapshot.data}'), 17 | onPressed: () { 18 | // _counterBloc.log(); 19 | _counterBloc.counter.add(1); 20 | }, 21 | ); 22 | }, 23 | ), 24 | ); 25 | } 26 | } 27 | 28 | class CounterActionButton extends StatelessWidget { 29 | @override 30 | Widget build(BuildContext context) { 31 | CounterBloc _counterBloc = CounterProvider.of(context).bloc; 32 | 33 | return FloatingActionButton( 34 | child: Icon(Icons.add), 35 | onPressed: () { 36 | // _counterBloc.log(); 37 | _counterBloc.counter.add(1); 38 | }, 39 | ); 40 | } 41 | } 42 | 43 | class CounterProvider extends InheritedWidget { 44 | final Widget child; 45 | final CounterBloc bloc; 46 | 47 | CounterProvider({ 48 | this.child, 49 | this.bloc, 50 | }) : super(child: child); 51 | 52 | static CounterProvider of(BuildContext context) => 53 | context.inheritFromWidgetOfExactType(CounterProvider); 54 | 55 | @override 56 | bool updateShouldNotify(CounterProvider oldWidget) { 57 | return true; 58 | } 59 | } 60 | 61 | class CounterBloc { 62 | int _count = 0; 63 | 64 | final _counterActionController = StreamController(); 65 | StreamSink get counter => _counterActionController.sink; 66 | 67 | final _counterController = StreamController(); 68 | Stream get count => _counterController.stream; 69 | 70 | CounterBloc() { 71 | _counterActionController.stream.listen(onData); 72 | } 73 | 74 | void onData(int data) { 75 | print('$data'); 76 | _count = data + _count; 77 | _counterController.add(_count); 78 | } 79 | 80 | void disponse() { 81 | _counterActionController.close(); 82 | _counterController.close(); 83 | } 84 | 85 | void log() { 86 | print('BLoC'); 87 | } 88 | } -------------------------------------------------------------------------------- /lib/demo/bottom_navigation_bar_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomNavigationBarDemo extends StatefulWidget { 4 | @override 5 | State createState() { 6 | // TODO: implement createState 7 | return _BottomNavigationBarDemoState(); 8 | } 9 | } 10 | 11 | class _BottomNavigationBarDemoState extends State { 12 | int _currentIndex = 0; 13 | 14 | void _onTapHandler (int index) { 15 | setState(() { 16 | _currentIndex = index; 17 | }); 18 | } 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | // TODO: implement build 23 | return BottomNavigationBar( 24 | currentIndex: _currentIndex, 25 | onTap: _onTapHandler, 26 | type: BottomNavigationBarType.fixed, 27 | fixedColor: Colors.black, 28 | items: [ 29 | BottomNavigationBarItem( 30 | icon: Icon(Icons.explore), 31 | title: Text('Explore'), 32 | ), 33 | BottomNavigationBarItem( 34 | icon: Icon(Icons.history), 35 | title: Text('History'), 36 | ), 37 | BottomNavigationBarItem( 38 | icon: Icon(Icons.list), 39 | title: Text('List'), 40 | ), 41 | BottomNavigationBarItem( 42 | icon: Icon(Icons.person), 43 | title: Text('My'), 44 | ), 45 | ], 46 | ); 47 | } 48 | } -------------------------------------------------------------------------------- /lib/demo/bottom_sheet_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:async'; 3 | 4 | class BottomSheetDemo extends StatefulWidget { 5 | @override 6 | _BottomSheetDemoState createState() => _BottomSheetDemoState(); 7 | } 8 | 9 | class _BottomSheetDemoState extends State { 10 | final _bottomSheetScaffoldKey = GlobalKey(); 11 | 12 | _openBottomSheet() { 13 | _bottomSheetScaffoldKey 14 | .currentState 15 | .showBottomSheet((BuildContext context) { 16 | return BottomAppBar( 17 | child: Container( 18 | height: 90.0, 19 | width: double.infinity, 20 | padding: EdgeInsets.all(16.0), 21 | child: Row( 22 | children: [ 23 | Icon(Icons.pause_circle_outline), 24 | SizedBox(width: 16.0,), 25 | Text('01:30 / 03:30'), 26 | Expanded( 27 | child: Text('Fix you - Coldplay', textAlign: TextAlign.right,), 28 | ), 29 | ], 30 | ), 31 | ), 32 | ); 33 | }); 34 | } 35 | 36 | Future _openModalBottomSheet() async { 37 | final option = await showModalBottomSheet( 38 | context: context, 39 | builder: (BuildContext context) { 40 | return Container( 41 | height: 200.0, 42 | child: Column( 43 | children: [ 44 | ListTile( 45 | title: Text('Option A'), 46 | onTap: () { 47 | Navigator.pop(context, 'A'); 48 | }, 49 | ), 50 | ListTile( 51 | title: Text('Option B'), 52 | onTap: () { 53 | Navigator.pop(context, 'B'); 54 | }, 55 | ), 56 | ListTile( 57 | title: Text('Option C'), 58 | onTap: () { 59 | Navigator.pop(context, 'C'); 60 | }, 61 | ), 62 | ], 63 | ), 64 | ); 65 | } 66 | ); 67 | 68 | print(option); 69 | } 70 | 71 | @override 72 | Widget build(BuildContext context) { 73 | return Scaffold( 74 | key: _bottomSheetScaffoldKey, 75 | appBar: AppBar( 76 | title: Text('BottomSheetDemo'), 77 | elevation: 0.0, 78 | ), 79 | body: Container( 80 | padding: EdgeInsets.all(16.0), 81 | child: Column( 82 | mainAxisAlignment: MainAxisAlignment.center, 83 | children: [ 84 | Row( 85 | mainAxisAlignment: MainAxisAlignment.center, 86 | children: [ 87 | FlatButton( 88 | child: Text('Open BottomSheet'), 89 | onPressed: _openBottomSheet, 90 | ), 91 | FlatButton( 92 | child: Text('Modal BottomSheet'), 93 | onPressed: _openModalBottomSheet, 94 | ), 95 | ] 96 | ), 97 | ], 98 | ), 99 | ), 100 | ); 101 | } 102 | } -------------------------------------------------------------------------------- /lib/demo/button_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ButtonDemo extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | final Widget flatButtonDemo = Row( 7 | mainAxisAlignment: MainAxisAlignment.center, 8 | children: [ 9 | FlatButton( 10 | child: Text('Button'), 11 | onPressed: () {}, 12 | splashColor: Colors.grey, 13 | textColor: Theme.of(context).accentColor, 14 | ), 15 | FlatButton.icon( 16 | icon: Icon(Icons.add), 17 | label: Text('Button'), 18 | onPressed: () {}, 19 | splashColor: Colors.grey, 20 | textColor: Theme.of(context).accentColor, 21 | ), 22 | ], 23 | ); 24 | 25 | final Widget raisedButtonDemo = Row( 26 | mainAxisAlignment: MainAxisAlignment.center, 27 | children: [ 28 | Theme( 29 | data: Theme.of(context).copyWith( 30 | buttonColor: Theme.of(context).accentColor, 31 | buttonTheme: ButtonThemeData( 32 | textTheme: ButtonTextTheme.primary, 33 | // shape: BeveledRectangleBorder( 34 | // borderRadius: BorderRadius.circular(5.0), 35 | // ), 36 | shape: StadiumBorder(), 37 | ), 38 | ), 39 | child: RaisedButton( 40 | child: Text('Button'), 41 | onPressed: () {}, 42 | splashColor: Colors.grey, 43 | elevation: 0.0, 44 | // color: Theme.of(context).accentColor, 45 | // textColor: Colors.white, 46 | // textTheme: ButtonTextTheme.primary, 47 | ), 48 | ), 49 | SizedBox(width: 16.0,), 50 | RaisedButton.icon( 51 | icon: Icon(Icons.add), 52 | label: Text('Button'), 53 | onPressed: () {}, 54 | splashColor: Colors.grey, 55 | elevation: 12.0, 56 | textColor: Theme.of(context).accentColor, 57 | ), 58 | ], 59 | ); 60 | 61 | final Widget outlineButtonDemo = Row( 62 | mainAxisAlignment: MainAxisAlignment.center, 63 | children: [ 64 | Theme( 65 | data: Theme.of(context).copyWith( 66 | buttonColor: Theme.of(context).accentColor, 67 | buttonTheme: ButtonThemeData( 68 | textTheme: ButtonTextTheme.primary, 69 | // shape: BeveledRectangleBorder( 70 | // borderRadius: BorderRadius.circular(5.0), 71 | // ), 72 | shape: StadiumBorder(), 73 | ), 74 | ), 75 | child: OutlineButton( 76 | child: Text('Button'), 77 | onPressed: () {}, 78 | splashColor: Colors.grey[100], 79 | borderSide: BorderSide( 80 | color: Colors.black, 81 | ), 82 | // color: Theme.of(context).accentColor, 83 | textColor: Colors.black, 84 | highlightedBorderColor: Colors.grey, 85 | // textTheme: ButtonTextTheme.primary, 86 | ), 87 | ), 88 | SizedBox(width: 16.0,), 89 | OutlineButton.icon( 90 | icon: Icon(Icons.add), 91 | label: Text('Button'), 92 | onPressed: () {}, 93 | splashColor: Colors.grey, 94 | textColor: Theme.of(context).accentColor, 95 | ), 96 | ], 97 | ); 98 | 99 | final Widget fixedWidthButton = Row( 100 | mainAxisAlignment: MainAxisAlignment.center, 101 | children: [ 102 | Container( 103 | width: 130.0, 104 | child: OutlineButton( 105 | child: Text('Button'), 106 | onPressed: () {}, 107 | splashColor: Colors.grey[100], 108 | borderSide: BorderSide( 109 | color: Colors.black, 110 | ), 111 | textColor: Colors.black, 112 | highlightedBorderColor: Colors.grey, 113 | ), 114 | ), 115 | ], 116 | ); 117 | 118 | final Widget expandedButton = Row( 119 | mainAxisAlignment: MainAxisAlignment.center, 120 | children: [ 121 | Expanded( 122 | child: OutlineButton( 123 | child: Text('Button'), 124 | onPressed: () {}, 125 | splashColor: Colors.grey[100], 126 | borderSide: BorderSide( 127 | color: Colors.black, 128 | ), 129 | textColor: Colors.black, 130 | highlightedBorderColor: Colors.grey, 131 | ), 132 | ), 133 | SizedBox(width: 16.0,), 134 | Expanded( 135 | flex: 2, 136 | child: OutlineButton( 137 | child: Text('Button'), 138 | onPressed: () {}, 139 | splashColor: Colors.grey[100], 140 | borderSide: BorderSide( 141 | color: Colors.black, 142 | ), 143 | textColor: Colors.black, 144 | highlightedBorderColor: Colors.grey, 145 | ), 146 | ), 147 | ], 148 | ); 149 | 150 | final Widget buttonBarDemo = Row( 151 | mainAxisAlignment: MainAxisAlignment.center, 152 | children: [ 153 | Theme( 154 | data: Theme.of(context).copyWith( 155 | buttonTheme: ButtonThemeData( 156 | padding: EdgeInsets.symmetric(horizontal: 32.0), 157 | ), 158 | ), 159 | child: ButtonBar( 160 | children: [ 161 | OutlineButton( 162 | child: Text('Button'), 163 | onPressed: () {}, 164 | splashColor: Colors.grey[100], 165 | borderSide: BorderSide( 166 | color: Colors.black, 167 | ), 168 | textColor: Colors.black, 169 | highlightedBorderColor: Colors.grey, 170 | ), 171 | OutlineButton( 172 | child: Text('Button'), 173 | onPressed: () {}, 174 | splashColor: Colors.grey[100], 175 | borderSide: BorderSide( 176 | color: Colors.black, 177 | ), 178 | textColor: Colors.black, 179 | highlightedBorderColor: Colors.grey, 180 | ), 181 | ], 182 | ), 183 | ), 184 | ], 185 | ); 186 | 187 | return Scaffold( 188 | appBar: AppBar( 189 | title: Text('ButtonDemo'), 190 | elevation: 0.0, 191 | ), 192 | body: Container( 193 | padding: EdgeInsets.all(16.0), 194 | child: Column( 195 | mainAxisAlignment: MainAxisAlignment.center, 196 | children: [ 197 | flatButtonDemo, 198 | raisedButtonDemo, 199 | outlineButtonDemo, 200 | fixedWidthButton, 201 | expandedButton, 202 | buttonBarDemo, 203 | ], 204 | ), 205 | ) 206 | ); 207 | } 208 | } -------------------------------------------------------------------------------- /lib/demo/card_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../model/post.dart'; 3 | 4 | class CardDemo extends StatefulWidget { 5 | @override 6 | _CardDemoState createState() => _CardDemoState(); 7 | } 8 | 9 | class _CardDemoState extends State { 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: AppBar( 14 | title: Text('CardDemo'), 15 | elevation: 0.0, 16 | ), 17 | body: Container( 18 | padding: EdgeInsets.all(16.0), 19 | child: ListView( 20 | children: posts.map((post) { 21 | return Card( 22 | child: Column( 23 | children: [ 24 | AspectRatio( 25 | aspectRatio: 16/9, 26 | child: ClipRRect( 27 | borderRadius: BorderRadius.only( 28 | topLeft: Radius.circular(4.0), 29 | topRight: Radius.circular(4.0), 30 | ), 31 | child: Image.network( 32 | post.imageUrl, 33 | fit: BoxFit.cover, 34 | ), 35 | ), 36 | ), 37 | ListTile( 38 | leading: CircleAvatar( 39 | backgroundImage: NetworkImage(post.imageUrl), 40 | ), 41 | title: Text(post.title), 42 | subtitle: Text(post.author), 43 | ), 44 | Container( 45 | padding: EdgeInsets.all(16.0), 46 | child: Text(post.description, maxLines: 2, overflow: TextOverflow.ellipsis,), 47 | ), 48 | ButtonTheme.bar( 49 | child: ButtonBar( 50 | children: [ 51 | FlatButton( 52 | child: Text('Like'.toUpperCase()), 53 | onPressed: () {}, 54 | ), 55 | FlatButton( 56 | child: Text('Read'.toUpperCase()), 57 | onPressed: () {}, 58 | ), 59 | ], 60 | ), 61 | ), 62 | ], 63 | ), 64 | ); 65 | }).toList(), 66 | ), 67 | ) 68 | ); 69 | } 70 | } -------------------------------------------------------------------------------- /lib/demo/checkbox_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CheckboxDemo extends StatefulWidget { 4 | @override 5 | _CheckboxDemoState createState() => _CheckboxDemoState(); 6 | } 7 | 8 | class _CheckboxDemoState extends State { 9 | bool _checkboxItemA = true; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text('CheckboxDemo'), 16 | elevation: 0.0, 17 | ), 18 | body: Container( 19 | padding: EdgeInsets.all(16.0), 20 | child: Column( 21 | mainAxisAlignment: MainAxisAlignment.center, 22 | children: [ 23 | CheckboxListTile( 24 | value: _checkboxItemA, 25 | onChanged: (value) { 26 | setState(() { 27 | _checkboxItemA = value; 28 | }); 29 | }, 30 | title: Text('Checkbox Item A'), 31 | subtitle: Text('Description'), 32 | secondary: Icon(Icons.bookmark), 33 | selected: _checkboxItemA, 34 | ), 35 | Row( 36 | mainAxisAlignment: MainAxisAlignment.center, 37 | children: [ 38 | // Checkbox( 39 | // value: _checkboxItemA, 40 | // onChanged: (value) { 41 | // setState(() { 42 | // _checkboxItemA = value; 43 | // }); 44 | // }, 45 | // activeColor: Colors.black, 46 | // ), 47 | ], 48 | ), 49 | ], 50 | ), 51 | ) 52 | ); 53 | } 54 | } -------------------------------------------------------------------------------- /lib/demo/chip_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ChipDemo extends StatefulWidget { 4 | @override 5 | _ChipDemoState createState() => _ChipDemoState(); 6 | } 7 | 8 | class _ChipDemoState extends State { 9 | List _tags = [ 10 | 'Apple', 11 | 'Banana', 12 | 'Lemon', 13 | ]; 14 | 15 | String _action = 'Nothing'; 16 | List _selected = []; 17 | String _choice = 'Lemon'; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Scaffold( 22 | appBar: AppBar( 23 | title: Text('ChipDemo'), 24 | elevation: 0.0, 25 | ), 26 | body: Container( 27 | padding: EdgeInsets.all(16.0), 28 | child: Column( 29 | mainAxisAlignment: MainAxisAlignment.center, 30 | children: [ 31 | Wrap( 32 | spacing: 8.0, 33 | runSpacing: 8.0, 34 | children: [ 35 | Chip( 36 | label: Text('Life'), 37 | ), 38 | Chip( 39 | label: Text('Sunset'), 40 | backgroundColor: Colors.orange, 41 | ), 42 | Chip( 43 | label: Text('Wanghao'), 44 | avatar: CircleAvatar( 45 | backgroundColor: Colors.grey, 46 | child: Text('皓'), 47 | ), 48 | ), 49 | Chip( 50 | label: Text('Wanghao'), 51 | avatar: CircleAvatar( 52 | backgroundImage: NetworkImage( 53 | 'https://resources.ninghao.net/images/wanghao.jpg' 54 | ), 55 | ), 56 | ), 57 | Chip( 58 | label: Text('City'), 59 | onDeleted: () {}, 60 | deleteIcon: Icon(Icons.delete), 61 | deleteIconColor: Colors.redAccent, 62 | deleteButtonTooltipMessage: 'Remove this tag', 63 | ), 64 | Divider( 65 | color: Colors.grey, 66 | height: 32.0, 67 | // indent: 32.0, 68 | ), 69 | Wrap( 70 | spacing: 8.0, 71 | children: _tags.map((tag) { 72 | return Chip( 73 | label: Text(tag), 74 | onDeleted: () { 75 | setState(() { 76 | _tags.remove(tag); 77 | }); 78 | }, 79 | ); 80 | }).toList(), 81 | ), 82 | Divider( 83 | color: Colors.grey, 84 | height: 32.0, 85 | // indent: 32.0, 86 | ), 87 | Container( 88 | width: double.infinity, 89 | child: Text('ActionChip: $_action'), 90 | ), 91 | Wrap( 92 | spacing: 8.0, 93 | children: _tags.map((tag) { 94 | return ActionChip( 95 | label: Text(tag), 96 | onPressed: () { 97 | setState(() { 98 | _action = tag; 99 | }); 100 | }, 101 | ); 102 | }).toList(), 103 | ), 104 | Divider( 105 | color: Colors.grey, 106 | height: 32.0, 107 | // indent: 32.0, 108 | ), 109 | Container( 110 | width: double.infinity, 111 | child: Text('FilterChip: ${_selected.toString()}'), 112 | ), 113 | Wrap( 114 | spacing: 8.0, 115 | children: _tags.map((tag) { 116 | return FilterChip( 117 | label: Text(tag), 118 | selected: _selected.contains(tag), 119 | onSelected: (value) { 120 | setState(() { 121 | if (_selected.contains(tag)) { 122 | _selected.remove(tag); 123 | } else { 124 | _selected.add(tag); 125 | } 126 | }); 127 | }, 128 | ); 129 | }).toList(), 130 | ), 131 | Divider( 132 | color: Colors.grey, 133 | height: 32.0, 134 | // indent: 32.0, 135 | ), 136 | Container( 137 | width: double.infinity, 138 | child: Text('ChoiceChip: $_choice'), 139 | ), 140 | Wrap( 141 | spacing: 8.0, 142 | children: _tags.map((tag) { 143 | return ChoiceChip( 144 | label: Text(tag), 145 | selectedColor: Colors.black, 146 | selected: _choice == tag, 147 | onSelected: (value) { 148 | setState(() { 149 | _choice = tag; 150 | }); 151 | }, 152 | ); 153 | }).toList(), 154 | ), 155 | ], 156 | ), 157 | ], 158 | ), 159 | ), 160 | floatingActionButton: FloatingActionButton( 161 | child: Icon(Icons.restore), 162 | onPressed: () { 163 | setState(() { 164 | _tags = [ 165 | 'Apple', 166 | 'Banana', 167 | 'Lemon', 168 | ]; 169 | 170 | _selected = []; 171 | 172 | _choice = 'Lemon'; 173 | }); 174 | }, 175 | ), 176 | ); 177 | } 178 | } -------------------------------------------------------------------------------- /lib/demo/data_table_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../model/post.dart'; 3 | 4 | class DataTableDemo extends StatefulWidget { 5 | @override 6 | _DataTableDemoState createState() => _DataTableDemoState(); 7 | } 8 | 9 | class _DataTableDemoState extends State { 10 | int _sortColumnIndex; 11 | bool _sortAscending = true; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text('DataTableDemo'), 18 | elevation: 0.0, 19 | ), 20 | body: Container( 21 | padding: EdgeInsets.all(16.0), 22 | child: ListView( 23 | children: [ 24 | DataTable( 25 | sortColumnIndex: _sortColumnIndex, 26 | sortAscending: _sortAscending, 27 | // onSelectAll: (bool value) {}, 28 | columns: [ 29 | DataColumn( 30 | label: Text('Title'), 31 | onSort: (int index, bool ascending) { 32 | setState(() { 33 | _sortColumnIndex = index; 34 | _sortAscending = ascending; 35 | 36 | posts.sort((a, b) { 37 | if (!ascending) { 38 | final c = a; 39 | a = b; 40 | b = c; 41 | } 42 | 43 | return a.title.length.compareTo(b.title.length); 44 | }); 45 | }); 46 | }, 47 | ), 48 | DataColumn( 49 | label: Text('Author'), 50 | ), 51 | DataColumn( 52 | label: Text('Image'), 53 | ), 54 | ], 55 | rows: posts.map((post) { 56 | return DataRow( 57 | selected: post.selected, 58 | onSelectChanged: (bool value) { 59 | setState(() { 60 | if (post.selected != value) { 61 | post.selected = value; 62 | } 63 | }); 64 | }, 65 | cells: [ 66 | DataCell(Text(post.title)), 67 | DataCell(Text(post.author)), 68 | DataCell(Image.network(post.imageUrl)), 69 | ] 70 | ); 71 | }).toList(), 72 | ), 73 | ], 74 | ), 75 | ) 76 | ); 77 | } 78 | } -------------------------------------------------------------------------------- /lib/demo/datetime_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:intl/intl.dart'; 3 | import 'dart:async'; 4 | 5 | class DateTimeDemo extends StatefulWidget { 6 | @override 7 | _DateTimeDemoState createState() => _DateTimeDemoState(); 8 | } 9 | 10 | class _DateTimeDemoState extends State { 11 | DateTime selectedDate = DateTime.now(); 12 | TimeOfDay selectedTime = TimeOfDay(hour: 9, minute: 30); 13 | 14 | Future _selectDate() async { 15 | final DateTime date = await showDatePicker( 16 | context: context, 17 | initialDate: selectedDate, 18 | firstDate: DateTime(1900), 19 | lastDate: DateTime(2100), 20 | ); 21 | 22 | if (date == null) return; 23 | 24 | setState(() { 25 | selectedDate = date; 26 | }); 27 | } 28 | 29 | Future _selectTime() async { 30 | final TimeOfDay time = await showTimePicker( 31 | context: context, 32 | initialTime: selectedTime, 33 | ); 34 | 35 | if (time == null) return; 36 | 37 | setState(() { 38 | selectedTime = time; 39 | }); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return Scaffold( 45 | appBar: AppBar( 46 | title: Text('DateTimeDemo'), 47 | elevation: 0.0, 48 | ), 49 | body: Container( 50 | padding: EdgeInsets.all(16.0), 51 | child: Column( 52 | mainAxisAlignment: MainAxisAlignment.center, 53 | children: [ 54 | Row( 55 | mainAxisAlignment: MainAxisAlignment.center, 56 | children: [ 57 | InkWell( 58 | onTap: _selectDate, 59 | child: Row( 60 | children: [ 61 | Text(DateFormat.yMMMMd().format(selectedDate)), 62 | Icon(Icons.arrow_drop_down), 63 | ], 64 | ), 65 | ), 66 | InkWell( 67 | onTap: _selectTime, 68 | child: Row( 69 | children: [ 70 | Text(selectedTime.format(context)), 71 | Icon(Icons.arrow_drop_down), 72 | ], 73 | ), 74 | ), 75 | ], 76 | ), 77 | ], 78 | ), 79 | ) 80 | ); 81 | } 82 | } -------------------------------------------------------------------------------- /lib/demo/drawer_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DrawerDemo extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | // TODO: implement build 7 | return Drawer( 8 | child: ListView( 9 | padding: EdgeInsets.zero, 10 | children: [ 11 | UserAccountsDrawerHeader( 12 | accountName: 13 | Text('wanghao', style: TextStyle(fontWeight: FontWeight.bold)), 14 | accountEmail: Text('wanghao@ninghao.net'), 15 | currentAccountPicture: CircleAvatar( 16 | backgroundImage: NetworkImage( 17 | 'https://resources.ninghao.org/images/wanghao.jpg'), 18 | ), 19 | decoration: BoxDecoration( 20 | color: Colors.yellow[400], 21 | image: DecorationImage( 22 | image: NetworkImage( 23 | 'https://resources.ninghao.org/images/childhood-in-a-picture.jpg'), 24 | fit: BoxFit.cover, 25 | colorFilter: ColorFilter.mode( 26 | Colors.yellow[400].withOpacity(0.6), BlendMode.hardLight), 27 | ), 28 | ), 29 | ), 30 | ListTile( 31 | title: Text( 32 | 'Messages', 33 | textAlign: TextAlign.right, 34 | ), 35 | trailing: Icon(Icons.message, color: Colors.black12, size: 22.0), 36 | onTap: () => Navigator.pop(context), 37 | ), 38 | ListTile( 39 | title: Text( 40 | 'Favorite', 41 | textAlign: TextAlign.right, 42 | ), 43 | trailing: Icon(Icons.favorite, color: Colors.black12, size: 22.0), 44 | onTap: () => Navigator.pop(context), 45 | ), 46 | ListTile( 47 | title: Text( 48 | 'Settings', 49 | textAlign: TextAlign.right, 50 | ), 51 | trailing: Icon(Icons.settings, color: Colors.black12, size: 22.0), 52 | onTap: () => Navigator.pop(context), 53 | ), 54 | ], 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/demo/expansion_panel_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ExpansionPanelItem { 4 | final String headerText; 5 | final Widget body; 6 | bool isExpanded; 7 | 8 | ExpansionPanelItem({ 9 | this.headerText, 10 | this.body, 11 | this.isExpanded, 12 | }); 13 | } 14 | 15 | class ExpansionPanelDemo extends StatefulWidget { 16 | @override 17 | _ExpansionPanelDemoState createState() => _ExpansionPanelDemoState(); 18 | } 19 | 20 | class _ExpansionPanelDemoState extends State { 21 | List _expansionPanelItems; 22 | 23 | @override 24 | void initState() { 25 | super.initState(); 26 | 27 | _expansionPanelItems = [ 28 | ExpansionPanelItem( 29 | headerText: 'Panel A', 30 | body: Container( 31 | padding: EdgeInsets.all(16.0), 32 | width: double.infinity, 33 | child: Text('Content for Panel A.'), 34 | ), 35 | isExpanded: false, 36 | ), 37 | ExpansionPanelItem( 38 | headerText: 'Panel B', 39 | body: Container( 40 | padding: EdgeInsets.all(16.0), 41 | width: double.infinity, 42 | child: Text('Content for Panel B.'), 43 | ), 44 | isExpanded: false, 45 | ), 46 | ExpansionPanelItem( 47 | headerText: 'Panel C', 48 | body: Container( 49 | padding: EdgeInsets.all(16.0), 50 | width: double.infinity, 51 | child: Text('Content for Panel C.'), 52 | ), 53 | isExpanded: false, 54 | ), 55 | ]; 56 | } 57 | 58 | @override 59 | Widget build(BuildContext context) { 60 | return Scaffold( 61 | appBar: AppBar( 62 | title: Text('ExpansionPanelDemo'), 63 | elevation: 0.0, 64 | ), 65 | body: Container( 66 | padding: EdgeInsets.all(16.0), 67 | child: Column( 68 | mainAxisAlignment: MainAxisAlignment.center, 69 | children: [ 70 | ExpansionPanelList( 71 | expansionCallback: (int panelIndex, bool isExpanded) { 72 | setState(() { 73 | _expansionPanelItems[panelIndex].isExpanded = !isExpanded; 74 | }); 75 | }, 76 | children: _expansionPanelItems.map( 77 | (ExpansionPanelItem item) { 78 | return ExpansionPanel( 79 | isExpanded: item.isExpanded, 80 | body: item.body, 81 | headerBuilder: (BuildContext context, bool isExpanded) { 82 | return Container( 83 | padding: EdgeInsets.all(16.0), 84 | child: Text( 85 | item.headerText, 86 | style: Theme.of(context).textTheme.title, 87 | ), 88 | ); 89 | }, 90 | ); 91 | } 92 | ).toList(), 93 | ), 94 | ], 95 | ), 96 | ), 97 | ); 98 | } 99 | } -------------------------------------------------------------------------------- /lib/demo/floating_action_button_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FloatingActionButtonDemo extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | final Widget _floatingActionButton = FloatingActionButton( 7 | onPressed: () {}, 8 | child: Icon(Icons.add), 9 | elevation: 0.0, 10 | backgroundColor: Colors.black87, 11 | // shape: BeveledRectangleBorder( 12 | // borderRadius: BorderRadius.circular(30.0) 13 | // ), 14 | ); 15 | 16 | final Widget _floatingActionButtonExtended = FloatingActionButton.extended( 17 | onPressed: () {}, 18 | icon: Icon(Icons.add), 19 | label: Text('Add'), 20 | ); 21 | 22 | return Scaffold( 23 | appBar: AppBar( 24 | title: Text('FloatingActionButtonDemo'), 25 | elevation: 0.0, 26 | ), 27 | floatingActionButton: _floatingActionButton, 28 | floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, 29 | bottomNavigationBar: BottomAppBar( 30 | child: Container( 31 | height: 80.0, 32 | ), 33 | shape: CircularNotchedRectangle(), 34 | ), 35 | ); 36 | } 37 | } -------------------------------------------------------------------------------- /lib/demo/form_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FormDemo extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Scaffold( 7 | appBar: AppBar( 8 | title: Text('FormDemo'), 9 | elevation: 0.0, 10 | ), 11 | body: Theme( 12 | data: Theme.of(context).copyWith( 13 | primaryColor: Colors.black, 14 | ), 15 | child: Container( 16 | padding: EdgeInsets.all(16.0), 17 | child: Column( 18 | mainAxisAlignment: MainAxisAlignment.center, 19 | children: [ 20 | RegisterForm(), 21 | ], 22 | ), 23 | ), 24 | ), 25 | ); 26 | } 27 | } 28 | 29 | class RegisterForm extends StatefulWidget { 30 | @override 31 | RegisterFormState createState() => RegisterFormState(); 32 | } 33 | 34 | class RegisterFormState extends State { 35 | final registerFormKey = GlobalKey(); 36 | String username, password; 37 | bool autovalidate = false; 38 | 39 | void submitRegisterForm() { 40 | if (registerFormKey.currentState.validate()) { 41 | registerFormKey.currentState.save(); 42 | 43 | debugPrint('username: $username'); 44 | debugPrint('password: $password'); 45 | 46 | Scaffold.of(context).showSnackBar( 47 | SnackBar( 48 | content: Text('Registering...'), 49 | ) 50 | ); 51 | } else { 52 | setState(() { 53 | autovalidate = true; 54 | }); 55 | } 56 | } 57 | 58 | String validateUsername(value) { 59 | if (value.isEmpty) { 60 | return 'Username is required.'; 61 | } 62 | 63 | return null; 64 | } 65 | 66 | String validatePassword(value) { 67 | if (value.isEmpty) { 68 | return 'Password is required.'; 69 | } 70 | 71 | return null; 72 | } 73 | 74 | @override 75 | Widget build(BuildContext context) { 76 | return Form( 77 | key: registerFormKey, 78 | child: Column( 79 | children: [ 80 | TextFormField( 81 | decoration: InputDecoration( 82 | labelText: 'Username', 83 | helperText: '', 84 | ), 85 | onSaved: (value) { 86 | username = value; 87 | }, 88 | validator: validateUsername, 89 | autovalidate: autovalidate, 90 | ), 91 | TextFormField( 92 | obscureText: true, 93 | decoration: InputDecoration( 94 | labelText: 'Password', 95 | helperText: '', 96 | ), 97 | onSaved: (value) { 98 | password = value; 99 | }, 100 | validator: validatePassword, 101 | autovalidate: autovalidate, 102 | ), 103 | SizedBox(height: 32.0,), 104 | Container( 105 | width: double.infinity, 106 | child: RaisedButton( 107 | color: Theme.of(context).accentColor, 108 | child: Text('Register', style: TextStyle(color: Colors.white)), 109 | elevation: 0.0, 110 | onPressed: submitRegisterForm, 111 | ), 112 | ), 113 | ], 114 | ), 115 | ); 116 | } 117 | } 118 | 119 | class TextFieldDemo extends StatefulWidget { 120 | @override 121 | TextFieldDemoState createState() => TextFieldDemoState(); 122 | } 123 | 124 | class TextFieldDemoState extends State { 125 | final textEditingController = TextEditingController(); 126 | 127 | @override 128 | void dispose() { 129 | textEditingController.dispose(); 130 | super.dispose(); 131 | } 132 | 133 | @override 134 | void initState() { 135 | super.initState(); 136 | // textEditingController.text = 'hi'; 137 | textEditingController.addListener( 138 | () { 139 | debugPrint('input: ${textEditingController.text}'); 140 | } 141 | ); 142 | } 143 | 144 | @override 145 | Widget build(BuildContext context) { 146 | return TextField( 147 | controller: textEditingController, 148 | // onChanged: (value) { 149 | // debugPrint('input: $value'); 150 | // }, 151 | onSubmitted: (value) { 152 | debugPrint('submit: $value'); 153 | }, 154 | decoration: InputDecoration( 155 | icon: Icon(Icons.subject), 156 | labelText: 'Title', 157 | hintText: 'Enter the post title.', 158 | // border: InputBorder.none, 159 | // border: OutlineInputBorder(), 160 | filled: true, 161 | ), 162 | ); 163 | } 164 | } 165 | 166 | class ThemeDemo extends StatelessWidget { 167 | @override 168 | Widget build(BuildContext context) { 169 | return Container( 170 | color: Theme.of(context).accentColor, 171 | ); 172 | } 173 | } -------------------------------------------------------------------------------- /lib/demo/hello_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Hello extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Center( 7 | child: Text( 8 | 'hello', 9 | textDirection: TextDirection.ltr, 10 | style: TextStyle( 11 | fontSize: 40.0, 12 | fontWeight: FontWeight.bold, 13 | color: Colors.black87, 14 | ) 15 | ), 16 | ); 17 | } 18 | } -------------------------------------------------------------------------------- /lib/demo/http/http_demo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:http/http.dart' as http; 5 | import 'dart:async'; 6 | 7 | class HttpDemo extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return Scaffold( 11 | appBar: AppBar( 12 | title: Text('HttpDemo'), 13 | elevation: 0.0, 14 | ), 15 | body: HttpDemoHome(), 16 | ); 17 | } 18 | } 19 | 20 | class HttpDemoHome extends StatefulWidget { 21 | @override 22 | _HttpDemoHomeState createState() => _HttpDemoHomeState(); 23 | } 24 | 25 | class _HttpDemoHomeState extends State { 26 | @override 27 | void initState() { 28 | super.initState(); 29 | // fetchPosts() 30 | // .then((value) => print(value)); 31 | 32 | // final post = { 33 | // 'title': 'hello', 34 | // 'description': 'nice to meet you.', 35 | // }; 36 | 37 | // print(post['title']); 38 | // print(post['description']); 39 | 40 | // final postJson = json.encode(post); 41 | // print(postJson); 42 | 43 | // final postJsonConverted = json.decode(postJson); 44 | // print(postJsonConverted['title']); 45 | // print(postJsonConverted['description']); 46 | // print(postJsonConverted is Map); 47 | 48 | // final postModel = Post.fromJson(postJsonConverted); 49 | // print('title: ${postModel.title}, description: ${postModel.description}'); 50 | 51 | // print('${json.encode(postModel)}'); 52 | } 53 | 54 | Future> fetchPosts() async { 55 | final response = 56 | await http.get('https://resources.ninghao.net/demo/posts.json'); 57 | 58 | // print('statusCode: ${response.statusCode}'); 59 | // print('body: ${response.body}'); 60 | 61 | if (response.statusCode == 200) { 62 | final responseBody = json.decode(response.body); 63 | List posts = responseBody['posts'] 64 | .map((item) => Post.fromJson(item)) 65 | .toList(); 66 | 67 | return posts; 68 | } else { 69 | throw Exception('Failed to fetch posts.'); 70 | } 71 | } 72 | 73 | @override 74 | Widget build(BuildContext context) { 75 | return FutureBuilder( 76 | future: fetchPosts(), 77 | builder: (BuildContext context, AsyncSnapshot snapshot) { 78 | print('data: ${snapshot.data}'); 79 | print('connectionState: ${snapshot.connectionState}'); 80 | 81 | if (snapshot.connectionState == ConnectionState.waiting) { 82 | return Center( 83 | child: Text('loading...'), 84 | ); 85 | } 86 | 87 | return ListView( 88 | children: snapshot.data.map((item) { 89 | return ListTile( 90 | title: Text(item.title), 91 | subtitle: Text(item.author), 92 | leading: CircleAvatar( 93 | backgroundImage: NetworkImage(item.imageUrl), 94 | ), 95 | ); 96 | }).toList(), 97 | ); 98 | }, 99 | ); 100 | } 101 | } 102 | 103 | class Post { 104 | final int id; 105 | final String title; 106 | final String description; 107 | final String author; 108 | final String imageUrl; 109 | 110 | Post( 111 | this.id, 112 | this.title, 113 | this.description, 114 | this.author, 115 | this.imageUrl, 116 | ); 117 | 118 | Post.fromJson(Map json) 119 | : id = json['id'], 120 | title = json['title'], 121 | description = json['description'], 122 | author = json['author'], 123 | imageUrl = json['imageUrl']; 124 | 125 | Map toJson() => { 126 | 'title': title, 127 | 'descritpion': description, 128 | }; 129 | } 130 | -------------------------------------------------------------------------------- /lib/demo/i18n/i18n_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | // import 'package:ninghao_flutter/demo/i18n/map/ninghao_demo_localizations.dart'; 3 | import 'package:ninghao_flutter/demo/i18n/intl/ninghao_demo_localizations.dart'; 4 | 5 | class I18nDemo extends StatelessWidget { 6 | @override 7 | Widget build(BuildContext context) { 8 | Locale locale = Localizations.localeOf(context); 9 | 10 | return Scaffold( 11 | appBar: AppBar( 12 | title: Text('I18nDemo'), 13 | elevation: 0.0, 14 | ), 15 | body: Center( 16 | child: Column( 17 | mainAxisAlignment: MainAxisAlignment.center, 18 | children: [ 19 | Text(locale.toString()), 20 | Text( 21 | // Localizations.of(context, NinghaoDemoLocalizations).title, 22 | // NinghaoDemoLocalizations.of(context).title, 23 | NinghaoDemoLocalizations.of(context).greet('ninghao'), 24 | style: Theme.of(context).textTheme.title, 25 | ) 26 | ], 27 | ), 28 | ) 29 | ); 30 | } 31 | } -------------------------------------------------------------------------------- /lib/demo/i18n/intl/intl_en.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@last_modified": "2018-10-19T15:45:15.386436", 3 | "title": "hello", 4 | "@title": { 5 | "description": "demo localizations.", 6 | "type": "text", 7 | "placeholders": {} 8 | }, 9 | "greet": "hello {name}", 10 | "@greet": { 11 | "description": "greet someone.", 12 | "type": "text", 13 | "placeholders": { 14 | "name": {} 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /lib/demo/i18n/intl/intl_messages.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@last_modified": "2018-10-19T15:45:15.386436", 3 | "title": "hello", 4 | "@title": { 5 | "description": "demo localizations.", 6 | "type": "text", 7 | "placeholders": {} 8 | }, 9 | "greet": "hello {name}", 10 | "@greet": { 11 | "description": "greet someone.", 12 | "type": "text", 13 | "placeholders": { 14 | "name": {} 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /lib/demo/i18n/intl/intl_zh.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@last_modified": "2018-10-19T15:45:15.386436", 3 | "title": "您好", 4 | "@title": { 5 | "description": "演示本地化", 6 | "type": "text", 7 | "placeholders": {} 8 | }, 9 | "greet": "您好 {name}", 10 | "@greet": { 11 | "description": "问候某人", 12 | "type": "text", 13 | "placeholders": { 14 | "name": {} 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /lib/demo/i18n/intl/ninghao_demo_localizations.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:intl/intl.dart'; 3 | import 'ninghao_demo_messages_all.dart'; 4 | 5 | class NinghaoDemoLocalizations { 6 | static NinghaoDemoLocalizations of(BuildContext context) { 7 | return Localizations.of( 8 | context, 9 | NinghaoDemoLocalizations 10 | ); 11 | } 12 | 13 | static Future load(Locale locale) { 14 | final String name = 15 | locale.countryCode.isEmpty ? locale.languageCode : locale.toString(); 16 | 17 | final String localeName = Intl.canonicalizedLocale(name); 18 | 19 | return initializeMessages(localeName).then((bool _) { 20 | Intl.defaultLocale = localeName; 21 | return NinghaoDemoLocalizations(); 22 | }); 23 | } 24 | 25 | String get title => Intl.message( 26 | 'hello', 27 | name: 'title', 28 | desc: 'demo localizations.', 29 | ); 30 | 31 | String greet(String name) => Intl.message( 32 | 'hello $name', 33 | name: 'greet', 34 | desc: 'greet someone.', 35 | args: [name], 36 | ); 37 | } 38 | 39 | class NinghaoDemoLocalizationsDelegate 40 | extends LocalizationsDelegate { 41 | NinghaoDemoLocalizationsDelegate(); 42 | 43 | @override 44 | Future load(Locale locale) { 45 | return NinghaoDemoLocalizations.load(locale); 46 | } 47 | 48 | @override 49 | bool isSupported(Locale locale) { 50 | return true; 51 | } 52 | 53 | @override 54 | bool shouldReload(LocalizationsDelegate old) { 55 | return false; 56 | } 57 | } -------------------------------------------------------------------------------- /lib/demo/i18n/intl/ninghao_demo_messages_all.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that looks up messages for specific locales by 3 | // delegating to the appropriate library. 4 | 5 | import 'dart:async'; 6 | 7 | import 'package:intl/intl.dart'; 8 | import 'package:intl/message_lookup_by_library.dart'; 9 | // ignore: implementation_imports 10 | import 'package:intl/src/intl_helpers.dart'; 11 | 12 | import 'ninghao_demo_messages_en.dart' as messages_en; 13 | import 'ninghao_demo_messages_messages.dart' as messages_messages; 14 | import 'ninghao_demo_messages_zh.dart' as messages_zh; 15 | 16 | typedef Future LibraryLoader(); 17 | Map _deferredLibraries = { 18 | // ignore: unnecessary_new 19 | 'en': () => new Future.value(null), 20 | // ignore: unnecessary_new 21 | 'messages': () => new Future.value(null), 22 | // ignore: unnecessary_new 23 | 'zh': () => new Future.value(null), 24 | }; 25 | 26 | MessageLookupByLibrary _findExact(localeName) { 27 | switch (localeName) { 28 | case 'en': 29 | return messages_en.messages; 30 | case 'messages': 31 | return messages_messages.messages; 32 | case 'zh': 33 | return messages_zh.messages; 34 | default: 35 | return null; 36 | } 37 | } 38 | 39 | /// User programs should call this before using [localeName] for messages. 40 | Future initializeMessages(String localeName) async { 41 | var availableLocale = Intl.verifiedLocale( 42 | localeName, 43 | (locale) => _deferredLibraries[locale] != null, 44 | onFailure: (_) => null); 45 | if (availableLocale == null) { 46 | // ignore: unnecessary_new 47 | return new Future.value(false); 48 | } 49 | var lib = _deferredLibraries[availableLocale]; 50 | // ignore: unnecessary_new 51 | await (lib == null ? new Future.value(false) : lib()); 52 | // ignore: unnecessary_new 53 | initializeInternalMessageLookup(() => new CompositeMessageLookup()); 54 | messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); 55 | // ignore: unnecessary_new 56 | return new Future.value(true); 57 | } 58 | 59 | bool _messagesExistFor(String locale) { 60 | try { 61 | return _findExact(locale) != null; 62 | } catch (e) { 63 | return false; 64 | } 65 | } 66 | 67 | MessageLookupByLibrary _findGeneratedMessagesFor(locale) { 68 | var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, 69 | onFailure: (_) => null); 70 | if (actualLocale == null) return null; 71 | return _findExact(actualLocale); 72 | } 73 | -------------------------------------------------------------------------------- /lib/demo/i18n/intl/ninghao_demo_messages_en.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a en locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | import 'package:intl/intl.dart'; 7 | import 'package:intl/message_lookup_by_library.dart'; 8 | 9 | // ignore: unnecessary_new 10 | final messages = new MessageLookup(); 11 | 12 | // ignore: unused_element 13 | final _keepAnalysisHappy = Intl.defaultLocale; 14 | 15 | // ignore: non_constant_identifier_names 16 | typedef MessageIfAbsent(String message_str, List args); 17 | 18 | class MessageLookup extends MessageLookupByLibrary { 19 | get localeName => 'en'; 20 | 21 | static m0(name) => "hello ${name}"; 22 | 23 | final messages = _notInlinedMessages(_notInlinedMessages); 24 | static _notInlinedMessages(_) => { 25 | "greet" : m0, 26 | "title" : MessageLookupByLibrary.simpleMessage("hello") 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /lib/demo/i18n/intl/ninghao_demo_messages_messages.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a messages locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | import 'package:intl/intl.dart'; 7 | import 'package:intl/message_lookup_by_library.dart'; 8 | 9 | // ignore: unnecessary_new 10 | final messages = new MessageLookup(); 11 | 12 | // ignore: unused_element 13 | final _keepAnalysisHappy = Intl.defaultLocale; 14 | 15 | // ignore: non_constant_identifier_names 16 | typedef MessageIfAbsent(String message_str, List args); 17 | 18 | class MessageLookup extends MessageLookupByLibrary { 19 | get localeName => 'messages'; 20 | 21 | static m0(name) => "hello ${name}"; 22 | 23 | final messages = _notInlinedMessages(_notInlinedMessages); 24 | static _notInlinedMessages(_) => { 25 | "greet" : m0, 26 | "title" : MessageLookupByLibrary.simpleMessage("hello") 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /lib/demo/i18n/intl/ninghao_demo_messages_zh.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a zh locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | import 'package:intl/intl.dart'; 7 | import 'package:intl/message_lookup_by_library.dart'; 8 | 9 | // ignore: unnecessary_new 10 | final messages = new MessageLookup(); 11 | 12 | // ignore: unused_element 13 | final _keepAnalysisHappy = Intl.defaultLocale; 14 | 15 | // ignore: non_constant_identifier_names 16 | typedef MessageIfAbsent(String message_str, List args); 17 | 18 | class MessageLookup extends MessageLookupByLibrary { 19 | get localeName => 'zh'; 20 | 21 | static m0(name) => "您好 ${name}"; 22 | 23 | final messages = _notInlinedMessages(_notInlinedMessages); 24 | static _notInlinedMessages(_) => { 25 | "greet" : m0, 26 | "title" : MessageLookupByLibrary.simpleMessage("您好") 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /lib/demo/i18n/map/ninghao_demo_localizations.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart' show SynchronousFuture; 2 | import 'package:flutter/material.dart'; 3 | 4 | class NinghaoDemoLocalizations { 5 | final Locale locale; 6 | 7 | NinghaoDemoLocalizations(this.locale); 8 | 9 | static NinghaoDemoLocalizations of(BuildContext context) { 10 | return Localizations.of( 11 | context, 12 | NinghaoDemoLocalizations 13 | ); 14 | } 15 | 16 | static Map> _localized = { 17 | 'en': { 18 | 'title': 'hello', 19 | }, 20 | 'zh': { 21 | 'title': '您好', 22 | } 23 | }; 24 | 25 | String get title { 26 | return _localized[locale.languageCode]['title']; 27 | } 28 | } 29 | 30 | class NinghaoDemoLocalizationsDelegate 31 | extends LocalizationsDelegate { 32 | NinghaoDemoLocalizationsDelegate(); 33 | 34 | @override 35 | Future load(Locale locale) { 36 | return SynchronousFuture( 37 | NinghaoDemoLocalizations(locale)); 38 | } 39 | 40 | @override 41 | bool isSupported(Locale locale) { 42 | return true; 43 | } 44 | 45 | @override 46 | bool shouldReload(LocalizationsDelegate old) { 47 | return false; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/demo/layout_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LayoutDemo extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Container( 7 | child: Column( 8 | mainAxisAlignment: MainAxisAlignment.center, 9 | children: [ 10 | StackDemo(), 11 | ], 12 | ), 13 | ); 14 | } 15 | } 16 | 17 | class ConstrainedBoxDemo extends StatelessWidget { 18 | @override 19 | Widget build(BuildContext context) { 20 | return ConstrainedBox( 21 | constraints: BoxConstraints( 22 | minHeight: 200.0, 23 | maxWidth: 200.0, 24 | ), 25 | child: Container( 26 | color: Color.fromRGBO(3, 54, 255, 1.0), 27 | ), 28 | ); 29 | } 30 | } 31 | 32 | class AspectRatioDemo extends StatelessWidget { 33 | @override 34 | Widget build(BuildContext context) { 35 | return AspectRatio( 36 | aspectRatio: 16.0 / 9.0, 37 | child: Container( 38 | color: Color.fromRGBO(3, 54, 255, 1.0), 39 | ), 40 | ); 41 | } 42 | } 43 | 44 | class StackDemo extends StatelessWidget { 45 | @override 46 | Widget build(BuildContext context) { 47 | return Stack( 48 | alignment: Alignment.topLeft, 49 | children: [ 50 | SizedBox( 51 | width: 200.0, 52 | height: 300.0, 53 | child: Container( 54 | alignment: Alignment(0.0, -0.9), 55 | decoration: BoxDecoration( 56 | color: Color.fromRGBO(3, 54, 255, 1.0), 57 | borderRadius: BorderRadius.circular(8.0), 58 | ), 59 | ), 60 | ), 61 | SizedBox( 62 | height: 32.0, 63 | ), 64 | SizedBox( 65 | width: 100.0, 66 | height: 100.0, 67 | child: Container( 68 | decoration: BoxDecoration( 69 | color: Color.fromRGBO(3, 54, 255, 1.0), 70 | shape: BoxShape.circle, 71 | gradient: RadialGradient(colors: [ 72 | Color.fromRGBO(7, 102, 255, 1.0), 73 | Color.fromRGBO(3, 54, 255, 1.0), 74 | ]), 75 | ), 76 | child: Icon(Icons.brightness_2, color: Colors.white, size: 32.0), 77 | ), 78 | ), 79 | Positioned( 80 | right: 20.0, 81 | top: 20.0, 82 | child: Icon(Icons.ac_unit, color: Colors.white, size: 16.0), 83 | ), 84 | Positioned( 85 | right: 40.0, 86 | top: 60.0, 87 | child: Icon(Icons.ac_unit, color: Colors.white, size: 18.0), 88 | ), 89 | Positioned( 90 | right: 20.0, 91 | top: 120.0, 92 | child: Icon(Icons.ac_unit, color: Colors.white, size: 20.0), 93 | ), 94 | Positioned( 95 | right: 70.0, 96 | top: 180.0, 97 | child: Icon(Icons.ac_unit, color: Colors.white, size: 16.0), 98 | ), 99 | Positioned( 100 | right: 30.0, 101 | top: 230.0, 102 | child: Icon(Icons.ac_unit, color: Colors.white, size: 18.0), 103 | ), 104 | Positioned( 105 | right: 90.0, 106 | bottom: 20.0, 107 | child: Icon(Icons.ac_unit, color: Colors.white, size: 16.0), 108 | ), 109 | Positioned( 110 | right: 4.0, 111 | bottom: -4.0, 112 | child: Icon(Icons.ac_unit, color: Colors.white, size: 16.0), 113 | ), 114 | ], 115 | ); 116 | } 117 | } 118 | 119 | class IconBadge extends StatelessWidget { 120 | final IconData icon; 121 | final double size; 122 | 123 | IconBadge(this.icon, {this.size = 32.0}); 124 | 125 | @override 126 | Widget build(BuildContext context) { 127 | return Container( 128 | child: Icon(icon, size: size, color: Colors.white), 129 | width: size + 60, 130 | height: size + 60, 131 | color: Color.fromRGBO(3, 54, 255, 1.0), 132 | ); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /lib/demo/listview_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import './post_show.dart'; 3 | import '../model/post.dart'; 4 | 5 | class ListViewDemo extends StatelessWidget { 6 | Widget _listItemBuilder(BuildContext context, int index) { 7 | return Container( 8 | color: Colors.white, 9 | margin: EdgeInsets.all(8.0), 10 | child: Stack( 11 | children: [ 12 | Column( 13 | children: [ 14 | AspectRatio( 15 | aspectRatio: 16/9, 16 | child: Image.network(posts[index].imageUrl, fit: BoxFit.cover), 17 | ), 18 | SizedBox(height: 16.0), 19 | Text( 20 | posts[index].title, 21 | style: Theme.of(context).textTheme.title 22 | ), 23 | Text( 24 | posts[index].author, 25 | style: Theme.of(context).textTheme.subhead 26 | ), 27 | SizedBox(height: 16.0), 28 | ], 29 | ), 30 | Positioned.fill( 31 | child: Material( 32 | color: Colors.transparent, 33 | child: InkWell( 34 | splashColor: Colors.white.withOpacity(0.3), 35 | highlightColor: Colors.white.withOpacity(0.1), 36 | onTap: () { 37 | Navigator.of(context).push( 38 | MaterialPageRoute(builder: (context) => PostShow(post: posts[index])) 39 | ); 40 | } 41 | ), 42 | ), 43 | ), 44 | ], 45 | ), 46 | ); 47 | } 48 | 49 | @override 50 | Widget build(BuildContext context) { 51 | // TODO: implement build 52 | return ListView.builder( 53 | itemCount: posts.length, 54 | itemBuilder: _listItemBuilder, 55 | ); 56 | } 57 | } -------------------------------------------------------------------------------- /lib/demo/material_components.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import './button_demo.dart'; 3 | import './floating_action_button_demo.dart'; 4 | import './popup_menu_button_demo.dart'; 5 | import './form_demo.dart'; 6 | import './checkbox_demo.dart'; 7 | import './radio_demo.dart'; 8 | import './switch_demo.dart'; 9 | import './slider_demo.dart'; 10 | import './datetime_demo.dart'; 11 | import './simple_dialog_demo.dart'; 12 | import './alert_dialog_demo.dart'; 13 | import './bottom_sheet_demo.dart'; 14 | import './snack_bar_demo.dart'; 15 | import './expansion_panel_demo.dart'; 16 | import './chip_demo.dart'; 17 | import './data_table_demo.dart'; 18 | import './paginated_data_table_demo.dart'; 19 | import './card_demo.dart'; 20 | import './stepper_demo.dart'; 21 | 22 | class MaterialComponents extends StatelessWidget { 23 | @override 24 | Widget build(BuildContext context) { 25 | return Scaffold( 26 | appBar: AppBar( 27 | title: Text('MaterialComponents'), 28 | elevation: 0.0, 29 | ), 30 | body: ListView( 31 | children: [ 32 | ListItem(title: 'Stepper', page: StepperDemo()), 33 | ListItem(title: 'Card', page: CardDemo()), 34 | ListItem(title: 'PaginatedDataTable', page: PaginatedDataTableDemo()), 35 | ListItem(title: 'DataTable', page: DataTableDemo()), 36 | ListItem(title: 'Chip', page: ChipDemo()), 37 | ListItem(title: 'ExpansionPanel', page: ExpansionPanelDemo()), 38 | ListItem(title: 'SnackBar', page: SnackBarDemo()), 39 | ListItem(title: 'BottomSheet', page: BottomSheetDemo()), 40 | ListItem(title: 'AlertDialog', page: AlertDialogDemo()), 41 | ListItem(title: 'SimpleDialog', page: SimpleDialogDemo()), 42 | ListItem(title: 'Date & Time', page: DateTimeDemo()), 43 | ListItem(title: 'Slider', page: SliderDemo()), 44 | ListItem(title: 'Switch', page: SwitchDemo()), 45 | ListItem(title: 'Radio', page: RadioDemo()), 46 | ListItem(title: 'Checkbox', page: CheckboxDemo()), 47 | ListItem(title: 'Form', page: FormDemo()), 48 | ListItem(title: 'PopupMenuButton', page: PopupMenuButtonDemo()), 49 | ListItem(title: 'Button', page: ButtonDemo()), 50 | ListItem(title: 'FloatingActionButton', page: FloatingActionButtonDemo()), 51 | ], 52 | ), 53 | ); 54 | } 55 | } 56 | 57 | class _WidgetDemo extends StatelessWidget { 58 | @override 59 | Widget build(BuildContext context) { 60 | return Scaffold( 61 | appBar: AppBar( 62 | title: Text('_WidgetDemo'), 63 | elevation: 0.0, 64 | ), 65 | body: Container( 66 | padding: EdgeInsets.all(16.0), 67 | child: Column( 68 | mainAxisAlignment: MainAxisAlignment.center, 69 | children: [ 70 | Row( 71 | mainAxisAlignment: MainAxisAlignment.center, 72 | children: [ 73 | 74 | ], 75 | ), 76 | ], 77 | ), 78 | ) 79 | ); 80 | } 81 | } 82 | 83 | class ListItem extends StatelessWidget { 84 | final String title; 85 | final Widget page; 86 | 87 | ListItem({ 88 | this.title, 89 | this.page, 90 | }); 91 | 92 | @override 93 | Widget build(BuildContext context) { 94 | return ListTile( 95 | title: Text(title), 96 | onTap: () { 97 | Navigator.of(context).push( 98 | MaterialPageRoute(builder: (context) => page), 99 | ); 100 | }, 101 | ); 102 | } 103 | } -------------------------------------------------------------------------------- /lib/demo/navigator_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NavigatorDemo extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Scaffold( 7 | body: Center( 8 | child: Row( 9 | mainAxisAlignment: MainAxisAlignment.center, 10 | children: [ 11 | FlatButton( 12 | child: Text('Home'), 13 | onPressed: null, 14 | ), 15 | FlatButton( 16 | child: Text('About'), 17 | onPressed: () { 18 | Navigator.pushNamed(context, '/about'); 19 | }, 20 | ), 21 | ], 22 | ), 23 | ), 24 | ); 25 | } 26 | } 27 | 28 | class Page extends StatelessWidget { 29 | final String title; 30 | 31 | Page({ 32 | this.title 33 | }); 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | return Scaffold( 38 | appBar: AppBar( 39 | title: Text(title), 40 | elevation: 0.0, 41 | ), 42 | floatingActionButton: FloatingActionButton( 43 | child: Icon(Icons.arrow_back), 44 | onPressed: () { 45 | Navigator.pop(context); 46 | }, 47 | ), 48 | ); 49 | } 50 | } -------------------------------------------------------------------------------- /lib/demo/paginated_data_table_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../model/post.dart'; 3 | 4 | class PostDataSource extends DataTableSource { 5 | final List _posts = posts; 6 | int _selectedCount = 0; 7 | 8 | @override 9 | int get rowCount => _posts.length; 10 | 11 | @override 12 | bool get isRowCountApproximate => false; 13 | 14 | @override 15 | int get selectedRowCount => _selectedCount; 16 | 17 | @override 18 | DataRow getRow(int index) { 19 | final Post post = _posts[index]; 20 | 21 | return DataRow.byIndex( 22 | index: index, 23 | cells: [ 24 | DataCell(Text(post.title)), 25 | DataCell(Text(post.author)), 26 | DataCell(Image.network(post.imageUrl)), 27 | ], 28 | ); 29 | } 30 | 31 | void _sort(getField(post), bool ascending) { 32 | _posts.sort((a, b) { 33 | if (!ascending) { 34 | final c = a; 35 | a = b; 36 | b = c; 37 | } 38 | 39 | final aValue = getField(a); 40 | final bValue = getField(b); 41 | 42 | return Comparable.compare(aValue, bValue); 43 | }); 44 | 45 | notifyListeners(); 46 | } 47 | } 48 | 49 | class PaginatedDataTableDemo extends StatefulWidget { 50 | @override 51 | _PaginatedDataTableDemoState createState() => _PaginatedDataTableDemoState(); 52 | } 53 | 54 | class _PaginatedDataTableDemoState extends State { 55 | int _sortColumnIndex; 56 | bool _sortAscending = true; 57 | 58 | final PostDataSource _postsDataSource = PostDataSource(); 59 | 60 | @override 61 | Widget build(BuildContext context) { 62 | return Scaffold( 63 | appBar: AppBar( 64 | title: Text('PaginatedDataTableDemo'), 65 | elevation: 0.0, 66 | ), 67 | body: Container( 68 | padding: EdgeInsets.all(16.0), 69 | child: ListView( 70 | children: [ 71 | PaginatedDataTable( 72 | header: Text('Posts'), 73 | rowsPerPage: 5, 74 | source: _postsDataSource, 75 | sortColumnIndex: _sortColumnIndex, 76 | sortAscending: _sortAscending, 77 | // onSelectAll: (bool value) {}, 78 | columns: [ 79 | DataColumn( 80 | label: Text('Title'), 81 | onSort: (int columnIndex, bool ascending) { 82 | _postsDataSource._sort((post) => post.title.length, ascending); 83 | 84 | setState(() { 85 | _sortColumnIndex = columnIndex; 86 | _sortAscending = ascending; 87 | }); 88 | }, 89 | ), 90 | DataColumn( 91 | label: Text('Author'), 92 | ), 93 | DataColumn( 94 | label: Text('Image'), 95 | ), 96 | ], 97 | ), 98 | ], 99 | ), 100 | )); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/demo/popup_menu_button_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class PopupMenuButtonDemo extends StatefulWidget { 4 | @override 5 | _PopupMenuButtonDemoState createState() => _PopupMenuButtonDemoState(); 6 | } 7 | 8 | class _PopupMenuButtonDemoState extends State { 9 | String _currentMenuItem = 'Home'; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text('PopupMenuButtonDemo'), 16 | elevation: 0.0, 17 | ), 18 | body: Container( 19 | padding: EdgeInsets.all(16.0), 20 | child: Column( 21 | mainAxisAlignment: MainAxisAlignment.center, 22 | children: [ 23 | Row( 24 | mainAxisAlignment: MainAxisAlignment.center, 25 | children: [ 26 | Text(_currentMenuItem), 27 | PopupMenuButton( 28 | onSelected: (value) { 29 | print(value); 30 | setState(() { 31 | _currentMenuItem = value; 32 | }); 33 | }, 34 | itemBuilder: (BuildContext context) => [ 35 | PopupMenuItem( 36 | value: 'Home', 37 | child: Text('Home'), 38 | ), 39 | PopupMenuItem( 40 | value: 'Discover', 41 | child: Text('Discover'), 42 | ), 43 | PopupMenuItem( 44 | value: 'Community', 45 | child: Text('Community'), 46 | ), 47 | ], 48 | ), 49 | ], 50 | ), 51 | ], 52 | ), 53 | ) 54 | ); 55 | } 56 | } -------------------------------------------------------------------------------- /lib/demo/post_show.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../model/post.dart'; 3 | 4 | class PostShow extends StatelessWidget { 5 | final Post post; 6 | 7 | PostShow({ 8 | @required this.post, 9 | }); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text('${post.title}'), 16 | elevation: 0.0, 17 | ), 18 | body: SingleChildScrollView( 19 | child: Column( 20 | children: [ 21 | Image.network(post.imageUrl), 22 | Container( 23 | padding: EdgeInsets.all(32.0), 24 | width: double.infinity, 25 | child: Column( 26 | crossAxisAlignment: CrossAxisAlignment.start, 27 | children: [ 28 | Text('${post.title}', 29 | style: Theme.of(context).textTheme.title), 30 | Text('${post.author}', 31 | style: Theme.of(context).textTheme.subhead), 32 | SizedBox(height: 32.0), 33 | Text('${post.description}', 34 | style: Theme.of(context).textTheme.body1), 35 | ], 36 | ), 37 | ), 38 | ], 39 | ), 40 | )); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/demo/radio_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class RadioDemo extends StatefulWidget { 4 | @override 5 | _RadioDemoState createState() => _RadioDemoState(); 6 | } 7 | 8 | class _RadioDemoState extends State { 9 | int _radioGroupA = 0; 10 | 11 | void _handleRadioValueChanged(int value) { 12 | setState(() { 13 | _radioGroupA = value; 14 | }); 15 | } 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | appBar: AppBar( 21 | title: Text('RadioDemo'), 22 | elevation: 0.0, 23 | ), 24 | body: Container( 25 | padding: EdgeInsets.all(16.0), 26 | child: Column( 27 | mainAxisAlignment: MainAxisAlignment.center, 28 | children: [ 29 | Text('RadioGroupValue: $_radioGroupA'), 30 | SizedBox(height: 32.0), 31 | RadioListTile( 32 | value: 0, 33 | groupValue: _radioGroupA, 34 | onChanged: _handleRadioValueChanged, 35 | title: Text('Options A'), 36 | subtitle: Text('Description'), 37 | secondary: Icon(Icons.filter_1), 38 | selected: _radioGroupA == 0, 39 | ), 40 | RadioListTile( 41 | value: 1, 42 | groupValue: _radioGroupA, 43 | onChanged: _handleRadioValueChanged, 44 | title: Text('Options B'), 45 | subtitle: Text('Description'), 46 | secondary: Icon(Icons.filter_2), 47 | selected: _radioGroupA == 1, 48 | ), 49 | Row( 50 | mainAxisAlignment: MainAxisAlignment.center, 51 | children: [ 52 | // Radio( 53 | // value: 0, 54 | // groupValue: _radioGroupA, 55 | // onChanged: _handleRadioValueChanged, 56 | // activeColor: Colors.black, 57 | // ), 58 | // Radio( 59 | // value: 1, 60 | // groupValue: _radioGroupA, 61 | // onChanged: _handleRadioValueChanged, 62 | // activeColor: Colors.black, 63 | // ), 64 | ], 65 | ), 66 | ], 67 | ), 68 | ) 69 | ); 70 | } 71 | } -------------------------------------------------------------------------------- /lib/demo/rxdart/rxdart_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:rxdart/rxdart.dart'; 3 | import 'dart:async'; 4 | 5 | class RxDartDemo extends StatelessWidget { 6 | @override 7 | Widget build(BuildContext context) { 8 | return Scaffold( 9 | appBar: AppBar( 10 | title: Text('RxDartDemo'), 11 | elevation: 0.0, 12 | ), 13 | body: RxDartDemoHome(), 14 | ); 15 | } 16 | } 17 | 18 | class RxDartDemoHome extends StatefulWidget { 19 | @override 20 | _RxDartDemoHomeState createState() => _RxDartDemoHomeState(); 21 | } 22 | 23 | class _RxDartDemoHomeState extends State { 24 | PublishSubject _textFieldSubject; 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | 30 | _textFieldSubject = PublishSubject(); 31 | 32 | _textFieldSubject 33 | // .map((item) => 'item: $item') 34 | // .where((item) => item.length > 9) 35 | .debounce(Duration(milliseconds: 500)) 36 | .listen((data) => print(data)); 37 | 38 | // Observable _observable = 39 | // // Observable(Stream.fromIterable(['hello', '您好'])); 40 | // // Observable.fromFuture(Future.value('hello ~')); 41 | // // Observable.fromIterable(['hello', '您好']); 42 | // // Observable.just('hello ~'); 43 | // Observable.periodic(Duration(seconds: 3), (x) => x.toString()); 44 | 45 | // _observable.listen(print); 46 | 47 | // PublishSubject _subject = PublishSubject(); 48 | // BehaviorSubject _subject = BehaviorSubject(); 49 | // ReplaySubject _subject = ReplaySubject(maxSize: 2); 50 | 51 | // _subject.add('hello'); 52 | // _subject.add('hola'); 53 | // _subject.add('hi'); 54 | // _subject.listen((data) => print('listen 1: $data')); 55 | // _subject.listen((data) => print('listen 2: ${data.toUpperCase()}')); 56 | 57 | // _subject.close(); 58 | } 59 | 60 | @override 61 | void dispose() { 62 | super.dispose(); 63 | _textFieldSubject.close(); 64 | } 65 | 66 | @override 67 | Widget build(BuildContext context) { 68 | return Theme( 69 | data: Theme.of(context).copyWith( 70 | primaryColor: Colors.black, 71 | ), 72 | child: TextField( 73 | onChanged: (value) { 74 | _textFieldSubject.add('input: $value'); 75 | }, 76 | onSubmitted: (value) { 77 | _textFieldSubject.add('submit: $value'); 78 | }, 79 | decoration: InputDecoration( 80 | labelText: 'Title', 81 | filled: true, 82 | ), 83 | ), 84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/demo/simple_dialog_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:async'; 3 | 4 | enum Option { 5 | A, B, C 6 | } 7 | 8 | class SimpleDialogDemo extends StatefulWidget { 9 | @override 10 | _SimpleDialogDemoState createState() => _SimpleDialogDemoState(); 11 | } 12 | 13 | class _SimpleDialogDemoState extends State { 14 | String _choice = 'Nothing'; 15 | 16 | Future _openSimpleDialog() async { 17 | final option = await showDialog( 18 | context: context, 19 | builder: (BuildContext context) { 20 | return SimpleDialog( 21 | title: Text('SimpleDialog'), 22 | children: [ 23 | SimpleDialogOption( 24 | child: Text('Option A'), 25 | onPressed: () { 26 | Navigator.pop(context, Option.A); 27 | }, 28 | ), 29 | SimpleDialogOption( 30 | child: Text('Option B'), 31 | onPressed: () { 32 | Navigator.pop(context, Option.B); 33 | }, 34 | ), 35 | SimpleDialogOption( 36 | child: Text('Option C'), 37 | onPressed: () { 38 | Navigator.pop(context, Option.C); 39 | }, 40 | ), 41 | ], 42 | ); 43 | } 44 | ); 45 | 46 | switch (option) { 47 | case Option.A: 48 | setState(() { 49 | _choice = 'A'; 50 | }); 51 | break; 52 | case Option.B: 53 | setState(() { 54 | _choice = 'B'; 55 | }); 56 | break; 57 | case Option.C: 58 | setState(() { 59 | _choice = 'C'; 60 | }); 61 | break; 62 | default: 63 | } 64 | } 65 | 66 | @override 67 | Widget build(BuildContext context) { 68 | return Scaffold( 69 | appBar: AppBar( 70 | title: Text('SimpleDialogDemo'), 71 | elevation: 0.0, 72 | ), 73 | body: Container( 74 | padding: EdgeInsets.all(16.0), 75 | child: Column( 76 | mainAxisAlignment: MainAxisAlignment.center, 77 | children: [ 78 | Text('Your choice is: $_choice'), 79 | Row( 80 | mainAxisAlignment: MainAxisAlignment.center, 81 | children: [ 82 | ], 83 | ), 84 | ], 85 | ), 86 | ), 87 | floatingActionButton: FloatingActionButton( 88 | child: Icon(Icons.format_list_numbered), 89 | onPressed: _openSimpleDialog, 90 | ), 91 | ); 92 | } 93 | } -------------------------------------------------------------------------------- /lib/demo/slider_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SliderDemo extends StatefulWidget { 4 | @override 5 | _SliderDemoState createState() => _SliderDemoState(); 6 | } 7 | 8 | class _SliderDemoState extends State { 9 | double _sliderItemA = 0.0; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text('SliderDemo'), 16 | elevation: 0.0, 17 | ), 18 | body: Container( 19 | padding: EdgeInsets.all(16.0), 20 | child: Column( 21 | mainAxisAlignment: MainAxisAlignment.center, 22 | children: [ 23 | Row( 24 | mainAxisAlignment: MainAxisAlignment.center, 25 | children: [ 26 | Slider( 27 | value: _sliderItemA, 28 | onChanged: (value) { 29 | setState(() { 30 | _sliderItemA = value; 31 | }); 32 | }, 33 | activeColor: Theme.of(context).accentColor, 34 | inactiveColor: Theme.of(context).accentColor.withOpacity(0.3), 35 | min: 0.0, 36 | max: 10.0, 37 | divisions: 10, 38 | label: '${_sliderItemA.toInt()}', 39 | ), 40 | ], 41 | ), 42 | SizedBox(height: 16.0,), 43 | Text('SliderValue: $_sliderItemA'), 44 | ], 45 | ), 46 | ) 47 | ); 48 | } 49 | } -------------------------------------------------------------------------------- /lib/demo/sliver_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../model/post.dart'; 3 | 4 | class SliverDemo extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Scaffold( 8 | body: CustomScrollView( 9 | slivers: [ 10 | SliverAppBar( 11 | // title: Text('NINGHAO'), 12 | // pinned: true, 13 | floating: true, 14 | expandedHeight: 178.0, 15 | flexibleSpace: FlexibleSpaceBar( 16 | title: Text( 17 | 'Ninghao Flutter'.toUpperCase(), 18 | style: TextStyle( 19 | fontSize: 15.0, 20 | letterSpacing: 3.0, 21 | fontWeight: FontWeight.w400, 22 | ), 23 | ), 24 | background: Image.network( 25 | 'https://resources.ninghao.net/images/overkill.png', 26 | fit: BoxFit.cover, 27 | ), 28 | ), 29 | ), 30 | SliverSafeArea( 31 | sliver: SliverPadding( 32 | padding: EdgeInsets.all(8.0), 33 | sliver: SliverGridDemo() 34 | ), 35 | ), 36 | ], 37 | ), 38 | ); 39 | } 40 | } 41 | 42 | class SliverListDemo extends StatelessWidget { 43 | @override 44 | Widget build(BuildContext context) { 45 | return SliverList( 46 | delegate: SliverChildBuilderDelegate( 47 | (BuildContext context, int index) { 48 | return Padding( 49 | padding: EdgeInsets.only(bottom: 32.0), 50 | child: Material( 51 | borderRadius: BorderRadius.circular(12.0), 52 | elevation: 14.0, 53 | shadowColor: Colors.grey.withOpacity(0.5), 54 | child: Stack( 55 | children: [ 56 | AspectRatio( 57 | aspectRatio: 16/9, 58 | child: Image.network( 59 | posts[index].imageUrl, 60 | fit: BoxFit.cover, 61 | ), 62 | ), 63 | Positioned( 64 | top: 32.0, 65 | left: 32.0, 66 | child: Column( 67 | crossAxisAlignment: CrossAxisAlignment.start, 68 | children: [ 69 | Text( 70 | posts[index].title, 71 | style: TextStyle( 72 | fontSize: 20.0, 73 | color: Colors.white 74 | ), 75 | ), 76 | Text( 77 | posts[index].author, 78 | style: TextStyle( 79 | fontSize: 13.0, 80 | color: Colors.white 81 | ), 82 | ), 83 | ], 84 | ), 85 | ), 86 | ], 87 | ), 88 | ), 89 | ); 90 | }, 91 | childCount: posts.length, 92 | ), 93 | ); 94 | } 95 | } 96 | 97 | class SliverGridDemo extends StatelessWidget { 98 | @override 99 | Widget build(BuildContext context) { 100 | return SliverGrid( 101 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 102 | crossAxisCount: 2, 103 | crossAxisSpacing: 8.0, 104 | mainAxisSpacing: 8.0, 105 | childAspectRatio: 1.0, 106 | ), 107 | delegate: SliverChildBuilderDelegate( 108 | (BuildContext context, int index) { 109 | return Container( 110 | child: Image.network( 111 | posts[index].imageUrl, 112 | fit: BoxFit.cover, 113 | ), 114 | ); 115 | }, 116 | childCount: posts.length, 117 | ), 118 | ); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /lib/demo/snack_bar_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SnackBarDemo extends StatefulWidget { 4 | @override 5 | _SnackBarDemoState createState() => _SnackBarDemoState(); 6 | } 7 | 8 | class _SnackBarDemoState extends State { 9 | @override 10 | Widget build(BuildContext context) { 11 | return Scaffold( 12 | appBar: AppBar( 13 | title: Text('SnackBarDemo'), 14 | elevation: 0.0, 15 | ), 16 | body: Container( 17 | padding: EdgeInsets.all(16.0), 18 | child: Column( 19 | mainAxisAlignment: MainAxisAlignment.center, 20 | children: [ 21 | Row( 22 | mainAxisAlignment: MainAxisAlignment.center, 23 | children: [ 24 | SnackBarButton(), 25 | ] 26 | ), 27 | ], 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | 34 | class SnackBarButton extends StatelessWidget { 35 | @override 36 | Widget build(BuildContext context) { 37 | return FlatButton( 38 | child: Text('Open SnackBar'), 39 | onPressed: () { 40 | Scaffold.of(context).showSnackBar( 41 | SnackBar( 42 | content: Text('Processing...'), 43 | action: SnackBarAction( 44 | label: 'OK', 45 | onPressed: () {}, 46 | ), 47 | ) 48 | ); 49 | }, 50 | ); 51 | } 52 | } -------------------------------------------------------------------------------- /lib/demo/state/state_management_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:scoped_model/scoped_model.dart'; 3 | 4 | class StateManagementDemo extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return ScopedModel( 8 | model: CounterModel(), 9 | child: Scaffold( 10 | appBar: AppBar( 11 | title: Text('StateManagementDemo'), 12 | elevation: 0.0, 13 | ), 14 | body: CounterWrapper(), 15 | floatingActionButton: ScopedModelDescendant( 16 | rebuildOnChange: false, 17 | builder: (context, _, model) => FloatingActionButton( 18 | child: Icon(Icons.add), 19 | onPressed: model.increaseCount, 20 | ), 21 | ), 22 | ), 23 | ); 24 | } 25 | } 26 | 27 | class CounterWrapper extends StatelessWidget { 28 | @override 29 | Widget build(BuildContext context) { 30 | return Center( 31 | child: Counter(), 32 | ); 33 | } 34 | } 35 | 36 | class Counter extends StatelessWidget { 37 | @override 38 | Widget build(BuildContext context) { 39 | return ScopedModelDescendant( 40 | builder: (context, _, model) => ActionChip( 41 | label: Text('${model.count}'), 42 | onPressed: model.increaseCount, 43 | ), 44 | ); 45 | } 46 | } 47 | 48 | class CounterProvider extends InheritedWidget { 49 | final int count; 50 | final VoidCallback increaseCount; 51 | final Widget child; 52 | 53 | CounterProvider({ 54 | this.count, 55 | this.increaseCount, 56 | this.child, 57 | }) : super(child: child); 58 | 59 | static CounterProvider of(BuildContext context) => 60 | context.inheritFromWidgetOfExactType(CounterProvider); 61 | 62 | @override 63 | bool updateShouldNotify(InheritedWidget oldWidget) { 64 | return true; 65 | } 66 | } 67 | 68 | class CounterModel extends Model { 69 | int _count = 0; 70 | int get count => _count; 71 | 72 | void increaseCount() { 73 | _count += 1; 74 | notifyListeners(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/demo/stepper_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class StepperDemo extends StatefulWidget { 4 | @override 5 | _StepperDemoState createState() => _StepperDemoState(); 6 | } 7 | 8 | class _StepperDemoState extends State { 9 | int _currentStep = 0; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text('StepperDemo'), 16 | elevation: 0.0, 17 | ), 18 | body: Container( 19 | padding: EdgeInsets.all(16.0), 20 | child: Column( 21 | mainAxisAlignment: MainAxisAlignment.center, 22 | children: [ 23 | Theme( 24 | data: Theme.of(context).copyWith( 25 | primaryColor: Colors.black, 26 | ), 27 | child: Stepper( 28 | currentStep: _currentStep, 29 | onStepTapped: (int value) { 30 | setState(() { 31 | _currentStep = value; 32 | }); 33 | }, 34 | onStepContinue: () { 35 | setState(() { 36 | _currentStep < 2 ? _currentStep += 1 : _currentStep = 0; 37 | }); 38 | }, 39 | onStepCancel: () { 40 | setState(() { 41 | _currentStep > 0 ? _currentStep -= 1 : _currentStep = 0; 42 | }); 43 | }, 44 | steps: [ 45 | Step( 46 | title: Text('Login'), 47 | subtitle: Text('Login first'), 48 | content: Text('Magna exercitation duis non sint eu nostrud.'), 49 | isActive: _currentStep == 0, 50 | ), 51 | Step( 52 | title: Text('Choose Plan'), 53 | subtitle: Text('Choose you plan.'), 54 | content: Text('Magna exercitation duis non sint eu nostrud.'), 55 | isActive: _currentStep == 1, 56 | ), 57 | Step( 58 | title: Text('Confirm payment'), 59 | subtitle: Text('Confirm your payment method.'), 60 | content: Text('Magna exercitation duis non sint eu nostrud.'), 61 | isActive: _currentStep == 2, 62 | ), 63 | ], 64 | ), 65 | ), 66 | ], 67 | ), 68 | ) 69 | ); 70 | } 71 | } -------------------------------------------------------------------------------- /lib/demo/stream/stream_demo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class StreamDemo extends StatelessWidget { 6 | @override 7 | Widget build(BuildContext context) { 8 | return Scaffold( 9 | appBar: AppBar( 10 | title: Text('StreamDemo'), 11 | elevation: 0.0, 12 | ), 13 | body: StreamDemoHome(), 14 | ); 15 | } 16 | } 17 | 18 | class StreamDemoHome extends StatefulWidget { 19 | @override 20 | _StreamDemoHomeState createState() => _StreamDemoHomeState(); 21 | } 22 | 23 | class _StreamDemoHomeState extends State { 24 | StreamSubscription _streamDemoSubscription; 25 | StreamController _streamDemo; 26 | StreamSink _sinkDemo; 27 | String _data = '...'; 28 | 29 | @override 30 | void dispose() { 31 | _streamDemo.close(); 32 | super.dispose(); 33 | } 34 | 35 | @override 36 | void initState() { 37 | super.initState(); 38 | 39 | print('Create a stream.'); 40 | // Stream _streamDemo = Stream.fromFuture(fetchData()); 41 | _streamDemo = StreamController.broadcast(); 42 | _sinkDemo = _streamDemo.sink; 43 | 44 | print('Start listening on a stream.'); 45 | _streamDemoSubscription = 46 | _streamDemo.stream.listen(onData, onError: onError, onDone: onDone); 47 | 48 | _streamDemo.stream.listen(onDataTwo, onError: onError, onDone: onDone); 49 | 50 | print('Initialize completed.'); 51 | } 52 | 53 | void onDone() { 54 | print('Done!'); 55 | } 56 | 57 | void onError(error) { 58 | print('Error: $error'); 59 | } 60 | 61 | void onData(String data) { 62 | setState(() { 63 | _data = data; 64 | }); 65 | print('$data'); 66 | } 67 | 68 | void onDataTwo(String data) { 69 | print('onDataTwo: $data'); 70 | } 71 | 72 | void _pauseStream() { 73 | print('Pause subscription'); 74 | _streamDemoSubscription.pause(); 75 | } 76 | 77 | void _resumeStream() { 78 | print('Resume subscription'); 79 | _streamDemoSubscription.resume(); 80 | } 81 | 82 | void _cancelStream() { 83 | print('Cancel subscription'); 84 | _streamDemoSubscription.cancel(); 85 | } 86 | 87 | void _addDataToStream() async { 88 | print('Add data to stream.'); 89 | 90 | String data = await fetchData(); 91 | // _streamDemo.add(data); 92 | _sinkDemo.add(data); 93 | } 94 | 95 | Future fetchData() async { 96 | await Future.delayed(Duration(seconds: 5)); 97 | // throw 'Something happened'; 98 | return 'hello ~'; 99 | } 100 | 101 | @override 102 | Widget build(BuildContext context) { 103 | return Container( 104 | child: Center( 105 | child: Column( 106 | mainAxisAlignment: MainAxisAlignment.center, 107 | children: [ 108 | // Text(_data), 109 | StreamBuilder( 110 | stream: _streamDemo.stream, 111 | initialData: '...', 112 | builder: (context, snapshot) { 113 | return Text('${snapshot.data}'); 114 | }, 115 | ), 116 | Row( 117 | mainAxisAlignment: MainAxisAlignment.center, 118 | children: [ 119 | FlatButton( 120 | child: Text('Add'), 121 | onPressed: _addDataToStream, 122 | ), 123 | FlatButton( 124 | child: Text('Pause'), 125 | onPressed: _pauseStream, 126 | ), 127 | FlatButton( 128 | child: Text('Resume'), 129 | onPressed: _resumeStream, 130 | ), 131 | FlatButton( 132 | child: Text('Cancel'), 133 | onPressed: _cancelStream, 134 | ), 135 | ], 136 | ), 137 | ], 138 | ), 139 | ), 140 | ); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /lib/demo/switch_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SwitchDemo extends StatefulWidget { 4 | @override 5 | _SwitchDemoState createState() => _SwitchDemoState(); 6 | } 7 | 8 | class _SwitchDemoState extends State { 9 | bool _switchItemA = false; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: Text('SwitchDemo'), 16 | elevation: 0.0, 17 | ), 18 | body: Container( 19 | padding: EdgeInsets.all(16.0), 20 | child: Column( 21 | mainAxisAlignment: MainAxisAlignment.center, 22 | children: [ 23 | SwitchListTile( 24 | value: _switchItemA, 25 | onChanged: (value) { 26 | setState(() { 27 | _switchItemA = value; 28 | }); 29 | }, 30 | title: Text('Switch Item A'), 31 | subtitle: Text('Description'), 32 | secondary: Icon(_switchItemA ? Icons.visibility : Icons.visibility_off), 33 | selected: _switchItemA, 34 | ), 35 | Row( 36 | mainAxisAlignment: MainAxisAlignment.center, 37 | children: [ 38 | // Text(_switchItemA ? '😁' : '😐', style: TextStyle(fontSize: 32.0),), 39 | // Switch( 40 | // value: _switchItemA, 41 | // onChanged: (value) { 42 | // setState(() { 43 | // _switchItemA = value; 44 | // }); 45 | // }, 46 | // ), 47 | ], 48 | ), 49 | ], 50 | ), 51 | ) 52 | ); 53 | } 54 | } -------------------------------------------------------------------------------- /lib/demo/test/test_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class TestDemo extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Scaffold( 7 | appBar: AppBar( 8 | title: Text('TestDemo'), 9 | elevation: 0.0, 10 | ), 11 | body: TestDemoHome(), 12 | ); 13 | } 14 | } 15 | 16 | class TestDemoHome extends StatefulWidget { 17 | @override 18 | _TestDemoHomeState createState() => _TestDemoHomeState(); 19 | } 20 | 21 | class _TestDemoHomeState extends State { 22 | int count = 0; 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Row( 27 | children: [ 28 | Chip( 29 | label: Text('hello'), 30 | ), 31 | ActionChip( 32 | key: Key('actionChip'), 33 | label: Text('$count', key: Key('actionChipLabelText')), 34 | onPressed: () { 35 | setState(() { 36 | count++; 37 | }); 38 | }, 39 | ) 40 | ], 41 | ); 42 | } 43 | } 44 | 45 | class NinghaoTestDemo { 46 | static greet(String name) { 47 | return 'hello $name ~~'; 48 | } 49 | } -------------------------------------------------------------------------------- /lib/demo/view_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../model/post.dart'; 3 | 4 | class ViewDemo extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return GridViewBuilderDemo(); 8 | } 9 | } 10 | 11 | class GridViewBuilderDemo extends StatelessWidget { 12 | Widget _gridItemBuilder(BuildContext context, int index) { 13 | return Container( 14 | child: Image.network( 15 | posts[index].imageUrl, 16 | fit: BoxFit.cover 17 | ), 18 | ); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return GridView.builder( 24 | padding: EdgeInsets.all(8.0), 25 | itemCount: posts.length, 26 | itemBuilder: _gridItemBuilder, 27 | gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( 28 | // crossAxisCount: 3, 29 | maxCrossAxisExtent: 150.0, 30 | crossAxisSpacing: 8.0, 31 | mainAxisSpacing: 8.0, 32 | ), 33 | ); 34 | } 35 | } 36 | 37 | class GridViewExtentDemo extends StatelessWidget { 38 | List _buildTiles(int length) { 39 | return List.generate(length, (int index) { 40 | return Container( 41 | color: Colors.grey[300], 42 | alignment: Alignment(0.0, 0.0), 43 | child: Text('Item $index', 44 | style: TextStyle(fontSize: 18.0, color: Colors.grey)), 45 | ); 46 | }); 47 | } 48 | 49 | @override 50 | Widget build(BuildContext context) { 51 | return GridView.extent( 52 | maxCrossAxisExtent: 150.0, 53 | crossAxisSpacing: 16.0, 54 | mainAxisSpacing: 16.0, 55 | // scrollDirection: Axis.horizontal, 56 | children: _buildTiles(100), 57 | ); 58 | } 59 | } 60 | 61 | class GridViewCountDemo extends StatelessWidget { 62 | List _buildTiles(int length) { 63 | return List.generate(length, (int index) { 64 | return Container( 65 | color: Colors.grey[300], 66 | alignment: Alignment(0.0, 0.0), 67 | child: Text('Item $index', 68 | style: TextStyle(fontSize: 18.0, color: Colors.grey)), 69 | ); 70 | }); 71 | } 72 | 73 | @override 74 | Widget build(BuildContext context) { 75 | return GridView.count( 76 | crossAxisCount: 3, 77 | crossAxisSpacing: 16.0, 78 | mainAxisSpacing: 16.0, 79 | scrollDirection: Axis.horizontal, 80 | children: _buildTiles(100), 81 | ); 82 | } 83 | } 84 | 85 | class PageViewBuilderDemo extends StatelessWidget { 86 | Widget _pageItemBuilder(BuildContext context, int index) { 87 | return Stack( 88 | children: [ 89 | SizedBox.expand( 90 | child: Image.network(posts[index].imageUrl, fit: BoxFit.cover), 91 | ), 92 | Positioned( 93 | bottom: 8.0, 94 | left: 8.0, 95 | child: Column( 96 | crossAxisAlignment: CrossAxisAlignment.start, 97 | children: [ 98 | Text(posts[index].title, 99 | style: TextStyle(fontWeight: FontWeight.bold)), 100 | Text(posts[index].author), 101 | ], 102 | ), 103 | ), 104 | ], 105 | ); 106 | } 107 | 108 | @override 109 | Widget build(BuildContext context) { 110 | // TODO: implement build 111 | return PageView.builder( 112 | itemCount: posts.length, 113 | itemBuilder: _pageItemBuilder, 114 | ); 115 | } 116 | } 117 | 118 | class PageViewDemo extends StatelessWidget { 119 | @override 120 | Widget build(BuildContext context) { 121 | // TODO: implement build 122 | return PageView( 123 | // pageSnapping: false, 124 | // reverse: true, 125 | scrollDirection: Axis.vertical, 126 | onPageChanged: (currentPage) => debugPrint('Page: $currentPage'), 127 | controller: PageController( 128 | initialPage: 1, 129 | keepPage: false, 130 | viewportFraction: 0.85, 131 | ), 132 | children: [ 133 | Container( 134 | color: Colors.brown[900], 135 | alignment: Alignment(0.0, 0.0), 136 | child: Text('ONE', 137 | style: TextStyle(fontSize: 32.0, color: Colors.white)), 138 | ), 139 | Container( 140 | color: Colors.grey[900], 141 | alignment: Alignment(0.0, 0.0), 142 | child: Text('TWO', 143 | style: TextStyle(fontSize: 32.0, color: Colors.white)), 144 | ), 145 | Container( 146 | color: Colors.blueGrey[900], 147 | alignment: Alignment(0.0, 0.0), 148 | child: Text('THREE', 149 | style: TextStyle(fontSize: 32.0, color: Colors.white)), 150 | ), 151 | ], 152 | ); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ninghao_flutter/demo/animation/animation_demo.dart'; 3 | import 'package:ninghao_flutter/demo/bloc/bloc_demo.dart'; 4 | import 'package:ninghao_flutter/demo/http/http_demo.dart'; 5 | import 'package:ninghao_flutter/demo/i18n/i18n_demo.dart'; 6 | import 'package:ninghao_flutter/demo/rxdart/rxdart_demo.dart'; 7 | import 'package:ninghao_flutter/demo/state/state_management_demo.dart'; 8 | import 'package:ninghao_flutter/demo/stream/stream_demo.dart'; 9 | import 'package:ninghao_flutter/demo/test/test_demo.dart'; 10 | import './demo/drawer_demo.dart'; 11 | import './demo/bottom_navigation_bar_demo.dart'; 12 | import './demo/listview_demo.dart'; 13 | import './demo/basic_demo.dart'; 14 | import './demo/layout_demo.dart'; 15 | import './demo/view_demo.dart'; 16 | import './demo/sliver_demo.dart'; 17 | import './demo/navigator_demo.dart'; 18 | import './demo/form_demo.dart'; 19 | import './demo/material_components.dart'; 20 | import 'package:flutter_localizations/flutter_localizations.dart'; 21 | // import 'package:ninghao_flutter/demo/i18n/map/ninghao_demo_localizations.dart'; 22 | import 'package:ninghao_flutter/demo/i18n/intl/ninghao_demo_localizations.dart'; 23 | 24 | void main() => runApp(App()); 25 | 26 | class App extends StatelessWidget { 27 | @override 28 | Widget build(BuildContext context) { 29 | return MaterialApp( 30 | locale: Locale('en', 'US'), 31 | // locale: Locale('zh', 'CN'), 32 | // localeResolutionCallback: (Locale locale, Iterable supportedLocales) { 33 | // return Locale('en', 'US'); 34 | // }, 35 | localizationsDelegates: [ 36 | NinghaoDemoLocalizationsDelegate(), 37 | GlobalMaterialLocalizations.delegate, 38 | GlobalWidgetsLocalizations.delegate, 39 | ], 40 | supportedLocales: [ 41 | Locale('en', 'US'), 42 | Locale('zh', 'CN'), 43 | ], 44 | debugShowCheckedModeBanner: false, 45 | // home: NavigatorDemo(), 46 | initialRoute: '/', 47 | routes: { 48 | '/': (context) => Home(), 49 | '/about': (context) => Page(title: 'About'), 50 | '/form': (context) => FormDemo(), 51 | '/mdc': (context) => MaterialComponents(), 52 | '/state-management': (context) => StateManagementDemo(), 53 | '/stream': (context) => StreamDemo(), 54 | '/rxdart': (context) => RxDartDemo(), 55 | '/bloc': (context) => BlocDemo(), 56 | '/http': (context) => HttpDemo(), 57 | '/animation': (context) => AnimationDemo(), 58 | '/i18n': (context) => I18nDemo(), 59 | '/test': (context) => TestDemo(), 60 | }, 61 | theme: ThemeData( 62 | primarySwatch: Colors.yellow, 63 | highlightColor: Color.fromRGBO(255, 255, 255, 0.5), 64 | splashColor: Colors.white70, 65 | accentColor: Color.fromRGBO(3, 54, 255, 1.0), 66 | )); 67 | } 68 | } 69 | 70 | class Home extends StatelessWidget { 71 | @override 72 | Widget build(BuildContext context) { 73 | return DefaultTabController( 74 | length: 4, 75 | child: Scaffold( 76 | backgroundColor: Colors.grey[100], 77 | appBar: AppBar( 78 | title: Text('NINGHAO'), 79 | actions: [ 80 | IconButton( 81 | icon: Icon(Icons.search), 82 | tooltip: 'Search', 83 | onPressed: () => debugPrint('Search button is pressed.'), 84 | ) 85 | ], 86 | elevation: 0.0, 87 | bottom: TabBar( 88 | unselectedLabelColor: Colors.black38, 89 | indicatorColor: Colors.black54, 90 | indicatorSize: TabBarIndicatorSize.label, 91 | indicatorWeight: 1.0, 92 | tabs: [ 93 | Tab(icon: Icon(Icons.local_florist)), 94 | Tab(icon: Icon(Icons.change_history)), 95 | Tab(icon: Icon(Icons.directions_bike)), 96 | Tab(icon: Icon(Icons.view_quilt)), 97 | ], 98 | ), 99 | ), 100 | body: TabBarView( 101 | children: [ 102 | ListViewDemo(), 103 | // Icon(Icons.change_history, size: 128.0, color: Colors.black12), 104 | BasicDemo(), 105 | // Icon(Icons.directions_bike, size: 128.0, color: Colors.black12), 106 | LayoutDemo(), 107 | SliverDemo(), 108 | ], 109 | ), 110 | drawer: DrawerDemo(), 111 | bottomNavigationBar: BottomNavigationBarDemo(), 112 | ), 113 | ); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /lib/model/post.dart: -------------------------------------------------------------------------------- 1 | class Post { 2 | Post({ 3 | this.title, 4 | this.author, 5 | this.imageUrl, 6 | this.description, 7 | }); 8 | 9 | final String title; 10 | final String author; 11 | final String imageUrl; 12 | final String description; 13 | 14 | bool selected = false; 15 | } 16 | 17 | final List posts = [ 18 | Post( 19 | title: 'Candy Shop', 20 | author: 'Mohamed Chahin', 21 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 22 | imageUrl: 'https://resources.ninghao.org/images/candy-shop.jpg', 23 | ), 24 | Post( 25 | title: 'Childhood in a picture', 26 | author: 'Mohamed Chahin', 27 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 28 | imageUrl: 'https://resources.ninghao.org/images/childhood-in-a-picture.jpg', 29 | ), 30 | Post( 31 | title: 'Contained', 32 | author: 'Mohamed Chahin', 33 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 34 | imageUrl: 'https://resources.ninghao.org/images/contained.jpg', 35 | ), 36 | Post( 37 | title: 'Dragon', 38 | author: 'Mohamed Chahin', 39 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 40 | imageUrl: 'https://resources.ninghao.org/images/dragon.jpg', 41 | ), 42 | Post( 43 | title: 'Free Hugs', 44 | author: 'Mohamed Chahin', 45 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 46 | imageUrl: 'https://resources.ninghao.org/images/free_hugs.jpg', 47 | ), 48 | Post( 49 | title: 'Gravity Falls', 50 | author: 'Mohamed Chahin', 51 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 52 | imageUrl: 'https://resources.ninghao.org/images/gravity-falls.png', 53 | ), 54 | Post( 55 | title: 'Icecream Truck', 56 | author: 'Mohamed Chahin', 57 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 58 | imageUrl: 'https://resources.ninghao.org/images/icecreamtruck.png', 59 | ), 60 | Post( 61 | title: 'keyclack', 62 | author: 'Mohamed Chahin', 63 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 64 | imageUrl: 'https://resources.ninghao.org/images/keyclack.jpg', 65 | ), 66 | Post( 67 | title: 'Overkill', 68 | author: 'Mohamed Chahin', 69 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 70 | imageUrl: 'https://resources.ninghao.org/images/overkill.png', 71 | ), 72 | Post( 73 | title: 'Say Hello to Barry', 74 | author: 'Mohamed Chahin', 75 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 76 | imageUrl: 'https://resources.ninghao.org/images/say-hello-to-barry.jpg', 77 | ), 78 | Post( 79 | title: 'Space Skull', 80 | author: 'Mohamed Chahin', 81 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 82 | imageUrl: 'https://resources.ninghao.org/images/space-skull.jpg', 83 | ), 84 | Post( 85 | title: 'The Old Fashioned', 86 | author: 'Mohamed Chahin', 87 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 88 | imageUrl: 'https://resources.ninghao.org/images/the-old-fashioned.png', 89 | ), 90 | Post( 91 | title: 'Tornado', 92 | author: 'Mohamed Chahin', 93 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 94 | imageUrl: 'https://resources.ninghao.org/images/tornado.jpg', 95 | ), 96 | Post( 97 | title: 'Undo', 98 | author: 'Mohamed Chahin', 99 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 100 | imageUrl: 'https://resources.ninghao.org/images/undo.jpg', 101 | ), 102 | Post( 103 | title: 'White Dragon', 104 | author: 'Mohamed Chahin', 105 | description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', 106 | imageUrl: 'https://resources.ninghao.org/images/white-dragon.jpg', 107 | ) 108 | ]; -------------------------------------------------------------------------------- /ninghao_flutter.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ninghao_flutter_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | analyzer: 5 | dependency: transitive 6 | description: 7 | name: analyzer 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "0.36.4" 11 | archive: 12 | dependency: transitive 13 | description: 14 | name: archive 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "2.0.10" 18 | args: 19 | dependency: transitive 20 | description: 21 | name: args 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "1.5.2" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "2.3.0" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.flutter-io.cn" 37 | source: hosted 38 | version: "1.0.5" 39 | charcode: 40 | dependency: transitive 41 | description: 42 | name: charcode 43 | url: "https://pub.flutter-io.cn" 44 | source: hosted 45 | version: "1.1.2" 46 | collection: 47 | dependency: transitive 48 | description: 49 | name: collection 50 | url: "https://pub.flutter-io.cn" 51 | source: hosted 52 | version: "1.14.11" 53 | convert: 54 | dependency: transitive 55 | description: 56 | name: convert 57 | url: "https://pub.flutter-io.cn" 58 | source: hosted 59 | version: "2.1.1" 60 | crypto: 61 | dependency: transitive 62 | description: 63 | name: crypto 64 | url: "https://pub.flutter-io.cn" 65 | source: hosted 66 | version: "2.1.3" 67 | csslib: 68 | dependency: transitive 69 | description: 70 | name: csslib 71 | url: "https://pub.flutter-io.cn" 72 | source: hosted 73 | version: "0.14.6" 74 | cupertino_icons: 75 | dependency: "direct main" 76 | description: 77 | name: cupertino_icons 78 | url: "https://pub.flutter-io.cn" 79 | source: hosted 80 | version: "0.1.2" 81 | dart_style: 82 | dependency: transitive 83 | description: 84 | name: dart_style 85 | url: "https://pub.flutter-io.cn" 86 | source: hosted 87 | version: "1.2.9" 88 | file: 89 | dependency: transitive 90 | description: 91 | name: file 92 | url: "https://pub.flutter-io.cn" 93 | source: hosted 94 | version: "5.0.10" 95 | flutter: 96 | dependency: "direct main" 97 | description: flutter 98 | source: sdk 99 | version: "0.0.0" 100 | flutter_driver: 101 | dependency: "direct dev" 102 | description: flutter 103 | source: sdk 104 | version: "0.0.0" 105 | flutter_localizations: 106 | dependency: "direct main" 107 | description: flutter 108 | source: sdk 109 | version: "0.0.0" 110 | flutter_test: 111 | dependency: "direct dev" 112 | description: flutter 113 | source: sdk 114 | version: "0.0.0" 115 | front_end: 116 | dependency: transitive 117 | description: 118 | name: front_end 119 | url: "https://pub.flutter-io.cn" 120 | source: hosted 121 | version: "0.1.19" 122 | fuchsia_remote_debug_protocol: 123 | dependency: transitive 124 | description: flutter 125 | source: sdk 126 | version: "0.0.0" 127 | glob: 128 | dependency: transitive 129 | description: 130 | name: glob 131 | url: "https://pub.flutter-io.cn" 132 | source: hosted 133 | version: "1.1.7" 134 | html: 135 | dependency: transitive 136 | description: 137 | name: html 138 | url: "https://pub.flutter-io.cn" 139 | source: hosted 140 | version: "0.14.0+3" 141 | http: 142 | dependency: "direct main" 143 | description: 144 | name: http 145 | url: "https://pub.flutter-io.cn" 146 | source: hosted 147 | version: "0.12.0" 148 | http_multi_server: 149 | dependency: transitive 150 | description: 151 | name: http_multi_server 152 | url: "https://pub.flutter-io.cn" 153 | source: hosted 154 | version: "2.1.0" 155 | http_parser: 156 | dependency: transitive 157 | description: 158 | name: http_parser 159 | url: "https://pub.flutter-io.cn" 160 | source: hosted 161 | version: "3.1.3" 162 | image: 163 | dependency: transitive 164 | description: 165 | name: image 166 | url: "https://pub.flutter-io.cn" 167 | source: hosted 168 | version: "2.1.4" 169 | intl: 170 | dependency: "direct main" 171 | description: 172 | name: intl 173 | url: "https://pub.flutter-io.cn" 174 | source: hosted 175 | version: "0.16.0" 176 | intl_translation: 177 | dependency: "direct dev" 178 | description: 179 | name: intl_translation 180 | url: "https://pub.flutter-io.cn" 181 | source: hosted 182 | version: "0.17.7" 183 | io: 184 | dependency: transitive 185 | description: 186 | name: io 187 | url: "https://pub.flutter-io.cn" 188 | source: hosted 189 | version: "0.3.3" 190 | js: 191 | dependency: transitive 192 | description: 193 | name: js 194 | url: "https://pub.flutter-io.cn" 195 | source: hosted 196 | version: "0.6.1+1" 197 | json_rpc_2: 198 | dependency: transitive 199 | description: 200 | name: json_rpc_2 201 | url: "https://pub.flutter-io.cn" 202 | source: hosted 203 | version: "2.1.0" 204 | kernel: 205 | dependency: transitive 206 | description: 207 | name: kernel 208 | url: "https://pub.flutter-io.cn" 209 | source: hosted 210 | version: "0.3.19" 211 | logging: 212 | dependency: transitive 213 | description: 214 | name: logging 215 | url: "https://pub.flutter-io.cn" 216 | source: hosted 217 | version: "0.11.3+2" 218 | matcher: 219 | dependency: transitive 220 | description: 221 | name: matcher 222 | url: "https://pub.flutter-io.cn" 223 | source: hosted 224 | version: "0.12.5" 225 | meta: 226 | dependency: transitive 227 | description: 228 | name: meta 229 | url: "https://pub.flutter-io.cn" 230 | source: hosted 231 | version: "1.1.7" 232 | mime: 233 | dependency: transitive 234 | description: 235 | name: mime 236 | url: "https://pub.flutter-io.cn" 237 | source: hosted 238 | version: "0.9.6+3" 239 | multi_server_socket: 240 | dependency: transitive 241 | description: 242 | name: multi_server_socket 243 | url: "https://pub.flutter-io.cn" 244 | source: hosted 245 | version: "1.0.2" 246 | node_preamble: 247 | dependency: transitive 248 | description: 249 | name: node_preamble 250 | url: "https://pub.flutter-io.cn" 251 | source: hosted 252 | version: "1.4.8" 253 | package_config: 254 | dependency: transitive 255 | description: 256 | name: package_config 257 | url: "https://pub.flutter-io.cn" 258 | source: hosted 259 | version: "1.1.0" 260 | package_resolver: 261 | dependency: transitive 262 | description: 263 | name: package_resolver 264 | url: "https://pub.flutter-io.cn" 265 | source: hosted 266 | version: "1.0.10" 267 | path: 268 | dependency: transitive 269 | description: 270 | name: path 271 | url: "https://pub.flutter-io.cn" 272 | source: hosted 273 | version: "1.6.4" 274 | pedantic: 275 | dependency: transitive 276 | description: 277 | name: pedantic 278 | url: "https://pub.flutter-io.cn" 279 | source: hosted 280 | version: "1.8.0+1" 281 | petitparser: 282 | dependency: transitive 283 | description: 284 | name: petitparser 285 | url: "https://pub.flutter-io.cn" 286 | source: hosted 287 | version: "2.4.0" 288 | platform: 289 | dependency: transitive 290 | description: 291 | name: platform 292 | url: "https://pub.flutter-io.cn" 293 | source: hosted 294 | version: "2.2.1" 295 | pool: 296 | dependency: transitive 297 | description: 298 | name: pool 299 | url: "https://pub.flutter-io.cn" 300 | source: hosted 301 | version: "1.4.0" 302 | process: 303 | dependency: transitive 304 | description: 305 | name: process 306 | url: "https://pub.flutter-io.cn" 307 | source: hosted 308 | version: "3.0.12" 309 | pub_semver: 310 | dependency: transitive 311 | description: 312 | name: pub_semver 313 | url: "https://pub.flutter-io.cn" 314 | source: hosted 315 | version: "1.4.2" 316 | quiver: 317 | dependency: transitive 318 | description: 319 | name: quiver 320 | url: "https://pub.flutter-io.cn" 321 | source: hosted 322 | version: "2.0.5" 323 | rxdart: 324 | dependency: "direct main" 325 | description: 326 | name: rxdart 327 | url: "https://pub.flutter-io.cn" 328 | source: hosted 329 | version: "0.18.1" 330 | scoped_model: 331 | dependency: "direct main" 332 | description: 333 | name: scoped_model 334 | url: "https://pub.flutter-io.cn" 335 | source: hosted 336 | version: "0.3.0" 337 | shelf: 338 | dependency: transitive 339 | description: 340 | name: shelf 341 | url: "https://pub.flutter-io.cn" 342 | source: hosted 343 | version: "0.7.5" 344 | shelf_packages_handler: 345 | dependency: transitive 346 | description: 347 | name: shelf_packages_handler 348 | url: "https://pub.flutter-io.cn" 349 | source: hosted 350 | version: "1.0.4" 351 | shelf_static: 352 | dependency: transitive 353 | description: 354 | name: shelf_static 355 | url: "https://pub.flutter-io.cn" 356 | source: hosted 357 | version: "0.2.8" 358 | shelf_web_socket: 359 | dependency: transitive 360 | description: 361 | name: shelf_web_socket 362 | url: "https://pub.flutter-io.cn" 363 | source: hosted 364 | version: "0.2.3" 365 | sky_engine: 366 | dependency: transitive 367 | description: flutter 368 | source: sdk 369 | version: "0.0.99" 370 | source_map_stack_trace: 371 | dependency: transitive 372 | description: 373 | name: source_map_stack_trace 374 | url: "https://pub.flutter-io.cn" 375 | source: hosted 376 | version: "1.1.5" 377 | source_maps: 378 | dependency: transitive 379 | description: 380 | name: source_maps 381 | url: "https://pub.flutter-io.cn" 382 | source: hosted 383 | version: "0.10.8" 384 | source_span: 385 | dependency: transitive 386 | description: 387 | name: source_span 388 | url: "https://pub.flutter-io.cn" 389 | source: hosted 390 | version: "1.5.5" 391 | stack_trace: 392 | dependency: transitive 393 | description: 394 | name: stack_trace 395 | url: "https://pub.flutter-io.cn" 396 | source: hosted 397 | version: "1.9.3" 398 | stream_channel: 399 | dependency: transitive 400 | description: 401 | name: stream_channel 402 | url: "https://pub.flutter-io.cn" 403 | source: hosted 404 | version: "2.0.0" 405 | string_scanner: 406 | dependency: transitive 407 | description: 408 | name: string_scanner 409 | url: "https://pub.flutter-io.cn" 410 | source: hosted 411 | version: "1.0.5" 412 | term_glyph: 413 | dependency: transitive 414 | description: 415 | name: term_glyph 416 | url: "https://pub.flutter-io.cn" 417 | source: hosted 418 | version: "1.1.0" 419 | test: 420 | dependency: "direct dev" 421 | description: 422 | name: test 423 | url: "https://pub.flutter-io.cn" 424 | source: hosted 425 | version: "1.6.3" 426 | test_api: 427 | dependency: transitive 428 | description: 429 | name: test_api 430 | url: "https://pub.flutter-io.cn" 431 | source: hosted 432 | version: "0.2.5" 433 | test_core: 434 | dependency: transitive 435 | description: 436 | name: test_core 437 | url: "https://pub.flutter-io.cn" 438 | source: hosted 439 | version: "0.2.5" 440 | typed_data: 441 | dependency: transitive 442 | description: 443 | name: typed_data 444 | url: "https://pub.flutter-io.cn" 445 | source: hosted 446 | version: "1.1.6" 447 | vector_math: 448 | dependency: transitive 449 | description: 450 | name: vector_math 451 | url: "https://pub.flutter-io.cn" 452 | source: hosted 453 | version: "2.0.8" 454 | vm_service_client: 455 | dependency: transitive 456 | description: 457 | name: vm_service_client 458 | url: "https://pub.flutter-io.cn" 459 | source: hosted 460 | version: "0.2.6+2" 461 | watcher: 462 | dependency: transitive 463 | description: 464 | name: watcher 465 | url: "https://pub.flutter-io.cn" 466 | source: hosted 467 | version: "0.9.7+10" 468 | web_socket_channel: 469 | dependency: transitive 470 | description: 471 | name: web_socket_channel 472 | url: "https://pub.flutter-io.cn" 473 | source: hosted 474 | version: "1.0.15" 475 | xml: 476 | dependency: transitive 477 | description: 478 | name: xml 479 | url: "https://pub.flutter-io.cn" 480 | source: hosted 481 | version: "3.5.0" 482 | yaml: 483 | dependency: transitive 484 | description: 485 | name: yaml 486 | url: "https://pub.flutter-io.cn" 487 | source: hosted 488 | version: "2.1.15" 489 | sdks: 490 | dart: ">=2.4.0 <3.0.0" 491 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ninghao_flutter 2 | description: A new Flutter project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # Read more about versioning at semver.org. 10 | version: 1.0.0+1 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | intl: ^0.16.0 16 | scoped_model: ^0.3.0 17 | rxdart: ^0.18.1 18 | http: ^0.12.0 19 | flutter_localizations: 20 | sdk: flutter 21 | 22 | # The following adds the Cupertino Icons font to your application. 23 | # Use with the CupertinoIcons class for iOS style icons. 24 | cupertino_icons: ^0.1.2 25 | 26 | dev_dependencies: 27 | flutter_test: 28 | sdk: flutter 29 | flutter_driver: 30 | sdk: flutter 31 | intl_translation: ^0.17.2 32 | test: ^1.5.1 33 | 34 | # For information on the generic Dart part of this file, see the 35 | # following page: https://www.dartlang.org/tools/pub/pubspec 36 | 37 | # The following section is specific to Flutter. 38 | flutter: 39 | # The following line ensures that the Material Icons font is 40 | # included with your application, so that you can use the icons in 41 | # the material Icons class. 42 | uses-material-design: true 43 | # To add assets to your application, add an assets section, like this: 44 | # assets: 45 | # - images/a_dot_burr.jpeg 46 | # - images/a_dot_ham.jpeg 47 | # An image asset can refer to one or more resolution-specific "variants", see 48 | # https://flutter.io/assets-and-images/#resolution-aware. 49 | # For details regarding adding assets from package dependencies, see 50 | # https://flutter.io/assets-and-images/#from-packages 51 | # To add custom fonts to your application, add a fonts section here, 52 | # in this "flutter" section. Each entry in this list should have a 53 | # "family" key with the font family name, and a "fonts" key with a 54 | # list giving the asset and other descriptors for the font. For 55 | # example: 56 | # fonts: 57 | # - family: Schyler 58 | # fonts: 59 | # - asset: fonts/Schyler-Regular.ttf 60 | # - asset: fonts/Schyler-Italic.ttf 61 | # style: italic 62 | # - family: Trajan Pro 63 | # fonts: 64 | # - asset: fonts/TrajanPro.ttf 65 | # - asset: fonts/TrajanPro_Bold.ttf 66 | # weight: 700 67 | # 68 | # For details regarding fonts from package dependencies, 69 | # see https://flutter.io/custom-fonts/#from-packages 70 | -------------------------------------------------------------------------------- /test/ninghao_demo_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:ninghao_flutter/demo/test/test_demo.dart'; 4 | 5 | void main() { 6 | test('should return hello + something.', () { 7 | var string = NinghaoTestDemo.greet('ninghao'); 8 | expect(string, 'hello ninghao ~~'); 9 | }); 10 | 11 | testWidgets('widget testing demo', (WidgetTester tester) async { 12 | await tester.pumpWidget( 13 | MaterialApp( 14 | home: TestDemo() 15 | ) 16 | ); 17 | 18 | final labelText = find.text('hello'); 19 | 20 | // expect(labelText, findsNothing); 21 | // expect(labelText, findsOneWidget); 22 | expect(labelText, findsNWidgets(1)); 23 | 24 | final actionChipLabelText = find.text('0'); 25 | expect(actionChipLabelText, findsOneWidget); 26 | 27 | final actionChip = find.byType(ActionChip); 28 | await tester.tap(actionChip); 29 | await tester.pump(); 30 | 31 | final actionChipLabelTextAfterTap = find.text('1'); 32 | expect(actionChipLabelTextAfterTap, findsOneWidget); 33 | expect(actionChipLabelText, findsNothing); 34 | }); 35 | } -------------------------------------------------------------------------------- /test_driver/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_driver/driver_extension.dart'; 2 | import 'package:ninghao_flutter/main.dart' as app; 3 | 4 | void main() { 5 | enableFlutterDriverExtension(); 6 | 7 | app.main(); 8 | } -------------------------------------------------------------------------------- /test_driver/app_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_driver/flutter_driver.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('App', () { 6 | FlutterDriver driver; 7 | 8 | final actionChip = find.byValueKey('actionChip'); 9 | final actionChipLabelText = find.byValueKey('actionChipLabelText'); 10 | 11 | setUpAll(() async { 12 | driver = await FlutterDriver.connect(); 13 | }); 14 | 15 | tearDownAll(() async { 16 | if (driver != null) { 17 | driver.close(); 18 | } 19 | }); 20 | 21 | test('starts at 0', () async { 22 | expect(await driver.getText(actionChipLabelText), '0'); 23 | }); 24 | 25 | test('increments the counter', () async { 26 | await driver.tap(actionChip); 27 | 28 | expect(await driver.getText(actionChipLabelText), '1'); 29 | }); 30 | }); 31 | } --------------------------------------------------------------------------------