├── .gitignore
├── .metadata
├── README.md
├── android
├── app
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── yourcompany
│ │ │ └── doubanmovies
│ │ │ └── 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
├── flutterKey.jks
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── ios
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── 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
├── lib
├── WanAndroid
│ ├── Data
│ │ ├── data_article_bean.dart
│ │ ├── data_banner_bean.dart
│ │ ├── data_key_bean.dart
│ │ ├── data_navi_bean.dart
│ │ ├── data_person_bean.dart
│ │ └── data_tree_bean.dart
│ ├── Manager
│ │ └── manager_article_base.dart
│ ├── Progress
│ │ ├── painter.dart
│ │ ├── painter
│ │ │ ├── WriteRoundEye
│ │ │ │ ├── Gy2Wht.dart
│ │ │ │ ├── GyWriteRoundEye.dart
│ │ │ │ ├── WhtWriteRoundEye.dart
│ │ │ │ ├── painter_write_round_eye.dart
│ │ │ │ └── widget_write_round_eye.dart
│ │ │ ├── painter_base.dart
│ │ │ ├── painter_circle.dart
│ │ │ ├── painter_circle_snapchat.dart
│ │ │ ├── painter_line_four.dart
│ │ │ ├── painter_progress_text.dart
│ │ │ ├── painter_wave.dart
│ │ │ └── rainDrop
│ │ │ │ ├── painter_rain_drop.dart
│ │ │ │ ├── point_rain_drop.dart
│ │ │ │ └── widget_rain_drop.dart
│ │ ├── painter_factory.dart
│ │ ├── progress_manager.dart
│ │ ├── rain_drop.dart
│ │ └── widget_rain_drop.dart
│ ├── article_detail_page.dart
│ ├── article_list_content.dart
│ ├── article_page.dart
│ ├── bloc
│ │ ├── AccountBloc.dart
│ │ ├── ApplicationBloc.dart
│ │ └── bloc_utils.dart
│ ├── config.dart
│ ├── dialog_utils.dart
│ ├── home_page.dart
│ ├── icon_font_utils.dart
│ ├── knowledge_tree_page.dart
│ ├── navigator_router_utils.dart
│ ├── person_page.dart
│ ├── popular_page.dart
│ ├── project_page.dart
│ ├── router_anim_utils.dart
│ ├── search_page.dart
│ ├── sp_utils.dart
│ ├── web_page.dart
│ └── widget_banner.dart
├── data
│ ├── bean_move_detail.dart
│ └── bean_move_list.dart
├── db
│ └── db_utils.dart
├── main.dart
├── net
│ └── http.dart
├── pages
│ ├── detail
│ │ ├── MovieActors
│ │ │ └── MovieActors.dart
│ │ ├── MovieChannel
│ │ │ └── MovieChannel.dart
│ │ ├── MovieComments
│ │ │ └── MovieCommentsView.dart
│ │ ├── MovieDesc
│ │ │ └── MovieDesc.dart
│ │ ├── MoviePopularComments
│ │ │ └── MoviePopularCommentsView.dart
│ │ ├── MovieRating
│ │ │ └── MovieRating.dart
│ │ ├── MovieTitle
│ │ │ └── MovieTitle.dart
│ │ └── page_detail.dart
│ ├── page_home.dart
│ └── views
│ │ ├── Chips.dart
│ │ ├── ClipImageView.dart
│ │ └── StartsView.dart
└── res
│ └── value_string.dart
├── pubspec.yaml
├── static
└── font
│ └── iconfont.ttf
└── 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: f37c235c32fc15babe6dc7b7bc2ee4387e5ecf92
8 | channel: beta
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # douban_movies
2 |
3 | A new Flutter application.
4 |
5 | ## Getting Started
6 |
7 | For help getting started with Flutter, view our online
8 | [documentation](https://flutter.io/).
9 |
--------------------------------------------------------------------------------
/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 27
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
36 | applicationId "com.yourcompany.doubanmovies"
37 | minSdkVersion 16
38 | targetSdkVersion 27
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
42 | }
43 |
44 | signingConfigs {
45 | debug {
46 | storeFile file("../flutterKey.jks")
47 | storePassword "3250905"
48 | keyAlias "flutter"
49 | keyPassword "3250905"
50 | }
51 | release {
52 | storeFile file("../flutterKey.jks")
53 | storePassword "3250905"
54 | keyAlias "flutter"
55 | keyPassword "3250905"
56 | }
57 | }
58 |
59 | buildTypes {
60 | debug {
61 | signingConfig signingConfigs.debug
62 | }
63 | release {
64 | signingConfig signingConfigs.release
65 | }
66 | }
67 |
68 | }
69 |
70 | flutter {
71 | source '../..'
72 | }
73 |
74 | dependencies {
75 | testImplementation 'junit:junit:4.12'
76 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
77 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
78 | }
79 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
15 |
19 |
26 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/yourcompany/doubanmovies/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.yourcompany.doubanmovies;
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 | }
15 |
--------------------------------------------------------------------------------
/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.1.2'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/flutterKey.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/android/flutterKey.jks
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/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 | douban_movies
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 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Data/data_article_bean.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert' show json;
2 |
3 | import 'package:html_unescape/html_unescape.dart';
4 |
5 | class HomeBean {
6 | int errorCode;
7 | String errorMsg;
8 | HomeListBean data;
9 |
10 | HomeBean.fromParams({
11 | this.errorCode,
12 | this.errorMsg,
13 | this.data,
14 | });
15 |
16 | factory HomeBean(jsonStr) => jsonStr == null
17 | ? null
18 | : jsonStr is String
19 | ? new HomeBean.fromJson(json.decode(jsonStr))
20 | : new HomeBean.fromJson(jsonStr);
21 |
22 | HomeBean.fromJson(jsonRes) {
23 | errorCode = jsonRes['errorCode'];
24 | errorMsg = jsonRes['errorMsg'];
25 | data = jsonRes['data'] == null
26 | ? null
27 | : new HomeListBean.fromJson(jsonRes['data']);
28 | }
29 |
30 | @override
31 | String toString() {
32 | // TODO: implement toString
33 | return super.toString();
34 | }
35 | }
36 |
37 | class HomeListBean {
38 | int curPage;
39 | int offset;
40 | bool over;
41 | int pageCount;
42 | int size;
43 | int total;
44 | List datas;
45 |
46 | HomeListBean.fromParams(
47 | {this.curPage,
48 | this.offset,
49 | this.over,
50 | this.pageCount,
51 | this.size,
52 | this.total,
53 | this.datas});
54 |
55 | factory HomeListBean(jsonStr) => jsonStr == null
56 | ? null
57 | : jsonStr is String
58 | ? new HomeListBean.fromJson(json.decode(jsonStr))
59 | : new HomeListBean.fromJson(jsonStr);
60 |
61 | HomeListBean.fromJson(jsonRes) {
62 | curPage = jsonRes['curPage'];
63 | offset = jsonRes['offset'];
64 | over = jsonRes['over'];
65 | pageCount = jsonRes['pageCount'];
66 | size = jsonRes['size'];
67 | total = jsonRes['total'];
68 | datas = jsonRes['datas'] == null ? null : [];
69 |
70 | for (var data in datas == null ? [] : jsonRes['datas']) {
71 | datas.add(data == null ? null : new Data.fromJson(data));
72 | }
73 | }
74 |
75 | @override
76 | String toString() {
77 | // TODO: implement toString
78 | return super.toString();
79 | }
80 | }
81 |
82 | class Data {
83 | String apkLink;
84 | String author;
85 | int chapterId;
86 | String chapterName;
87 | bool collect;
88 | int courseId;
89 | String desc;
90 | String envelopePic;
91 | bool fresh;
92 | int mId;
93 | String link;
94 | String niceDate;
95 | String origin;
96 | String projectLink;
97 | int publishTime;
98 | int superChapterId;
99 | String superChapterName;
100 | List tags;
101 | String title;
102 | int type;
103 | int userId;
104 | int visible;
105 | int zan;
106 |
107 | getTitle() {
108 | var unescape = new HtmlUnescape();
109 | return unescape.convert(title);
110 | }
111 |
112 | getChapterName() {
113 | var unescape = new HtmlUnescape();
114 | return unescape.convert(chapterName);
115 | }
116 |
117 | getNiceDate() {
118 | var unescape = new HtmlUnescape();
119 | return unescape.convert(niceDate);
120 | }
121 |
122 | Data.fromParams({
123 | this.apkLink,
124 | this.author,
125 | this.chapterId,
126 | this.chapterName,
127 | this.collect,
128 | this.courseId,
129 | this.desc,
130 | this.envelopePic,
131 | this.fresh,
132 | this.mId,
133 | this.link,
134 | this.niceDate,
135 | this.origin,
136 | this.projectLink,
137 | this.publishTime,
138 | this.superChapterId,
139 | this.superChapterName,
140 | this.tags,
141 | this.title,
142 | this.type,
143 | this.userId,
144 | this.visible,
145 | this.zan,
146 | });
147 |
148 | Data.fromJson(jsonRes) {
149 | apkLink = jsonRes['apkLink'];
150 | author = jsonRes['author'];
151 | chapterId = jsonRes['chapterId'];
152 | chapterName = jsonRes['chapterName'];
153 | collect = jsonRes['collect'];
154 | courseId = jsonRes['courseId'];
155 | desc = jsonRes['desc'];
156 | envelopePic = jsonRes['envelopePic'];
157 | fresh = jsonRes['fresh'];
158 | mId = jsonRes['id'];
159 | link = jsonRes['link'];
160 | niceDate = jsonRes['niceDate'];
161 | origin = jsonRes['origin'];
162 | projectLink = jsonRes['projectLink'];
163 | publishTime = jsonRes['publishTime'];
164 | superChapterId = jsonRes['superChapterId'];
165 | superChapterName = jsonRes['superChapterName'];
166 | tags = jsonRes['tags'] == null ? null : [];
167 | title = jsonRes['title'];
168 | type = jsonRes['type'];
169 | userId = jsonRes['userId'];
170 | visible = jsonRes['visible'];
171 | zan = jsonRes['zan'];
172 | }
173 |
174 | Map toJson() => {
175 | 'apkLink': apkLink,
176 | 'author': author,
177 | 'chapterId': chapterId,
178 | 'chapterName': chapterName,
179 | 'collect': collect,
180 | 'courseId': courseId,
181 | 'desc': desc,
182 | 'envelopePic': envelopePic,
183 | 'fresh': fresh,
184 | 'id': mId,
185 | 'link': link,
186 | 'niceDate': niceDate,
187 | 'origin': origin,
188 | 'projectLink': projectLink,
189 | 'publishTime': publishTime,
190 | 'superChapterId': superChapterId,
191 | 'superChapterName': superChapterName,
192 | 'tags': tags,
193 | 'title': title,
194 | 'type': type,
195 | 'userId': userId,
196 | 'visible': visible,
197 | 'zan': zan,
198 | };
199 | }
200 |
201 | class Tag {
202 | String name;
203 | String url;
204 |
205 | Tag.fromParams({
206 | this.name,
207 | this.url,
208 | });
209 |
210 | Tag.fromJson(jsonRes) {
211 | name = jsonRes['name'];
212 | url = jsonRes['url'];
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Data/data_banner_bean.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert' show json;
2 |
3 | import 'package:html_unescape/html_unescape.dart';
4 |
5 | class BannerListBean {
6 |
7 | int errorCode;
8 | String errorMsg;
9 | List data;
10 |
11 | BannerListBean.fromParams({this.errorCode, this.errorMsg, this.data});
12 |
13 | factory BannerListBean(jsonStr) => jsonStr == null ? null : jsonStr is String ? new BannerListBean.fromJson(json.decode(jsonStr)) : new BannerListBean.fromJson(jsonStr);
14 |
15 | BannerListBean.fromJson(jsonRes) {
16 | errorCode = jsonRes['errorCode'];
17 | errorMsg = jsonRes['errorMsg'];
18 | data = jsonRes['data'] == null ? null : [];
19 |
20 | for (var dataItem in data == null ? [] : jsonRes['data']){
21 | data.add(dataItem == null ? null : new banner.fromJson(dataItem));
22 | }
23 | }
24 |
25 | @override
26 | String toString() {
27 | return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}';
28 | }
29 | }
30 |
31 | class banner {
32 |
33 | int id;
34 | int isVisible;
35 | int order;
36 | int type;
37 | String desc;
38 | String imagePath;
39 | String title;
40 | String url;
41 |
42 | getName(){
43 | var unescape = new HtmlUnescape();
44 | return unescape.convert(desc);
45 | }
46 |
47 | banner.fromParams({this.id, this.isVisible, this.order, this.type, this.desc, this.imagePath, this.title, this.url});
48 |
49 | banner.fromJson(jsonRes) {
50 | id = jsonRes['id'];
51 | isVisible = jsonRes['isVisible'];
52 | order = jsonRes['order'];
53 | type = jsonRes['type'];
54 | desc = jsonRes['desc'];
55 | imagePath = jsonRes['imagePath'];
56 | title = jsonRes['title'];
57 | url = jsonRes['url'];
58 | }
59 |
60 | @override
61 | String toString() {
62 | return '{"id": $id,"isVisible": $isVisible,"order": $order,"type": $type,"desc": ${desc != null?'${json.encode(desc)}':'null'},"imagePath": ${imagePath != null?'${json.encode(imagePath)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"url": ${url != null?'${json.encode(url)}':'null'}}';
63 | }
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Data/data_key_bean.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert' show json;
2 |
3 | import 'package:html_unescape/html_unescape.dart';
4 |
5 | class KeyBean {
6 | int errorCode;
7 | String errorMsg;
8 | List nodes;
9 |
10 | KeyBean.fromParams({
11 | this.errorCode,
12 | this.errorMsg,
13 | this.nodes,
14 | });
15 |
16 | factory KeyBean(jsonStr) => jsonStr == null
17 | ? null
18 | : jsonStr is String
19 | ? new KeyBean.fromJson(json.decode(jsonStr))
20 | : new KeyBean.fromJson(jsonStr);
21 |
22 | KeyBean.fromJson(jsonRes) {
23 | errorCode = jsonRes['errorCode'];
24 | errorMsg = jsonRes['errorMsg'];
25 | nodes = jsonRes['data'] == null ? null : [];
26 |
27 | for (var node in nodes == null ? [] : jsonRes['data']) {
28 | nodes.add(node == null ? null : new KeyNode.fromJson(node));
29 | }
30 | }
31 |
32 | @override
33 | String toString() {
34 | // TODO: implement toString
35 | return super.toString();
36 | }
37 | }
38 |
39 | class KeyNode {
40 | int mid;
41 | String link;
42 | String name;
43 | int order;
44 | int visible;
45 |
46 | getName(){
47 | var unescape = new HtmlUnescape();
48 | return unescape.convert(name);
49 | }
50 |
51 | KeyNode.fromParams(
52 | {this.mid, this.link, this.name, this.order, this.visible});
53 |
54 | factory KeyNode(jsonStr) => jsonStr == null
55 | ? null
56 | : jsonStr is String
57 | ? new KeyNode.fromJson(json.decode(jsonStr))
58 | : new KeyNode.fromJson(jsonStr);
59 |
60 | KeyNode.fromJson(jsonRes) {
61 | mid = jsonRes['id'];
62 | link = jsonRes['link'];
63 | name = jsonRes['name'];
64 | order = jsonRes['order'];
65 | visible = jsonRes['visible'];
66 | }
67 |
68 | @override
69 | String toString() {
70 | // TODO: implement toString
71 | return super.toString();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Data/data_navi_bean.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert' show json;
2 |
3 | import 'package:douban_movies/WanAndroid/Data/data_article_bean.dart';
4 | import 'package:html_unescape/html_unescape.dart';
5 |
6 | class NaviBean {
7 | int errorCode;
8 | String errorMsg;
9 | List nodes;
10 |
11 | NaviBean.fromParams({
12 | this.errorCode,
13 | this.errorMsg,
14 | this.nodes,
15 | });
16 |
17 | factory NaviBean(jsonStr) => jsonStr == null
18 | ? null
19 | : jsonStr is String
20 | ? new NaviBean.fromJson(json.decode(jsonStr))
21 | : new NaviBean.fromJson(jsonStr);
22 |
23 | NaviBean.fromJson(jsonRes) {
24 | errorCode = jsonRes['errorCode'];
25 | errorMsg = jsonRes['errorMsg'];
26 | nodes = jsonRes['data'] == null ? null : [];
27 |
28 | for (var node in nodes == null ? [] : jsonRes['data']) {
29 | nodes.add(node == null ? null : new NaviNode.fromJson(node));
30 | }
31 | }
32 |
33 | @override
34 | String toString() {
35 | // TODO: implement toString
36 | return super.toString();
37 | }
38 | }
39 |
40 | class NaviNode {
41 | int cid;
42 | String name;
43 | List articles;
44 |
45 | getName(){
46 | var unescape = new HtmlUnescape();
47 | return unescape.convert(name);
48 | }
49 |
50 | NaviNode.fromParams({this.cid, this.name, this.articles});
51 |
52 | factory NaviNode(jsonStr) => jsonStr == null
53 | ? null
54 | : jsonStr is String
55 | ? new NaviNode.fromJson(json.decode(jsonStr))
56 | : new NaviNode.fromJson(jsonStr);
57 |
58 | NaviNode.fromJson(jsonRes) {
59 | cid = jsonRes['cid'];
60 | name = jsonRes['name'];
61 | articles = jsonRes['articles'] == null ? null : [];
62 |
63 | for (var article in articles == null ? [] : jsonRes['articles']) {
64 | articles.add(article == null ? null : new Data.fromJson(article));
65 | }
66 | }
67 |
68 | @override
69 | String toString() {
70 | // TODO: implement toString
71 | return super.toString();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Data/data_person_bean.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert' show json;
2 |
3 | class PersonBean {
4 |
5 | int errorCode;
6 | String errorMsg;
7 | detail data;
8 |
9 | PersonBean.fromParams({this.errorCode, this.errorMsg, this.data});
10 |
11 | factory PersonBean(jsonStr) => jsonStr == null ? null : jsonStr is String ? new PersonBean.fromJson(json.decode(jsonStr)) : new PersonBean.fromJson(jsonStr);
12 |
13 | PersonBean.fromJson(jsonRes) {
14 | errorCode = jsonRes['errorCode'];
15 | errorMsg = jsonRes['errorMsg'];
16 | data = jsonRes['data'] == null ? null : new detail.fromJson(jsonRes['data']);
17 | }
18 |
19 | @override
20 | String toString() {
21 | return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}';
22 | }
23 | }
24 |
25 | class detail {
26 |
27 | int id;
28 | int type;
29 | String email;
30 | String icon;
31 | String password;
32 | String token;
33 | String username;
34 | List chapterTops;
35 | List collectIds;
36 |
37 | detail.fromParams({this.id, this.type, this.email, this.icon, this.password, this.token, this.username, this.chapterTops, this.collectIds});
38 |
39 | detail.fromJson(jsonRes) {
40 | id = jsonRes['id'];
41 | type = jsonRes['type'];
42 | email = jsonRes['email'];
43 | icon = jsonRes['icon'];
44 | password = jsonRes['password'];
45 | token = jsonRes['token'];
46 | username = jsonRes['username'];
47 | chapterTops = jsonRes['chapterTops'] == null ? null : [];
48 |
49 | for (var chapterTopsItem in chapterTops == null ? [] : jsonRes['chapterTops']){
50 | chapterTops.add(chapterTopsItem);
51 | }
52 |
53 | collectIds = jsonRes['collectIds'] == null ? null : [];
54 |
55 | for (var collectIdsItem in collectIds == null ? [] : jsonRes['collectIds']){
56 | collectIds.add(collectIdsItem);
57 | }
58 | }
59 |
60 | @override
61 | String toString() {
62 | return '{"id": $id,"type": $type,"email": ${email != null?'${json.encode(email)}':'null'},"icon": ${icon != null?'${json.encode(icon)}':'null'},"password": ${password != null?'${json.encode(password)}':'null'},"token": ${token != null?'${json.encode(token)}':'null'},"username": ${username != null?'${json.encode(username)}':'null'},"chapterTops": $chapterTops,"collectIds": $collectIds}';
63 | }
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Data/data_tree_bean.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert' show json;
2 | import 'package:html_unescape/html_unescape.dart';
3 |
4 | class TreeBean {
5 | int errorCode;
6 | String errorMsg;
7 | List nodes;
8 |
9 | TreeBean.fromParams(
10 | {this.errorCode, this.errorMsg, this.nodes,});
11 |
12 | factory TreeBean(jsonStr) =>
13 | jsonStr == null ? null : jsonStr is String ? new TreeBean
14 | .fromJson(json.decode(jsonStr)) : new TreeBean.fromJson(
15 | jsonStr);
16 |
17 | TreeBean.fromJson(jsonRes) {
18 | errorCode = jsonRes['errorCode'];
19 | errorMsg = jsonRes['errorMsg'];
20 | nodes = jsonRes['data'] == null ? null : [];
21 |
22 | for (var node in nodes == null ? [] : jsonRes['data']) {
23 | nodes.add(node == null ? null : new Node.fromJson(node));
24 | }
25 | }
26 |
27 | @override
28 | String toString() {
29 | // TODO: implement toString
30 | return super.toString();
31 | }
32 | }
33 |
34 | class Node {
35 |
36 | int courseId;
37 | int mId;
38 | String name;
39 | int order;
40 | int parentChapterId;
41 | bool userControlSetTop;
42 | int visible;
43 | List childNodes;
44 |
45 | getName(){
46 | var unescape = new HtmlUnescape();
47 | return unescape.convert(name);
48 | }
49 |
50 |
51 | Node.fromParams(
52 | {this.courseId, this.mId, this.name, this.order, this.parentChapterId,
53 | this.userControlSetTop, this.visible,this.childNodes});
54 |
55 | factory Node(jsonStr) =>
56 | jsonStr == null ? null : jsonStr is String ? new Node
57 | .fromJson(json.decode(jsonStr)) : new Node.fromJson(
58 | jsonStr);
59 |
60 | Node.fromJson(jsonRes) {
61 | courseId = jsonRes['courseId'];
62 | mId = jsonRes['id'];
63 | name = jsonRes['name'];
64 | order = jsonRes['order'];
65 | parentChapterId = jsonRes['parentChapterId'];
66 | userControlSetTop = jsonRes['userControlSetTop'];
67 | visible = jsonRes['visible'];
68 | childNodes = jsonRes['children'] == null ? null : [];
69 |
70 | for (var childNode in childNodes == null ? [] : jsonRes['children']) {
71 | childNodes.add(childNode == null ? null : new Node.fromJson(childNode));
72 | }
73 | }
74 |
75 | @override
76 | String toString() {
77 | // TODO: implement toString
78 | return super.toString();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Manager/manager_article_base.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/Data/data_article_bean.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:douban_movies/WanAndroid/sp_utils.dart';
4 | import 'dart:convert' show json;
5 |
6 |
7 | class ArticleSaveManager{
8 | static final String KEY_FAVORITE="key_favorite";
9 | static final String KEY_HISTORY="key_history";
10 |
11 | static Future> getSaveList(String key) async{
12 | List dataList=[];
13 | String dataListStr=await SpUtils.getString(key, "");
14 | if(dataListStr==null||dataListStr.isEmpty){
15 | return dataList;
16 | }
17 | List itemStrList=dataListStr.split("-");
18 | if(itemStrList==null){
19 | return dataList;
20 | }
21 | for(int i=0;i _xAnimation;
23 | Animation _yAnimation;
24 |
25 | set XAnimation(Animation value) {
26 | _xAnimation = value;
27 | }
28 |
29 | set YAnimation(Animation value) {
30 | _yAnimation = value;
31 | }
32 | }
33 |
34 | class WavePainter extends BasePainter {
35 | int waveCount;
36 | double waveHeight;
37 | List waveColors;
38 | double circleWidth;
39 | Color circleColor;
40 | Color circleBackgroundColor;
41 |
42 | WavePainter({
43 | this.waveCount = 1,
44 | this.waveHeight,
45 | this.waveColors,
46 | this.circleColor = Colors.blue,
47 | this.circleBackgroundColor = Colors.white,
48 | this.circleWidth = 5.0});
49 |
50 | @override
51 | void paint(Canvas canvas, Size size) {
52 | double width = size.width;
53 | double height = size.height;
54 |
55 | if (waveHeight == null) {
56 | waveHeight = height / 8;
57 | }
58 |
59 | if (waveColors == null) {
60 | waveColors = [
61 | Color.fromARGB(
62 | 100, Colors.blue.red, Colors.blue.green, Colors.blue.blue)
63 | ];
64 | }
65 |
66 | Offset center = new Offset(width / 2, height / 2);
67 | double xMove = width * _xAnimation.value;
68 | double yAnimValue = 0.0;
69 | if (_yAnimation != null) {
70 | yAnimValue = _yAnimation.value;
71 | }
72 | double yMove = height * (1.0 - yAnimValue);
73 | Offset waveCenter = new Offset(xMove, yMove);
74 |
75 |
76 | var paintCircle = new Paint()
77 | ..color = circleColor
78 | ..style = PaintingStyle.stroke
79 | ..strokeWidth = circleWidth;
80 |
81 | canvas.drawCircle(center, min(width, height) / 2, paintCircle);
82 |
83 | List wavePaths = [];
84 |
85 | for (int i = 0; i < waveCount; i++) {
86 | double direction = pow(-1.0, i);
87 | Path path = new Path()
88 | ..moveTo(waveCenter.dx - width, waveCenter.dy)
89 | ..lineTo(waveCenter.dx - width, center.dy + height / 2)
90 | ..lineTo(waveCenter.dx + width, center.dy + height / 2)
91 | ..lineTo(waveCenter.dx + width, waveCenter.dy)
92 | ..quadraticBezierTo(
93 | waveCenter.dx + width * 3 / 4,
94 | waveCenter.dy + waveHeight * direction,
95 | waveCenter.dx + width / 2,
96 | waveCenter.dy)
97 | ..quadraticBezierTo(
98 | waveCenter.dx + width / 4,
99 | waveCenter.dy - waveHeight * direction,
100 | waveCenter.dx,
101 | waveCenter.dy)
102 | ..quadraticBezierTo(
103 | waveCenter.dx - width / 4,
104 | waveCenter.dy + waveHeight * direction,
105 | waveCenter.dx - width / 2,
106 | waveCenter.dy)
107 | ..quadraticBezierTo(
108 | waveCenter.dx - width * 3 / 4,
109 | waveCenter.dy - waveHeight * direction,
110 | waveCenter.dx - width,
111 | waveCenter.dy)
112 | ..close();
113 |
114 | wavePaths.add(path);
115 | }
116 | var paint = new Paint()
117 | ..color = circleBackgroundColor
118 | ..style = PaintingStyle.fill;
119 |
120 | canvas.saveLayer(
121 | Rect.fromCircle(center: center, radius: min(width, height) / 2), paint);
122 | canvas.drawCircle(center, min(width, height) / 2, paint);
123 | paint
124 | ..blendMode = BlendMode.srcATop
125 | ..style = PaintingStyle.fill
126 | ..strokeWidth = 2.0;
127 | for (int i = 0; i < wavePaths.length; i++) {
128 | if (waveColors.length >= wavePaths.length) {
129 | paint.color = waveColors[i];
130 | } else {
131 | paint.color = waveColors[0];
132 | }
133 | canvas.drawPath(wavePaths[i], paint);
134 | }
135 | paint.blendMode = BlendMode.src;
136 |
137 | canvas.restore();
138 |
139 | TextPainter tp = TextPainter(
140 | text: TextSpan(
141 | text: '${(yAnimValue * 100.0).toStringAsFixed(0)}%',
142 | style: TextStyle(
143 | fontSize: 60.0,
144 | color: Color.fromARGB(
145 | 100, Colors.blue.red, Colors.blue.green, Colors.blue.blue),
146 | fontWeight: FontWeight.bold,
147 | )),
148 | textDirection: TextDirection.rtl)
149 | ..layout();
150 |
151 | tp.paint(
152 | canvas, Offset(center.dx - tp.width / 2, center.dy - tp.height / 2));
153 | }
154 |
155 | @override
156 | bool shouldRepaint(CustomPainter oldDelegate) {
157 | return oldDelegate != this;
158 | }
159 |
160 | }
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/WriteRoundEye/Gy2Wht.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class Gy2Wht {
4 | double outRadius = 100.0;
5 |
6 | //中心的半径
7 | double _centerRadius = 15.0;
8 |
9 | int progress;
10 |
11 | //绘制
12 | void drawPonit(Canvas canvas, Size size, int progress) {
13 | Paint _paint = new Paint()
14 | ..color = Colors.black
15 | ..style = PaintingStyle.stroke
16 | ..strokeCap = StrokeCap.round
17 | ..strokeWidth = 3.0;
18 |
19 | double width = size.width;
20 | double height = size.height;
21 | Offset center = new Offset(width / 2, height / 2);
22 | //绘制红色
23 | _paint.color = Colors.red;
24 | _paint.style = PaintingStyle.fill;
25 | canvas.drawCircle(center, outRadius, _paint);
26 | //绘制外圈
27 | _paint.color = Colors.black;
28 | _paint.style = PaintingStyle.stroke;
29 | _paint.strokeCap = StrokeCap.round;
30 | _paint.strokeWidth = 5.0;
31 | canvas.drawCircle(center, outRadius, _paint);
32 |
33 | //内环越来越收拢
34 | double centerRadius;
35 | centerRadius = _centerRadius + (outRadius - _centerRadius) * progress / 360;
36 |
37 | //绘制中心
38 | _paint.style = PaintingStyle.fill;
39 | canvas.drawCircle(center, centerRadius, _paint);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/WriteRoundEye/GyWriteRoundEye.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class GyWriteRoundEye {
6 | double outRadius = 100.0;
7 | double whtRadius = 100.0;
8 |
9 | //圆环的半径
10 | double _initRadius = 60.0;
11 |
12 | //圆环的厚度
13 | double initGap = 10.0;
14 |
15 | //中心的半径
16 | double centerRadius = 15.0;
17 |
18 | //勾玉的大小
19 | double _gyRadius = 10;
20 | int _initCount = 180;
21 | int progress;
22 |
23 | //绘制
24 | void drawPonit(Canvas canvas, Size size, int progress) {
25 | Paint _paint = new Paint()
26 | ..color = Colors.black
27 | ..style = PaintingStyle.stroke
28 | ..strokeCap = StrokeCap.round
29 | ..strokeWidth = 3.0;
30 |
31 | double width = size.width;
32 | double height = size.height;
33 | Offset center = new Offset(width / 2, height / 2);
34 | //绘制红色
35 | _paint.color = Colors.red;
36 | _paint.style = PaintingStyle.fill;
37 | canvas.drawCircle(center, outRadius, _paint);
38 | //绘制外圈
39 | _paint.color = Colors.black;
40 | _paint.style = PaintingStyle.stroke;
41 | _paint.strokeCap = StrokeCap.round;
42 | _paint.strokeWidth = 5.0;
43 | canvas.drawCircle(center, outRadius, _paint);
44 |
45 | //内环越来越收拢
46 | double initRadius, gyRadius, initCount;
47 | initRadius = _initRadius * (360 - progress) / 360;
48 | //勾玉越来越小,缩小的速率毕内环要慢一倍
49 | gyRadius = _gyRadius * (360 - 0.7 * progress) / 360;
50 | //内圈的齿数越来越小
51 | initCount = _initCount * (360 - 0.7 * progress) / 360;
52 |
53 | //绘制内圈
54 | Offset start, end;
55 | _paint.strokeWidth = 1;
56 | for (int i = 0; i < initCount; i++) {
57 | start = Offset(initRadius * sin(2 * pi * (i + 1) / initCount) + center.dx,
58 | initRadius * cos(2 * pi * (i + 1) / initCount) + center.dy);
59 | end = Offset(
60 | (initRadius + initGap) * sin(2 * pi * (i + 1) / initCount) +
61 | center.dx,
62 | (initRadius + initGap) * cos(2 * pi * (i + 1) / initCount) +
63 | center.dy);
64 | canvas.drawLine(start, end, _paint);
65 | }
66 | canvas.save();
67 | canvas.translate(width / 2, height / 2);
68 | //绘制3个逗号
69 | double gyCenterGap = initRadius;
70 | Offset gyStart;
71 | [1, 2, 3].forEach((a) {
72 | double offsetAngle = 2 * a * pi / 3 + progress * 2 * pi / 360;
73 |
74 | gyStart = new Offset((gyCenterGap - gyRadius) * sin(offsetAngle),
75 | (gyCenterGap - gyRadius) * cos(offsetAngle));
76 |
77 | _paint.style = PaintingStyle.fill;
78 |
79 | Path gyPath = new Path();
80 |
81 | Offset p1 = new Offset((gyCenterGap + 3 * gyRadius) * sin(offsetAngle),
82 | (gyCenterGap + 3 * gyRadius) * cos(offsetAngle));
83 |
84 | Offset p2 = new Offset((gyCenterGap + 2 * gyRadius) * sin(offsetAngle),
85 | (gyCenterGap + 2 * gyRadius) * cos(offsetAngle));
86 |
87 | gyPath
88 | ..lineTo(gyStart.dx, gyStart.dy)
89 | ..arcToPoint(p1,
90 | radius: Radius.circular(1.5 * gyRadius),
91 | largeArc: true,
92 | clockwise: false)
93 | ..arcToPoint(p2,
94 | radius: Radius.circular(0.5 * gyRadius),
95 | largeArc: true,
96 | clockwise: true)
97 | ..arcToPoint(gyStart,
98 | radius: Radius.circular(1 * gyRadius),
99 | largeArc: true,
100 | clockwise: false);
101 |
102 | canvas.drawPath(gyPath, _paint);
103 | });
104 | canvas.restore();
105 | //绘制中心
106 | _paint.style = PaintingStyle.fill;
107 | canvas.drawCircle(center, centerRadius, _paint);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/WriteRoundEye/WhtWriteRoundEye.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class WhtWriteRoundEye {
6 | double outRadius = 100.0;
7 | double _whtRadius = 100.0;
8 |
9 | //圆环的半径
10 | double initRadius = 60.0;
11 |
12 | //圆环的厚度
13 | double initGap = 10.0;
14 |
15 | //中心的半径
16 | double centerRadius = 15.0;
17 |
18 | //勾玉的大小
19 | double gyRadius = 10;
20 | int initCount = 180;
21 | int progress;
22 |
23 | //绘制
24 | void drawPonit(Canvas canvas, Size size, int progress) {
25 | Paint paint = new Paint()
26 | ..color = Colors.black
27 | ..style = PaintingStyle.stroke
28 | ..strokeCap = StrokeCap.round
29 | ..strokeWidth = 3.0;
30 |
31 | double width = size.width;
32 | double height = size.height;
33 | Offset center = new Offset(width / 2, height / 2);
34 | //绘制红色
35 | paint.color = Colors.black;
36 | paint.style = PaintingStyle.fill;
37 | canvas.drawCircle(center, outRadius, paint);
38 | //绘制外圈
39 | paint.color = Colors.black;
40 | paint.style = PaintingStyle.stroke;
41 | paint.strokeCap = StrokeCap.round;
42 | paint.strokeWidth = 5.0;
43 | canvas.drawCircle(center, outRadius, paint);
44 |
45 | canvas.save();
46 | //先绘制万花筒写轮眼的竖直部分
47 | canvas.translate(width / 2, height / 2);
48 | paint.strokeWidth = 2.0;
49 |
50 | //内环越来越收拢
51 | double whtRadius;
52 | whtRadius = _whtRadius * progress / 360;
53 |
54 | paint.color = Colors.red;
55 | paint.style = PaintingStyle.fill;
56 |
57 | [1, 2, 3].forEach((a) {
58 | double offsetAngle = 2 * a * pi / 3 + progress * 2 * pi / 360;
59 | Offset start = new Offset(
60 | whtRadius * sin(offsetAngle), whtRadius * cos(offsetAngle));
61 | Offset end = new Offset(
62 | -1 * whtRadius * sin(offsetAngle), -1 * whtRadius * cos(offsetAngle));
63 | Path path = new Path();
64 | path
65 | ..moveTo(start.dx, start.dy)
66 | ..arcToPoint(end,
67 | radius: Radius.circular(1.5 * whtRadius), clockwise: false)
68 | ..arcToPoint(start,
69 | radius: Radius.circular(1.5 * whtRadius), clockwise: false);
70 | canvas.drawPath(path, paint);
71 | });
72 | paint.style = PaintingStyle.stroke;
73 | paint.color = Colors.black;
74 | [1, 2, 3].forEach((a) {
75 | double offsetAngle = 2 * a * pi / 3 + progress * 2 * pi / 360;
76 | Offset start = new Offset(
77 | whtRadius * sin(offsetAngle), whtRadius * cos(offsetAngle));
78 | Offset end = new Offset(
79 | -1 * whtRadius * sin(offsetAngle), -1 * whtRadius * cos(offsetAngle));
80 | Path path = new Path();
81 |
82 | path
83 | ..moveTo(start.dx, start.dy)
84 | ..arcToPoint(end,
85 | radius: Radius.circular(1.5 * whtRadius), clockwise: false)
86 | ..arcToPoint(start,
87 | radius: Radius.circular(1.5 * whtRadius), clockwise: false);
88 | canvas.drawPath(path, paint);
89 | });
90 | canvas.restore();
91 |
92 | //绘制中心
93 | paint.style = PaintingStyle.fill;
94 | canvas.drawCircle(center, centerRadius, paint);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/WriteRoundEye/painter_write_round_eye.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:douban_movies/WanAndroid/Progress/painter/WriteRoundEye/Gy2Wht.dart';
4 | import 'package:douban_movies/WanAndroid/Progress/painter/WriteRoundEye/GyWriteRoundEye.dart';
5 | import 'package:douban_movies/WanAndroid/Progress/painter/WriteRoundEye/WhtWriteRoundEye.dart';
6 | import 'package:flutter/material.dart';
7 |
8 | class WriteRoundEyePainter extends CustomPainter {
9 | int progress;
10 | GyWriteRoundEye gyWriteRoundEye;
11 | WhtWriteRoundEye whtWriteRoundEye;
12 | Gy2Wht gy2wht;
13 |
14 | WriteRoundEyePainter(this.progress,
15 | {this.gyWriteRoundEye, this.whtWriteRoundEye, this.gy2wht});
16 |
17 | @override
18 | void paint(Canvas canvas, Size size) {
19 | if ((progress / 360).floor() == 0) {
20 | gyWriteRoundEye.drawPonit(canvas, size, progress % 360);
21 | } else if ((progress / 360).floor() == 1) {
22 | gy2wht.drawPonit(canvas, size, progress % 360);
23 | } else {
24 | whtWriteRoundEye.drawPonit(canvas, size, progress % 360);
25 | }
26 | }
27 |
28 | @override
29 | bool shouldRepaint(CustomPainter oldDelegate) {
30 | return oldDelegate != this;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/WriteRoundEye/widget_write_round_eye.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/Progress/painter/WriteRoundEye/Gy2Wht.dart';
2 | import 'package:douban_movies/WanAndroid/Progress/painter/WriteRoundEye/GyWriteRoundEye.dart';
3 | import 'package:douban_movies/WanAndroid/Progress/painter/WriteRoundEye/WhtWriteRoundEye.dart';
4 | import 'package:douban_movies/WanAndroid/Progress/painter/WriteRoundEye/painter_write_round_eye.dart';
5 | import 'package:flutter/material.dart';
6 |
7 | class TestWidget extends StatelessWidget {
8 | @override
9 | Widget build(BuildContext context) {
10 | // TODO: implement build
11 | return Center(
12 | child: Container(
13 | width: 300.0,
14 | height: 300.0,
15 | child: WriteRoundEyeWidget(
16 | width: 300.0,
17 | height: 300.0,
18 | ),
19 | ),
20 | );
21 | }
22 | }
23 |
24 | class WriteRoundEyeWidget extends StatefulWidget {
25 | final width;
26 | final height;
27 | int progress = 0;
28 | GyWriteRoundEye gyEye = new GyWriteRoundEye();
29 | WhtWriteRoundEye whtEye = new WhtWriteRoundEye();
30 | Gy2Wht gy2wht = new Gy2Wht();
31 |
32 | WriteRoundEyeWidget({Key key, this.width, this.height}) : super(key: key);
33 |
34 | @override
35 | _WriteRoundEyeWidgetState createState() =>
36 | new _WriteRoundEyeWidgetState(width, height);
37 | }
38 |
39 | class _WriteRoundEyeWidgetState extends State
40 | with TickerProviderStateMixin {
41 | AnimationController xController;
42 | Animation xAnimation;
43 | double _width = 200;
44 | double _height = 200;
45 |
46 | _WriteRoundEyeWidgetState(double width, double height) {
47 | _width = width ?? _width;
48 | _height = height ?? _height;
49 | }
50 |
51 | @override
52 | void initState() {
53 | // TODO: implement initState
54 | super.initState();
55 | xController = new AnimationController(
56 | vsync: this, duration: Duration(milliseconds: 3000));
57 | xAnimation = new Tween(begin: 0.0, end: 1.0).animate(xController);
58 | xAnimation.addListener(_change);
59 | doDelay(xController, 0);
60 | }
61 |
62 | @override
63 | Widget build(BuildContext context) {
64 | if ((widget.progress / 360).floor() == 0) {
65 | widget.progress++;
66 | } else if ((widget.progress / 360).floor() == 1) {
67 | widget.progress += 10;
68 | } else {
69 | widget.progress += 2;
70 | }
71 | if (widget.progress > 1079) {
72 | widget.progress = 1080 - 1;
73 | }
74 |
75 | print("progress=${widget.progress}");
76 | return Container(
77 | child: new CustomPaint(
78 | painter: WriteRoundEyePainter(widget.progress,
79 | gyWriteRoundEye: widget.gyEye,
80 | whtWriteRoundEye: widget.whtEye,
81 | gy2wht: widget.gy2wht),
82 | ),
83 | );
84 | }
85 |
86 | void _change() {
87 | setState(() {});
88 | }
89 |
90 | void doDelay(AnimationController controller, int delay) async {
91 | Future.delayed(Duration(milliseconds: delay), () {
92 | try {
93 | controller..repeat();
94 | } catch (e) {}
95 | });
96 | }
97 |
98 | @override
99 | void dispose() {
100 | xController.dispose();
101 | xAnimation.removeListener(_change);
102 | super.dispose();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/painter_base.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | abstract class BasePainter extends CustomPainter{
4 | Animation _xAnimation;
5 | Animation _yAnimation;
6 |
7 | set XAnimation(Animation value) {
8 | _xAnimation = value;
9 | }
10 |
11 | set YAnimation(Animation value) {
12 | _yAnimation = value;
13 | }
14 |
15 | Animation get YAnimation => _yAnimation;
16 |
17 | Animation get XAnimation => _xAnimation;
18 |
19 | }
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/painter_circle.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:douban_movies/WanAndroid/Progress/painter/painter_base.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class CirclePainter extends BasePainter {
7 | List waveColors;
8 | double circleWidth;
9 | double circleGap;
10 | Color circleColor;
11 | Color progressColor;
12 |
13 | CirclePainter(
14 | {this.waveColors,
15 | this.circleColor = Colors.blue,
16 | this.progressColor = Colors.blue,
17 | this.circleWidth = 1.0,
18 | this.circleGap = 1.0});
19 |
20 | @override
21 | void paint(Canvas canvas, Size size) {
22 | double width = size.width;
23 | double height = size.height;
24 | double radius = min(width, height) / 2 - circleWidth - circleGap;
25 | double scale = YAnimation.value;
26 | double degree = 2 * pi * scale;
27 | Offset center = new Offset(width / 2, height / 2);
28 |
29 | var circlePaint = new Paint()
30 | ..color = circleColor
31 | ..style = PaintingStyle.stroke
32 | ..strokeWidth = circleWidth;
33 |
34 | canvas.drawCircle(center, min(width, height) / 2, circlePaint);
35 |
36 | var progressPaint = new Paint()
37 | ..color = progressColor
38 | ..style = PaintingStyle.fill
39 | ..strokeWidth = circleWidth;
40 |
41 | if (scale == 1) {
42 | canvas.saveLayer(
43 | Rect.fromCircle(center: center, radius: min(width, height) / 2),
44 | progressPaint);
45 | canvas.drawCircle(center, radius, progressPaint);
46 | canvas.restore();
47 | return;
48 | }
49 |
50 | List wavePaths = [];
51 |
52 | Path path = new Path()
53 | ..moveTo(center.dx, center.dy)
54 | ..lineTo(center.dx, center.dy + radius)
55 | ..arcTo(Rect.fromCircle(center: center, radius: radius), 0, degree, true)
56 | ..lineTo(center.dy, center.dy)
57 | ..close();
58 |
59 | wavePaths.add(path);
60 | canvas.saveLayer(
61 | Rect.fromCircle(center: center, radius: min(width, height) / 2),
62 | progressPaint);
63 | canvas.drawPath(path, progressPaint);
64 | canvas.restore();
65 | }
66 |
67 | @override
68 | bool shouldRepaint(CustomPainter oldDelegate) {
69 | return oldDelegate != this;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/painter_circle_snapchat.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:douban_movies/WanAndroid/Progress/painter/painter_base.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class SnapchatCirclePainter extends BasePainter {
7 | double circleWidth;
8 | double circleGap;
9 | Color circleColor;
10 | Color progressColor;
11 |
12 | SnapchatCirclePainter(
13 | {this.circleColor = Colors.blue,
14 | this.progressColor = Colors.blue,
15 | this.circleWidth = 1.0,
16 | this.circleGap = 1.0});
17 |
18 | @override
19 | void paint(Canvas canvas, Size size) {
20 | double width = size.width;
21 | double height = size.height;
22 | double radius = min(width, height) / 2 - circleWidth - circleGap;
23 |
24 | double scale = XAnimation.value;
25 | double rotateDegree = 2 * pi * scale;
26 |
27 | Offset center = new Offset(width / 2, height / 2);
28 |
29 | var circlePaint = new Paint()
30 | ..color = circleColor
31 | ..style = PaintingStyle.stroke
32 | ..strokeWidth = circleWidth
33 | ..strokeCap = StrokeCap.round;
34 |
35 | canvas.save();
36 | // canvas.translate(width / 2, height / 2);
37 | // canvas.rotate(rotateDegree);
38 |
39 | canvas.drawArc(
40 | Rect.fromCircle(center: center, radius: min(width, height) / 2),
41 | 0 + rotateDegree,
42 | 1.5 * pi,
43 | false,
44 | circlePaint);
45 |
46 | canvas.restore();
47 |
48 | var progressPaint = new Paint()
49 | ..color = progressColor
50 | ..style = PaintingStyle.stroke
51 | ..strokeWidth = circleWidth
52 | ..isAntiAlias = true
53 | ..strokeCap = StrokeCap.round;
54 |
55 | canvas.drawArc(Rect.fromCircle(center: center, radius: radius),
56 | 0 - rotateDegree, 1.5 * pi, false, progressPaint);
57 | //
58 | // List wavePaths = [];
59 | // Path path = new Path()
60 | // ..moveTo(center.dx + radius * cos(rotateDegree),
61 | // center.dy + radius * sin(rotateDegree))
62 | // ..arcTo(Rect.fromCircle(center: center, radius: radius), 0,
63 | // 1.5 * pi + rotateDegree, false)
64 | // ..close();
65 | //
66 | // wavePaths.add(path);
67 | //
68 | // canvas.saveLayer(
69 | // Rect.fromCircle(center: center, radius: min(width, height) / 2),
70 | // progressPaint);
71 | // canvas.drawPath(path, progressPaint);
72 | // canvas.restore();
73 | }
74 |
75 | @override
76 | bool shouldRepaint(CustomPainter oldDelegate) {
77 | return oldDelegate != this;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/painter_line_four.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/Progress/painter/painter_base.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class FourLinePainter extends BasePainter {
5 | double gap;
6 | List lineColors;
7 | List baseHightScales;
8 |
9 | FourLinePainter({
10 | this.gap = 0,
11 | this.lineColors = const [
12 | Colors.green,
13 | Colors.red,
14 | Colors.blue,
15 | Colors.yellow,
16 | ],
17 | this.baseHightScales = const [
18 | 0.1,
19 | 0.6,
20 | 0.3,
21 | 0.8,
22 | ],
23 | });
24 |
25 | @override
26 | void paint(Canvas canvas, Size size) {
27 | double width = size.width;
28 | double height = size.height;
29 |
30 | int count = lineColors.length;
31 | double lineWidth = (width - count * gap) / count;
32 |
33 | var bgPainter = new Paint()
34 | ..color = Colors.grey
35 | ..style = PaintingStyle.fill
36 | ..strokeWidth = lineWidth
37 | ..strokeCap = StrokeCap.round;
38 |
39 | canvas.drawRect(
40 | new Rect.fromPoints(new Offset(0.0, 0.0), new Offset(width, height)),
41 | bgPainter);
42 |
43 | double scale = XAnimation.value;
44 |
45 | for (int i = 0; i < count; i++) {
46 | var painter = new Paint()
47 | ..color = lineColors[i]
48 | ..style = PaintingStyle.stroke
49 | ..strokeWidth = lineWidth
50 | ..strokeCap = StrokeCap.round;
51 |
52 | Offset start =
53 | new Offset(width / (count * 2) + width * i / count, height);
54 |
55 | double lastScale = scale + baseHightScales[i];
56 | if (lastScale > 2.0) {
57 | lastScale = lastScale - 2;
58 | } else if (lastScale > 1.0) {
59 | lastScale = 2 - lastScale;
60 | }
61 |
62 | Offset end = new Offset(
63 | width / (count * 2) + width * i / count, height - lastScale * height);
64 | canvas.drawLine(start, end, painter);
65 | }
66 | }
67 |
68 | @override
69 | bool shouldRepaint(CustomPainter oldDelegate) {
70 | return oldDelegate != this;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/painter_progress_text.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/Progress/painter/painter_base.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class TextProgressPainter extends BasePainter {
5 | Color progressColor;
6 | TextStyle textStyle;
7 |
8 | TextProgressPainter({this.progressColor, this.textStyle});
9 |
10 | @override
11 | void paint(Canvas canvas, Size size) {
12 | double width = size.width;
13 | double height = size.height;
14 |
15 | if (textStyle == null) {
16 | textStyle = new TextStyle(
17 | color: Colors.yellow,
18 | // shadows: [
19 | // Shadow(color: Colors.grey, offset: Offset(5.0, 5.0), blurRadius: 5.0)
20 | // ],
21 |
22 | fontSize: 80.0,
23 | );
24 | }
25 | TextPainter tp = TextPainter(
26 | text: TextSpan(
27 | text: '${(YAnimation.value * 100.0).toStringAsFixed(0)}%',
28 | style: textStyle),
29 | textDirection: TextDirection.rtl)
30 | ..layout();
31 |
32 | var baseLineHight =
33 | tp.computeDistanceToActualBaseline(TextBaseline.alphabetic);
34 |
35 | print('baseLine:$baseLineHight\nheight:${tp.height}');
36 |
37 | double textHeight = tp.height;
38 |
39 | Offset center = new Offset(width / 2, height / 2);
40 | double xMove = width * XAnimation.value;
41 | double yAnimValue = 0.0;
42 | if (YAnimation != null) {
43 | yAnimValue = YAnimation.value;
44 | }
45 |
46 | double yMove = height * (1.0 - yAnimValue);
47 | Offset waveCenter = new Offset(xMove, yMove);
48 |
49 | Path path = new Path()
50 | ..moveTo(0, height / 2)
51 | ..lineTo(width, height / 2)
52 | ..close();
53 |
54 | var paint = new Paint()
55 | ..color = Colors.black
56 | ..style = PaintingStyle.fill;
57 |
58 | canvas.drawLine(Offset(0, height / 2 + baseLineHight / 2),
59 | Offset(width, height / 2 + baseLineHight / 2), paint);
60 |
61 | // canvas.saveLayer(
62 | // Rect.fromCircle(center: center, radius: min(width, height) / 2), paint);
63 | paint
64 | ..blendMode = BlendMode.srcATop
65 | ..style = PaintingStyle.fill
66 | ..strokeWidth = 2.0
67 | ..color = Colors.black;
68 | tp.paint(
69 | canvas, Offset(center.dx - tp.width / 2, center.dy - tp.height / 2));
70 |
71 | canvas.drawPath(path, paint);
72 | // canvas.restore();
73 | }
74 |
75 | @override
76 | bool shouldRepaint(CustomPainter oldDelegate) {
77 | return oldDelegate != this;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/painter_wave.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:douban_movies/WanAndroid/Progress/painter/painter_base.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class WavePainter extends BasePainter {
7 | int waveCount;
8 | int crestCount;
9 | double waveHeight;
10 | List waveColors;
11 | double circleWidth;
12 | Color circleColor;
13 | Color circleBackgroundColor;
14 | bool showProgressText;
15 | TextStyle textStyle;
16 |
17 | WavePainter(
18 | {this.waveCount = 1,
19 | this.crestCount = 2,
20 | this.waveHeight,
21 | this.waveColors,
22 | this.circleColor = Colors.grey,
23 | this.circleBackgroundColor = Colors.white,
24 | this.circleWidth = 5.0,
25 | this.showProgressText = true,
26 | this.textStyle = const TextStyle(
27 | fontSize: 60.0,
28 | color: Colors.blue,
29 | fontWeight: FontWeight.bold,
30 | shadows: [
31 | Shadow(color: Colors.grey, offset: Offset(5.0, 5.0), blurRadius: 5.0)
32 | ],
33 | )});
34 |
35 | @override
36 | void paint(Canvas canvas, Size size) {
37 | double width = size.width;
38 | double height = size.height;
39 |
40 | if (waveHeight == null) {
41 | waveHeight = height / 8;
42 | height = height + waveHeight;
43 | }
44 |
45 | if (waveColors == null) {
46 | waveColors = [
47 | Color.fromARGB(
48 | 100, Colors.blue.red, Colors.blue.green, Colors.blue.blue)
49 | ];
50 | }
51 |
52 | Offset center = new Offset(width / 2, height / 2);
53 | double xMove = width * XAnimation.value;
54 | double yAnimValue = 0.0;
55 | if (YAnimation != null) {
56 | yAnimValue = YAnimation.value;
57 | }
58 | double yMove = height * (1.0 - yAnimValue);
59 | Offset waveCenter = new Offset(xMove, yMove);
60 |
61 | var paintCircle = new Paint()
62 | ..color = Colors.grey
63 | ..style = PaintingStyle.fill
64 | ..strokeWidth = circleWidth
65 | ..maskFilter = MaskFilter.blur(BlurStyle.inner, 5.0);
66 |
67 | canvas.drawCircle(center, min(width, height) / 2, paintCircle);
68 |
69 | List wavePaths = [];
70 |
71 | for (int index = 0; index < waveCount; index++) {
72 | double direction = pow(-1.0, index);
73 | Path path = new Path()
74 | ..moveTo(waveCenter.dx - width, waveCenter.dy)
75 | ..lineTo(waveCenter.dx - width, center.dy + height / 2)
76 | ..lineTo(waveCenter.dx + width, center.dy + height / 2)
77 | ..lineTo(waveCenter.dx + width, waveCenter.dy);
78 |
79 | for (int i = 0; i < 2; i++) {
80 | for (int j = 0; j < crestCount; j++) {
81 | double a = pow(-1.0, j);
82 | path
83 | ..quadraticBezierTo(
84 | waveCenter.dx +
85 | width * (1 - i - (1 + 2 * j) / (2 * crestCount)),
86 | waveCenter.dy + waveHeight * a * direction,
87 | waveCenter.dx +
88 | width * (1 - i - (2 + 2 * j) / (2 * crestCount)),
89 | waveCenter.dy);
90 | }
91 | }
92 |
93 | path..close();
94 |
95 | wavePaths.add(path);
96 | }
97 | var paint = new Paint()
98 | ..color = circleBackgroundColor
99 | ..style = PaintingStyle.fill
100 | ..maskFilter = MaskFilter.blur(BlurStyle.inner, 5.0);
101 |
102 | canvas.saveLayer(
103 | Rect.fromCircle(center: center, radius: min(width, height) / 2), paint);
104 |
105 | canvas.drawCircle(center, min(width, height) / 2, paint);
106 |
107 | paint
108 | ..blendMode = BlendMode.srcATop
109 | ..style = PaintingStyle.fill
110 | ..strokeWidth = 2.0
111 | ..maskFilter = MaskFilter.blur(BlurStyle.inner, 10.0);
112 |
113 | for (int i = 0; i < wavePaths.length; i++) {
114 | if (waveColors.length >= wavePaths.length) {
115 | paint.color = waveColors[i];
116 | } else {
117 | paint.color = waveColors[0];
118 | }
119 | canvas.drawPath(wavePaths[i], paint);
120 | }
121 | // paint.blendMode = BlendMode.srcATop;
122 | if (showProgressText) {
123 | TextPainter tp = TextPainter(
124 | text: TextSpan(
125 | text: '${(yAnimValue * 100.0).toStringAsFixed(0)}%',
126 | style: textStyle),
127 | textDirection: TextDirection.rtl)
128 | ..layout();
129 |
130 | tp.paint(
131 | canvas, Offset(center.dx - tp.width / 2, center.dy - tp.height / 2));
132 | }
133 | canvas.restore();
134 | }
135 |
136 | @override
137 | bool shouldRepaint(CustomPainter oldDelegate) {
138 | return oldDelegate != this;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/rainDrop/painter_rain_drop.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/Progress/painter/rainDrop/point_rain_drop.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class RainDropPainter extends CustomPainter {
5 | List rainList = List();
6 | // Paint _paint = new Paint()
7 | // ..style = PaintingStyle.stroke
8 | // ..strokeWidth = 1.0
9 | // ..strokeCap = StrokeCap.round;
10 |
11 | RainDropPainter({@required this.rainList});
12 |
13 | @override
14 | void paint(Canvas canvas, Size size) {
15 | double width = size.width;
16 | double height = size.height;
17 |
18 | var bgPainter = new Paint()
19 | ..color = Colors.black87
20 | ..style = PaintingStyle.fill;
21 |
22 | //绘制背景
23 | canvas.drawRect(
24 | new Rect.fromPoints(new Offset(0.0, 0.0), new Offset(width, height)),
25 | bgPainter);
26 |
27 | rainList.forEach((rain) {
28 | rain.drawPonit(canvas);
29 | });
30 |
31 | rainList.removeWhere((rain) {
32 | return !rain.isVaild();
33 | });
34 | }
35 |
36 | @override
37 | bool shouldRepaint(CustomPainter oldDelegate) {
38 | return oldDelegate != this;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/rainDrop/point_rain_drop.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | /**
6 | * 定义一个雨点类
7 | * 功能:
8 | * - 在给定位置的时候,绘制对应的雨点
9 | * - 具有自己的动画控制
10 | */
11 | class RainDropPoint {
12 | Offset offset;
13 | final double MAX_RADIUS = 30.0;
14 | double radius = 0.0;
15 | Paint _paint;
16 | Color _color;
17 |
18 | RainDropPoint({this.offset}) {
19 | Random random = new Random();
20 | _color = Color.fromARGB(
21 | 255, random.nextInt(255), random.nextInt(255), random.nextInt(255));
22 | _paint = new Paint()
23 | ..style = PaintingStyle.stroke
24 | ..strokeWidth = 1.0
25 | ..strokeCap = StrokeCap.round;
26 | }
27 |
28 | //绘制
29 | void drawPonit(Canvas canvas) {
30 | int alpha = (255 * (MAX_RADIUS - radius) / MAX_RADIUS).toInt();
31 | _paint.color = Color.fromARGB(alpha, _color.red, _color.green, _color.blue);
32 | canvas.drawCircle(offset, radius, _paint);
33 | radius += 0.5;
34 | }
35 |
36 | //是否有效,无效则隐藏
37 | bool isVaild() {
38 | return radius < MAX_RADIUS;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter/rainDrop/widget_rain_drop.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:douban_movies/WanAndroid/Progress/painter/rainDrop/painter_rain_drop.dart';
4 | import 'package:douban_movies/WanAndroid/Progress/painter/rainDrop/point_rain_drop.dart';
5 | import 'package:flutter/material.dart';
6 |
7 | class TestWidget extends StatelessWidget {
8 | @override
9 | Widget build(BuildContext context) {
10 | // TODO: implement build
11 | return Center(
12 | child: Container(
13 | width: 300.0,
14 | height: 300.0,
15 | child: RainDropWidget(
16 | width: 300.0,
17 | height: 300.0,
18 | ),
19 | ),
20 | );
21 | }
22 | }
23 |
24 | class RainDropWidget extends StatefulWidget {
25 | List rainList = List();
26 | final width;
27 | final height;
28 |
29 | RainDropWidget({Key key, this.width, this.height}) : super(key: key);
30 |
31 | @override
32 | _RainDropWidgetState createState() => new _RainDropWidgetState(width, height);
33 | }
34 |
35 | class _RainDropWidgetState extends State
36 | with TickerProviderStateMixin {
37 | AnimationController xController;
38 | Animation xAnimation;
39 | AnimationController rainController;
40 | Animation rainAnimation;
41 | double _width = 200;
42 | double _height = 200;
43 |
44 | _RainDropWidgetState(double width, double height) {
45 | _width = width ?? _width;
46 | _height = height ?? _height;
47 | }
48 |
49 | @override
50 | void initState() {
51 | // TODO: implement initState
52 | super.initState();
53 | xController = new AnimationController(
54 | vsync: this, duration: Duration(milliseconds: 3000));
55 | xAnimation = new Tween(begin: 0.0, end: 1.0).animate(xController);
56 | xAnimation.addListener(_change);
57 |
58 | rainController = new AnimationController(
59 | vsync: this, duration: Duration(milliseconds: 100000));
60 | rainAnimation = new Tween(begin: 0.0, end: 1.0).animate(rainController);
61 | rainAnimation.addListener(_rainDrop);
62 | doDelay(rainController, 0);
63 | }
64 |
65 | @override
66 | Widget build(BuildContext context) {
67 | return Container(
68 | child: GestureDetector(
69 | onTapUp: (tapUp) {
70 | RenderBox getBox = context.findRenderObject();
71 | var localOffset = getBox.globalToLocal(tapUp.globalPosition);
72 | print("w: ${localOffset.dx},h: ${localOffset.dy}");
73 | var rainDrop =
74 | RainDropPoint(offset: new Offset(localOffset.dx, localOffset.dy));
75 | addRain(rainDrop);
76 | },
77 | onHorizontalDragUpdate: (hMove) {
78 | RenderBox getBox = context.findRenderObject();
79 | var localOffset = getBox.globalToLocal(hMove.globalPosition);
80 | var rainDrop =
81 | RainDropPoint(offset: new Offset(localOffset.dx, localOffset.dy));
82 | addRain(rainDrop);
83 | },
84 | onVerticalDragUpdate: (hMove) {
85 | RenderBox getBox = context.findRenderObject();
86 | var localOffset = getBox.globalToLocal(hMove.globalPosition);
87 | var rainDrop =
88 | RainDropPoint(offset: new Offset(localOffset.dx, localOffset.dy));
89 | addRain(rainDrop);
90 | },
91 | child: new CustomPaint(
92 | painter: RainDropPainter(rainList: widget.rainList),
93 | ),
94 | ),
95 | );
96 | }
97 |
98 | void addRain(RainDropPoint rainDrop) {
99 | widget.rainList.add(rainDrop);
100 | doDelay(xController, 0);
101 | }
102 |
103 | void _change() {
104 | if (widget.rainList.isEmpty) {
105 | print("xController stop!");
106 | xController.stop();
107 | }
108 | setState(() {});
109 | }
110 |
111 | void _rainDrop() {
112 | var random = new Random();
113 | addRain(RainDropPoint(
114 | offset: Offset(
115 | _width * random.nextDouble(), _height * random.nextDouble())));
116 | }
117 |
118 | void doDelay(AnimationController controller, int delay) async {
119 | Future.delayed(Duration(milliseconds: delay), () {
120 | try {
121 | controller..repeat();
122 | } catch (e) {}
123 | });
124 | }
125 |
126 | @override
127 | void dispose() {
128 | xController.dispose();
129 | xAnimation.removeListener(_change);
130 | rainController.dispose();
131 | rainAnimation.removeListener(_rainDrop);
132 | super.dispose();
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/painter_factory.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/Progress/painter/painter_base.dart';
2 | import 'package:douban_movies/WanAndroid/Progress/painter/painter_circle_snapchat.dart';
3 | import 'package:douban_movies/WanAndroid/Progress/painter/painter_line_four.dart';
4 | import 'package:douban_movies/WanAndroid/Progress/painter/painter_wave.dart';
5 | import 'package:flutter/material.dart';
6 |
7 | abstract class BasePainterFactory {
8 | BasePainter getPainter();
9 | }
10 |
11 | class WavePainterFactory extends BasePainterFactory {
12 | BasePainter getPainter() {
13 | return WavePainter(
14 | waveCount: 1,
15 | waveColors: [
16 | Colors.lightBlue,
17 | ],
18 | textStyle: TextStyle(
19 | fontSize: 60.0,
20 | foreground: Paint()
21 | ..color = Colors.lightBlue
22 | ..style = PaintingStyle.fill
23 | ..strokeWidth = 2.0
24 | ..blendMode = BlendMode.difference
25 | ..colorFilter = ColorFilter.mode(Colors.white, BlendMode.exclusion)
26 | ..maskFilter = MaskFilter.blur(BlurStyle.solid, 5.0),
27 | // color: Color.fromARGB(
28 | // 255, Colors.green.red, Colors.green.green, Colors.green.blue),
29 | fontWeight: FontWeight.bold,
30 | // shadows: [
31 | // Shadow(
32 | // color: Color.fromARGB(
33 | // 255, Colors.grey.red, Colors.grey.green, Colors.grey.blue),
34 | // offset: Offset(5.0, 5.0),
35 | // blurRadius: 5.0)
36 | // ],
37 | ),
38 | );
39 | }
40 | }
41 |
42 | class SnapchatCirclePainterFactory extends BasePainterFactory {
43 | BasePainter getPainter() {
44 | return SnapchatCirclePainter(
45 | circleGap: 15.0,
46 | circleColor: Colors.pink,
47 | circleWidth: 20.0,
48 | progressColor: Colors.green,
49 | );
50 | }
51 | }
52 |
53 | class FourLinePainterFactory extends BasePainterFactory {
54 | BasePainter getPainter() {
55 | return FourLinePainter(
56 | gap: 10.0,
57 | lineColors: const [
58 | Colors.green,
59 | Colors.red,
60 | Colors.blue,
61 | Colors.yellow,
62 | Colors.pinkAccent,
63 | ],
64 | baseHightScales: const [
65 | 0.1,
66 | 0.6,
67 | 0.3,
68 | 0.8,
69 | 0.7,
70 | ],
71 | );
72 | }
73 | }
74 |
75 | //class RainDropPainterFactory extends BasePainterFactory {
76 | // BasePainter getPainter(List rainList) {
77 | // return RainDropPainter(
78 | // rainList: rainList,
79 | // );
80 | // }
81 | //}
82 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/progress_manager.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/Progress/painter_factory.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class ProgressManager extends StatefulWidget {
5 | @override
6 | _ProgressManagerState createState() =>
7 | new _ProgressManagerState().._factory = WavePainterFactory();
8 | }
9 |
10 | class _ProgressManagerState extends State
11 | with TickerProviderStateMixin {
12 | AnimationController xController;
13 | AnimationController yController;
14 | Animation xAnimation;
15 | Animation yAnimation;
16 | List _progressList = [];
17 | double curProgress = 0;
18 | BasePainterFactory _factory;
19 |
20 | set painter(BasePainterFactory factory) {
21 | _factory = factory;
22 | }
23 |
24 | setProgress(double progress) {
25 | _progressList.add(progress);
26 | onProgressChange();
27 | }
28 |
29 | onProgressChange() {
30 | if (_progressList.length > 0) {
31 | if (yController != null && yController.isAnimating) {
32 | return;
33 | }
34 | double nextProgress = _progressList[0];
35 | _progressList.removeAt(0);
36 | final double begin = curProgress;
37 | yController = new AnimationController(
38 | vsync: this, duration: Duration(milliseconds: 500));
39 | yAnimation =
40 | new Tween(begin: begin, end: nextProgress).animate(yController);
41 | yAnimation.addListener(_onProgressChange);
42 | yAnimation.addStatusListener(_onProgressStatusChange);
43 | yController.forward();
44 | }
45 | }
46 |
47 | @override
48 | void initState() {
49 | // TODO: implement initState
50 | super.initState();
51 | xController = new AnimationController(
52 | vsync: this, duration: Duration(milliseconds: 3000));
53 | xAnimation = new Tween(begin: 0.0, end: 1.0).animate(xController);
54 |
55 | xAnimation.addListener(_change);
56 | // xAnimation.addStatusListener((status) {
57 | // if (status == AnimationStatus.completed) {
58 | // xController.reverse();
59 | // } else if (status == AnimationStatus.dismissed) {
60 | // xController.forward();
61 | // }
62 | // });
63 |
64 | yController = new AnimationController(
65 | vsync: this, duration: Duration(milliseconds: 500));
66 | yAnimation = new Tween(begin: 0.0, end: 1.0).animate(yController);
67 | yAnimation.addListener(_onProgressChange);
68 | yAnimation.addStatusListener(_onProgressStatusChange);
69 |
70 | doDelay(xController, 0);
71 |
72 | Future.delayed(Duration(milliseconds: 1000), () {
73 | setProgress(0.8);
74 | });
75 | Future.delayed(Duration(milliseconds: 2000), () {
76 | setProgress(0.2);
77 | });
78 | Future.delayed(Duration(milliseconds: 3000), () {
79 | setProgress(1.0);
80 | });
81 | Future.delayed(Duration(milliseconds: 4000), () {
82 | setProgress(0.5);
83 | });
84 | }
85 |
86 | @override
87 | Widget build(BuildContext context) {
88 | return Center(
89 | child: Container(
90 | width: 200.0,
91 | height: 200.0,
92 | child: new CustomPaint(
93 | painter: _factory.getPainter()
94 | ..XAnimation = xAnimation
95 | ..YAnimation = yAnimation,
96 | size: new Size(200.0, 200.0),
97 | ),
98 | ),
99 | );
100 | }
101 |
102 | void _change() {
103 | setState(() {});
104 | }
105 |
106 | void _onProgressChange() {
107 | setState(() {
108 | curProgress = yAnimation.value;
109 | });
110 | }
111 |
112 | void _onProgressStatusChange(status) {
113 | if (status == AnimationStatus.completed) {
114 | onProgressChange();
115 | }
116 | }
117 |
118 | void doDelay(AnimationController controller, int delay) async {
119 | Future.delayed(Duration(milliseconds: delay), () {
120 | controller..repeat();
121 | });
122 | }
123 |
124 | @override
125 | void dispose() {
126 | xController.dispose();
127 | yController.dispose();
128 | xAnimation.removeListener(_change);
129 | yAnimation.removeListener(_onProgressChange);
130 | yAnimation.removeStatusListener(_onProgressStatusChange);
131 | super.dispose();
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/rain_drop.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/rendering.dart';
3 |
4 | class RainDropWidget extends StatefulWidget {
5 | RainDropWidget({Key key, this.width, this.height}) : super(key: key);
6 |
7 | final double width;
8 | final double height;
9 |
10 | @override
11 | State createState() {
12 | return RainDropState(width, height);
13 | }
14 | }
15 |
16 | class RainDropState extends State
17 | with TickerProviderStateMixin {
18 | List _rainList;
19 | AnimationController _animation;
20 | double _width = 200;
21 | double _height = 200;
22 |
23 | RainDropState(double width, double height) {
24 | _width = width ?? _width;
25 | _height = height ?? _height;
26 | }
27 |
28 | @override
29 | void initState() {
30 | super.initState();
31 | _rainList = List();
32 | _animation = new AnimationController(
33 | // 因为是repeat的,这里的duration其实不care
34 | duration: const Duration(milliseconds: 200),
35 | vsync: this)
36 | ..addListener(() {
37 | if (_rainList.isEmpty) {
38 | _animation.stop();
39 | }
40 | setState(() {});
41 | });
42 | }
43 |
44 | @override
45 | Widget build(BuildContext context) {
46 | return Container(
47 | color: Colors.lightBlueAccent,
48 | width: _width,
49 | height: _height,
50 | child: GestureDetector(
51 | onTapUp: (TapUpDetails tapUp) {
52 | RenderBox getBox = context.findRenderObject();
53 | var localOffset = getBox.globalToLocal(tapUp.globalPosition);
54 | var rainDrop = RainDropDrawer(localOffset.dx, localOffset.dy);
55 | _rainList.add(rainDrop);
56 | _animation.repeat();
57 | },
58 | child: CustomPaint(
59 | painter: RainDrop(_rainList),
60 | ),
61 | ),
62 | );
63 | }
64 | }
65 |
66 | class RainDrop extends CustomPainter {
67 | RainDrop(this.rainList);
68 |
69 | List rainList = List();
70 | Paint _paint = new Paint()..style = PaintingStyle.stroke;
71 |
72 | @override
73 | void paint(Canvas canvas, Size size) {
74 | rainList.forEach((item) {
75 | item.drawRainDrop(canvas, _paint);
76 | });
77 | rainList.removeWhere((item) {
78 | return !item.isValid();
79 | });
80 | }
81 |
82 | @override
83 | bool shouldRepaint(CustomPainter oldDelegate) {
84 | return true;
85 | }
86 | }
87 |
88 | class RainDropDrawer {
89 | static const double MAX_RADIUS = 30;
90 | double posX;
91 | double posY;
92 | double radius = 5;
93 |
94 | RainDropDrawer(this.posX, this.posY);
95 |
96 | drawRainDrop(Canvas canvas, Paint paint) {
97 | double opt = (MAX_RADIUS - radius) / MAX_RADIUS;
98 | paint.color = Color.fromRGBO(0, 0, 0, opt);
99 | canvas.drawCircle(Offset(posX, posY), radius, paint);
100 | radius += 0.5;
101 | }
102 |
103 | bool isValid() {
104 | return radius < MAX_RADIUS;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/lib/WanAndroid/Progress/widget_rain_drop.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/Progress/painter/rainDrop/painter_rain_drop.dart';
2 | import 'package:douban_movies/WanAndroid/Progress/painter/rainDrop/point_rain_drop.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class RainDropWidget extends StatefulWidget {
6 | List rainList = List();
7 | final width;
8 | final height;
9 |
10 | RainDropWidget({Key key, this.width, this.height}) : super(key: key);
11 |
12 | @override
13 | _RainDropWidgetState createState() => new _RainDropWidgetState(width, height);
14 | }
15 |
16 | class _RainDropWidgetState extends State
17 | with TickerProviderStateMixin {
18 | AnimationController xController;
19 | Animation xAnimation;
20 | AnimationController rainController;
21 | Animation rainAnimation;
22 | double _width = 200;
23 | double _height = 200;
24 |
25 | _RainDropWidgetState(double width, double height) {
26 | _width = width ?? _width;
27 | _height = height ?? _height;
28 | }
29 |
30 | @override
31 | void initState() {
32 | // TODO: implement initState
33 | super.initState();
34 | xController = new AnimationController(
35 | vsync: this, duration: Duration(milliseconds: 3000));
36 | xAnimation = new Tween(begin: 0.0, end: 1.0).animate(xController);
37 | xAnimation.addListener(_change);
38 |
39 | rainController = new AnimationController(
40 | vsync: this, duration: Duration(milliseconds: 100000));
41 | rainAnimation = new Tween(begin: 0.0, end: 1.0).animate(rainController);
42 | rainAnimation.addListener(_rainDrop);
43 | doDelay(rainController, 0);
44 | }
45 |
46 | @override
47 | Widget build(BuildContext context) {
48 | return Container(
49 | width: _width,
50 | height: _height,
51 | child: GestureDetector(
52 | onTapUp: (tapUp) {
53 | RenderBox getBox = context.findRenderObject();
54 | var localOffset = getBox.globalToLocal(tapUp.globalPosition);
55 | var rainDrop =
56 | RainDropPoint(offset: new Offset(localOffset.dx, localOffset.dy));
57 | addRain(rainDrop);
58 | },
59 | onHorizontalDragUpdate: (hMove) {
60 | RenderBox getBox = context.findRenderObject();
61 | var localOffset = getBox.globalToLocal(hMove.globalPosition);
62 | var rainDrop =
63 | RainDropPoint(offset: new Offset(localOffset.dx, localOffset.dy));
64 | addRain(rainDrop);
65 | },
66 | onVerticalDragUpdate: (hMove) {
67 | RenderBox getBox = context.findRenderObject();
68 | var localOffset = getBox.globalToLocal(hMove.globalPosition);
69 | var rainDrop =
70 | RainDropPoint(offset: new Offset(localOffset.dx, localOffset.dy));
71 | addRain(rainDrop);
72 | },
73 | child: new CustomPaint(
74 | painter: RainDropPainter(rainList: widget.rainList),
75 | ),
76 | ),
77 | );
78 | }
79 |
80 | void addRain(RainDropPoint rainDrop) {
81 | widget.rainList.add(rainDrop);
82 | doDelay(xController, 0);
83 | }
84 |
85 | void _change() {
86 | if (widget.rainList.isEmpty) {
87 | print("xController stop!");
88 | xController.stop();
89 | }
90 | setState(() {});
91 | }
92 |
93 | void _rainDrop() {
94 | // var random = new Random();
95 | // addRain(RainDropPoint(
96 | // offset: Offset(
97 | // _width * random.nextDouble(), _height * random.nextDouble())));
98 | }
99 |
100 | void doDelay(AnimationController controller, int delay) async {
101 | Future.delayed(Duration(milliseconds: delay), () {
102 | controller..repeat();
103 | });
104 | }
105 |
106 | @override
107 | void dispose() {
108 | xController.dispose();
109 | xAnimation.removeListener(_change);
110 | super.dispose();
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/lib/WanAndroid/article_detail_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/web_page.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
4 | import 'package:douban_movies/WanAndroid/Data/data_article_bean.dart';
5 |
6 | class ArticleDetailPage extends StatelessWidget {
7 | final Data data;
8 |
9 | ArticleDetailPage({this.data});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return WebPage(
14 | title: data.getTitle(),
15 | url: data.link,
16 | );
17 | // return Container(
18 | // child: new WebviewScaffold(
19 | // url: data.link,
20 | // appBar: new AppBar(
21 | // title:Text(data.getTitle()),
22 | // ),
23 | // withZoom: true,
24 | // withLocalStorage: true,
25 | // hidden: true,
26 | // initialChild: new Center(
27 | // child: new CircularProgressIndicator(),
28 | // ),
29 | // ),
30 | // );
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/lib/WanAndroid/article_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/article_list_content.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | enum ArticleType {
5 | HOME_ARTICLE,
6 | NORMAL_ARTICLE,
7 | PROJECT_ARTICLE,
8 | }
9 |
10 | enum JumpFromType{
11 | KNOWLEDGE,
12 | OTHER,
13 | }
14 |
15 | class ArticlePage extends StatelessWidget {
16 | final String name;
17 | final int id;
18 | final ArticleType type;
19 |
20 | ArticlePage({this.name, this.id, this.type});
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return new Scaffold(
25 | appBar: new AppBar(
26 | title: Text(name),
27 | ),
28 | body: ArticleListPage(
29 | type: type,
30 | id: id,
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/WanAndroid/bloc/AccountBloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:douban_movies/WanAndroid/sp_utils.dart';
4 |
5 | import 'bloc_utils.dart';
6 |
7 | class AccountBloc implements BlocBase {
8 | String _account;
9 |
10 | String get getAccount => _account;
11 |
12 | StreamController _accountController =
13 | StreamController.broadcast();
14 |
15 | StreamSink get _accountSink => _accountController.sink;
16 |
17 | Stream get accountStream => _accountController.stream;
18 |
19 | StreamController _actionControll = StreamController.broadcast();
20 |
21 | StreamSink get accountSaveSink => _actionControll.sink;
22 |
23 | AccountBloc() {
24 | _account = "";
25 | _actionControll.stream.listen(_handleLogic);
26 | initAccount();
27 | }
28 |
29 | @override
30 | void dispose() {
31 | _accountController.close();
32 | _actionControll.close();
33 | }
34 |
35 | void _handleLogic(data) {
36 | _account = data;
37 | _accountSink.add(_account);
38 | SpUtils.save(SpUtils.KEY_ACCOUNT, data);
39 | }
40 |
41 | void initAccount() async {
42 | _account = await SpUtils.get(SpUtils.KEY_ACCOUNT, "");
43 | accountSaveSink.add(_account);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/WanAndroid/bloc/ApplicationBloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:douban_movies/WanAndroid/sp_utils.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | import 'bloc_utils.dart';
7 |
8 | class ApplicationBloc implements BlocBase {
9 | ThemeData _theme;
10 |
11 | ThemeData get getTheme => _theme;
12 |
13 | StreamController _themeController =
14 | StreamController < ThemeData
15 |
16 | >
17 |
18 | .
19 |
20 | broadcast();
21 |
22 | StreamSink get _themeSink => _themeController.sink;
23 |
24 | Stream get themeStream => _themeController.stream;
25 |
26 | StreamController _changeThemeController = StreamController.broadcast();
27 |
28 | StreamSink get changeThemeSink => _changeThemeController.sink;
29 |
30 | ApplicationBloc() {
31 | _theme = new ThemeData(
32 | primaryColor: Colors.blue,
33 | );
34 | _changeThemeController.stream.listen(_changeTheme);
35 | initTheme();
36 | }
37 |
38 | @override
39 | void dispose() {
40 | _themeController.close();
41 | _changeThemeController.close();
42 | }
43 |
44 | void _changeTheme(data) {
45 | _theme = data;
46 | _themeSink.add(_theme);
47 | }
48 |
49 | void initTheme() async {
50 | _theme = new ThemeData(
51 | primaryColor: Color(
52 | await SpUtils.get(SpUtils.KEY_PRIMARYCOLOR, Colors.blue.value)),
53 | );
54 | changeThemeSink.add(_theme);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/WanAndroid/bloc/bloc_utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:async';
3 |
4 | abstract class BlocBase {
5 | void dispose();
6 | }
7 |
8 | class BlocProvider extends StatefulWidget {
9 | final T bloc;
10 | final Widget child;
11 |
12 | BlocProvider({
13 | Key key,
14 | @required this.child,
15 | @required this.bloc,
16 | }) : super(key: key);
17 |
18 | @override
19 | _BlocProviderState createState() => new _BlocProviderState();
20 |
21 | static T of(BuildContext context) {
22 | final type = _typeOf>();
23 | BlocProvider provider = context.ancestorWidgetOfExactType(type);
24 | return provider.bloc;
25 | }
26 |
27 | static Type _typeOf() => T;
28 | }
29 |
30 | class _BlocProviderState extends State> {
31 | @override
32 | Widget build(BuildContext context) {
33 | return widget.child;
34 | }
35 |
36 | @override
37 | void dispose() {
38 | // TODO: implement dispose
39 | widget.bloc.dispose();
40 | super.dispose();
41 | }
42 | }
43 |
44 | class IncrementBloc implements BlocBase {
45 | int _counter;
46 |
47 | StreamController _counterController = StreamController.broadcast();
48 |
49 | StreamSink get _inAdd => _counterController.sink;
50 |
51 | Stream get outCounter => _counterController.stream;
52 |
53 | StreamController _actionControll = StreamController.broadcast();
54 |
55 | StreamSink get incrementCounter => _actionControll.sink;
56 |
57 | IncrementBloc() {
58 | _counter = 0;
59 | _actionControll.stream.listen(_handleLogic);
60 | }
61 |
62 | @override
63 | void dispose() {
64 | _actionControll.close();
65 | _counterController.close();
66 | }
67 |
68 | void _handleLogic(data) {
69 | _counter += 1;
70 | _inAdd.add(_counter);
71 | }
72 | }
--------------------------------------------------------------------------------
/lib/WanAndroid/config.dart:
--------------------------------------------------------------------------------
1 | final String URL_HOME_ARTICLE_LIST_part_1 =
2 | 'http://www.wanandroid.com/article/list/';
3 | final String URL_HOME_ARTICLE_LIST_part_2 = '/json';
4 |
5 | final String URL_TREE_ARTICLE_LIST_part_1 =
6 | 'http://www.wanandroid.com/article/list/';
7 | final String URL_TREE_ARTICLE_LIST_part_2 = '/json?cid=';
8 |
9 | final String URL_PROJECT_ARTICLE_LIST_part_1 =
10 | 'http://www.wanandroid.com/project/list/';
11 |
12 | final String URL_PROJECT_ARTICLE_LIST_part_2 = '/json?cid=';
13 |
14 | final String URL_LOGIN='http://www.wanandroid.com/user/login';
15 |
16 | final String URL_REGISTER='http://www.wanandroid.com/user/register';
17 |
18 | final String URL_NAVI_LIST = 'http://www.wanandroid.com/navi/json';
19 |
20 | final String URL_BANNER_LIST = 'http://www.wanandroid.com/banner/json';
--------------------------------------------------------------------------------
/lib/WanAndroid/dialog_utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | // ignore: must_be_immutable
4 | class CustomizeDialog extends Dialog {
5 | final Widget widget;
6 | double width;
7 | double height;
8 | bool canceledOnTouchOutSide;
9 |
10 | CustomizeDialog({
11 | Key key,
12 | @required this.widget,
13 | @required this.width,
14 | @required this.height,
15 | this.canceledOnTouchOutSide,
16 | }) : super(key: key);
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return new Material(
21 | //创建透明层
22 | type: MaterialType.transparency, //透明类型
23 | child: GestureDetector(
24 | onTap: () {
25 | //设置弹窗范围外点击是否返回
26 | if (!canceledOnTouchOutSide) {
27 | return;
28 | }
29 | Navigator.pop(context);
30 | },
31 | child: Container(
32 | color: Colors.transparent,
33 | child: GestureDetector(
34 | onTap: () {
35 | //设置点击弹窗范围内点击无响应
36 | },
37 | child: new Center(
38 | //保证控件居中效果
39 | child: new SizedBox(
40 | width: width,
41 | height: height,
42 | child: new Container(
43 | decoration: ShapeDecoration(
44 | color: Colors.white,
45 | shape: RoundedRectangleBorder(
46 | borderRadius: BorderRadius.all(
47 | Radius.circular(8.0),
48 | ),
49 | ),
50 | ),
51 | child: widget,
52 | ),
53 | ),
54 | ),
55 | ),
56 | ),
57 | ),
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/WanAndroid/home_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/Progress/progress_manager.dart';
2 | import 'package:douban_movies/WanAndroid/Progress/widget_rain_drop.dart';
3 | import 'package:douban_movies/WanAndroid/article_list_content.dart';
4 | import 'package:douban_movies/WanAndroid/article_page.dart';
5 | import 'package:douban_movies/WanAndroid/bloc/AccountBloc.dart';
6 | import 'package:douban_movies/WanAndroid/bloc/bloc_utils.dart';
7 | import 'package:douban_movies/WanAndroid/icon_font_utils.dart';
8 | import 'package:douban_movies/WanAndroid/knowledge_tree_page.dart';
9 | import 'package:douban_movies/WanAndroid/person_page.dart';
10 | import 'package:douban_movies/WanAndroid/popular_page.dart';
11 | import 'package:douban_movies/WanAndroid/project_page.dart';
12 | import 'package:douban_movies/WanAndroid/search_page.dart';
13 | import 'package:flutter/material.dart';
14 |
15 |
16 | class WanAndroidMainPage extends StatelessWidget {
17 |
18 | final ThemeData themeData;
19 |
20 | WanAndroidMainPage({this.themeData});
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | // TODO: implement build
25 | return MaterialApp(
26 | title: '玩安卓',
27 | theme: themeData,
28 | home: new WanAndroidHomePage(),
29 | );
30 | }
31 | }
32 |
33 | class WanAndroidHomePage extends StatefulWidget {
34 | @override
35 | _WanAndroidHomePageState createState() => _WanAndroidHomePageState();
36 | }
37 |
38 | class _WanAndroidHomePageState extends State {
39 | final _pages = [
40 | ArticleListPage(
41 | type: ArticleType.HOME_ARTICLE,
42 | ),
43 | // ProgressManager(),
44 | // RainDropWidget(),
45 | PopularContentView(),
46 | KnowledgeTreePage(),
47 | ProjectTreePage(),
48 | BlocProvider(
49 | child: PersonPage(),
50 | bloc: AccountBloc(),
51 | ),
52 | ];
53 | final _controller = PageController(initialPage: 0);
54 | int _selectedIndex = 0;
55 |
56 | void onItemTap(int index) {
57 | debugPrint('$index');
58 | _controller.animateToPage(index,
59 | duration: const Duration(milliseconds: 200), curve: Curves.ease);
60 | }
61 |
62 | @override
63 | Widget build(BuildContext context) {
64 | return new Scaffold(
65 | backgroundColor: Colors.white,
66 | appBar: new AppBar(
67 | elevation: 0.0,
68 | title: new Text('玩安卓'),
69 | actions: [
70 | IconButton(
71 | icon: Icon(
72 | Icons.search,
73 | color: Colors.black87,
74 | ),
75 | onPressed: () {
76 | showSearch(context: context, delegate: searchBarDelegate());
77 | },
78 | ),
79 | ],
80 | ),
81 | body: PageView(
82 | controller: _controller,
83 | scrollDirection: Axis.horizontal,
84 | children: _pages,
85 | onPageChanged: (index) {
86 | if (_selectedIndex != index) {
87 | setState(() {
88 | _selectedIndex = index;
89 | });
90 | }
91 | },
92 | ),
93 | bottomNavigationBar: new BottomNavigationBar(
94 | items: [
95 | new BottomNavigationBarItem(
96 | icon: IconFontUtils.getIcon(0xe639),
97 | title: Text(
98 | '文章',
99 | style: TextStyle(
100 | height: 1.1,
101 | ),
102 | ),
103 | backgroundColor: Colors.blue),
104 | new BottomNavigationBarItem(
105 | icon: IconFontUtils.getIcon(0xe600),
106 | title: Text(
107 | '导航',
108 | style: TextStyle(
109 | height: 1.1,
110 | ),
111 | ),
112 | backgroundColor: Colors.orange,
113 | ),
114 | new BottomNavigationBarItem(
115 | icon: IconFontUtils.getIcon(0xe61f),
116 | title: Text(
117 | '知识树',
118 | style: TextStyle(
119 | height: 1.1,
120 | ),
121 | ),
122 | backgroundColor: Colors.green,
123 | ),
124 | new BottomNavigationBarItem(
125 | icon: IconFontUtils.getIcon(0xe64f),
126 | title: Text(
127 | '项目',
128 | style: TextStyle(
129 | height: 1.1,
130 | ),
131 | ),
132 | backgroundColor: Colors.yellow,
133 | ),
134 | new BottomNavigationBarItem(
135 | icon: IconFontUtils.getIcon(0xe612),
136 | title: Text(
137 | '个人',
138 | style: TextStyle(
139 | height: 1.1,
140 | ),
141 | ),
142 | backgroundColor: Colors.purple,
143 | ),
144 | ],
145 | currentIndex: _selectedIndex,
146 | fixedColor: Colors.blue,
147 | onTap: onItemTap,
148 | type: BottomNavigationBarType.fixed,
149 | ),
150 | );
151 | }
152 |
153 | }
154 |
--------------------------------------------------------------------------------
/lib/WanAndroid/icon_font_utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class IconFontUtils {
4 | static getIcon(int codePoint) {
5 | return Icon(IconData(codePoint, fontFamily: "IconFont"));
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/lib/WanAndroid/knowledge_tree_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 | import 'dart:ui';
3 |
4 | import 'package:dio/dio.dart';
5 | import 'package:douban_movies/WanAndroid/Data/data_tree_bean.dart';
6 | import 'package:douban_movies/WanAndroid/article_page.dart';
7 | import 'package:douban_movies/WanAndroid/navigator_router_utils.dart';
8 | import 'package:flutter/material.dart';
9 |
10 | final String URL_TREE_LIST = 'http://www.wanandroid.com/tree/json';
11 |
12 | class KnowledgeTreePage extends StatefulWidget {
13 | @override
14 | _KnowledgeTreePageState createState() => new _KnowledgeTreePageState();
15 | }
16 |
17 | class _KnowledgeTreePageState extends State
18 | with AutomaticKeepAliveClientMixin {
19 | @override
20 | Widget build(BuildContext context) {
21 | // TODO: implement build
22 | return buildFutureBuilder();
23 | }
24 |
25 | FutureBuilder buildFutureBuilder() {
26 | return new FutureBuilder(
27 | builder: (context, AsyncSnapshot async) {
28 | if (async.connectionState == ConnectionState.active ||
29 | async.connectionState == ConnectionState.waiting) {
30 | return new Center(
31 | child: new CircularProgressIndicator(),
32 | );
33 | }
34 |
35 | if (async.connectionState == ConnectionState.done) {
36 | debugPrint('done');
37 | if (async.hasError) {
38 | return new Center(
39 | child: new Text('Error:code '),
40 | );
41 | } else if (async.hasData) {
42 | TreeBean bean = async.data;
43 | return RefreshIndicator(
44 | child: new ContentView(bean.nodes),
45 | onRefresh: () {},
46 | );
47 | }
48 | }
49 | },
50 | future: getData(),
51 | );
52 | }
53 |
54 | Future getData() async {
55 | debugPrint('getData');
56 | var dio = new Dio();
57 | Response response = await dio.get(URL_TREE_LIST);
58 | TreeBean bean = TreeBean.fromJson(response.data);
59 | return bean;
60 | }
61 |
62 | @override
63 | // TODO: implement wantKeepAlive
64 | bool get wantKeepAlive => true;
65 | }
66 |
67 | class ContentView extends StatelessWidget {
68 | final List nodes;
69 |
70 | ContentView(this.nodes);
71 |
72 | void jump2AtriclePage(int id) {}
73 |
74 | @override
75 | Widget build(BuildContext context) {
76 | // TODO: implement build
77 | return ListView.builder(
78 | itemBuilder: (context, i) {
79 | return new ContentItemView(nodes[i]);
80 | },
81 | itemCount: nodes.length,
82 | scrollDirection: Axis.vertical,
83 | );
84 | }
85 | }
86 |
87 | class ContentItemView extends StatelessWidget {
88 | final Node node;
89 |
90 | ContentItemView(this.node);
91 |
92 | getRandomColor() {
93 | return Color.fromARGB(255, Random.secure().nextInt(255),
94 | Random.secure().nextInt(255), Random.secure().nextInt(255));
95 | }
96 |
97 | @override
98 | Widget build(BuildContext context) {
99 | // TODO: implement build
100 | return Container(
101 | decoration: BoxDecoration(
102 | border: Border(bottom: BorderSide(color: Colors.grey, width: 0.2)),
103 | ),
104 | padding: EdgeInsets.all(10.0),
105 | child: Column(
106 | children: [
107 | Container(
108 | alignment: Alignment.centerLeft,
109 | child: Text(
110 | node.getName(),
111 | style: TextStyle(
112 | fontSize: 18.0,
113 | fontWeight: FontWeight.bold,
114 | ),
115 | ),
116 | ),
117 | Container(
118 | margin: EdgeInsets.only(
119 | top: 10.0,
120 | ),
121 | alignment: Alignment.centerLeft,
122 | child: Wrap(
123 | spacing: 8.0,
124 | runSpacing: 8.0,
125 | children: node.childNodes.map((childNode) {
126 | return GestureDetector(
127 | child: new ClipRRect(
128 | child: Container(
129 | padding: EdgeInsets.all(3.0),
130 | child: Text(
131 | childNode.getName(),
132 | style: TextStyle(
133 | color: Colors.white,
134 | shadows: [
135 | BoxShadow(
136 | color: Colors.grey, offset: Offset(0.2, 0.2))
137 | ],
138 | ),
139 | ),
140 | color: getRandomColor(),
141 | ),
142 | borderRadius: new BorderRadius.circular(3.0),
143 | ),
144 | onTap: () {
145 | NavigatorRouterUtils.pushToPage(
146 | context,
147 | new ArticlePage(
148 | name: childNode.getName(),
149 | id: childNode.mId,
150 | type: ArticleType.NORMAL_ARTICLE,
151 | ));
152 | },
153 | );
154 | }).toList(),
155 | ),
156 | ),
157 | ],
158 | ),
159 | );
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/lib/WanAndroid/navigator_router_utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/router_anim_utils.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | /**
5 | * 跳转管理
6 | */
7 | class NavigatorRouterUtils {
8 | /**
9 | * 跳转到指定page
10 | */
11 | static void pushToPage(BuildContext context, Widget page) {
12 | Navigator.of(context).push(new PageRouteBuilder(pageBuilder:
13 | (BuildContext c, Animation animation,
14 | Animation secondartAnimation) {
15 | return page;
16 | }, transitionsBuilder: (BuildContext c, Animation animation,
17 | Animation secondartAnimation, Widget child) {
18 | return RouterAnim.createTransition(animation, child);
19 | }));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/WanAndroid/popular_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:dio/dio.dart';
4 | import 'package:douban_movies/WanAndroid/Data/data_navi_bean.dart';
5 | import 'package:douban_movies/WanAndroid/Data/data_article_bean.dart';
6 | import 'package:douban_movies/WanAndroid/article_detail_page.dart';
7 | import 'package:douban_movies/WanAndroid/navigator_router_utils.dart';
8 | import 'package:flutter/material.dart';
9 |
10 | final String URL_NAVI_LIST = 'http://www.wanandroid.com/navi/json';
11 |
12 | class PopularContentView extends StatefulWidget {
13 | @override
14 | _PopularContentViewState createState() => _PopularContentViewState();
15 | }
16 |
17 | class _PopularContentViewState extends State
18 | with AutomaticKeepAliveClientMixin {
19 | @override
20 | Widget build(BuildContext context) {
21 | // TODO: implement build
22 | return buildFutureBuilder();
23 | }
24 |
25 | FutureBuilder buildFutureBuilder() {
26 | return new FutureBuilder(
27 | builder: (context, AsyncSnapshot async) {
28 | if (async.connectionState == ConnectionState.active ||
29 | async.connectionState == ConnectionState.waiting) {
30 | return new Center(
31 | child: new CircularProgressIndicator(),
32 | );
33 | }
34 |
35 | if (async.connectionState == ConnectionState.done) {
36 | debugPrint('done');
37 | if (async.hasError) {
38 | return new Center(
39 | child: new Text('Error:code '),
40 | );
41 | } else if (async.hasData) {
42 | NaviBean bean = async.data;
43 | return new PopularMenuView(
44 | nodes: bean.nodes,
45 | );
46 | }
47 | }
48 | },
49 | future: getData(),
50 | );
51 | }
52 |
53 | Future getData() async {
54 | debugPrint('getData');
55 | var dio = new Dio();
56 | Response response = await dio.get(URL_NAVI_LIST);
57 | NaviBean bean = NaviBean.fromJson(response.data);
58 | return bean;
59 | }
60 |
61 | @override
62 | // TODO: implement wantKeepAlive
63 | bool get wantKeepAlive => true;
64 | }
65 |
66 | class PopularMenuView extends StatefulWidget {
67 | final List nodes;
68 |
69 | PopularMenuView({this.nodes});
70 |
71 | @override
72 | _PopularMenuViewState createState() => _PopularMenuViewState();
73 | }
74 |
75 | class _PopularMenuViewState extends State {
76 | int _checkedIndex=0;
77 | void Function(int) onMenuChecked;
78 |
79 | @override
80 | void initState() {
81 | // TODO: implement initState
82 | super.initState();
83 | onMenuChecked=(int index){
84 | if(_checkedIndex!=index){
85 | _checkedIndex=index;
86 | setState(() {
87 |
88 | });
89 | }
90 | };
91 | }
92 |
93 |
94 | @override
95 | Widget build(BuildContext context) {
96 | // TODO: implement build
97 | return Row(
98 | children: [
99 | Expanded(
100 | child: ContentLeftListView(
101 | nodes: widget.nodes,
102 | checkedIndex: _checkedIndex,
103 | onMenuCheckedListener: onMenuChecked,
104 | ),
105 | flex: 3,
106 | ),
107 | Expanded(
108 | child: ContentRightListView(
109 | articles:widget.nodes[_checkedIndex].articles,
110 | ),
111 | flex: 8,
112 | ),
113 | ],
114 | );
115 | }
116 | }
117 |
118 | class ContentLeftListView extends StatelessWidget {
119 | final List nodes;
120 | final int checkedIndex;
121 | final onMenuCheckedListener;
122 |
123 | ContentLeftListView({this.nodes,this.checkedIndex,this.onMenuCheckedListener});
124 |
125 | @override
126 | Widget build(BuildContext context) {
127 | // TODO: implement build
128 | return ListView.builder(
129 | itemCount: nodes.length,
130 | itemBuilder: (BuildContext context, int i) {
131 | return InkWell(
132 | child: Container(
133 | margin: const EdgeInsets.all(3.0),
134 | padding: const EdgeInsets.only(top: 10.0, bottom: 10.0),
135 | alignment: Alignment.center,
136 | decoration: BoxDecoration(
137 | borderRadius: BorderRadius.circular(5.0),
138 | border: Border.all(color: checkedIndex==i?Colors.blue:Colors.white,width: 1.0),
139 | ),
140 | child: Text(
141 | nodes[i].getName(),
142 | style: TextStyle(
143 | fontSize: 15.0,
144 | color: Colors.black,
145 | ),
146 | ),
147 | ),
148 | onTap: (){
149 | onMenuCheckedListener(i);
150 | },
151 | );
152 | },
153 | scrollDirection: Axis.vertical,
154 | );
155 | }
156 | }
157 |
158 | class ContentRightListView extends StatelessWidget {
159 | final List articles;
160 |
161 |
162 | ContentRightListView({this.articles});
163 |
164 | @override
165 | Widget build(BuildContext context) {
166 | // TODO: implement build
167 | return Container(
168 | margin: EdgeInsets.only(
169 | left: 10.0,
170 | top: 10.0,
171 | ),
172 | alignment: Alignment.topLeft,
173 | child: Wrap(
174 | spacing: 8.0,
175 | runSpacing: 8.0,
176 | children: articles.map((childNode) {
177 | return GestureDetector(
178 | child: new ClipRRect(
179 | child: Container(
180 | padding: EdgeInsets.all(3.0),
181 | child: Text(
182 | childNode.getTitle(),
183 | style: TextStyle(
184 | color: Colors.white,
185 | shadows: [
186 | BoxShadow(
187 | color: Colors.grey, offset: Offset(0.2, 0.2))
188 | ],
189 | ),
190 | ),
191 | color: getRandomColor(),
192 | ),
193 | borderRadius: new BorderRadius.circular(3.0),
194 | ),
195 | onTap: () {
196 | NavigatorRouterUtils.pushToPage(
197 | context,
198 | ArticleDetailPage(
199 | data: childNode,
200 | ),
201 | );
202 | },
203 | );
204 | }).toList(),
205 | ),
206 | );
207 | }
208 | }
209 |
210 | class ContentView extends StatelessWidget {
211 | final List nodes;
212 |
213 | ContentView(this.nodes);
214 |
215 | @override
216 | Widget build(BuildContext context) {
217 | // TODO: implement build
218 | return ListView.builder(
219 | itemCount: nodes.length,
220 | scrollDirection: Axis.vertical,
221 | itemBuilder: (context, i) {
222 | return ContentItemView(nodes[i]);
223 | });
224 | }
225 | }
226 |
227 | getRandomColor() {
228 | return Color.fromARGB(255, Random.secure().nextInt(255),
229 | Random.secure().nextInt(255), Random.secure().nextInt(255));
230 | }
231 |
232 | class ContentItemView extends StatelessWidget {
233 | final NaviNode naviNode;
234 |
235 | ContentItemView(this.naviNode);
236 |
237 |
238 |
239 | @override
240 | Widget build(BuildContext context) {
241 | // TODO: implement build
242 | return Card(
243 | elevation: 0.3,
244 | child: Container(
245 | margin: EdgeInsets.all(5.0),
246 | child: Column(
247 | children: [
248 | Container(
249 | alignment: Alignment.centerLeft,
250 | child: Text(
251 | naviNode.getName(),
252 | style: TextStyle(
253 | fontSize: 18.0,
254 | fontWeight: FontWeight.bold,
255 | ),
256 | ),
257 | ),
258 | Container(
259 | margin: EdgeInsets.only(
260 | top: 10.0,
261 | ),
262 | alignment: Alignment.centerLeft,
263 | child: Wrap(
264 | spacing: 8.0,
265 | runSpacing: 8.0,
266 | children: naviNode.articles.map((childNode) {
267 | return GestureDetector(
268 | child: new ClipRRect(
269 | child: Container(
270 | padding: EdgeInsets.all(3.0),
271 | child: Text(
272 | childNode.getTitle(),
273 | style: TextStyle(
274 | color: Colors.white,
275 | shadows: [
276 | BoxShadow(
277 | color: Colors.grey, offset: Offset(0.2, 0.2))
278 | ],
279 | ),
280 | ),
281 | color: getRandomColor(),
282 | ),
283 | borderRadius: new BorderRadius.circular(3.0),
284 | ),
285 | onTap: () {
286 | NavigatorRouterUtils.pushToPage(
287 | context,
288 | ArticleDetailPage(
289 | data: childNode,
290 | ),
291 | );
292 | },
293 | );
294 | }).toList(),
295 | ),
296 | ),
297 | ],
298 | ),
299 | ),
300 | );
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/lib/WanAndroid/project_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:douban_movies/WanAndroid/Data/data_tree_bean.dart';
3 | import 'package:douban_movies/WanAndroid/article_page.dart';
4 | import 'package:douban_movies/WanAndroid/navigator_router_utils.dart';
5 | import 'package:flutter/material.dart';
6 | import 'dart:math';
7 |
8 | final String URL_TREE_LIST = 'http://www.wanandroid.com/project/tree/json';
9 |
10 | getRandomColor() {
11 | return Color.fromARGB(255, Random.secure().nextInt(255),
12 | Random.secure().nextInt(255), Random.secure().nextInt(255));
13 | }
14 |
15 | class ProjectTreePage extends StatefulWidget {
16 | @override
17 | _ProjectTreePageState createState() => new _ProjectTreePageState();
18 | }
19 |
20 | class _ProjectTreePageState extends State
21 | with AutomaticKeepAliveClientMixin {
22 | @override
23 | Widget build(BuildContext context) {
24 | // TODO: implement build
25 | return buildFutureBuilder();
26 | }
27 |
28 | FutureBuilder buildFutureBuilder() {
29 | return new FutureBuilder(
30 | builder: (context, AsyncSnapshot async) {
31 | if (async.connectionState == ConnectionState.active ||
32 | async.connectionState == ConnectionState.waiting) {
33 | return new Center(
34 | child: new CircularProgressIndicator(),
35 | );
36 | }
37 |
38 | if (async.connectionState == ConnectionState.done) {
39 | debugPrint('done');
40 | if (async.hasError) {
41 | return new Center(
42 | child: new Text('Error:code '),
43 | );
44 | } else if (async.hasData) {
45 | TreeBean bean = async.data;
46 | return RefreshIndicator(
47 | child: new ContentView(bean.nodes),
48 | onRefresh: () {},
49 | );
50 | }
51 | }
52 | },
53 | future: getData(),
54 | );
55 | }
56 |
57 | Future getData() async {
58 | debugPrint('getData');
59 | var dio = new Dio();
60 | Response response = await dio.get(URL_TREE_LIST);
61 | TreeBean bean = TreeBean.fromJson(response.data);
62 | return bean;
63 | }
64 |
65 | @override
66 | // TODO: implement wantKeepAlive
67 | bool get wantKeepAlive => true;
68 | }
69 |
70 | class ContentView extends StatelessWidget {
71 | final List nodes;
72 |
73 | ContentView(this.nodes);
74 |
75 | void jump2AtriclePage(int id) {}
76 |
77 | @override
78 | Widget build(BuildContext context) {
79 | // TODO: implement build
80 | // return ListView.builder(
81 | // itemBuilder: (context, i) {
82 | // return new ContentItemView(nodes[i]);
83 | // },
84 | // itemCount: nodes.length,
85 | // scrollDirection: Axis.vertical,
86 | // );
87 | return GridView.count(
88 | crossAxisCount: 2,
89 | padding: const EdgeInsets.all(10.0),
90 | children: nodes.map((node) {
91 | return ProjectItemView(
92 | node: node,
93 | );
94 | }).toList(),
95 | );
96 | }
97 | }
98 |
99 | class ProjectItemView extends StatelessWidget {
100 | final Node node;
101 |
102 | ProjectItemView({this.node});
103 |
104 | @override
105 | Widget build(BuildContext context) {
106 | // TODO: implement build
107 | return Card(
108 | color: getRandomColor(),
109 | shape: new RoundedRectangleBorder(
110 | borderRadius: BorderRadius.only(
111 | topLeft: Radius.circular(5.0),
112 | topRight: Radius.circular(5.0),
113 | bottomLeft: Radius.circular(5.0),
114 | bottomRight: Radius.circular(5.0),
115 | ),
116 | ),
117 | elevation: 2.5,
118 | child: InkWell(
119 | onTap: () {
120 | NavigatorRouterUtils.pushToPage(
121 | context,
122 | new ArticlePage(
123 | name: node.getName(),
124 | id: node.mId,
125 | type: ArticleType.PROJECT_ARTICLE,
126 | ));
127 | },
128 | child: Container(
129 | decoration: BoxDecoration(
130 | borderRadius: BorderRadius.circular(5.0),
131 | ),
132 | alignment: Alignment.center,
133 | child: Container(
134 | margin: const EdgeInsets.only(left: 10.0, right: 10.0),
135 | child: Text(
136 | node.getName(),
137 | textAlign: TextAlign.center,
138 | style: TextStyle(
139 | fontWeight: FontWeight.bold,
140 | fontSize: 20.0,
141 | color: Colors.white,
142 | shadows: [
143 | BoxShadow(color: Colors.grey, offset: Offset(0.5, 0.5)),
144 | ],
145 | ),
146 | ),
147 | ),
148 | ),
149 | ),
150 | );
151 | }
152 | }
153 |
154 | class ContentItemView extends StatelessWidget {
155 | final Node node;
156 |
157 | ContentItemView(this.node);
158 |
159 | @override
160 | Widget build(BuildContext context) {
161 | // TODO: implement build
162 | return Card(
163 | elevation: 0.3,
164 | child: InkWell(
165 | onTap: () {
166 | NavigatorRouterUtils.pushToPage(
167 | context,
168 | new ArticlePage(
169 | name: node.getName(),
170 | id: node.mId,
171 | type: ArticleType.PROJECT_ARTICLE,
172 | ));
173 | },
174 | child: Container(
175 | margin: EdgeInsets.all(10.0),
176 | child: Column(
177 | children: [
178 | Container(
179 | alignment: Alignment.centerLeft,
180 | child: Text(
181 | node.getName(),
182 | style: TextStyle(
183 | fontSize: 18.0,
184 | fontWeight: FontWeight.bold,
185 | ),
186 | ),
187 | ),
188 | ],
189 | ),
190 | ),
191 | ),
192 | );
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/lib/WanAndroid/router_anim_utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class RouterAnim {
4 | static createTransition(Animation animation, Widget child) {
5 | return SlideTransition(
6 | position: new Tween(
7 | begin: const Offset(1.0, 0.0),
8 | end: const Offset(0.0, 0.0),
9 | ).animate(animation),
10 | child: child,
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/WanAndroid/search_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:dio/dio.dart';
4 | import 'package:douban_movies/WanAndroid/Data/data_article_bean.dart';
5 | import 'package:douban_movies/WanAndroid/Data/data_key_bean.dart';
6 | import 'package:douban_movies/WanAndroid/article_list_content.dart';
7 | import 'package:flutter/material.dart';
8 |
9 | import 'article_page.dart';
10 |
11 | final String URL_HOT_KEY = 'http://www.wanandroid.com/hotkey/json';
12 | final String URL_SEARCH = 'http://www.wanandroid.com/article/query/0/json';
13 |
14 | List nodes = [];
15 |
16 |
17 | class searchBarDelegate extends SearchDelegate {
18 | @override
19 | List buildActions(BuildContext context) {
20 | return [
21 | IconButton(
22 | icon: Icon(Icons.clear),
23 | onPressed: () {
24 | query = "";
25 | showSuggestions(context);
26 | },
27 | ),
28 | ];
29 | }
30 |
31 | @override
32 | Widget buildLeading(BuildContext context) {
33 | return IconButton(
34 | icon: AnimatedIcon(
35 | icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
36 | onPressed: () => close(context, null),
37 | );
38 | }
39 |
40 | @override
41 | Widget buildResults(BuildContext context) {
42 | return buildSearchFutureBuilder(query);
43 | }
44 |
45 | @override
46 | Widget buildSuggestions(BuildContext context) {
47 | //如果说已经加载过一次搜索热榜,那么下次就不再重复加载了
48 | if (nodes.length == 0) {
49 | return buildDefaultFutureBuilder();
50 | } else {
51 | return new SearchDefaultView(
52 | nodes: nodes,
53 | callback: (key) {
54 | query = key;
55 | showResults(context);
56 | },
57 | );
58 | }
59 | }
60 |
61 | FutureBuilder buildDefaultFutureBuilder() {
62 | return new FutureBuilder(
63 | builder: (context, AsyncSnapshot async) {
64 | if (async.connectionState == ConnectionState.active ||
65 | async.connectionState == ConnectionState.waiting) {
66 | return new Center(
67 | child: new Text('Waitiing...'),
68 | );
69 | }
70 |
71 | if (async.connectionState == ConnectionState.done) {
72 | debugPrint('done');
73 | if (async.hasError) {
74 | return new Center(
75 | child: new Text('Error:code '),
76 | );
77 | } else if (async.hasData) {
78 | KeyBean bean = async.data;
79 | nodes = bean.nodes;
80 | return new SearchDefaultView(
81 | nodes: nodes,
82 | callback: (key) {
83 | query = key;
84 | showResults(context);
85 | },
86 | );
87 | }
88 | }
89 | },
90 | future: getData(),
91 | );
92 | }
93 |
94 | Future getData() async {
95 | debugPrint('getKeyBeanData');
96 | var dio = new Dio();
97 | Response response = await dio.get(URL_HOT_KEY);
98 | KeyBean bean = KeyBean.fromJson(response.data);
99 | return bean;
100 | }
101 |
102 | FutureBuilder buildSearchFutureBuilder(String key) {
103 | return new FutureBuilder(
104 | builder: (context, AsyncSnapshot async) {
105 | if (async.connectionState == ConnectionState.active ||
106 | async.connectionState == ConnectionState.waiting) {
107 | return new Center(
108 | child: new CircularProgressIndicator(),
109 | );
110 | }
111 |
112 | if (async.connectionState == ConnectionState.done) {
113 | debugPrint('done');
114 | if (async.hasError) {
115 | return new Center(
116 | child: new Text('Error:code '),
117 | );
118 | } else if (async.hasData) {
119 | HomeBean bean = async.data;
120 | return new ArticleListView(
121 | bean.data.datas, ArticleType.NORMAL_ARTICLE, null);
122 | }
123 | }
124 | },
125 | future: getSearchData(key),
126 | );
127 | }
128 |
129 | Future getSearchData(String key) async {
130 | var dio = new Dio();
131 | Response response = await dio.post(
132 | URL_SEARCH,
133 | options: Options(
134 | contentType: new ContentType('application', 'x-www-form-urlencoded',
135 | charset: 'utf-8'),
136 | ),
137 | data: {
138 | "k": key,
139 | },
140 | );
141 | HomeBean bean = HomeBean.fromJson(response.data);
142 | return bean;
143 | }
144 | }
145 |
146 | class SearchDefaultView extends StatelessWidget {
147 | final List nodes;
148 | final callback;
149 |
150 | SearchDefaultView({this.nodes, this.callback});
151 |
152 | @override
153 | Widget build(BuildContext context) {
154 | // TODO: implement build
155 | return Column(
156 | children: [
157 | SearchDefaultItemView(
158 | nodes: nodes,
159 | callback: callback,
160 | ),
161 | ],
162 | );
163 | }
164 | }
165 |
166 | class SearchDefaultItemView extends StatelessWidget {
167 | final List nodes;
168 | final callback;
169 |
170 | SearchDefaultItemView({this.nodes, this.callback});
171 |
172 | @override
173 | Widget build(BuildContext context) {
174 | return Container(
175 | margin: EdgeInsets.all(10.0),
176 | child: Column(
177 | children: [
178 | Container(
179 | alignment: Alignment.centerLeft,
180 | child: Text(
181 | '大家都在搜',
182 | style: TextStyle(
183 | fontSize: 18.0,
184 | fontWeight: FontWeight.bold,
185 | ),
186 | ),
187 | ),
188 | Container(
189 | margin: EdgeInsets.only(
190 | top: 10.0,
191 | ),
192 | alignment: Alignment.centerLeft,
193 | child: Wrap(
194 | spacing: 8.0,
195 | runSpacing: 8.0,
196 | children: nodes.map((childNode) {
197 | return GestureDetector(
198 | child: new ClipRRect(
199 | child: Container(
200 | padding: EdgeInsets.all(3.0),
201 | child: Text(
202 | childNode.getName(),
203 | style: TextStyle(
204 | color: Colors.white,
205 | ),
206 | ),
207 | color: Colors.blue,
208 | ),
209 | borderRadius: new BorderRadius.circular(3.0),
210 | ),
211 | onTap: () {
212 | debugPrint('onTap key-> ${childNode.getName()}');
213 | callback(childNode.getName());
214 | },
215 | );
216 | }).toList(),
217 | ),
218 | ),
219 | ],
220 | ),
221 | );
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/lib/WanAndroid/sp_utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:shared_preferences/shared_preferences.dart';
3 |
4 | /*
5 | * 存储数据
6 | */
7 | class SpUtils {
8 | static final String KEY_ACCOUNT="key_account";
9 | static final String KEY_PRIMARYCOLOR="key_primarycolor";
10 |
11 |
12 | static Future save(String key, Object value) async {
13 | SharedPreferences preferences = await SharedPreferences.getInstance();
14 | if (value is String) {
15 | preferences.setString(key, value);
16 | } else if (value is int) {
17 | preferences.setInt(key, value);
18 | } else if (value is bool) {
19 | preferences.setBool(key, value);
20 | } else if (value is double) {
21 | preferences.setDouble(key, value);
22 | } else if (value is List) {
23 | preferences.setStringList(key, value);
24 | }
25 | }
26 |
27 | static Future get(String key, Object defaultValue) async {
28 | SharedPreferences preferences = await SharedPreferences.getInstance();
29 | if (defaultValue is String) {
30 | defaultValue = preferences.getString(key);
31 | } else if (defaultValue is int) {
32 | defaultValue = preferences.getInt(key);
33 | } else if (defaultValue is bool) {
34 | defaultValue = preferences.getBool(key);
35 | } else if (defaultValue is double) {
36 | defaultValue = preferences.getDouble(key);
37 | } else if (defaultValue is List) {
38 | defaultValue = preferences.getStringList(key);
39 | }
40 | return defaultValue;
41 | }
42 |
43 | static Future getString(String key, String defaultValue) async {
44 | SharedPreferences preferences = await SharedPreferences.getInstance();
45 | defaultValue = preferences.getString(key);
46 | return defaultValue;
47 | }
48 |
49 | static Future getInt(String key, Object defaultValue) async {
50 | SharedPreferences preferences = await SharedPreferences.getInstance();
51 | defaultValue = preferences.getInt(key);
52 | return defaultValue;
53 | }
54 |
55 | static Future getBool(String key, Object defaultValue) async {
56 | SharedPreferences preferences = await SharedPreferences.getInstance();
57 | defaultValue = preferences.getBool(key);
58 | return defaultValue;
59 | }
60 |
61 | static Future getDouoble(String key, Object defaultValue) async {
62 | SharedPreferences preferences = await SharedPreferences.getInstance();
63 | defaultValue = preferences.getDouble(key);
64 | return defaultValue;
65 | }
66 |
67 | static Future getStringList(String key, Object defaultValue) async {
68 | SharedPreferences preferences = await SharedPreferences.getInstance();
69 | defaultValue = preferences.getStringList(key);
70 | return defaultValue;
71 | }
72 |
73 | static Future remove(String key) async {
74 | SharedPreferences preferences = await SharedPreferences.getInstance();
75 | preferences.remove(key);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/lib/WanAndroid/web_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
3 | import 'package:douban_movies/WanAndroid/Data/data_article_bean.dart';
4 | import 'package:webview_flutter/webview_flutter.dart';
5 |
6 | class WebPage extends StatelessWidget {
7 | final String title;
8 | final String url;
9 |
10 | WebPage({this.title,this.url});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Scaffold(
15 | appBar: AppBar(
16 | title: Text(title),
17 | ),
18 | body: new WebView(
19 | onWebViewCreated: (WebViewController webViewController) {
20 | // _webViewController = webViewController;
21 | // _webViewController.addListener(() {
22 | // int _scrollY = _webViewController.scrollY.toInt();
23 | // if (_scrollY < 480 && _isShowFloatBtn) {
24 | // _isShowFloatBtn = false;
25 | // setState(() {});
26 | // } else if (_scrollY > 480 && !_isShowFloatBtn) {
27 | // _isShowFloatBtn = true;
28 | // setState(() {});
29 | // }
30 | // });
31 | },
32 | initialUrl: url,
33 | javascriptMode: JavascriptMode.unrestricted,
34 | ),
35 | );
36 | // return Container(
37 | // child: new WebviewScaffold(
38 | // url: url,
39 | // appBar: new AppBar(
40 | // title:Text(title),
41 | // ),
42 | // withZoom: true,
43 | // withLocalStorage: true,
44 | // hidden: true,
45 | // initialChild: new Center(
46 | // child: new CircularProgressIndicator(),
47 | // ),
48 | // ),
49 | // );
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/lib/WanAndroid/widget_banner.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_swiper/flutter_swiper.dart';
3 | import 'package:dio/dio.dart';
4 | import 'package:douban_movies/WanAndroid/Data/data_banner_bean.dart';
5 | import 'package:douban_movies/WanAndroid/config.dart';
6 | import 'package:transparent_image/transparent_image.dart';
7 | import 'package:douban_movies/WanAndroid/navigator_router_utils.dart';
8 | import 'package:douban_movies/WanAndroid/web_page.dart';
9 |
10 |
11 | BannerListBean bannerListBean;
12 |
13 | class BannerWidget extends StatefulWidget {
14 | @override
15 | _BannerWidgetState createState() => _BannerWidgetState();
16 | }
17 |
18 | class _BannerWidgetState extends State {
19 | @override
20 | Widget build(BuildContext context) {
21 | //如果banner已经加载过,那么刷新的时候轮播图就不再进行下一次刷新了
22 | if (bannerListBean != null) {
23 | return Swiper(
24 | itemBuilder: (BuildContext context, int index) {
25 | return Container(
26 | padding: const EdgeInsets.only(bottom: 20.0),
27 | child: Card(
28 | shape: const RoundedRectangleBorder(
29 | borderRadius: BorderRadius.all(Radius.circular(6.0)),
30 | ),
31 | elevation: 4.0,
32 | child: ClipRRect(
33 | borderRadius: BorderRadius.circular(6.0),
34 | child: new FadeInImage.memoryNetwork(
35 | fit: BoxFit.fill,
36 | placeholder: kTransparentImage,
37 | image: bannerListBean.data[index].imagePath,
38 | ),
39 | ),
40 | ),
41 | );
42 | },
43 | itemCount: bannerListBean.data.length,
44 | viewportFraction: 0.85,
45 | scale: 0.95,
46 | pagination: null,
47 | control: null,
48 | scrollDirection: Axis.horizontal,
49 | autoplay: true,
50 | onTap: (index) {
51 | NavigatorRouterUtils.pushToPage(
52 | context,
53 | new WebPage(
54 | title: bannerListBean.data[index].getName(),
55 | url: bannerListBean.data[index].url,
56 | ));
57 | },
58 | );
59 | } else {
60 | return buildFutureBuilder();
61 | }
62 | }
63 |
64 | FutureBuilder buildFutureBuilder() {
65 | return new FutureBuilder(
66 | builder: (context, AsyncSnapshot async) {
67 | if (async.connectionState == ConnectionState.active ||
68 | async.connectionState == ConnectionState.waiting) {
69 | return new Center(
70 | child: new CircularProgressIndicator(),
71 | );
72 | }
73 |
74 | if (async.connectionState == ConnectionState.done) {
75 | debugPrint('done');
76 | if (async.hasError) {
77 | return new Center(
78 | child: new Text('Error:code '),
79 | );
80 | } else if (async.hasData) {
81 | bannerListBean = async.data;
82 | return Swiper(
83 | itemBuilder: (BuildContext context, int index) {
84 | return Container(
85 | padding: const EdgeInsets.only(bottom: 20.0),
86 | child: Card(
87 | shape: const RoundedRectangleBorder(
88 | borderRadius: BorderRadius.all(Radius.circular(6.0)),
89 | ),
90 | elevation: 4.0,
91 | child: ClipRRect(
92 | borderRadius: BorderRadius.circular(6.0),
93 | child: new FadeInImage.memoryNetwork(
94 | fit: BoxFit.fill,
95 | placeholder: kTransparentImage,
96 | image: bannerListBean.data[index].imagePath,
97 | ),
98 | ),
99 | ),
100 | );
101 | },
102 | itemCount: bannerListBean.data.length,
103 | viewportFraction: 0.85,
104 | scale: 0.95,
105 | pagination: null,
106 | control: null,
107 | scrollDirection: Axis.horizontal,
108 | autoplay: true,
109 | onTap: (index) {
110 | NavigatorRouterUtils.pushToPage(
111 | context,
112 | new WebPage(
113 | title: bannerListBean.data[index].getName(),
114 | url: bannerListBean.data[index].url,
115 | ));
116 | },
117 | );
118 | }
119 | }
120 | },
121 | future: getData(),
122 | );
123 | }
124 |
125 |
126 | Future getData() async {
127 | debugPrint('getData');
128 | var dio = new Dio();
129 | Response response = await dio.get(URL_BANNER_LIST);
130 | BannerListBean bean = BannerListBean.fromJson(response.data);
131 | return bean;
132 | }
133 |
134 | }
--------------------------------------------------------------------------------
/lib/data/bean_move_list.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert' show json;
2 |
3 | class MovieList {
4 |
5 | int count;
6 | int start;
7 | int total;
8 | String title;
9 | List subjects;
10 |
11 | static getDetailDesc(subject detail){
12 | StringBuffer sb=new StringBuffer();
13 | for(var i=0;i jsonStr == null ? null : jsonStr is String ? new MovieList.fromJson(json.decode(jsonStr)) : new MovieList.fromJson(jsonStr);
26 |
27 | MovieList.fromJson(jsonRes) {
28 | count = jsonRes['count'];
29 | start = jsonRes['start'];
30 | total = jsonRes['total'];
31 | title = jsonRes['title'];
32 | subjects = jsonRes['subjects'] == null ? null : [];
33 |
34 | for (var subjectsItem in subjects == null ? [] : jsonRes['subjects']){
35 | subjects.add(subjectsItem == null ? null : new subject.fromJson(subjectsItem));
36 | }
37 | }
38 |
39 | @override
40 | String toString() {
41 | return '{"count": $count,"start": $start,"total": $total,"title": ${title != null?'${json.encode(title)}':'null'},"subjects": $subjects}';
42 | }
43 | }
44 |
45 | class subject {
46 |
47 | int collect_count;
48 | bool has_video;
49 | String alt;
50 | String id;
51 | String mainland_pubdate;
52 | String original_title;
53 | String subtype;
54 | String title;
55 | String year;
56 | List casts;
57 | List directors;
58 | List durations;
59 | List genres;
60 | List pubdates;
61 | image images;
62 | rate rating;
63 |
64 | subject.fromParams({this.collect_count, this.has_video, this.alt, this.id, this.mainland_pubdate, this.original_title, this.subtype, this.title, this.year, this.casts, this.directors, this.durations, this.genres, this.pubdates, this.images, this.rating});
65 |
66 | subject.fromJson(jsonRes) {
67 | collect_count = jsonRes['collect_count'];
68 | has_video = jsonRes['has_video'];
69 | alt = jsonRes['alt'];
70 | id = jsonRes['id'];
71 | mainland_pubdate = jsonRes['mainland_pubdate'];
72 | original_title = jsonRes['original_title'];
73 | subtype = jsonRes['subtype'];
74 | title = jsonRes['title'];
75 | year = jsonRes['year'];
76 | casts = jsonRes['casts'] == null ? null : [];
77 |
78 | for (var castsItem in casts == null ? [] : jsonRes['casts']){
79 | casts.add(castsItem == null ? null : new cast.fromJson(castsItem));
80 | }
81 |
82 | directors = jsonRes['directors'] == null ? null : [];
83 |
84 | for (var directorsItem in directors == null ? [] : jsonRes['directors']){
85 | directors.add(directorsItem == null ? null : new director.fromJson(directorsItem));
86 | }
87 |
88 | durations = jsonRes['durations'] == null ? null : [];
89 |
90 | for (var durationsItem in durations == null ? [] : jsonRes['durations']){
91 | durations.add(durationsItem);
92 | }
93 |
94 | genres = jsonRes['genres'] == null ? null : [];
95 |
96 | for (var genresItem in genres == null ? [] : jsonRes['genres']){
97 | genres.add(genresItem);
98 | }
99 |
100 | pubdates = jsonRes['pubdates'] == null ? null : [];
101 |
102 | for (var pubdatesItem in pubdates == null ? [] : jsonRes['pubdates']){
103 | pubdates.add(pubdatesItem);
104 | }
105 |
106 | images = jsonRes['images'] == null ? null : new image.fromJson(jsonRes['images']);
107 | rating = jsonRes['rating'] == null ? null : new rate.fromJson(jsonRes['rating']);
108 | }
109 |
110 | @override
111 | String toString() {
112 | return '{"collect_count": $collect_count,"has_video": $has_video,"alt": ${alt != null?'${json.encode(alt)}':'null'},"id": ${id != null?'${json.encode(id)}':'null'},"mainland_pubdate": ${mainland_pubdate != null?'${json.encode(mainland_pubdate)}':'null'},"original_title": ${original_title != null?'${json.encode(original_title)}':'null'},"subtype": ${subtype != null?'${json.encode(subtype)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"year": ${year != null?'${json.encode(year)}':'null'},"casts": $casts,"directors": $directors,"durations": $durations,"genres": $genres,"pubdates": $pubdates,"images": $images,"rating": $rating}';
113 | }
114 | }
115 |
116 | class rate {
117 |
118 | int max;
119 | int min;
120 | var average;
121 | String stars;
122 | detail details;
123 |
124 | rate.fromParams({this.max, this.min, this.average, this.stars, this.details});
125 |
126 | rate.fromJson(jsonRes) {
127 | max = jsonRes['max'];
128 | min = jsonRes['min'];
129 | average = jsonRes['average'];
130 | stars = jsonRes['stars'];
131 | details = jsonRes['details'] == null ? null : new detail.fromJson(jsonRes['details']);
132 | }
133 |
134 | @override
135 | String toString() {
136 | return '{"max": $max,"min": $min,"average": $average,"stars": ${stars != null?'${json.encode(stars)}':'null'},"details": $details}';
137 | }
138 | }
139 |
140 | class detail {
141 |
142 | var detial_1;
143 | var detial_2;
144 | var detial_3;
145 | var detial_4;
146 | var detial_5;
147 |
148 | detail.fromParams({this.detial_1, this.detial_2, this.detial_3, this.detial_4, this.detial_5});
149 |
150 | detail.fromJson(jsonRes) {
151 | detial_1 = jsonRes['1'];
152 | detial_2 = jsonRes['2'];
153 | detial_3 = jsonRes['3'];
154 | detial_4 = jsonRes['4'];
155 | detial_5 = jsonRes['5'];
156 | }
157 |
158 | @override
159 | String toString() {
160 | return '{"1": $detial_1,"2": $detial_2,"3": $detial_3,"4": $detial_4,"5": $detial_5}';
161 | }
162 | }
163 |
164 | class image {
165 |
166 | String large;
167 | String medium;
168 | String small;
169 |
170 | image.fromParams({this.large, this.medium, this.small});
171 |
172 | image.fromJson(jsonRes) {
173 | large = jsonRes['large'];
174 | medium = jsonRes['medium'];
175 | small = jsonRes['small'];
176 | }
177 |
178 | @override
179 | String toString() {
180 | return '{"large": ${large != null?'${json.encode(large)}':'null'},"medium": ${medium != null?'${json.encode(medium)}':'null'},"small": ${small != null?'${json.encode(small)}':'null'}}';
181 | }
182 | }
183 |
184 | class director {
185 |
186 | String alt;
187 | String id;
188 | String name;
189 | String name_en;
190 | avatar avatars;
191 |
192 | director.fromParams({this.alt, this.id, this.name, this.name_en, this.avatars});
193 |
194 | director.fromJson(jsonRes) {
195 | alt = jsonRes['alt'];
196 | id = jsonRes['id'];
197 | name = jsonRes['name'];
198 | name_en = jsonRes['name_en'];
199 | avatars = jsonRes['avatars'] == null ? null : new avatar.fromJson(jsonRes['avatars']);
200 | }
201 |
202 | @override
203 | String toString() {
204 | return '{"alt": ${alt != null?'${json.encode(alt)}':'null'},"id": ${id != null?'${json.encode(id)}':'null'},"name": ${name != null?'${json.encode(name)}':'null'},"name_en": ${name_en != null?'${json.encode(name_en)}':'null'},"avatars": $avatars}';
205 | }
206 | }
207 |
208 | class avatar {
209 |
210 | String large;
211 | String medium;
212 | String small;
213 |
214 | avatar.fromParams({this.large, this.medium, this.small});
215 |
216 | avatar.fromJson(jsonRes) {
217 | large = jsonRes['large'];
218 | medium = jsonRes['medium'];
219 | small = jsonRes['small'];
220 | }
221 |
222 | @override
223 | String toString() {
224 | return '{"large": ${large != null?'${json.encode(large)}':'null'},"medium": ${medium != null?'${json.encode(medium)}':'null'},"small": ${small != null?'${json.encode(small)}':'null'}}';
225 | }
226 | }
227 |
228 | class cast {
229 |
230 | String alt;
231 | String id;
232 | String name;
233 | String name_en;
234 | avatar avatars;
235 |
236 | cast.fromParams({this.alt, this.id, this.name, this.name_en, this.avatars});
237 |
238 | cast.fromJson(jsonRes) {
239 | alt = jsonRes['alt'];
240 | id = jsonRes['id'];
241 | name = jsonRes['name'];
242 | name_en = jsonRes['name_en'];
243 | avatars = jsonRes['avatars'] == null ? null : new avatar.fromJson(jsonRes['avatars']);
244 | }
245 |
246 | @override
247 | String toString() {
248 | return '{"alt": ${alt != null?'${json.encode(alt)}':'null'},"id": ${id != null?'${json.encode(id)}':'null'},"name": ${name != null?'${json.encode(name)}':'null'},"name_en": ${name_en != null?'${json.encode(name_en)}':'null'},"avatars": $avatars}';
249 | }
250 | }
251 |
252 |
253 |
254 |
--------------------------------------------------------------------------------
/lib/db/db_utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:sqflite/sqflite.dart';
3 | import 'dart:io';
4 |
5 |
6 |
7 | class DbUtils {
8 | }
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/rendering.dart';
3 | import 'package:douban_movies/WanAndroid/bloc/ApplicationBloc.dart';
4 | import 'package:douban_movies/WanAndroid/bloc/bloc_utils.dart';
5 | import 'WanAndroid/home_page.dart';
6 |
7 | void main() {
8 | //设置debugPaintSizeEnabled为true来更直观的调试布局问题
9 | debugPaintSizeEnabled = false;
10 | return runApp(BlocProvider(
11 | child: Application(),
12 | bloc: ApplicationBloc(),
13 | ));
14 | }
15 |
16 | class Application extends StatefulWidget {
17 | @override
18 | _ApplicationState createState() => _ApplicationState();
19 | }
20 |
21 | class _ApplicationState extends State {
22 | @override
23 | Widget build(BuildContext context) {
24 | ApplicationBloc bloc=BlocProvider.of(context);
25 |
26 | return StreamBuilder(
27 | initialData: bloc.getTheme,
28 | stream: bloc.themeStream,
29 | builder: (BuildContext context,AsyncSnapshot snapshot){
30 | return WanAndroidMainPage(
31 | themeData: snapshot.data,
32 | );
33 | },
34 | );
35 | }
36 | }
37 |
38 |
39 |
--------------------------------------------------------------------------------
/lib/net/http.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | class HttpUtils {
4 | static String URL_GET_MOVIE_LIST_IN_THEATERS = 'https://api.douban.com/v2/movie/in_theaters';
5 | static String URL_GET_MOVIE_LIST_COMING_SOON = 'https://api.douban.com/v2/movie/coming_soon';
6 | static String URL_GET_MOVIE_LIST_TOP_250 = 'https://api.douban.com/v2/movie/top250';
7 | static String URL_GET_MOVIE_LIST_WEEKLY = 'https://api.douban.com/v2/movie/weekly';
8 | static String URL_GET_MOVIE_LIST_US_BOX = 'https://api.douban.com/v2/movie/us_box';
9 | static String URL_GET_MOVIE_LIST_NEW_MOVIES = 'https://api.douban.com/v2/movie/new_movies';
10 | static String URL_GET_MOVIE_DETAIL = 'http://api.douban.com/v2/movie/subject/';
11 | static String URL_API_KEY='0b2bdeda43b5688921839c8ecb20399b';
12 | static String URL_UDID='dddddddddddddddddddddd';
13 |
14 | static get(String url, {Map map}) async {
15 | Dio dio = new Dio();
16 | Response response = await dio.get(url,data: map);
17 | return response.data;
18 | }
19 | }
--------------------------------------------------------------------------------
/lib/pages/detail/MovieActors/MovieActors.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:douban_movies/data/bean_move_detail.dart';
3 | import 'package:douban_movies/pages/views/ClipImageView.dart';
4 |
5 | class MovieActorsView extends StatelessWidget {
6 |
7 | final MovieDetail detail;
8 |
9 | MovieActorsView(this.detail);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | // TODO: implement build
14 | return new Container(
15 | margin: new EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0),
16 | child: new Column(
17 | children: [
18 | new Container(
19 | alignment: Alignment.centerLeft,
20 | child: new Text('影人',
21 | style: new TextStyle(
22 | fontSize: 20.0,
23 | fontWeight: FontWeight.bold,
24 | ),
25 | ),
26 | ),
27 | new Container(
28 | height: 160.0,
29 | margin: EdgeInsets.only(top: 10.0),
30 | child: new Row(
31 | children: [
32 | getActorsListView(detail.casts),
33 | ],
34 | ),
35 | ),
36 | ],
37 | ),
38 | );
39 | }
40 |
41 | getActorsListView(List casts) {
42 | return new Expanded(
43 | child: new ListView.builder(
44 | itemBuilder: (c, i) {
45 | return new Container(
46 | width: 85.0,
47 | child: new Column(
48 | children: [
49 | new ClipImageView(
50 | casts[i].avatars.small,
51 | new BorderRadius.circular(4.0),
52 | ),
53 | new Container(
54 | width: double.infinity,
55 | child: new Text(
56 | '${casts[i].name}',
57 | overflow: TextOverflow.ellipsis,
58 | textAlign: TextAlign.start,
59 | ),
60 | ),
61 | new Container(
62 | width: double.infinity,
63 | child: new Text(
64 | '${casts[i].name_en}',
65 | overflow: TextOverflow.ellipsis,
66 | textAlign: TextAlign.start,
67 | style: TextStyle(
68 | fontSize: 10.0,
69 | color: Colors.grey,
70 | ),
71 | ),
72 | ),
73 | ],
74 |
75 | ),
76 | margin: EdgeInsets.only(right: 10.0),
77 | );
78 | },
79 | itemCount: casts.length,
80 | scrollDirection: Axis.horizontal,
81 | ),
82 | );
83 | }
84 | }
--------------------------------------------------------------------------------
/lib/pages/detail/MovieChannel/MovieChannel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:douban_movies/data/bean_move_detail.dart';
3 | import 'package:douban_movies/pages/views/Chips.dart';
4 |
5 | class MovieChnnelView extends StatelessWidget {
6 | final MovieDetail detail;
7 | MovieChnnelView(this.detail);
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | // TODO: implement build
12 | return new Container(
13 | padding: new EdgeInsets.only(left:10.0,right: 10.0,bottom: 5.0),
14 | child: new Row(
15 | children: [
16 | getMovieChannelItems(detail),
17 | ],
18 | ),
19 | );
20 | }
21 |
22 | ///get movie channel items
23 | getMovieChannelItems(MovieDetail detail) {
24 | return new Expanded(
25 | child: new ListView.builder(
26 | scrollDirection: Axis.horizontal,
27 | itemCount: detail.tags.length,
28 | itemBuilder: (context, i) {
29 | if(i==0){
30 | return new Container(
31 | alignment: Alignment.centerLeft,
32 | padding: new EdgeInsets.only(right:5.0),
33 | child: new Text('所属频道'),
34 | );
35 | }else {
36 | return new Container(
37 | padding: new EdgeInsets.only(right: 5.0),
38 | child: new Chip(
39 | onDeleted: () {
40 | print('点击了标签!');
41 | },
42 | deleteIcon: new Icon(Icons.chevron_right),
43 | label: new Text(detail.tags[i]),
44 | ),
45 | );
46 | }
47 | },
48 | ),
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/pages/detail/MovieComments/MovieCommentsView.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:douban_movies/pages/views/ClipImageView.dart';
3 | import 'package:douban_movies/data/bean_move_detail.dart';
4 | import 'package:douban_movies/pages/views/StartsView.dart';
5 |
6 | class MovieCommentsView extends StatelessWidget {
7 | final MovieDetail _detail;
8 |
9 | MovieCommentsView(this._detail);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | // TODO: implement build
14 | return Container(
15 | margin: EdgeInsets.all(10.0),
16 | decoration: new BoxDecoration(
17 | color: Colors.grey,
18 | borderRadius: BorderRadius.circular(5.0),
19 | ),
20 | child: new Column(
21 | children:
22 | getCommentsList(_detail),
23 | ),
24 | );
25 | }
26 |
27 | getCommentsList(MovieDetail detail) {
28 | if (detail == null) {
29 | return [];
30 | }
31 | List views = [];
32 | views.add(new Container(
33 | width: double.infinity,
34 | margin: EdgeInsets.only(left: 10.0,top: 10.0,bottom: 20.0),
35 | alignment: Alignment.centerLeft,
36 | child: Text(
37 | '短评',
38 | textAlign: TextAlign.start,
39 | style: TextStyle(
40 | fontWeight: FontWeight.bold,
41 | fontSize: 20.0,
42 | color: Colors.white,
43 | ),
44 | ),
45 | ));
46 | for (var i = 0; i < detail.popular_comments.length; i++) {
47 | print(detail.popular_comments[i]);
48 | views.add(new CommentItemView(detail.popular_comments[i],
49 | (i == (detail.popular_comments.length - 1))));
50 | }
51 | return views;
52 | }
53 |
54 | }
55 |
56 | class CommentItemView extends StatelessWidget {
57 | final popular_comment comment;
58 | final bool isLast;
59 |
60 | CommentItemView(this.comment, this.isLast);
61 |
62 | @override
63 | Widget build(BuildContext context) {
64 | // TODO: implement build
65 | return new Container(
66 | margin: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 20.0),
67 | child: Column(
68 | children: [
69 | Container(
70 | height: 40.0,
71 | child: new Row(
72 | children: [
73 | new Container(
74 | alignment: Alignment.center,
75 | width: 30.0,
76 | child: ClipImageView(
77 | comment.author.avatar, BorderRadius.circular(15.0)),
78 | ),
79 | new Container(width: 10.0,),
80 | new Expanded(
81 | child: Column(
82 | children: [
83 | Expanded(
84 | flex: 1,
85 | child: Container(
86 | alignment: Alignment.centerLeft,
87 | width: double.infinity,
88 | child: new Text(
89 | comment.author.name,
90 | textAlign: TextAlign.start,
91 | style: TextStyle(
92 | fontSize: 15.0,
93 | color: Colors.white,
94 | fontWeight: FontWeight.bold,
95 | ),
96 | ),
97 | ),
98 | ),
99 | Expanded(
100 | flex: 1,
101 | child: Container(
102 | alignment: Alignment.centerLeft,
103 | width: double.infinity,
104 | child: new Text(
105 | comment.created_at,
106 | textAlign: TextAlign.start,
107 | style: TextStyle(
108 | fontSize: 12.0,
109 | color: Colors.grey[300],
110 | ),
111 | ),
112 | ),
113 | ),
114 | ],
115 | )
116 | ),
117 | ],
118 | ),
119 | ),
120 | Container(
121 | margin: EdgeInsets.only(top: 10.0),
122 | width: double.infinity,
123 | child: new Text(
124 | comment.content,
125 | textAlign: TextAlign.start,
126 | style: TextStyle(
127 | color: Colors.white,
128 | ),
129 | ),
130 | ),
131 | Container(
132 | margin: EdgeInsets.only(top: 10.0),
133 | width: double.infinity,
134 | child: Row(
135 | children: [
136 | Icon(Icons.thumb_up, color: Colors.grey[300], size: 15.0,),
137 | Expanded(
138 | child: Container(
139 | alignment: Alignment.centerLeft,
140 | margin: EdgeInsets.only(left: 5.0),
141 | child: new Text(
142 | '${comment.getUserfulCountDesc()}k',
143 | textAlign: TextAlign.start,
144 | style: TextStyle(
145 | color: Colors.grey[300],
146 | ),
147 | ),
148 | ),
149 | ),
150 | ],
151 | ),
152 | ),
153 | getDivider(isLast),
154 | ],
155 | ),
156 | );
157 | }
158 |
159 | getDivider(bool isLast) {
160 | if (!isLast) {
161 | return Container(
162 | margin: EdgeInsets.only(top: 20.0),
163 | child: new Divider(color: Colors.white,),
164 | );
165 | } else {
166 | return new Container();
167 | }
168 | }
169 |
170 | }
--------------------------------------------------------------------------------
/lib/pages/detail/MovieDesc/MovieDesc.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/gestures.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:douban_movies/data/bean_move_detail.dart';
4 |
5 | class MovieDescView extends StatelessWidget {
6 |
7 | final MovieDetail detail;
8 |
9 | MovieDescView(this.detail);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return new Container(
14 | margin: new EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0),
15 | child: new Column(
16 | children: [
17 | new Container(
18 | alignment: Alignment.centerLeft,
19 | child: new Text('简介',
20 | style: new TextStyle(
21 | fontSize: 20.0,
22 | fontWeight: FontWeight.bold,
23 | ),
24 | ),
25 | ),
26 | new Container(
27 | margin: EdgeInsets.only(top: 10.0),
28 | child: new ExpansionText(detail.summary.substring(0, 40),
29 | detail.summary, false),
30 | ),
31 | ],
32 | ),
33 | );
34 | }
35 | }
36 |
37 |
38 | class ExpansionText extends StatefulWidget {
39 |
40 | final String title;
41 | final String body;
42 | final bool expand;
43 |
44 | ExpansionText(this.title, this.body, this.expand);
45 |
46 | @override
47 | _ExpansionTextState createState() =>
48 | _ExpansionTextState(this.title, this.body, this.expand);
49 |
50 | }
51 |
52 | class _ExpansionTextState extends State {
53 |
54 | String _title;
55 | String _body;
56 | bool _expand;
57 |
58 | _ExpansionTextState(String title, String body, bool expand) {
59 | this._title = title;
60 | this._body = body;
61 | this._expand = expand;
62 | }
63 |
64 |
65 | expandText() {
66 | if (_expand) {
67 | _expand = false;
68 | } else {
69 | _expand = true;
70 | }
71 | setState(() {
72 |
73 | });
74 | }
75 |
76 | @override
77 | Widget build(BuildContext context) {
78 |
79 |
80 | return new Container(
81 | width: double.infinity,
82 | alignment: Alignment.centerLeft,
83 | child: new Text.rich(new TextSpan(
84 | children: [
85 | new TextSpan(
86 | text: _expand ? _body : _title,
87 | recognizer: new TapGestureRecognizer()
88 | ..onTap = () {
89 | expandText();
90 | },
91 | ),
92 | getExpandText(_expand),
93 | ],
94 | ),),
95 | );
96 | }
97 |
98 | getExpandText(bool expand) {
99 | return expand ? new TextSpan() : new TextSpan(
100 | text: '展开',
101 | recognizer: new TapGestureRecognizer()
102 | ..onTap = () {
103 | expandText();
104 | },
105 | style: new TextStyle(
106 | decoration: TextDecoration.underline,
107 | color: Colors.lightBlue,
108 | ),
109 | );
110 | }
111 | }
--------------------------------------------------------------------------------
/lib/pages/detail/MoviePopularComments/MoviePopularCommentsView.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:douban_movies/data/bean_move_detail.dart';
3 | import 'package:douban_movies/pages/views/ClipImageView.dart';
4 | import 'package:douban_movies/pages/views/StartsView.dart';
5 |
6 | class MoviePopularCommentsView extends StatelessWidget {
7 | final MovieDetail _detail;
8 |
9 | MoviePopularCommentsView(this._detail);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return _detail.popular_comments != null ?
14 | new Container(
15 | child: Column(
16 | children: [
17 | new CommentItemView(_detail.popular_comments[0]),
18 | ],
19 | ),
20 | ) : new Container();
21 | }
22 |
23 | }
24 |
25 | class CommentItemView extends StatelessWidget {
26 | final popular_comment _comment;
27 |
28 | CommentItemView(this._comment);
29 |
30 | @override
31 | Widget build(BuildContext context) {
32 | // TODO: implement build
33 | return new Container(
34 | child: new Column(
35 | children: [
36 | new CommentItemTopView(_comment),
37 | new Container(
38 | child: Text(
39 | '${_comment.content}',
40 | ),
41 | ),
42 | // new CommentItemBottomView(_comments),
43 | ],
44 | ),
45 | );
46 | }
47 | }
48 |
49 | class CommentItemTopView extends StatelessWidget {
50 | final popular_comment _comment;
51 |
52 | CommentItemTopView(this._comment);
53 |
54 | @override
55 | Widget build(BuildContext context) {
56 | return Container(
57 | child: new Row(
58 | children: [
59 | new ClipImageView(
60 | _comment.author.avatar,
61 | BorderRadius.circular(4.0),
62 | ),
63 | new Expanded(
64 | child: Container(
65 | child: new Column(
66 | children: [
67 | new Row(
68 | children: [
69 | new Container(
70 | child: new Text('${_comment.author.name}'),
71 | ),
72 | new Expanded(
73 | child: new Container(
74 | child: new StarItem(
75 | int.parse(_comment.rating.stars==null?50:_comment.rating.stars), 15.0,
76 | Colors.orange[300], true),
77 | ),
78 | ),
79 | ],
80 | ),
81 | new Container(
82 | child: Text('${_comment.created_at}'),
83 | ),
84 | ],
85 | ),
86 | )
87 | ),
88 | ],
89 | ),
90 | );
91 | }
92 | }
--------------------------------------------------------------------------------
/lib/pages/detail/MovieRating/MovieRating.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:douban_movies/data/bean_move_detail.dart';
3 | import 'package:douban_movies/pages/views/StartsView.dart';
4 |
5 | class MovieRatingView extends StatelessWidget {
6 | final MovieDetail detail;
7 |
8 | MovieRatingView(this.detail);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return new Container(
13 | decoration: new BoxDecoration(
14 | color: Colors.grey[500],
15 | borderRadius: new BorderRadius.all(new Radius.circular(5.0)),
16 | ),
17 | margin: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0),
18 | width: double.infinity,
19 | height: 160.0,
20 | child: new Column(
21 | children: [
22 | new Container(
23 | padding: EdgeInsets.only(top: 10.0, left: 10.0),
24 | child: new Text(
25 | '豆瓣评分',
26 | style: new TextStyle(
27 | color: Colors.white,
28 | ),
29 | ),
30 | height: 10.0,
31 | width: double.infinity,
32 | ),
33 | new Container(
34 | height: 110.0,
35 | width: double.infinity,
36 | child: new RateStarsView(detail),
37 | ),
38 | new Container(
39 | margin: EdgeInsets.only(left: 10.0, right: 10.0),
40 | child: new Divider(color: Colors.grey[300],),
41 | ),
42 | new Container(
43 | margin: EdgeInsets.only(right: 10.0),
44 | width: double.infinity,
45 | child: Text('${detail.getCollectPeopleCount()}k人看过 ${detail
46 | .getWishPeopleCount()}k人想看',
47 | style: TextStyle(
48 | color: Colors.grey[300],
49 | fontSize: 12.0,
50 | ),
51 | textAlign: TextAlign.end,),
52 | ),
53 | ],
54 | ),
55 | );
56 | }
57 | }
58 |
59 | class RateStarsView extends StatelessWidget {
60 | final MovieDetail detail;
61 |
62 | RateStarsView(this.detail);
63 |
64 | @override
65 | Widget build(BuildContext context) {
66 | // TODO: implement build
67 | return new Row(
68 | children: [
69 | new Expanded(
70 | flex: 3,
71 | child: new RateStarsLeftView(detail),
72 | ),
73 | new Expanded(
74 | flex: 7,
75 | child: new RateStarsRightView(detail),
76 | ),
77 | ],
78 | );
79 | }
80 | }
81 |
82 | ///评分区域中间左边的部分
83 | class RateStarsLeftView extends StatelessWidget {
84 | final MovieDetail detail;
85 |
86 | RateStarsLeftView(this.detail);
87 |
88 | @override
89 | Widget build(BuildContext context) {
90 | // TODO: implement build
91 | return new Column(
92 | children: [
93 | new Expanded(
94 | child: new Container(
95 | child: new Text(
96 | '${detail.rating.average}',
97 | style: new TextStyle(
98 | fontSize: 40.0,
99 | fontWeight: FontWeight.bold,
100 | color: Colors.white,
101 | ),
102 | ),
103 | alignment: Alignment.bottomRight,
104 | )),
105 | new Row(
106 | children: [
107 | new Expanded(child: new Container()),
108 | new Container(
109 | child: new StarItem(int.parse(detail.rating.stars), 15.0,
110 | Colors.orange[300], true),
111 | padding: EdgeInsets.only(bottom: 20.0),
112 | alignment: Alignment.topRight,
113 | )
114 | ],
115 | )
116 | ],
117 | );
118 | }
119 | }
120 |
121 | ///评分区域中间中部的部分
122 | class RateStarsRightView extends StatelessWidget {
123 | final MovieDetail detail;
124 |
125 | RateStarsRightView(this.detail);
126 |
127 | @override
128 | Widget build(BuildContext context) {
129 | // TODO: implement build
130 | return new Column(
131 | children: [
132 | new Expanded(child: new Container()),
133 | new Container(
134 | alignment: Alignment.bottomRight,
135 | margin: EdgeInsets.only(left: 5.0),
136 | child: new Column(
137 | children: [
138 | new StarAndProgressItem(detail.rating, 5),
139 | new StarAndProgressItem(detail.rating, 4),
140 | new StarAndProgressItem(detail.rating, 3),
141 | new StarAndProgressItem(detail.rating, 2),
142 | new StarAndProgressItem(detail.rating, 1),
143 | ],
144 | mainAxisSize: MainAxisSize.min,
145 | ),
146 | ),
147 | new Container(
148 | height: 20.0,
149 | width: double.infinity,
150 | margin: EdgeInsets.only(left: 145.0),
151 | alignment: Alignment.centerLeft,
152 | child: new Text('${detail.rating.details.getDetailTotal()}人评分',
153 | style: TextStyle(
154 | fontSize: 12.0,
155 | color: Colors.grey[300]
156 | ),
157 | textAlign: TextAlign.start,
158 | ),
159 | ),
160 | ],
161 | );
162 | }
163 | }
164 |
165 | class StarAndProgressItem extends StatelessWidget {
166 | final rate _rate;
167 | final int _starIndex;
168 |
169 | StarAndProgressItem(this._rate, this._starIndex);
170 |
171 | @override
172 | Widget build(BuildContext context) {
173 | return new Row(
174 | children: [
175 | new Container(
176 | width: 60.0,
177 | alignment: Alignment.centerRight,
178 | child: new Row(
179 | children: [
180 | new Expanded(child: new Container()),
181 | new Container(
182 | alignment: Alignment.centerRight,
183 | child: new StarItem(
184 | _starIndex * 10, 12.0, Colors.grey[300], false),
185 | )
186 | ],
187 | ),
188 | ),
189 | new Container(
190 | width: 150.0,
191 | child: new LinearProgressIndicator(
192 | value: _rate.details.getDetailIndexRate(_starIndex),
193 | backgroundColor: Colors.grey[600],
194 | ),
195 | ),
196 | ],
197 | );
198 | }
199 | }
--------------------------------------------------------------------------------
/lib/pages/detail/MovieTitle/MovieTitle.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:douban_movies/data/bean_move_detail.dart';
3 | import 'package:douban_movies/pages/views/ClipImageView.dart';
4 |
5 | ///Movie Title block
6 | class MovieTitleView extends StatelessWidget {
7 | final MovieDetail detail;
8 |
9 | MovieTitleView(this.detail);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return new Container(
14 | padding: new EdgeInsets.all(10.0),
15 | child: new Row(
16 | children: [
17 | new Container(
18 | width: 100.0,
19 | child: new ClipImageView(
20 | detail.images.medium,
21 | new BorderRadius.circular(4.0),
22 | ),
23 | ),
24 | new MovieTitleContentItem(detail),
25 | ],
26 | ),
27 | );
28 | }
29 | }
30 |
31 | ///Movie title 右边的内容区域
32 | class MovieTitleContentItem extends StatelessWidget {
33 | final MovieDetail detail;
34 |
35 | MovieTitleContentItem(this.detail);
36 |
37 | @override
38 | Widget build(BuildContext context) {
39 | return new Expanded(
40 | child: new Container(
41 | padding: new EdgeInsets.only(
42 | left: 10.0, top: 5.0, right: 5.0, bottom: 5.0),
43 | child: new Column(
44 | children: [
45 |
46 | /// Title
47 | new Container(
48 | width: double.infinity,
49 | child: new Text(
50 | detail.title,
51 | style: new TextStyle(
52 | fontWeight: FontWeight.bold,
53 | fontSize: 20.0,
54 | ),
55 | ),
56 | ),
57 |
58 | /// Title Top Desc
59 | new Container(
60 | margin: new EdgeInsets.only(top: 5.0, right: 5.0),
61 | width: double.infinity,
62 | alignment: Alignment.centerLeft,
63 | child: new Text(
64 | detail.getTitleDescTop(),
65 | style: new TextStyle(
66 | fontWeight: FontWeight.bold,
67 | fontSize: 15.0,
68 | ),
69 | ),
70 | ),
71 |
72 | ///Title Bottom Desc
73 | new Container(
74 | margin: new EdgeInsets.only(top: 5.0, right: 5.0),
75 | width: double.infinity,
76 | alignment: Alignment.centerLeft,
77 | child: new Text(
78 | detail.getTitleDescBottom(),
79 | style: new TextStyle(
80 | fontWeight: FontWeight.bold,
81 | color: Colors.grey,
82 | fontSize: 12.0,
83 | ),
84 | ),
85 | ),
86 |
87 | /// Title Bottom Buttons
88 | getTitleButtons()
89 | ],
90 | ),
91 | ),
92 | );
93 | }
94 |
95 | ///get Title Block bottom buttons
96 | getTitleButtons() {
97 | return new Container(
98 | margin: new EdgeInsets.only(top: 10.0),
99 | child: new Row(
100 | children: [
101 | new Expanded(
102 | flex: 1,
103 | child: new RaisedButton.icon(
104 | color: Colors.white,
105 | icon: new Icon(
106 | Icons.favorite_border,
107 | color: Colors.orange[400],
108 | ),
109 | label: new Text(
110 | '想看',
111 | style: new TextStyle(fontWeight: FontWeight.bold),
112 | ),
113 | onPressed: () {
114 | print('点击了按钮!');
115 | },
116 | )),
117 | new Padding(padding: new EdgeInsets.all(5.0)),
118 | new Expanded(
119 | flex: 1,
120 | child: new RaisedButton.icon(
121 | color: Colors.white,
122 | icon: new Icon(
123 | Icons.star_border,
124 | color: Colors.orange[400],
125 | ),
126 | label: new Text(
127 | '看过',
128 | style: new TextStyle(fontWeight: FontWeight.bold),
129 | ),
130 | onPressed: () {
131 | print('点击了按钮!');
132 | },
133 | )),
134 | ],
135 | ),
136 | );
137 | }
138 | }
--------------------------------------------------------------------------------
/lib/pages/detail/page_detail.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:douban_movies/res/value_string.dart';
3 | import 'package:douban_movies/pages/page_home.dart';
4 | import 'package:douban_movies/data/bean_move_list.dart' as MoveList;
5 | import 'package:douban_movies/net/http.dart';
6 | import 'package:douban_movies/data/bean_move_detail.dart';
7 | import 'package:douban_movies/pages/views/StartsView.dart';
8 | import 'package:transparent_image/transparent_image.dart';
9 | import 'package:douban_movies/pages/detail/MovieTitle/MovieTitle.dart';
10 | import 'package:douban_movies/pages/detail/MovieRating/MovieRating.dart';
11 | import 'package:douban_movies/pages/detail/MovieChannel/MovieChannel.dart';
12 | import 'package:douban_movies/pages/detail/MovieDesc/MovieDesc.dart';
13 | import 'package:douban_movies/pages/detail/MovieActors/MovieActors.dart';
14 | import 'package:douban_movies/pages/detail/MovieComments/MovieCommentsView.dart';
15 |
16 | class DetailPage extends StatelessWidget {
17 | final subjectItem;
18 |
19 | DetailPage(this.subjectItem);
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return new Scaffold(
24 | appBar: new AppBar(
25 | title: new Text(subjectItem.getTitle()),
26 | ),
27 | body: new DetailContent(subjectItem.id),
28 | );
29 | }
30 | }
31 |
32 | class DetailContent extends StatefulWidget {
33 | final String id;
34 |
35 | DetailContent(this.id);
36 |
37 | @override
38 | _DetailContentState createState() => _DetailContentState(id);
39 | }
40 |
41 | class _DetailContentState extends State {
42 | final String id;
43 | MovieDetail detail;
44 |
45 | _DetailContentState(this.id);
46 |
47 | @override
48 | void initState() {
49 | super.initState();
50 | loadData();
51 | }
52 |
53 | //获取电影详情
54 | loadData() async {
55 | var datas = await HttpUtils.get(
56 | HttpUtils.URL_GET_MOVIE_DETAIL + id,
57 | map: {
58 | 'apikey': HttpUtils.URL_API_KEY,
59 | 'udid': HttpUtils.URL_UDID,
60 | 'city': '上海',
61 | 'client': '',
62 | },
63 | );
64 | detail = new MovieDetail(datas);
65 | setState(() {});
66 | }
67 |
68 | @override
69 | Widget build(BuildContext context) {
70 | // TODO: implement build
71 | return new Container(
72 | child: detail == null ? new Container() : new MovieDetial(detail),
73 | );
74 | }
75 | }
76 |
77 | class MovieDetial extends StatelessWidget {
78 | final MovieDetail detail;
79 |
80 | MovieDetial(this.detail);
81 |
82 | @override
83 | Widget build(BuildContext context) {
84 | return new ListView(
85 | children: [
86 | new MovieTitleView(detail),
87 | new MovieRatingView(detail),
88 | new Container(
89 | padding: new EdgeInsets.only(left: 10.0, right: 10.0),
90 | child: new Divider(color: Colors.grey,),
91 | ),
92 | new Container(
93 | height: 50.0,
94 | child: new MovieChnnelView(detail),
95 | ),
96 | new MovieDescView(detail),
97 | new MovieActorsView(detail),
98 | new MovieCommentsView(detail),
99 | // new Expanded(child: new Container(),
100 | // ),
101 | ],
102 | );
103 | }
104 | }
105 |
106 |
107 |
--------------------------------------------------------------------------------
/lib/pages/page_home.dart:
--------------------------------------------------------------------------------
1 | import 'package:douban_movies/WanAndroid/navigator_router_utils.dart';
2 | import 'package:douban_movies/data/bean_move_list.dart';
3 | import 'package:douban_movies/net/http.dart';
4 | import 'package:douban_movies/pages/detail/page_detail.dart';
5 | import 'package:douban_movies/pages/views/ClipImageView.dart';
6 | import 'package:douban_movies/res/value_string.dart';
7 | import 'package:flutter/material.dart';
8 | import 'package:transparent_image/transparent_image.dart';
9 |
10 | import 'views/StartsView.dart';
11 |
12 | final List tabs = [
13 | new Tab(text: '正在热映'),
14 | new Tab(text: '即将上映'),
15 | new Tab(text: 'Top250'),
16 | // new Tab(text: '口碑榜'),
17 | // new Tab(text: '北美票房榜'),
18 | new Tab(text: '新片榜'),
19 | ];
20 |
21 | class HomePage extends StatelessWidget {
22 | @override
23 | Widget build(BuildContext context) {
24 | return new MaterialApp(
25 | title: AppStrings.AppName,
26 | home: new DefaultTabController(
27 | length: tabs.length,
28 | child: new Scaffold(
29 | appBar: new AppBar(
30 | title: new Text(AppStrings.HomePageAppBarTitle),
31 | bottom: new TabBar(
32 | tabs: tabs,
33 | isScrollable: true,
34 | ),
35 | ),
36 | body: new TabBarView(
37 | children: tabs.map((Tab tab) {
38 | return HomeContent(tab);
39 | }).toList(),
40 | ),
41 | ),
42 | ),
43 | );
44 | }
45 | }
46 |
47 | /**
48 | * 创建显示在首页的内容
49 | */
50 | class HomeContent extends StatefulWidget {
51 | final Tab _tab;
52 |
53 | HomeContent(this._tab);
54 |
55 | @override
56 | _HomeContentState createState() => _HomeContentState(_tab);
57 | }
58 |
59 | class _HomeContentState extends State
60 | with AutomaticKeepAliveClientMixin {
61 | final Tab _tab;
62 | List _subjects = new List();
63 | ScrollController _scrollController = new ScrollController();
64 | final GlobalKey _refreshIndicaterState =
65 | GlobalKey();
66 | int start = 0;
67 | int limit = 25;
68 | int page = 0;
69 |
70 | _HomeContentState(this._tab);
71 |
72 | @override
73 | void initState() {
74 | super.initState();
75 | _scrollController.addListener(() {
76 | if (_scrollController.position.pixels ==
77 | _scrollController.position.maxScrollExtent) {
78 | _getMore();
79 | }
80 | });
81 | _loadData();
82 | new Future.delayed(const Duration(seconds: 0), () {
83 | _refreshIndicaterState.currentState.show().then((e) {});
84 | return true;
85 | });
86 | }
87 |
88 | //获取电影列表
89 | Future _loadData() async {
90 | page = 0;
91 | String url = HttpUtils.URL_GET_MOVIE_LIST_IN_THEATERS;
92 | Map map = {
93 | 'apikey': HttpUtils.URL_API_KEY,
94 | 'udid': HttpUtils.URL_UDID,
95 | 'city': '上海',
96 | 'client': '',
97 | 'start': start + page * limit,
98 | 'count': limit
99 | };
100 | switch (_tab.text) {
101 | case '正在热映':
102 | url = HttpUtils.URL_GET_MOVIE_LIST_IN_THEATERS;
103 | break;
104 | case '即将上映':
105 | url = HttpUtils.URL_GET_MOVIE_LIST_COMING_SOON;
106 | break;
107 | case 'Top250':
108 | url = HttpUtils.URL_GET_MOVIE_LIST_TOP_250;
109 | break;
110 | case '口碑榜':
111 | url = HttpUtils.URL_GET_MOVIE_LIST_WEEKLY;
112 | map = {
113 | 'apikey': HttpUtils.URL_API_KEY,
114 | 'udid': '',
115 | 'city': '上海',
116 | 'client': '',
117 | };
118 | break;
119 | case '北美票房榜':
120 | url = HttpUtils.URL_GET_MOVIE_LIST_US_BOX;
121 | map = {
122 | 'apikey': HttpUtils.URL_API_KEY,
123 | 'udid': '',
124 | 'client': '',
125 | };
126 | break;
127 | case '新片榜':
128 | url = HttpUtils.URL_GET_MOVIE_LIST_NEW_MOVIES;
129 | map = {
130 | 'apikey': HttpUtils.URL_API_KEY,
131 | 'udid': '',
132 | 'client': '',
133 | };
134 | break;
135 | }
136 | var datas = await HttpUtils.get(
137 | url,
138 | map: map,
139 | );
140 | MovieList moveList = new MovieList(datas);
141 | _subjects = moveList.subjects;
142 | setState(() {});
143 | }
144 |
145 | @override
146 | Widget build(BuildContext context) {
147 | return new RefreshIndicator(
148 | key: _refreshIndicaterState,
149 | child: new Container(
150 | child: new ListView.builder(
151 | // physics: new AlwaysScrollableScrollPhysics(),
152 | controller: _scrollController,
153 | itemCount: _subjects.length,
154 | itemBuilder: (context, i) {
155 | if (i.isOdd) return new Divider();
156 | int index = i ~/ 2;
157 | return new Container(
158 | margin: EdgeInsets.only(top: i == 0 ? 10.0 : 0),
159 | child: new MoveItem(_subjects[index]),
160 | );
161 | },
162 | ),
163 | ),
164 | onRefresh: _loadData,
165 | );
166 | }
167 |
168 | void _getMore() async {
169 | page++;
170 | print('$page');
171 | String url = HttpUtils.URL_GET_MOVIE_LIST_IN_THEATERS;
172 | bool canGetMore = true;
173 | switch (_tab.text) {
174 | case '正在热映':
175 | url = HttpUtils.URL_GET_MOVIE_LIST_IN_THEATERS;
176 | break;
177 | case '即将上映':
178 | url = HttpUtils.URL_GET_MOVIE_LIST_COMING_SOON;
179 | break;
180 | case 'Top250':
181 | url = HttpUtils.URL_GET_MOVIE_LIST_TOP_250;
182 | break;
183 | case '口碑榜':
184 | canGetMore = false;
185 | url = HttpUtils.URL_GET_MOVIE_LIST_WEEKLY;
186 | break;
187 | case '北美票房榜':
188 | canGetMore = false;
189 | url = HttpUtils.URL_GET_MOVIE_LIST_US_BOX;
190 | break;
191 | case '新片榜':
192 | canGetMore = false;
193 | url = HttpUtils.URL_GET_MOVIE_LIST_NEW_MOVIES;
194 | break;
195 | }
196 | if (canGetMore) {
197 | var datas = await HttpUtils.get(url, map: {
198 | 'apikey': HttpUtils.URL_API_KEY,
199 | 'udid': HttpUtils.URL_UDID,
200 | 'city': '上海',
201 | 'client': '',
202 | 'start': start + page * limit,
203 | 'count': limit
204 | });
205 | MovieList moveList = new MovieList(datas);
206 | _subjects.addAll(moveList.subjects);
207 | }
208 | setState(() {});
209 | }
210 |
211 | @override
212 | // TODO: implement wantKeepAlive
213 | bool get wantKeepAlive => true;
214 | }
215 |
216 | class MoveItem extends StatelessWidget {
217 | final subject subjectData;
218 |
219 | MoveItem(this.subjectData);
220 |
221 | @override
222 | Widget build(BuildContext context) {
223 | return new GestureDetector(
224 | onTap: () {
225 | NavigatorRouterUtils.pushToPage(context, new DetailPage(subjectData));
226 | },
227 | child: new Row(
228 | children: [
229 | new Container(
230 | width: 110.0,
231 | padding: EdgeInsets.only(left: 10.0),
232 | //使用图片渐入框架
233 | child: ClipImageView(
234 | subjectData.images.medium, new BorderRadius.circular(4.0)),
235 | ),
236 | new Expanded(
237 | child: new Container(
238 | height: 150.0,
239 | padding: EdgeInsets.all(10.0),
240 | child: new Column(
241 | children: [
242 | new Container(
243 | width: double.infinity,
244 | child: new Text(
245 | subjectData.title,
246 | style: new TextStyle(
247 | fontSize: 18.0,
248 | fontWeight: FontWeight.bold,
249 | ),
250 | textAlign: TextAlign.left,
251 | ),
252 | ),
253 | getRatingItem(subjectData),
254 | new Container(
255 | margin: new EdgeInsets.only(top: 10.0),
256 | width: double.infinity,
257 | child: new Text(
258 | '${MovieList.getDetailDesc(subjectData)}',
259 | textAlign: TextAlign.left,
260 | style: TextStyle(
261 | color: Colors.grey,
262 | ),
263 | ),
264 | ),
265 | // new Expanded(
266 | // child: new Container(
267 | // padding: new EdgeInsets.only(top:10.0),
268 | // child: new CastsView(subjectData.casts),
269 | // ),
270 | // ),
271 | ],
272 | ),
273 | ),
274 | ),
275 | ],
276 | ),
277 | );
278 | }
279 |
280 | getRatingItem(subject subjectData) {
281 | return int.parse(subjectData.rating.stars) == 0
282 | ? new Container(
283 | width: double.infinity,
284 | margin: new EdgeInsets.only(top: 10.0),
285 | child: Text(
286 | '暂无评分',
287 | textAlign: TextAlign.start,
288 | style: TextStyle(
289 | color: Colors.grey,
290 | fontSize: 12.0,
291 | ),
292 | ),
293 | )
294 | : new Container(
295 | margin: new EdgeInsets.only(top: 10.0),
296 | child: new Row(
297 | children: [
298 | new StarItem(int.parse(subjectData.rating.stars), 15.0,
299 | Colors.orange[300], true),
300 | new Container(
301 | margin: EdgeInsets.only(left: 5.0),
302 | child: new Text(
303 | '${subjectData.rating.average}',
304 | style: TextStyle(
305 | fontSize: 12.0,
306 | ),
307 | ),
308 | )
309 | ],
310 | ),
311 | );
312 | }
313 | }
314 |
315 | class CastsView extends StatelessWidget {
316 | final List casts;
317 |
318 | CastsView(this.casts);
319 |
320 | @override
321 | Widget build(BuildContext context) {
322 | // TODO: implement build
323 | return casts == null
324 | ? new Container()
325 | : new ListView.builder(
326 | scrollDirection: Axis.horizontal,
327 | itemCount: casts.length,
328 | itemBuilder: (context, i) {
329 | return new Column(
330 | children: [
331 | new Container(
332 | padding: new EdgeInsets.only(
333 | left: i != 0 ? 10.0 : 0.0, top: 5.0),
334 | child: new ClipOval(
335 | child: new FadeInImage.memoryNetwork(
336 | placeholder: kTransparentImage,
337 | fit: BoxFit.fitWidth,
338 | image: casts[i].avatars.small,
339 | height: 45.0,
340 | width: 45.0,
341 | ),
342 | ),
343 | ),
344 | ],
345 | );
346 | },
347 | );
348 | }
349 | }
350 |
--------------------------------------------------------------------------------
/lib/pages/views/Chips.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | class _ChipsTile extends StatelessWidget {
3 | const _ChipsTile({
4 | Key key,
5 | this.label,
6 | this.children,
7 | }) : super(key: key);
8 |
9 | final String label;
10 | final List children;
11 |
12 | // Wraps a list of chips into a ListTile for display as a section in the demo.
13 | @override
14 | Widget build(BuildContext context) {
15 | final List cardChildren = [
16 | Container(
17 | padding: const EdgeInsets.only(top: 16.0, bottom: 4.0),
18 | alignment: Alignment.center,
19 | child: Text(label, textAlign: TextAlign.start),
20 | ),
21 | ];
22 | if (children.isNotEmpty) {
23 | cardChildren.add(Wrap(
24 | children: children.map((Widget chip) {
25 | return Padding(
26 | padding: const EdgeInsets.all(2.0),
27 | child: chip,
28 | );
29 | }).toList()));
30 | } else {
31 | final TextStyle textStyle = Theme.of(context).textTheme.caption.copyWith(fontStyle: FontStyle.italic);
32 | cardChildren.add(
33 | Semantics(
34 | container: true,
35 | child: Container(
36 | alignment: Alignment.center,
37 | constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0),
38 | padding: const EdgeInsets.all(8.0),
39 | child: Text('None', style: textStyle),
40 | ),
41 | ));
42 | }
43 |
44 | return Card(
45 | semanticContainer: false,
46 | child: Column(
47 | mainAxisSize: MainAxisSize.min,
48 | children: cardChildren,
49 | )
50 | );
51 | }
52 | }
--------------------------------------------------------------------------------
/lib/pages/views/ClipImageView.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:transparent_image/transparent_image.dart';
3 |
4 | class ClipImageView extends StatelessWidget {
5 | final String imgUrl;
6 | final BorderRadius borderRadius;
7 |
8 | ClipImageView(this.imgUrl, this.borderRadius);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | // TODO: implement build
13 | return new ClipRRect(
14 | child: new FadeInImage.memoryNetwork(
15 | fit: BoxFit.fitWidth,
16 | placeholder: kTransparentImage,
17 | image: imgUrl,
18 | ),
19 | borderRadius: borderRadius,
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/pages/views/StartsView.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class StarItem extends StatelessWidget {
4 | final int _startCount;
5 | final double _starSize;
6 | final Color _starColor;
7 | final bool _hasBorderStar;
8 |
9 | StarItem(
10 | this._startCount, this._starSize, this._starColor, this._hasBorderStar);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return getStarView(_startCount, _starSize, _starColor, _hasBorderStar);
15 | }
16 | }
17 |
18 | getStarView(int starts, double starSize, Color starColor, bool hasBorderStar) {
19 | //获取半实心Start的数量
20 | int halfStarCount = starts % 10 == 0 ? 0 : 1;
21 | //获取实心Start的数量
22 | int fullStartCount = starts ~/ 10;
23 |
24 | List starList = [];
25 |
26 | for (var i = 0; i < fullStartCount; i++) {
27 | starList.add(new Icon(
28 | Icons.star,
29 | color: starColor,
30 | size: starSize,
31 | ));
32 | }
33 |
34 | if (halfStarCount != 0) {
35 | starList.add(new Icon(
36 | Icons.star_half,
37 | color: starColor,
38 | size: starSize,
39 | ));
40 | }
41 |
42 | if (hasBorderStar) {
43 | int borderStartCount=halfStarCount!=0?4 - fullStartCount:5-fullStartCount;
44 | for (var i = 0; i < borderStartCount; i++) {
45 | starList.add(new Icon(
46 | Icons.star_border,
47 | color: starColor,
48 | size: starSize,
49 | ));
50 | }
51 | }
52 |
53 | return new Row(
54 | children: starList,
55 | );
56 | }
57 |
--------------------------------------------------------------------------------
/lib/res/value_string.dart:
--------------------------------------------------------------------------------
1 | class AppStrings {
2 | static String AppName = '豆瓣电影';
3 | static String HomePageAppBarTitle = '豆瓣电影';
4 | static String DetailPageAppBarTitle = '电影详情';
5 | }
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: douban_movies
2 | description: A new Flutter application.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # Read more about versioning at semver.org.
10 | version: 1.0.0+1
11 |
12 | environment:
13 | sdk: ">=2.0.0-dev.68.0 <3.0.0"
14 |
15 | dependencies:
16 | flutter:
17 | sdk: flutter
18 |
19 | # The following adds the Cupertino Icons font to your application.
20 | # Use with the CupertinoIcons class for iOS style icons.
21 | cupertino_icons: ^0.1.2
22 | dio: ^1.0.6
23 | cached_network_image: ^0.4.1+1
24 | transparent_image: ^0.1.0
25 | flutter_webview_plugin: ^0.3.0+2
26 | html_unescape: ^1.0.1+2
27 | sqflite: ^0.13.0+1
28 | shared_preferences: ^0.4.3
29 | flutter_swiper: ^1.1.4
30 | webview_flutter: ^0.3.3+1
31 |
32 |
33 | dev_dependencies:
34 | flutter_test:
35 | sdk: flutter
36 |
37 |
38 | # For information on the generic Dart part of this file, see the
39 | # following page: https://www.dartlang.org/tools/pub/pubspec
40 |
41 | # The following section is specific to Flutter.
42 | flutter:
43 |
44 | # The following line ensures that the Material Icons font is
45 | # included with your application, so that you can use the icons in
46 | # the material Icons class.
47 | uses-material-design: true
48 |
49 | # To add assets to your application, add an assets section, like this:
50 | # assets:
51 | # - images/a_dot_burr.jpeg
52 | # - images/a_dot_ham.jpeg
53 |
54 | # An image asset can refer to one or more resolution-specific "variants", see
55 | # https://flutter.io/assets-and-images/#resolution-aware.
56 |
57 | # For details regarding adding assets from package dependencies, see
58 | # https://flutter.io/assets-and-images/#from-packages
59 |
60 | # To add custom fonts to your application, add a fonts section here,
61 | # in this "flutter" section. Each entry in this list should have a
62 | # "family" key with the font family name, and a "fonts" key with a
63 | # list giving the asset and other descriptors for the font. For
64 | # example:
65 | fonts:
66 | - family: IconFont
67 | fonts:
68 | - asset: static/font/iconfont.ttf
69 | # - asset: fonts/Schyler-Italic.ttf
70 | # style: italic
71 | # - family: Trajan Pro
72 | # fonts:
73 | # - asset: fonts/TrajanPro.ttf
74 | # - asset: fonts/TrajanPro_Bold.ttf
75 | # weight: 700
76 | #
77 | # For details regarding fonts from package dependencies,
78 | # see https://flutter.io/custom-fonts/#from-packages
79 |
--------------------------------------------------------------------------------
/static/font/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mhgd3250905/WANAndroid_Proj/a34763eb11f342ee3042bfaa2197a71b25fe5804/static/font/iconfont.ttf
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | // To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
3 | // provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to
4 | // find child widgets in the widget tree, read text, and verify that the values of widget properties
5 | // are correct.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_test/flutter_test.dart';
9 |
10 | import 'package:douban_movies/main.dart';
11 |
12 | void main() {
13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
14 | // Build our app and trigger a frame.
15 | await tester.pumpWidget(new MyApp());
16 |
17 | // Verify that our counter starts at 0.
18 | expect(find.text('0'), findsOneWidget);
19 | expect(find.text('1'), findsNothing);
20 |
21 | // Tap the '+' icon and trigger a frame.
22 | await tester.tap(find.byIcon(Icons.add));
23 | await tester.pump();
24 |
25 | // Verify that our counter has incremented.
26 | expect(find.text('0'), findsNothing);
27 | expect(find.text('1'), findsOneWidget);
28 | });
29 | }
30 |
--------------------------------------------------------------------------------