Repository: ngu2008/wanandroid Branch: master Commit: a42574101ad1 Files: 86 Total size: 234.2 KB Directory structure: gitextract_ft2s6f_c/ ├── .gitignore ├── .metadata ├── README.md ├── android/ │ ├── app/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── ngu/ │ │ │ └── wanandroidngu/ │ │ │ └── MainActivity.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── launch_background.xml │ │ └── values/ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle/ │ │ └── wrapper/ │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── key.properties │ ├── settings.gradle │ └── wandroid_ngu.jks ├── interview.md ├── ios/ │ ├── Flutter/ │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner/ │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets/ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ └── LaunchImage.imageset/ │ │ │ ├── Contents.json │ │ │ └── README.md │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── main.m │ ├── Runner.xcodeproj/ │ │ ├── project.pbxproj │ │ ├── project.xcworkspace/ │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── xcschemes/ │ │ └── Runner.xcscheme │ └── Runner.xcworkspace/ │ └── contents.xcworkspacedata ├── lib/ │ ├── app.dart │ ├── base/ │ │ └── _base_widget.dart │ ├── common/ │ │ ├── application.dart │ │ └── user.dart │ ├── db/ │ │ └── db_helper.dart │ ├── event/ │ │ ├── change_theme_event.dart │ │ └── login_event.dart │ ├── http/ │ │ ├── api.dart │ │ ├── api_service.dart │ │ └── dio_manager.dart │ ├── loading.dart │ ├── main.dart │ ├── model/ │ │ ├── article_model.dart │ │ ├── banner_model.dart │ │ ├── base_model.dart │ │ ├── collection_model.dart │ │ ├── common_websit_model.dart │ │ ├── common_website_model.dart │ │ ├── hotword_model.dart │ │ ├── hotword_result_model.dart │ │ ├── navi_model.dart │ │ ├── pretty_model.dart │ │ ├── project_tree_model.dart │ │ ├── projectlist_model.dart │ │ ├── system_tree_content_model.dart │ │ ├── system_tree_model.dart │ │ ├── todo_item.dart │ │ ├── todolist_model.dart │ │ ├── user_model.dart │ │ ├── website_collection_model.dart │ │ ├── wx_article_content_model.dart │ │ └── wx_article_title_model.dart │ ├── splash_screen.dart │ ├── ui/ │ │ ├── drawer/ │ │ │ ├── about.dart │ │ │ ├── collctions.dart │ │ │ ├── common_website.dart │ │ │ ├── drawer.dart │ │ │ └── pretty.dart │ │ ├── home/ │ │ │ ├── banner.dart │ │ │ └── home_page.dart │ │ ├── knowledge/ │ │ │ ├── knowledge.dart │ │ │ └── knowledge_content.dart │ │ ├── login/ │ │ │ └── login_page.dart │ │ ├── navigation/ │ │ │ └── navigation.dart │ │ ├── project/ │ │ │ └── project.dart │ │ ├── public_ui/ │ │ │ └── webview_page.dart │ │ ├── publicc/ │ │ │ └── publicc.dart │ │ └── search/ │ │ ├── hot_search_result.dart │ │ └── search.dart │ └── util/ │ ├── bubble_indication_painter.dart │ ├── style_util.dart │ ├── theme_util.dart │ └── utils.dart ├── pubspec.yaml └── test/ └── widget_test.dart ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Miscellaneous *.class *.lock *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # Visual Studio Code related .vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .packages .pub-cache/ .pub/ build/ # Android related **/android/**/gradle-wrapper.jar **/android/.gradle **/android/captures/ **/android/gradlew **/android/gradlew.bat **/android/local.properties **/android/**/GeneratedPluginRegistrant.java # iOS/XCode related **/ios/**/*.mode1v3 **/ios/**/*.mode2v3 **/ios/**/*.moved-aside **/ios/**/*.pbxuser **/ios/**/*.perspectivev3 **/ios/**/*sync/ **/ios/**/.sconsign.dblite **/ios/**/.tags* **/ios/**/.vagrant/ **/ios/**/DerivedData/ **/ios/**/Icon? **/ios/**/Pods/ **/ios/**/.symlinks/ **/ios/**/profile **/ios/**/xcuserdata **/ios/.generated/ **/ios/Flutter/App.framework **/ios/Flutter/Flutter.framework **/ios/Flutter/Generated.xcconfig **/ios/Flutter/app.flx **/ios/Flutter/app.zip **/ios/Flutter/flutter_assets/ **/ios/ServiceDefinitions.json **/ios/Runner/GeneratedPluginRegistrant.* # Exceptions to above rules. !**/ios/**/default.mode1v3 !**/ios/**/default.mode2v3 !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages ================================================ FILE: .metadata ================================================ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled and should not be manually edited. version: revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b channel: stable project_type: app ================================================ FILE: README.md ================================================ ## Flutter学习资源汇总持续更新中...... - [Flutter官方网站](https://flutter.dev/) - [Flutter中文网](https://flutterchina.club/) - wendux的[Flutter实战](https://book.flutterchina.club/) - Flutter官方example[flutter_gallery](https://github.com/flutter/flutter/tree/master/examples/flutter_gallery) - [阿里巴巴咸鱼团队系列文章](https://www.yuque.com/xytech/flutter) - [阿里巴巴flutter-go](https://github.com/alibaba/flutter-go),flutter 开发者帮助 APP,包含 flutter 常用 140+ 组件的demo 演示与中文文档 - [awesome-flutter](https://github.com/Solido/awesome-flutter)包含居多优秀的Flutter库,工具,教程,文章等 - [玩Android跨平台项目](https://www.wanandroid.com/project/list/1?cid=402) - 非常有用的[Json转Model插件](https://github.com/neverwoodsS/idea_dart_json_format) - [Flutter-Notebook](https://github.com/OpenFlutter/Flutter-Notebook),提供了很多优秀样例和Demo - [Flutter-plugins](https://github.com/flutter/plugins),flutter官方插件,提供了众多优秀插件 - 掘金作者[恋猫de小郭系列文章](https://juejin.im/user/582aca2ba22b9d006b59ae68/posts) ## 前言 - 这是一款使用Flutter写的WanAndroid客户端应用,在Android和IOS都完美运行 - ~~可以用来入门Flutter,简单明了,适合初学者~~ - [项目完全开源](https://github.com/ngu2008/wanandroid_ngu),如果本项目确实能够帮助到你学习Flutter,谢谢start一下,有问题请提交Issues,我会及时回复 ## 环境搭建 - 根据[Flutter中文网](https://flutterchina.club/get-started/install)搭建开发环境,使用Android Studio安装Flutter插件,点击pubspec.yaml的package get,然后运行 ## APP下载 - Android[点击下载](https://www.pgyer.com/haFL),或者扫描下方二维码下载 ![](screenshot/a7.png) - 暂不支持IOS版本下载,请自行clone项目代码运行。 ## App目录结构 >- |--lib > - |-- main (入口类) > - |-- loading (启动页) > - |-- splash_screen (引导页) > - |-- util (工具类) > - |-- base (基类,封装基类BaseWidget和BaseWidgetState) > - |-- http (网络请求相关类) > - |-- common (常用类) > - |-- event (事件类) > - |-- model (实体类) > - |-- ui (界面相关) > - |-- util (工具类) ## 功能介绍 #### V1.5版本 - 常用网站增加数据库[sqflite](https://pub.flutter-io.cn/packages/sqflite)功能 - 修复注册登录按钮颜色与主题色不一致的问题 #### V1.4版本 - 增加切换主题 - 封装基类BaseWidget和BaseWidgetState - 显示隐藏AppBar - 增加状态页切换(数据加载中,数据加载失败,空数据) #### V1.3版本 - 新增搜索和搜索结果列表 - 新增页面正在加载... - 整个界面UI风格修改 #### V1.2版本 - 新增福利,妹子图,使用[photo_view](https://pub.flutter-io.cn/packages/photo_view),你懂得 - 新增分享[share](https://pub.flutter-io.cn/packages/share) - 新增常用网站 - 新增关于作者,退出登录 #### V1.1版本 - 新增引导页[flutter-intro-slider](https://github.com/duytq94/flutter-intro-slider) - 列表页悬浮FloatingActionButton,点击迅速回到顶部 - 新增注册、登录、我的收藏,增加侧滑抽屉,详见截图 #### V1.0版本 - 项目首页、知识体系、公众号、导航、项目、各个页面,和详情页面 - 主要的UI包括首页轮播图和列表,体系流式布局,公众号导航TabBar,以及下拉刷新和加载更多 - 轮播图使用的是开源库[flutter_swiper](https://github.com/best-flutter/flutter_swiper) - 网络请求使用的是开源库[dio](https://github.com/flutterchina/dio) ## 我的主页 - [掘金](https://juejin.im/user/5b319afee51d455e2c32fb5b/posts) - [CSDN](https://blog.csdn.net/zw2008224044) ## 应用截图 | 福利,妹子图 | 导航页 | 导航页 | | :--: | :--: | :--: | | 福利,妹子图 | 导航页 | 导航页 | | 登录 | 注册 | 分享 | | :--: | :--: | :--: | | 登录 | 注册 | 分享 | | 关于作者 | 常用网站 | 侧滑抽屉 | | :--: | :--: | :--: | | 关于作者 | 常用网站 | 侧滑抽屉 | | 首页 | 体系 | 公众号 | | :--: | :--: | :--: | | 首页 | 体系 | 公众号 | | 导航 | 项目 | 基础知识 | | :--: | :--: | :--: | | 导航 | 项目 | 基础知识 | | 我的收藏 | 详情页 |详情页 | | :--: | :--: |:--: | | 我的收藏 | 详情页 | 热门搜索 | | 搜索列表 | 正在加载| 加载错误| | :--: | :--: |:--: | | 搜索列表 | 正在加载 |加载错误 | | 正在加载| 正在加载 | | | :--: | :--: |:--: | | 数据为空 | 切换主题 | | ## 感谢 1. 特别感谢github开源作者[shijiacheng](https://github.com/shijiacheng/wanandroid_flutter) 2. 感谢鸿洋大神及[玩Android官网](http://www.wanandroid.com/)提供的[开放API](http://www.wanandroid.com/blog/show/2) 3. 感谢[干货集中营 API](http://gank.io/api) ## 使用开源库 - [shared_preferences](https://pub.dartlang.org/packages/shared_preferences) - [fluttertoast](https://pub.dartlang.org/packages/fluttertoast) - [share](https://pub.flutter-io.cn/packages/share) - [flutter_swiper](https://pub.flutter-io.cn/packages/flutter_swiper) - [cupertino_icons](https://pub.flutter-io.cn/packages/cupertino_icons) - [flutter_webview_plugin](https://pub.flutter-io.cn/packages/flutter_webview_plugin) - [dio](https://pub.flutter-io.cn/packages/dio) - [flutter-intro-slider](https://github.com/duytq94/flutter-intro-slider) - [photo_view](https://pub.flutter-io.cn/packages/photo_view) - [sqflite](https://pub.flutter-io.cn/packages/sqflite) - [path_provider ](https://pub.flutter-io.cn/packages/path_provider#-installing-tab-) ## 欢迎关注我的微信公众号 ![](screenshot/wechat.jpg) ================================================ FILE: android/app/build.gradle ================================================ def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { localPropertiesFile.withReader('UTF-8') { reader -> localProperties.load(reader) } } def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { flutterVersionCode = '1' } def flutterVersionName = localProperties.getProperty('flutter.versionName') if (flutterVersionName == null) { flutterVersionName = '1.0' } apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" def keystorePropertiesFile = rootProject.file("key.properties") def keystoreProperties = new Properties() keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) android { compileSdkVersion 28 lintOptions { disable 'InvalidPackage' } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.ngu.wanandroidngu" minSdkVersion 16 targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true } signingConfigs { release { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } } buildTypes { release { signingConfig signingConfigs.release } } } flutter { source '../..' } dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' } ================================================ FILE: android/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/app/src/main/java/com/ngu/wanandroidngu/MainActivity.java ================================================ package com.ngu.wanandroidngu; import android.os.Bundle; import io.flutter.app.FlutterActivity; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); } } ================================================ FILE: android/app/src/main/res/drawable/launch_background.xml ================================================ ================================================ FILE: android/app/src/main/res/values/styles.xml ================================================ ================================================ FILE: android/build.gradle ================================================ buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' } } allprojects { repositories { google() jcenter() } } rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } subprojects { project.evaluationDependsOn(':app') } task clean(type: Delete) { delete rootProject.buildDir } ================================================ FILE: android/gradle/wrapper/gradle-wrapper.properties ================================================ #Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip ================================================ FILE: android/gradle.properties ================================================ android.enableJetifier=true android.useAndroidX=true org.gradle.jvmargs=-Xmx1536M ================================================ FILE: android/key.properties ================================================ storePassword=wandroid_ngu keyPassword=wandroid_ngu keyAlias=wandroid_ngu storeFile=../wandroid_ngu.jks ================================================ FILE: android/settings.gradle ================================================ include ':app' def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() def plugins = new Properties() def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') if (pluginsFile.exists()) { pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } } plugins.each { name, path -> def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() include ":$name" project(":$name").projectDir = pluginDirectory } ================================================ FILE: interview.md ================================================ # 一道面试题 > 分享一道面试题,结果有点出乎意料 代码如下:输出结果是什么? public class Test { public static void main(String[] args) { Set stack = new HashSet<>(); for (Short i = 0; i < 100; i++) { stack.add(i); stack.remove(i - 1); } System.out.println(stack.size()); } - 答案是100,i-1这里用到了隐式类型转换i-1会转成int型的减法,所以在remove时,根本没有那个对象,所以无论怎么调stack.remove(i-1)都不会有元素移出,所以答案是100. ================================================ FILE: ios/Flutter/AppFrameworkInfo.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable App CFBundleIdentifier io.flutter.flutter.app CFBundleInfoDictionaryVersion 6.0 CFBundleName App CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1.0 MinimumOSVersion 8.0 ================================================ FILE: ios/Flutter/Debug.xcconfig ================================================ #include "Generated.xcconfig" ================================================ FILE: ios/Flutter/Release.xcconfig ================================================ #include "Generated.xcconfig" ================================================ FILE: ios/Runner/AppDelegate.h ================================================ #import #import @interface AppDelegate : FlutterAppDelegate @end ================================================ FILE: ios/Runner/AppDelegate.m ================================================ #include "AppDelegate.h" #include "GeneratedPluginRegistrant.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant registerWithRegistry:self]; // Override point for customization after application launch. return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @end ================================================ FILE: ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "20x20", "idiom" : "iphone", "filename" : "Icon-App-20x20@2x.png", "scale" : "2x" }, { "size" : "20x20", "idiom" : "iphone", "filename" : "Icon-App-20x20@3x.png", "scale" : "3x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-App-29x29@1x.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-App-29x29@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-App-29x29@3x.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-App-40x40@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-App-40x40@3x.png", "scale" : "3x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-App-60x60@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-App-60x60@3x.png", "scale" : "3x" }, { "size" : "20x20", "idiom" : "ipad", "filename" : "Icon-App-20x20@1x.png", "scale" : "1x" }, { "size" : "20x20", "idiom" : "ipad", "filename" : "Icon-App-20x20@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-App-29x29@1x.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-App-29x29@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-App-40x40@1x.png", "scale" : "1x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-App-40x40@2x.png", "scale" : "2x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-App-76x76@1x.png", "scale" : "1x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-App-76x76@2x.png", "scale" : "2x" }, { "size" : "83.5x83.5", "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" }, { "size" : "1024x1024", "idiom" : "ios-marketing", "filename" : "Icon-App-1024x1024@1x.png", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "LaunchImage.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "LaunchImage@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "LaunchImage@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md ================================================ # Launch Screen Assets You can customize the launch screen with your own desired assets by replacing the image files in this directory. You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. ================================================ FILE: ios/Runner/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: ios/Runner/Base.lproj/Main.storyboard ================================================ ================================================ FILE: ios/Runner/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName wanandroid_ngu CFBundlePackageType APPL CFBundleShortVersionString $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleVersion $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance ================================================ FILE: ios/Runner/main.m ================================================ #import #import #import "AppDelegate.h" int main(int argc, char* argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: ios/Runner.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, ); name = Flutter; sourceTree = ""; }; 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, ); sourceTree = ""; }; 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, ); name = Products; sourceTree = ""; }; 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, ); path = Runner; sourceTree = ""; }; 97C146F11CF9000F007C117D /* Supporting Files */ = { isa = PBXGroup; children = ( 97C146F21CF9000F007C117D /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, ); buildRules = ( ); dependencies = ( ); name = Runner; productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0910; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 97C146E51CF9000F007C117D; productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 97C146F31CF9000F007C117D /* main.m in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 97C146FB1CF9000F007C117D /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 97C147001CF9000F007C117D /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Profile; }; 249021D4217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = com.ngu.wanandroidNgu; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 97C147061CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = com.ngu.wanandroidNgu; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 97C147071CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = com.ngu.wanandroidNgu; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } ================================================ FILE: ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme ================================================ ================================================ FILE: ios/Runner.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: lib/app.dart ================================================ import 'package:flutter/material.dart'; import 'package:wanandroid_ngu/ui/drawer/drawer.dart'; import 'package:wanandroid_ngu/ui/home/home_page.dart'; import 'package:wanandroid_ngu/ui/knowledge/knowledge.dart'; import 'package:wanandroid_ngu/ui/navigation/navigation.dart'; import 'package:wanandroid_ngu/ui/project/project.dart'; import 'package:wanandroid_ngu/ui/publicc/publicc.dart'; import 'package:wanandroid_ngu/ui/search/search.dart'; //应用页面使用有状态Widget class App extends StatefulWidget { App({Key key}) : super(key: key); @override AppState createState() => AppState(); } //应用页面状态实现类 class AppState extends State { int _selectedIndex = 0; //当前选中项的索引 final appBarTitles = ['玩Android', '体系', '公众号', '导航', "项目"]; int elevation = 4; var pages = [ HomePage(), KnowledgePage(), PubliccPage(), NavigationPage(), ProjectPage() ]; @override Widget build(BuildContext context) { return WillPopScope( onWillPop: _onWillPop, child: Scaffold( drawer: DrawerPage(), appBar: AppBar( title: new Text(appBarTitles[_selectedIndex]), bottom: null, elevation: 0, actions: [ IconButton( icon: Icon(Icons.search), onPressed: () { Navigator.of(context) .push(new MaterialPageRoute(builder: (context) { return new SearchPage(); })); }) ], ), body: new IndexedStack(children: pages, index: _selectedIndex), //底部导航按钮 包含图标及文本 bottomNavigationBar: BottomNavigationBar( items: [ BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('首页')), BottomNavigationBarItem( icon: Icon(Icons.assignment), title: Text('体系')), BottomNavigationBarItem(icon: Icon(Icons.chat), title: Text('公众号')), BottomNavigationBarItem( icon: Icon(Icons.navigation), title: Text('导航')), BottomNavigationBarItem(icon: Icon(Icons.book), title: Text('项目')) ], type: BottomNavigationBarType.fixed, //设置显示的模式 currentIndex: _selectedIndex, //当前选中项的索引 onTap: _onItemTapped, //选择按下处理 ), ), ); } //选择按下处理 设置当前索引为index值 void _onItemTapped(int index) { setState(() { _selectedIndex = index; if (index == 2 || index == 4) { elevation = 0; } else { elevation = 4; } }); } Future _onWillPop() { return showDialog( context: context, builder: (context) => new AlertDialog( title: new Text('提示'), content: new Text('确定退出应用吗?'), actions: [ new FlatButton( onPressed: () => Navigator.of(context).pop(false), child: new Text('再看一会'), ), new FlatButton( onPressed: () => Navigator.of(context).pop(true), child: new Text('退出'), ), ], ), ) ?? false; } } ================================================ FILE: lib/base/_base_widget.dart ================================================ import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; abstract class BaseWidget extends StatefulWidget { BaseWidgetState baseWidgetState; @override BaseWidgetState createState() { baseWidgetState = getState(); return baseWidgetState; } BaseWidgetState getState(); } abstract class BaseWidgetState extends State { bool _isAppBarShow = true; //导航栏是否显示 bool _isErrorWidgetShow = false; //错误信息是否显示 String _errorContentMesage = "网络请求失败,请检查您的网络"; String _errImgPath = "images/ic_error.png"; bool _isLoadingWidgetShow = false; bool _isEmptyWidgetShow = false; String _emptyWidgetContent = "暂无数据~"; String _emptyImgPath = "images/ic_empty.png"; //自己根据需求变更 FontWeight _fontWidget = FontWeight.w600; //错误页面和空页面的字体粗度 @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return Scaffold( appBar: _getBaseAppBar(), body: Container( color: Colors.white, //背景颜色,可自己变更 child: Stack( children: [ getContentWidget(context), _getBaseErrorWidget(), _getBaseEmptyWidget(), _getBassLoadingWidget(), ], ), )); } @override void dispose() { super.dispose(); } Widget getContentWidget(BuildContext context); ///暴露的错误页面方法,可以自己重写定制 Widget getErrorWidget() { return Container( //错误页面中心可以自己调整 padding: EdgeInsets.fromLTRB(0, 0, 0, 80), color: Colors.white, width: double.infinity, height: double.infinity, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image( image: AssetImage(_errImgPath), width: 120, height: 120, ), Container( margin: EdgeInsets.fromLTRB(0, 20, 0, 0), child: Text(_errorContentMesage, style: TextStyle( color: Colors.grey, fontWeight: _fontWidget, )), ), Container( margin: EdgeInsets.fromLTRB(0, 20, 0, 0), child: OutlineButton( child: Text("重新加载", style: TextStyle( color: Colors.grey, fontWeight: _fontWidget, )), onPressed: () => {onClickErrorWidget()}, )) ], ), ), ); } Widget getLoadingWidget() { return Center( child: CupertinoActivityIndicator( radius: 15.0, //值越大加载的图形越大 )); } Widget getEmptyWidget() { return Container( padding: EdgeInsets.fromLTRB(0, 0, 0, 100), color: Colors.white, width: double.infinity, height: double.infinity, child: Center( child: Container( alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image( color: Colors.black12, image: AssetImage(_emptyImgPath), width: 150, height: 150, ), Container( margin: EdgeInsets.fromLTRB(0, 10, 0, 0), child: Text(_emptyWidgetContent, style: TextStyle( color: Colors.grey, fontWeight: _fontWidget, )), ) ], ), ), ), ); } PreferredSizeWidget _getBaseAppBar() { return PreferredSize( child: Offstage( offstage: !_isAppBarShow, child: getAppBar(), ), preferredSize: Size.fromHeight(50)); } ///导航栏 appBar AppBar getAppBar(); Widget _getBaseErrorWidget() { return Offstage( offstage: !_isErrorWidgetShow, child: getErrorWidget(), ); } Widget _getBassLoadingWidget() { return Offstage( offstage: !_isLoadingWidgetShow, child: getLoadingWidget(), ); } Widget _getBaseEmptyWidget() { return Offstage( offstage: !_isEmptyWidgetShow, child: getEmptyWidget(), ); } ///点击错误页面后展示内容 void onClickErrorWidget(); ///设置错误提示信息 void setErrorContent(String content) { if (content != null) { setState(() { _errorContentMesage = content; }); } } ///设置导航栏隐藏或者显示 void setAppBarVisible(bool isVisible) { setState(() { _isAppBarShow = isVisible; }); } void showContent() { setState(() { _isEmptyWidgetShow = false; _isLoadingWidgetShow = false; _isErrorWidgetShow = false; }); } void showloading() { setState(() { _isEmptyWidgetShow = false; _isLoadingWidgetShow = true; _isErrorWidgetShow = false; }); } void showEmpty() { setState(() { _isEmptyWidgetShow = true; _isLoadingWidgetShow = false; _isErrorWidgetShow = false; }); } void showError() { setState(() { _isEmptyWidgetShow = false; _isLoadingWidgetShow = false; _isErrorWidgetShow = true; }); } ///设置空页面内容 void setEmptyWidgetContent(String content) { if (content != null) { setState(() { _emptyWidgetContent = content; }); } } ///设置错误页面图片 void setErrorImage(String imagePath) { if (imagePath != null) { setState(() { _errImgPath = imagePath; }); } } ///设置空页面图片 void setEmptyImage(String imagePath) { if (imagePath != null) { setState(() { _emptyImgPath = imagePath; }); } } } ================================================ FILE: lib/common/application.dart ================================================ import 'package:event_bus/event_bus.dart'; class Application{ static EventBus eventBus=new EventBus(); } ================================================ FILE: lib/common/user.dart ================================================ import '../model/user_model.dart'; import 'package:dio/dio.dart'; import 'package:shared_preferences/shared_preferences.dart'; class User { static final User singleton = User._internal(); factory User() { return singleton; } User._internal(); List cookie; String userName; void saveUserInfo(UserModel _userModel,Response response){ List cookies = response.headers["set-cookie"]; cookie = cookies; userName = _userModel.data.username; saveInfo(); } Future getUserInfo() async { SharedPreferences sp = await SharedPreferences.getInstance(); List cookies = sp.getStringList("cookies"); if (cookies != null) { cookie = cookies; } String username = sp.getString("username"); if(username!=null){ userName = username; } } saveInfo() async { SharedPreferences sp = await SharedPreferences.getInstance(); sp.setStringList("cookies", cookie); sp.setString("username", userName); } void clearUserInfor(){ cookie = null; userName = null; clearInfo(); } clearInfo() async { SharedPreferences sp = await SharedPreferences.getInstance(); sp.setStringList("cookies", null); sp.setString("username", null); } } ================================================ FILE: lib/db/db_helper.dart ================================================ import 'dart:io'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; import 'dart:async'; import 'package:path/path.dart'; import 'package:wanandroid_ngu/model/common_websit_model.dart'; class DatabaseHelper { static final DatabaseHelper _instance = DatabaseHelper.internal(); factory DatabaseHelper() => _instance; final String tableName = "table_common_web"; final String columnId = "id"; final String columnName = "name"; final String columnlink = "link"; final String columnIcon = "icon"; final String columnOrder = "web_order"; final String columnVisible = "visible"; static Database _db; Future get db async { if (_db != null) { return _db; } _db = await initDb(); return _db; } DatabaseHelper.internal(); initDb() async { Directory documentDirectory = await getApplicationDocumentsDirectory(); String path = join(documentDirectory.path, "wanandroid.db"); var ourDb = await openDatabase(path, version: 1, onCreate: _onCreate); return ourDb; } //创建数据库表 void _onCreate(Database db, int version) async { await db.execute( "create table $tableName($columnId integer primary key,$columnIcon text not null, $columnlink text not null,$columnName text not null , $columnVisible integer not null , $columnOrder integer not null)"); print("Table is created"); } //插入 Future saveItem(DataListBean item) async { var dbClient = await db; int res = await dbClient.insert("$tableName", item.toMap()); print(res.toString()); return res; } //查询 Future getTotalList() async { var dbClient = await db; var result = await dbClient.rawQuery("SELECT * FROM $tableName "); return result.toList(); } //查询总数 Future getCount() async { var dbClient = await db; return Sqflite.firstIntValue(await dbClient.rawQuery( "SELECT COUNT(*) FROM $tableName" )); } //按照id查询 Future getItem(int id) async { var dbClient = await db; var result = await dbClient.rawQuery("SELECT * FROM $tableName WHERE id = $id"); if (result.length == 0) return null; return DataListBean.fromMap(result.first); } //清空数据 Future clear() async { var dbClient = await db; return await dbClient.delete(tableName); } //根据id删除 Future deleteItem(int id) async { var dbClient = await db; return await dbClient.delete(tableName, where: "$columnId = ?", whereArgs: [id]); } //修改 Future updateItem(DataListBean item) async { var dbClient = await db; return await dbClient.update("$tableName", item.toMap(), where: "$columnId = ?", whereArgs: [item.id]); } //清空数据库 //关闭 Future close() async { var dbClient = await db; return dbClient.close(); } } ================================================ FILE: lib/event/change_theme_event.dart ================================================ import 'package:flutter/material.dart'; class ChangeThemeEvent { Color color; ChangeThemeEvent(Color c) { color = c; } } ================================================ FILE: lib/event/login_event.dart ================================================ class LoginEvent{ } ================================================ FILE: lib/http/api.dart ================================================ class Api{ static const String HOME_BANNER = "https://www.wanandroid.com/banner/json"; static const String HOME_ARTICLE_LIST = "https://www.wanandroid.com/article/list/"; /// 知识体系 static const String SYSTEM_TREE = "https://www.wanandroid.com/tree/json"; // 知识体系详情 static const String SYSTEM_TREE_CONTENT = "https://www.wanandroid.com/article/list/"; // 公众号名称 static const String WX_LIST = "https://wanandroid.com/wxarticle/chapters/json"; // 公众号文章 static const String WX_ARTICLE_LIST = "https://wanandroid.com/wxarticle/list/"; // 导航列表数据 static const String NAVI_LIST = "https://www.wanandroid.com/navi/json"; // 项目分类 static const String PROJECT_TREE = "https://www.wanandroid.com/project/tree/json"; // 项目列表 static const String PROJECT_LIST = "https://www.wanandroid.com/project/list/"; // 搜索热词 static const String SEARCH_HOT_WORD = "https://www.wanandroid.com//hotkey/json"; // 搜索结果 static const String SEARCH_RESULT = "https://www.wanandroid.com/article/query/"; // 用户登录 static const String USER_LOGIN = "https://www.wanandroid.com/user/login"; // 用户注册 static const String USER_REGISTER = "https://www.wanandroid.com/user/register"; // 收藏列表 static const String COLLECTION_LIST = "https://www.wanandroid.com/lg/collect/list/"; //常用网站 static const String COMMON_WEBSITE = "https://www.wanandroid.com/friend/json"; // 我的收藏-取消收藏 static const String CANCEL_COLLECTION = "https://www.wanandroid.com/lg/uncollect/"; // 我的收藏-新增收藏 static const String ADD_COLLECTION = "https://www.wanandroid.com/lg/collect/add/json"; // 网站收藏 static const String WEBSITE_COLLECTION_LIST = "https://www.wanandroid.com/lg/collect/usertools/json"; // 取消网站收藏 static const String CANCEL_WEBSITE_COLLECTION = "https://www.wanandroid.com/lg/collect/deletetool/json"; // 新增网站收藏 static const String ADD_WEBSITE_COLLECTION = "https://www.wanandroid.com/lg/collect/addtool/json"; // 编辑网站收藏 static const String EDIT_WEBSITE_COLLECTION = "https://www.wanandroid.com/lg/collect/updatetool/json"; // todo列表数据 static const String TODO_LIST = "https://wanandroid.com/lg/todo/list/"; // 新增todo数据 static const String ADD_TODO = "https://www.wanandroid.com/lg/todo/add/json"; // 更新todo数据 static const String UPDATE_TODO = "https://www.wanandroid.com/lg/todo/update/"; // 删除todo数据 static const String DELETE_TODO = "https://www.wanandroid.com/lg/todo/delete/"; // 仅更新todo完成状态 static const String DONE_TODO = "https://www.wanandroid.com/lg/todo/done/"; } ================================================ FILE: lib/http/api_service.dart ================================================ import 'package:dio/dio.dart'; import 'package:wanandroid_ngu/common/user.dart'; import 'package:wanandroid_ngu/http/dio_manager.dart'; import 'package:wanandroid_ngu/model/article_model.dart'; import 'package:wanandroid_ngu/model/banner_model.dart'; import 'package:wanandroid_ngu/model/base_model.dart'; import 'package:wanandroid_ngu/model/collection_model.dart'; import 'package:wanandroid_ngu/model/common_websit_model.dart'; import 'package:wanandroid_ngu/model/hotword_result_model.dart'; import 'package:wanandroid_ngu/model/navi_model.dart'; import 'package:wanandroid_ngu/model/pretty_model.dart'; import 'package:wanandroid_ngu/model/projectlist_model.dart'; import 'package:wanandroid_ngu/model/project_tree_model.dart'; import 'package:wanandroid_ngu/model/system_tree_content_model.dart'; import 'package:wanandroid_ngu/model/system_tree_model.dart'; import 'package:wanandroid_ngu/model/todolist_model.dart'; import 'package:wanandroid_ngu/model/user_model.dart'; import 'package:wanandroid_ngu/model/website_collection_model.dart'; import 'package:wanandroid_ngu/model/wx_article_content_model.dart'; import 'package:wanandroid_ngu/model/wx_article_title_model.dart'; import 'package:wanandroid_ngu/model/hotword_model.dart'; import 'api.dart'; class ApiService { void getBanner(Function callback) async { DioManager.singleton.dio .get(Api.HOME_BANNER, options: _getOptions()) .then((response) { callback(BannerModel(response.data)); }); } void getArticleList(Function callback, Function errorback, int _page) async { DioManager.singleton.dio .get(Api.HOME_ARTICLE_LIST + "$_page/json", options: _getOptions()) .then((response) { callback(ArticleModel(response.data)); }).catchError((e) { errorback(e); }); } /// 获取知识体系列表 void getSystemTree(Function callback, Function errorback) async { DioManager.singleton.dio .get(Api.SYSTEM_TREE, options: _getOptions()) .then((response) { callback(SystemTreeModel(response.data)); }).catchError((e) { errorback(e); }); } /// 获取知识体系列表详情 void getSystemTreeContent(Function callback, Function errorback,int _page, int _id) async { DioManager.singleton.dio .get(Api.SYSTEM_TREE_CONTENT + "$_page/json?cid=$_id", options: _getOptions()) .then((response) { callback(SystemTreeContentModel(response.data)); }).catchError((e) { errorback(e); }); } /// 获取公众号名称 void getWxList(Function callback, Function errorback) async { DioManager.singleton.dio .get(Api.WX_LIST, options: _getOptions()) .then((response) { callback(WxArticleTitleModel(response.data)); }).catchError((e) { errorback(e); }); } /// 获取公众号文章 void getWxArticleList(Function callback, int _id, int _page) async { DioManager.singleton.dio .get(Api.WX_ARTICLE_LIST + "$_id/$_page/json", options: _getOptions()) .then((response) { callback(WxArticleContentModel(response.data)); }); } /// 获取导航列表数据 void getNaviList(Function callback, Function errorback) async { DioManager.singleton.dio .get(Api.NAVI_LIST, options: _getOptions()) .then((response) { callback(NaviModel(response.data)); }).catchError((e) { errorback(e); }); } /// 获取项目分类 void getProjectTree(Function callback,Function errorback) async { DioManager.singleton.dio .get(Api.PROJECT_TREE, options: _getOptions()) .then((response) { callback(ProjectTreeModel(response.data)); }).catchError((e) { errorback(e); }); } /// 获取项目列表 void getProjectList(Function callback, int _page, int _id) async { DioManager.singleton.dio .get(Api.PROJECT_LIST + "$_page/json?cid=$_id", options: _getOptions()) .then((response) { callback(ProjectTreeListModel(response.data)); }); } /// 获取搜索热词 void getSearchHotWord(Function callback) async { DioManager.singleton.dio .get(Api.SEARCH_HOT_WORD, options: _getOptions()) .then((response) { callback(HotwordModel.fromMap(response.data)); }); } /// 获取搜索结果 void getSearchResult(Function callback, Function errorback, int _page, String _keyword) async { FormData formData = new FormData.from({ "k": _keyword, }); DioManager.singleton.dio .post(Api.SEARCH_RESULT + "$_page/json", data: formData, options: _getOptions()) .then((response) { callback(HotwordResultModel.fromMap(response.data)); }).catchError((e) { errorback(e); }); } /// 登录 void login(Function callback, String _username, String _password) async { FormData formData = new FormData.from({"username": _username, "password": _password}); DioManager.singleton.dio .post(Api.USER_LOGIN, data: formData, options: _getOptions()) .then((response) { callback(UserModel(response.data), response); }); } /// 注册 void register(Function callback, String _username, String _password) async { FormData formData = new FormData.from({ "username": _username, "password": _password, "repassword": _password }); DioManager.singleton.dio .post(Api.USER_REGISTER, data: formData, options: null) .then((response) { print(response.toString()); callback(UserModel(response.data)); }); } /// 获取收藏列表 void getCollectionList( Function callback, Function errorback, int _page) async { DioManager.singleton.dio .get(Api.COLLECTION_LIST + "$_page/json", options: _getOptions()) .then((response) { callback(CollectionModel(response.data)); }).catchError((e) { errorback(e); }); } /// 我的收藏-取消收藏 void cancelCollection( Function callback, Function errorback, int _id, int _originId) async { FormData formData = new FormData.from({"originId": _originId}); DioManager.singleton.dio .post(Api.CANCEL_COLLECTION + "$_id/json", data: formData, options: _getOptions()) .then((response) { callback(BaseModel(response.data)); }).catchError((e) { errorback(e); }); } ///常用网站 void getCommonWebsite(Function callback, Function errorback) async { DioManager.singleton.dio .get(Api.COMMON_WEBSITE, options: _getOptions()) .then((response) { callback(CommonWebsitModel.fromMap(response.data)); }).catchError((e) { errorback(e); }); } void getPrettyGirl(Function callback, int _page) async { DioManager.singleton.dio .get("http://gank.io/api/data/福利/10/" + "$_page") .then((response) { callback(PrettyModel.fromMap(response.data)); }); } /// 取消网站收藏 void cancelWebsiteCollectionList(Function callback, int _id) async { FormData formData = new FormData.from({ "id": _id, }); DioManager.singleton.dio .post(Api.CANCEL_WEBSITE_COLLECTION, data: formData, options: _getOptions()) .then((response) { callback(BaseModel(response.data)); }); } Options _getOptions() { Map map = new Map(); List cookies = User().cookie; map["Cookie"] = cookies.toString(); return Options(headers: map); } } ================================================ FILE: lib/http/dio_manager.dart ================================================ import 'dart:io'; import 'package:dio/dio.dart'; class DioManager { Dio _dio; DioManager._internal() { _dio = new Dio(); (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) { client.badCertificateCallback = (X509Certificate cert, String host, int port) { return true; }; }; } static DioManager singleton = DioManager._internal(); factory DioManager() => singleton; get dio { return _dio; } } ================================================ FILE: lib/loading.dart ================================================ import 'package:flutter/material.dart'; import 'dart:async'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:wanandroid_ngu/app.dart'; //加载页面 class LoadingPage extends StatefulWidget { @override _LoadingState createState() => new _LoadingState(); } class _LoadingState extends State { @override void initState(){ super.initState(); //在加载页面停顿2秒 new Future.delayed(Duration(seconds: 2),(){ _getHasSkip(); }); } void _getHasSkip ()async { SharedPreferences prefs = await SharedPreferences.getInstance(); bool hasSkip = prefs.getBool("hasSkip"); if(hasSkip==null||!hasSkip){ Navigator.of(context).pushReplacementNamed("splash"); }else { Navigator.of(context).pushAndRemoveUntil( new MaterialPageRoute( builder: (context) => App()), (route) => route == null); } } @override Widget build(BuildContext context) { return new Center( child: Stack( children: [ //加载页面居中背景图 使用cover模式 Image.asset("images/loading.png",fit: BoxFit.cover,), ], ), ); } } ================================================ FILE: lib/main.dart ================================================ import 'package:flutter/material.dart'; import 'package:wanandroid_ngu/common/application.dart'; import 'package:wanandroid_ngu/common/user.dart'; import 'package:wanandroid_ngu/event/change_theme_event.dart'; import 'package:wanandroid_ngu/splash_screen.dart'; import 'package:wanandroid_ngu/util/theme_util.dart'; import 'package:wanandroid_ngu/util/utils.dart'; import './app.dart'; import './loading.dart'; import 'dart:io'; import 'package:flutter/services.dart'; void main() { getLoginInfo(); runApp(MyApp()); if (Platform.isAndroid) { // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent); SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); } } Future getLoginInfo() async { User.singleton.getUserInfo(); } class MyApp extends StatefulWidget { @override State createState() { return MyAppState(); } } class MyAppState extends State { Color themeColor = ThemeUtils.currentColorTheme; @override void initState() { super.initState(); Utils.getColorThemeIndex().then((index) { print('color theme index = $index'); if (index != null) { ThemeUtils.currentColorTheme = ThemeUtils.supportColors[index]; Application.eventBus .fire(new ChangeThemeEvent(ThemeUtils.supportColors[index])); } }); Application.eventBus.on().listen((event) { setState(() { themeColor = event.color; }); }); } @override Widget build(BuildContext context) { return MaterialApp( title: "玩Android", debugShowCheckedModeBanner: false, theme: new ThemeData(primaryColor: themeColor, brightness: Brightness.light), routes: { "app": (BuildContext context) => new App(), "splash": (BuildContext context) => new SplashScreen(), }, home: new LoadingPage(), ); } } ================================================ FILE: lib/model/article_model.dart ================================================ import 'dart:convert' show json; class ArticleModel { int errorCode; String errorMsg; Data data; ArticleModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory ArticleModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new ArticleModel.fromJson(json.decode(jsonStr)) : new ArticleModel.fromJson(jsonStr); ArticleModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : new Data.fromJson(jsonRes['data']); } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class Data { int curPage; int offset; int pageCount; int size; int total; bool over; List
datas; Data.fromParams({this.curPage, this.offset, this.pageCount, this.size, this.total, this.over, this.datas}); Data.fromJson(jsonRes) { curPage = jsonRes['curPage']; offset = jsonRes['offset']; pageCount = jsonRes['pageCount']; size = jsonRes['size']; total = jsonRes['total']; over = jsonRes['over']; datas = jsonRes['datas'] == null ? null : []; for (var datasItem in datas == null ? [] : jsonRes['datas']){ datas.add(datasItem == null ? null : new Article.fromJson(datasItem)); } } @override String toString() { return '{"curPage": $curPage,"offset": $offset,"pageCount": $pageCount,"size": $size,"total": $total,"over": $over,"datas": $datas}'; } } class Article { int chapterId; int courseId; int id; int publishTime; int superChapterId; int type; int userId; int visible; int zan; bool collect; bool fresh; String apkLink; String author; String chapterName; String desc; String envelopePic; String link; String niceDate; String origin; String projectLink; String superChapterName; String title; List tags; Article.fromParams({this.chapterId, this.courseId, this.id, this.publishTime, this.superChapterId, this.type, this.userId, this.visible, this.zan, this.collect, this.fresh, this.apkLink, this.author, this.chapterName, this.desc, this.envelopePic, this.link, this.niceDate, this.origin, this.projectLink, this.superChapterName, this.title, this.tags}); Article.fromJson(jsonRes) { chapterId = jsonRes['chapterId']; courseId = jsonRes['courseId']; id = jsonRes['id']; publishTime = jsonRes['publishTime']; superChapterId = jsonRes['superChapterId']; type = jsonRes['type']; userId = jsonRes['userId']; visible = jsonRes['visible']; zan = jsonRes['zan']; collect = jsonRes['collect']; fresh = jsonRes['fresh']; apkLink = jsonRes['apkLink']; author = jsonRes['author']; chapterName = jsonRes['chapterName']; desc = jsonRes['desc']; envelopePic = jsonRes['envelopePic']; link = jsonRes['link']; niceDate = jsonRes['niceDate']; origin = jsonRes['origin']; projectLink = jsonRes['projectLink']; superChapterName = jsonRes['superChapterName']; title = jsonRes['title']; tags = jsonRes['tags'] == null ? null : []; for (var tagsItem in tags == null ? [] : jsonRes['tags']){ tags.add(tagsItem == null ? null : new Tag.fromJson(tagsItem)); } } @override String toString() { return '{"chapterId": $chapterId,"courseId": $courseId,"id": $id,"publishTime": $publishTime,"superChapterId": $superChapterId,"type": $type,"userId": $userId,"visible": $visible,"zan": $zan,"collect": $collect,"fresh": $fresh,"apkLink": ${apkLink != null?'${json.encode(apkLink)}':'null'},"author": ${author != null?'${json.encode(author)}':'null'},"chapterName": ${chapterName != null?'${json.encode(chapterName)}':'null'},"desc": ${desc != null?'${json.encode(desc)}':'null'},"envelopePic": ${envelopePic != null?'${json.encode(envelopePic)}':'null'},"link": ${link != null?'${json.encode(link)}':'null'},"niceDate": ${niceDate != null?'${json.encode(niceDate)}':'null'},"origin": ${origin != null?'${json.encode(origin)}':'null'},"projectLink": ${projectLink != null?'${json.encode(projectLink)}':'null'},"superChapterName": ${superChapterName != null?'${json.encode(superChapterName)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"tags": $tags}'; } } class Tag { String name; String url; Tag.fromParams({this.name, this.url}); Tag.fromJson(jsonRes) { name = jsonRes['name']; url = jsonRes['url']; } @override String toString() { return '{"name": ${name != null?'${json.encode(name)}':'null'},"url": ${url != null?'${json.encode(url)}':'null'}}'; } } ================================================ FILE: lib/model/banner_model.dart ================================================ import 'dart:convert' show json; class BannerModel { int errorCode; String errorMsg; List data; BannerModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory BannerModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new BannerModel.fromJson(json.decode(jsonStr)) : new BannerModel.fromJson(jsonStr); BannerModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : []; for (var dataItem in data == null ? [] : jsonRes['data']){ data.add(dataItem == null ? null : new BannerData.fromJson(dataItem)); } } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class BannerData { int id; int isVisible; int order; int type; String desc; String imagePath; String title; String url; BannerData.fromParams({this.id, this.isVisible, this.order, this.type, this.desc, this.imagePath, this.title, this.url}); BannerData.fromJson(jsonRes) { id = jsonRes['id']; isVisible = jsonRes['isVisible']; order = jsonRes['order']; type = jsonRes['type']; desc = jsonRes['desc']; imagePath = jsonRes['imagePath']; title = jsonRes['title']; url = jsonRes['url']; } @override String toString() { 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'}}'; } } ================================================ FILE: lib/model/base_model.dart ================================================ import 'dart:convert' show json; class BaseModel { int errorCode; String errorMsg; BaseModel.fromParams({ this.errorCode, this.errorMsg}); factory BaseModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new BaseModel.fromJson(json.decode(jsonStr)) : new BaseModel.fromJson(jsonStr); BaseModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'}}'; } } ================================================ FILE: lib/model/collection_model.dart ================================================ import 'dart:convert' show json; class CollectionModel { int errorCode; String errorMsg; CollectionData data; CollectionModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory CollectionModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new CollectionModel.fromJson(json.decode(jsonStr)) : new CollectionModel.fromJson(jsonStr); CollectionModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : new CollectionData.fromJson(jsonRes['data']); } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class CollectionData { int curPage; int offset; int pageCount; int size; int total; bool over; List datas; CollectionData.fromParams({this.curPage, this.offset, this.pageCount, this.size, this.total, this.over, this.datas}); CollectionData.fromJson(jsonRes) { curPage = jsonRes['curPage']; offset = jsonRes['offset']; pageCount = jsonRes['pageCount']; size = jsonRes['size']; total = jsonRes['total']; over = jsonRes['over']; datas = jsonRes['datas'] == null ? null : []; for (var datasItem in datas == null ? [] : jsonRes['datas']){ datas.add(datasItem == null ? null : new Collection.fromJson(datasItem)); } } @override String toString() { return '{"curPage": $curPage,"offset": $offset,"pageCount": $pageCount,"size": $size,"total": $total,"over": $over,"datas": $datas}'; } } class Collection { int chapterId; int courseId; int id; int originId; int publishTime; int userId; int visible; int zan; String author; String chapterName; String desc; String envelopePic; String link; String niceDate; String origin; String title; Collection.fromParams({this.chapterId, this.courseId, this.id, this.originId, this.publishTime, this.userId, this.visible, this.zan, this.author, this.chapterName, this.desc, this.envelopePic, this.link, this.niceDate, this.origin, this.title}); Collection.fromJson(jsonRes) { chapterId = jsonRes['chapterId']; courseId = jsonRes['courseId']; id = jsonRes['id']; originId = jsonRes['originId']; publishTime = jsonRes['publishTime']; userId = jsonRes['userId']; visible = jsonRes['visible']; zan = jsonRes['zan']; author = jsonRes['author']; chapterName = jsonRes['chapterName']; desc = jsonRes['desc']; envelopePic = jsonRes['envelopePic']; link = jsonRes['link']; niceDate = jsonRes['niceDate']; origin = jsonRes['origin']; title = jsonRes['title']; } @override String toString() { return '{"chapterId": $chapterId,"courseId": $courseId,"id": $id,"originId": ${origin != null?'${json.encode(origin)}':'null'}Id,"publishTime": $publishTime,"userId": $userId,"visible": $visible,"zan": $zan,"author": ${author != null?'${json.encode(author)}':'null'},"chapterName": ${chapterName != null?'${json.encode(chapterName)}':'null'},"desc": ${desc != null?'${json.encode(desc)}':'null'},"envelopePic": ${envelopePic != null?'${json.encode(envelopePic)}':'null'},"link": ${link != null?'${json.encode(link)}':'null'},"niceDate": ${niceDate != null?'${json.encode(niceDate)}':'null'},"origin": ${origin != null?'${json.encode(origin)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'}}'; } } ================================================ FILE: lib/model/common_websit_model.dart ================================================ class CommonWebsitModel { String errorMsg; int errorCode; List data; static CommonWebsitModel fromMap(Map map) { CommonWebsitModel common_websit_model = new CommonWebsitModel(); common_websit_model.errorMsg = map['errorMsg']; common_websit_model.errorCode = map['errorCode']; common_websit_model.data = DataListBean.fromMapList(map['data']); return common_websit_model; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } } class DataListBean { String icon; String link; String name; int id; int order; int visible; static DataListBean fromMap(Map map) { DataListBean dataListBean = new DataListBean(); dataListBean.icon = map['icon']; dataListBean.link = map['link']; dataListBean.name = map['name']; dataListBean.id = map['id']; dataListBean.order = map['order']; dataListBean.visible = map['visible']; return dataListBean; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } Map toMap() { var map = Map(); map["icon"] = icon; map["link"] = link; map["name"] = name; map["id"] = id; map["web_order"] = order; map["visible"] = visible; if (id != null) { map["id"] = id; } return map; } } ================================================ FILE: lib/model/common_website_model.dart ================================================ import 'dart:convert' show json; class CommonWebsiteModel { int errorCode; String errorMsg; List data; CommonWebsiteModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory CommonWebsiteModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new CommonWebsiteModel.fromJson(json.decode(jsonStr)) : new CommonWebsiteModel.fromJson(jsonStr); CommonWebsiteModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : []; for (var dataItem in data == null ? [] : jsonRes['data']){ data.add(dataItem == null ? null : new CommonWebsiteData.fromJson(dataItem)); } } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class CommonWebsiteData { int id; int order; int visible; String icon; String link; String name; CommonWebsiteData.fromParams({this.id, this.order, this.visible, this.icon, this.link, this.name}); CommonWebsiteData.fromJson(jsonRes) { id = jsonRes['id']; order = jsonRes['order']; visible = jsonRes['visible']; icon = jsonRes['icon']; link = jsonRes['link']; name = jsonRes['name']; } @override String toString() { return '{"id": $id,"order": $order,"visible": $visible,"icon": ${icon != null?'${json.encode(icon)}':'null'},"link": ${link != null?'${json.encode(link)}':'null'},"name": ${name != null?'${json.encode(name)}':'null'}}'; } } ================================================ FILE: lib/model/hotword_model.dart ================================================ class HotwordModel { String errorMsg; int errorCode; List data; static HotwordModel fromMap(Map map) { HotwordModel hotword_model = new HotwordModel(); hotword_model.errorMsg = map['errorMsg']; hotword_model.errorCode = map['errorCode']; hotword_model.data = DataListBean.fromMapList(map['data']); return hotword_model; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } } class DataListBean { String link; String name; int id; int order; int visible; static DataListBean fromMap(Map map) { DataListBean dataListBean = new DataListBean(); dataListBean.link = map['link']; dataListBean.name = map['name']; dataListBean.id = map['id']; dataListBean.order = map['order']; dataListBean.visible = map['visible']; return dataListBean; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } } ================================================ FILE: lib/model/hotword_result_model.dart ================================================ class HotwordResultModel { String errorMsg; int errorCode; DataBean data; static HotwordResultModel fromMap(Map map) { HotwordResultModel hotword_result_model = new HotwordResultModel(); hotword_result_model.errorMsg = map['errorMsg']; hotword_result_model.errorCode = map['errorCode']; hotword_result_model.data = DataBean.fromMap(map['data']); return hotword_result_model; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } } class DataBean { bool over; int curPage; int offset; int pageCount; int size; int total; List datas; static DataBean fromMap(Map map) { DataBean dataBean = new DataBean(); dataBean.over = map['over']; dataBean.curPage = map['curPage']; dataBean.offset = map['offset']; dataBean.pageCount = map['pageCount']; dataBean.size = map['size']; dataBean.total = map['total']; dataBean.datas = DatasListBean.fromMapList(map['datas']); return dataBean; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } } class DatasListBean { String apkLink; String author; String chapterName; String desc; String envelopePic; String link; String niceDate; String origin; String projectLink; String superChapterName; String title; bool collect; bool fresh; int chapterId; int courseId; int id; int publishTime; int superChapterId; int type; int userId; int visible; int zan; List tags; static DatasListBean fromMap(Map map) { DatasListBean datasListBean = new DatasListBean(); datasListBean.apkLink = map['apkLink']; datasListBean.author = map['author']; datasListBean.chapterName = map['chapterName']; datasListBean.desc = map['desc']; datasListBean.envelopePic = map['envelopePic']; datasListBean.link = map['link']; datasListBean.niceDate = map['niceDate']; datasListBean.origin = map['origin']; datasListBean.projectLink = map['projectLink']; datasListBean.superChapterName = map['superChapterName']; datasListBean.title = map['title']; datasListBean.collect = map['collect']; datasListBean.fresh = map['fresh']; datasListBean.chapterId = map['chapterId']; datasListBean.courseId = map['courseId']; datasListBean.id = map['id']; datasListBean.publishTime = map['publishTime']; datasListBean.superChapterId = map['superChapterId']; datasListBean.type = map['type']; datasListBean.userId = map['userId']; datasListBean.visible = map['visible']; datasListBean.zan = map['zan']; datasListBean.tags = TagsListBean.fromMapList(map['tags']); return datasListBean; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } } class TagsListBean { String name; String url; static TagsListBean fromMap(Map map) { TagsListBean tagsListBean = new TagsListBean(); tagsListBean.name = map['name']; tagsListBean.url = map['url']; return tagsListBean; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } } ================================================ FILE: lib/model/navi_model.dart ================================================ import 'dart:convert' show json; class NaviModel { int errorCode; String errorMsg; List data; NaviModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory NaviModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new NaviModel.fromJson(json.decode(jsonStr)) : new NaviModel.fromJson(jsonStr); NaviModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : []; for (var dataItem in data == null ? [] : jsonRes['data']){ data.add(dataItem == null ? null : new NaviData.fromJson(dataItem)); } } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class NaviData { int cid; String name; List articles; NaviData.fromParams({this.cid, this.name, this.articles}); NaviData.fromJson(jsonRes) { cid = jsonRes['cid']; name = jsonRes['name']; articles = jsonRes['articles'] == null ? null : []; for (var articlesItem in articles == null ? [] : jsonRes['articles']){ articles.add(articlesItem == null ? null : new NaviArticle.fromJson(articlesItem)); } } @override String toString() { return '{"cid": $cid,"name": ${name != null?'${json.encode(name)}':'null'},"articles": $articles}'; } } class NaviArticle { int chapterId; int courseId; int id; int publishTime; int superChapterId; int type; int userId; int visible; int zan; bool collect; bool fresh; String apkLink; String author; String chapterName; String desc; String envelopePic; String link; String niceDate; String origin; String projectLink; String superChapterName; String title; List tags; NaviArticle.fromParams({this.chapterId, this.courseId, this.id, this.publishTime, this.superChapterId, this.type, this.userId, this.visible, this.zan, this.collect, this.fresh, this.apkLink, this.author, this.chapterName, this.desc, this.envelopePic, this.link, this.niceDate, this.origin, this.projectLink, this.superChapterName, this.title, this.tags}); NaviArticle.fromJson(jsonRes) { chapterId = jsonRes['chapterId']; courseId = jsonRes['courseId']; id = jsonRes['id']; publishTime = jsonRes['publishTime']; superChapterId = jsonRes['superChapterId']; type = jsonRes['type']; userId = jsonRes['userId']; visible = jsonRes['visible']; zan = jsonRes['zan']; collect = jsonRes['collect']; fresh = jsonRes['fresh']; apkLink = jsonRes['apkLink']; author = jsonRes['author']; chapterName = jsonRes['chapterName']; desc = jsonRes['desc']; envelopePic = jsonRes['envelopePic']; link = jsonRes['link']; niceDate = jsonRes['niceDate']; origin = jsonRes['origin']; projectLink = jsonRes['projectLink']; superChapterName = jsonRes['superChapterName']; title = jsonRes['title']; tags = jsonRes['tags'] == null ? null : []; for (var tagsItem in tags == null ? [] : jsonRes['tags']){ tags.add(tagsItem); } } @override String toString() { return '{"chapterId": $chapterId,"courseId": $courseId,"id": $id,"publishTime": $publishTime,"superChapterId": $superChapterId,"type": $type,"userId": $userId,"visible": $visible,"zan": $zan,"collect": $collect,"fresh": $fresh,"apkLink": ${apkLink != null?'${json.encode(apkLink)}':'null'},"author": ${author != null?'${json.encode(author)}':'null'},"chapterName": ${chapterName != null?'${json.encode(chapterName)}':'null'},"desc": ${desc != null?'${json.encode(desc)}':'null'},"envelopePic": ${envelopePic != null?'${json.encode(envelopePic)}':'null'},"link": ${link != null?'${json.encode(link)}':'null'},"niceDate": ${niceDate != null?'${json.encode(niceDate)}':'null'},"origin": ${origin != null?'${json.encode(origin)}':'null'},"projectLink": ${projectLink != null?'${json.encode(projectLink)}':'null'},"superChapterName": ${superChapterName != null?'${json.encode(superChapterName)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"tags": $tags}'; } } ================================================ FILE: lib/model/pretty_model.dart ================================================ class PrettyModel { bool error; List results; static PrettyModel fromMap(Map map) { PrettyModel pretty_model = new PrettyModel(); pretty_model.error = map['error']; pretty_model.results = ResultsListBean.fromMapList(map['results']); return pretty_model; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } } class ResultsListBean { String _id; String createdAt; String desc; String publishedAt; String source; String type; String url; String who; bool used; static ResultsListBean fromMap(Map map) { ResultsListBean resultsListBean = new ResultsListBean(); resultsListBean._id = map['_id']; resultsListBean.createdAt = map['createdAt']; resultsListBean.desc = map['desc']; resultsListBean.publishedAt = map['publishedAt']; resultsListBean.source = map['source']; resultsListBean.type = map['type']; resultsListBean.url = map['url']; resultsListBean.who = map['who']; resultsListBean.used = map['used']; return resultsListBean; } static List fromMapList(dynamic mapList) { List list = new List(mapList.length); for (int i = 0; i < mapList.length; i++) { list[i] = fromMap(mapList[i]); } return list; } } ================================================ FILE: lib/model/project_tree_model.dart ================================================ import 'dart:convert' show json; class ProjectTreeModel { int errorCode; String errorMsg; List data; ProjectTreeModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory ProjectTreeModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new ProjectTreeModel.fromJson(json.decode(jsonStr)) : new ProjectTreeModel.fromJson(jsonStr); ProjectTreeModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : []; for (var dataItem in data == null ? [] : jsonRes['data']){ data.add(dataItem == null ? null : new ProjectTreeData.fromJson(dataItem)); } } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class ProjectTreeData { int courseId; int id; int order; int parentChapterId; int visible; bool userControlSetTop; String name; List children; ProjectTreeData.fromParams({this.courseId, this.id, this.order, this.parentChapterId, this.visible, this.userControlSetTop, this.name, this.children}); ProjectTreeData.fromJson(jsonRes) { courseId = jsonRes['courseId']; id = jsonRes['id']; order = jsonRes['order']; parentChapterId = jsonRes['parentChapterId']; visible = jsonRes['visible']; userControlSetTop = jsonRes['userControlSetTop']; name = jsonRes['name']; children = jsonRes['children'] == null ? null : []; for (var childrenItem in children == null ? [] : jsonRes['children']){ children.add(childrenItem); } } @override String toString() { return '{"courseId": $courseId,"id": $id,"order": $order,"parentChapterId": $parentChapterId,"visible": $visible,"userControlSetTop": $userControlSetTop,"name": ${name != null?'${json.encode(name)}':'null'},"children": $children}'; } } ================================================ FILE: lib/model/projectlist_model.dart ================================================ import 'dart:convert' show json; class ProjectTreeListModel { int errorCode; String errorMsg; ProjectTreeListData data; ProjectTreeListModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory ProjectTreeListModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new ProjectTreeListModel.fromJson(json.decode(jsonStr)) : new ProjectTreeListModel.fromJson(jsonStr); ProjectTreeListModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : new ProjectTreeListData.fromJson(jsonRes['data']); } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class ProjectTreeListData { int curPage; int offset; int pageCount; int size; int total; bool over; List datas; ProjectTreeListData.fromParams({this.curPage, this.offset, this.pageCount, this.size, this.total, this.over, this.datas}); ProjectTreeListData.fromJson(jsonRes) { curPage = jsonRes['curPage']; offset = jsonRes['offset']; pageCount = jsonRes['pageCount']; size = jsonRes['size']; total = jsonRes['total']; over = jsonRes['over']; datas = jsonRes['datas'] == null ? null : []; for (var datasItem in datas == null ? [] : jsonRes['datas']){ datas.add(datasItem == null ? null : new ProjectTreeListDatas.fromJson(datasItem)); } } @override String toString() { return '{"curPage": $curPage,"offset": $offset,"pageCount": $pageCount,"size": $size,"total": $total,"over": $over,"datas": $datas}'; } } class ProjectTreeListDatas { int chapterId; int courseId; int id; int publishTime; int superChapterId; int type; int userId; int visible; int zan; bool collect; bool fresh; String apkLink; String author; String chapterName; String desc; String envelopePic; String link; String niceDate; String origin; String projectLink; String superChapterName; String title; List tags; ProjectTreeListDatas.fromParams({this.chapterId, this.courseId, this.id, this.publishTime, this.superChapterId, this.type, this.userId, this.visible, this.zan, this.collect, this.fresh, this.apkLink, this.author, this.chapterName, this.desc, this.envelopePic, this.link, this.niceDate, this.origin, this.projectLink, this.superChapterName, this.title, this.tags}); ProjectTreeListDatas.fromJson(jsonRes) { chapterId = jsonRes['chapterId']; courseId = jsonRes['courseId']; id = jsonRes['id']; publishTime = jsonRes['publishTime']; superChapterId = jsonRes['superChapterId']; type = jsonRes['type']; userId = jsonRes['userId']; visible = jsonRes['visible']; zan = jsonRes['zan']; collect = jsonRes['collect']; fresh = jsonRes['fresh']; apkLink = jsonRes['apkLink']; author = jsonRes['author']; chapterName = jsonRes['chapterName']; desc = jsonRes['desc']; envelopePic = jsonRes['envelopePic']; link = jsonRes['link']; niceDate = jsonRes['niceDate']; origin = jsonRes['origin']; projectLink = jsonRes['projectLink']; superChapterName = jsonRes['superChapterName']; title = jsonRes['title']; tags = jsonRes['tags'] == null ? null : []; for (var tagsItem in tags == null ? [] : jsonRes['tags']){ tags.add(tagsItem == null ? null : new ProjectTreeListTag.fromJson(tagsItem)); } } @override String toString() { return '{"chapterId": $chapterId,"courseId": $courseId,"id": $id,"publishTime": $publishTime,"superChapterId": $superChapterId,"type": $type,"userId": $userId,"visible": $visible,"zan": $zan,"collect": $collect,"fresh": $fresh,"apkLink": ${apkLink != null?'${json.encode(apkLink)}':'null'},"author": ${author != null?'${json.encode(author)}':'null'},"chapterName": ${chapterName != null?'${json.encode(chapterName)}':'null'},"desc": ${desc != null?'${json.encode(desc)}':'null'},"envelopePic": ${envelopePic != null?'${json.encode(envelopePic)}':'null'},"link": ${link != null?'${json.encode(link)}':'null'},"niceDate": ${niceDate != null?'${json.encode(niceDate)}':'null'},"origin": ${origin != null?'${json.encode(origin)}':'null'},"projectLink": ${projectLink != null?'${json.encode(projectLink)}':'null'},"superChapterName": ${superChapterName != null?'${json.encode(superChapterName)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"tags": $tags}'; } } class ProjectTreeListTag { String name; String url; ProjectTreeListTag.fromParams({this.name, this.url}); ProjectTreeListTag.fromJson(jsonRes) { name = jsonRes['name']; url = jsonRes['url']; } @override String toString() { return '{"name": ${name != null?'${json.encode(name)}':'null'},"url": ${url != null?'${json.encode(url)}':'null'}}'; } } ================================================ FILE: lib/model/system_tree_content_model.dart ================================================ import 'dart:convert' show json; class SystemTreeContentModel { int errorCode; String errorMsg; SystemTreeContentData data; SystemTreeContentModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory SystemTreeContentModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new SystemTreeContentModel.fromJson(json.decode(jsonStr)) : new SystemTreeContentModel.fromJson(jsonStr); SystemTreeContentModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : new SystemTreeContentData.fromJson(jsonRes['data']); } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class SystemTreeContentData { int curPage; int offset; int pageCount; int size; int total; bool over; List datas; SystemTreeContentData.fromParams({this.curPage, this.offset, this.pageCount, this.size, this.total, this.over, this.datas}); SystemTreeContentData.fromJson(jsonRes) { curPage = jsonRes['curPage']; offset = jsonRes['offset']; pageCount = jsonRes['pageCount']; size = jsonRes['size']; total = jsonRes['total']; over = jsonRes['over']; datas = jsonRes['datas'] == null ? null : []; for (var datasItem in datas == null ? [] : jsonRes['datas']){ datas.add(datasItem == null ? null : new SystemTreeContentChild.fromJson(datasItem)); } } @override String toString() { return '{"curPage": $curPage,"offset": $offset,"pageCount": $pageCount,"size": $size,"total": $total,"over": $over,"datas": $datas}'; } } class SystemTreeContentChild { int chapterId; int courseId; int id; int publishTime; int superChapterId; int type; int userId; int visible; int zan; bool collect; bool fresh; String apkLink; String author; String chapterName; String desc; String envelopePic; String link; String niceDate; String origin; String projectLink; String superChapterName; String title; List tags; SystemTreeContentChild.fromParams({this.chapterId, this.courseId, this.id, this.publishTime, this.superChapterId, this.type, this.userId, this.visible, this.zan, this.collect, this.fresh, this.apkLink, this.author, this.chapterName, this.desc, this.envelopePic, this.link, this.niceDate, this.origin, this.projectLink, this.superChapterName, this.title, this.tags}); SystemTreeContentChild.fromJson(jsonRes) { chapterId = jsonRes['chapterId']; courseId = jsonRes['courseId']; id = jsonRes['id']; publishTime = jsonRes['publishTime']; superChapterId = jsonRes['superChapterId']; type = jsonRes['type']; userId = jsonRes['userId']; visible = jsonRes['visible']; zan = jsonRes['zan']; collect = jsonRes['collect']; fresh = jsonRes['fresh']; apkLink = jsonRes['apkLink']; author = jsonRes['author']; chapterName = jsonRes['chapterName']; desc = jsonRes['desc']; envelopePic = jsonRes['envelopePic']; link = jsonRes['link']; niceDate = jsonRes['niceDate']; origin = jsonRes['origin']; projectLink = jsonRes['projectLink']; superChapterName = jsonRes['superChapterName']; title = jsonRes['title']; tags = jsonRes['tags'] == null ? null : []; for (var tagsItem in tags == null ? [] : jsonRes['tags']){ tags.add(tagsItem); } } @override String toString() { return '{"chapterId": $chapterId,"courseId": $courseId,"id": $id,"publishTime": $publishTime,"superChapterId": $superChapterId,"type": $type,"userId": $userId,"visible": $visible,"zan": $zan,"collect": $collect,"fresh": $fresh,"apkLink": ${apkLink != null?'${json.encode(apkLink)}':'null'},"author": ${author != null?'${json.encode(author)}':'null'},"chapterName": ${chapterName != null?'${json.encode(chapterName)}':'null'},"desc": ${desc != null?'${json.encode(desc)}':'null'},"envelopePic": ${envelopePic != null?'${json.encode(envelopePic)}':'null'},"link": ${link != null?'${json.encode(link)}':'null'},"niceDate": ${niceDate != null?'${json.encode(niceDate)}':'null'},"origin": ${origin != null?'${json.encode(origin)}':'null'},"projectLink": ${projectLink != null?'${json.encode(projectLink)}':'null'},"superChapterName": ${superChapterName != null?'${json.encode(superChapterName)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"tags": $tags}'; } } ================================================ FILE: lib/model/system_tree_model.dart ================================================ import 'dart:convert' show json; class SystemTreeModel { int errorCode; String errorMsg; List data; SystemTreeModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory SystemTreeModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new SystemTreeModel.fromJson(json.decode(jsonStr)) : new SystemTreeModel.fromJson(jsonStr); SystemTreeModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : []; for (var dataItem in data == null ? [] : jsonRes['data']){ data.add(dataItem == null ? null : new SystemTreeData.fromJson(dataItem)); } } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class SystemTreeData { int courseId; int id; int order; int parentChapterId; int visible; bool userControlSetTop; String name; List children; SystemTreeData.fromParams({this.courseId, this.id, this.order, this.parentChapterId, this.visible, this.userControlSetTop, this.name, this.children}); SystemTreeData.fromJson(jsonRes) { courseId = jsonRes['courseId']; id = jsonRes['id']; order = jsonRes['order']; parentChapterId = jsonRes['parentChapterId']; visible = jsonRes['visible']; userControlSetTop = jsonRes['userControlSetTop']; name = jsonRes['name']; children = jsonRes['children'] == null ? null : []; for (var childrenItem in children == null ? [] : jsonRes['children']){ children.add(childrenItem == null ? null : new SystemTreeChild.fromJson(childrenItem)); } } @override String toString() { return '{"courseId": $courseId,"id": $id,"order": $order,"parentChapterId": $parentChapterId,"visible": $visible,"userControlSetTop": $userControlSetTop,"name": ${name != null?'${json.encode(name)}':'null'},"children": $children}'; } } class SystemTreeChild { int courseId; int id; int order; int parentChapterId; int visible; bool userControlSetTop; String name; List children; SystemTreeChild.fromParams({this.courseId, this.id, this.order, this.parentChapterId, this.visible, this.userControlSetTop, this.name, this.children}); SystemTreeChild.fromJson(jsonRes) { courseId = jsonRes['courseId']; id = jsonRes['id']; order = jsonRes['order']; parentChapterId = jsonRes['parentChapterId']; visible = jsonRes['visible']; userControlSetTop = jsonRes['userControlSetTop']; name = jsonRes['name']; children = jsonRes['children'] == null ? null : []; for (var childrenItem in children == null ? [] : jsonRes['children']){ children.add(childrenItem); } } @override String toString() { return '{"courseId": $courseId,"id": $id,"order": $order,"parentChapterId": $parentChapterId,"visible": $visible,"userControlSetTop": $userControlSetTop,"name": ${name != null?'${json.encode(name)}':'null'},"children": $children}'; } } ================================================ FILE: lib/model/todo_item.dart ================================================ import 'package:flutter/material.dart'; class TodoItem extends StatelessWidget { String _itemName; String _dateCreated; int _id; TodoItem(this._itemName, this._dateCreated); TodoItem.map(dynamic obj) { this._itemName = obj["itemName"]; this._dateCreated = obj["dateCreated"]; this._id = obj["id"]; } String get itemName => _itemName; String get dateCreated => _dateCreated; int get id => _id; Map toMap() { var map = Map(); map["itemName"] = _itemName; map["dateCreated"] = _dateCreated; if (_id != null) { map["id"] = _id; } return map; } TodoItem.fromMap(Map map) { this._itemName = map["itemName"]; this._dateCreated = map["dateCreated"]; this._id = map["id"]; } @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.all(8.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ //solve the overflow problem Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _itemName, style: TextStyle( color: Colors.black, fontWeight: FontWeight.bold, fontSize: 18.0), maxLines: 1, overflow: TextOverflow.ellipsis, ), Container( margin: const EdgeInsets.only(top: 10.0), child: Text( "Created on: $_dateCreated", style: TextStyle( color: Colors.black, fontSize: 12.0, fontStyle: FontStyle.italic), ), ), ], ), ) ], ), ); } } ================================================ FILE: lib/model/todolist_model.dart ================================================ import 'dart:convert' show json; class TodoListModel { int errorCode; String errorMsg; TodoListData data; TodoListModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory TodoListModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new TodoListModel.fromJson(json.decode(jsonStr)) : new TodoListModel.fromJson(jsonStr); TodoListModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : new TodoListData.fromJson(jsonRes['data']); } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class TodoListData { int type; List doneList; List todoList; TodoListData.fromParams({this.type, this.doneList, this.todoList}); TodoListData.fromJson(jsonRes) { type = jsonRes['type']; doneList = jsonRes['doneList'] == null ? null : []; for (var doneListItem in doneList == null ? [] : jsonRes['doneList']){ doneList.add(doneListItem == null ? null : new TodoListDatas.fromJson(doneListItem)); } todoList = jsonRes['todoList'] == null ? null : []; for (var todoListItem in todoList == null ? [] : jsonRes['todoList']){ todoList.add(todoListItem == null ? null : new TodoListDatas.fromJson(todoListItem)); } } @override String toString() { return '{"type": $type,"doneList": $doneList,"todoList": $todoList}'; } } class TodoListDatas { int date; List todoList; TodoListDatas.fromParams({this.date, this.todoList}); TodoListDatas.fromJson(jsonRes) { date = jsonRes['date']; todoList = jsonRes['todoList'] == null ? null : []; for (var todoListItem in todoList == null ? [] : jsonRes['todoList']){ todoList.add(todoListItem == null ? null : new TodoData.fromJson(todoListItem)); } } @override String toString() { return '{"date": $date,"todoList": $todoList}'; } } class TodoData { TodoData(); TodoData.origin(String title){ this.title = title; } int completeDate; int date; int id; int priority; int status; int type; int userId; String completeDateStr; String content; String dateStr; String title; TodoData.fromParams({this.completeDate, this.date, this.id, this.priority, this.status, this.type, this.userId, this.completeDateStr, this.content, this.dateStr, this.title}); TodoData.fromJson(jsonRes) { completeDate = jsonRes['completeDate']; date = jsonRes['date']; id = jsonRes['id']; priority = jsonRes['priority']; status = jsonRes['status']; type = jsonRes['type']; userId = jsonRes['userId']; completeDateStr = jsonRes['completeDateStr']; content = jsonRes['content']; dateStr = jsonRes['dateStr']; title = jsonRes['title']; } @override String toString() { return '{"completeDate": $completeDate,"date": $date,"id": $id,"priority": $priority,"status": $status,"type": $type,"userId": $userId,"completeDateStr": ${completeDateStr != null?'${json.encode(completeDateStr)}':'null'},"content": ${content != null?'${json.encode(content)}':'null'},"dateStr": ${dateStr != null?'${json.encode(dateStr)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'}}'; } } ================================================ FILE: lib/model/user_model.dart ================================================ import 'dart:convert' show json; class UserModel { int errorCode; String errorMsg; UserData data; UserModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory UserModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new UserModel.fromJson(json.decode(jsonStr)) : new UserModel.fromJson(jsonStr); UserModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : new UserData.fromJson(jsonRes['data']); } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class UserData { int id; int type; String email; String icon; String password; String token; String username; List chapterTops; List collectIds; UserData.fromParams({this.id, this.type, this.email, this.icon, this.password, this.token, this.username, this.chapterTops, this.collectIds}); UserData.fromJson(jsonRes) { id = jsonRes['id']; type = jsonRes['type']; email = jsonRes['email']; icon = jsonRes['icon']; password = jsonRes['password']; token = jsonRes['token']; username = jsonRes['username']; chapterTops = jsonRes['chapterTops'] == null ? null : []; for (var chapterTopsItem in chapterTops == null ? [] : jsonRes['chapterTops']){ chapterTops.add(chapterTopsItem); } collectIds = jsonRes['collectIds'] == null ? null : []; for (var collectIdsItem in collectIds == null ? [] : jsonRes['collectIds']){ collectIds.add(collectIdsItem); } } @override String toString() { 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}'; } } ================================================ FILE: lib/model/website_collection_model.dart ================================================ import 'dart:convert' show json; class WebsiteCollectionModel { int errorCode; String errorMsg; List data; WebsiteCollectionModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory WebsiteCollectionModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new WebsiteCollectionModel.fromJson(json.decode(jsonStr)) : new WebsiteCollectionModel.fromJson(jsonStr); WebsiteCollectionModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : []; for (var dataItem in data == null ? [] : jsonRes['data']){ data.add(dataItem == null ? null : new WebsiteCollectionData.fromJson(dataItem)); } } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class WebsiteCollectionData { int id; int order; int userId; int visible; String desc; String icon; String link; String name; WebsiteCollectionData.fromParams({this.id, this.order, this.userId, this.visible, this.desc, this.icon, this.link, this.name}); WebsiteCollectionData.fromJson(jsonRes) { id = jsonRes['id']; order = jsonRes['order']; userId = jsonRes['userId']; visible = jsonRes['visible']; desc = jsonRes['desc']; icon = jsonRes['icon']; link = jsonRes['link']; name = jsonRes['name']; } @override String toString() { return '{"id": $id,"order": $order,"userId": $userId,"visible": $visible,"desc": ${desc != null?'${json.encode(desc)}':'null'},"icon": ${icon != null?'${json.encode(icon)}':'null'},"link": ${link != null?'${json.encode(link)}':'null'},"name": ${name != null?'${json.encode(name)}':'null'}}'; } } ================================================ FILE: lib/model/wx_article_content_model.dart ================================================ import 'dart:convert' show json; class WxArticleContentModel { int errorCode; String errorMsg; WxArticleContentData data; WxArticleContentModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory WxArticleContentModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new WxArticleContentModel.fromJson(json.decode(jsonStr)) : new WxArticleContentModel.fromJson(jsonStr); WxArticleContentModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : new WxArticleContentData.fromJson(jsonRes['data']); } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class WxArticleContentData { int curPage; int offset; int pageCount; int size; int total; bool over; List datas; WxArticleContentData.fromParams({this.curPage, this.offset, this.pageCount, this.size, this.total, this.over, this.datas}); WxArticleContentData.fromJson(jsonRes) { curPage = jsonRes['curPage']; offset = jsonRes['offset']; pageCount = jsonRes['pageCount']; size = jsonRes['size']; total = jsonRes['total']; over = jsonRes['over']; datas = jsonRes['datas'] == null ? null : []; for (var datasItem in datas == null ? [] : jsonRes['datas']){ datas.add(datasItem == null ? null : new WxArticleContentDatas.fromJson(datasItem)); } } @override String toString() { return '{"curPage": $curPage,"offset": $offset,"pageCount": $pageCount,"size": $size,"total": $total,"over": $over,"datas": $datas}'; } } class WxArticleContentDatas { int chapterId; int courseId; int id; int publishTime; int superChapterId; int type; int userId; int visible; int zan; bool collect; bool fresh; String apkLink; String author; String chapterName; String desc; String envelopePic; String link; String niceDate; String origin; String projectLink; String superChapterName; String title; List tags; WxArticleContentDatas.fromParams({this.chapterId, this.courseId, this.id, this.publishTime, this.superChapterId, this.type, this.userId, this.visible, this.zan, this.collect, this.fresh, this.apkLink, this.author, this.chapterName, this.desc, this.envelopePic, this.link, this.niceDate, this.origin, this.projectLink, this.superChapterName, this.title, this.tags}); WxArticleContentDatas.fromJson(jsonRes) { chapterId = jsonRes['chapterId']; courseId = jsonRes['courseId']; id = jsonRes['id']; publishTime = jsonRes['publishTime']; superChapterId = jsonRes['superChapterId']; type = jsonRes['type']; userId = jsonRes['userId']; visible = jsonRes['visible']; zan = jsonRes['zan']; collect = jsonRes['collect']; fresh = jsonRes['fresh']; apkLink = jsonRes['apkLink']; author = jsonRes['author']; chapterName = jsonRes['chapterName']; desc = jsonRes['desc']; envelopePic = jsonRes['envelopePic']; link = jsonRes['link']; niceDate = jsonRes['niceDate']; origin = jsonRes['origin']; projectLink = jsonRes['projectLink']; superChapterName = jsonRes['superChapterName']; title = jsonRes['title']; tags = jsonRes['tags'] == null ? null : []; for (var tagsItem in tags == null ? [] : jsonRes['tags']){ tags.add(tagsItem == null ? null : new WxArticleContentTags.fromJson(tagsItem)); } } @override String toString() { return '{"chapterId": $chapterId,"courseId": $courseId,"id": $id,"publishTime": $publishTime,"superChapterId": $superChapterId,"type": $type,"userId": $userId,"visible": $visible,"zan": $zan,"collect": $collect,"fresh": $fresh,"apkLink": ${apkLink != null?'${json.encode(apkLink)}':'null'},"author": ${author != null?'${json.encode(author)}':'null'},"chapterName": ${chapterName != null?'${json.encode(chapterName)}':'null'},"desc": ${desc != null?'${json.encode(desc)}':'null'},"envelopePic": ${envelopePic != null?'${json.encode(envelopePic)}':'null'},"link": ${link != null?'${json.encode(link)}':'null'},"niceDate": ${niceDate != null?'${json.encode(niceDate)}':'null'},"origin": ${origin != null?'${json.encode(origin)}':'null'},"projectLink": ${projectLink != null?'${json.encode(projectLink)}':'null'},"superChapterName": ${superChapterName != null?'${json.encode(superChapterName)}':'null'},"title": ${title != null?'${json.encode(title)}':'null'},"tags": $tags}'; } } class WxArticleContentTags { String name; String url; WxArticleContentTags.fromParams({this.name, this.url}); WxArticleContentTags.fromJson(jsonRes) { name = jsonRes['name']; url = jsonRes['url']; } @override String toString() { return '{"name": ${name != null?'${json.encode(name)}':'null'},"url": ${url != null?'${json.encode(url)}':'null'}}'; } } ================================================ FILE: lib/model/wx_article_title_model.dart ================================================ import 'dart:convert' show json; class WxArticleTitleModel { int errorCode; String errorMsg; List data; WxArticleTitleModel.fromParams({this.errorCode, this.errorMsg, this.data}); factory WxArticleTitleModel(jsonStr) => jsonStr == null ? null : jsonStr is String ? new WxArticleTitleModel.fromJson(json.decode(jsonStr)) : new WxArticleTitleModel.fromJson(jsonStr); WxArticleTitleModel.fromJson(jsonRes) { errorCode = jsonRes['errorCode']; errorMsg = jsonRes['errorMsg']; data = jsonRes['data'] == null ? null : []; for (var dataItem in data == null ? [] : jsonRes['data']){ data.add(dataItem == null ? null : new WxArticleTitleData.fromJson(dataItem)); } } @override String toString() { return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}'; } } class WxArticleTitleData { int courseId; int id; int order; int parentChapterId; int visible; bool userControlSetTop; String name; List children; WxArticleTitleData.fromParams({this.courseId, this.id, this.order, this.parentChapterId, this.visible, this.userControlSetTop, this.name, this.children}); WxArticleTitleData.fromJson(jsonRes) { courseId = jsonRes['courseId']; id = jsonRes['id']; order = jsonRes['order']; parentChapterId = jsonRes['parentChapterId']; visible = jsonRes['visible']; userControlSetTop = jsonRes['userControlSetTop']; name = jsonRes['name']; children = jsonRes['children'] == null ? null : []; for (var childrenItem in children == null ? [] : jsonRes['children']){ children.add(childrenItem); } } @override String toString() { return '{"courseId": $courseId,"id": $id,"order": $order,"parentChapterId": $parentChapterId,"visible": $visible,"userControlSetTop": $userControlSetTop,"name": ${name != null?'${json.encode(name)}':'null'},"children": $children}'; } } ================================================ FILE: lib/splash_screen.dart ================================================ import 'package:flutter/material.dart'; import 'package:intro_slider/intro_slider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:wanandroid_ngu/app.dart'; class SplashScreen extends StatefulWidget { @override State createState() { return new SplashScreenState() ; } } class SplashScreenState extends State { List slides = new List(); @override void initState() { super.initState(); slides.add( new Slide( title: "Flutter", description: "Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。", styleDescription: TextStyle( color: Colors.white, fontSize: 20.0, fontFamily: 'Raleway'), marginDescription: EdgeInsets.only(left: 20.0, right: 20.0, top: 20.0, bottom: 70.0), colorBegin: Color(0xffFFDAB9), colorEnd: Color(0xff40E0D0), directionColorBegin: Alignment.topLeft, directionColorEnd: Alignment.bottomRight, ), ); slides.add( new Slide( title: "Wanandroid", description: "这是一款使用Flutter写的WanAndroid客户端应用,在Android和IOS都完美运行,可以用来入门Flutter,简单明了,适合初学者,项目完全开源,如果本项目确实能够帮助到你学习Flutter,谢谢start,有问题请提交Issues,我会及时回复。", styleDescription: TextStyle( color: Colors.white, fontSize: 20.0, fontFamily: 'Raleway'), marginDescription: EdgeInsets.only(left: 20.0, right: 20.0, top: 20.0, bottom: 70.0), colorBegin: Color(0xffFFFACD), colorEnd: Color(0xffFF6347), directionColorBegin: Alignment.topLeft, directionColorEnd: Alignment.bottomRight, ), ); slides.add( new Slide( title: "Welcome", description: "赠人玫瑰,手有余香;\n分享技术,传递快乐。", styleDescription: TextStyle( color: Colors.white, fontSize: 20.0, fontFamily: 'Raleway'), marginDescription: EdgeInsets.only(left: 20.0, right: 20.0, top: 20.0, bottom: 70.0), colorBegin: Color(0xffFFA500), colorEnd: Color(0xff7FFFD4), directionColorBegin: Alignment.topLeft, directionColorEnd: Alignment.bottomRight, ), ); } void onDonePress() { _setHasSkip(); Navigator.of(context).pushAndRemoveUntil( new MaterialPageRoute( builder: (context) => App()), (route) => route == null); } void onSkipPress() { _setHasSkip(); Navigator.of(context).pushAndRemoveUntil( new MaterialPageRoute( builder: (context) => App()), (route) => route == null); } void _setHasSkip ()async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setBool("hasSkip", true); } @override Widget build(BuildContext context) { return IntroSlider( slides: this.slides, onDonePress: this.onDonePress, //renderSkipBtn: this.onSkipPress, nameSkipBtn: "跳过", nameNextBtn: "下一页", nameDoneBtn: "进入", ); } } ================================================ FILE: lib/ui/drawer/about.dart ================================================ import 'package:flutter/material.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; class AboutMePage extends StatefulWidget { @override State createState() { return AboutMePageState(); } } class AboutMePageState extends State { TextStyle textStyle = new TextStyle( color: Colors.blue, decoration: new TextDecoration.combine([TextDecoration.underline])); @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text("关于作者"), ), body: new Container( padding: EdgeInsets.fromLTRB(35, 50, 35, 15), child: new Column( children: [ CircleAvatar( minRadius: 60, maxRadius: 60, backgroundImage: AssetImage('images/head.jpg'), ), Padding(padding: EdgeInsets.only(top: 30)), new Text("基于Google Flutter的玩Android客户端"), Container( margin: const EdgeInsets.fromLTRB(0.0, 80.0, 0.0, 0.0), child: new Row( children: [ new Text("邮箱:"), new Text( "zw20082012@126.com", style: TextStyle(color: Colors.blue), ), ], ), ), GestureDetector( child: new Container( margin: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0), child: new Row( children: [ new Text("CSDN:"), new Text( "https://blog.csdn.net/zw2008224044", style: textStyle, ), ], ), ), onTap: () { Navigator.of(context) .push(new MaterialPageRoute(builder: (ctx) { return new WebViewPage( title: "ngu2008", url: "https://blog.csdn.net/zw2008224044"); })); }, ), GestureDetector( child: new Container( margin: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0), child: new Row( children: [ new Text("GitHub:"), new Text( "https://github.com/ngu2008/wanandroid", style: textStyle, ), ], ), ), onTap: () { Navigator.of(context) .push(new MaterialPageRoute(builder: (ctx) { return new WebViewPage( title: "GitHub", url: "https://github.com/ngu2008/wanandroid"); })); }, ), Expanded(child: Container(), flex: 1), new Text( "本项目仅供学习使用,不得用作商业目的", style: new TextStyle(fontSize: 12.0), ) ], ), )); } } ================================================ FILE: lib/ui/drawer/collctions.dart ================================================ import 'dart:ui'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/base/_base_widget.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/base_model.dart'; import 'package:wanandroid_ngu/model/collection_model.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; class CollectionsPage extends BaseWidget { @override BaseWidgetState getState() { return CollectionsPageState(); } } class CollectionsPageState extends BaseWidgetState { List _datas = new List(); ScrollController _scrollController = ScrollController(); //listview的控制器 int _page = 0; //加载的页数 bool showToTopBtn = false; //是否显示“返回到顶部”按钮 Future getData() async { _page = 0; ApiService().getCollectionList(( CollectionModel _collectionModel, ) { if (_collectionModel.errorCode==0) {//成功 if (_collectionModel.data.datas.length > 0) {//有数据 showContent(); setState(() { _datas.clear(); _datas.addAll(_collectionModel.data.datas); }); } else {//数据为空 showEmpty(); } }else{ Fluttertoast.showToast(msg: _collectionModel.errorMsg); } }, (DioError error) {//发生错误 print(error.response); setState(() { showError(); }); }, _page); } Future _getMore() async { _page++; ApiService().getCollectionList(( CollectionModel _collectionModel, ){ if (_collectionModel.errorCode==0) {//成功 showContent(); if (_collectionModel.data.datas.length > 0) {//有数据 setState(() { _datas.addAll(_collectionModel.data.datas); }); } else {//数据为空 Fluttertoast.showToast(msg:"没有更多数据了"); } }else{ Fluttertoast.showToast(msg: _collectionModel.errorMsg); } }, (DioError error) { print(error.response); setState(() { showError(); }); }, _page); } @override void initState() { super.initState(); showloading(); getData(); _scrollController.addListener(() { if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { _getMore(); } }); _scrollController.addListener(() { //当前位置是否超过屏幕高度 if (_scrollController.offset < 200 && showToTopBtn) { setState(() { showToTopBtn = false; }); } else if (_scrollController.offset >= 200 && showToTopBtn == false) { setState(() { showToTopBtn = true; }); } }); } @override Widget getContentWidget(BuildContext context) { return Scaffold( body: RefreshIndicator( displacement: 15, child: ListView.separated( //普通项 itemBuilder: _renderRow, //插入项 separatorBuilder: (BuildContext context, int index) { return Container( height: 0.5, color: Colors.black26, ); }, controller: _scrollController, itemCount: _datas.length + 1, ), onRefresh: getData), floatingActionButton: !showToTopBtn ? null : FloatingActionButton( child: Icon(Icons.arrow_upward), onPressed: () { //返回到顶部时执行动画 _scrollController.animateTo(.0, duration: Duration(milliseconds: 200), curve: Curves.ease ); } ), ); } Future _cancelCollection(int _position, int _id, int _originId) async { ApiService().cancelCollection((BaseModel _baseModel) { if (_baseModel.errorCode == 0) { _datas.removeAt(_position); } Scaffold.of(context).showSnackBar(new SnackBar( content: Text("移除成功!"), )); setState(() {}); }, (DioError error) { print(error.response); setState(() { showError(); }); }, _id, _originId); } Widget _renderRow(BuildContext context, int index) { if (index < _datas.length) { return _itemView(context, index); } return null; } Widget _itemView(BuildContext context, int index) { return InkWell( child: _slideRow(index, _datas[index]), onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new WebViewPage( title: _datas[index].title, url: _datas[index].link); })); }, ); } Widget _slideRow(int index, Collection item) { return new Slidable( delegate: new SlidableDrawerDelegate(), actionExtentRatio: 0.25, child: _newsRow(item), secondaryActions: [ new IconSlideAction( caption: '取消收藏', color: Colors.red, icon: Icons.delete, onTap: () { _cancelCollection(index, item.id, item.originId); }, ), ], ); } Widget _newsRow(Collection item) { return new Column( children: [ new Container( padding: EdgeInsets.fromLTRB(16, 16, 16, 8), child: new Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "作者:" + item.author, style: TextStyle(fontSize: 12), ), new Expanded( child: new Text( "收藏时间:" + item.niceDate, style: TextStyle(fontSize: 12), textAlign: TextAlign.right, ), ), ], )), Container( padding: EdgeInsets.fromLTRB(16, 0, 16, 0), child: Row( children: [ Expanded( child: Text( item.title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: const Color(0xFF3D4E5F), ), textAlign: TextAlign.left, )) ], )), Container( padding: EdgeInsets.fromLTRB(16, 8, 16, 16), child: Row( children: [ item.chapterName.isNotEmpty ? Expanded( child: Text( "分类:" + item.chapterName, style: TextStyle(fontSize: 12), ), ) : Text("") ], )), ], ); } @override void dispose() { super.dispose(); _scrollController.dispose(); } @override void onClickErrorWidget() { showloading(); getData(); } @override AppBar getAppBar() { return AppBar( title: Text("我的收藏"), elevation: 0.4, ); } } ================================================ FILE: lib/ui/drawer/common_website.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/base/_base_widget.dart'; import 'package:wanandroid_ngu/db/db_helper.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/common_websit_model.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; class CommonWebsitePage extends BaseWidget { @override BaseWidgetState getState() { return CommonWebsitePageState(); } } class CommonWebsitePageState extends BaseWidgetState { List _datas = new List(); ScrollController _scrollController = ScrollController(); var db = DatabaseHelper(); bool showToTopBtn = false; //是否显示“返回到顶部”按钮 Future _getData() async { ApiService().getCommonWebsite((CommonWebsitModel commonWebsitModel) { if (commonWebsitModel.errorCode == 0) { var datas = commonWebsitModel.data; if (datas != null && datas.length > 0) { showContent(); setState(() { _datas = datas; }); //清空表数据 db.clear(); //数据存入数据库 for (int i = 0; i < datas.length; i++) { db.saveItem(datas[i]); } } else { showEmpty(); } } else { Fluttertoast.showToast(msg: commonWebsitModel.errorMsg); } }, (DioError error) { //发生错误 print(error.response); // setState(() { // showError(); // }); }); } _getDataFromDb() async { List datas = await db.getTotalList(); if (datas.length > 0) { datas.forEach((item) { DataListBean dataListBean = DataListBean.fromMap(item); _datas.add(dataListBean); }); setState(() { }); } else { showloading(); } } @override void initState() { super.initState(); // showloading(); //读取数据库的数据 _getDataFromDb(); _getData(); _scrollController.addListener(() { //当前位置是否超过屏幕高度 if (_scrollController.offset < 200 && showToTopBtn) { setState(() { showToTopBtn = false; }); } else if (_scrollController.offset >= 200 && showToTopBtn == false) { setState(() { showToTopBtn = true; }); } }); } Widget _getBodyWidget(List datas) { return RefreshIndicator( displacement: 15, onRefresh: _getData, child: GridView.builder( padding: EdgeInsets.all(15), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, //每行2列 mainAxisSpacing: 15, crossAxisSpacing: 15, childAspectRatio: 1.333 // ), controller: _scrollController, itemCount: _datas.length, itemBuilder: _renderItem), ); } Color _getColor(int index) { switch (index % 8) { case 0: return const Color(0xFFfb6e52); case 1: return const Color(0xFFa1d46f); case 2: return const Color(0xFF5cc0e2); case 3: return const Color(0xFFffbb44); case 4: return const Color(0xFFef6666); case 5: return const Color(0xFFf8d19e); case 6: return const Color(0xFF48cfae); case 7: return const Color(0xFFaa9ef8); } } Widget _renderItem(BuildContext context, int index) { return new InkWell( onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new WebViewPage( title: _datas[index].name, url: _datas[index].link); })); }, child: Container( padding: EdgeInsets.only(top: 25, left: 25), color: _getColor(index), child: Text( _datas[index].name, style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold), ), ), ); } @override AppBar getAppBar() { return AppBar( title: Text("常用网站"), elevation: 0.4, ); } @override Widget getContentWidget(BuildContext context) { return Scaffold( body: _getBodyWidget(_datas), floatingActionButton: !showToTopBtn ? null : FloatingActionButton( child: Icon(Icons.arrow_upward), onPressed: () { //返回到顶部时执行动画 _scrollController.animateTo(.0, duration: Duration(milliseconds: 200), curve: Curves.ease); }), ); } @override void onClickErrorWidget() { showloading(); _getData(); } @override void dispose() { super.dispose(); } } ================================================ FILE: lib/ui/drawer/drawer.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:share/share.dart'; import 'package:wanandroid_ngu/common/application.dart'; import 'package:wanandroid_ngu/common/user.dart'; import 'package:wanandroid_ngu/event/change_theme_event.dart'; import 'package:wanandroid_ngu/event/login_event.dart'; import 'package:wanandroid_ngu/ui/drawer/about.dart'; import 'package:wanandroid_ngu/ui/drawer/collctions.dart'; import 'package:wanandroid_ngu/ui/drawer/common_website.dart'; import 'package:wanandroid_ngu/ui/drawer/pretty.dart'; import 'package:wanandroid_ngu/ui/login/login_page.dart'; import 'package:wanandroid_ngu/util/theme_util.dart'; import 'package:wanandroid_ngu/util/utils.dart'; class DrawerPage extends StatefulWidget { @override State createState() { return new DrawerPageState(); } } class DrawerPageState extends State { bool isLogin = false; String username = "未登录"; @override void initState() { super.initState(); this.registerLoginEvent(); if (null != User.singleton.userName) { isLogin = true; username = User.singleton.userName; } } void registerLoginEvent() { Application.eventBus.on().listen((event) { changeUI(); }); } changeUI() async { setState(() { isLogin = true; username = User.singleton.userName; }); } @override Widget build(BuildContext context) { return Drawer( child: ListView( padding: EdgeInsets.zero, children: [ UserAccountsDrawerHeader( accountName: InkWell( child: Text(username, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)), onTap: () { if (!isLogin) { Navigator.of(context) .push(new MaterialPageRoute(builder: (context) { return new LoginPage(); })); } }, ), currentAccountPicture: InkWell( child: CircleAvatar( backgroundImage: AssetImage('images/head.jpg'), ), onTap: () { if (!isLogin) { Navigator.of(context) .push(new MaterialPageRoute(builder: (context) { return new LoginPage(); })); } }, ), ), ListTile( title: Text( '我的收藏', textAlign: TextAlign.left, ), leading: Icon(Icons.collections, size: 22.0), onTap: () { if (isLogin) { onCollectionClick(); } else { onLoginClick(); } }, ), ListTile( title: Text( '常用网站', textAlign: TextAlign.left, ), leading: Icon(Icons.web, size: 22.0), onTap: () { Navigator.of(context) .push(new MaterialPageRoute(builder: (context) { return new CommonWebsitePage(); })); }, ), ListTile( title: Text( '主题', textAlign: TextAlign.left, ), leading: Icon(Icons.settings, size: 22.0), onTap: () { showDialog( context: context, builder: (BuildContext context) { return new SimpleDialog( title: Text("设置主题"), children: ThemeUtils.supportColors.map((Color color) { return new SimpleDialogOption( child: Container( padding: EdgeInsets.fromLTRB(10, 8, 10, 8), height: 35, color: color, ), onPressed: () { ThemeUtils.currentColorTheme = color; Utils.setColorTheme( ThemeUtils.supportColors.indexOf(color)); changeColorTheme(color); Navigator.of(context).pop(); }, ); }).toList(), ); }, ); }, ), ListTile( title: Text( '分享', textAlign: TextAlign.left, ), leading: Icon(Icons.share, size: 22.0), onTap: () { Share.share( '给你推荐一个特别好玩的应用玩安卓客户端,点击下载:https://www.pgyer.com/haFL'); }, ), ListTile( title: Text( '妹子图', textAlign: TextAlign.left, ), leading: Icon(Icons.directions_bike, size: 22.0), onTap: () { Navigator.of(context) .push(new MaterialPageRoute(builder: (context) { return new PrettyPage(); })); }, ), ListTile( title: Text( '关于作者', textAlign: TextAlign.left, ), leading: Icon(Icons.info, size: 22.0), onTap: () { Navigator.of(context) .push(new MaterialPageRoute(builder: (context) { return new AboutMePage(); })); }, ), logoutWidget() ], ), ); } Widget logoutWidget() { if (User.singleton.userName != null) { return ListTile( title: Text( '退出登录', textAlign: TextAlign.left, ), leading: Icon(Icons.power_settings_new, size: 22.0), onTap: () { User.singleton.clearUserInfor(); setState(() { isLogin = false; username = "未登录"; }); }, ); } else { return SizedBox( height: 0, ); } } void onCollectionClick() async { await Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new CollectionsPage(); })); } void onLoginClick() async { await Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new LoginPage(); })); } changeColorTheme(Color c) { Application.eventBus.fire(new ChangeThemeEvent(c)); } } ================================================ FILE: lib/ui/drawer/pretty.dart ================================================ import 'package:flutter/material.dart'; import 'package:photo_view/photo_view_gallery.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/pretty_model.dart'; class PrettyPage extends StatefulWidget { @override State createState() { return new PrettyPageState(); } } class PrettyPageState extends State { //当前页数据 List _datas = new List(); //所有的照片数据 List photos = new List(); int _page = 1; Future _getData() async { ApiService().getPrettyGirl((PrettyModel prettyModel) { setState(() { _datas = prettyModel.results; for (int i = 0; i < _datas.length; i++) { PhotoViewGalleryPageOptions pageOptions = PhotoViewGalleryPageOptions( imageProvider: NetworkImage(_datas[i].url)); photos.add(pageOptions); } }); }, _page); } @override void initState() { super.initState(); _getData(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("妹子图"), ), body: Container( child: PhotoViewGallery( onPageChanged: (int index) { if(index==photos.length-1){//加载到最有一页 _page++; _getData(); } }, pageOptions: photos, backgroundDecoration: BoxDecoration(color: Colors.black87), )), ); } } ================================================ FILE: lib/ui/home/banner.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_swiper/flutter_swiper.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/banner_model.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; class BannerWidget extends StatefulWidget { @override State createState() { return BannerWidgetState(); } } class BannerWidgetState extends State { List _bannerList = new List(); @override void initState() { _bannerList.add(null); _getBanner(); } Future _getBanner() { ApiService().getBanner((BannerModel _bannerModel) { if (_bannerModel.data.length > 0) { setState(() { _bannerList = _bannerModel.data; }); } }); } Widget buildItemImageWidget(BuildContext context, int index) { return new InkWell( onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context){ return new WebViewPage(title: _bannerList[index].title,url: _bannerList[index].url); })); }, child: new Container( child: new Image.network( _bannerList[index].imagePath, fit: BoxFit.fill, ), ), ); } @override Widget build(BuildContext context) { return Swiper( itemBuilder: (BuildContext context, int index) { if (_bannerList[index] == null || _bannerList[index].imagePath == null) { return new Container( color: Colors.grey[100], ); } else { return buildItemImageWidget(context, index); } }, itemCount: _bannerList.length, autoplay: true, pagination: new SwiperPagination(), );; } } ================================================ FILE: lib/ui/home/home_page.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/base/_base_widget.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/article_model.dart'; import 'package:wanandroid_ngu/ui/home/banner.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; class HomePage extends BaseWidget { @override BaseWidgetState getState() { return HomePageState(); } } class HomePageState extends BaseWidgetState { List
_datas = new List(); //listview控制器 ScrollController _scrollController = ScrollController(); bool showToTopBtn = false; //是否显示“返回到顶部”按钮 int _page = 0; @override void initState() { super.initState(); setAppBarVisible(false); getData(); _scrollController.addListener(() { //滑到了底部,加载更多 if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { _getMore(); } //当前位置是否超过屏幕高度 if (_scrollController.offset < 200 && showToTopBtn) { setState(() { showToTopBtn = false; }); } else if (_scrollController.offset >= 200 && showToTopBtn == false) { setState(() { showToTopBtn = true; }); } }); } //获取文章列表数据 Future getData() async { _page = 0; ApiService().getArticleList((ArticleModel _articleModel) { if (_articleModel.errorCode == 0) { //成功 if (_articleModel.data.datas.length > 0) { //有数据 showContent(); setState(() { _datas.clear(); _datas.addAll(_articleModel.data.datas); }); } else { //数据为空 showEmpty(); } } else { Fluttertoast.showToast(msg: _articleModel.errorMsg); } }, (DioError error) { //发生错误 print(error.response); setState(() { showError(); }); }, _page); } //加载更多的数据 Future _getMore() async { _page++; ApiService().getArticleList((ArticleModel _articleModel) { if (_articleModel.errorCode == 0) { //成功 if (_articleModel.data.datas.length > 0) { //有数据 showContent(); setState(() { _datas.addAll(_articleModel.data.datas); }); } else { //数据为空 Fluttertoast.showToast(msg: "没有更多数据了"); } } else { Fluttertoast.showToast(msg: _articleModel.errorMsg); } }, (DioError error) { //发生错误 print(error.response); setState(() { showError(); }); }, _page); } @override AppBar getAppBar() { return AppBar( title: Text("不显示"), ); } @override Widget getContentWidget(BuildContext context) { return Scaffold( body: RefreshIndicator( displacement: 15, onRefresh: getData, child: ListView.separated( itemBuilder: _renderRow, physics: new AlwaysScrollableScrollPhysics(), separatorBuilder: (BuildContext context, int index) { return Container( height: 0.5, color: Colors.black26, ); }, controller: _scrollController, //包含轮播图和加载更多 itemCount: _datas.length + 2), ), floatingActionButton: !showToTopBtn ? null : FloatingActionButton( child: Icon(Icons.arrow_upward), onPressed: () { //返回到顶部时执行动画 _scrollController.animateTo(.0, duration: Duration(milliseconds: 200), curve: Curves.ease); }), ); } Widget _renderRow(BuildContext context, int index) { if (index == 0) { return Container( height: 200, color: Colors.green, child: new BannerWidget(), ); } if (index < _datas.length - 1) { return new InkWell( onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new WebViewPage( title: _datas[index - 1].title, url: _datas[index - 1].link); })); }, child: Column( children: [ Container( color: Colors.white, padding: EdgeInsets.fromLTRB(16, 16, 16, 8), child: Row( children: [ Text( _datas[index - 1].author, style: TextStyle(fontSize: 12), textAlign: TextAlign.left, ), Expanded( child: Text( _datas[index - 1].niceDate, style: TextStyle(fontSize: 12), textAlign: TextAlign.right, ), ), ], ), ), Container( color: Colors.white, padding: EdgeInsets.fromLTRB(16, 0, 16, 0), child: Row( children: [ Expanded( child: Text( _datas[index - 1].title, maxLines: 2, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: const Color(0xFF3D4E5F), ), textAlign: TextAlign.left, ), ) ], ), ), Container( color: Colors.white, padding: EdgeInsets.fromLTRB(16, 8, 16, 16), child: Row( children: [ Expanded( child: Text( _datas[index - 1].superChapterName, style: TextStyle(fontSize: 12), textAlign: TextAlign.left, ), ) ], ), ), ], ), ); } return null; } @override void dispose() { super.dispose(); _scrollController.dispose(); } @override bool get wantKeepAlive => true; @override void onClickErrorWidget() { showloading(); getData(); } } ================================================ FILE: lib/ui/knowledge/knowledge.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/base/_base_widget.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/system_tree_model.dart'; import 'package:wanandroid_ngu/ui/knowledge/knowledge_content.dart'; import 'package:wanandroid_ngu/util/utils.dart'; class KnowledgePage extends BaseWidget { @override BaseWidgetState getState() { return KnowledgePageState(); } } class KnowledgePageState extends BaseWidgetState { List _datas = new List(); //listview控制器 ScrollController _scrollController = ScrollController(); bool showToTopBtn = false; //是否显示“返回到顶部”按钮 @override void initState() { super.initState(); setAppBarVisible(false); _getData(); _scrollController.addListener(() { //当前位置是否超过屏幕高度 if (_scrollController.offset < 200 && showToTopBtn) { setState(() { showToTopBtn = false; }); } else if (_scrollController.offset >= 200 && showToTopBtn == false) { setState(() { showToTopBtn = true; }); } }); } Future _getData() async { ApiService().getSystemTree((SystemTreeModel _systemTreeModel) { if (_systemTreeModel.errorCode == 0) { //成功 if (_systemTreeModel.data.length > 0) { //有数据 showContent(); setState(() { _datas.clear(); _datas.addAll(_systemTreeModel.data); }); } else { //数据为空 showEmpty(); } } else { Fluttertoast.showToast(msg: _systemTreeModel.errorMsg); } },(DioError error) { //发生错误 print(error.response); showError(); }); } Widget _renderRow(BuildContext context, int index) { if (index < _datas.length) { return InkWell( onTap: () { Navigator.of(context) .push(new MaterialPageRoute(builder: (context) { return new KnowledgeContentPage(new ValueKey(_datas[index])); })); }, child: Container( color: Colors.white, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Container( padding: EdgeInsets.all(16), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( alignment: Alignment.centerLeft, padding: EdgeInsets.only(bottom: 8), child: Text( _datas[index].name, style: TextStyle( fontSize: 16, color: Color(0xFF3D4E5F), fontWeight: FontWeight.bold), textAlign: TextAlign.left, ), ), Container( alignment: Alignment.centerLeft, child: buildChildren(_datas[index].children)), ], ), )), Icon(Icons.chevron_right) ], ), )); } return null; } Widget buildChildren(List children) { List tiles = []; //先建一个数组用于存放循环生成的widget Widget content; //单独一个widget组件,用于返回需要生成的内容widget for (var item in children) { tiles.add( new Chip( materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, backgroundColor: Utils.getChipBgColor(item.name), label: new Text(item.name), // avatar: new CircleAvatar(backgroundColor: Colors.blue,child: Text("A"),), ), ); } content = Wrap( spacing: 12, runSpacing: 12, alignment: WrapAlignment.start, children: tiles); return content; } @override void dispose() { super.dispose(); _scrollController.dispose(); } @override AppBar getAppBar() { return AppBar( title: Text("不显示"), ); } @override Widget getContentWidget(BuildContext context) { return Scaffold( body: RefreshIndicator( displacement: 15, onRefresh: _getData, child: ListView.separated( itemBuilder: _renderRow, physics: new AlwaysScrollableScrollPhysics(), separatorBuilder: (BuildContext context, int index) { return Container( height: 0.5, color: Colors.black26, ); }, itemCount: _datas.length, controller: _scrollController, ), ), floatingActionButton: !showToTopBtn ? null : FloatingActionButton( child: Icon(Icons.arrow_upward), onPressed: () { //返回到顶部时执行动画 _scrollController.animateTo(.0, duration: Duration(milliseconds: 200), curve: Curves.ease ); } ), ); } @override void onClickErrorWidget() { showloading(); _getData(); } } ================================================ FILE: lib/ui/knowledge/knowledge_content.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/base/_base_widget.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/system_tree_content_model.dart'; import 'package:wanandroid_ngu/model/system_tree_model.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; class KnowledgeContentPage extends StatefulWidget { SystemTreeData data; KnowledgeContentPage(ValueKey key) : super(key: key) { this.data = key.value; } @override State createState() { return KnowledgeContentPageState(); } } class KnowledgeContentPageState extends State with TickerProviderStateMixin { SystemTreeData _datas; TabController _tabController; @override void initState() { super.initState(); _datas = widget.data; } @override void dispose() { super.dispose(); _tabController.dispose(); } @override Widget build(BuildContext context) { _tabController = new TabController(length: _datas.children.length, vsync: this); return new Scaffold( appBar: new AppBar( title: Text(_datas.name), bottom: new TabBar( indicatorColor: Colors.white, labelStyle:TextStyle(fontSize: 16), unselectedLabelStyle: TextStyle(fontSize: 16), controller: _tabController, isScrollable: true, tabs: _datas.children.map((SystemTreeChild item) { return Tab( text: item.name, ); }).toList()), ), body: TabBarView( controller: _tabController, children: _datas.children.map((item) { return NewsList( item.id, ); }).toList(), ), ); } } //知识体系文章列表 class NewsList extends BaseWidget { final int id; NewsList(this.id); @override BaseWidgetState getState() { return _NewsListState(); } //知识体系id } class _NewsListState extends BaseWidgetState { List _datas = new List(); ScrollController _scrollController = ScrollController(); //listview的控制器 int _page = 0; @override void initState() { setAppBarVisible(false); showloading(); getData(); _scrollController.addListener(() { if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { _getMore(); } }); } Future getData() async { _page = 0; int _id = widget.id; ApiService().getSystemTreeContent( (SystemTreeContentModel _systemTreeContentModel) { if (_systemTreeContentModel.errorCode == 0) { //成功 if (_systemTreeContentModel.data.datas.length > 0) { //有数据 showContent(); setState(() { _datas = _systemTreeContentModel.data.datas; }); } else { //数据为空 showEmpty(); } } else { Fluttertoast.showToast(msg: _systemTreeContentModel.errorMsg); } },(DioError error) { //发生错误 print(error.response); showError(); }, _page, _id); } Future _getMore() async { _page++; int _id = widget.id; ApiService().getSystemTreeContent( (SystemTreeContentModel _systemTreeContentModel) { if (_systemTreeContentModel.errorCode == 0) { //成功 if (_systemTreeContentModel.data.datas.length > 0) { //有数据 showContent(); setState(() { _datas.addAll(_systemTreeContentModel.data.datas); }); } else { //数据为空 Fluttertoast.showToast(msg: "没有更多数据了"); } } else { Fluttertoast.showToast(msg: _systemTreeContentModel.errorMsg); } },(DioError error) { //发生错误 print(error.response); showError(); }, _page, _id); } Widget _renderRow(BuildContext context, int index) { if (index < _datas.length) { return InkWell( child: Container( child: _newsRow(_datas[index]), ), onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new WebViewPage( title: _datas[index].title, url: _datas[index].link); })); }, ); } return null; } //新闻列表单个item Widget _newsRow(SystemTreeContentChild item) { return new Container( color: Colors.white, padding: EdgeInsets.all(16), child: Column( children: [ new Container( padding: EdgeInsets.fromLTRB(8, 8, 8, 8), child: new Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( item.author, style: TextStyle(fontSize: 12, color: Colors.grey), ), new Expanded( child: new Text( item.niceDate, style: TextStyle(fontSize: 12, color: Colors.grey), textAlign: TextAlign.right, ), ), ], )), Container( padding: EdgeInsets.fromLTRB(8, 0, 8, 8), child: Row( children: [ Expanded( child: Text( item.title, style: TextStyle( fontSize: 16, color: const Color(0xFF3D4E5F), fontWeight: FontWeight.bold), textAlign: TextAlign.left, )) ], )), Container( padding: EdgeInsets.fromLTRB(8, 0, 8, 8), child: Row( children: [ Text( item.superChapterName, style: TextStyle(fontSize: 12, color: Colors.grey), ), new Text( "/" + item.chapterName, style: TextStyle(fontSize: 12, color: Colors.grey), textAlign: TextAlign.right, ), ], )), ], ), ); } @override AppBar getAppBar() { return AppBar( title: Text("不显示"), ); } @override Widget getContentWidget(BuildContext context) { return RefreshIndicator( onRefresh: getData, child: ListView.separated( physics: new AlwaysScrollableScrollPhysics(), itemBuilder: _renderRow, itemCount: _datas.length + 1, controller: _scrollController, separatorBuilder: (BuildContext context, int index) { return Container( height: 0.5, color: Colors.black26, ); }, ), ); } @override void onClickErrorWidget() { showloading(); getData(); } } ================================================ FILE: lib/ui/login/login_page.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:wanandroid_ngu/common/application.dart'; import 'package:wanandroid_ngu/common/user.dart'; import 'package:wanandroid_ngu/event/login_event.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/user_model.dart'; import 'package:wanandroid_ngu/util/bubble_indication_painter.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/util/theme_util.dart'; class LoginPage extends StatefulWidget { LoginPage({Key key}) : super(key: key); @override _LoginPageState createState() => new _LoginPageState(); } class _LoginPageState extends State with SingleTickerProviderStateMixin { Color themeColor = ThemeUtils.currentColorTheme; final GlobalKey _scaffoldKey = new GlobalKey(); final FocusNode myFocusNodeEmailLogin = FocusNode(); final FocusNode myFocusNodePasswordLogin = FocusNode(); final FocusNode myFocusNodePassword = FocusNode(); final FocusNode myFocusNodeName = FocusNode(); TextEditingController loginEmailController = new TextEditingController(); TextEditingController loginPasswordController = new TextEditingController(); bool _obscureTextLogin = true; bool _obscureTextSignup = true; bool _obscureTextSignupConfirm = true; TextEditingController signupNameController = new TextEditingController(); TextEditingController signupPasswordController = new TextEditingController(); TextEditingController signupConfirmPasswordController = new TextEditingController(); PageController _pageController; Color left = Colors.black; Color right = Colors.white; String title = "登录"; @override Widget build(BuildContext context) { return new Scaffold( appBar: AppBar( title: Text(title), ), key: _scaffoldKey, body: NotificationListener( onNotification: (overscroll) { overscroll.disallowGlow(); }, child: SingleChildScrollView( child: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height >= 775.0 ? MediaQuery.of(context).size.height : 775.0, decoration: new BoxDecoration( gradient: new LinearGradient( colors: [Color(0xFFffffff), Color(0xFFffffff)], begin: const FractionalOffset(0.0, 0.0), end: const FractionalOffset(1.0, 1.0), stops: [0.0, 1.0], tileMode: TileMode.clamp), ), child: Column( mainAxisSize: MainAxisSize.max, children: [ Padding( padding: EdgeInsets.only(top: 60.0), child: _buildMenuBar(context), ), Expanded( flex: 2, child: PageView( controller: _pageController, onPageChanged: (i) { if (i == 0) { setState(() { right = Colors.white; left = Colors.black; title = "登录"; }); } else if (i == 1) { setState(() { right = Colors.black; left = Colors.white; title = "注册"; }); } }, children: [ new ConstrainedBox( constraints: const BoxConstraints.expand(), child: _buildSignIn(context), ), new ConstrainedBox( constraints: const BoxConstraints.expand(), child: _buildSignUp(context), ), ], ), ), ], ), ), ), ), ); } @override void dispose() { myFocusNodePassword.dispose(); myFocusNodeName.dispose(); _pageController?.dispose(); super.dispose(); } @override void initState() { super.initState(); SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); _pageController = PageController(); } void showInSnackBar(String value) { FocusScope.of(context).requestFocus(new FocusNode()); _scaffoldKey.currentState?.removeCurrentSnackBar(); _scaffoldKey.currentState.showSnackBar(new SnackBar( content: new Text( value, textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 16.0, ), ), backgroundColor: themeColor, duration: Duration(seconds: 3), )); } Widget _buildMenuBar(BuildContext context) { return Container( width: 300.0, height: 50.0, decoration: BoxDecoration( color: Color(0x552B2B2B), borderRadius: BorderRadius.all(Radius.circular(25.0)), ), child: CustomPaint( painter: TabIndicationPainter(pageController: _pageController), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Expanded( child: FlatButton( splashColor: Colors.transparent, highlightColor: Colors.transparent, onPressed: _onSignInButtonPress, child: Text( "登录", style: TextStyle(color: left, fontSize: 16.0), ), ), ), //Container(height: 33.0, width: 1.0, color: Colors.white), Expanded( child: FlatButton( splashColor: Colors.transparent, highlightColor: Colors.transparent, onPressed: _onSignUpButtonPress, child: Text( "注册", style: TextStyle( color: right, fontSize: 16.0, ), ), ), ), ], ), ), ); } Widget _buildSignIn(BuildContext context) { //登录 Future _login() async { String username = loginEmailController.text; String password = loginPasswordController.text; if ((null != username && username.trim().length > 0) && (null != password && password.trim().length > 0)) { ApiService().login((UserModel _userModel, Response response) { if (_userModel != null) { User().saveUserInfo(_userModel, response); Application.eventBus.fire(new LoginEvent()); if (_userModel.errorCode == 0) { Fluttertoast.showToast(msg: "登录成功!"); Navigator.of(context).pop(); } else { Fluttertoast.showToast(msg: _userModel.errorMsg); } } }, username, password); } else { Fluttertoast.showToast( msg: "用户名或者密码不能为空", ); } } return Container( padding: EdgeInsets.only(top: 23.0), child: Column( children: [ Stack( alignment: Alignment.topCenter, overflow: Overflow.visible, children: [ Card( elevation: 2.0, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), child: Container( width: 300.0, height: 150.0, child: Column( children: [ Padding( padding: EdgeInsets.only( top: 10.0, bottom: 10.0, left: 25.0, right: 25.0), child: TextField( focusNode: myFocusNodeEmailLogin, controller: loginEmailController, keyboardType: TextInputType.emailAddress, style: TextStyle(fontSize: 14.0, color: Colors.black), decoration: InputDecoration( border: InputBorder.none, icon: Icon( FontAwesomeIcons.user, color: Colors.black, size: 18.0, ), hintText: "用户名", hintStyle: TextStyle(fontSize: 17.0), ), ), ), Container( width: 250.0, height: 1.0, color: Colors.grey[400], ), Padding( padding: EdgeInsets.only( top: 10.0, bottom: 10.0, left: 25.0, right: 25.0), child: TextField( focusNode: myFocusNodePasswordLogin, controller: loginPasswordController, obscureText: _obscureTextLogin, style: TextStyle(fontSize: 16.0, color: Colors.black), decoration: InputDecoration( border: InputBorder.none, icon: Icon( FontAwesomeIcons.lock, size: 22.0, color: Colors.black, ), hintText: "密码", hintStyle: TextStyle(fontSize: 17.0), suffixIcon: GestureDetector( onTap: _toggleLogin, child: Icon( FontAwesomeIcons.eye, size: 15.0, color: Colors.black, ), ), ), ), ), ], ), ), ), Container( margin: EdgeInsets.only(top: 240.0), decoration: new BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(5.0)), boxShadow: [ BoxShadow( color: const Color(0xFFffffff), offset: Offset(1.0, 6.0), blurRadius: 20.0, ), BoxShadow( color: const Color(0xFFffffff), offset: Offset(1.0, 6.0), blurRadius: 20.0, ), ], gradient: new LinearGradient( colors: [Color(0xFFffffff), Color(0xFFffffff)], begin: const FractionalOffset(0.2, 0.2), end: const FractionalOffset(1.0, 1.0), stops: [0.0, 1.0], tileMode: TileMode.clamp), ), child: FlatButton( shape: RoundedRectangleBorder( side: BorderSide( color: themeColor, width: 1, ), borderRadius: BorderRadius.circular(30)), color: themeColor, child: Padding( padding: const EdgeInsets.symmetric( vertical: 10.0, horizontal: 60.0), child: Text( "登录", style: TextStyle( color: Colors.white, fontSize: 18.0, ), ), ), onPressed: () { _login(); }), ), ], ) ], ), ); } Widget _buildSignUp(BuildContext context) { Future _regist() async { String username = signupNameController.text; String password = signupPasswordController.text; String rePassword = signupConfirmPasswordController.text; if ((null != username && username.trim().length > 0) && (null != password && password.trim().length > 0) && (null != rePassword && rePassword.trim().length > 0)) { if (password != rePassword) { Fluttertoast.showToast(msg: "两次密码输入不一致!"); } else { ApiService().register((UserModel _userModel) { if (_userModel != null) { if (_userModel.errorCode == 0) { Fluttertoast.showToast(msg: "注册成功!"); } else { Fluttertoast.showToast(msg: _userModel.errorMsg); } } }, username, password); } } else { Fluttertoast.showToast( msg: "用户名或者密码不能为空", ); } } return Container( padding: EdgeInsets.only(top: 23.0), child: Column( children: [ Stack( alignment: Alignment.topCenter, overflow: Overflow.visible, children: [ Card( elevation: 2.0, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), child: Container( width: 300.0, height: 210.0, child: Column( children: [ Padding( padding: EdgeInsets.only( top: 10.0, bottom: 10.0, left: 25.0, right: 25.0), child: TextField( focusNode: myFocusNodeName, controller: signupNameController, keyboardType: TextInputType.text, textCapitalization: TextCapitalization.words, style: TextStyle(fontSize: 16.0, color: Colors.black), decoration: InputDecoration( border: InputBorder.none, icon: Icon( FontAwesomeIcons.user, color: Colors.black, ), hintText: "用户名", hintStyle: TextStyle(fontSize: 16.0), ), ), ), Container( width: 250.0, height: 1.0, color: Colors.grey[400], ), Padding( padding: EdgeInsets.only( top: 10.0, bottom: 10.0, left: 25.0, right: 25.0), child: TextField( focusNode: myFocusNodePassword, controller: signupPasswordController, obscureText: _obscureTextSignup, style: TextStyle(fontSize: 16.0, color: Colors.black), decoration: InputDecoration( border: InputBorder.none, icon: Icon( FontAwesomeIcons.lock, color: Colors.black, ), hintText: "密码", hintStyle: TextStyle(fontSize: 16.0), suffixIcon: GestureDetector( onTap: _toggleSignup, child: Icon( FontAwesomeIcons.eye, size: 15.0, color: Colors.black, ), ), ), ), ), Container( width: 250.0, height: 1.0, color: Colors.grey[400], ), Padding( padding: EdgeInsets.only( top: 10.0, bottom: 10, left: 25.0, right: 25.0), child: TextField( controller: signupConfirmPasswordController, obscureText: _obscureTextSignupConfirm, style: TextStyle(fontSize: 16.0, color: Colors.black), decoration: InputDecoration( border: InputBorder.none, icon: Icon( FontAwesomeIcons.lock, color: Colors.black, ), hintText: "确认密码", hintStyle: TextStyle(fontSize: 16.0), suffixIcon: GestureDetector( onTap: _toggleSignupConfirm, child: Icon( FontAwesomeIcons.eye, size: 15.0, color: Colors.black, ), ), ), ), ), ], ), ), ), Container( margin: EdgeInsets.only(top: 340.0), decoration: new BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(5.0)), ), child: FlatButton( shape: RoundedRectangleBorder( side: BorderSide( color: themeColor, width: 1, ), borderRadius: BorderRadius.circular(30)), color: themeColor, child: Padding( padding: const EdgeInsets.symmetric( vertical: 10.0, horizontal: 60.0), child: Text( "注册", style: TextStyle(color: Colors.white, fontSize: 18.0), ), ), onPressed: () { _regist(); }), ), ], ), ], ), ); } //切换到登录 void _onSignInButtonPress() { _pageController.animateToPage(0, duration: Duration(milliseconds: 500), curve: Curves.decelerate); } //切换到注册 void _onSignUpButtonPress() { _pageController?.animateToPage(1, duration: Duration(milliseconds: 500), curve: Curves.decelerate); } //登录密码安全开关 void _toggleLogin() { setState(() { _obscureTextLogin = !_obscureTextLogin; }); } //注册密码安全开关 void _toggleSignup() { setState(() { _obscureTextSignup = !_obscureTextSignup; }); } //注册确认密码安全开关 void _toggleSignupConfirm() { setState(() { _obscureTextSignupConfirm = !_obscureTextSignupConfirm; }); } } ================================================ FILE: lib/ui/navigation/navigation.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/base/_base_widget.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/navi_model.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; import 'package:wanandroid_ngu/util/utils.dart'; class NavigationPage extends BaseWidget { @override BaseWidgetState getState() { return NavigationState(); } } class NavigationState extends BaseWidgetState { List _naviTitles = new List(); //listview控制器 ScrollController _scrollController = ScrollController(); bool showToTopBtn = false; //是否显示“返回到顶部”按钮 @override void initState() { super.initState(); setAppBarVisible(false); _getData(); _scrollController.addListener(() { _scrollController.addListener(() { //当前位置是否超过屏幕高度 if (_scrollController.offset < 200 && showToTopBtn) { setState(() { showToTopBtn = false; }); } else if (_scrollController.offset >= 200 && showToTopBtn == false) { setState(() { showToTopBtn = true; }); } }); }); } Future _getData() async { ApiService().getNaviList((NaviModel _naviData) { if (_naviData.errorCode == 0) { //成功 if (_naviData.data.length > 0) { //有数据 showContent(); setState(() { _naviTitles = _naviData.data; }); } else { //数据为空 showEmpty(); } } else { Fluttertoast.showToast(msg: _naviData.errorMsg); } },(DioError error) { //发生错误 print(error.response); showError(); }); } Widget _rightListView(BuildContext context) { return ListView.separated( itemBuilder: _renderContent, itemCount: _naviTitles.length, controller: _scrollController, physics: new AlwaysScrollableScrollPhysics(), separatorBuilder: (BuildContext context, int index) { return Container( height: 0.5, color: Colors.black26, ); }); } Widget _renderContent(BuildContext context, int index) { return Container( color: Colors.white, padding: EdgeInsets.all(16), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( alignment: Alignment.centerLeft, padding: EdgeInsets.only(bottom: 8), child: Text( _naviTitles[index].name, style: TextStyle( fontSize: 16, color: Color(0xFF3D4E5F), fontWeight: FontWeight.bold), textAlign: TextAlign.left, ), ), Container( alignment: Alignment.centerLeft, child: buildChildren(_naviTitles[index].articles), ), ], ), ); } Widget buildChildren(List children) { List tiles = []; //先建一个数组用于存放循环生成的widget Widget content; //单独一个widg for (NaviArticle item in children) { tiles.add(new InkWell( child: new Chip( materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, backgroundColor: Utils.getChipBgColor(item.title), label: new Text(item.title)), onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new WebViewPage(title: item.title, url: item.link); })); }, )); } content = Wrap( spacing: 12, runSpacing: 12, alignment: WrapAlignment.start, children: tiles, ); return content; } @override AppBar getAppBar() { return AppBar( title: Text("不显示"), ); } @override Widget getContentWidget(BuildContext context) { return Scaffold( body: RefreshIndicator( displacement: 15, child: _rightListView(context), onRefresh: _getData, ), floatingActionButton: !showToTopBtn ? null : FloatingActionButton( child: Icon(Icons.arrow_upward), onPressed: () { //返回到顶部时执行动画 _scrollController.animateTo(.0, duration: Duration(milliseconds: 200), curve: Curves.ease); }), ); } @override void onClickErrorWidget() { showloading(); _getData(); } } ================================================ FILE: lib/ui/project/project.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/base/_base_widget.dart'; import 'package:wanandroid_ngu/common/application.dart'; import 'package:wanandroid_ngu/event/change_theme_event.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/projectlist_model.dart'; import 'package:wanandroid_ngu/model/project_tree_model.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; import 'package:wanandroid_ngu/util/theme_util.dart'; class ProjectPage extends BaseWidget { @override BaseWidgetState getState() { return ProjectPageState(); } } class ProjectPageState extends BaseWidgetState with TickerProviderStateMixin { Color themeColor = ThemeUtils.currentColorTheme; List _datas = new List(); TabController _tabController; Future _getData() async { ApiService().getProjectTree((ProjectTreeModel _projectTreeModel) { if (_projectTreeModel.errorCode == 0) { //成功 if (_projectTreeModel.data.length > 0) { //有数据 showContent(); setState(() { _datas = _projectTreeModel.data; }); } else { //数据为空 showEmpty(); } } else { Fluttertoast.showToast(msg: _projectTreeModel.errorMsg); } }, (DioError error) { //发生错误 print(error.response); showError(); }); } @override void initState() { super.initState(); setAppBarVisible(false); _getData(); Application.eventBus.on().listen((event) { setState(() { themeColor = event.color; }); }); } @override void dispose() { super.dispose(); _tabController.dispose(); super.dispose(); } @override AppBar getAppBar() { return AppBar( title: Text("不显示"), ); } @override Widget getContentWidget(BuildContext context) { _tabController = new TabController( vsync: this, length: _datas.length, ); return Scaffold( body: Column( children: [ Container( color: themeColor, height: 48, child: TabBar( indicatorColor: Colors.white, labelStyle:TextStyle(fontSize: 16), unselectedLabelStyle: TextStyle(fontSize: 16), controller: _tabController, tabs: _datas.map((ProjectTreeData item) { return Tab(text: item.name); }).toList(), isScrollable: true, ), ), Expanded( child: TabBarView( controller: _tabController, children: _datas.map((item) { return ProjectList(item.id); }).toList(), )) ], )); } @override void onClickErrorWidget() { showloading(); _getData(); } } class ProjectList extends StatefulWidget { final int id; ProjectList(this.id); @override _ProjectListState createState() { return new _ProjectListState(); } } class _ProjectListState extends State { List _datas = new List(); ScrollController _scrollController = ScrollController(); int _page = 1; bool showToTopBtn = false; //是否显示“返回到顶部”按钮 Future _getData() async { _page = 1; int _id = widget.id; ApiService().getProjectList((ProjectTreeListModel projectTreeListModel) { setState(() { _datas = projectTreeListModel.data.datas; }); }, _page, _id); } Future _getMore() async { _page++; int _id = widget.id; ApiService().getProjectList((ProjectTreeListModel projectTreeListModel) { setState(() { _datas.addAll(projectTreeListModel.data.datas); }); }, _page, _id); } @override void initState() { super.initState(); _getData(); _scrollController.addListener(() { if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { _getMore(); } }); _scrollController.addListener(() { //当前位置是否超过屏幕高度 if (_scrollController.offset < 200 && showToTopBtn) { setState(() { showToTopBtn = false; }); } else if (_scrollController.offset >= 200 && showToTopBtn == false) { setState(() { showToTopBtn = true; }); } }); } @override void dispose() { super.dispose(); _scrollController.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: RefreshIndicator( displacement: 15, onRefresh: _getData, child: ListView.separated( itemBuilder: _renderRow, physics: new AlwaysScrollableScrollPhysics(), separatorBuilder: (BuildContext context, int index) { return Container( height: 0.5, color: Colors.black26, ); }, controller: _scrollController, //包含加载更多 itemCount: _datas.length + 1), ), floatingActionButton: !showToTopBtn ? null : FloatingActionButton( child: Icon(Icons.arrow_upward), onPressed: () { //返回到顶部时执行动画 _scrollController.animateTo(.0, duration: Duration(milliseconds: 200), curve: Curves.ease ); } ), ); } Widget _renderRow(BuildContext context, int index) { if (index < _datas.length) { return new InkWell( onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new WebViewPage( title: _datas[index].title, url: _datas[index].link); })); }, child: Container( color: Colors.white, child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Container( padding: EdgeInsets.fromLTRB(8, 8, 8, 8), child: Row( children: [ Expanded( child: Text( _datas[index].title, maxLines: 2, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: const Color(0xFF3D4E5F), ), textAlign: TextAlign.left, ), ) ], ), ), Container( padding: EdgeInsets.fromLTRB(8, 0, 8, 8), child: Row( children: [ Expanded( child: Text( _datas[index].desc, style: TextStyle(fontSize: 12, color: Colors.grey), textAlign: TextAlign.left, maxLines: 3, ), ) ], ), ), Container( padding: EdgeInsets.fromLTRB(8, 0, 8, 8), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( _datas[index].author, style: TextStyle(fontSize: 12, color: Colors.grey), ), Text( _datas[index].niceDate, style: TextStyle(fontSize: 12, color: Colors.grey), ), ], ), ) ], ), ), Container( padding: EdgeInsets.fromLTRB(8, 16, 8, 8), child: Image.network( _datas[index].envelopePic, width: 80, height: 120, fit: BoxFit.fill, )), ], ) , ), ); } return null; } } ================================================ FILE: lib/ui/public_ui/webview_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; import 'package:wanandroid_ngu/util/theme_util.dart'; class WebViewPage extends StatefulWidget { String title; String url; WebViewPage({ Key key, @required this.title, @required this.url, }) : super(key: key); @override State createState() { return new WebViewPageState(); } } class WebViewPageState extends State { bool isLoad = true; final flutterWebviewPlugin = new FlutterWebviewPlugin(); @override void initState() { flutterWebviewPlugin.onStateChanged.listen((state) { debugPrint("state:_" + state.type.toString()); if (state.type == WebViewState.finishLoad) { setState(() { isLoad = false; }); } else if (state.type == WebViewState.startLoad) { setState(() { isLoad = true; }); } }); } // Future _requestPop() { // //相当于Android的setResult // Navigator.pop(context, "返回给上一个页面的测试数据"); // return new Future.value(false); // } @override Widget build(BuildContext context) { return WillPopScope( child: WebviewScaffold( url: widget.url, appBar: new AppBar( elevation: 0.4, title: new Text(widget.title), bottom: new PreferredSize( child: isLoad ? new LinearProgressIndicator() : new Divider(height: 1.0, color: ThemeUtils.currentColorTheme), preferredSize: const Size.fromHeight(1.0), ), ), withJavascript: true, withZoom: false, withLocalStorage: true, ), ); } } ================================================ FILE: lib/ui/publicc/publicc.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/base/_base_widget.dart'; import 'package:wanandroid_ngu/common/application.dart'; import 'package:wanandroid_ngu/event/change_theme_event.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/wx_article_content_model.dart'; import 'package:wanandroid_ngu/model/wx_article_title_model.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; import 'package:wanandroid_ngu/util/theme_util.dart'; class PubliccPage extends BaseWidget { @override BaseWidgetState getState() { return PubliccPageState(); } } class PubliccPageState extends BaseWidgetState with TickerProviderStateMixin { Color themeColor = ThemeUtils.currentColorTheme; List _datas = new List(); TabController _tabController; Future _getData() async { ApiService().getWxList((WxArticleTitleModel _articleTitleModel) { if (_articleTitleModel.errorCode == 0) { //成功 if (_articleTitleModel.data.length > 0) { //有数据 showContent(); setState(() { _datas = _articleTitleModel.data; }); } else { //数据为空 showEmpty(); } } else { Fluttertoast.showToast(msg: _articleTitleModel.errorMsg); } }, (DioError error) { //发生错误 print(error.response); showError(); }); } @override void initState() { super.initState(); setAppBarVisible(false); _getData(); Application.eventBus.on().listen((event) { setState(() { themeColor = event.color; }); }); } @override void dispose() { super.dispose(); _tabController.dispose(); super.dispose(); } @override AppBar getAppBar() { return AppBar( title: Text("不显示"), ); } @override Widget getContentWidget(BuildContext context) { _tabController = new TabController( vsync: this, length: _datas.length, ); return Scaffold( body: Column( children: [ Container( color: themeColor, height: 48, child: TabBar( indicatorColor: Colors.white, labelStyle: TextStyle(fontSize: 16), unselectedLabelStyle: TextStyle(fontSize: 16), controller: _tabController, tabs: _datas.map((WxArticleTitleData item) { return Tab(text: item.name); }).toList(), isScrollable: true, ), ), Expanded( child: TabBarView( controller: _tabController, children: _datas.map((item) { return NewsList(item.id); }).toList(), )) ], )); } @override void onClickErrorWidget() { showloading(); _getData(); } } class NewsList extends StatefulWidget { final int id; NewsList(this.id); @override _NewsListState createState() { return new _NewsListState(); } } class _NewsListState extends State { List _datas = new List(); ScrollController _scrollController = ScrollController(); int _page = 1; bool showToTopBtn = false; //是否显示“返回到顶部”按钮 Future _getData() async { _page = 1; int _id = widget.id; ApiService().getWxArticleList( (WxArticleContentModel _wxArticleContentModel) { setState(() { _datas = _wxArticleContentModel.data.datas; }); }, _id, _page); } Future _getMore() async { _page++; int _id = widget.id; ApiService().getWxArticleList((WxArticleContentModel _articleContentModel) { setState(() { _datas.addAll(_articleContentModel.data.datas); }); }, _id, _page); } @override void initState() { super.initState(); _getData(); _scrollController.addListener(() { if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { _getMore(); } }); _scrollController.addListener(() { //当前位置是否超过屏幕高度 if (_scrollController.offset < 200 && showToTopBtn) { setState(() { showToTopBtn = false; }); } else if (_scrollController.offset >= 200 && showToTopBtn == false) { setState(() { showToTopBtn = true; }); } }); } @override void dispose() { super.dispose(); _scrollController.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: RefreshIndicator( displacement: 15, onRefresh: _getData, child: ListView.separated( physics: new AlwaysScrollableScrollPhysics(), itemBuilder: _renderRow, separatorBuilder: (BuildContext context, int index) { return Container( height: 0.5, color: Colors.black26, ); }, controller: _scrollController, //包含加载更多 itemCount: _datas.length + 1), ), floatingActionButton: !showToTopBtn ? null : FloatingActionButton( child: Icon(Icons.arrow_upward), onPressed: () { //返回到顶部时执行动画 _scrollController.animateTo(.0, duration: Duration(milliseconds: 200), curve: Curves.ease); }), ); } Widget _renderRow(BuildContext context, int index) { if (index < _datas.length) { return new InkWell( onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new WebViewPage( title: _datas[index].title, url: _datas[index].link); })); }, child: Column( children: [ Container( color: Colors.white, padding: EdgeInsets.fromLTRB(16, 16, 16, 8), child: Row( children: [ Text( _datas[index].author, style: TextStyle(fontSize: 12), textAlign: TextAlign.left, ), Expanded( child: Text( _datas[index].niceDate, style: TextStyle(fontSize: 12), textAlign: TextAlign.right, ), ), ], ), ), Container( color: Colors.white, padding: EdgeInsets.fromLTRB(16, 0, 16, 0), child: Row( children: [ Expanded( child: Text( _datas[index].title, maxLines: 2, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: const Color(0xFF3D4E5F), ), textAlign: TextAlign.left, ), ) ], ), ), Container( color: Colors.white, padding: EdgeInsets.fromLTRB(16, 8, 16, 16), child: Row( children: [ Expanded( child: Text( _datas[index].superChapterName, style: TextStyle(fontSize: 12), textAlign: TextAlign.left, ), ) ], ), ), ], ), ); } return null; } } ================================================ FILE: lib/ui/search/hot_search_result.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:wanandroid_ngu/base/_base_widget.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/hotword_result_model.dart'; import 'package:wanandroid_ngu/ui/public_ui/webview_page.dart'; class HotResultPage extends BaseWidget { String hot; HotResultPage(this.hot); @override BaseWidgetState getState() { return HotResultPageState(); } } class HotResultPageState extends BaseWidgetState { List _datas = new List(); ScrollController _scrollController = ScrollController(); int _page = 0; bool showToTopBtn = false; //是否显示“返回到顶部”按钮 Future _getData() async { _page = 0; String _keyword = widget.hot; ApiService().getSearchResult((HotwordResultModel otwordResultModel) { if (otwordResultModel.errorCode == 0) { //成功 if (otwordResultModel.data.datas.length > 0) { //有数据 showContent(); setState(() { _datas.clear(); _datas.addAll(otwordResultModel.data.datas); }); } else { //数据为空 showEmpty(); } } else { Fluttertoast.showToast(msg: otwordResultModel.errorMsg); } },(DioError error) { //发生错误 print(error.response); showError(); }, _page, _keyword); } Future _getMore() async { _page++; String _keyword = widget.hot; ApiService().getSearchResult((HotwordResultModel otwordResultModel) { if (otwordResultModel.errorCode == 0) { //成功 if (otwordResultModel.data.datas.length > 0) { //有数据 showContent(); setState(() { _datas.addAll(otwordResultModel.data.datas); }); } else { //数据为空 Fluttertoast.showToast(msg: "没有更多数据了"); } } else { Fluttertoast.showToast(msg: otwordResultModel.errorMsg); } },(DioError error) { //发生错误 print(error.response); showError(); }, _page, _keyword); } @override void initState() { super.initState(); showloading(); _getData(); _scrollController.addListener(() { if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { _getMore(); } }); _scrollController.addListener(() { //当前位置是否超过屏幕高度 if (_scrollController.offset < 200 && showToTopBtn) { setState(() { showToTopBtn = false; }); } else if (_scrollController.offset >= 200 && showToTopBtn == false) { setState(() { showToTopBtn = true; }); } }); } @override void dispose() { super.dispose(); _scrollController.dispose(); } Widget _renderRow(BuildContext context, int index) { if (index < _datas.length) { return new InkWell( onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new WebViewPage( title: _datas[index] .title .replaceAll("", "") .replaceAll("<\/em>", ""), url: _datas[index].link); })); }, child: Column( children: [ Container( color: Colors.white, padding: EdgeInsets.fromLTRB(16, 16, 16, 8), child: Row( children: [ Text( _datas[index].author, style: TextStyle(fontSize: 12), textAlign: TextAlign.left, ), Expanded( child: Text( _datas[index].niceDate, style: TextStyle(fontSize: 12), textAlign: TextAlign.right, ), ), ], ), ), Container( color: Colors.white, padding: EdgeInsets.fromLTRB(16, 0, 16, 0), child: Row( children: [ Expanded( child: Text( _datas[index] .title .replaceAll("", "") .replaceAll("<\/em>", ""), maxLines: 2, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: const Color(0xFF3D4E5F), ), textAlign: TextAlign.left, ), ) ], ), ), Container( color: Colors.white, padding: EdgeInsets.fromLTRB(16, 8, 16, 16), child: Row( children: [ Expanded( child: Text( _datas[index].superChapterName, style: TextStyle(fontSize: 12), textAlign: TextAlign.left, ), ) ], ), ), ], ), ); } return null; } @override AppBar getAppBar() { return AppBar( title: Text(widget.hot), ); } @override Widget getContentWidget(BuildContext context) { return Scaffold( body: RefreshIndicator( onRefresh: _getData, child: ListView.separated( itemBuilder: _renderRow, physics: new AlwaysScrollableScrollPhysics(), separatorBuilder: (BuildContext context, int index) { return Container( height: 0.5, color: Colors.black26, ); }, controller: _scrollController, //包含加载更多 itemCount: _datas.length + 1), ), floatingActionButton: !showToTopBtn ? null : FloatingActionButton( child: Icon(Icons.arrow_upward), onPressed: () { //返回到顶部时执行动画 _scrollController.animateTo(.0, duration: Duration(milliseconds: 200), curve: Curves.ease); }), ); } @override void onClickErrorWidget() { showloading(); _getData(); } } ================================================ FILE: lib/ui/search/search.dart ================================================ import 'package:flutter/material.dart'; import 'package:wanandroid_ngu/http/api_service.dart'; import 'package:wanandroid_ngu/model/hotword_model.dart'; import 'package:wanandroid_ngu/ui/search/hot_search_result.dart'; import 'package:wanandroid_ngu/util/utils.dart'; class SearchPage extends StatefulWidget { @override State createState() { return SearchPageState(); } } class SearchPageState extends State { TextEditingController editingController; FocusNode focusNode = new FocusNode(); List actions = new List(); List _datas = new List(); String search; @override void initState() { super.initState(); editingController = new TextEditingController(text: search); editingController.addListener(() { if (editingController.text == null || editingController.text == "") { setState(() { actions = [ IconButton( icon: Icon(Icons.search), onPressed: () { changeContent(); }) ]; }); } else { setState(() { actions = [ IconButton( icon: Icon(Icons.close), onPressed: () { editingController.clear(); changeContent(); }), IconButton( icon: Icon(Icons.search), onPressed: () { changeContent(); }) ]; }); } }); _getData(); } //获取文章列表数据 Future _getData() async { ApiService().getSearchHotWord((HotwordModel hotwordModel) { setState(() { _datas = hotwordModel.data; }); }); } void changeContent() { focusNode.unfocus(); setState(() {}); if (editingController.text == null || editingController.text == "") { }else{ Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new HotResultPage(editingController.text); })); } } @override Widget build(BuildContext context) { TextField searchField = new TextField( autofocus: true, style: TextStyle(color: Colors.white), decoration: new InputDecoration( hintStyle: TextStyle(color: Colors.white), border: InputBorder.none, hintText: "搜索更多干货"), focusNode: focusNode, controller: editingController, ); return Scaffold( appBar: AppBar( title: searchField, actions: actions, ), body: buildChildren(_datas), ); } Widget buildChildren(List children) { List names = []; //先建一个数组用于存放循环生成的widget Widget content; //单独一个widg for (DataListBean item in children) { names.add(new InkWell( child: new Chip( materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, backgroundColor: Utils.getChipBgColor(item.name), label: new Text(item.name)), onTap: () { Navigator.of(context).push(new MaterialPageRoute(builder: (context) { return new HotResultPage(item.name); })); }, )); } content = Padding( padding: EdgeInsets.only(left: 20), child: Wrap( spacing: 12, runSpacing: 12, alignment: WrapAlignment.start, children: names, )); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all(15), child: Text( "热门搜索", style: TextStyle(color: const Color(0xFF5394FF), fontSize: 18), ), ), content, ], ); } } ================================================ FILE: lib/util/bubble_indication_painter.dart ================================================ import 'dart:math'; import 'package:flutter/material.dart'; class TabIndicationPainter extends CustomPainter { Paint painter; final double dxTarget; final double dxEntry; final double radius; final double dy; final PageController pageController; TabIndicationPainter( {this.dxTarget = 125.0, this.dxEntry = 25.0, this.radius = 21.0, this.dy = 25.0, this.pageController}) : super(repaint: pageController) { painter = new Paint() ..color = Color(0xFFFFFFFF) ..style = PaintingStyle.fill; } @override void paint(Canvas canvas, Size size) { final pos = pageController.position; double fullExtent = (pos.maxScrollExtent - pos.minScrollExtent + pos.viewportDimension); double pageOffset = pos.extentBefore / fullExtent; bool left2right = dxEntry < dxTarget; Offset entry = new Offset(left2right ? dxEntry: dxTarget, dy); Offset target = new Offset(left2right ? dxTarget : dxEntry, dy); Path path = new Path(); path.addArc( new Rect.fromCircle(center: entry, radius: radius), 0.5 * pi, 1 * pi); path.addRect( new Rect.fromLTRB(entry.dx, dy - radius, target.dx, dy + radius)); path.addArc( new Rect.fromCircle(center: target, radius: radius), 1.5 * pi, 1 * pi); canvas.translate(size.width * pageOffset, 0.0); canvas.drawPath(path, painter); } @override bool shouldRepaint(TabIndicationPainter oldDelegate) => true; } ================================================ FILE: lib/util/style_util.dart ================================================ import 'package:flutter/material.dart'; class StyleUtil { /** * TextStyle:封装 * colors:颜色 * fontsizes:字体大小 * isFontWeight:是否加粗 */ static TextStyle getTextStyle(Color colors,double fontsizes,bool isFontWeight){ return TextStyle( color:colors, fontSize: fontsizes, fontWeight: isFontWeight == true ? FontWeight.bold : FontWeight.normal , ); } /** * 组件加上下左右padding * w:所要加padding的组件 * all:加多少padding */ static Widget getPadding(Widget w,double all){ return Padding( child:w, padding:EdgeInsets.all(all), ); } /** * 组件选择性加padding * 这里用了位置可选命名参数{param1,param2,...}来命名参数,也调用的时候可以不传 * */ static Widget getPaddingfromLTRB(Widget w,{double l,double t,double,r,double b}){ return Padding( child:w, padding:EdgeInsets.fromLTRB(l ?? 0,t ?? 0,r ?? 0,b ?? 0), ); } } ================================================ FILE: lib/util/theme_util.dart ================================================ import 'package:flutter/material.dart'; class ThemeUtils { // 默认主题色 static const Color defaultColor =Colors.redAccent ; // 可选的主题色 static const List supportColors = [const Color(0xFF5394FF), Colors.purple, Colors.orange, Colors.deepPurpleAccent, Colors.redAccent, Colors.blue, Colors.amber, Colors.green, Colors.lime, Colors.indigo, Colors.cyan, Colors.teal]; // 当前的主题色 static Color currentColorTheme = defaultColor; } ================================================ FILE: lib/util/utils.dart ================================================ import 'package:common_utils/common_utils.dart'; import 'package:flutter/material.dart'; import 'package:lpinyin/lpinyin.dart'; import 'package:shared_preferences/shared_preferences.dart'; class Utils { static final String SP_COLOR_THEME_INDEX = "colorThemeIndex"; static String getImgPath(String name, {String format: 'png'}) { return 'assets/images/$name.$format'; } static String getPinyin(String str) { return PinyinHelper.getShortPinyin(str).substring(0, 1).toUpperCase(); } static Color getChipBgColor(String name) { String pinyin = PinyinHelper.getFirstWordPinyin(name); pinyin = pinyin.substring(0, 1).toUpperCase(); return nameToColor(pinyin); } static Color nameToColor(String name) { // assert(name.length > 1); final int hash = name.hashCode & 0xffff; final double hue = (360.0 * hash / (1 << 15)) % 360.0; return HSVColor.fromAHSV(1.0, hue, 0.4, 0.90).toColor(); } static String getTimeLine(BuildContext context, int timeMillis) { // LogUtil.e("countryCode: " + // Localizations.localeOf(context).countryCode + // " languageCode: " + // Localizations.localeOf(context).languageCode); return TimelineUtil.format(timeMillis, locale: Localizations.localeOf(context).languageCode, dayFormat: DayFormat.Common); } static double getTitleFontSize(String title) { if (ObjectUtil.isEmpty(title) || title.length < 10) { return 18.0; } int count = 0; List list = title.split(""); for (int i = 0, length = list.length; i < length; i++) { String ss = list[i]; if (RegexUtil.isZh(ss)) { count++; } } return (count >= 10 || title.length > 16) ? 14.0 : 18.0; } // 设置选择的主题色 static setColorTheme(int colorThemeIndex) async { SharedPreferences sp = await SharedPreferences.getInstance(); sp.setInt(SP_COLOR_THEME_INDEX, colorThemeIndex); } static Future getColorThemeIndex() async { SharedPreferences sp = await SharedPreferences.getInstance(); return sp.getInt(SP_COLOR_THEME_INDEX); } } ================================================ FILE: pubspec.yaml ================================================ name: wanandroid_ngu description: A new Flutter application. # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # Read more about versioning at semver.org. version: 1.0.5+5 environment: sdk: ">=2.0.0-dev.68.0 <3.0.0" dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 flutter_swiper: ^1.1.4 flutter_webview_plugin: ^0.3.0+2 dio: ^2.1.0 shared_preferences: ^0.4.3 fluttertoast: ^3.1.0 event_bus: ^1.0.3 flutter_slidable: ^0.4.9 # 汉字转拼音库 https://github.com/flutterchina/lpinyin lpinyin: ^1.0.7 # Dart 常用工具类库 https://github.com/Sky24n/common_utils common_utils: ^1.0.9 flutter_screenutil: ^0.5.0 intro_slider: ^1.2.0 share: ^0.6.0+1 # 查看图片 photo_view: ^0.2.2 #数据 sqflite: ^1.1.3 #文件读写 path_provider: ^0.5.0+1 dev_dependencies: flutter_test: sdk: flutter font_awesome_flutter: ^8.0.1 # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec # The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true assets: #加载页面图片资源 - images/loading.png - images/flutter.png - images/head.jpg - images/arrow_right.png - images/ic_error.png - images/ic_empty.png ================================================ FILE: test/widget_test.dart ================================================ // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester // utility that Flutter provides. For example, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:wanandroid_ngu/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(MyApp()); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); expect(find.text('1'), findsNothing); // Tap the '+' icon and trigger a frame. await tester.tap(find.byIcon(Icons.add)); await tester.pump(); // Verify that our counter has incremented. expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); }); }