Repository: Rice4Gua/ZhihuDailyFlutter
Branch: master
Commit: 7a2c8fe6d5bf
Files: 74
Total size: 125.4 KB
Directory structure:
gitextract_j4o_q4iv/
├── .gitignore
├── .metadata
├── README.md
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── build.gradle
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── yourcompany/
│ │ │ └── starter/
│ │ │ ├── MainActivity.java
│ │ │ └── TestActivity.java
│ │ └── res/
│ │ ├── drawable/
│ │ │ └── launch_background.xml
│ │ ├── layout/
│ │ │ └── test_activity.xml
│ │ └── values/
│ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── key.properties
│ └── settings.gradle
├── flutter_01.log
├── ios/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ └── Runner.xcworkspace/
│ └── contents.xcworkspacedata
├── lib/
│ ├── common/
│ │ ├── common_divider.dart
│ │ ├── common_loading_dialog.dart
│ │ ├── common_retry.dart
│ │ ├── common_snakeBar.dart
│ │ └── constant.dart
│ ├── exampleDemo/
│ │ ├── fadeAppTest.dart
│ │ ├── isolateApp.dart
│ │ ├── layoutApp.dart
│ │ ├── listItem.dart
│ │ ├── navigatorTest.dart
│ │ ├── platformChannel.dart
│ │ ├── sampleApp1.dart
│ │ ├── sampleApp2.dart
│ │ ├── showLoading.dart
│ │ └── startApp.dart
│ ├── generated/
│ │ └── i18n.dart
│ ├── main.dart
│ ├── model/
│ │ ├── ThemeModel.dart
│ │ ├── base_model.dart
│ │ ├── homePageModel.dart
│ │ └── theme_list_model.dart
│ ├── net/
│ │ ├── apis.dart
│ │ └── dio_factory.dart
│ ├── presenter/
│ │ ├── mvp.dart
│ │ ├── theme_list_presenter.dart
│ │ └── theme_list_presenter_impl.dart
│ ├── repository/
│ │ ├── theme_list_repository.dart
│ │ └── theme_list_repository_impl.dart
│ ├── utils/
│ │ └── RouterUtils.dart
│ ├── widget/
│ │ ├── drawerContent.dart
│ │ └── homeBanner.dart
│ └── zhihu/
│ ├── storyItem.dart
│ ├── themeListPage.dart
│ └── zhihudaily.dart
├── pubspec.yaml
├── res/
│ └── values/
│ └── strings_en.arb
├── test/
│ └── widget_test.dart
└── zhihu.keystore
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
.atom/
.dart_tool/
.idea
.vscode/
.packages
.pub/
build/
ios/.generated/
packages
.flutter-plugins
================================================
FILE: .metadata
================================================
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: eef77ccaff6ca0a9884c7454938b7833746e95df
channel: dev
================================================
FILE: README.md
================================================
# zhihudaily_flutter
A new Flutter zhihudaily project.
## Getting Started
For help getting started with Flutter, view our online
[documentation](https://flutter.io/).
waiting..
================================================
FILE: android/.gitignore
================================================
*.iml
*.class
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
GeneratedPluginRegistrant.java
================================================
FILE: android/app/build.gradle
================================================
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
compileSdkVersion 27
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.yourcompany.starter"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
flutter {
source '../..'
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
================================================
FILE: android/app/src/main/AndroidManifest.xml
================================================
================================================
FILE: android/app/src/main/java/com/yourcompany/starter/MainActivity.java
================================================
package com.yourcompany.starter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import junit.framework.Test;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private static final String BATTERY_CHANNEL = "samples.flutter.io/battery";
private static final String CHARGING_CHANNEL = "samples.flutter.io/charging";
private static final String INTENT_CHANNEL = "samples.flutter.io/intent";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new EventChannel(getFlutterView(), CHARGING_CHANNEL).setStreamHandler(new StreamHandler() {
private BroadcastReceiver chargingStateChangeReceiver;
@Override
public void onListen(Object arguments, EventSink events) {
chargingStateChangeReceiver = createChargingStateChangeReceiver(events);
registerReceiver(chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
@Override
public void onCancel(Object arguments) {
unregisterReceiver(chargingStateChangeReceiver);
chargingStateChangeReceiver = null;
}
});
new MethodChannel(getFlutterView(), INTENT_CHANNEL).setMethodCallHandler(new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("gotoActivity")) {
Intent intent = new Intent(MainActivity.this, TestActivity.class);
startActivity(intent);
} else {
result.notImplemented();
}
}
});
new MethodChannel(getFlutterView(), BATTERY_CHANNEL).setMethodCallHandler(new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if (batteryLevel != -1) {
result.success(batteryLevel);
} else {
result.error("UNAVAILABLE", "Battery level not available.", null);
}
} else {
result.notImplemented();
}
}
});
}
private BroadcastReceiver createChargingStateChangeReceiver(final EventSink events) {
return new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if (status == BatteryManager.BATTERY_STATUS_UNKNOWN) {
events.error("UNAVAILABLE", "Charging status unavailable", null);
} else {
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING
|| status == BatteryManager.BATTERY_STATUS_FULL;
events.success(isCharging ? "charging" : "discharging");
}
}
};
}
private int getBatteryLevel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
} else {
Intent intent = new ContextWrapper(getApplicationContext()).
registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
return (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) / intent.getIntExtra(
BatteryManager.EXTRA_SCALE, -1);
}
}
}
================================================
FILE: android/app/src/main/java/com/yourcompany/starter/TestActivity.java
================================================
package com.yourcompany.starter;
import android.app.Activity;
import android.os.Bundle;
public class TestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
}
}
================================================
FILE: android/app/src/main/res/drawable/launch_background.xml
================================================
================================================
FILE: android/app/src/main/res/layout/test_activity.xml
================================================
================================================
FILE: android/app/src/main/res/values/styles.xml
================================================
================================================
FILE: android/build.gradle
================================================
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: android/gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
================================================
FILE: android/gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: android/gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: android/key.properties
================================================
storePassword=rice1985
keyPassword=rice1985
keyAlias=key
storeFile=/Users/lhw/key.jks
================================================
FILE: android/settings.gradle
================================================
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
================================================
FILE: flutter_01.log
================================================
Flutter crash report; please file at https://github.com/flutter/flutter/issues.
## command
flutter upgrade
## exception
ArgumentError: Invalid argument(s): Cannot find executable for /Users/lhw/flutter/bin/cache/dart-sdk/bin/pub.
```
#0 _getExecutable (package:process/src/interface/local_process_manager.dart:113)
#1 LocalProcessManager.start (package:process/src/interface/local_process_manager.dart:41)
#2 runCommand (package:flutter_tools/src/base/process.dart:115)
#3 runCommandAndStreamOutput (package:flutter_tools/src/base/process.dart:133)
#4 pub (package:flutter_tools/src/dart/pub.dart:153)
#5 pubGet (package:flutter_tools/src/dart/pub.dart:104)
#6 UpgradeCommand.runCommand (package:flutter_tools/src/commands/upgrade.dart:75)
#7 FlutterCommand.verifyThenRunCommand (package:flutter_tools/src/runner/flutter_command.dart:344)
#8 FlutterCommand.run. (package:flutter_tools/src/runner/flutter_command.dart:279)
#9 AppContext.run. (package:flutter_tools/src/base/context.dart:142)
#10 _rootRun (dart:async/zone.dart:1126)
#11 _CustomZone.run (dart:async/zone.dart:1023)
#12 runZoned (dart:async/zone.dart:1501)
#13 AppContext.run (package:flutter_tools/src/base/context.dart:141)
#14 FlutterCommand.run (package:flutter_tools/src/runner/flutter_command.dart:270)
#15 CommandRunner.runCommand (package:args/command_runner.dart:194)
#16 FlutterCommandRunner.runCommand. (package:flutter_tools/src/runner/flutter_command_runner.dart:309)
#17 AppContext.run. (package:flutter_tools/src/base/context.dart:142)
#18 _rootRun (dart:async/zone.dart:1126)
#19 _CustomZone.run (dart:async/zone.dart:1023)
#20 runZoned (dart:async/zone.dart:1501)
#21 AppContext.run (package:flutter_tools/src/base/context.dart:141)
#22 FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:265)
#23 CommandRunner.run. (package:args/command_runner.dart:109)
#24 new Future.sync (dart:async/future.dart:222)
#25 CommandRunner.run (package:args/command_runner.dart:109)
#26 FlutterCommandRunner.run (package:flutter_tools/src/runner/flutter_command_runner.dart:174)
#27 run. (package:flutter_tools/runner.dart:59)
#28 AppContext.run. (package:flutter_tools/src/base/context.dart:142)
#29 _rootRun (dart:async/zone.dart:1126)
#30 _CustomZone.run (dart:async/zone.dart:1023)
#31 runZoned (dart:async/zone.dart:1501)
#32 AppContext.run (package:flutter_tools/src/base/context.dart:141)
#33 runInContext (package:flutter_tools/src/context_runner.dart:43)
#34 run (package:flutter_tools/runner.dart:50)
#35 main (package:flutter_tools/executable.dart:49)
#36 main (file:///Users/lhw/flutter/packages/flutter_tools/bin/flutter_tools.dart:8)
#37 _startIsolate. (dart:isolate-patch/dart:isolate/isolate_patch.dart:277)
#38 _RawReceivePortImpl._handleMessage (dart:isolate-patch/dart:isolate/isolate_patch.dart:165)
```
## flutter doctor
```
[✓] Flutter (Channel beta, v0.5.1, on Mac OS X 10.14.1 18B75, locale zh-Hans-CN)
• Flutter version 0.5.1 at /Users/lhw/flutter
• Framework revision c7ea3ca377 (7 months ago), 2018-11-29 19:41:26 -0800
• Engine revision 7375a0f414
• Dart version 2.0.0-dev.58.0.flutter-f981f09760
[!] Android toolchain - develop for Android devices (Android SDK 28.0.3)
• Android SDK at /Users/lhw/android-sdks
• Android NDK at /Users/lhw/android-sdks/ndk-bundle
• Platform android-28, build-tools 28.0.3
• ANDROID_HOME = /Users/lhw/android-sdks
• Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1136-b06)
! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses
[✓] iOS toolchain - develop for iOS devices (Xcode 10.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 10.1, Build version 10B61
• ios-deploy 1.9.2
• CocoaPods version 1.5.3
[✓] Android Studio (version 3.2)
• Android Studio at /Applications/Android Studio.app/Contents
✗ Flutter plugin not installed; this adds Flutter specific functionality.
✗ Dart plugin not installed; this adds Dart specific functionality.
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1136-b06)
[✓] IntelliJ IDEA Ultimate Edition (version 2018.1.1)
• IntelliJ at /Applications/IntelliJ IDEA.app
• Flutter plugin version 26.0.2
• Dart plugin version 181.4096.12
[✓] Connected devices (1 available)
• MIX 2 • e4413f71 • android-arm64 • Android 8.0.0 (API 26)
! Doctor found issues in 1 category.
```
================================================
FILE: ios/.gitignore
================================================
.idea/
.vagrant/
.sconsign.dblite
.svn/
.DS_Store
*.swp
profile
DerivedData/
build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
/Flutter/app.flx
/Flutter/app.zip
/Flutter/flutter_assets/
/Flutter/App.framework
/Flutter/Flutter.framework
/Flutter/Generated.xcconfig
/ServiceDefinitions.json
Pods/
================================================
FILE: ios/Flutter/AppFrameworkInfo.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
App
CFBundleIdentifier
io.flutter.flutter.app
CFBundleInfoDictionaryVersion
6.0
CFBundleName
App
CFBundlePackageType
FMWK
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1.0
UIRequiredDeviceCapabilities
arm64
MinimumOSVersion
8.0
================================================
FILE: ios/Flutter/Debug.xcconfig
================================================
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
================================================
FILE: ios/Flutter/Release.xcconfig
================================================
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
================================================
FILE: ios/Podfile
================================================
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end
target 'Runner' do
use_frameworks!
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
# Flutter Pods
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
end
}
# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join('.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(symlink, 'ios')
}
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
================================================
FILE: ios/Runner/AppDelegate.swift
================================================
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
================================================
FILE: ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
================================================
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
================================================
FILE: ios/Runner/Base.lproj/LaunchScreen.storyboard
================================================
================================================
FILE: ios/Runner/Base.lproj/Main.storyboard
================================================
================================================
FILE: ios/Runner/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
zhihudaily
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
LSRequiresIPhoneOS
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
Main
UIRequiredDeviceCapabilities
arm64
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UIViewControllerBasedStatusBarAppearance
================================================
FILE: ios/Runner/Runner-Bridging-Header.h
================================================
#import "GeneratedPluginRegistrant.h"
================================================
FILE: ios/Runner.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
EB0651998627A6BC08E57EBD /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F21928A2C461EE664C8DA388 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
F21928A2C461EE664C8DA388 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
EB0651998627A6BC08E57EBD /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0C6D914149C756CDE70B051B /* Frameworks */ = {
isa = PBXGroup;
children = (
F21928A2C461EE664C8DA388 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "";
};
34AF4E4C77695DC132C6AEDF /* Pods */ = {
isa = PBXGroup;
children = (
);
name = Pods;
sourceTree = "";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
34AF4E4C77695DC132C6AEDF /* Pods */,
0C6D914149C756CDE70B051B /* Frameworks */,
);
sourceTree = "";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
);
name = "Supporting Files";
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
E3A3C064A2A1150EAB121034 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
CAA558AFB9BBA78D9B607F6A /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0910;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
CAA558AFB9BBA78D9B607F6A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/flutter_webview_plugin/flutter_webview_plugin.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_webview_plugin.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
E3A3C064A2A1150EAB121034 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ARCHS = arm64;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.starter;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.0;
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ARCHS = arm64;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.starter;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
================================================
================================================
FILE: ios/Runner.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: lib/common/common_divider.dart
================================================
import 'package:flutter/material.dart';
class CommonDivider {
static Widget buildDivider() {
return new Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: new Divider(height: 1.0),
);
}
}
================================================
FILE: lib/common/common_loading_dialog.dart
================================================
import 'package:flutter/material.dart';
class ProgressDialog{
static Widget buildProgressDialog() {
return new Center(child: new CircularProgressIndicator());
}
}
================================================
FILE: lib/common/common_retry.dart
================================================
import 'package:flutter/material.dart';
class CommonRetry {
static Widget buildRetry(VoidCallback v) {
return new Center(
child: new Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: new InkWell(
borderRadius: new BorderRadius.all(new Radius.circular(10.0)),
onTap: v,
child: new Container(
width: 200.0,
alignment: Alignment.center,
padding: const EdgeInsets.only(
left: 10.0, top: 10.0, right: 10.0, bottom: 10.0),
height: 48.0,
decoration: new BoxDecoration(
border: new Border.all(
width: 1.0,
color: Colors.blue,
),
borderRadius: new BorderRadius.all(new Radius.circular(10.0)),
),
child: new Text('网络异常,请检查后重试'),
),
)),
);
}
}
================================================
FILE: lib/common/common_snakeBar.dart
================================================
import 'package:flutter/material.dart';
class CommonSnakeBar{
static buildSnakeBar(BuildContext context,String str) {
final snackBar = new SnackBar(content: new Text(str));
Scaffold.of(context).showSnackBar(snackBar);
}
//如果弹不出请用这个
static buildSnakeBarByKey(final GlobalKey key,BuildContext context,String str) {
final snackBar = new SnackBar(content: new Text(str));
key.currentState.showSnackBar(snackBar);
}
}
================================================
FILE: lib/common/constant.dart
================================================
class Constant {
static const String baseUrl="https://news-at.zhihu.com/api/4/";
//宽高常量
static const double bannerHeight = 200.0;
static const double normalItemHeight = 100.0;
static const double dateTimeItemHeight = 40.0;
//字符串常量
static const String todayHot = '今日热点';
static const String themeTitle = '专题';
static const String storyTitle = '详情';
static const String tips = '本页应该由banner+html组成,由于Flutter对Html支持的问题,以及暂时没找到好的解决方案,暂缓该功能,怕忘记了,故保留该页面,作为优化\n请点击下面链接跳转到webview查看本文';
//SharedPreferences key
static const String spThemeCache = 'sp_theme_cache';
static const String spThemeCacheHours = 'sp_theme_cache_hours';
//time
static const int oneDay = 24 * 60 * 60;
//def headimg
static const String defHeadimg = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRb0V6OlKdbsP-45kue1bb3QsVF2vV6Ncm_Nw3OzSwdTmWstfzY';
//comment pop
static const String popReply = '回复';
static const String popAgree = '赞同';
static const String popCopy = '复制';
static const String popReport = '举报';
//def bg
static const String defBg ='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1529724791909&di=02909c10c9d8ed553d070522f4c11b44&imgtype=0&src=http%3A%2F%2Fimg17.3lian.com%2Fd%2Ffile%2F201702%2F14%2Fbf13787b4f6a5c346c07b8f10466a682.jpg';
}
================================================
FILE: lib/exampleDemo/fadeAppTest.dart
================================================
import 'package:flutter/material.dart';
class FadeAppTest extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Fade Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyFadeTest(title: 'Fade Demo'),
);
}
}
class MyFadeTest extends StatefulWidget {
MyFadeTest({Key key, this.title}) : super(key: key);
final String title;
@override
_MyFadeTest createState() => new _MyFadeTest();
}
class _MyFadeTest extends State with TickerProviderStateMixin {
AnimationController controller;
CurvedAnimation curve;
@override
void initState() {
controller = new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
curve = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Container(
child: new FadeTransition(
opacity: curve,
child: new FlutterLogo(
size: 100.0,
)))),
floatingActionButton: new FloatingActionButton(
tooltip: 'Fade',
child: new Icon(Icons.brush),
onPressed: () {
controller.forward();
},
),
);
}
}
================================================
FILE: lib/exampleDemo/isolateApp.dart
================================================
import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class IsolateApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Sample App',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => new _SampleAppPageState();
}
class _SampleAppPageState extends State {
List widgets = [];
@override
void initState() {
super.initState();
loadData();
}
showLoadingDialog() {
if (widgets.length == 0) {
return true;
}
return false;
}
getBody() {
if (showLoadingDialog()) {
return getProgressDialog();
} else {
return getListView();
}
}
getProgressDialog() {
return new Center(child: new CircularProgressIndicator());
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Sample App"),
),
body: getBody());
}
ListView getListView() => new ListView.builder(
itemCount: widgets.length,
itemBuilder: (BuildContext context, int position) {
return getRow(position);
});
Widget getRow(int i) {
return new Padding(padding: new EdgeInsets.all(10.0), child: new Text("Row ${widgets[i]["title"]}"));
}
loadData() async {
ReceivePort receivePort = new ReceivePort();
await Isolate.spawn(dataLoader, receivePort.sendPort);
// The 'echo' isolate sends it's SendPort as the first message
SendPort sendPort = await receivePort.first;
List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts");
setState(() {
widgets = msg;
});
}
// the entry point for the isolate
static dataLoader(SendPort sendPort) async {
// Open the ReceivePort for incoming messages.
ReceivePort port = new ReceivePort();
// Notify any other isolates what port this isolate listens to.
sendPort.send(port.sendPort);
await for (var msg in port) {
String data = msg[0];
SendPort replyTo = msg[1];
String dataURL = data;
http.Response response = await http.get(dataURL);
// Lots of JSON to parse
// replyTo.send(JSON.decode(response.body));
}
}
Future sendReceive(SendPort port, msg) {
ReceivePort response = new ReceivePort();
port.send([msg, response.sendPort]);
return response.first;
}
}
================================================
FILE: lib/exampleDemo/layoutApp.dart
================================================
import 'package:flutter/material.dart';
class LayoutApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: MyHomePage(title: 'Strawberry Pavlova Recipe'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
@override
Widget build(BuildContext context) {
var titleText = Container(
padding: EdgeInsets.all(0.0),
child: Text(
'Strawberry Pavlova',
style: TextStyle(
fontWeight: FontWeight.w800,
letterSpacing: 0.5,
fontSize: 30.0,
),
),
);
var subTitle = Text(
'Pavlova is a meringue-based dessert named after the Russian ballerina Anna Pavlova. Pavlova features a crisp crust and soft, light inside, topped with fruit and whipped cream.',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Georgia',
fontSize: 25.0,
),
);
var ratings = Container(
padding: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
),
Text(
'170 Reviews',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 20.0,
),
),
],
),
);
var descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 18.0,
height: 2.0,
);
// DefaultTextStyle.merge allows you to create a default text
// style that is inherited by its child and all subsequent children.
var iconList = DefaultTextStyle.merge(
style: descTextStyle,
child: Container(
padding: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Icon(Icons.kitchen, color: Colors.green[500]),
Text('PREP:'),
Text('25 min'),
],
),
Column(
children: [
Icon(Icons.timer, color: Colors.green[500]),
Text('COOK:'),
Text('1 hr'),
],
),
Column(
children: [
Icon(Icons.restaurant, color: Colors.green[500]),
Text('FEEDS:'),
Text('4-6'),
],
),
],
),
),
);
var leftColumn = Container(
padding: EdgeInsets.fromLTRB(20.0, 30.0, 20.0, 20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
titleText,
subTitle,
ratings,
iconList,
],
),
);
var mainImage = Image.asset(
'lib/images/pavlova.jpg',
fit: BoxFit.fill,
);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Container(
margin: EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0),
height: 600.0,
child: Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
flex: 1,
child: Container(
width: 440.0,
child: leftColumn,
)),
Expanded(
flex: 1,
child: mainImage,
),
],
),
),
),
),
);
}
}
================================================
FILE: lib/exampleDemo/listItem.dart
================================================
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class ListItemApp extends StatelessWidget {
final List items;
ListItemApp({Key key, @required this.items}) : super(key: key);
@override
Widget build(BuildContext context) {
final title = 'Mixed List';
return new MaterialApp(
title: title,
home: new Scaffold(
appBar: new AppBar(
title: new Text(title),
),
body: new ListView.builder(
// Let the ListView know how many items it needs to build
itemCount: items.length,
// Provide a builder function. This is where the magic happens! We'll
// convert each item into a Widget based on the type of item it is.
itemBuilder: (context, index) {
final item = items[index];
if (item is HeadingItem) {
return new ListTile(
title: new Text(
item.heading,
style: Theme.of(context).textTheme.headline,
),
);
} else if (item is MessageItem) {
return new ListTile(
title: new Text(item.sender),
subtitle: new Text(item.body),
);
}
},
),
),
);
}
}
// The base class for the different types of items the List can contain
abstract class ListItem {}
// A ListItem that contains data to display a heading
class HeadingItem implements ListItem {
final String heading;
HeadingItem(this.heading);
}
// A ListItem that contains data to display a message
class MessageItem implements ListItem {
final String sender;
final String body;
MessageItem(this.sender, this.body);
}
================================================
FILE: lib/exampleDemo/navigatorTest.dart
================================================
import 'package:flutter/material.dart';
class NavigatorTest extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Fade Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyFadeTest(title: 'Navigator Demo'),
routes: {
'/a': (BuildContext context) => new MyFadeTest(title: 'page A'),
},
);
}
}
class MyFadeTest extends StatefulWidget {
MyFadeTest({Key key, this.title}) : super(key: key);
final String title;
@override
_MyFadeTest createState() => new _MyFadeTest();
}
class _MyFadeTest extends State with TickerProviderStateMixin {
AnimationController controller;
CurvedAnimation curve;
@override
void initState() {
controller = new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
curve = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
),
floatingActionButton: new FloatingActionButton(
tooltip: 'Fade',
child: new Icon(Icons.arrow_forward_ios),
onPressed: () {
Navigator.of(context).pushNamed('/a');
},
),
);
}
}
================================================
FILE: lib/exampleDemo/platformChannel.dart
================================================
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class ChannelApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'PlatformChannel App',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new PlatformChannel(),
);
}
}
class PlatformChannel extends StatefulWidget {
@override
_PlatformChannelState createState() => new _PlatformChannelState();
}
class _PlatformChannelState extends State {
static const MethodChannel methodChannel =
const MethodChannel('samples.flutter.io/battery');
static const MethodChannel gotoChannel =
const MethodChannel('samples.flutter.io/intent');
static const EventChannel eventChannel =
const EventChannel('samples.flutter.io/charging');
String _batteryLevel = 'Battery level: unknown.';
String _chargingStatus = 'Battery status: unknown.';
Future _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await methodChannel.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level: $result%.';
} on PlatformException {
batteryLevel = 'Failed to get battery level.';
}
setState(() {
_batteryLevel = batteryLevel;
});
}
Future _gotoActivity() async {
gotoChannel.invokeMethod('gotoActivity');
}
@override
void initState() {
super.initState();
eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
_getBatteryLevel();
}
void _onEvent(Object event) {
setState(() {
_chargingStatus =
"Battery status: ${event == 'charging' ? '' : 'dis'}charging.";
});
}
void _onError(Object error) {
setState(() {
_chargingStatus = 'Battery status: unknown.';
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('PlatformChannel App'),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Text(_batteryLevel, key: const Key('Battery level label')),
new Padding(
padding: const EdgeInsets.all(16.0),
child: new RaisedButton(
child: const Text('Refresh'),
onPressed: _getBatteryLevel,
),
),
],
),
new Text(_chargingStatus),
],
),
),
floatingActionButton: new FloatingActionButton(
tooltip: 'Fade',
child: new Icon(Icons.arrow_forward_ios),
onPressed: () {
_gotoActivity();
},
),
);
}
}
================================================
FILE: lib/exampleDemo/sampleApp1.dart
================================================
import 'package:flutter/material.dart';
class SampleApp1 extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Sample App',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => new _SampleAppPageState();
}
class _SampleAppPageState extends State {
// Default placeholder text
String textToShow = "I Like Flutter";
void _updateText() {
setState(() {
// update the text
textToShow = "Flutter is Awesome!";
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Sample App"),
),
body: new Center(child: new Text(textToShow)),
floatingActionButton: new FloatingActionButton(
onPressed: _updateText,
tooltip: 'Update Text',
child: new Icon(Icons.update),
),
);
}
}
================================================
FILE: lib/exampleDemo/sampleApp2.dart
================================================
import 'package:flutter/material.dart';
class SampleApp2 extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Sample App',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => new _SampleAppPageState();
}
class _SampleAppPageState extends State {
// Default value for toggle
bool toggle = true;
void _toggle() {
setState(() {
toggle = !toggle;
});
}
_getToggleChild() {
if (toggle) {
return new Text('Toggle One');
} else {
return new MaterialButton(onPressed: () {}, child: new Text('Toggle Two'));
}
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Sample App"),
),
body: new Center(
child: _getToggleChild(),
),
floatingActionButton: new FloatingActionButton(
onPressed: _toggle,
tooltip: 'Update Text',
child: new Icon(Icons.update),
),
);
}
}
================================================
FILE: lib/exampleDemo/showLoading.dart
================================================
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class ShowLoading extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Sample App',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => new _SampleAppPageState();
}
class _SampleAppPageState extends State {
List widgets = [];
@override
void initState() {
super.initState();
loadData();
}
showLoadingDialog() {
if (widgets.length == 0) {
return true;
}
return false;
}
getBody() {
if (showLoadingDialog()) {
return getProgressDialog();
} else {
return getListView();
}
}
getProgressDialog() {
return new Center(child: new CircularProgressIndicator());
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Sample App"),
),
body: getBody());
}
ListView getListView() => new ListView.builder(
itemCount: widgets.length,
itemBuilder: (BuildContext context, int position) {
return getRow(position);
});
Widget getRow(int i) {
return new Padding(padding: new EdgeInsets.all(10.0), child: new Text("Row ${widgets[i]["title"]}"));
}
loadData() async {
String dataURL = "https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(dataURL);
setState(() {
widgets = JSON.decode(response.body);
});
}
}
================================================
FILE: lib/exampleDemo/startApp.dart
================================================
// Step 7 (Final): Change the app's theme
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
class StartApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//MaterialApp widget本身是一个 widget 的 StatelessWidget 类
//在 Flutter 中,大多数时候一切都可以看作 widget , 包括 alignment,padding 和 layout
return new MaterialApp(
//这个不是标题栏title
title: 'Startup Name Generator',
//主题颜色
theme: new ThemeData(
primaryColor: Colors.black,
),
//StatelessWidget嵌套了一个StatefulWidget
home: new RandomWords(),
);
}
}
class RandomWords extends StatefulWidget {
//只需要实现一个方法,返回一个State
@override
createState() => new RandomWordsState();
}
class RandomWordsState extends State {
//保存建议的单词对
//final关键字让变量不能被再次赋值
//在Dart语言中使用下划线前缀标识符,会强制其变成私有的
final _suggestions = [];
//存储用户收藏的单词对
final _saved = new Set();
//自定义字体大小
final _biggerFont = const TextStyle(fontSize: 18.0);
@override
void initState() {
//重写initState,以完成仅需要执行一次的工作
}
//将 Widget build(BuildContext context)方法放在State上而不是StatefulWidget上是为了在继承StatefulWidget时能更加灵活
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Startup Name Generator111111111'),
//右上角事件,进行页面跳转
actions: [
new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved)
],
),
body: _buildSuggestions(),
);
}
//构建显示建议单词对的ListView,当不知道要返回的组件属于什么类型,都可以定义为Widget
Widget _buildSuggestions() {
return new ListView.builder(
padding: const EdgeInsets.all(16.0),
// 对于每个建议的单词对都会调用一次itemBuilder,然后将单词对添加到ListTile行中
//不指定itemCount时,是一个无限长度的列表
itemBuilder: (context, i) {
// 在奇数行,该行添加一个分割线widget,来分隔相邻的词对。
if (i.isOdd) return new Divider();
// 在偶数行,该函数会为单词对添加一个ListTile row.
// 语法 "i ~/ 2" 表示i除以2,但返回值是整形(向下取整),比如i为:1, 2, 3, 4, 5
// 时,结果为0, 1, 1, 2, 2, 这可以计算出ListView中减去分隔线后的实际单词对数量
final index = i ~/ 2;
// 如果是建议列表中最后一个单词对
if (index >= _suggestions.length) {
// ...接着再生成10个单词对,然后添加到建议列表
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
},
);
}
Widget _buildRow(WordPair pair) {
final alreadySaved = _saved.contains(pair);
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: new Icon(
alreadySaved ? Icons.album : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
//在 _buildRow中让心形❤图标变得可以点击。如果单词条目已经添加到收藏夹中,
// 再次点击它将其从收藏夹中删除。当心形❤图标被点击时,函数调用setState()通知框架状态已经改变。
//只要添加了onTap属性,在MD主题下会有水波纹点击效果
onTap: () {
setState(
() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
},
);
},
);
}
void _pushSaved() {
//当用户点击导航栏中的列表图标时,建立一个路由并将其推入到导航管理器栈中。此操作会切换页面以显示新路由。
Navigator.of(context).push(
new MaterialPageRoute(
builder: (context) {
final tiles = _saved.map(
(pair) {
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final divided = ListTile
.divideTiles(
context: context,
tiles: tiles,
)
.toList();
return new Scaffold(
appBar: new AppBar(
title: new Text('Saved Suggestions'),
),
body: new ListView(children: divided),
);
},
),
);
}
}
================================================
FILE: lib/generated/i18n.dart
================================================
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: camel_case_types
// ignore_for_file: prefer_single_quotes
//This file is automatically generated. DO NOT EDIT, all your changes would be lost.
class S implements WidgetsLocalizations {
const S();
static const GeneratedLocalizationsDelegate delegate =
GeneratedLocalizationsDelegate();
static S of(BuildContext context) => Localizations.of(context, S);
@override
TextDirection get textDirection => TextDirection.ltr;
}
class en extends S {
const en();
}
class GeneratedLocalizationsDelegate extends LocalizationsDelegate {
const GeneratedLocalizationsDelegate();
List get supportedLocales {
return const [
Locale("en", ""),
];
}
LocaleListResolutionCallback listResolution({Locale fallback}) {
return (List locales, Iterable supported) {
if (locales == null || locales.isEmpty) {
return fallback ?? supported.first;
} else {
return _resolve(locales.first, fallback, supported);
}
};
}
LocaleResolutionCallback resolution({Locale fallback}) {
return (Locale locale, Iterable supported) {
return _resolve(locale, fallback, supported);
};
}
Locale _resolve(Locale locale, Locale fallback, Iterable supported) {
if (locale == null || !isSupported(locale)) {
return fallback ?? supported.first;
}
final Locale languageLocale = Locale(locale.languageCode, "");
if (supported.contains(locale)) {
return locale;
} else if (supported.contains(languageLocale)) {
return languageLocale;
} else {
final Locale fallbackLocale = fallback ?? supported.first;
return fallbackLocale;
}
}
@override
Future load(Locale locale) {
final String lang = getLang(locale);
if (lang != null) {
switch (lang) {
case "en":
return SynchronousFuture(const en());
default:
// NO-OP.
}
}
return SynchronousFuture(const S());
}
@override
bool isSupported(Locale locale) =>
locale != null && supportedLocales.contains(locale);
@override
bool shouldReload(GeneratedLocalizationsDelegate old) => false;
}
String getLang(Locale l) => l == null
? null
: l.countryCode != null && l.countryCode.isEmpty
? l.languageCode
: l.toString();
================================================
FILE: lib/main.dart
================================================
import 'package:flutter/material.dart';
import 'package:zhihudaily/exampleDemo/sampleApp2.dart';
import 'package:zhihudaily/exampleDemo/sampleApp1.dart';
import 'package:zhihudaily/exampleDemo/fadeAppTest.dart';
import 'package:zhihudaily/exampleDemo/navigatorTest.dart';
import 'package:zhihudaily/exampleDemo/platformChannel.dart';
import 'package:zhihudaily/zhihu/zhihudaily.dart';
import 'package:zhihudaily/exampleDemo/showLoading.dart';
import 'package:zhihudaily/exampleDemo/isolateApp.dart';
import 'package:zhihudaily/exampleDemo/listItem.dart';
import 'package:zhihudaily/exampleDemo/layoutApp.dart';
import 'package:zhihudaily/exampleDemo/startApp.dart';
import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;
//void main() => runApp(new LayoutApp());
void main() {
debugPaintSizeEnabled = true;
runApp(StartApp());
}
================================================
FILE: lib/model/ThemeModel.dart
================================================
class ThemeModel {
final String thumbnail;
final String description;
final int id;
final String name;
final int color;
const ThemeModel(
{this.thumbnail, this.description, this.id, this.name, this.color});
ThemeModel.fromJson(Map json)
: thumbnail = json['thumbnail'],
description = json['description'],
id = json['id'],
color = json['color'],
name = json['name'];
}
================================================
FILE: lib/model/base_model.dart
================================================
class BaseModel{
final int code;
final String errorMsg;
final T data;
const BaseModel({this.code, this.errorMsg, this.data});
}
================================================
FILE: lib/model/homePageModel.dart
================================================
class HomePageModel {
static const int itemTypeNormal = 0;
static const int itemTypeBanner = 1;
final List images;
final int type;
final int id;
final String title;
int itemType = itemTypeNormal;
HomePageModel({this.images, this.type, this.id, this.title});
setItemType(int type) {
itemType = type;
}
HomePageModel.fromJson(Map json)
: images = json['images'],
type = json['type'],
id = json['id'],
title = json['title'];
}
class TopStoriesModel {
final String image;
final int type;
final int id;
final String title;
const TopStoriesModel({this.image, this.type, this.id, this.title});
TopStoriesModel.fromJson(Map json)
: image = json['image'],
type = json['type'],
id = json['id'],
title = json['title'];
}
================================================
FILE: lib/model/theme_list_model.dart
================================================
class ThemeListModel {
final String description;
final String name;
final String background;
final String image;
final List stories;
final List editors;
const ThemeListModel(
{this.description,
this.name,
this.background,
this.image,
this.stories,
this.editors});
}
class ThemeListStoriesModel {
static const int itemTypeNormal = 0;
static const int itemTypeBanner = 1;
static const int itemTypeEditor = 2;
final List images;
final int type;
final int id;
final String title;
int itemType = itemTypeNormal;
setItemType(int type) {
itemType = type;
}
ThemeListStoriesModel({this.images, this.type, this.id, this.title});
ThemeListStoriesModel.fromJson(Map json)
: images = json['images'],
type = json['type'],
id = json['id'],
title = json['title'];
}
class ThemeListEditorsModel {
final String url;
final String bio;
final String avatar;
final int id;
final String name;
const ThemeListEditorsModel(
{this.url, this.bio, this.avatar, this.id, this.name});
ThemeListEditorsModel.fromJson(Map json)
: url = json['url'],
bio = json['bio'],
id = json['id'],
name = json['name'],
avatar = json['avatar'];
}
================================================
FILE: lib/net/apis.dart
================================================
class Apis {
//首页数据
static const String latest = "news/latest";
//首页数据 跟日期 example:news/before/20131119
static const String before ="news/before/" ;
//详情 跟id example:news/3892357
static const String detail = "news/";
//评论数 点赞数 跟id example:news/3892357
static const String story_extra = "story-extra/";
//长评论详情 跟id example:story/8997528/long-comments
static const String long_comment = "story/id/long-comments";
//短评论详情 跟id
static const String short_comment = "story/id/short-comments";
//查看主题日报分类列表
static const String themes = "themes";
//查看某个主题的列表 跟id example:themes/13
static const String themes_list = "theme/";
//查看某个主题的列表 跟tid story_id 是每次请求的最后一条 example:theme/13/before/4731018
static const String themes_list_before = "/before/";
}
================================================
FILE: lib/net/dio_factory.dart
================================================
import 'package:dio/dio.dart';
//总觉得怪怪的,但是打印出来确实是只有一个dio对象。。
class DioFactory {
static Dio _dio;
static DioFactory _instance;
static DioFactory getInstance() {
if (_instance == null) {
_instance = new DioFactory._();
_instance._init();
}
return _instance;
}
DioFactory._();
_init(){
_dio = new Dio();
}
getDio() {
return _dio;
}
}
//测试是否是单例
void main() {
print(DioFactory.getInstance().getDio() == DioFactory.getInstance().getDio());
}
================================================
FILE: lib/presenter/mvp.dart
================================================
abstract class IView {
setPresenter(T presenter);
}
abstract class IPresenter{
init();
}
================================================
FILE: lib/presenter/theme_list_presenter.dart
================================================
import 'package:zhihudaily/model/base_model.dart';
import 'package:zhihudaily/model/theme_list_model.dart';
import 'package:zhihudaily/presenter/mvp.dart';
abstract class ThemeListPresenter implements IPresenter {
loadThemeList(String themeId, String lastId);
}
abstract class ThemeListView implements IView {
void onLoadThemeListSuc(BaseModel model);
void onLoadThemeListFail();
}
================================================
FILE: lib/presenter/theme_list_presenter_impl.dart
================================================
import 'package:zhihudaily/presenter/theme_list_presenter.dart';
import 'package:zhihudaily/repository/theme_list_repository.dart';
import 'package:zhihudaily/repository/theme_list_repository_impl.dart';
class ThemeListPresenterImpl implements ThemeListPresenter {
ThemeListView _view;
ThemeListRepository _repository;
ThemeListPresenterImpl(this._view) {
_view.setPresenter(this);
}
@override
loadThemeList(String themeId, String lastId) {
assert(_view != null);
_repository.loadThemeList(themeId,lastId).then((data) {
_view.onLoadThemeListSuc(data);
}).catchError((error) {
_view.onLoadThemeListFail();
});
}
@override
init() {
_repository = new ThemeListRepositoryImpl();
}
}
================================================
FILE: lib/repository/theme_list_repository.dart
================================================
import 'dart:async';
import 'package:zhihudaily/model/theme_list_model.dart';
import 'package:zhihudaily/model/base_model.dart';
abstract class ThemeListRepository {
Future> loadThemeList(String themeId,String lastId);
}
================================================
FILE: lib/repository/theme_list_repository_impl.dart
================================================
import 'dart:async';
import 'dart:io';
import 'package:zhihudaily/common/constant.dart';
import 'package:zhihudaily/model/base_model.dart';
import 'package:zhihudaily/model/theme_list_model.dart';
import 'package:zhihudaily/repository/theme_list_repository.dart';
import 'package:zhihudaily/net/apis.dart';
import 'package:zhihudaily/net/dio_factory.dart';
import 'package:dio/dio.dart';
class ThemeListRepositoryImpl implements ThemeListRepository {
@override
Future> loadThemeList(
String themeId, String lastId) {
return _getThemeList(themeId, lastId);
}
}
Future> _getThemeList(
String themeId, String lastId) async {
Dio dio =DioFactory.getInstance().getDio();
String url;
if (null == lastId) {
url = Constant.baseUrl + Apis.themes_list + themeId;
} else {
url = Constant.baseUrl +
Apis.themes_list +
themeId +
Apis.themes_list_before +
lastId;
}
print(url);
int code;
String errorMsg;
ThemeListModel themeListModel;
BaseModel model;
try {
Response response = await dio.get(url);
code = response.statusCode;
if (response.statusCode == HttpStatus.OK) {
String description = response.data['description'];
String name = response.data['name'];
String image = response.data['image'];
String background = response.data['background'];
List stories = response.data['stories'];
List editors = response.data['editors'];
List editorList;
List storiesList = stories.map((model) {
return new ThemeListStoriesModel.fromJson(model);
}).toList();
//topStories根据接口只有当天有,过去时间的topStories为空
if (editors != null && editors.isNotEmpty) {
editorList = editors.map((model) {
return new ThemeListEditorsModel.fromJson(model);
}).toList();
}
themeListModel = new ThemeListModel(
description: description,
background: background,
name: name,
image: image,
stories: storiesList,
editors: editorList);
} else {
errorMsg = '服务器异常';
}
} catch (exception) {
errorMsg = '您的网络似乎出了什么问题';
} finally {
model = new BaseModel(code: code, errorMsg: errorMsg, data: themeListModel);
}
return model;
}
================================================
FILE: lib/utils/RouterUtils.dart
================================================
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:http/http.dart' as http;
import 'package:zhihudaily/zhihu/themeListPage.dart';
import 'package:zhihudaily/zhihu/zhihudaily.dart';
class RouterUtils {
static routeToMain(BuildContext context) {
Navigator.of(context).push(new PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _, __) {
return new ZhihuDailyApp();
},
transitionsBuilder: (_, Animation animation, __, Widget child) {
return new FadeTransition(
opacity: animation,
child: new FadeTransition(
opacity:
new Tween(begin: 0.5, end: 1.0).animate(animation),
child: child,
),
);
}));
}
static startWebView(BuildContext context, int id) async {
String dataURL = "https://news-at.zhihu.com/api/4/news/$id";
http.Response response = await http.get(dataURL);
Navigator.of(context).push(new PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _, __) {
return new WebviewScaffold(
url: json.decode(response.body)["share_url"],
appBar: new AppBar(
title: new Text(json.decode(response.body)["title"]),
),
withZoom: true,
withLocalStorage: true,
);
},
transitionsBuilder: (_, Animation animation, __, Widget child) {
return new FadeTransition(
opacity: animation,
child: new FadeTransition(
opacity:
new Tween(begin: 0.5, end: 1.0).animate(animation),
child: child,
),
);
}));
}
static route2ThemeList(BuildContext context, String themeId) {
Navigator.of(context).push(new PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _, __) {
return new ThemeListPage(themeId);
},
transitionsBuilder: (_, Animation animation, __, Widget child) {
return new FadeTransition(
opacity: animation,
child: new FadeTransition(
opacity:
new Tween(begin: 0.5, end: 1.0).animate(animation),
child: child,
),
);
}));
}
}
================================================
FILE: lib/widget/drawerContent.dart
================================================
import 'package:flutter/material.dart';
import 'package:zhihudaily/model/ThemeModel.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:zhihudaily/common/common_loading_dialog.dart';
import 'package:zhihudaily/utils/RouterUtils.dart';
class DrawerBody extends StatefulWidget {
@override
DrawerState createState() => new DrawerState();
}
class DrawerState extends State {
List themes = [];
@override
void initState() {
super.initState();
loadData();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.white,
body: buildBody(),
);
}
Widget buildBody() {
if (null != themes && themes.isNotEmpty) {
return new Column(
children: [
buildDrawer(),
buildItem(),
new Divider(height: 1.0),
buildList()
],
);
} else {
return ProgressDialog.buildProgressDialog();
}
}
Widget buildDrawer() {
return new UserAccountsDrawerHeader(
onDetailsPressed: () {},
accountName: new Text('MelonRice'),
accountEmail: new Text('rice@bmqb.com'),
currentAccountPicture: new CircleAvatar(
backgroundImage: new NetworkImage(
'https://wx3.sinaimg.cn/mw690/44485fa4gy1ft4q8gk1vmj205k05kjsn.jpg'),
),
);
}
Widget buildItem() {
return new InkWell(
onTap: () {
Navigator.of(context).pop();
RouterUtils.routeToMain(context);
},
child: new Padding(
padding: const EdgeInsets.only(left: 10.0),
child: new Row(
children: [
new Icon(Icons.home, color: Colors.blue, size: 36.0),
new Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: new Text('首页',
style:
new TextStyle(color: Colors.blue, fontSize: 18.0))),
],
)),
);
}
Widget buildList() {
return new MediaQuery.removePadding(
context: context,
// DrawerHeader consumes top MediaQuery padding.
removeTop: true,
child: new Expanded(
child: new ListView(
children: [
new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: themes.map((ThemeModel model) {
return buildOtherItem(model);
}).toList(),
),
],
)),
);
}
Widget buildOtherItem(ThemeModel model) {
return new InkWell(
onTap: () {
Navigator.of(context).pop();
RouterUtils.route2ThemeList(context, '${model.id}');
},
child: new ListTile(
trailing: new Icon(Icons.add, color: Colors.grey[300]),
title: new Text('${model.name}',
style: new TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey[700],
fontSize: 16.0)),
),
);
}
loadData() async {
String dataURL = "https://news-at.zhihu.com/api/4/themes";
http.Response response = await http.get(dataURL);
List others = json.decode(response.body)["others"];
themes = others.map((model) {
return new ThemeModel.fromJson(model);
}).toList();
setState(() {});
}
}
class DrawerPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.white,
body: new DrawerBody(),
);
}
}
================================================
FILE: lib/widget/homeBanner.dart
================================================
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:zhihudaily/model/homePageModel.dart';
import 'package:zhihudaily/utils/RouterUtils.dart';
class HomeBanner extends StatefulWidget {
final List bannerList;
HomeBanner(this.bannerList);
@override
State createState() => new HomeBannerState();
}
class HomeBannerState extends State {
List _indicators = [];
int _curIndicatorsIndex = 0;
Timer timer;
PageController pageController = new PageController(initialPage: 0);
@override
void initState() {
super.initState();
timer = new Timer.periodic(new Duration(seconds: 3), (timer) {
pageController.animateToPage(_curIndicatorsIndex == _indicators.length - 1 ? 0 : _curIndicatorsIndex + 1,
duration: new Duration(milliseconds: 500), curve: Curves.linear);
});
}
@override
void dispose() {
super.dispose();
timer.cancel();
}
@override
Widget build(BuildContext context) {
return buildBanner();
}
Widget buildBanner() {
return new Container(
height: 220.0,
child: new Stack(
children: [
buildPagerView(),
buildIndicators(),
],
),
);
}
Widget buildPagerView() {
return new PageView.builder(
controller: pageController,
itemBuilder: (BuildContext context, int index) {
return buildItem(context, index);
},
itemCount: widget.bannerList.length,
onPageChanged: (index) {
_changePage(index);
},
);
}
Widget buildItem(BuildContext context, int index) {
TopStoriesModel banner = widget.bannerList[index];
return new GestureDetector(
onTap: () {
RouterUtils.startWebView(context, banner.id);
},
child: new Image.network(
banner.image,
fit: BoxFit.fitWidth,
height: 200.0,
),
);
}
Widget buildIndicators() {
_initIndicators();
return new Align(
alignment: Alignment.bottomCenter,
child: new Container(
color: Colors.black38,
height: 60.0,
width: double.infinity,
child: new Column(
children: [
new Padding(
padding: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 0.0),
child: new Text(widget.bannerList[_curIndicatorsIndex].title,
maxLines: 1,
style: new TextStyle(color: Colors.white, fontSize: 16.0)),
),
new Padding(
padding: const EdgeInsets.fromLTRB(0.0, 16.0, 0.0, 0.0),
child: new SizedBox(
width: widget.bannerList.length * 12.0,
height: 6.0,
child: new Row(
children: _indicators,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
),
)
],
),
),
);
}
_initIndicators() {
_indicators.clear();
for (int i = 0; i < widget.bannerList.length; i++) {
_indicators.add(new CircleAvatar(
radius: 6.0,
backgroundColor: i == _curIndicatorsIndex ? Colors.white : Colors.grey,
));
}
}
_changePage(int index) {
_curIndicatorsIndex = index;
setState(() {});
}
}
================================================
FILE: lib/zhihu/storyItem.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:zhihudaily/model/homePageModel.dart';
class StoryItem extends StatelessWidget {
StoryItem({Key key, this.onTap, @required this.detail}) : super(key: key);
static const double height = 120.0;
final HomePageModel detail;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
theme.textTheme.headline.copyWith(color: Colors.white);
final TextStyle descriptionStyle = theme.textTheme.title;
return new SafeArea(
top: false,
bottom: false,
child: new Container(
padding: const EdgeInsets.all(0.0),
height: height,
child: new Card(
child: new InkWell(
onTap: onTap,
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// photo and title
new Expanded(
child: new Padding(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: new DefaultTextStyle(
softWrap: true,
overflow: TextOverflow.ellipsis,
style: descriptionStyle,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: new Text(
detail.title,
maxLines: 3,
style: descriptionStyle.copyWith(
fontSize: 16.0, color: Colors.black87),
),
),
],
),
),
),
),
new SizedBox(
width: 115.0,
child: new Padding(
padding: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 8.0),
child: new Stack(
children: [
new Positioned.fill(
child: new Container(
foregroundDecoration: new BoxDecoration(
image: new DecorationImage(
image: new NetworkImage(detail.images[0]),
fit: BoxFit.cover),
),
)),
],
),
),
),
],
),
)),
),
);
}
}
================================================
FILE: lib/zhihu/themeListPage.dart
================================================
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';
import 'package:zhihudaily/common/common_divider.dart';
import 'package:zhihudaily/common/common_snakeBar.dart';
import 'package:zhihudaily/common/constant.dart';
import 'package:zhihudaily/model/base_model.dart';
import 'package:zhihudaily/model/theme_list_model.dart';
import 'package:zhihudaily/presenter/theme_list_presenter.dart';
import 'package:zhihudaily/presenter/theme_list_presenter_impl.dart';
import 'package:zhihudaily/utils/RouterUtils.dart';
import 'package:zhihudaily/widget/drawerContent.dart';
class ThemeListPage extends StatefulWidget {
final String themeId;
ThemeListPage(this.themeId, {Key key}) : super(key: key);
@override
_ThemeListPageState createState() {
_ThemeListPageState view = new _ThemeListPageState();
ThemeListPresenter presenter = new ThemeListPresenterImpl(view);
presenter.init();
return view;
}
}
enum AppBarBehavior { normal, pinned, floating, snapping }
class _ThemeListPageState extends State
implements ThemeListView {
final GlobalKey _refreshIndicatorKey =
new GlobalKey();
// static final GlobalKey _scaffoldKey = new GlobalKey<
// ScaffoldState>();
final double _appBarHeight = 256.0;
AppBarBehavior _appBarBehavior = AppBarBehavior.pinned;
String _title = Constant.themeTitle;
ScrollController _scrollController;
ThemeListPresenter _themeListPresenter;
List _normalDatas = [];
List _editorDatas = [];
List _widgets = [];
String _barBg = Constant.defBg;
ThemeListModel _themeListModel;
bool _isSlideUp = false;
int _curStoryId;
void _scrollListener() {
//滑到最底部刷新
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_loadData();
}
}
Future _refreshData() {
_isSlideUp = false;
final Completer completer = new Completer();
_themeListPresenter.loadThemeList(widget.themeId, null);
completer.complete(null);
return completer.future;
}
Future _loadData() {
_isSlideUp = true;
final Completer completer = new Completer();
_themeListPresenter.loadThemeList(widget.themeId, '$_curStoryId');
setState(() {});
completer.complete(null);
return completer.future;
}
@override
void initState() {
super.initState();
_scrollController = new ScrollController()..addListener(_scrollListener);
_refreshData();
}
@override
void dispose() {
super.dispose();
_scrollController.removeListener(_scrollListener);
}
Widget _buildEditor() {
//横向控件的集合
List editors = [];
//主编
Widget lableWidget = new Padding(
padding: const EdgeInsets.only(right: 12.0),
child: new Text(
'主编',
style: new TextStyle(fontSize: 14.0),
),
);
editors.add(lableWidget);
//循环加入主编的头像
for (ThemeListEditorsModel model in _editorDatas) {
Widget headView = new InkWell(
onTap: () {
//todo
// RouterUtils.route2Web(context, model.name, model.url);
},
child: new Padding(
padding: const EdgeInsets.only(
left: 6.0, right: 6.0, top: 12.0, bottom: 12.0),
child: new CircleAvatar(
radius: 12.0,
backgroundImage: new NetworkImage(model.avatar),
)),
);
editors.add(headView);
}
//组装
return new Column(
children: [
new Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: new Row(
children: editors,
),
),
CommonDivider.buildDivider(),
],
);
}
Widget _buildNormalItem(ThemeListStoriesModel item) {
final List images = item.images;
final String title = item.title;
final int id = item.id;
bool hasImage = (null != images && images.isNotEmpty);
if (hasImage) {
return new InkWell(
onTap: () {
RouterUtils.startWebView(context, id);
},
child: new Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: new SizedBox(
height: Constant.normalItemHeight,
child: new Column(
children: [
new Row(
children: [
new Expanded(
child: new Text(
title,
style: new TextStyle(
fontSize: 16.0, fontWeight: FontWeight.w300),
),
),
new Padding(
padding: const EdgeInsets.all(8.0),
child: new SizedBox(
height: 80.0,
width: 80.0,
child: new Image.network(images[0]),
),
)
],
),
new Expanded(
child: new Align(
alignment: Alignment.bottomCenter,
child: CommonDivider.buildDivider(),
),
),
],
),
)));
} else {
return new InkWell(
onTap: () {
RouterUtils.startWebView(context, id);
},
child: new Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: new SizedBox(
height: Constant.normalItemHeight,
child: new Column(
children: [
new Row(
children: [
new Expanded(
child: new SizedBox(
height: Constant.normalItemHeight,
child: new Align(
alignment: Alignment.centerLeft,
child: new Text(
title,
style: new TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w300),
),
),
),
),
],
),
new Expanded(
child: new Align(
alignment: Alignment.bottomCenter,
child: CommonDivider.buildDivider(),
),
),
],
),
)));
}
}
Widget _buildNewItem(ThemeListStoriesModel item) {
Widget widget;
switch (item.itemType) {
case ThemeListStoriesModel.itemTypeEditor:
widget = _buildEditor();
break;
case ThemeListStoriesModel.itemTypeNormal:
widget = _buildNormalItem(item);
break;
}
return widget;
}
_refreshItems() {
for (ThemeListStoriesModel model in _normalDatas) {
_widgets.add(_buildNewItem(model));
}
setState(() {});
}
Widget _buildList(BuildContext context) {
var content = new CustomScrollView(
//没有铺满也可以滑动
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
slivers: [
new SliverAppBar(
expandedHeight: _appBarHeight,
pinned: _appBarBehavior == AppBarBehavior.pinned,
floating: _appBarBehavior == AppBarBehavior.floating ||
_appBarBehavior == AppBarBehavior.snapping,
snap: _appBarBehavior == AppBarBehavior.snapping,
flexibleSpace: new FlexibleSpaceBar(
//标题
title: Text('$_title'),
centerTitle: true,
//背景图
background: new FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: _barBg,
fit: BoxFit.fitHeight),
),
),
new SliverList(
delegate: new SliverChildListDelegate(
new List.generate(_normalDatas.length, (int i) {
return _buildNewItem(_normalDatas[i]);
})),
),
],
);
var _refreshIndicator = new RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: _refreshData,
child: content,
);
return _refreshIndicator;
}
@override
Widget build(BuildContext context) {
return new Scaffold(
// key: _scaffoldKey,
backgroundColor: Colors.white,
drawer: new Drawer(
child: new DrawerPage(),
),
body: _buildList(context),
);
}
@override
setPresenter(ThemeListPresenter presenter) {
_themeListPresenter = presenter;
}
@override
void onLoadThemeListFail() {
// TODO: implement onLoadThemeListFail
}
@override
void onLoadThemeListSuc(BaseModel model) {
if (!mounted) return; //异步处理,防止报错
if (model.code != HttpStatus.OK) {
CommonSnakeBar.buildSnakeBar(context, model.errorMsg);
return;
}
if (_isSlideUp) {
List normalList = model.data.stories;
_normalDatas.addAll(normalList);
} else {
_themeListModel = model.data;
List normalList = model.data.stories;
List editorList = _themeListModel.editors;
_themeListModel = model.data;
_barBg = _themeListModel.image;
_title = _themeListModel.name;
_normalDatas.clear();
_editorDatas.clear();
_normalDatas = normalList;
_editorDatas = editorList;
_curStoryId = _normalDatas[0].id;
if (null != _editorDatas && _editorDatas.isNotEmpty) {
ThemeListStoriesModel fakeItem = new ThemeListStoriesModel();
fakeItem.setItemType(ThemeListStoriesModel.itemTypeEditor);
_normalDatas.insert(0, fakeItem);
}
}
_refreshItems();
}
}
================================================
FILE: lib/zhihu/zhihudaily.dart
================================================
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:zhihudaily/model/homePageModel.dart';
import 'package:zhihudaily/utils/RouterUtils.dart';
import 'package:zhihudaily/widget/drawerContent.dart';
import 'package:zhihudaily/widget/homeBanner.dart';
import 'package:zhihudaily/zhihu/storyItem.dart';
class ZhihuDailyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: '知乎日报',
color: Colors.grey,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => new _SampleAppPageState();
}
class _SampleAppPageState extends State {
List homePageDataList = new List();
List topBannerModel;
@override
void initState() {
super.initState();
loadData();
}
Widget buildItem(BuildContext context, int position) {
Widget widget;
HomePageModel item = homePageDataList[position];
switch (item.itemType) {
case HomePageModel.itemTypeBanner:
widget = new HomeBanner(topBannerModel);
break;
case HomePageModel.itemTypeNormal:
widget = getItem(context, position);
break;
}
return widget;
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("知乎日报"),
),
body: new ListView.builder(
itemCount: homePageDataList.length,
itemBuilder: (BuildContext context, int position) {
return buildItem(context, position);
}),
drawer: new Drawer(
child: new DrawerPage(),
)
);
}
Widget getItem(BuildContext context, int i) {
return new Container(
margin: const EdgeInsets.only(left: 4.0, right: 4.0),
child: new StoryItem(
detail: homePageDataList[i],
onTap: () {
RouterUtils.startWebView(context, homePageDataList[i].id);
},
));
}
loadData() async {
String dataURL = "https://news-at.zhihu.com/api/4/news/latest";
http.Response response = await http.get(dataURL);
List banner = json.decode(response.body)["top_stories"];
List storise = json.decode(response.body)["stories"];
if (storise.isNotEmpty) {
homePageDataList = storise.map((model) {
return new HomePageModel.fromJson(model);
}).toList();
}
if (banner.isNotEmpty) {
topBannerModel = banner.map((model) {
return new TopStoriesModel.fromJson(model);
}).toList();
HomePageModel top = new HomePageModel();
top.setItemType(HomePageModel.itemTypeBanner);
homePageDataList.insert(0, top);
}
setState(() {});
}
}
================================================
FILE: pubspec.yaml
================================================
name: zhihudaily
description: A new Flutter project.
dependencies:
flutter:
sdk: flutter
flutter_webview_plugin: "^0.3.0+2"
transparent_image: "^0.1.0"
dio: "^1.0.9"
http: "^0.12.0"
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
english_words: ^3.1.5
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- lib/images/pavlova.jpg
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.io/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.io/custom-fonts/#from-packages
================================================
FILE: res/values/strings_en.arb
================================================
{}
================================================
FILE: test/widget_test.dart
================================================
// This is a basic Flutter widget test.
// To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
// provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to
// find child widgets in the widget tree, read text, and verify that the values of widget properties
// are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:zhihudaily/exampleDemo/sampleApp1.dart';
import 'package:zhihudaily/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(new SampleApp1());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}