├── .DS_Store
├── .flutter-plugins
├── .flutter-plugins-dependencies
├── .gitignore
├── .metadata
├── .packages
├── LICENSE
├── README.md
├── android
├── .DS_Store
├── .gitignore
├── app
│ ├── .DS_Store
│ ├── build.gradle
│ ├── release
│ │ ├── app-release.apk
│ │ └── output.json
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── xfhy
│ │ │ │ └── wanandroidflutter
│ │ │ │ └── MainActivity.java
│ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── mykey.jks
└── settings.gradle
├── doc
├── 1. 遇到的一些问题.md
└── TODO.md
├── images
├── ic_default_avatar.webp
├── ic_launcher.png
├── ic_launcher_foreground.png
└── ic_zone_background.webp
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Runner
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── main.m
├── lib
├── common
│ └── application.dart
├── constant
│ ├── api.dart
│ ├── app_colors.dart
│ ├── constants.dart
│ └── routes.dart
├── data
│ ├── data_utils.dart
│ ├── http_util.dart
│ └── model
│ │ ├── .DS_Store
│ │ ├── article_data_entity.dart
│ │ ├── banner_data.dart
│ │ ├── hot_key_entity.dart
│ │ ├── knowledge_entity.dart
│ │ └── login_data_entity.dart
├── demo
│ ├── bottom_navigation_bar.dart
│ ├── flutter_webview_demo.dart
│ ├── request_data.dart
│ └── sliver_app_bar.dart
├── generated
│ └── json
│ │ ├── article_data_entity_helper.dart
│ │ ├── base
│ │ ├── json_convert_content.dart
│ │ └── json_filed.dart
│ │ ├── hot_key_entity_helper.dart
│ │ ├── knowledge_entity_helper.dart
│ │ └── login_data_entity_helper.dart
├── main.dart
├── page
│ ├── about
│ │ └── about_page.dart
│ ├── favorite
│ │ └── my_favorite_page.dart
│ ├── home_list_page.dart
│ ├── item
│ │ └── article_item.dart
│ ├── knowledge
│ │ ├── knowledge_page.dart
│ │ └── knowledge_page_data.dart
│ ├── knowledge_system_tree_page.dart
│ ├── login
│ │ ├── login_event.dart
│ │ └── login_page.dart
│ ├── myinfo_page.dart
│ ├── question
│ │ └── question_page.dart
│ ├── search
│ │ ├── hot_search_widget.dart
│ │ ├── search_list_widget.dart
│ │ └── search_page.dart
│ ├── wan_android_page.dart
│ └── webview
│ │ ├── route_web_page_data.dart
│ │ └── web_view_page.dart
├── util
│ ├── log_util.dart
│ ├── shared_preferences.dart
│ └── tool_utils.dart
└── widget
│ ├── home_banner.dart
│ ├── refresh
│ └── refresh_page.dart
│ └── stroke_widget.dart
├── pic
├── image1.png
├── image2.png
├── image3.png
├── image4.png
├── image5.png
└── image6.png
├── pubspec.lock
├── pubspec.yaml
└── test
└── widget_test.dart
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/.DS_Store
--------------------------------------------------------------------------------
/.flutter-plugins:
--------------------------------------------------------------------------------
1 | # This is a generated file; do not edit or check into version control.
2 | flutter_webview_plugin=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_webview_plugin-0.3.10+1/
3 | fluttertoast=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/fluttertoast-4.0.1/
4 | path_provider=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider-1.6.5/
5 | path_provider_macos=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider_macos-0.0.4/
6 | shared_preferences=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences-0.5.6+3/
7 | shared_preferences_macos=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_macos-0.0.1+6/
8 | shared_preferences_web=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_web-0.1.2+4/
9 | url_launcher=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/url_launcher-5.4.2/
10 | url_launcher_macos=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_macos-0.0.1+4/
11 | url_launcher_web=/Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_web-0.1.1+1/
12 |
--------------------------------------------------------------------------------
/.flutter-plugins-dependencies:
--------------------------------------------------------------------------------
1 | {"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"flutter_webview_plugin","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos"]},{"name":"path_provider_macos","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_macos","shared_preferences_web"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_web","url_launcher_macos"]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]}]}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.aar
3 | *.ap_
4 | *.aab
5 |
6 | # Files for the ART/Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 | # Uncomment the following line in case you need and you don't have the release build type files in your app
17 | # release/
18 |
19 | # Gradle files
20 | .gradle/
21 | build/
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Log Files
30 | *.log
31 |
32 | # Android Studio Navigation editor temp files
33 | .navigation/
34 |
35 | # Android Studio captures folder
36 | captures/
37 |
38 | # IntelliJ
39 | *.iml
40 | .idea/
41 |
42 | .dart_tool/
43 |
44 | # Keystore files
45 | # Uncomment the following lines if you do not want to check your keystore files in.
46 | #*.jks
47 | #*.keystore
48 |
49 | # External native build folder generated in Android Studio 2.2 and later
50 | .externalNativeBuild
51 | .cxx/
52 |
53 | # Google Services (e.g. APIs or Firebase)
54 | # google-services.json
55 |
56 | # Freeline
57 | freeline.py
58 | freeline/
59 | freeline_project_description.json
60 |
61 | # fastlane
62 | fastlane/report.xml
63 | fastlane/Preview.html
64 | fastlane/screenshots
65 | fastlane/test_output
66 | fastlane/readme.md
67 |
68 | # Version control
69 | vcs.xml
70 |
71 | # lint
72 | lint/intermediates/
73 | lint/generated/
74 | lint/outputs/
75 | lint/tmp/
76 | # lint/reports/
77 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/.packages:
--------------------------------------------------------------------------------
1 | # Generated by pub on 2020-03-29 11:13:06.338022.
2 | archive:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/archive-2.0.11/lib/
3 | args:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/args-1.5.2/lib/
4 | async:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/async-2.4.0/lib/
5 | boolean_selector:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/boolean_selector-1.0.5/lib/
6 | charcode:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/charcode-1.1.2/lib/
7 | collection:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/collection-1.14.11/lib/
8 | convert:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/convert-2.1.1/lib/
9 | cookie_jar:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/cookie_jar-1.0.1/lib/
10 | crypto:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/crypto-2.1.3/lib/
11 | cupertino_icons:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/cupertino_icons-0.1.3/lib/
12 | dio:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/dio-3.0.9/lib/
13 | dio_cookie_manager:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/dio_cookie_manager-1.0.0/lib/
14 | event_bus:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/event_bus-1.1.1/lib/
15 | flutter:file:///Users/xfhy/development/flutter/packages/flutter/lib/
16 | flutter_spinkit:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_spinkit-4.1.2/lib/
17 | flutter_test:file:///Users/xfhy/development/flutter/packages/flutter_test/lib/
18 | flutter_web_plugins:file:///Users/xfhy/development/flutter/packages/flutter_web_plugins/lib/
19 | flutter_webview_plugin:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_webview_plugin-0.3.10+1/lib/
20 | fluttertoast:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/fluttertoast-4.0.1/lib/
21 | http_parser:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/http_parser-3.1.3/lib/
22 | image:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/image-2.1.4/lib/
23 | matcher:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/matcher-0.12.6/lib/
24 | meta:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/meta-1.1.8/lib/
25 | path:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/path-1.6.4/lib/
26 | path_provider:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider-1.6.5/lib/
27 | path_provider_macos:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider_macos-0.0.4/lib/
28 | path_provider_platform_interface:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/path_provider_platform_interface-1.0.1/lib/
29 | pedantic:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/pedantic-1.8.0+1/lib/
30 | petitparser:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/petitparser-2.4.0/lib/
31 | platform:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/platform-2.2.1/lib/
32 | plugin_platform_interface:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/plugin_platform_interface-1.0.2/lib/
33 | quiver:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/quiver-2.0.5/lib/
34 | shared_preferences:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences-0.5.6+3/lib/
35 | shared_preferences_macos:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_macos-0.0.1+6/lib/
36 | shared_preferences_platform_interface:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_platform_interface-1.0.3/lib/
37 | shared_preferences_web:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_web-0.1.2+4/lib/
38 | sky_engine:file:///Users/xfhy/development/flutter/bin/cache/pkg/sky_engine/lib/
39 | source_span:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/source_span-1.5.5/lib/
40 | sprintf:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/sprintf-4.0.2/lib/
41 | stack_trace:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/stack_trace-1.9.3/lib/
42 | stream_channel:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/stream_channel-2.0.0/lib/
43 | string_scanner:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/string_scanner-1.0.5/lib/
44 | term_glyph:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/term_glyph-1.1.0/lib/
45 | test_api:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/test_api-0.2.11/lib/
46 | typed_data:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/typed_data-1.1.6/lib/
47 | url_launcher:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/url_launcher-5.4.2/lib/
48 | url_launcher_macos:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_macos-0.0.1+4/lib/
49 | url_launcher_platform_interface:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_platform_interface-1.0.6/lib/
50 | url_launcher_web:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_web-0.1.1+1/lib/
51 | vector_math:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/vector_math-2.0.8/lib/
52 | xml:file:///Users/xfhy/development/flutter/.pub-cache/hosted/pub.flutter-io.cn/xml-3.5.0/lib/
53 | wanandroidflutter:lib/
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | [](https://github.com/xfhy)
4 | [](https://blog.csdn.net/xfhy_)
5 |
6 | ## 1. WanAndroid-Flutter
7 |
8 | Flutter版本 WanAndroid客户端,适合Flutter入门学习.该项目是我在学习Flutter过程中写的.
9 |
10 | ## 2. 技术点
11 |
12 | - 封装 上拉加载,下拉刷新
13 | - dio进行网络请求,统一封装get,post
14 | - 封装banner
15 | - Future
16 | - 路由,跳转界面
17 | - 事件总线 event_bus
18 | - toast
19 | - SharedPreference
20 | - ....
21 |
22 | ## 3. 项目截图
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | release 版本[试玩地址](http://d.alphaqr.com/3s7z)
34 |
35 | 
36 |
37 | ## 4. 遇到的一些问题
38 |
39 | ### 4.1 引入第三方库
40 |
41 | 1. 首先去[官网package](https://pub.dev/packages)搜索.
42 | 2. 找到相应插件,点进详情,切换到Installing tab,然后在pubspec.yaml中引入该插件.
43 | 3. 在本项目控制台,输入flutter pub get. 即引入三方库完成.
44 |
45 | ### 4.2 loading
46 |
47 | 当页面正在loading时,需要一个Widget来占位,不然Widget为空要报错.
48 |
49 | ### 4.3 运行在iOS上
50 |
51 | 1. 首先得安装Xcode(7.8G)
52 | 2. 然后安装 cocoapods `sudo gem install cocoapods`
53 | 3. 然后在ios工程下,执行`pod install`,引入那些依赖
54 | 4. 然后用AS打开ios项目里面的Info.plist,点击右上角的用Xcode打开.
55 | 5. 编辑Podfile,将顶部的`platform :ios, '9.0'` 注释放开
56 | 6. 运行到模拟器上.
57 |
58 | ### 4.4 如何快速解析json
59 |
60 | > Flutter不支持运行时反射,所以没有像Gson这样自动解析JSON的库来降低解析成本.在Flutter中解析JSON需要完全手动进行操作,麻烦.
61 |
62 | 可以在AS上装FlutterJsonBeanFactory这个插件,然后右键New->JsonToDartBeanAction,输入文件名和json数据.即可自动生成bean对象,和它所对应的解析代码.
63 |
64 | 原理是它生成了一个JsonConvert,然后这里面可以根据运行时type去选择应该解析哪一个类对象.
65 | 然后bean类在声明的时候是混入了JsonConvert的,可以直接使用JsonConvert里面的方法,完美.
66 |
67 | ### 4.5 Flutter ScrollView (滚动视图)
68 |
69 | ScrollView是一个带有滚动的视图组件,它本身由三部分组成
70 |
71 | - Scrollable - 它监听各种用户手势并实现滚动的交互设计。
72 | - Viewport - 它通过在滚动视图内仅显示一部分小部件来实现滚动的可视化设计。
73 | - Slider - 它们是可以组合以创建各种滚动效果的小部件,如列表,网格和扩展标题。
74 |
75 | Scroll是一个抽象类,通常使用CustomScrollView
76 |
77 | ```
78 | CustomScrollView(
79 | shrinkWrap: true,
80 | // 内容
81 | slivers: [
82 | new SliverPadding(
83 | padding: const EdgeInsets.all(20.0),
84 | sliver: new SliverList(
85 | delegate: new SliverChildListDelegate(
86 | [
87 | const Text('A'),
88 | const Text('B'),
89 | const Text('C'),
90 | const Text('D'),
91 | ],
92 | ),
93 | ),
94 | ),
95 | ],
96 | )
97 | ```
98 |
99 | ### 4.6 处理Text超出问题
100 |
101 | 可以放Row或Column中,用Expanded包起来,然后用maxLines控制行数,用`overflow:
102 | TextOverflow.ellipsis,`控制超出部分的展示.
103 |
104 | ### 4.7 让一个ListView支持下拉刷新
105 |
106 | 非常简单,
107 | 使用官方自带的RefreshIndicator即可,将listview放child,然后实现一个_pullToRefresh下拉刷新时调用的方法(做下拉刷新的逻辑).
108 |
109 | ```
110 | RefreshIndicator(
111 | child: listView,
112 | onRefresh: _pullToRefresh,
113 | );
114 |
115 | Future _pullToRefresh() {
116 | loadData();
117 | //这里Feature不能返回 null
118 | return Future(() => LogUtil.d("lalala"));
119 | }
120 | ```
121 |
122 | ### 4.8 获取屏幕宽度,高度
123 |
124 | ```
125 | MediaQuery.of(context).size.width,
126 | MediaQuery.of(context).size.height
127 | ```
128 |
129 | ### 4.9 封装通用标题栏
130 |
131 | 标题栏,每个界面都需要,所以封装一个,取需.
132 |
133 | ```dart
134 | ///get通用状态栏
135 | static AppBar getCommonAppBar(BuildContext context, String title, {double fontSize, List actions}) {
136 | if (title == null) {
137 | title = "";
138 | }
139 | return AppBar(
140 | leading: IconButton(
141 | icon: Icon(
142 | Icons.arrow_back,
143 | color: Colors.white,
144 | ),
145 | //点击返回
146 | onPressed: () {
147 | if (context != null) {
148 | Navigator.pop(context);
149 | }
150 | },
151 | ),
152 | title: Text(
153 | title,
154 | style: TextStyle(
155 | color: Colors.white,
156 | fontSize: fontSize == null ? 18.0 : fontSize,
157 | ),
158 | ),
159 | //标题栏居中
160 | centerTitle: true,
161 | //右边的action 按钮
162 | actions: actions == null ? [] : actions,
163 | );
164 | }
165 | ```
166 |
167 | ### 4.10 格式化String
168 |
169 | dart中格式化String,需要引入三方库`sprintf`,使用方式如下:
170 |
171 | ```dart
172 | sprintf("lg/collect/%s/json", [15615]);
173 | ```
174 |
175 | ### 4.11 获取Android/iOS本地目录
176 |
177 | 需要引入三方库`path_provider`,用于查找文件系统上的常用位置,支持Android和iOS.免得去写一原生代码,这个三方库帮我们封装好了.
178 |
179 | ```dart
180 | Directory tempDir = await getTemporaryDirectory();
181 | String tempPath = tempDir.path;
182 |
183 | Directory appDocDir = await getApplicationDocumentsDirectory();
184 | String appDocPath = appDocDir.path;
185 | ```
186 |
187 | ### 4.12 展示一个Dialog
188 |
189 | 以下方法是dart的material包下面的方法.
190 |
191 | ```dart
192 | //展示对话框
193 | showDialog(
194 | context: context,
195 | barrierDismissible: false,
196 | builder: (_) {
197 | return SpinKitFadingCircle(
198 | color: AppColors.colorPrimary,
199 | );
200 | });
201 |
202 | //取消对话框
203 | Navigator.of(context).pop();
204 | ```
205 |
206 | ### 4.13 间距的简单方式
207 |
208 | 可以用Padding和margin来实现.其实还有一种方式,可以在Column和Row中快速增加一段间距,利用SizedBox,类似Android中的Space
209 |
210 | ```dart
211 | SizedBox(width: 10.0),
212 | ```
213 |
214 | ### 4.14 收起软键盘
215 |
216 | 有时候需要在点击某些按钮时收起软键盘
217 | ```dart
218 | FocusScope.of(context).requestFocus(FocusNode());
219 | ```
220 |
221 | ### 4.15 让ListView的item点击时有水波纹效果
222 |
223 | 用InkWell把Item包起来
224 |
225 |
226 |
--------------------------------------------------------------------------------
/android/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/android/.DS_Store
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/android/app/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/android/app/.DS_Store
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
26 |
27 | android {
28 | compileSdkVersion 28
29 |
30 | lintOptions {
31 | disable 'InvalidPackage'
32 | }
33 |
34 | defaultConfig {
35 | applicationId "com.xfhy.wanandroidflutter"
36 | minSdkVersion 16
37 | targetSdkVersion 28
38 | versionCode flutterVersionCode.toInteger()
39 | versionName flutterVersionName
40 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
41 | }
42 |
43 | signingConfigs {
44 | release {
45 | keyAlias "xfhy"
46 | keyPassword "11111111"
47 | storeFile file("../mykey.jks")
48 | storePassword "11111111"
49 | }
50 | }
51 |
52 | buildTypes {
53 | release {
54 | // Signing with the debug keys for now, so `flutter run --release` works.
55 | signingConfig signingConfigs.release
56 |
57 | ndk { // 必须加入这部分,否则可能导致编译成功的release包在真机中会闪退
58 | abiFilters "armeabi-v7a"
59 | }
60 | }
61 |
62 | debug {
63 | ndk {
64 | //这里要加上,否则debug包会出问题,后面三个为可选,x86建议加上不然部分模拟器回报错
65 | abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86"
66 | }
67 | }
68 |
69 | }
70 | }
71 |
72 | flutter {
73 | source '../..'
74 | }
75 |
76 | dependencies {
77 | testImplementation 'junit:junit:4.12'
78 | androidTestImplementation 'androidx.test:runner:1.1.1'
79 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
80 | }
81 |
--------------------------------------------------------------------------------
/android/app/release/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/android/app/release/app-release.apk
--------------------------------------------------------------------------------
/android/app/release/output.json:
--------------------------------------------------------------------------------
1 | [{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
9 |
10 |
11 |
15 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/xfhy/wanandroidflutter/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.xfhy.wanandroidflutter;
2 |
3 | import androidx.annotation.NonNull;
4 | import io.flutter.embedding.android.FlutterActivity;
5 | import io.flutter.embedding.engine.FlutterEngine;
6 | import io.flutter.plugins.GeneratedPluginRegistrant;
7 |
8 | public class MainActivity extends FlutterActivity {
9 | @Override
10 | public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
11 | GeneratedPluginRegistrant.registerWith(flutterEngine);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.5.0'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/mykey.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/android/mykey.jks
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/doc/1. 遇到的一些问题.md:
--------------------------------------------------------------------------------
1 | ### 1. 引入第三方库
2 |
3 | 1. 首先去[官网package](https://pub.dev/packages)搜索.
4 | 2. 找到相应插件,点进详情,切换到Installing tab,然后在pubspec.yaml中引入该插件.
5 | 3. 在本项目控制台,输入flutter pub get. 即引入三方库完成.
6 |
7 | ### 2. loading
8 |
9 | 当页面正在loading时,需要一个Widget来占位,不然Widget为空要报错.
10 |
11 | ### 3. 运行在iOS上
12 |
13 | 1. 首先得安装Xcode(7.8G)
14 | 2. 然后安装 cocoapods `sudo gem install cocoapods`
15 | 3. 然后在ios工程下,执行`pod install`,引入那些依赖
16 | 4. 然后用AS打开ios项目里面的Info.plist,点击右上角的用Xcode打开.
17 | 5. 编辑Podfile,将顶部的`platform :ios, '9.0'` 注释放开
18 | 6. 运行到模拟器上.
19 |
20 | ### 4. 如何快速解析json
21 |
22 | > Flutter不支持运行时反射,所以没有像Gson这样自动解析JSON的库来降低解析成本.在Flutter中解析JSON需要完全手动进行操作,麻烦.
23 |
24 | 可以在AS上装FlutterJsonBeanFactory这个插件,然后右键New->JsonToDartBeanAction,输入文件名和json数据.即可自动生成bean对象,和它所对应的解析代码.
25 |
26 | 原理是它生成了一个JsonConvert,然后这里面可以根据运行时type去选择应该解析哪一个类对象.
27 | 然后bean类在声明的时候是混入了JsonConvert的,可以直接使用JsonConvert里面的方法,完美.
28 |
29 | ### 5. Flutter ScrollView (滚动视图)
30 |
31 | ScrollView是一个带有滚动的视图组件,它本身由三部分组成
32 |
33 | - Scrollable - 它监听各种用户手势并实现滚动的交互设计。
34 | - Viewport - 它通过在滚动视图内仅显示一部分小部件来实现滚动的可视化设计。
35 | - Slider - 它们是可以组合以创建各种滚动效果的小部件,如列表,网格和扩展标题。
36 |
37 | Scroll是一个抽象类,通常使用CustomScrollView
38 |
39 | ```
40 | CustomScrollView(
41 | shrinkWrap: true,
42 | // 内容
43 | slivers: [
44 | new SliverPadding(
45 | padding: const EdgeInsets.all(20.0),
46 | sliver: new SliverList(
47 | delegate: new SliverChildListDelegate(
48 | [
49 | const Text('A'),
50 | const Text('B'),
51 | const Text('C'),
52 | const Text('D'),
53 | ],
54 | ),
55 | ),
56 | ),
57 | ],
58 | )
59 | ```
60 |
61 | ### 6. 处理Text超出问题
62 |
63 | 可以放Row或Column中,用Expanded包起来,然后用maxLines控制行数,用`overflow:
64 | TextOverflow.ellipsis,`控制超出部分的展示.
65 |
66 | ### 7. 让一个ListView支持下拉刷新
67 |
68 | 非常简单,
69 | 使用官方自带的RefreshIndicator即可,将listview放child,然后实现一个_pullToRefresh下拉刷新时调用的方法(做下拉刷新的逻辑).
70 |
71 | ```
72 | RefreshIndicator(
73 | child: listView,
74 | onRefresh: _pullToRefresh,
75 | );
76 |
77 | Future _pullToRefresh() {
78 | loadData();
79 | //这里Feature不能返回 null
80 | return Future(() => LogUtil.d("lalala"));
81 | }
82 | ```
83 |
84 | ### 8. 获取屏幕宽度,高度
85 |
86 | ```
87 | MediaQuery.of(context).size.width,
88 | MediaQuery.of(context).size.height
89 | ```
90 |
91 | ### 9. 封装通用标题栏
92 |
93 | 标题栏,每个界面都需要,所以封装一个,取需.
94 |
95 | ```dart
96 | ///get通用状态栏
97 | static AppBar getCommonAppBar(BuildContext context, String title, {double fontSize, List actions}) {
98 | if (title == null) {
99 | title = "";
100 | }
101 | return AppBar(
102 | leading: IconButton(
103 | icon: Icon(
104 | Icons.arrow_back,
105 | color: Colors.white,
106 | ),
107 | //点击返回
108 | onPressed: () {
109 | if (context != null) {
110 | Navigator.pop(context);
111 | }
112 | },
113 | ),
114 | title: Text(
115 | title,
116 | style: TextStyle(
117 | color: Colors.white,
118 | fontSize: fontSize == null ? 18.0 : fontSize,
119 | ),
120 | ),
121 | //标题栏居中
122 | centerTitle: true,
123 | //右边的action 按钮
124 | actions: actions == null ? [] : actions,
125 | );
126 | }
127 | ```
128 |
129 | ### 10. 格式化String
130 |
131 | dart中格式化String,需要引入三方库`sprintf`,使用方式如下:
132 |
133 | ```dart
134 | sprintf("lg/collect/%s/json", [15615]);
135 | ```
136 |
137 | ### 11. 获取Android/iOS本地目录
138 |
139 | 需要引入三方库`path_provider`,用于查找文件系统上的常用位置,支持Android和iOS.免得去写一原生代码,这个三方库帮我们封装好了.
140 |
141 | ```dart
142 | Directory tempDir = await getTemporaryDirectory();
143 | String tempPath = tempDir.path;
144 |
145 | Directory appDocDir = await getApplicationDocumentsDirectory();
146 | String appDocPath = appDocDir.path;
147 | ```
148 |
149 | ### 12. 展示一个Dialog
150 |
151 | 以下方法是dart的material包下面的方法.
152 |
153 | ```dart
154 | //展示对话框
155 | showDialog(
156 | context: context,
157 | barrierDismissible: false,
158 | builder: (_) {
159 | return SpinKitFadingCircle(
160 | color: AppColors.colorPrimary,
161 | );
162 | });
163 |
164 | //取消对话框
165 | Navigator.of(context).pop();
166 | ```
167 |
168 | ### 13. 间距的简单方式
169 |
170 | 可以用Padding和margin来实现.其实还有一种方式,可以在Column和Row中快速增加一段间距,利用SizedBox,类似Android中的Space
171 |
172 | ```dart
173 | SizedBox(width: 10.0),
174 | ```
175 |
176 | ### 14. 收起软键盘
177 |
178 | 有时候需要在点击某些按钮时收起软键盘
179 | ```dart
180 | FocusScope.of(context).requestFocus(FocusNode());
181 | ```
182 |
183 | ### 15. 让ListView的item点击时有水波纹效果
184 |
185 | 用InkWell把Item包起来
186 |
--------------------------------------------------------------------------------
/doc/TODO.md:
--------------------------------------------------------------------------------
1 |
2 | ### 开发
3 |
4 | - 开屏页
5 |
6 | ### 其他
7 |
8 | 1. webview页面,打开一些网址会出现无法加载的情况,提供一个默认失败页面.
9 | 2. 开屏页
10 |
--------------------------------------------------------------------------------
/images/ic_default_avatar.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/images/ic_default_avatar.webp
--------------------------------------------------------------------------------
/images/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/images/ic_launcher.png
--------------------------------------------------------------------------------
/images/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/images/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/images/ic_zone_background.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/images/ic_zone_background.webp
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def parse_KV_file(file, separator='=')
14 | file_abs_path = File.expand_path(file)
15 | if !File.exists? file_abs_path
16 | return [];
17 | end
18 | generated_key_values = {}
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) do |line|
21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22 | plugin = line.split(pattern=separator)
23 | if plugin.length == 2
24 | podname = plugin[0].strip()
25 | path = plugin[1].strip()
26 | podpath = File.expand_path("#{path}", file_abs_path)
27 | generated_key_values[podname] = podpath
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | end
32 | generated_key_values
33 | end
34 |
35 | target 'Runner' do
36 | # Flutter Pod
37 |
38 | copied_flutter_dir = File.join(__dir__, 'Flutter')
39 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
40 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
41 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
42 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
43 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
44 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
45 |
46 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
47 | unless File.exist?(generated_xcode_build_settings_path)
48 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
49 | end
50 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
51 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
52 |
53 | unless File.exist?(copied_framework_path)
54 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
55 | end
56 | unless File.exist?(copied_podspec_path)
57 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
58 | end
59 | end
60 |
61 | # Keep pod path relative so it can be checked into Podfile.lock.
62 | pod 'Flutter', :path => 'Flutter'
63 |
64 | # Plugin Pods
65 |
66 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
67 | # referring to absolute paths on developers' machines.
68 | system('rm -rf .symlinks')
69 | system('mkdir -p .symlinks/plugins')
70 | plugin_pods = parse_KV_file('../.flutter-plugins')
71 | plugin_pods.each do |name, path|
72 | symlink = File.join('.symlinks', 'plugins', name)
73 | File.symlink(path, symlink)
74 | pod name, :path => File.join(symlink, 'ios')
75 | end
76 | end
77 |
78 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
79 | install! 'cocoapods', :disable_input_output_paths => true
80 |
81 | post_install do |installer|
82 | installer.pods_project.targets.each do |target|
83 | target.build_configurations.each do |config|
84 | config.build_settings['ENABLE_BITCODE'] = 'NO'
85 | end
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - flutter_webview_plugin (0.0.1):
4 | - Flutter
5 | - fluttertoast (0.0.2):
6 | - Flutter
7 | - path_provider (0.0.1):
8 | - Flutter
9 | - path_provider_macos (0.0.1):
10 | - Flutter
11 | - shared_preferences (0.0.1):
12 | - Flutter
13 | - shared_preferences_macos (0.0.1):
14 | - Flutter
15 | - shared_preferences_web (0.0.1):
16 | - Flutter
17 | - url_launcher (0.0.1):
18 | - Flutter
19 | - url_launcher_macos (0.0.1):
20 | - Flutter
21 | - url_launcher_web (0.0.1):
22 | - Flutter
23 |
24 | DEPENDENCIES:
25 | - Flutter (from `Flutter`)
26 | - flutter_webview_plugin (from `.symlinks/plugins/flutter_webview_plugin/ios`)
27 | - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
28 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
29 | - path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`)
30 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
31 | - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`)
32 | - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`)
33 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
34 | - url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`)
35 | - url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`)
36 |
37 | EXTERNAL SOURCES:
38 | Flutter:
39 | :path: Flutter
40 | flutter_webview_plugin:
41 | :path: ".symlinks/plugins/flutter_webview_plugin/ios"
42 | fluttertoast:
43 | :path: ".symlinks/plugins/fluttertoast/ios"
44 | path_provider:
45 | :path: ".symlinks/plugins/path_provider/ios"
46 | path_provider_macos:
47 | :path: ".symlinks/plugins/path_provider_macos/ios"
48 | shared_preferences:
49 | :path: ".symlinks/plugins/shared_preferences/ios"
50 | shared_preferences_macos:
51 | :path: ".symlinks/plugins/shared_preferences_macos/ios"
52 | shared_preferences_web:
53 | :path: ".symlinks/plugins/shared_preferences_web/ios"
54 | url_launcher:
55 | :path: ".symlinks/plugins/url_launcher/ios"
56 | url_launcher_macos:
57 | :path: ".symlinks/plugins/url_launcher_macos/ios"
58 | url_launcher_web:
59 | :path: ".symlinks/plugins/url_launcher_web/ios"
60 |
61 | SPEC CHECKSUMS:
62 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
63 | flutter_webview_plugin: ed9e8a6a96baf0c867e90e1bce2673913eeac694
64 | fluttertoast: b644586ef3b16f67fae9a1f8754cef6b2d6b634b
65 | path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d
66 | path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0
67 | shared_preferences: 430726339841afefe5142b9c1f50cb6bd7793e01
68 | shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087
69 | shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9
70 | url_launcher: a1c0cc845906122c4784c542523d8cacbded5626
71 | url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313
72 | url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c
73 |
74 | PODFILE CHECKSUM: 49ec7d4076524b7e225c38b98147173651ac4b9d
75 |
76 | COCOAPODS: 1.9.1
77 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #import "AppDelegate.h"
2 | #import "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 | NSAllowsArbitraryLoadsInWebContent
10 |
11 |
12 |
13 | CFBundleDevelopmentRegion
14 | $(DEVELOPMENT_LANGUAGE)
15 | CFBundleExecutable
16 | $(EXECUTABLE_NAME)
17 | CFBundleIdentifier
18 | $(PRODUCT_BUNDLE_IDENTIFIER)
19 | CFBundleInfoDictionaryVersion
20 | 6.0
21 | CFBundleName
22 | wanandroidflutter
23 | CFBundlePackageType
24 | APPL
25 | CFBundleShortVersionString
26 | $(FLUTTER_BUILD_NAME)
27 | CFBundleSignature
28 | ????
29 | CFBundleVersion
30 | $(FLUTTER_BUILD_NUMBER)
31 | LSRequiresIPhoneOS
32 |
33 | UILaunchStoryboardName
34 | LaunchScreen
35 | UIMainStoryboardFile
36 | Main
37 | UISupportedInterfaceOrientations
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationLandscapeLeft
41 | UIInterfaceOrientationLandscapeRight
42 |
43 | UISupportedInterfaceOrientations~ipad
44 |
45 | UIInterfaceOrientationPortrait
46 | UIInterfaceOrientationPortraitUpsideDown
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 | UIViewControllerBasedStatusBarAppearance
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/common/application.dart:
--------------------------------------------------------------------------------
1 | import 'package:event_bus/event_bus.dart';
2 | import 'package:wanandroidflutter/data/data_utils.dart';
3 |
4 | //设置一些环节变量 全局的变量之类的
5 | class Application {
6 | static bool isDebug = true;
7 |
8 | //事件总线
9 | static EventBus eventBus;
10 |
11 | //是否登录
12 | static bool isLogin = false;
13 |
14 | static void init() async {
15 | await dataUtils.isLogin().then((value) {
16 | isLogin = value;
17 | });
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/constant/api.dart:
--------------------------------------------------------------------------------
1 | class Api {
2 | static const String BASE_URL = "https://www.wanandroid.com/";
3 |
4 | //玩Android api https://www.wanandroid.com/blog/show/2
5 |
6 | ///首页banner
7 | static const String BANNER = "banner/json";
8 |
9 | //首页文章列表 http://www.wanandroid.com/article/list/0/json
10 | // 知识体系下的文章http://www.wanandroid.com/article/list/0/json?cid=60
11 | static const String ARTICLE_LIST = "article/list/";
12 |
13 | //置顶文章
14 | static const String ARTICLE_TO_LIST = "article/top/json";
15 |
16 | //登录
17 | static const String LOGIN = "user/login";
18 |
19 | //注册
20 | static const String REGISTER = "user/register";
21 |
22 | //退出登录
23 | static const String LOGIN_OUT = "user/logout/json";
24 |
25 | //收藏 站内文章
26 | static const String COLLECT_ARTICLE = "lg/collect/%s/json";
27 | //取消收藏文章
28 | static const String CANCEL_COLLECT_ARTICLE = "lg/uncollect_originId/%s/json";
29 | //取消收藏文章 我的收藏页
30 | static const String CANCEL_COLLECT_ARTICLE_FOR_MY_FAV = "lg/uncollect/%s/json";
31 |
32 | //收藏的文章列表
33 | static const String COLLECT_ARTICLE_LIST = "lg/collect/list/%s/json";
34 | //每日一问文章列表
35 | static const String QUESTION_ARTICLE_LIST = "wenda/list/%s/json";
36 | //知识体系
37 | static const String KNOWLEDGE_SYSTEM = "tree/json";
38 | //知识体系下面的文章
39 | static const String KNOWLEDGE_ARTICLE_LIST = "article/list/%s/json";
40 | //搜索
41 | static const String SEARCH = "article/query/%s/json";
42 | //热搜关键字
43 | static const String SEARCH_HOT_KEY = "hotkey/json";
44 |
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/lib/constant/app_colors.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | ///颜色配置
4 | class AppColors {
5 | static Color colorPrimary = const Color(0xFFFFC800);
6 | static Color accentColor = const Color(0xFFFFC800);
7 | static Color iconColor = const Color(0xFFFFC800);
8 | }
9 |
--------------------------------------------------------------------------------
/lib/constant/constants.dart:
--------------------------------------------------------------------------------
1 |
2 | ///2020年03月28日16:33:13
3 | ///常量类
4 | ///xfhy
5 |
6 | class SharedPreferencesKeys {
7 | //登录状态
8 | static const String LOGIN_STATE_KEY = "login_state_key";
9 | //登录用户名
10 | static const String LOGIN_USERNAME_KEY = "login_username_key";
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/lib/constant/routes.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:wanandroidflutter/page/about/about_page.dart';
3 | import 'package:wanandroidflutter/page/favorite/my_favorite_page.dart';
4 | import 'package:wanandroidflutter/page/knowledge/knowledge_page.dart';
5 | import 'package:wanandroidflutter/page/login/login_page.dart';
6 | import 'package:wanandroidflutter/page/question/question_page.dart';
7 | import 'package:wanandroidflutter/page/search/search_list_widget.dart';
8 | import 'package:wanandroidflutter/page/search/search_page.dart';
9 | import 'package:wanandroidflutter/page/webview/web_view_page.dart';
10 |
11 | ///路由
12 | ///2020年03月22日12:44:43
13 | ///xfhy
14 |
15 | class Routes {
16 | static String root = "/";
17 |
18 | //webview
19 | static String webViewPage = '/web_view_page';
20 |
21 | //知识体系 作者文章列表
22 | static String knowledgePage = '/knowledge_page';
23 |
24 | //登录界面
25 | static String loginPage = '/login_page';
26 |
27 | //搜索页面
28 | static String searchPage = '/search_page';
29 |
30 | //搜索结果页面 真正在干搜索这事儿的页面
31 | static String searchResultPage = '/search_result_page';
32 |
33 | //收藏界面
34 | static String favoritePage = '/favorite_page';
35 |
36 | //每日一问
37 | static String questionPage = '/question_page';
38 |
39 | //关于
40 | static String aboutPage = '/about_page';
41 |
42 | static Map routes = {};
43 |
44 | static void init() {
45 | routes[webViewPage] = (context) => WebViewPage();
46 | routes[knowledgePage] = (context) => KnowledgePage();
47 | routes[loginPage] = (context) => LoginPage();
48 | routes[searchPage] = (context) => SearchPage();
49 | routes[searchResultPage] = (context) => SearchResultWidget();
50 | routes[favoritePage] = (context) => FavoritePage();
51 | routes[questionPage] = (context) => QuestionPage();
52 | routes[aboutPage] = (context) => AboutUsPage();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/data/data_utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:sprintf/sprintf.dart';
4 | import 'package:wanandroidflutter/common/application.dart';
5 | import 'package:wanandroidflutter/constant/api.dart';
6 | import 'package:wanandroidflutter/constant/constants.dart';
7 | import 'package:wanandroidflutter/data/http_util.dart';
8 | import 'package:wanandroidflutter/data/model/banner_data.dart';
9 | import 'package:wanandroidflutter/data/model/hot_key_entity.dart';
10 | import 'package:wanandroidflutter/util/log_util.dart';
11 | import 'package:wanandroidflutter/util/shared_preferences.dart';
12 |
13 | import 'model/article_data_entity.dart';
14 | import 'model/knowledge_entity.dart';
15 | import 'model/login_data_entity.dart';
16 |
17 | ///数据获取帮助类
18 | ///2020年03月21日15:16:55
19 | ///xfhy
20 | ///dart 单例: 使用static变量+工厂构造函数的方式,可以保证new DataUtils始终返回都是同一个实例
21 |
22 | DataUtils dataUtils = DataUtils();
23 |
24 | class DataUtils {
25 | //私有构造函数
26 | DataUtils._internal();
27 |
28 | //保存单例
29 | static DataUtils _singleton = new DataUtils._internal();
30 |
31 | //工厂构造函数
32 | //当实现一个使用 factory 关键词修饰的构造函数时,这个构造函数不必创建类的新实例。
33 | //当实现构造函数但是不想每次都创建该类的一个实例的时候使用
34 | factory DataUtils() => _singleton;
35 |
36 | ///首页数据模块
37 | //获取首页banner数据
38 | //在Future一个函数内,加了async的,会同步执行的.先等前面的执行完再执行后面的.
39 | Future> getBannerData() async {
40 | //首先从服务端获取最外层的json数据的data
41 | List datas = await httpUtils.get(Api.BANNER);
42 | //然后将data(list)解析成一个一个的BannerData对象,然后组装成list
43 | return datas == null ? null : datas.map((item) => BannerData.fromJson(item)).toList();
44 | }
45 |
46 | ///首页数据模块
47 | //获取首页最新文章数据
48 | Future getArticleData(int pageIndex) async {
49 | //首先从服务端获取最外层的json数据的data
50 | var datas = await httpUtils.get(Api.ARTICLE_LIST + "$pageIndex/json");
51 | return datas == null ? null : ArticleDataEntity().fromJson(datas);
52 | }
53 |
54 | ///获取首页置顶文章数据
55 | Future> getTopArticleData() async {
56 | List datas = await httpUtils.get(Api.ARTICLE_TO_LIST);
57 | return datas == null ? null : datas.map((item) => ArticleData().fromJson(item)).toList();
58 | }
59 |
60 | // 按照作者昵称搜索文章(点击文章作者头像)
61 | Future getAuthorArticleData(String author, int pageIndex) async {
62 | String path = 'article/list/$pageIndex/json';
63 | Map params = {"author": author};
64 | var datas = await httpUtils.get(path, params: params);
65 | return datas == null ? null : ArticleDataEntity().fromJson(datas);
66 | }
67 |
68 | // 获取分享人的列表数据
69 | Future getShareAuthorArticleData(int userId, int pageIndex) async {
70 | String path = 'user/$userId/share_articles/$pageIndex/json';
71 | var datas = await httpUtils.get(path);
72 | var articleData = datas['shareArticles'];
73 | return articleData == null ? null : ArticleDataEntity().fromJson(articleData);
74 | }
75 |
76 | //登录
77 | Future login(String userName, String password, BuildContext context) async {
78 | FormData formData = FormData.fromMap({"username": userName, "password": password});
79 | var data = await httpUtils.post(Api.LOGIN, formData: formData, isAddLoading: true, context: context, loadingText: "正在登录...");
80 | //登录失败,则为null
81 | LogUtil.d(data);
82 | if (data != null) {
83 | Application.isLogin = true;
84 | }
85 | return data == null ? null : LoginDataEntity().fromJson(data);
86 | }
87 |
88 | //注册
89 | Future register(String userName, String password, BuildContext context) async {
90 | FormData formData = FormData.fromMap({"username": userName, "password": password, "repassword": password});
91 | var data = await httpUtils.post(Api.REGISTER, formData: formData, isAddLoading: true, context: context, loadingText: "正在注册并登录...");
92 | //登录失败,则为null
93 | LogUtil.d(data);
94 | if (data != null) {
95 | Application.isLogin = true;
96 | }
97 | return data == null ? null : LoginDataEntity().fromJson(data);
98 | }
99 |
100 | //退出登录
101 | Future loginOut() async {
102 | var data = await httpUtils.get(Api.LOGIN_OUT);
103 | //LogUtil.d(data);
104 | //return data == null ? null : LoginDataEntity().fromJson(data);
105 | Application.isLogin = false;
106 | dataUtils.setLoginUserName("");
107 | return data;
108 | }
109 |
110 | ///收藏文章 articleId:文章id
111 | Future collectArticle(int articleId) async {
112 | //https://www.wanandroid.com/lg/collect/1165/json
113 | //格式化语法 使用了一个三方库才能格式化 print(sprintf("%s %s", ["Hello", "World"]));
114 | var data = await httpUtils.post(sprintf(Api.COLLECT_ARTICLE, [articleId]));
115 | //LogUtil.d(data);
116 | return data;
117 | }
118 |
119 | //取消收藏文章
120 | Future cancelCollectArticle(int articleId) async {
121 | var data = await httpUtils.post(sprintf(Api.CANCEL_COLLECT_ARTICLE, [articleId]));
122 | //LogUtil.d(data);
123 | return data;
124 | }
125 |
126 | //取消收藏文章 我的收藏页
127 | Future cancelCollectArticleForMyFavoritePage(int articleId, String originId) async {
128 | FormData formData = FormData.fromMap({"originId": originId});
129 | var data = await httpUtils.post(sprintf(Api.CANCEL_COLLECT_ARTICLE_FOR_MY_FAV, [articleId]), formData: formData);
130 | //LogUtil.d(data);
131 | return data;
132 | }
133 |
134 | ///获取收藏文章列表
135 | Future getCollectArticles(int pageIndex) async {
136 | var data = await httpUtils.get(sprintf(Api.COLLECT_ARTICLE_LIST, [pageIndex]));
137 | //LogUtil.d(data);
138 | return data == null ? null : ArticleDataEntity().fromJson(data);
139 | }
140 |
141 | ///每日一问文章列表
142 | Future getQuestionArticles(int pageIndex) async {
143 | var data = await httpUtils.get(sprintf(Api.QUESTION_ARTICLE_LIST, [pageIndex]));
144 | //LogUtil.d(data);
145 | return data == null ? null : ArticleDataEntity().fromJson(data);
146 | }
147 |
148 | //知识体系下的文章
149 | Future getKnowledgeArticleData(int cid, int pageIndex) async {
150 | Map params = {"cid": cid};
151 | var data = await httpUtils.get(sprintf(Api.KNOWLEDGE_ARTICLE_LIST, [pageIndex]), params: params);
152 | return data == null ? null : ArticleDataEntity().fromJson(data);
153 | }
154 |
155 | //搜索
156 | Future search(String key, int pageIndex, BuildContext context) async {
157 | FormData formData = FormData.fromMap({"k": key});
158 | var data =
159 | await httpUtils.post(sprintf(Api.SEARCH, [pageIndex]), formData: formData, isAddLoading: false, loadingText: "搜索中...", context: context);
160 | return data == null ? null : ArticleDataEntity().fromJson(data);
161 | }
162 |
163 | ///热搜关键词
164 | Future> getSearchHotKeys() async {
165 | List data = await httpUtils.get(Api.SEARCH_HOT_KEY);
166 | return data == null ? null : data.map((item) => HotKeyEntity().fromJson(item)).toList();
167 | }
168 |
169 | ///知识体系
170 | Future> getKnowledgeSystem() async {
171 | List data = await httpUtils.get(Api.KNOWLEDGE_SYSTEM);
172 | return data == null ? null : data.map((item) => KnowledgeEntity().fromJson(item)).toList();
173 | }
174 |
175 | //--------------sp--------------
176 |
177 | //设置登录状态
178 | Future setLoginState(bool isLogin) async {
179 | return await spUtil.putBool(SharedPreferencesKeys.LOGIN_STATE_KEY, isLogin);
180 | }
181 |
182 | ///当前是否已经登录
183 | Future isLogin() async {
184 | return await spUtil.getBool(SharedPreferencesKeys.LOGIN_STATE_KEY);
185 | }
186 |
187 | //设置登录用户名
188 | Future setLoginUserName(String username) async {
189 | return await spUtil.putString(SharedPreferencesKeys.LOGIN_USERNAME_KEY, username);
190 | }
191 |
192 | ///清除用户名信息
193 | Future clearUserName() async {
194 | return await spUtil.remove(SharedPreferencesKeys.LOGIN_USERNAME_KEY);
195 | }
196 |
197 | //获取登录用户名
198 | Future getUserName() async {
199 | return await spUtil.getString(SharedPreferencesKeys.LOGIN_USERNAME_KEY);
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/lib/data/http_util.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:cookie_jar/cookie_jar.dart';
4 | import 'package:dio/dio.dart';
5 | import 'package:dio_cookie_manager/dio_cookie_manager.dart';
6 | import 'package:flutter/material.dart';
7 | import 'package:path_provider/path_provider.dart';
8 | import 'package:wanandroidflutter/constant/api.dart';
9 | import 'package:wanandroidflutter/util/log_util.dart';
10 | import 'package:wanandroidflutter/util/tool_utils.dart';
11 |
12 | /*
13 | 通用格式
14 | {
15 | "data":{},
16 | "errorCode":0,
17 | "errorMsg":""
18 | }
19 | * */
20 |
21 | HttpUtils httpUtils = HttpUtils();
22 |
23 | ///http请求封装
24 | class HttpUtils {
25 | HttpUtils._internal() {
26 | if (null == _dio) {
27 | _dio = Dio();
28 | //dio 也是单例,设置baseUrl等一些配置
29 | _dio.options.baseUrl = Api.BASE_URL;
30 | _dio.options.connectTimeout = 30 * 1000;
31 | _dio.options.sendTimeout = 30 * 1000;
32 | _dio.options.receiveTimeout = 30 * 1000;
33 | }
34 | }
35 |
36 | static HttpUtils _singleton = HttpUtils._internal();
37 |
38 | factory HttpUtils() => _singleton;
39 |
40 | Dio _dio;
41 |
42 | Future get(String url, {Map params, bool isAddLoading = false, BuildContext context, String loadingText}) async {
43 | Response response;
44 |
45 | //path_provider 负责查找 iOS/Android 的目录文件,IO 模块负责对文件进行读写。 获取文档目录的路径
46 | Directory documentsDir = await getApplicationDocumentsDirectory();
47 | String documentsPath = documentsDir.path;
48 | //新建目录
49 | var dir = Directory("$documentsPath/cookies");
50 | await dir.create();
51 |
52 | //LogUtil.d("文档目录path = ${documentsPath}");
53 |
54 | //添加cookie
55 | _dio.interceptors.add(CookieManager(PersistCookieJar(dir: dir.path, ignoreExpires: true)));
56 |
57 | //loading
58 | if (isAddLoading) {
59 | ToolUtils.showLoading(context, loadingText);
60 | }
61 |
62 | try {
63 | if (params != null) {
64 | response = await _dio.get(url, queryParameters: params);
65 | } else {
66 | response = await _dio.get(url);
67 | }
68 |
69 | //隐藏loading
70 | ToolUtils.disMissLoadingDialog(isAddLoading, context);
71 |
72 | if (response.data['errorCode'] == 0) {
73 | //这里直接把data部分给搞出来,免得每次在外面去解析˛
74 | return response.data['data'];
75 | } else {
76 | String data = response.data["errorMsg"];
77 | ToolUtils.showToast(msg: data);
78 | LogUtil.d("请求网络错误 : $data");
79 | }
80 | } on DioError catch (e) {
81 | if (e.response != null) {
82 | LogUtil.d(e.response.headers.toString());
83 | LogUtil.d(e.response.request.toString());
84 | } else {
85 | LogUtil.d(e.request.toString());
86 | }
87 |
88 | //ToolUtils.showToast(msg: handleError(e));
89 | ToolUtils.disMissLoadingDialog(isAddLoading, context);
90 | return null;
91 | }
92 | }
93 |
94 | ///post请求
95 | ///url : 地址
96 | ///formData : 请求参数
97 | Future post(String url,
98 | {FormData formData, Map queryParameters, bool isAddLoading = false, BuildContext context, String loadingText}) async {
99 | Response response;
100 |
101 | Directory documentsDir = await getApplicationDocumentsDirectory();
102 | String documentsPath = documentsDir.path;
103 | var dir = Directory("$documentsPath/cookies");
104 | await dir.create();
105 |
106 | //cookie
107 | _dio.interceptors.add(CookieManager(PersistCookieJar(dir: dir.path)));
108 |
109 | //loading
110 | if (isAddLoading) {
111 | ToolUtils.showLoading(context, loadingText);
112 | }
113 |
114 | try {
115 | if (formData != null) {
116 | response = await _dio.post(url, data: formData);
117 | } else if (queryParameters != null) {
118 | response = await _dio.post(url, queryParameters: queryParameters);
119 | } else {
120 | response = await _dio.post(url);
121 | }
122 |
123 | //隐藏loading
124 | ToolUtils.disMissLoadingDialog(isAddLoading, context);
125 |
126 | //json 数据
127 | //LogUtil.d(response.toString());
128 |
129 | if (response.data['errorCode'] == 0) {
130 | //这里直接把data部分给搞出来,免得每次在外面去解析˛
131 | return response.data['data'];
132 | } else {
133 | String data = response.data["errorMsg"];
134 | ToolUtils.showToast(msg: data);
135 | LogUtil.d("请求网络错误 : $data");
136 | }
137 | } on DioError catch (e) {
138 | if (e.response != null) {
139 | LogUtil.d(e.response.headers.toString());
140 | LogUtil.d(e.response.request.toString());
141 | } else {
142 | LogUtil.d(e.request.toString());
143 | }
144 |
145 | //ToolUtils.showToast(msg: handleError(e));
146 | ToolUtils.disMissLoadingDialog(isAddLoading, context);
147 | return null;
148 | }
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/lib/data/model/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xfhy/WanAndroid-Flutter/b119e15cd5342a45dc1e2e246856e655ee757ea1/lib/data/model/.DS_Store
--------------------------------------------------------------------------------
/lib/data/model/article_data_entity.dart:
--------------------------------------------------------------------------------
1 | import 'package:wanandroidflutter/generated/json/base/json_convert_content.dart';
2 |
3 | ///文章数据
4 | ///mixin 混入 可以重复代码,这里ArticleDataEntity可以有JsonConvert种的方法
5 | class ArticleDataEntity with JsonConvert {
6 | int curPage;
7 | List datas;
8 | int offset;
9 | bool over;
10 | int pageCount;
11 | int size;
12 | int total;
13 | }
14 |
15 | class ArticleData with JsonConvert {
16 | String apkLink;
17 | int audit;
18 | String author;
19 | bool canEdit;
20 | int chapterId;
21 | String chapterName;
22 | bool collect;
23 | int courseId;
24 | String desc;
25 | String descMd;
26 | String envelopePic;
27 | bool fresh;
28 | int id;
29 | String link;
30 | String niceDate;
31 | String niceShareDate;
32 | String origin;
33 | String originId;
34 | String prefix;
35 | String projectLink;
36 | int publishTime;
37 | int selfVisible;
38 | int shareDate;
39 | String shareUser;
40 | int superChapterId;
41 | String superChapterName;
42 | List tags;
43 | String title;
44 | ///type=1 是置顶数据
45 | int type;
46 | int userId;
47 | int visible;
48 | int zan;
49 |
50 | @override
51 | String toString() {
52 | return 'ArticleData{apkLink: $apkLink, audit: $audit, author: $author, canEdit: $canEdit, chapterId: $chapterId, chapterName: $chapterName, collect: $collect, courseId: $courseId, desc: $desc, descMd: $descMd, envelopePic: $envelopePic, fresh: $fresh, id: $id, link: $link, niceDate: $niceDate, niceShareDate: $niceShareDate, origin: $origin, prefix: $prefix, projectLink: $projectLink, publishTime: $publishTime, selfVisible: $selfVisible, shareDate: $shareDate, shareUser: $shareUser, superChapterId: $superChapterId, superChapterName: $superChapterName, tags: $tags, title: $title, type: $type, userId: $userId, visible: $visible, zan: $zan}';
53 | }
54 |
55 | }
56 |
57 | class ArticleTags with JsonConvert {
58 | String name;
59 | String url;
60 | }
61 |
--------------------------------------------------------------------------------
/lib/data/model/banner_data.dart:
--------------------------------------------------------------------------------
1 | /**
2 | * {
3 | "desc": "Android高级进阶直播课免费学习",
4 | "id": 23,
5 | "imagePath": "https://wanandroid.com/blogimgs/d9a6f718-5011-429c-8dd5-273f02f3bf25.jpeg",
6 | "isVisible": 1,
7 | "order": 0,
8 | "title": "Android高级进阶直播课免费学习",
9 | "type": 0,
10 | "url": "https://url.163.com/4bj"
11 | },
12 | */
13 |
14 | ///Banner数据
15 | class BannerData {
16 | String desc;
17 | int id;
18 | String imagePath;
19 | int isVisible;
20 | int order;
21 | String title;
22 | int type;
23 | String url;
24 |
25 | BannerData(
26 | {this.desc,
27 | this.id,
28 | this.imagePath,
29 | this.isVisible,
30 | this.order,
31 | this.title,
32 | this.type,
33 | this.url});
34 |
35 | ///入参是待解析的json map
36 | factory BannerData.fromJson(Map parsedJson) {
37 | return BannerData(
38 | desc: parsedJson['desc'],
39 | id: parsedJson['id'],
40 | imagePath: parsedJson['imagePath'],
41 | isVisible: parsedJson['isVisible'],
42 | order: parsedJson['order'],
43 | title: parsedJson['title'],
44 | type: parsedJson['type'],
45 | url: parsedJson['url'],
46 | );
47 | }
48 |
49 | @override
50 | String toString() {
51 | return 'BannerData{desc: $desc, id: $id, imagePath: $imagePath, isVisible: $isVisible, order: $order, title: $title, type: $type, url: $url}';
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/lib/data/model/hot_key_entity.dart:
--------------------------------------------------------------------------------
1 | import 'package:wanandroidflutter/generated/json/base/json_convert_content.dart';
2 |
3 | ///热搜关键词
4 | ///2020年03月29日15:44:54
5 | ///xfhy
6 | class HotKeyEntity with JsonConvert {
7 | int id;
8 | String link;
9 | String name;
10 | int order;
11 | int visible;
12 | }
13 |
--------------------------------------------------------------------------------
/lib/data/model/knowledge_entity.dart:
--------------------------------------------------------------------------------
1 | import 'package:wanandroidflutter/generated/json/base/json_convert_content.dart';
2 |
3 | ///知识体系
4 | class KnowledgeEntity with JsonConvert {
5 | List children;
6 | int courseId;
7 | int id;
8 | String name;
9 | int order;
10 | int parentChapterId;
11 | bool userControlSetTop;
12 | int visible;
13 | }
14 |
15 | class KnowledgeChild with JsonConvert {
16 | List children;
17 | int courseId;
18 | int id;
19 | String name;
20 | int order;
21 | int parentChapterId;
22 | bool userControlSetTop;
23 | int visible;
24 | }
25 |
--------------------------------------------------------------------------------
/lib/data/model/login_data_entity.dart:
--------------------------------------------------------------------------------
1 | import 'package:wanandroidflutter/generated/json/base/json_convert_content.dart';
2 |
3 | class LoginDataEntity with JsonConvert {
4 | bool admin;
5 | List chapterTops;
6 | List collectIds;
7 | String email;
8 | String icon;
9 | int id;
10 | String nickname;
11 | String password;
12 | String publicName;
13 | String token;
14 | int type;
15 | String username;
16 | }
17 |
--------------------------------------------------------------------------------
/lib/demo/bottom_navigation_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:wanandroidflutter/constant/app_colors.dart';
4 |
5 | class BottomNavigationBarWidget extends StatefulWidget {
6 | @override //一般是需要下划线开头,然后后面加一个State
7 | State createState() => _BottomNavigationBarWidgetState();
8 | }
9 |
10 | class _BottomNavigationBarWidgetState extends State {
11 | var currentPage = 0;
12 | PageController _pageController;
13 | final appBarTitles = ['首页', '发现', '我的'];
14 |
15 | @override
16 | void initState() {
17 | super.initState();
18 | _pageController = PageController();
19 | }
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return MaterialApp(
24 | home: Scaffold(
25 | appBar: AppBar(
26 | title: Text(
27 | appBarTitles[currentPage],
28 | style: TextStyle(color: Colors.white),
29 | ),
30 | ),
31 | body: getBody(),
32 | ),
33 | );
34 | }
35 |
36 | getBody() {
37 | return Column(
38 | children: [
39 | //上面把空间占满
40 | Expanded(
41 | //PageView类似于Android中的ViewPager
42 | child: PageView(
43 | children: [
44 | Container(
45 | color: Colors.deepOrange,
46 | ),
47 | Container(
48 | color: Colors.yellow,
49 | ),
50 | Container(
51 | color: Colors.blue,
52 | ),
53 | ],
54 | //设置controller,可以控制PageView的当前页
55 | controller: _pageController,
56 | //滑动的那种控制,
57 | // BouncingScrollPhysics是用来适用于
58 | // 允许滚动偏移超出内容范围,然后将内容反弹到那些范围边缘的环境的滚动物理。iOS上经常有这种效果
59 | physics: BouncingScrollPhysics(),
60 | onPageChanged: (page) {
61 | setState(() {
62 | currentPage = page;
63 | });
64 | },
65 | ),
66 | ),
67 | //下面的bottomNavigationBar
68 | BottomNavigationBar(
69 | items: [
70 | BottomNavigationBarItem(
71 | icon: Icon(Icons.toys),
72 | title: Text('toys'),
73 | ),
74 | BottomNavigationBarItem(
75 | icon: Icon(Icons.tap_and_play),
76 | title: Text("play"),
77 | ),
78 | BottomNavigationBarItem(
79 | icon: Icon(Icons.landscape),
80 | title: Text("landscape"),
81 | ),
82 | ],
83 | onTap: (page) {
84 | //滑动到相应页面 curve是动画效果
85 | _pageController.animateToPage(page,
86 | duration: Duration(milliseconds: 300), curve: Curves.easeIn);
87 | },
88 | currentIndex: currentPage,
89 | ),
90 | ],
91 | );
92 | }
93 | }
94 |
95 | /*class BottomNavigationDemo extends StatelessWidget {
96 | final appBarTitles = ['首页', '发现', '我的'];
97 |
98 | @override
99 | Widget build(BuildContext context) {
100 | return MaterialApp(
101 | theme: ThemeData(
102 | primaryColor: AppColors.colorPrimary, accentColor: Colors.blue),
103 | home: Scaffold(
104 | appBar: AppBar(
105 | title: Text(
106 | '首页',
107 | style: TextStyle(color: Colors.white),
108 | ),
109 | ),
110 | bottomNavigationBar: BottomNavigationBar(
111 | items: [
112 | BottomNavigationBarItem(
113 | icon: const Icon(Icons.home),
114 | title: Text(appBarTitles[0]),
115 | backgroundColor: Colors.blue,
116 | ),
117 | BottomNavigationBarItem(
118 | icon: const Icon(Icons.widgets),
119 | title: Text(appBarTitles[1]),
120 | backgroundColor: Colors.blue,
121 | ),
122 | BottomNavigationBarItem(
123 | icon: const Icon(Icons.person),
124 | title: Text(appBarTitles[2]),
125 | backgroundColor: Colors.blue,
126 | ),
127 | ],
128 | ),
129 | ),
130 | );
131 | }
132 | }*/
133 |
--------------------------------------------------------------------------------
/lib/demo/flutter_webview_demo.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
3 |
4 | void main() => runApp(MyApp());
5 |
6 | class MyApp extends StatelessWidget {
7 | @override
8 | Widget build(BuildContext context) {
9 | return MaterialApp(
10 | title: 'Flutter WebView Demo',
11 | routes: {
12 | '/widget': (context) => WebViewPage(),
13 | },
14 | home: HomeWidget(),
15 | );
16 | }
17 | }
18 |
19 | class HomeWidget extends StatelessWidget {
20 | @override
21 | Widget build(BuildContext context) {
22 | return Scaffold(
23 | body: Center(
24 | child: RaisedButton(
25 | child: Text('跳转网页'),
26 | onPressed: () {
27 | //命名路由 且 传递参数
28 | Navigator.pushNamed(context, '/widget',
29 | arguments: WebData("https://www.baidu.com", false));
30 | },
31 | ),
32 | ),
33 | );
34 | }
35 | }
36 |
37 | class WebData {
38 | String url;
39 | bool isLiked;
40 |
41 | WebData(this.url, this.isLiked);
42 | }
43 |
44 | class WebViewPage extends StatelessWidget {
45 | @override
46 | Widget build(BuildContext context) {
47 | //通过RouteSettings 获取传递过来的参数
48 | WebData webData = ModalRoute.of(context).settings.arguments as WebData;
49 | return new WebviewScaffold(
50 | url: webData.url,
51 | appBar: new AppBar(
52 | title: const Text('Widget webview'),
53 | ),
54 | withZoom: true,
55 | withLocalStorage: true,
56 | hidden: true,
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/lib/demo/request_data.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:sprintf/sprintf.dart';
3 | import 'package:wanandroidflutter/data/data_utils.dart';
4 | import 'package:wanandroidflutter/data/model/article_data_entity.dart';
5 | import 'package:wanandroidflutter/util/log_util.dart';
6 |
7 | void main() => runApp(RequestDemo());
8 |
9 | class RequestDemo extends StatelessWidget {
10 | @override
11 | Widget build(BuildContext context) {
12 | return MaterialApp(
13 | home: Scaffold(
14 | body: CustomScrollView(
15 | shrinkWrap: true,
16 | slivers: [
17 | new SliverPadding(
18 | padding: EdgeInsets.all(20.0),
19 | sliver: new SliverList(
20 | delegate: new SliverChildListDelegate([
21 | RaisedButton(
22 | child: Text('获取最新文章'),
23 | onPressed: () {
24 | dataUtils.getArticleData(0);
25 | },
26 | ),
27 | RaisedButton(
28 | child: Text('获取置顶文章'),
29 | onPressed: () {
30 | dataUtils.getTopArticleData();
31 | },
32 | ),
33 | RaisedButton(
34 | child: Text('获取置顶文章和正常文章'),
35 | onPressed: () {
36 | getTopAndArticleList();
37 | },
38 | ),
39 | RaisedButton(
40 | child: Text('搜索作者文章'),
41 | onPressed: () {
42 | dataUtils.getAuthorArticleData("扔物线", 0);
43 | },
44 | ),
45 | RaisedButton(
46 | child: Text('分享人列表数据'),
47 | onPressed: () {
48 | dataUtils.getShareAuthorArticleData(2, 0);
49 | },
50 | ),
51 | RaisedButton(
52 | child: Text('登录'),
53 | onPressed: () {
54 | dataUtils.login("xxxxxxx415456465465", "xxxxxxx", context);
55 | },
56 | ),
57 | RaisedButton(
58 | child: Text('注册'),
59 | onPressed: () {
60 | dataUtils.register("xxxxxxx415456465465qqqqq", "xxxxxxx", context);
61 | },
62 | ),
63 | RaisedButton(
64 | child: Text('退出登录'),
65 | onPressed: () {
66 | dataUtils.loginOut();
67 | },
68 | ),
69 | RaisedButton(
70 | child: Text('收藏文章'),
71 | onPressed: () {
72 | LogUtil.d(sprintf("lg/collect/%s/json", [15615]));
73 | dataUtils.collectArticle(12424);
74 | },
75 | ),
76 | RaisedButton(
77 | child: Text('取消收藏文章'),
78 | onPressed: () {
79 | dataUtils.cancelCollectArticle(12424);
80 | },
81 | ),
82 | RaisedButton(
83 | child: Text('收藏的文章列表'),
84 | onPressed: () {
85 | //LogUtil.d(sprintf("lg/collect/%s/json", [15615]));
86 | dataUtils.getCollectArticles(0);
87 | },
88 | ),
89 | RaisedButton(
90 | child: Text('请求知识体系'),
91 | onPressed: () {
92 | dataUtils.getKnowledgeArticleData(60, 0);
93 | },
94 | ),
95 | RaisedButton(
96 | child: Text('搜索'),
97 | onPressed: () {
98 | dataUtils.search("控件", 0, context);
99 | },
100 | ),
101 | RaisedButton(
102 | child: Text('热搜关键词'),
103 | onPressed: () {
104 | dataUtils.getSearchHotKeys();
105 | },
106 | ),
107 | RaisedButton(
108 | child: Text('知识体系'),
109 | onPressed: () {
110 | dataUtils.getKnowledgeSystem();
111 | },
112 | ),
113 | const Text('C'),
114 | const Text('D'),
115 | ]),
116 | ),
117 | )
118 | ],
119 | ),
120 | ),
121 | );
122 | }
123 |
124 | void getTopAndArticleList() async {
125 | await Future.wait([dataUtils.getTopArticleData(), dataUtils.getArticleData(0)]).then((List listData) {
126 | //需要将顶部数据List 和 正常文章数据ArticleDataEntity中的datas进行合并,组成一个新的List
127 | List articleDataList = [];
128 | for (var value in listData) {
129 | if (value is List) {
130 | articleDataList.addAll(value);
131 | } else if (value is ArticleDataEntity) {
132 | articleDataList.addAll(value.datas);
133 | }
134 | }
135 | LogUtil.d("合并数据成功了");
136 | });
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/lib/demo/sliver_app_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | ///SliverAppBar 效果
4 | ///2020年03月28日08:00:19
5 | ///xfhy
6 |
7 | void main() => runApp(MySliverApp());
8 |
9 | class MySliverApp extends StatefulWidget {
10 | @override
11 | State createState() {
12 | return _MySliverAppState();
13 | }
14 | }
15 |
16 | class _MySliverAppState extends State {
17 | @override
18 | Widget build(BuildContext context) {
19 | return MaterialApp(
20 | home: Scaffold(
21 | body: CustomScrollView(
22 | slivers: [
23 | SliverAppBar(
24 | expandedHeight: 230.0,
25 | floating: false,
26 | pinned: true,
27 | snap: false,
28 | //滑动时 标题上移效果
29 | flexibleSpace: FlexibleSpaceBar(
30 | title: Text('标题标题标题'),
31 | centerTitle: true,
32 | collapseMode: CollapseMode.pin,
33 | //背景图
34 | background: Image.asset(
35 | "images/ic_zone_background.webp",
36 | fit: BoxFit.cover,
37 | ),
38 | ),
39 | //返回按钮
40 | leading: IconButton(
41 | icon: Icon(Icons.arrow_back),
42 | onPressed: () {},
43 | ),
44 | //右边按钮区域
45 | actions: [
46 | IconButton(
47 | icon: Icon(Icons.add),
48 | onPressed: () {
49 | print("添加");
50 | },
51 | ),
52 | IconButton(
53 | icon: Icon(Icons.more_horiz),
54 | onPressed: () {
55 | print("更多");
56 | },
57 | ),
58 | ],
59 | ),
60 | SliverFixedExtentList(
61 | itemExtent: 50.0,
62 | delegate: SliverChildBuilderDelegate(
63 | (context, index) => ListTile(
64 | title: Text("Item $index"),
65 | ),
66 | childCount: 88,
67 | ),
68 | ),
69 | ],
70 | ),
71 | ),
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/generated/json/article_data_entity_helper.dart:
--------------------------------------------------------------------------------
1 | import 'package:wanandroidflutter/data/model/article_data_entity.dart';
2 |
3 | articleDataEntityFromJson(ArticleDataEntity data, Map json) {
4 | if (json['curPage'] != null) {
5 | data.curPage = json['curPage']?.toInt();
6 | }
7 | if (json['datas'] != null) {
8 | data.datas = new List();
9 | (json['datas'] as List).forEach((v) {
10 | data.datas.add(new ArticleData().fromJson(v));
11 | });
12 | }
13 | if (json['offset'] != null) {
14 | data.offset = json['offset']?.toInt();
15 | }
16 | if (json['over'] != null) {
17 | data.over = json['over'];
18 | }
19 | if (json['pageCount'] != null) {
20 | data.pageCount = json['pageCount']?.toInt();
21 | }
22 | if (json['size'] != null) {
23 | data.size = json['size']?.toInt();
24 | }
25 | if (json['total'] != null) {
26 | data.total = json['total']?.toInt();
27 | }
28 | return data;
29 | }
30 |
31 | Map articleDataEntityToJson(ArticleDataEntity entity) {
32 | final Map data = new Map();
33 | data['curPage'] = entity.curPage;
34 | if (entity.datas != null) {
35 | data['datas'] = entity.datas.map((v) => v.toJson()).toList();
36 | }
37 | data['offset'] = entity.offset;
38 | data['over'] = entity.over;
39 | data['pageCount'] = entity.pageCount;
40 | data['size'] = entity.size;
41 | data['total'] = entity.total;
42 | return data;
43 | }
44 |
45 | articleDataFromJson(ArticleData data, Map json) {
46 | if (json['apkLink'] != null) {
47 | data.apkLink = json['apkLink']?.toString();
48 | }
49 | if (json['audit'] != null) {
50 | data.audit = json['audit']?.toInt();
51 | }
52 | if (json['author'] != null) {
53 | data.author = json['author']?.toString();
54 | }
55 | if (json['canEdit'] != null) {
56 | data.canEdit = json['canEdit'];
57 | }
58 | if (json['chapterId'] != null) {
59 | data.chapterId = json['chapterId']?.toInt();
60 | }
61 | if (json['chapterName'] != null) {
62 | data.chapterName = json['chapterName']?.toString();
63 | }
64 | if (json['collect'] != null) {
65 | data.collect = json['collect'];
66 | }
67 | if (json['courseId'] != null) {
68 | data.courseId = json['courseId']?.toInt();
69 | }
70 | if (json['desc'] != null) {
71 | data.desc = json['desc']?.toString();
72 | }
73 | if (json['descMd'] != null) {
74 | data.descMd = json['descMd']?.toString();
75 | }
76 | if (json['envelopePic'] != null) {
77 | data.envelopePic = json['envelopePic']?.toString();
78 | }
79 | if (json['fresh'] != null) {
80 | data.fresh = json['fresh'];
81 | }
82 | if (json['id'] != null) {
83 | data.id = json['id']?.toInt();
84 | }
85 | if (json['link'] != null) {
86 | data.link = json['link']?.toString();
87 | }
88 | if (json['niceDate'] != null) {
89 | data.niceDate = json['niceDate']?.toString();
90 | }
91 | if (json['niceShareDate'] != null) {
92 | data.niceShareDate = json['niceShareDate']?.toString();
93 | }
94 | if (json['origin'] != null) {
95 | data.origin = json['origin']?.toString();
96 | }
97 | if (json['originId'] != null) {
98 | data.origin = json['originId']?.toString();
99 | }
100 | if (json['prefix'] != null) {
101 | data.prefix = json['prefix']?.toString();
102 | }
103 | if (json['projectLink'] != null) {
104 | data.projectLink = json['projectLink']?.toString();
105 | }
106 | if (json['publishTime'] != null) {
107 | data.publishTime = json['publishTime']?.toInt();
108 | }
109 | if (json['selfVisible'] != null) {
110 | data.selfVisible = json['selfVisible']?.toInt();
111 | }
112 | if (json['shareDate'] != null) {
113 | data.shareDate = json['shareDate']?.toInt();
114 | }
115 | if (json['shareUser'] != null) {
116 | data.shareUser = json['shareUser']?.toString();
117 | }
118 | if (json['superChapterId'] != null) {
119 | data.superChapterId = json['superChapterId']?.toInt();
120 | }
121 | if (json['superChapterName'] != null) {
122 | data.superChapterName = json['superChapterName']?.toString();
123 | }
124 | if (json['tags'] != null) {
125 | data.tags = new List();
126 | (json['tags'] as List).forEach((v) {
127 | data.tags.add(new ArticleTags().fromJson(v));
128 | });
129 | }
130 | if (json['title'] != null) {
131 | data.title = json['title']?.toString();
132 | }
133 | if (json['type'] != null) {
134 | data.type = json['type']?.toInt();
135 | }
136 | if (json['userId'] != null) {
137 | data.userId = json['userId']?.toInt();
138 | }
139 | if (json['visible'] != null) {
140 | data.visible = json['visible']?.toInt();
141 | }
142 | if (json['zan'] != null) {
143 | data.zan = json['zan']?.toInt();
144 | }
145 | return data;
146 | }
147 |
148 | Map articleDataToJson(ArticleData entity) {
149 | final Map data = new Map();
150 | data['apkLink'] = entity.apkLink;
151 | data['audit'] = entity.audit;
152 | data['author'] = entity.author;
153 | data['canEdit'] = entity.canEdit;
154 | data['chapterId'] = entity.chapterId;
155 | data['chapterName'] = entity.chapterName;
156 | data['collect'] = entity.collect;
157 | data['courseId'] = entity.courseId;
158 | data['desc'] = entity.desc;
159 | data['descMd'] = entity.descMd;
160 | data['envelopePic'] = entity.envelopePic;
161 | data['fresh'] = entity.fresh;
162 | data['id'] = entity.id;
163 | data['link'] = entity.link;
164 | data['niceDate'] = entity.niceDate;
165 | data['niceShareDate'] = entity.niceShareDate;
166 | data['origin'] = entity.origin;
167 | data['originId'] = entity.originId;
168 | data['prefix'] = entity.prefix;
169 | data['projectLink'] = entity.projectLink;
170 | data['publishTime'] = entity.publishTime;
171 | data['selfVisible'] = entity.selfVisible;
172 | data['shareDate'] = entity.shareDate;
173 | data['shareUser'] = entity.shareUser;
174 | data['superChapterId'] = entity.superChapterId;
175 | data['superChapterName'] = entity.superChapterName;
176 | if (entity.tags != null) {
177 | data['tags'] = entity.tags.map((v) => v.toJson()).toList();
178 | }
179 | data['title'] = entity.title;
180 | data['type'] = entity.type;
181 | data['userId'] = entity.userId;
182 | data['visible'] = entity.visible;
183 | data['zan'] = entity.zan;
184 | return data;
185 | }
186 |
187 | articleTagsFromJson(ArticleTags data, Map json) {
188 | if (json['name'] != null) {
189 | data.name = json['name']?.toString();
190 | }
191 | if (json['url'] != null) {
192 | data.url = json['url']?.toString();
193 | }
194 | return data;
195 | }
196 |
197 | Map articleTagsToJson(ArticleTags entity) {
198 | final Map data = new Map();
199 | data['name'] = entity.name;
200 | data['url'] = entity.url;
201 | return data;
202 | }
--------------------------------------------------------------------------------
/lib/generated/json/base/json_convert_content.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: non_constant_identifier_names
2 | // ignore_for_file: camel_case_types
3 | // ignore_for_file: prefer_single_quotes
4 |
5 | // This file is automatically generated. DO NOT EDIT, all your changes would be lost.
6 | import 'package:wanandroidflutter/data/model/login_data_entity.dart';
7 | import 'package:wanandroidflutter/generated/json/login_data_entity_helper.dart';
8 | import 'package:wanandroidflutter/data/model/hot_key_entity.dart';
9 | import 'package:wanandroidflutter/generated/json/hot_key_entity_helper.dart';
10 | import 'package:wanandroidflutter/data/model/article_data_entity.dart';
11 | import 'package:wanandroidflutter/generated/json/article_data_entity_helper.dart';
12 | import 'package:wanandroidflutter/data/model/knowledge_entity.dart';
13 | import 'package:wanandroidflutter/generated/json/knowledge_entity_helper.dart';
14 |
15 | class JsonConvert {
16 | T fromJson(Map json) {
17 | return _getFromJson(runtimeType, this, json);
18 | }
19 |
20 | Map toJson() {
21 | return _getToJson(runtimeType, this);
22 | }
23 |
24 | static _getFromJson(Type type, data, json) {
25 | switch (type) { case LoginDataEntity:
26 | return loginDataEntityFromJson(data as LoginDataEntity, json) as T; case HotKeyEntity:
27 | return hotKeyEntityFromJson(data as HotKeyEntity, json) as T; case ArticleDataEntity:
28 | return articleDataEntityFromJson(data as ArticleDataEntity, json) as T; case ArticleData:
29 | return articleDataFromJson(data as ArticleData, json) as T; case ArticleTags:
30 | return articleTagsFromJson(data as ArticleTags, json) as T; case KnowledgeEntity:
31 | return knowledgeEntityFromJson(data as KnowledgeEntity, json) as T; case KnowledgeChild:
32 | return knowledgechildFromJson(data as KnowledgeChild, json) as T; }
33 | return data as T;
34 | }
35 |
36 | static _getToJson(Type type, data) {
37 | switch (type) { case LoginDataEntity:
38 | return loginDataEntityToJson(data as LoginDataEntity); case HotKeyEntity:
39 | return hotKeyEntityToJson(data as HotKeyEntity); case ArticleDataEntity:
40 | return articleDataEntityToJson(data as ArticleDataEntity); case ArticleData:
41 | return articleDataToJson(data as ArticleData); case ArticleTags:
42 | return articleTagsToJson(data as ArticleTags); case KnowledgeEntity:
43 | return knowledgeEntityToJson(data as KnowledgeEntity); case KnowledgeChild:
44 | return knowledgechildToJson(data as KnowledgeChild); }
45 | return data as T;
46 | }
47 | //Go back to a single instance by type
48 | static _fromJsonSingle(String type, json) {
49 | switch (type) { case 'LoginDataEntity':
50 | return LoginDataEntity().fromJson(json); case 'HotKeyEntity':
51 | return HotKeyEntity().fromJson(json); case 'ArticleDataEntity':
52 | return ArticleDataEntity().fromJson(json); case 'ArticleData':
53 | return ArticleData().fromJson(json); case 'ArticleTags':
54 | return ArticleTags().fromJson(json); case 'KnowledgeEntity':
55 | return KnowledgeEntity().fromJson(json); case 'Knowledgechild':
56 | return KnowledgeChild().fromJson(json); }
57 | return null;
58 | }
59 |
60 | //empty list is returned by type
61 | static _getListFromType(String type) {
62 | switch (type) { case 'LoginDataEntity':
63 | return List(); case 'HotKeyEntity':
64 | return List(); case 'ArticleDataEntity':
65 | return List(); case 'ArticleData':
66 | return List(); case 'ArticleTags':
67 | return List(); case 'KnowledgeEntity':
68 | return List(); case 'Knowledgechild':
69 | return List(); }
70 | return null;
71 | }
72 |
73 | static M fromJsonAsT(json) {
74 | String type = M.toString();
75 | if (json is List && type.contains("List<")) {
76 | String itemType = type.substring(5, type.length - 1);
77 | List tempList = _getListFromType(itemType);
78 | json.forEach((itemJson) {
79 | tempList
80 | .add(_fromJsonSingle(type.substring(5, type.length - 1), itemJson));
81 | });
82 | return tempList as M;
83 | } else {
84 | return _fromJsonSingle(M.toString(), json) as M;
85 | }
86 | }
87 | }
--------------------------------------------------------------------------------
/lib/generated/json/base/json_filed.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: non_constant_identifier_names
2 | // ignore_for_file: camel_case_types
3 | // ignore_for_file: prefer_single_quotes
4 |
5 | // This file is automatically generated. DO NOT EDIT, all your changes would be lost.
6 |
7 | class JSONField {
8 | //Specify the parse field name
9 | final String name;
10 |
11 | //Specify the time resolution format
12 | final String format;
13 |
14 | //Whether to participate in toJson
15 | final bool serialize;
16 |
17 | //Whether to participate in fromMap
18 | final bool deserialize;
19 |
20 | const JSONField({this.name, this.format, this.serialize, this.deserialize});
21 | }
22 |
--------------------------------------------------------------------------------
/lib/generated/json/hot_key_entity_helper.dart:
--------------------------------------------------------------------------------
1 | import 'package:wanandroidflutter/data/model/hot_key_entity.dart';
2 |
3 | hotKeyEntityFromJson(HotKeyEntity data, Map json) {
4 | if (json['id'] != null) {
5 | data.id = json['id']?.toInt();
6 | }
7 | if (json['link'] != null) {
8 | data.link = json['link']?.toString();
9 | }
10 | if (json['name'] != null) {
11 | data.name = json['name']?.toString();
12 | }
13 | if (json['order'] != null) {
14 | data.order = json['order']?.toInt();
15 | }
16 | if (json['visible'] != null) {
17 | data.visible = json['visible']?.toInt();
18 | }
19 | return data;
20 | }
21 |
22 | Map hotKeyEntityToJson(HotKeyEntity entity) {
23 | final Map data = new Map();
24 | data['id'] = entity.id;
25 | data['link'] = entity.link;
26 | data['name'] = entity.name;
27 | data['order'] = entity.order;
28 | data['visible'] = entity.visible;
29 | return data;
30 | }
--------------------------------------------------------------------------------
/lib/generated/json/knowledge_entity_helper.dart:
--------------------------------------------------------------------------------
1 | import 'package:wanandroidflutter/data/model/knowledge_entity.dart';
2 |
3 | knowledgeEntityFromJson(KnowledgeEntity data, Map json) {
4 | if (json['children'] != null) {
5 | data.children = new List();
6 | (json['children'] as List).forEach((v) {
7 | data.children.add(new KnowledgeChild().fromJson(v));
8 | });
9 | }
10 | if (json['courseId'] != null) {
11 | data.courseId = json['courseId']?.toInt();
12 | }
13 | if (json['id'] != null) {
14 | data.id = json['id']?.toInt();
15 | }
16 | if (json['name'] != null) {
17 | data.name = json['name']?.toString();
18 | }
19 | if (json['order'] != null) {
20 | data.order = json['order']?.toInt();
21 | }
22 | if (json['parentChapterId'] != null) {
23 | data.parentChapterId = json['parentChapterId']?.toInt();
24 | }
25 | if (json['userControlSetTop'] != null) {
26 | data.userControlSetTop = json['userControlSetTop'];
27 | }
28 | if (json['visible'] != null) {
29 | data.visible = json['visible']?.toInt();
30 | }
31 | return data;
32 | }
33 |
34 | Map knowledgeEntityToJson(KnowledgeEntity entity) {
35 | final Map data = new Map();
36 | if (entity.children != null) {
37 | data['children'] = entity.children.map((v) => v.toJson()).toList();
38 | }
39 | data['courseId'] = entity.courseId;
40 | data['id'] = entity.id;
41 | data['name'] = entity.name;
42 | data['order'] = entity.order;
43 | data['parentChapterId'] = entity.parentChapterId;
44 | data['userControlSetTop'] = entity.userControlSetTop;
45 | data['visible'] = entity.visible;
46 | return data;
47 | }
48 |
49 | knowledgechildFromJson(KnowledgeChild data, Map json) {
50 | if (json['children'] != null) {
51 | data.children = new List();
52 | data.children.addAll(json['children']);
53 | }
54 | if (json['courseId'] != null) {
55 | data.courseId = json['courseId']?.toInt();
56 | }
57 | if (json['id'] != null) {
58 | data.id = json['id']?.toInt();
59 | }
60 | if (json['name'] != null) {
61 | data.name = json['name']?.toString();
62 | }
63 | if (json['order'] != null) {
64 | data.order = json['order']?.toInt();
65 | }
66 | if (json['parentChapterId'] != null) {
67 | data.parentChapterId = json['parentChapterId']?.toInt();
68 | }
69 | if (json['userControlSetTop'] != null) {
70 | data.userControlSetTop = json['userControlSetTop'];
71 | }
72 | if (json['visible'] != null) {
73 | data.visible = json['visible']?.toInt();
74 | }
75 | return data;
76 | }
77 |
78 | Map knowledgechildToJson(KnowledgeChild entity) {
79 | final Map data = new Map();
80 | if (entity.children != null) {
81 | data['children'] = [];
82 | }
83 | data['courseId'] = entity.courseId;
84 | data['id'] = entity.id;
85 | data['name'] = entity.name;
86 | data['order'] = entity.order;
87 | data['parentChapterId'] = entity.parentChapterId;
88 | data['userControlSetTop'] = entity.userControlSetTop;
89 | data['visible'] = entity.visible;
90 | return data;
91 | }
--------------------------------------------------------------------------------
/lib/generated/json/login_data_entity_helper.dart:
--------------------------------------------------------------------------------
1 | import 'package:wanandroidflutter/data/model/login_data_entity.dart';
2 |
3 | loginDataEntityFromJson(LoginDataEntity data, Map json) {
4 | if (json['admin'] != null) {
5 | data.admin = json['admin'];
6 | }
7 | if (json['chapterTops'] != null) {
8 | data.chapterTops = new List();
9 | data.chapterTops.addAll(json['chapterTops']);
10 | }
11 | if (json['collectIds'] != null) {
12 | data.collectIds = json['collectIds']?.map((v) => v?.toInt())?.toList()?.cast();
13 | }
14 | if (json['email'] != null) {
15 | data.email = json['email']?.toString();
16 | }
17 | if (json['icon'] != null) {
18 | data.icon = json['icon']?.toString();
19 | }
20 | if (json['id'] != null) {
21 | data.id = json['id']?.toInt();
22 | }
23 | if (json['nickname'] != null) {
24 | data.nickname = json['nickname']?.toString();
25 | }
26 | if (json['password'] != null) {
27 | data.password = json['password']?.toString();
28 | }
29 | if (json['publicName'] != null) {
30 | data.publicName = json['publicName']?.toString();
31 | }
32 | if (json['token'] != null) {
33 | data.token = json['token']?.toString();
34 | }
35 | if (json['type'] != null) {
36 | data.type = json['type']?.toInt();
37 | }
38 | if (json['username'] != null) {
39 | data.username = json['username']?.toString();
40 | }
41 | return data;
42 | }
43 |
44 | Map loginDataEntityToJson(LoginDataEntity entity) {
45 | final Map data = new Map();
46 | data['admin'] = entity.admin;
47 | if (entity.chapterTops != null) {
48 | data['chapterTops'] = [];
49 | }
50 | data['collectIds'] = entity.collectIds;
51 | data['email'] = entity.email;
52 | data['icon'] = entity.icon;
53 | data['id'] = entity.id;
54 | data['nickname'] = entity.nickname;
55 | data['password'] = entity.password;
56 | data['publicName'] = entity.publicName;
57 | data['token'] = entity.token;
58 | data['type'] = entity.type;
59 | data['username'] = entity.username;
60 | return data;
61 | }
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/services.dart';
5 | import 'package:wanandroidflutter/page/wan_android_page.dart';
6 |
7 | void main() async {
8 | if (Platform.isAndroid) {
9 | // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,
10 | // 是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。
11 | SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent);
12 | SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
13 | }
14 | runApp(WanAndroidApp());
15 | }
16 |
--------------------------------------------------------------------------------
/lib/page/about/about_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:url_launcher/url_launcher.dart';
3 | import 'package:wanandroidflutter/constant/app_colors.dart';
4 | import 'package:wanandroidflutter/util/tool_utils.dart';
5 |
6 | ///2020年04月03日21:18:12
7 | ///关于作者
8 | ///xfhy
9 |
10 | class AboutUsPage extends StatelessWidget {
11 | @override
12 | Widget build(BuildContext context) {
13 | return Scaffold(
14 | appBar: ToolUtils.getCommonAppBar(context, "关于作者"),
15 | body: ListView(
16 | children: [
17 | //头像
18 | buildAvatar(),
19 | buildAboutItem("GitHub地址", "这个项目是我在学习Flutter之后,写的练手项目.功能还是比较完善,基本把WanAndroid核心功能都实现了", "https://github.com/xfhy/WanAndroid-Flutter"),
20 | buildAboutItem("CSDN", "一名Android菜鸟的进阶之路", "https://blog.csdn.net/xfhy_"),
21 | buildAboutItem("掘金", "一名Android菜鸟", "https://juejin.im/user/5983fc6b6fb9a03c5539c8bb"),
22 | ],
23 | ),
24 | );
25 | }
26 |
27 | ///构建头像
28 | Widget buildAvatar() {
29 | return Center(
30 | child: Container(
31 | margin: EdgeInsets.only(top: 10, bottom: 10),
32 | width: 200,
33 | height: 200,
34 | child: Image.network("https://i.loli.net/2018/11/09/5be4f534dd326.jpg"),
35 | ),
36 | );
37 | }
38 |
39 | buildAboutItem(String title, String content, String url) {
40 | return InkWell(
41 | child: Padding(
42 | padding: EdgeInsets.all(15.0),
43 | child: Row(
44 | children: [
45 | Expanded(
46 | child: Column(
47 | crossAxisAlignment: CrossAxisAlignment.start,
48 | children: [
49 | Text(
50 | title,
51 | style: TextStyle(color: Colors.black),
52 | ),
53 | Text(
54 | content,
55 | style: TextStyle(color: Colors.black54, fontSize: 13.0),
56 | ),
57 | ],
58 | ),
59 | ),
60 | Icon(
61 | Icons.chevron_right,
62 | color: AppColors.colorPrimary,
63 | ),
64 | ],
65 | ),
66 | ),
67 | onTap: () async {
68 | ///用系统浏览器打开
69 | if (await canLaunch(url)) {
70 | await launch(url);
71 | } else {
72 | ToolUtils.showToast(msg: "打开浏览器失败");
73 | }
74 | },
75 | );
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/lib/page/favorite/my_favorite_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:wanandroidflutter/data/data_utils.dart';
3 | import 'package:wanandroidflutter/data/model/article_data_entity.dart';
4 | import 'package:wanandroidflutter/page/item/article_item.dart';
5 | import 'package:wanandroidflutter/util/log_util.dart';
6 | import 'package:wanandroidflutter/util/tool_utils.dart';
7 | import 'package:wanandroidflutter/widget/refresh/refresh_page.dart';
8 |
9 | ///2020年04月03日20:20:41
10 | ///我的收藏
11 | ///xfhy
12 |
13 | class FavoritePage extends StatefulWidget {
14 | @override
15 | State createState() {
16 | return _FavoritePageState();
17 | }
18 | }
19 |
20 | class _FavoritePageState extends State with AutomaticKeepAliveClientMixin {
21 | @override
22 | Widget build(BuildContext context) {
23 | super.build(context);
24 | return Scaffold(
25 | appBar: ToolUtils.getCommonAppBar(context, "我的收藏"),
26 | body: RefreshPage(
27 | requestApi: _getArticleData,
28 | renderItem: _buildArticleItem,
29 | ),
30 | );
31 | }
32 |
33 | Future