├── .gitignore
├── .metadata
├── README.md
├── android
├── app
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── club
│ │ │ └── flutterchina
│ │ │ └── flutterinaction
│ │ │ └── MainActivity.java
│ │ └── res
│ │ ├── drawable
│ │ └── launch_background.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ └── values
│ │ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── fonts
└── iconfont.ttf
├── github_client_app
├── .gitignore
├── .metadata
├── README.md
├── android
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ │ └── club
│ │ │ │ │ └── flutteraction
│ │ │ │ │ └── github_client_app
│ │ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── fonts
│ └── iconfont.ttf
├── i10n-arb
│ ├── intl_messages.arb
│ └── intl_zh_CN.arb
├── imgs
│ ├── avatar-default.png
│ ├── logo_dark.png
│ └── logo_light.png
├── intl.sh
├── ios
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── flutter_export_environment.sh
│ ├── Podfile
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── Runner
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── main.m
├── jsons
│ ├── cacheConfig.json
│ ├── profile.json
│ ├── repo.json
│ └── user.json
├── lib
│ ├── common
│ │ ├── funs.dart
│ │ ├── git_api.dart
│ │ ├── global.dart
│ │ ├── icons.dart
│ │ ├── index.dart
│ │ └── net_cache.dart
│ ├── index.dart
│ ├── l10n
│ │ ├── localization_intl.dart
│ │ ├── messages_all.dart
│ │ ├── messages_messages.dart
│ │ └── messages_zh_CN.dart
│ ├── main.dart
│ ├── models
│ │ ├── cacheConfig.dart
│ │ ├── cacheConfig.g.dart
│ │ ├── index.dart
│ │ ├── profile.dart
│ │ ├── profile.g.dart
│ │ ├── repo.dart
│ │ ├── repo.g.dart
│ │ ├── user.dart
│ │ └── user.g.dart
│ ├── routes
│ │ ├── home_page.dart
│ │ ├── index.dart
│ │ ├── language.dart
│ │ ├── login.dart
│ │ └── theme_change.dart
│ ├── states
│ │ ├── index.dart
│ │ └── profile_change_notifier.dart
│ └── widgets
│ │ ├── index.dart
│ │ └── repo_item.dart
├── pubspec.yaml
└── test
│ └── widget_test.dart
├── home.png
├── img_des.txt
├── imgs
└── avatar.png
├── intl.sh
├── ios
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ ├── Flutter.podspec
│ ├── Release.xcconfig
│ └── flutter_export_environment.sh
├── Podfile
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Runner
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── main.m
├── l10n-arb
├── intl_messages.arb
└── intl_zh_CN.arb
├── lib
├── common.dart
├── event_bus.dart
├── http.dart
├── i10n
│ ├── _localization.dart
│ ├── localization_intl.dart
│ ├── messages_all.dart
│ ├── messages_messages.dart
│ └── messages_zh_CN.dart
├── main.dart
├── provider.dart
├── routes
│ ├── align.dart
│ ├── animated_switcher_counter.dart
│ ├── animated_widgets.dart
│ ├── animation_switcher.dart
│ ├── button.dart
│ ├── camera.dart
│ ├── clip.dart
│ ├── color.dart
│ ├── context.dart
│ ├── custom_paint.dart
│ ├── custom_ui_framework.dart
│ ├── decoratedbox.dart
│ ├── dialog.dart
│ ├── future_and_stream_builder.dart
│ ├── gradient_button.dart
│ ├── gradient_circular_progress.dart
│ ├── grow_transition.dart
│ ├── hero_animation.dart
│ ├── image_icon.dart
│ ├── image_internal.dart
│ ├── index.dart
│ ├── inheritedwidget.dart
│ ├── notification.dart
│ ├── padding.dart
│ ├── platform_view.dart
│ ├── pointer.dart
│ ├── progress.dart
│ ├── provider.dart
│ ├── router.dart
│ ├── row_column.dart
│ ├── scaffold.dart
│ ├── scale_animation.dart
│ ├── scale_animation_animatedbuilder.dart
│ ├── scale_animation_animatedwidget.dart
│ ├── size_constraints.dart
│ ├── stagger_animation.dart
│ ├── state.dart
│ ├── switch_checkbox.dart
│ ├── table.dart
│ ├── test.dart
│ ├── text.dart
│ ├── textfield.dart
│ ├── theme.dart
│ └── turn_box.dart
└── widgets
│ ├── gradient_button.dart
│ ├── gradient_circular_progress_indicator.dart
│ ├── index.dart
│ ├── page_scaffold.dart
│ └── turn_box.dart
├── pubspec.yaml
└── test
└── widget_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | /# Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .vscode/
21 |
22 | # Flutter/Dart/Pub related
23 | **/doc/api/
24 | .dart_tool/
25 | .flutter-plugins
26 | .packages
27 | .pub-cache/
28 | .pub/
29 | build/
30 |
31 | # Android related
32 | **/android/**/gradle-wrapper.jar
33 | **/android/.gradle
34 | **/android/captures/
35 | **/android/gradlew
36 | **/android/gradlew.bat
37 | **/android/local.properties
38 | **/android/**/GeneratedPluginRegistrant.java
39 |
40 | # iOS/XCode related
41 | **/ios/**/*.mode1v3
42 | **/ios/**/*.mode2v3
43 | **/ios/**/*.moved-aside
44 | **/ios/**/*.pbxuser
45 | **/ios/**/*.perspectivev3
46 | **/ios/**/*sync/
47 | **/ios/**/.sconsign.dblite
48 | **/ios/**/.tags*
49 | **/ios/**/.vagrant/
50 | **/ios/**/DerivedData/
51 | **/ios/**/Icon?
52 | **/ios/**/Pods/
53 | **/ios/**/.symlinks/
54 | **/ios/**/profile
55 | **/ios/**/xcuserdata
56 | **/ios/.generated/
57 | **/ios/Flutter/App.framework
58 | **/ios/Flutter/Flutter.framework
59 | **/ios/Flutter/Generated.xcconfig
60 | **/ios/Flutter/app.flx
61 | **/ios/Flutter/app.zip
62 | **/ios/Flutter/flutter_assets/
63 | **/ios/ServiceDefinitions.json
64 | **/ios/Runner/GeneratedPluginRegistrant.*
65 |
66 | # Exceptions to above rules.
67 | !**/ios/**/default.mode1v3
68 | !**/ios/**/default.mode2v3
69 | !**/ios/**/default.pbxuser
70 | !**/ios/**/default.perspectivev3
71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
72 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
8 | channel: beta
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 《Flutter实战》随书源码
2 |
3 | 本项目为[《Flutter实战》电子书](https://github.com/flutterchina/flutter-in-action)随书源码,本书实体书名待定。
4 |
5 | ## 说明
6 |
7 | 1. 示例文件列表可以参照main.dart。
8 | 2. 并不是《Flutter实战》所有示例都有源码。如有必要,欢迎读者补充其它示例(提PR).
9 | 3. ”实例篇“源码位于 "github_client_app"子目录下,需要用IDE单独打开
10 |
11 | ## 运行效果
12 |
13 | 
14 |
15 | ## 打赏
16 |
17 | 对我有帮助?请作者喝杯咖啡
18 |
19 | 
20 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 28
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
36 | applicationId "club.flutterchina.flutterinaction"
37 | minSdkVersion 21
38 | targetSdkVersion 28
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | testImplementation 'junit:junit:4.12'
59 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
61 | }
62 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
15 |
19 |
26 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/android/app/src/main/java/club/flutterchina/flutterinaction/MainActivity.java:
--------------------------------------------------------------------------------
1 | package club.flutterchina.flutterinaction;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GeneratedPluginRegistrant.registerWith(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.2.1'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/fonts/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/fonts/iconfont.ttf
--------------------------------------------------------------------------------
/github_client_app/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 |
32 | # Android related
33 | **/android/**/gradle-wrapper.jar
34 | **/android/.gradle
35 | **/android/captures/
36 | **/android/gradlew
37 | **/android/gradlew.bat
38 | **/android/local.properties
39 | **/android/**/GeneratedPluginRegistrant.java
40 |
41 | # iOS/XCode related
42 | **/ios/**/*.mode1v3
43 | **/ios/**/*.mode2v3
44 | **/ios/**/*.moved-aside
45 | **/ios/**/*.pbxuser
46 | **/ios/**/*.perspectivev3
47 | **/ios/**/*sync/
48 | **/ios/**/.sconsign.dblite
49 | **/ios/**/.tags*
50 | **/ios/**/.vagrant/
51 | **/ios/**/DerivedData/
52 | **/ios/**/Icon?
53 | **/ios/**/Pods/
54 | **/ios/**/.symlinks/
55 | **/ios/**/profile
56 | **/ios/**/xcuserdata
57 | **/ios/.generated/
58 | **/ios/Flutter/App.framework
59 | **/ios/Flutter/Flutter.framework
60 | **/ios/Flutter/Generated.xcconfig
61 | **/ios/Flutter/app.flx
62 | **/ios/Flutter/app.zip
63 | **/ios/Flutter/flutter_assets/
64 | **/ios/ServiceDefinitions.json
65 | **/ios/Runner/GeneratedPluginRegistrant.*
66 |
67 | # Exceptions to above rules.
68 | !**/ios/**/default.mode1v3
69 | !**/ios/**/default.mode2v3
70 | !**/ios/**/default.pbxuser
71 | !**/ios/**/default.perspectivev3
72 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
73 |
--------------------------------------------------------------------------------
/github_client_app/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 67237b960ceeb2bd3d3a646de126c883fabae6d5
8 | channel: master
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/github_client_app/README.md:
--------------------------------------------------------------------------------
1 | # github_client_app
2 |
3 | A Github client APP built with Flutter
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/github_client_app/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 28
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
36 | applicationId "club.flutteraction.github_client_app"
37 | minSdkVersion 16
38 | targetSdkVersion 28
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
42 | }
43 |
44 | buildTypes {
45 | release {
46 | // TODO: Add your own signing config for the release build.
47 | // Signing with the debug keys for now, so `flutter run --release` works.
48 | signingConfig signingConfigs.debug
49 | }
50 | }
51 | }
52 |
53 | flutter {
54 | source '../..'
55 | }
56 |
57 | dependencies {
58 | testImplementation 'junit:junit:4.12'
59 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
61 | }
62 |
--------------------------------------------------------------------------------
/github_client_app/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/github_client_app/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
13 |
20 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/github_client_app/android/app/src/main/java/club/flutteraction/github_client_app/MainActivity.java:
--------------------------------------------------------------------------------
1 | package club.flutteraction.github_client_app;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GeneratedPluginRegistrant.registerWith(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/github_client_app/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/github_client_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/github_client_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/github_client_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/github_client_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/github_client_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/github_client_app/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/github_client_app/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/github_client_app/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.2.1'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/github_client_app/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
3 | android.enableR8=true
4 |
--------------------------------------------------------------------------------
/github_client_app/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/github_client_app/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/github_client_app/fonts/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/fonts/iconfont.ttf
--------------------------------------------------------------------------------
/github_client_app/i10n-arb/intl_messages.arb:
--------------------------------------------------------------------------------
1 | {
2 | "@@last_modified": "2019-08-11T18:39:59.060353",
3 | "title": "Flutter APP",
4 | "@title": {
5 | "description": "Title for the Demo application",
6 | "type": "text",
7 | "placeholders": {}
8 | },
9 | "home": "Github",
10 | "@home": {
11 | "type": "text",
12 | "placeholders": {}
13 | },
14 | "language": "Language",
15 | "@language": {
16 | "type": "text",
17 | "placeholders": {}
18 | },
19 | "login": "Login",
20 | "@login": {
21 | "type": "text",
22 | "placeholders": {}
23 | },
24 | "auto": "Auto",
25 | "@auto": {
26 | "type": "text",
27 | "placeholders": {}
28 | },
29 | "setting": "Setting",
30 | "@setting": {
31 | "type": "text",
32 | "placeholders": {}
33 | },
34 | "theme": "Theme",
35 | "@theme": {
36 | "type": "text",
37 | "placeholders": {}
38 | },
39 | "noDescription": "No description yet !",
40 | "@noDescription": {
41 | "type": "text",
42 | "placeholders": {}
43 | },
44 | "userName": "User Name",
45 | "@userName": {
46 | "type": "text",
47 | "placeholders": {}
48 | },
49 | "userNameRequired": "User name required!",
50 | "@userNameRequired": {
51 | "type": "text",
52 | "placeholders": {}
53 | },
54 | "password": "Password",
55 | "@password": {
56 | "type": "text",
57 | "placeholders": {}
58 | },
59 | "passwordRequired": "Password required!",
60 | "@passwordRequired": {
61 | "type": "text",
62 | "placeholders": {}
63 | },
64 | "userNameOrPasswordWrong": "User name or password is not correct!",
65 | "@userNameOrPasswordWrong": {
66 | "type": "text",
67 | "placeholders": {}
68 | },
69 | "logout": "logout",
70 | "@logout": {
71 | "type": "text",
72 | "placeholders": {}
73 | },
74 | "logoutTip": "Are you sure you want to quit your current account?",
75 | "@logoutTip": {
76 | "type": "text",
77 | "placeholders": {}
78 | },
79 | "yes": "yes",
80 | "@yes": {
81 | "type": "text",
82 | "placeholders": {}
83 | },
84 | "cancel": "cancel",
85 | "@cancel": {
86 | "type": "text",
87 | "placeholders": {}
88 | }
89 | }
--------------------------------------------------------------------------------
/github_client_app/i10n-arb/intl_zh_CN.arb:
--------------------------------------------------------------------------------
1 | {
2 | "@@last_modified": "2019-04-30T15:02:44.753296",
3 | "title": "Github客户端",
4 | "@title": {
5 | "description": "Title for the Demo application",
6 | "type": "text",
7 | "placeholders": {}
8 | },
9 | "home": "Github客户端",
10 | "@home": {
11 | "type": "text",
12 | "placeholders": {}
13 | },
14 | "language": "语言",
15 | "@language": {
16 | "type": "text",
17 | "placeholders": {}
18 | },
19 | "login": "登录",
20 | "@login": {
21 | "type": "text",
22 | "placeholders": {}
23 | },
24 | "auto": "跟随系统",
25 | "@auto": {
26 | "type": "text",
27 | "placeholders": {}
28 | },
29 | "setting": "设置",
30 | "@setting": {
31 | "type": "text",
32 | "placeholders": {}
33 | },
34 | "theme": "换肤",
35 | "@theme": {
36 | "type": "text",
37 | "placeholders": {}
38 | },
39 | "noDescription": "暂无描述!",
40 | "@noDescription": {
41 | "type": "text",
42 | "placeholders": {}
43 | },
44 | "userName": "用户名",
45 | "@userName": {
46 | "type": "text",
47 | "placeholders": {}
48 | },
49 | "userNameRequired": "用户名不能为空",
50 | "@userNameRequired": {
51 | "type": "text",
52 | "placeholders": {}
53 | },
54 | "password": "密码",
55 | "@password": {
56 | "type": "text",
57 | "placeholders": {}
58 | },
59 | "passwordRequired": "密码不能为空",
60 | "@passwordRequired": {
61 | "type": "text",
62 | "placeholders": {}
63 | },
64 | "userNameOrPasswordWrong": "用户名或密码不正确",
65 | "@userNameOrPasswordWrong": {
66 | "type": "text",
67 | "placeholders": {}
68 | },
69 | "logout": "注销",
70 | "@logout": {
71 | "type": "text",
72 | "placeholders": {}
73 | },
74 | "logoutTip": "确定要退出当前账号吗?",
75 | "@logoutTip": {
76 | "type": "text",
77 | "placeholders": {}
78 | },
79 | "yes": "确定",
80 | "@yes": {
81 | "type": "text",
82 | "placeholders": {}
83 | },
84 | "cancel": "取消",
85 | "@cancel": {
86 | "type": "text",
87 | "placeholders": {}
88 | }
89 | }
--------------------------------------------------------------------------------
/github_client_app/imgs/avatar-default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/imgs/avatar-default.png
--------------------------------------------------------------------------------
/github_client_app/imgs/logo_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/imgs/logo_dark.png
--------------------------------------------------------------------------------
/github_client_app/imgs/logo_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/imgs/logo_light.png
--------------------------------------------------------------------------------
/github_client_app/intl.sh:
--------------------------------------------------------------------------------
1 | flutter pub pub run intl_translation:extract_to_arb --output-dir=l10n-arb lib/l10n/localization_intl.dart
2 | flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/l10n/localization_intl.dart l10n-arb/intl_*.arb
--------------------------------------------------------------------------------
/github_client_app/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/github_client_app/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/github_client_app/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/github_client_app/ios/Flutter/flutter_export_environment.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a generated file; do not edit or check into version control.
3 | export "FLUTTER_ROOT=/Users/duwen/Documents/flutter"
4 | export "FLUTTER_APPLICATION_PATH=/Users/duwen/Documents/code/flutter_in_action/github_client_app"
5 | export "FLUTTER_TARGET=/Users/duwen/Documents/code/flutter_in_action/github_client_app/lib/main.dart"
6 | export "FLUTTER_BUILD_DIR=build"
7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios"
8 | export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
9 | export "FLUTTER_FRAMEWORK_DIR=/Users/duwen/Documents/flutter/bin/cache/artifacts/engine/ios"
10 | export "FLUTTER_BUILD_NAME=1.0.0"
11 | export "FLUTTER_BUILD_NUMBER=1"
12 | export "TRACK_WIDGET_CREATION=true"
13 |
--------------------------------------------------------------------------------
/github_client_app/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def parse_KV_file(file, separator='=')
14 | file_abs_path = File.expand_path(file)
15 | if !File.exists? file_abs_path
16 | return [];
17 | end
18 | pods_ary = []
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) { |line|
21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22 | plugin = line.split(pattern=separator)
23 | if plugin.length == 2
24 | podname = plugin[0].strip()
25 | path = plugin[1].strip()
26 | podpath = File.expand_path("#{path}", file_abs_path)
27 | pods_ary.push({:name => podname, :path => podpath});
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | }
32 | return pods_ary
33 | end
34 |
35 | target 'Runner' do
36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
37 | # referring to absolute paths on developers' machines.
38 | system('rm -rf .symlinks')
39 | system('mkdir -p .symlinks/plugins')
40 |
41 | # Flutter Pods
42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
43 | if generated_xcode_build_settings.empty?
44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first."
45 | end
46 | generated_xcode_build_settings.map { |p|
47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
48 | symlink = File.join('.symlinks', 'flutter')
49 | File.symlink(File.dirname(p[:path]), symlink)
50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
51 | end
52 | }
53 |
54 | # Plugin Pods
55 | plugin_pods = parse_KV_file('../.flutter-plugins')
56 | plugin_pods.map { |p|
57 | symlink = File.join('.symlinks', 'plugins', p[:name])
58 | File.symlink(p[:path], symlink)
59 | pod p[:name], :path => File.join(symlink, 'ios')
60 | }
61 | end
62 |
63 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
64 | install! 'cocoapods', :disable_input_output_paths => true
65 |
66 | post_install do |installer|
67 | installer.pods_project.targets.each do |target|
68 | target.build_configurations.each do |config|
69 | config.build_settings['ENABLE_BITCODE'] = 'NO'
70 | end
71 | end
72 | end
73 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/github_client_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | github_client_app
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/github_client_app/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/github_client_app/jsons/cacheConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "enable":true,
3 | "maxAge":1000,
4 | "maxCount":100
5 | }
--------------------------------------------------------------------------------
/github_client_app/jsons/profile.json:
--------------------------------------------------------------------------------
1 | {
2 | "user":"$user",
3 | "token":"",
4 | "theme":5678,
5 | "cache":"$cacheConfig",
6 | "lastLogin":"",
7 | "locale":"en"
8 | }
--------------------------------------------------------------------------------
/github_client_app/jsons/repo.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": 1296269,
3 | "name": "Hello-World",
4 | "full_name": "octocat/Hello-World",
5 | "owner": "$user",
6 | "parent":"$repo",
7 | "private": false,
8 | "html_url": "https://github.com/octocat/Hello-World",
9 | "description": "This your first repo!",
10 | "fork": false,
11 | "homepage": "https://github.com",
12 | "language": "JavaScript",
13 | "forks_count": 9,
14 | "stargazers_count": 80,
15 | "watchers_count": 80,
16 | "size": 108,
17 | "default_branch": "master",
18 | "open_issues_count": 0,
19 | "topics": [
20 | "octocat",
21 | "atom",
22 | "electron",
23 | "API"
24 | ],
25 | "has_issues": true,
26 | "has_projects": true,
27 | "has_wiki": true,
28 | "has_pages": false,
29 | "has_downloads": true,
30 | "pushed_at": "2011-01-26T19:06:43Z",
31 | "created_at": "2011-01-26T19:01:12Z",
32 | "updated_at": "2011-01-26T19:14:43Z",
33 | "permissions": {
34 | "admin": false,
35 | "push": false,
36 | "pull": true
37 | },
38 | "subscribers_count": 42,
39 | "license": {
40 | "key": "mit",
41 | "name": "MIT License",
42 | "spdx_id": "MIT",
43 | "url": "https://api.github.com/licenses/mit",
44 | "node_id": "MDc6TGljZW5zZW1pdA=="
45 | }
46 | }
--------------------------------------------------------------------------------
/github_client_app/jsons/user.json:
--------------------------------------------------------------------------------
1 | {
2 | "login": "octocat",
3 | "id": 1,
4 | "avatar_url": "https://github.com/images/error/octocat_happy.gif",
5 | "url": "https://api.github.com/users/octocat",
6 | "type": "User",
7 | "site_admin": false,
8 | "name": "monalisa octocat",
9 | "company": "GitHub",
10 | "blog": "https://github.com/blog",
11 | "location": "San Francisco",
12 | "email": "octocat@github.com",
13 | "hireable": false,
14 | "bio": "There once was...",
15 | "public_repos": 2,
16 | "public_gists": 1,
17 | "followers": 20,
18 | "following": 0,
19 | "created_at": "2008-01-14T04:33:35Z",
20 | "updated_at": "2008-01-14T04:33:35Z",
21 | "total_private_repos": 100,
22 | "owned_private_repos": 100
23 | }
--------------------------------------------------------------------------------
/github_client_app/lib/common/funs.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:cached_network_image/cached_network_image.dart';
3 | import 'package:fluttertoast/fluttertoast.dart';
4 |
5 | Widget gmAvatar(String url, {
6 | double width = 30,
7 | double height,
8 | BoxFit fit,
9 | BorderRadius borderRadius,
10 | }) {
11 | var placeholder = Image.asset(
12 | "imgs/avatar-default.png", //头像默认值
13 | width: width,
14 | height: height
15 | );
16 | return ClipRRect(
17 | borderRadius: borderRadius ?? BorderRadius.circular(2),
18 | child: CachedNetworkImage(
19 | imageUrl: url,
20 | width: width,
21 | height: height,
22 | fit: fit,
23 | placeholder: (context, url) =>placeholder,
24 | errorWidget: (context, url, error) =>placeholder,
25 | ),
26 | );
27 | }
28 |
29 | void showToast(String text, {
30 | gravity: ToastGravity.CENTER,
31 | toastLength: Toast.LENGTH_SHORT,
32 | }) {
33 | Fluttertoast.showToast(
34 | msg: text,
35 | toastLength: Toast.LENGTH_SHORT,
36 | gravity: ToastGravity.BOTTOM,
37 | timeInSecForIos: 1,
38 | backgroundColor: Colors.grey[600],
39 | fontSize: 16.0,
40 | );
41 | }
42 |
43 | void showLoading(context, [String text]) {
44 | text = text ?? "Loading...";
45 | showDialog(
46 | barrierDismissible: false,
47 | context: context,
48 | builder: (context) {
49 | return Center(
50 | child: Container(
51 | decoration: BoxDecoration(
52 | color: Colors.white,
53 | borderRadius: BorderRadius.circular(3.0),
54 | boxShadow: [
55 | //阴影
56 | BoxShadow(
57 | color: Colors.black12,
58 | //offset: Offset(2.0,2.0),
59 | blurRadius: 10.0,
60 | )
61 | ]),
62 | padding: EdgeInsets.all(16),
63 | margin: EdgeInsets.all(16),
64 | constraints: BoxConstraints(minHeight: 120, minWidth: 180),
65 | child: Column(
66 | mainAxisSize: MainAxisSize.min,
67 | mainAxisAlignment: MainAxisAlignment.center,
68 | children: [
69 | SizedBox(
70 | height: 30,
71 | width: 30,
72 | child: CircularProgressIndicator(
73 | strokeWidth: 3,
74 | ),
75 | ),
76 | Padding(
77 | padding: const EdgeInsets.only(top: 20.0),
78 | child: Text(
79 | text,
80 | style: Theme
81 | .of(context)
82 | .textTheme
83 | .body2,
84 | ),
85 | ),
86 | ],
87 | ),
88 | ),
89 | );
90 | });
91 | }
--------------------------------------------------------------------------------
/github_client_app/lib/common/git_api.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:convert';
3 | import 'dart:io';
4 | import 'package:dio/adapter.dart';
5 | import 'package:dio/dio.dart';
6 | import 'package:flutter/material.dart';
7 | import '../index.dart';
8 |
9 | class Git {
10 | // 在网络请求过程中可能会需要使用当前的context信息,比如在请求失败时
11 | // 打开一个新路由,而打开新路由需要context信息。
12 | Git([this.context]) {
13 | _options = Options(extra: {"context": context});
14 | }
15 |
16 | BuildContext context;
17 | Options _options;
18 | static Dio dio = new Dio(BaseOptions(
19 | baseUrl: 'https://api.github.com/',
20 | headers: {
21 | HttpHeaders.acceptHeader: "application/vnd.github.squirrel-girl-preview,"
22 | "application/vnd.github.symmetra-preview+json",
23 | },
24 | ));
25 |
26 | static void init() {
27 | // 添加缓存插件
28 | dio.interceptors.add(Global.netCache);
29 | // 设置用户token(可能为null,代表未登录)
30 | dio.options.headers[HttpHeaders.authorizationHeader] = Global.profile.token;
31 |
32 | // 在调试模式下需要抓包调试,所以我们使用代理,并禁用HTTPS证书校验
33 | if (!Global.isRelease) {
34 | (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
35 | (client) {
36 | client.findProxy = (uri) {
37 | return "PROXY 10.95.249.53:8888";
38 | };
39 | //代理工具会提供一个抓包的自签名证书,会通不过证书校验,所以我们禁用证书校验
40 | client.badCertificateCallback =
41 | (X509Certificate cert, String host, int port) => true;
42 | };
43 | }
44 | }
45 |
46 | // 登录接口,登录成功后返回用户信息
47 | Future login(String login, String pwd) async {
48 | String basic = 'Basic ' + base64.encode(utf8.encode('$login:$pwd'));
49 | var r = await dio.get(
50 | "/users/$login",
51 | options: _options.merge(headers: {
52 | HttpHeaders.authorizationHeader: basic
53 | }, extra: {
54 | "noCache": true, //本接口禁用缓存
55 | }),
56 | );
57 | //登录成功后更新公共头(authorization),此后的所有请求都会带上用户身份信息
58 | dio.options.headers[HttpHeaders.authorizationHeader] = basic;
59 | //清空所有缓存
60 | Global.netCache.cache.clear();
61 | //更新profile中的token信息
62 | Global.profile.token = basic;
63 | return User.fromJson(r.data);
64 | }
65 |
66 | //获取用户项目列表
67 | Future> getRepos(
68 | {Map queryParameters, //query参数,用于接收分页信息
69 | refresh = false}) async {
70 | if (refresh) {
71 | // 列表下拉刷新,需要删除缓存(拦截器中会读取这些信息)
72 | _options.extra.addAll({"refresh": true, "list": true});
73 | }
74 | var r = await dio.get(
75 | "user/repos",
76 | queryParameters: queryParameters,
77 | options: _options,
78 | );
79 | return r.data.map((e) => Repo.fromJson(e)).toList();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/github_client_app/lib/common/global.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 | import 'package:flutter/material.dart';
3 | import 'package:shared_preferences/shared_preferences.dart';
4 | import '../index.dart';
5 |
6 | // 提供四套可选主题色
7 | const _themes = [
8 | Colors.blue,
9 | Colors.cyan,
10 | Colors.teal,
11 | Colors.green,
12 | Colors.red,
13 | ];
14 |
15 | class Global {
16 | static SharedPreferences _prefs;
17 | static Profile profile = Profile();
18 | // 网络缓存对象
19 | static NetCache netCache = NetCache();
20 |
21 | // 可选的主题列表
22 | static List get themes => _themes;
23 |
24 | // 是否为release版
25 | static bool get isRelease => bool.fromEnvironment("dart.vm.product");
26 |
27 | //初始化全局信息
28 | static Future init() async {
29 | WidgetsFlutterBinding.ensureInitialized();
30 | _prefs = await SharedPreferences.getInstance();
31 | var _profile = _prefs.getString("profile");
32 | if (_profile != null) {
33 | try {
34 | profile = Profile.fromJson(jsonDecode(_profile));
35 | } catch (e) {
36 | print(e);
37 | }
38 | }
39 |
40 | // 如果没有缓存策略,设置默认缓存策略
41 | profile.cache = profile.cache ?? CacheConfig()
42 | ..enable = true
43 | ..maxAge = 3600
44 | ..maxCount = 100;
45 |
46 | //初始化网络请求相关配置
47 | Git.init();
48 | }
49 |
50 | // 持久化Profile信息
51 | static saveProfile() =>
52 | _prefs.setString("profile", jsonEncode(profile.toJson()));
53 | }
54 |
--------------------------------------------------------------------------------
/github_client_app/lib/common/icons.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class MyIcons {
4 | static const IconData github_outline = IconData(0xe799, fontFamily: 'myIcon');
5 | static const IconData github = IconData(0xe7ab, fontFamily: 'myIcon');
6 | static const IconData fork = IconData(0xe65b, fontFamily: 'myIcon');
7 | static const IconData pr = IconData(0xe8b8, fontFamily: 'myIcon');
8 | static const IconData code = IconData(0xe646, fontFamily: 'myIcon');
9 | }
--------------------------------------------------------------------------------
/github_client_app/lib/common/index.dart:
--------------------------------------------------------------------------------
1 | export 'git_api.dart';
2 | export 'global.dart';
3 | export 'net_cache.dart';
4 | export 'icons.dart';
5 | export 'funs.dart';
--------------------------------------------------------------------------------
/github_client_app/lib/common/net_cache.dart:
--------------------------------------------------------------------------------
1 | import 'dart:collection';
2 | import 'package:dio/dio.dart';
3 | import '../index.dart';
4 |
5 | class CacheObject {
6 | CacheObject(this.response)
7 | : timeStamp = DateTime.now().millisecondsSinceEpoch;
8 | Response response;
9 | int timeStamp;
10 |
11 | @override
12 | bool operator ==(other) {
13 | return response.hashCode == other.hashCode;
14 | }
15 |
16 | @override
17 | int get hashCode => response.realUri.hashCode;
18 | }
19 |
20 | class NetCache extends Interceptor {
21 | // 为确保迭代器顺序和对象插入时间一致顺序一致,我们使用LinkedHashMap
22 | var cache = LinkedHashMap();
23 |
24 | @override
25 | onRequest(RequestOptions options) async {
26 | if (!Global.profile.cache.enable) return options;
27 | // refresh标记是否是"下拉刷新"
28 | bool refresh = options.extra["refresh"] == true;
29 | //如果是下拉刷新,先删除相关缓存
30 | if (refresh) {
31 | if (options.extra["list"] == true) {
32 | //若是列表,则只要url中包含当前path的缓存全部删除(简单实现,并不精准)
33 | cache.removeWhere((key, v) => key.contains(options.path));
34 | } else {
35 | // 如果不是列表,则只删除uri相同的缓存
36 | delete(options.uri.toString());
37 | }
38 | return options;
39 | }
40 | if (options.extra["noCache"] != true &&
41 | options.method.toLowerCase() == 'get') {
42 | String key = options.extra["cacheKey"] ?? options.uri.toString();
43 | var ob = cache[key];
44 | if (ob != null) {
45 | //若缓存未过期,则返回缓存内容
46 | if ((DateTime.now().millisecondsSinceEpoch - ob.timeStamp) / 1000 <
47 | Global.profile.cache.maxAge) {
48 | return cache[key].response;
49 | } else {
50 | //若已过期则删除缓存,继续向服务器请求
51 | cache.remove(key);
52 | }
53 | }
54 | }
55 | }
56 |
57 |
58 | @override
59 | onResponse(Response response) async {
60 | // 如果启用缓存,将返回结果保存到缓存
61 | if (Global.profile.cache.enable) {
62 | _saveCache(response);
63 | }
64 | }
65 |
66 | _saveCache(Response object) {
67 | RequestOptions options = object.request;
68 | if (options.extra["noCache"] != true &&
69 | options.method.toLowerCase() == "get") {
70 | // 如果缓存数量超过最大数量限制,则先移除最早的一条记录
71 | if (cache.length == Global.profile.cache.maxCount) {
72 | cache.remove(cache[cache.keys.first]);
73 | }
74 | String key = options.extra["cacheKey"] ?? options.uri.toString();
75 | cache[key] = CacheObject(object);
76 | }
77 | }
78 |
79 | void delete(String key) {
80 | cache.remove(key);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/github_client_app/lib/index.dart:
--------------------------------------------------------------------------------
1 | export 'package:github_client_app/common/global.dart';
2 | export 'models/index.dart';
3 | export 'states/index.dart';
4 | export 'routes/index.dart';
5 | export 'widgets/index.dart';
6 | export 'l10n/localization_intl.dart';
7 | export 'package:provider/provider.dart';
8 | export 'common/index.dart';
9 | export 'package:flutter/material.dart';
10 |
11 |
12 |
--------------------------------------------------------------------------------
/github_client_app/lib/l10n/localization_intl.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:intl/intl.dart';
3 | import 'messages_all.dart'; //1
4 |
5 | class GmLocalizations {
6 | static Future load(Locale locale) {
7 | final String name =
8 | locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
9 | final String localeName = Intl.canonicalizedLocale(name);
10 | //2
11 | return initializeMessages(localeName).then((b) {
12 | Intl.defaultLocale = localeName;
13 | return new GmLocalizations();
14 | });
15 | }
16 |
17 | static GmLocalizations of(BuildContext context) {
18 | return Localizations.of(context, GmLocalizations);
19 | }
20 |
21 | String get title {
22 | return Intl.message(
23 | 'Flutter APP',
24 | name: 'title',
25 | desc: 'Title for the Demo application',
26 | );
27 | }
28 |
29 | String get home => Intl.message('Github', name: 'home');
30 |
31 | String get language => Intl.message('Language', name: 'language');
32 |
33 | String get login => Intl.message('Login', name: 'login');
34 |
35 | String get auto => Intl.message('Auto', name: 'auto');
36 |
37 | String get setting => Intl.message('Setting', name: 'setting');
38 |
39 | String get theme => Intl.message('Theme', name: 'theme');
40 |
41 | String get noDescription =>
42 | Intl.message('No description yet !', name: 'noDescription');
43 |
44 | String get userName => Intl.message('User Name', name: 'userName');
45 | String get userNameRequired => Intl.message("User name required!" , name: 'userNameRequired');
46 | String get password => Intl.message('Password', name: 'password');
47 | String get passwordRequired => Intl.message('Password required!', name: 'passwordRequired');
48 | String get userNameOrPasswordWrong=>Intl.message('User name or password is not correct!', name: 'userNameOrPasswordWrong');
49 | String get logout => Intl.message('logout', name: 'logout');
50 | String get logoutTip => Intl.message('Are you sure you want to quit your current account?', name: 'logoutTip');
51 | String get yes => Intl.message('yes', name: 'yes');
52 | String get cancel => Intl.message('cancel', name: 'cancel');
53 | }
54 |
55 | //Locale代理类
56 | class GmLocalizationsDelegate extends LocalizationsDelegate {
57 | const GmLocalizationsDelegate();
58 |
59 | //是否支持某个Local
60 | @override
61 | bool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode);
62 |
63 | // Flutter会调用此类加载相应的Locale资源类
64 | @override
65 | Future load(Locale locale) {
66 | //3
67 | return GmLocalizations.load(locale);
68 | }
69 |
70 | // 当Localizations Widget重新build时,是否调用load重新加载Locale资源.
71 | @override
72 | bool shouldReload(GmLocalizationsDelegate old) => false;
73 | }
74 |
--------------------------------------------------------------------------------
/github_client_app/lib/l10n/messages_all.dart:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
2 | // This is a library that looks up messages for specific locales by
3 | // delegating to the appropriate library.
4 |
5 | import 'dart:async';
6 |
7 | import 'package:intl/intl.dart';
8 | import 'package:intl/message_lookup_by_library.dart';
9 | // ignore: implementation_imports
10 | import 'package:intl/src/intl_helpers.dart';
11 |
12 | import 'messages_messages.dart' as messages_messages;
13 | import 'messages_zh_CN.dart' as messages_zh_cn;
14 |
15 | typedef Future LibraryLoader();
16 | Map _deferredLibraries = {
17 | // ignore: unnecessary_new
18 | 'messages': () => new Future.value(null),
19 | // ignore: unnecessary_new
20 | 'zh_CN': () => new Future.value(null),
21 | };
22 |
23 | MessageLookupByLibrary _findExact(localeName) {
24 | switch (localeName) {
25 | case 'messages':
26 | return messages_messages.messages;
27 | case 'zh_CN':
28 | return messages_zh_cn.messages;
29 | default:
30 | return null;
31 | }
32 | }
33 |
34 | /// User programs should call this before using [localeName] for messages.
35 | Future initializeMessages(String localeName) async {
36 | var availableLocale = Intl.verifiedLocale(
37 | localeName,
38 | (locale) => _deferredLibraries[locale] != null,
39 | onFailure: (_) => null);
40 | if (availableLocale == null) {
41 | // ignore: unnecessary_new
42 | return new Future.value(false);
43 | }
44 | var lib = _deferredLibraries[availableLocale];
45 | // ignore: unnecessary_new
46 | await (lib == null ? new Future.value(false) : lib());
47 | // ignore: unnecessary_new
48 | initializeInternalMessageLookup(() => new CompositeMessageLookup());
49 | messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
50 | // ignore: unnecessary_new
51 | return new Future.value(true);
52 | }
53 |
54 | bool _messagesExistFor(String locale) {
55 | try {
56 | return _findExact(locale) != null;
57 | } catch (e) {
58 | return false;
59 | }
60 | }
61 |
62 | MessageLookupByLibrary _findGeneratedMessagesFor(locale) {
63 | var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor,
64 | onFailure: (_) => null);
65 | if (actualLocale == null) return null;
66 | return _findExact(actualLocale);
67 | }
68 |
--------------------------------------------------------------------------------
/github_client_app/lib/l10n/messages_messages.dart:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
2 | // This is a library that provides messages for a messages locale. All the
3 | // messages from the main program should be duplicated here with the same
4 | // function name.
5 |
6 | // ignore_for_file: unnecessary_brace_in_string_interps
7 |
8 | import 'package:intl/intl.dart';
9 | import 'package:intl/message_lookup_by_library.dart';
10 |
11 | // ignore: unnecessary_new
12 | final messages = new MessageLookup();
13 |
14 | // ignore: unused_element
15 | final _keepAnalysisHappy = Intl.defaultLocale;
16 |
17 | // ignore: non_constant_identifier_names
18 | typedef MessageIfAbsent(String message_str, List args);
19 |
20 | class MessageLookup extends MessageLookupByLibrary {
21 | get localeName => 'messages';
22 |
23 | final messages = _notInlinedMessages(_notInlinedMessages);
24 | static _notInlinedMessages(_) => {
25 | "auto" : MessageLookupByLibrary.simpleMessage("Auto"),
26 | "cancel" : MessageLookupByLibrary.simpleMessage("cancel"),
27 | "home" : MessageLookupByLibrary.simpleMessage("Github"),
28 | "language" : MessageLookupByLibrary.simpleMessage("Language"),
29 | "login" : MessageLookupByLibrary.simpleMessage("Login"),
30 | "logout" : MessageLookupByLibrary.simpleMessage("logout"),
31 | "logoutTip" : MessageLookupByLibrary.simpleMessage("Are you sure you want to quit your current account?"),
32 | "noDescription" : MessageLookupByLibrary.simpleMessage("No description yet !"),
33 | "password" : MessageLookupByLibrary.simpleMessage("Password"),
34 | "passwordRequired" : MessageLookupByLibrary.simpleMessage("Password required!"),
35 | "setting" : MessageLookupByLibrary.simpleMessage("Setting"),
36 | "theme" : MessageLookupByLibrary.simpleMessage("Theme"),
37 | "title" : MessageLookupByLibrary.simpleMessage("Flutter APP"),
38 | "userName" : MessageLookupByLibrary.simpleMessage("User Name"),
39 | "userNameOrPasswordWrong" : MessageLookupByLibrary.simpleMessage("User name or password is not correct!"),
40 | "userNameRequired" : MessageLookupByLibrary.simpleMessage("User name required!"),
41 | "yes" : MessageLookupByLibrary.simpleMessage("yes")
42 | };
43 | }
44 |
--------------------------------------------------------------------------------
/github_client_app/lib/l10n/messages_zh_CN.dart:
--------------------------------------------------------------------------------
1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
2 | // This is a library that provides messages for a zh_CN locale. All the
3 | // messages from the main program should be duplicated here with the same
4 | // function name.
5 |
6 | // ignore_for_file: unnecessary_brace_in_string_interps
7 |
8 | import 'package:intl/intl.dart';
9 | import 'package:intl/message_lookup_by_library.dart';
10 |
11 | // ignore: unnecessary_new
12 | final messages = new MessageLookup();
13 |
14 | // ignore: unused_element
15 | final _keepAnalysisHappy = Intl.defaultLocale;
16 |
17 | // ignore: non_constant_identifier_names
18 | typedef MessageIfAbsent(String message_str, List args);
19 |
20 | class MessageLookup extends MessageLookupByLibrary {
21 | get localeName => 'zh_CN';
22 |
23 | final messages = _notInlinedMessages(_notInlinedMessages);
24 | static _notInlinedMessages(_) => {
25 | "auto" : MessageLookupByLibrary.simpleMessage("跟随系统"),
26 | "cancel" : MessageLookupByLibrary.simpleMessage("取消"),
27 | "home" : MessageLookupByLibrary.simpleMessage("Github客户端"),
28 | "language" : MessageLookupByLibrary.simpleMessage("语言"),
29 | "login" : MessageLookupByLibrary.simpleMessage("登录"),
30 | "logout" : MessageLookupByLibrary.simpleMessage("注销"),
31 | "logoutTip" : MessageLookupByLibrary.simpleMessage("确定要退出当前账号吗?"),
32 | "noDescription" : MessageLookupByLibrary.simpleMessage("暂无描述!"),
33 | "password" : MessageLookupByLibrary.simpleMessage("密码"),
34 | "passwordRequired" : MessageLookupByLibrary.simpleMessage("密码不能为空"),
35 | "setting" : MessageLookupByLibrary.simpleMessage("设置"),
36 | "theme" : MessageLookupByLibrary.simpleMessage("换肤"),
37 | "title" : MessageLookupByLibrary.simpleMessage("Github客户端"),
38 | "userName" : MessageLookupByLibrary.simpleMessage("用户名"),
39 | "userNameOrPasswordWrong" : MessageLookupByLibrary.simpleMessage("用户名或密码不正确"),
40 | "userNameRequired" : MessageLookupByLibrary.simpleMessage("用户名不能为空"),
41 | "yes" : MessageLookupByLibrary.simpleMessage("确定")
42 | };
43 | }
44 |
--------------------------------------------------------------------------------
/github_client_app/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:provider/provider.dart';
3 | import 'package:flutter_localizations/flutter_localizations.dart';
4 | import 'index.dart';
5 |
6 | void main() => Global.init().then((e) => runApp(MyApp()));
7 |
8 | class MyApp extends StatelessWidget {
9 | // This widget is the root of your application.
10 | @override
11 | Widget build(BuildContext context) {
12 | return MultiProvider(
13 | providers: [
14 | ChangeNotifierProvider.value(value: ThemeModel()),
15 | ChangeNotifierProvider.value(value: UserModel()),
16 | ChangeNotifierProvider.value(value: LocaleModel()),
17 | ],
18 | child: Consumer2(
19 | builder: (BuildContext context, themeModel, localeModel, Widget child) {
20 | return MaterialApp(
21 | theme: ThemeData(
22 | primarySwatch: themeModel.theme,
23 | ),
24 | onGenerateTitle: (context){
25 | return GmLocalizations.of(context).title;
26 | },
27 | home: HomeRoute(),
28 | locale: localeModel.getLocale(),
29 | //我们只支持美国英语和中文简体
30 | supportedLocales: [
31 | const Locale('en', 'US'), // 美国英语
32 | const Locale('zh', 'CN'), // 中文简体
33 | //其它Locales
34 | ],
35 | localizationsDelegates: [
36 | // 本地化的代理类
37 | GlobalMaterialLocalizations.delegate,
38 | GlobalWidgetsLocalizations.delegate,
39 | GmLocalizationsDelegate()
40 | ],
41 | localeResolutionCallback:
42 | (Locale _locale, Iterable supportedLocales) {
43 | if (localeModel.getLocale() != null) {
44 | //如果已经选定语言,则不跟随系统
45 | return localeModel.getLocale();
46 | } else {
47 | //跟随系统
48 | Locale locale;
49 | if (supportedLocales.contains(_locale)) {
50 | locale= _locale;
51 | } else {
52 | //如果系统语言不是中文简体或美国英语,则默认使用美国英语
53 | locale= Locale('en', 'US');
54 | }
55 | return locale;
56 | }
57 | },
58 | // 注册路由表
59 | routes: {
60 | "login": (context) => LoginRoute(),
61 | "themes": (context) => ThemeChangeRoute(),
62 | "language": (context) => LanguageRoute(),
63 | },
64 | );
65 | },
66 | ),
67 | );
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/github_client_app/lib/models/cacheConfig.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 |
3 | part 'cacheConfig.g.dart';
4 |
5 | @JsonSerializable()
6 | class CacheConfig {
7 | CacheConfig();
8 |
9 | bool enable;
10 | num maxAge;
11 | num maxCount;
12 |
13 | factory CacheConfig.fromJson(Map json) => _$CacheConfigFromJson(json);
14 | Map toJson() => _$CacheConfigToJson(this);
15 | }
16 |
--------------------------------------------------------------------------------
/github_client_app/lib/models/cacheConfig.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'cacheConfig.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | CacheConfig _$CacheConfigFromJson(Map json) {
10 | return CacheConfig()
11 | ..enable = json['enable'] as bool
12 | ..maxAge = json['maxAge'] as num
13 | ..maxCount = json['maxCount'] as num;
14 | }
15 |
16 | Map _$CacheConfigToJson(CacheConfig instance) =>
17 | {
18 | 'enable': instance.enable,
19 | 'maxAge': instance.maxAge,
20 | 'maxCount': instance.maxCount
21 | };
22 |
--------------------------------------------------------------------------------
/github_client_app/lib/models/index.dart:
--------------------------------------------------------------------------------
1 | export 'repo.dart' ;
2 | export 'cacheConfig.dart' ;
3 | export 'user.dart' ;
4 | export 'profile.dart' ;
5 |
--------------------------------------------------------------------------------
/github_client_app/lib/models/profile.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 | import "user.dart";
3 | import "cacheConfig.dart";
4 | part 'profile.g.dart';
5 |
6 | @JsonSerializable()
7 | class Profile {
8 | Profile();
9 |
10 | User user;
11 | String token;
12 | num theme;
13 | CacheConfig cache;
14 | String lastLogin;
15 | String locale;
16 |
17 | factory Profile.fromJson(Map json) => _$ProfileFromJson(json);
18 | Map toJson() => _$ProfileToJson(this);
19 | }
20 |
--------------------------------------------------------------------------------
/github_client_app/lib/models/profile.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'profile.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | Profile _$ProfileFromJson(Map json) {
10 | return Profile()
11 | ..user = json['user'] == null
12 | ? null
13 | : User.fromJson(json['user'] as Map)
14 | ..token = json['token'] as String
15 | ..theme = json['theme'] as num
16 | ..cache = json['cache'] == null
17 | ? null
18 | : CacheConfig.fromJson(json['cache'] as Map)
19 | ..lastLogin = json['lastLogin'] as String
20 | ..locale = json['locale'] as String;
21 | }
22 |
23 | Map _$ProfileToJson(Profile instance) => {
24 | 'user': instance.user,
25 | 'token': instance.token,
26 | 'theme': instance.theme,
27 | 'cache': instance.cache,
28 | 'lastLogin': instance.lastLogin,
29 | 'locale': instance.locale
30 | };
31 |
--------------------------------------------------------------------------------
/github_client_app/lib/models/repo.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 | import "user.dart";
3 | part 'repo.g.dart';
4 |
5 | @JsonSerializable()
6 | class Repo {
7 | Repo();
8 |
9 | num id;
10 | String name;
11 | String full_name;
12 | User owner;
13 | Repo parent;
14 | bool private;
15 | String html_url;
16 | String description;
17 | bool fork;
18 | String homepage;
19 | String language;
20 | num forks_count;
21 | num stargazers_count;
22 | num watchers_count;
23 | num size;
24 | String default_branch;
25 | num open_issues_count;
26 | List topics;
27 | bool has_issues;
28 | bool has_projects;
29 | bool has_wiki;
30 | bool has_pages;
31 | bool has_downloads;
32 | String pushed_at;
33 | String created_at;
34 | String updated_at;
35 | Map permissions;
36 | num subscribers_count;
37 | Map license;
38 |
39 | factory Repo.fromJson(Map json) => _$RepoFromJson(json);
40 | Map toJson() => _$RepoToJson(this);
41 | }
42 |
--------------------------------------------------------------------------------
/github_client_app/lib/models/repo.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'repo.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | Repo _$RepoFromJson(Map json) {
10 | return Repo()
11 | ..id = json['id'] as num
12 | ..name = json['name'] as String
13 | ..full_name = json['full_name'] as String
14 | ..owner = json['owner'] == null
15 | ? null
16 | : User.fromJson(json['owner'] as Map)
17 | ..parent = json['parent'] == null
18 | ? null
19 | : Repo.fromJson(json['parent'] as Map)
20 | ..private = json['private'] as bool
21 | ..html_url = json['html_url'] as String
22 | ..description = json['description'] as String
23 | ..fork = json['fork'] as bool
24 | ..homepage = json['homepage'] as String
25 | ..language = json['language'] as String
26 | ..forks_count = json['forks_count'] as num
27 | ..stargazers_count = json['stargazers_count'] as num
28 | ..watchers_count = json['watchers_count'] as num
29 | ..size = json['size'] as num
30 | ..default_branch = json['default_branch'] as String
31 | ..open_issues_count = json['open_issues_count'] as num
32 | ..topics = json['topics'] as List
33 | ..has_issues = json['has_issues'] as bool
34 | ..has_projects = json['has_projects'] as bool
35 | ..has_wiki = json['has_wiki'] as bool
36 | ..has_pages = json['has_pages'] as bool
37 | ..has_downloads = json['has_downloads'] as bool
38 | ..pushed_at = json['pushed_at'] as String
39 | ..created_at = json['created_at'] as String
40 | ..updated_at = json['updated_at'] as String
41 | ..permissions = json['permissions'] as Map
42 | ..subscribers_count = json['subscribers_count'] as num
43 | ..license = json['license'] as Map;
44 | }
45 |
46 | Map _$RepoToJson(Repo instance) => {
47 | 'id': instance.id,
48 | 'name': instance.name,
49 | 'full_name': instance.full_name,
50 | 'owner': instance.owner,
51 | 'parent': instance.parent,
52 | 'private': instance.private,
53 | 'html_url': instance.html_url,
54 | 'description': instance.description,
55 | 'fork': instance.fork,
56 | 'homepage': instance.homepage,
57 | 'language': instance.language,
58 | 'forks_count': instance.forks_count,
59 | 'stargazers_count': instance.stargazers_count,
60 | 'watchers_count': instance.watchers_count,
61 | 'size': instance.size,
62 | 'default_branch': instance.default_branch,
63 | 'open_issues_count': instance.open_issues_count,
64 | 'topics': instance.topics,
65 | 'has_issues': instance.has_issues,
66 | 'has_projects': instance.has_projects,
67 | 'has_wiki': instance.has_wiki,
68 | 'has_pages': instance.has_pages,
69 | 'has_downloads': instance.has_downloads,
70 | 'pushed_at': instance.pushed_at,
71 | 'created_at': instance.created_at,
72 | 'updated_at': instance.updated_at,
73 | 'permissions': instance.permissions,
74 | 'subscribers_count': instance.subscribers_count,
75 | 'license': instance.license
76 | };
77 |
--------------------------------------------------------------------------------
/github_client_app/lib/models/user.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 |
3 | part 'user.g.dart';
4 |
5 | @JsonSerializable()
6 | class User {
7 | User();
8 |
9 | String login;
10 | num id;
11 | String avatar_url;
12 | String url;
13 | String type;
14 | bool site_admin;
15 | String name;
16 | String company;
17 | String blog;
18 | String location;
19 | String email;
20 | bool hireable;
21 | String bio;
22 | num public_repos;
23 | num public_gists;
24 | num followers;
25 | num following;
26 | String created_at;
27 | String updated_at;
28 | num total_private_repos;
29 | num owned_private_repos;
30 |
31 | factory User.fromJson(Map json) => _$UserFromJson(json);
32 | Map toJson() => _$UserToJson(this);
33 | }
34 |
--------------------------------------------------------------------------------
/github_client_app/lib/models/user.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'user.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | User _$UserFromJson(Map json) {
10 | return User()
11 | ..login = json['login'] as String
12 | ..id = json['id'] as num
13 | ..avatar_url = json['avatar_url'] as String
14 | ..url = json['url'] as String
15 | ..type = json['type'] as String
16 | ..site_admin = json['site_admin'] as bool
17 | ..name = json['name'] as String
18 | ..company = json['company'] as String
19 | ..blog = json['blog'] as String
20 | ..location = json['location'] as String
21 | ..email = json['email'] as String
22 | ..hireable = json['hireable'] as bool
23 | ..bio = json['bio'] as String
24 | ..public_repos = json['public_repos'] as num
25 | ..public_gists = json['public_gists'] as num
26 | ..followers = json['followers'] as num
27 | ..following = json['following'] as num
28 | ..created_at = json['created_at'] as String
29 | ..updated_at = json['updated_at'] as String
30 | ..total_private_repos = json['total_private_repos'] as num
31 | ..owned_private_repos = json['owned_private_repos'] as num;
32 | }
33 |
34 | Map _$UserToJson(User instance) => {
35 | 'login': instance.login,
36 | 'id': instance.id,
37 | 'avatar_url': instance.avatar_url,
38 | 'url': instance.url,
39 | 'type': instance.type,
40 | 'site_admin': instance.site_admin,
41 | 'name': instance.name,
42 | 'company': instance.company,
43 | 'blog': instance.blog,
44 | 'location': instance.location,
45 | 'email': instance.email,
46 | 'hireable': instance.hireable,
47 | 'bio': instance.bio,
48 | 'public_repos': instance.public_repos,
49 | 'public_gists': instance.public_gists,
50 | 'followers': instance.followers,
51 | 'following': instance.following,
52 | 'created_at': instance.created_at,
53 | 'updated_at': instance.updated_at,
54 | 'total_private_repos': instance.total_private_repos,
55 | 'owned_private_repos': instance.owned_private_repos
56 | };
57 |
--------------------------------------------------------------------------------
/github_client_app/lib/routes/index.dart:
--------------------------------------------------------------------------------
1 | export 'home_page.dart';
2 | export 'login.dart';
3 | export 'theme_change.dart';
4 | export 'language.dart';
--------------------------------------------------------------------------------
/github_client_app/lib/routes/language.dart:
--------------------------------------------------------------------------------
1 | import '../index.dart';
2 |
3 | class LanguageRoute extends StatelessWidget {
4 | @override
5 | Widget build(BuildContext context) {
6 | var color = Theme.of(context).primaryColor;
7 | var localeModel = Provider.of(context);
8 | var gm = GmLocalizations.of(context);
9 | Widget _buildLanguageItem(String lan, value) {
10 | return ListTile(
11 | title: Text(
12 | lan,
13 | // 对APP当前语言进行高亮显示
14 | style: TextStyle(color: localeModel.locale == value ? color : null),
15 | ),
16 | trailing:
17 | localeModel.locale == value ? Icon(Icons.done, color: color) : null,
18 | onTap: () {
19 | // 此行代码会通知MaterialApp重新build
20 | localeModel.locale = value;
21 | },
22 | );
23 | }
24 |
25 | return Scaffold(
26 | appBar: AppBar(
27 | title: Text(gm.language),
28 | ),
29 | body: ListView(
30 | children: [
31 | _buildLanguageItem("中文简体", "zh_CN"),
32 | _buildLanguageItem("English", "en_US"),
33 | _buildLanguageItem(gm.auto, null),
34 | ],
35 | ),
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/github_client_app/lib/routes/theme_change.dart:
--------------------------------------------------------------------------------
1 | import '../index.dart';
2 |
3 | class ThemeChangeRoute extends StatelessWidget{
4 | @override
5 | Widget build(BuildContext context) {
6 | return Scaffold(
7 | appBar: AppBar(
8 | title: Text(GmLocalizations.of(context).theme),
9 | ),
10 | body: ListView( //显示主题色块
11 | children: Global.themes.map((e) {
12 | return GestureDetector(
13 | child: Padding(
14 | padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 16),
15 | child: Container(
16 | color: e,
17 | height: 40,
18 | ),
19 | ),
20 | onTap: () {
21 | //主题更新后,MaterialApp会重新build
22 | Provider.of(context).theme = e;
23 | },
24 | );
25 | }).toList(),
26 | ),
27 | );
28 | }
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/github_client_app/lib/states/index.dart:
--------------------------------------------------------------------------------
1 | export 'profile_change_notifier.dart';
2 |
--------------------------------------------------------------------------------
/github_client_app/lib/states/profile_change_notifier.dart:
--------------------------------------------------------------------------------
1 | import '../index.dart';
2 |
3 | class ProfileChangeNotifier extends ChangeNotifier {
4 | Profile get _profile => Global.profile;
5 |
6 | @override
7 | void notifyListeners() {
8 | Global.saveProfile(); //保存Profile变更
9 | super.notifyListeners(); //通知依赖的Widget更新
10 | }
11 | }
12 |
13 | class UserModel extends ProfileChangeNotifier {
14 | User get user => _profile.user;
15 |
16 | // APP是否登录(如果有用户信息,则证明登录过)
17 | bool get isLogin => user != null;
18 |
19 | //用户信息发生变化,更新用户信息并通知依赖它的子孙Widgets更新
20 | set user(User user) {
21 | if (user?.login != _profile.user?.login) {
22 | _profile.lastLogin = _profile.user?.login;
23 | _profile.user = user;
24 | notifyListeners();
25 | }
26 | }
27 | }
28 |
29 | class ThemeModel extends ProfileChangeNotifier {
30 | // 获取当前主题,如果为设置主题,则默认使用蓝色主题
31 | ColorSwatch get theme => Global.themes
32 | .firstWhere((e) => e.value == _profile.theme, orElse: () => Colors.blue);
33 |
34 | // 主题改变后,通知其依赖项,新主题会立即生效
35 | set theme(ColorSwatch color) {
36 | if (color != theme) {
37 | _profile.theme = color[500].value;
38 | notifyListeners();
39 | }
40 | }
41 | }
42 |
43 | class LocaleModel extends ProfileChangeNotifier {
44 | // 获取当前用户的APP语言配置Locale类,如果为null,则语言跟随系统语言
45 | Locale getLocale() {
46 | if (_profile.locale == null) return null;
47 | var t = _profile.locale.split("_");
48 | return Locale(t[0], t[1]);
49 | }
50 |
51 | // 获取当前Locale的字符串表示
52 | String get locale => _profile.locale;
53 |
54 | // 用户改变APP语言后,通知依赖项更新,新语言会立即生效
55 | set locale(String locale) {
56 | if (locale != _profile.locale) {
57 | _profile.locale = locale;
58 | notifyListeners();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/github_client_app/lib/widgets/index.dart:
--------------------------------------------------------------------------------
1 | export 'repo_item.dart';
--------------------------------------------------------------------------------
/github_client_app/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: github_client_app
2 | description: A Github client APP built with Flutter
3 | version: 1.0.0+1
4 |
5 | environment:
6 | sdk: ">=2.1.0 <3.0.0"
7 |
8 | dependencies:
9 | flutter:
10 | sdk: flutter
11 | flutter_localizations:
12 | sdk: flutter
13 | intl: ^0.16.0
14 | dio: ^3.0.3
15 | provider: ^3.0.0+1
16 | shared_preferences: ^0.5.1+1
17 | cached_network_image: ^2.0.0
18 | fluttertoast: ^3.0.3
19 | flukit: ^1.0.2
20 |
21 | # The following adds the Cupertino Icons font to your application.
22 | # Use with the CupertinoIcons class for iOS style icons.
23 | cupertino_icons: ^0.1.2
24 |
25 | dev_dependencies:
26 | flutter_test:
27 | sdk: flutter
28 | json_model: ^0.0.2
29 | intl_translation: ^0.17.4
30 | build_runner: ^1.0.0
31 | json_serializable: ^2.0.0
32 |
33 |
34 |
35 | # For information on the generic Dart part of this file, see the
36 | # following page: https://dart.dev/tools/pub/pubspec
37 |
38 | # The following section is specific to Flutter.
39 | flutter:
40 |
41 | # The following line ensures that the Material Icons font is
42 | # included with your application, so that you can use the icons in
43 | # the material Icons class.
44 | uses-material-design: true
45 |
46 | # To add assets to your application, add an assets section, like this:
47 | assets:
48 | - imgs/avatar-default.png
49 | - imgs/logo_light.png
50 | - imgs/logo_dark.png
51 |
52 | # An image asset can refer to one or more resolution-specific "variants", see
53 | # https://flutter.dev/assets-and-images/#resolution-aware.
54 |
55 | # For details regarding adding assets from package dependencies, see
56 | # https://flutter.dev/assets-and-images/#from-packages
57 |
58 | # To add custom fonts to your application, add a fonts section here,
59 | # in this "flutter" section. Each entry in this list should have a
60 | # "family" key with the font family name, and a "fonts" key with a
61 | # list giving the asset and other descriptors for the font. For
62 | # example:
63 |
64 | fonts:
65 | - family: myIcon
66 | fonts:
67 | - asset: fonts/iconfont.ttf
68 | # fonts:
69 | # - family: Schyler
70 | # fonts:
71 | # - asset: fonts/Schyler-Regular.ttf
72 | # - asset: fonts/Schyler-Italic.ttf
73 | # style: italic
74 | # - family: Trajan Pro
75 | # fonts:
76 | # - asset: fonts/TrajanPro.ttf
77 | # - asset: fonts/TrajanPro_Bold.ttf
78 | # weight: 700
79 | #
80 | # For details regarding fonts from package dependencies,
81 | # see https://flutter.dev/custom-fonts/#from-packages
82 |
--------------------------------------------------------------------------------
/github_client_app/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:github_client_app/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/home.png
--------------------------------------------------------------------------------
/img_des.txt:
--------------------------------------------------------------------------------
1 | 3-1 StatelessWidget
2 | 3-2 StatefulWidget生命周期图
--------------------------------------------------------------------------------
/imgs/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/imgs/avatar.png
--------------------------------------------------------------------------------
/intl.sh:
--------------------------------------------------------------------------------
1 | flutter pub pub run intl_translation:extract_to_arb --output-dir=l10n-arb lib/l10n/localization_intl.dart
2 | flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/l10n/localization_intl.dart l10n-arb/intl_*.arb
3 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Flutter.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # NOTE: This podspec is NOT to be published. It is only used as a local source!
3 | #
4 |
5 | Pod::Spec.new do |s|
6 | s.name = 'Flutter'
7 | s.version = '1.0.0'
8 | s.summary = 'High-performance, high-fidelity mobile apps.'
9 | s.description = <<-DESC
10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
11 | DESC
12 | s.homepage = 'https://flutter.io'
13 | s.license = { :type => 'MIT' }
14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
16 | s.ios.deployment_target = '8.0'
17 | s.vendored_frameworks = 'Flutter.framework'
18 | end
19 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/flutter_export_environment.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a generated file; do not edit or check into version control.
3 | export "FLUTTER_ROOT=/Users/duwen/Documents/flutter"
4 | export "FLUTTER_APPLICATION_PATH=/Users/duwen/Documents/code/flutter_in_action"
5 | export "FLUTTER_TARGET=/Users/duwen/Documents/code/flutter_in_action/lib/main.dart"
6 | export "FLUTTER_BUILD_DIR=build"
7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios"
8 | export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
9 | export "FLUTTER_FRAMEWORK_DIR=/Users/duwen/Documents/flutter/bin/cache/artifacts/engine/ios"
10 | export "FLUTTER_BUILD_NAME=1.0.0"
11 | export "FLUTTER_BUILD_NUMBER=1"
12 | export "TRACK_WIDGET_CREATION=true"
13 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def parse_KV_file(file, separator='=')
14 | file_abs_path = File.expand_path(file)
15 | if !File.exists? file_abs_path
16 | return [];
17 | end
18 | pods_ary = []
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) { |line|
21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22 | plugin = line.split(pattern=separator)
23 | if plugin.length == 2
24 | podname = plugin[0].strip()
25 | path = plugin[1].strip()
26 | podpath = File.expand_path("#{path}", file_abs_path)
27 | pods_ary.push({:name => podname, :path => podpath});
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | }
32 | return pods_ary
33 | end
34 |
35 | target 'Runner' do
36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
37 | # referring to absolute paths on developers' machines.
38 | system('rm -rf .symlinks')
39 | system('mkdir -p .symlinks/plugins')
40 |
41 | # Flutter Pods
42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
43 | if generated_xcode_build_settings.empty?
44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first."
45 | end
46 | generated_xcode_build_settings.map { |p|
47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
48 | symlink = File.join('.symlinks', 'flutter')
49 | File.symlink(File.dirname(p[:path]), symlink)
50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
51 | end
52 | }
53 |
54 | # Plugin Pods
55 | plugin_pods = parse_KV_file('../.flutter-plugins')
56 | plugin_pods.map { |p|
57 | symlink = File.join('.symlinks', 'plugins', p[:name])
58 | File.symlink(p[:path], symlink)
59 | pod p[:name], :path => File.join(symlink, 'ios')
60 | }
61 | end
62 |
63 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
64 | install! 'cocoapods', :disable_input_output_paths => true
65 |
66 | post_install do |installer|
67 | installer.pods_project.targets.each do |target|
68 | target.build_configurations.each do |config|
69 | config.build_settings['ENABLE_BITCODE'] = 'NO'
70 | end
71 | end
72 | end
73 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wendux/flutter_in_action_source_code/e5e54b3082bc344fb9c236a9e24796ac568ac859/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_in_action
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/l10n-arb/intl_messages.arb:
--------------------------------------------------------------------------------
1 | {
2 | "@@last_modified": "2018-12-10T18:00:52.404540",
3 | "title": "Flutter APP",
4 | "@title": {
5 | "description": "Title for the Demo application",
6 | "type": "text",
7 | "placeholders": {}
8 | },
9 | "remainingEmailsMessage": "{howMany,plural, =0{There are no emails left}=1{There is {howMany} email left}other{There are {howMany} emails left}}",
10 | "@remainingEmailsMessage": {
11 | "description": "How many emails remain after archiving.",
12 | "type": "text",
13 | "placeholders": {
14 | "howMany": {
15 | "example": 42
16 | }
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/l10n-arb/intl_zh_CN.arb:
--------------------------------------------------------------------------------
1 | {
2 | "@@last_modified": "2018-12-10T15:46:20.897228",
3 | "@@locale":"zh_CN",
4 | "title": "Flutter应用",
5 | "@title": {
6 | "description": "Title for the Demo application",
7 | "type": "text",
8 | "placeholders": {}
9 | },
10 | "remainingEmailsMessage": "{howMany,plural, =0{没有未读邮件}=1{有{howMany}封未读邮件}other{有{howMany}封未读邮件}}",
11 | "@remainingEmailsMessage": {
12 | "description": "How many emails remain after archiving.",
13 | "type": "text",
14 | "placeholders": {
15 | "howMany": {
16 | "example": 42
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/lib/common.dart:
--------------------------------------------------------------------------------
1 | import 'package:camera/camera.dart';
2 |
3 | List cameras;
--------------------------------------------------------------------------------
/lib/event_bus.dart:
--------------------------------------------------------------------------------
1 | //订阅者回调签名
2 | typedef void EventCallback(arg);
3 |
4 | class EventBus {
5 | //私有构造函数
6 | EventBus._internal();
7 |
8 | //保存单例
9 | static EventBus _singleton = new EventBus._internal();
10 |
11 | //工厂构造函数
12 | factory EventBus()=> _singleton;
13 |
14 | //保存事件订阅者队列,key:事件名(id),value: 对应事件的订阅者队列
15 | var _emap = new Map