[
70 | Image.asset('assets/images/logo.jpg', width: ZFit().setWidth(70), height: ZFit().setWidth(90)),
71 | Padding(
72 | padding: EdgeInsets.only(top: ZFit().setWidth(15), bottom: ZFit().setWidth(40)),
73 | child: Text(
74 | '互联网金融平台',
75 | style: TextStyle(color: Color(0xFFb3b3b3)),
76 | ),
77 | ),
78 | TextField(
79 | autofocus: false,
80 | keyboardType: TextInputType.numberWithOptions(),
81 | decoration: InputDecoration(
82 | labelText: "手机号",
83 | hintText: "请输入11位手机号",
84 | prefixIcon: Icon(Icons.phone_iphone)
85 | ),
86 | onChanged: (val) {
87 | _checkPhoneNum(val);
88 | },
89 | ),
90 | Padding(
91 | padding: EdgeInsets.only(top: ZFit().setWidth(25)),
92 | child: SizedBox(
93 | width: ZFit().setWidth(335),
94 | height: ZFit().setWidth(40),
95 | child: FlatButton(
96 | child: Text("下一步"),
97 | color: ZColor.thinBlue,
98 | textColor: Colors.white,
99 | disabledColor: ZColor.grey,
100 | disabledTextColor: ZColor.black ,
101 | onPressed: _submitLogin()
102 | ),
103 | )
104 | )
105 | ],
106 | )
107 | ),
108 | );
109 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter-App
2 |
3 |
4 |
5 | 
6 |
7 | [](https://github.com/zhongmeizhi/fultter-example-app) [](https://github.com/zhongmeizhi/fultter-example-app) [](https://github.com/zhongmeizhi/fultter-example-app) [](https://github.com/zhongmeizhi/fultter-example-app)
8 |
9 |
10 |
11 | ### 项目介绍
12 |
13 | > 一个功能完整齐全的Bloc模式Flutter App项目。更关注架构的SPA应用。
14 |
15 | 项目更关注整体架构,以`SPA`方式完成全局`Loading`,全局`Toast`,全局`命名路由动画`,参数传递等功能。以`Bloc`方式实现状态管理,一键换肤等功能。实现了屏幕适配,可自定义全局Loading的请求封装,分离开发、测试、生产环境,WebView自然也一定要有咯。项目大部分都使用Flutter原生API来完成。使用少量原生插件。喜欢请Star,尽量别 Fork。
16 |
17 | APP强更提示:
18 | * 虚拟机似乎不支持强更,需要用真机试
19 |
20 |
21 | ### 项目预览
22 | |||||
23 | |:--:|:--:|:--:|:--:|
24 | ||||
25 | |||||
26 |
27 |
28 |
29 | ### 项目计划
30 | * [x] ZFit 屏幕适配
31 | * [x] RouteSetting + 路由数据回传
32 | * [x] 自定义App桌面 图标 + 名称
33 | * [x] 无限轮播图
34 | * [x] EventBus
35 | * [x] koa2 + node 后台服务器
36 | * [x] 封装请求
37 | * [x] Storage 保持登录状态
38 | * [x] 解决页面切换重绘问题
39 | * [x] webview
40 | * [x] 下拉刷新 + 上拉加载
41 | * [x] keepa-live && 缓存Widget
42 | * [x] 搜索功能
43 | * [x] App强制更新
44 | * [x] 拖动式排序
45 | * [x] BLoC模式 实现状态管理
46 | * [x] 一键换肤
47 | * [x] 重写Flutter部分类
48 | * [x] 全局Toast + 全局 Dialog
49 | * [x] 全局 命名路由动画
50 | * [x] 实现 SPA (单页面应用)
51 | * [x] 环境分离
52 | * [x] 元数据(由于flutter不支持反射,End)
53 | * [ ] Bloc模式完善
54 | * [ ] node架构完善
55 |
56 |
57 |
58 | ### 目录结构
59 |
60 | 主目录:
61 | * assets:静态文件
62 | * back-end:mock数据
63 |
64 |
65 | lib目录:
66 | * config:配置文件
67 | * domain:实体类
68 | * bloc:逻辑模块
69 | * page:页面
70 | * plugin:独立组件/插件
71 | * routes:路由
72 | * service:接口封装 + API地址
73 | * styles: 常用样式类
74 | * utils:工具类
75 | * view:可复用Widget
76 |
77 | 主要管理文件
78 | * `service.dart` :请求管理
79 | * `manager_page.dart` :单页管理
80 |
81 | ### Node 后台:
82 | 1. 安装`node.js`
83 | 2. cd 到项目`back-end`目录下
84 | 3. 控制台运行`npm i`
85 | 4. 控制台运行`node server.js`
86 | 5. 启动服务端成功
87 | 6. tip:记得先要修改`config`文件下的 baseUrl
88 | 7. tip:如果要启动node的负载均衡/热重载请使用[PM2](https://www.npmjs.com/package/pm2)
89 |
90 | 附: 如果是本地调试,baseUrl请使用`IP + 端口`
91 |
92 |
93 |
94 | End 附:
95 |
96 | * BLoC模式
97 | * 不使用setState就能刷新页面
98 | * 在多个页面中共享状态。
99 |
100 |
101 |
102 |
103 | [Flutter API文档](https://flutter.io/docs/get-started/codelab)
104 |
--------------------------------------------------------------------------------
/lib/page/treasure/selection/bank_selection_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:zmz_app/compose/compose.dart';
2 | import 'package:zmz_app/view/bank_product.dart';
3 | // 请求
4 | import 'package:zmz_app/service/api.dart';
5 | // storage
6 | import 'package:zmz_app/utils/storage.dart';
7 | // 参数
8 | import 'package:zmz_app/domain/route_argument.dart';
9 |
10 | class BankSelectionPage extends StatefulWidget {
11 | final item;
12 | BankSelectionPage({Key key, this.item}) : super(key: key);
13 |
14 | @override
15 | _BankSelectionState createState() => _BankSelectionState();
16 |
17 | }
18 |
19 | class _BankSelectionState extends State
20 | with AutomaticKeepAliveClientMixin{
21 |
22 | @override
23 | bool get wantKeepAlive => true;
24 |
25 | List _bankProductList = [];
26 |
27 | void getBankProduct() async {
28 | List data = await Api.getBankProductList();
29 | if (!mounted) return;
30 | setState(() {
31 | // Unhandled exception: setState() called after dispose()
32 | if (!mounted) {
33 | return;
34 | }
35 | _bankProductList = data;
36 | });
37 | }
38 |
39 | void _intoChoicenessDetail({id}) {
40 | bool isLogin = LocalStorage.getString('phone') == null;
41 | if (isLogin) {
42 | print('已登陆');
43 | } else {
44 | Navigator.pushNamed(context, "/login", arguments: RouteArguments('想从银行精选登陆'));
45 | }
46 | }
47 |
48 | @override
49 | void initState() {
50 | getBankProduct();
51 | super.initState();
52 | }
53 |
54 | // 会提示 被 @mustCallSuper 重写后面在调用这个重写方法
55 | @override
56 | Widget build(BuildContext context) {
57 | super.build(context);
58 | return ListView(
59 | children: _itemsWidget(bankProductList: _bankProductList, intoChoicenessDetail: _intoChoicenessDetail),
60 | );
61 | }
62 |
63 | }
64 |
65 | // 如果在setSate时items不会重新渲染
66 | // 可以看看Flutter的Diff算法。
67 | List _itemsWidget({@required bankProductList, @required intoChoicenessDetail}) {
68 |
69 | List items = [];
70 | final int _len = bankProductList.length;
71 |
72 | for (int i = 0; i < _len; i++) {
73 | Map bank = bankProductList[i];
74 | List productList = bank['productList'];
75 |
76 | // 银行名称
77 | items.add(
78 | Padding(
79 | padding: EdgeInsets.only(left: ZFit().setWidth(20), top: ZFit().setWidth(10)),
80 | child: Text(
81 | bank['bankName'],
82 | textAlign: TextAlign.start,
83 | style: TextStyle(fontSize: ZFit().setSp(18), fontWeight: FontWeight.w500),
84 | )
85 | )
86 | );
87 |
88 | // 银行产品添加
89 | for (int j = 0; j < productList.length; j++) {
90 | Map item = productList[j];
91 | items.add(
92 | Padding(
93 | padding: EdgeInsets.symmetric(
94 | horizontal: ZFit().setWidth(20)
95 | ),
96 | child: BankProductWidget(item: item, intoChoicenessDetail: intoChoicenessDetail)
97 | )
98 | );
99 | }
100 |
101 | // 添加灰色横隔, 最底部不需要
102 | if ((i + 1) < _len) {
103 | items.add(
104 | Container(
105 | height: ZFit().setWidth(10),
106 | color: ZColor.thinGrey,
107 | )
108 | );
109 | }
110 | }
111 |
112 | // 最底部提示
113 | items.add(
114 | SizedBox(
115 | height: ZFit().setWidth(36),
116 | child: Text('已经到最底部啦...', textAlign: TextAlign.center, style: TextStyle(color: Colors.grey))
117 | )
118 | );
119 |
120 | return items;
121 |
122 | }
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/lib/page/nav_page.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/gestures.dart';
4 | import 'package:flutter_bloc/flutter_bloc.dart';
5 | import 'package:zmz_app/bloc/theme_bloc.dart';
6 | import 'package:zmz_app/compose/compose.dart';
7 | // 页面
8 | import 'package:zmz_app/page/home/home_page.dart';
9 | import 'package:zmz_app/page/treasure/treasure_page.dart';
10 | import 'package:zmz_app/page/customer/customer_page.dart';
11 | import 'package:zmz_app/page/news/news_page.dart';
12 | // 其他
13 | import 'package:zmz_app/utils/update_app.dart'; // 更新App操作
14 | import 'package:zmz_app/utils/center_nav.dart'; // BottomNav加号位置
15 |
16 | class NavPage extends StatefulWidget {
17 | final String title;
18 | NavPage({Key key, this.title}) : super(key: key);
19 |
20 | @override
21 | _NavPageState createState() => _NavPageState();
22 | }
23 |
24 | class _NavPageState extends State {
25 |
26 | int _selectedIndex = 0;
27 |
28 | // 并不是 GlobalKey 类型
29 | // final GlobalKey _scaffoldKey = new GlobalKey();
30 | PageController _pageController = new PageController();
31 |
32 | // bottomNavigationBar 点击事件
33 | void _tapBottomBar (index) {
34 | if (!mounted) return;
35 | setState(() { // 页面展示切换使用setState
36 | _selectedIndex = index;
37 | _pageController.jumpToPage(index);
38 | });
39 | }
40 |
41 | void _checkAndUpate() {
42 | // 可以在第一次打开APP时执行"版本更新"的网络请求
43 | UpdateApp _updateApp = new UpdateApp();
44 | // context 能拿到
45 | _updateApp.checkAndUpate(context);
46 | }
47 |
48 | @override
49 | void initState() {
50 | super.initState();
51 | _checkAndUpate();
52 | }
53 |
54 | @override
55 | Widget build(BuildContext context) {
56 |
57 | final ThemeBloc themeBloc = BlocProvider.of(context);
58 |
59 | return Scaffold(
60 | // key: _scaffoldKey,
61 | bottomNavigationBar: new BottomNavigationBar( // 底部导航
62 | type: BottomNavigationBarType.fixed, // 如果有4个bar那么必须要设置type
63 | items: [
64 | const BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('首页')),
65 | const BottomNavigationBarItem(icon: Icon(Icons.payment), title: Text('财富')),
66 | const BottomNavigationBarItem(icon: Icon(null), title: Text('')), // 空BottomNav
67 | const BottomNavigationBarItem(icon: Icon(Icons.book), title: Text('资讯')),
68 | const BottomNavigationBarItem(icon: Icon(Icons.person), title: Text('我的')),
69 | ],
70 | currentIndex: _selectedIndex,
71 | fixedColor: Colors.blue,
72 | onTap: _tapBottomBar,
73 | ),
74 | body: PageView(
75 | physics: NeverScrollableScrollPhysics(), // 禁止页面滑动
76 | controller: _pageController,
77 | children: [
78 | new HomePage(),
79 | TreasurePage(),
80 | Container(), // 空BottomNav对应页面
81 | NewsPage(),
82 | CustomerPage()
83 | ],
84 | ),
85 | floatingActionButton: Container(
86 | padding: ZEdge.all_5,
87 | decoration: BoxDecoration(
88 | border: Border.all(width: 1, color: ZColor.grey),
89 | borderRadius: BorderRadius.all(Radius.circular(ZFit().setWidth(55))),
90 | color: ZColor.defaultBackground
91 | ),
92 | child: FloatingActionButton(
93 | elevation: 0,
94 | backgroundColor: Colors.blue,
95 | child: Icon(Icons.autorenew, color: Colors.white,),
96 | onPressed: (){
97 | themeBloc.dispatch(ThemeEvent.toggle);
98 | },
99 | ),
100 | ),
101 | // const 很重要,不然每次点击BottomNav就会被重写一次
102 | floatingActionButtonLocation: const CenterNav()
103 | );
104 | }
105 |
106 | }
--------------------------------------------------------------------------------
/lib/view/common/my_search.dart:
--------------------------------------------------------------------------------
1 | import 'package:zmz_app/compose/compose.dart';
2 |
3 | class MySearch extends SearchDelegate {
4 |
5 | var _searchValue;
6 |
7 | MySearch(this._searchValue);
8 |
9 |
10 | @override
11 | List buildActions(BuildContext context) {
12 | print(_searchValue);
13 |
14 | return [
15 | RawMaterialButton(
16 | constraints: BoxConstraints(minWidth: 50.0, minHeight: 36.0),
17 | child: Icon(Icons.close),
18 | onPressed: () {
19 | this.query = '';
20 | },
21 | ),
22 | RawMaterialButton(
23 | constraints: BoxConstraints(minWidth: 50.0, minHeight: 36.0),
24 | child: Text('取消'),
25 | onPressed: () {
26 | Navigator.maybePop(context);
27 | },
28 | )
29 | ];
30 | }
31 |
32 | @override
33 | Widget buildResults(BuildContext context) {
34 | if (this.query == '') {
35 | return Container();
36 | } else {
37 | List _data = List.generate(10, (idx) => idx);
38 | // 搜索结果
39 | return Container(
40 | margin: EdgeInsets.symmetric(vertical: ZFit().setWidth(12), horizontal: ZFit().setWidth(6)),
41 | child: GridView.builder(
42 | itemCount: _data.length,
43 | //SliverGridDelegateWithFixedCrossAxisCount 构建一个横轴固定数量Widget
44 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
45 | //横轴元素个数
46 | crossAxisCount: 2,
47 | //纵轴间距
48 | mainAxisSpacing: 10.0,
49 | //横轴间距
50 | crossAxisSpacing: 10.0,
51 | //子组件宽高长度比例
52 | childAspectRatio: 1.0
53 | ),
54 | itemBuilder: (BuildContext context, int index) {
55 | return Container(
56 | decoration: BoxDecoration(
57 | border: Border.all(color: Colors.pink.withAlpha(55)),
58 | borderRadius: BorderRadius.all(Radius.circular(16)),
59 | ),
60 | child: Stack(
61 | children: [
62 | Container(
63 | alignment: Alignment.center,
64 | child: CircleAvatar(
65 | radius: ZFit().setWidth(60),
66 | backgroundImage: AssetImage('assets/images/One-Piece/${index.toString()}.jpg'),
67 | // child: Image.asset('assets/images/One-Piece/${index.toString()}.jpg'),
68 | )
69 | ),
70 | Positioned(
71 | child: Container(
72 | alignment: Alignment.topCenter,
73 | child: Text(this.query, style: TextStyle(fontSize: ZFit().setSp(16)),),
74 | ),
75 | )
76 | ],
77 | )
78 | );
79 | }
80 | )
81 | );
82 | }
83 | }
84 |
85 | @override
86 | Widget buildSuggestions(BuildContext context) {
87 | // 搜索建议
88 | return Column(
89 | children: List.generate(4, (index) {
90 | String _text = '${this.query == '' ? '猜你喜欢' : this.query} - ${index.toString()} ';
91 | // 搜索建议list
92 | return ListTile(
93 | title: Text(_text),
94 | onTap: (){
95 | // 修改SearchDelegate的 query
96 | this.query = _text;
97 | // 调用SearchDelegate的显示结果方法
98 | this.showResults(context);
99 | },
100 | );
101 | }).toList()
102 | );
103 | }
104 |
105 | @override
106 | Widget buildLeading(BuildContext context) {
107 | // 搜索Icon
108 | return RaisedButton(
109 | child: Icon(Icons.search),
110 | color: Colors.white,
111 | onPressed: (){ // 点击搜索按钮
112 | // 调用SearchDelegate的显示结果方法
113 | this.showResults(context);
114 | },
115 | );
116 | }
117 |
118 | }
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: zmz_app
2 | description: A new Flutter application.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.0.0+1
15 |
16 | environment:
17 | sdk: ">=2.2.0 <3.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 | flutter_localizations:
23 | sdk: flutter
24 | # The following adds the Cupertino Icons font to your application.
25 | # Use with the CupertinoIcons class for iOS style icons.
26 | cupertino_icons: ^0.1.2
27 | common_utils: ^1.1.1
28 | webview_flutter: ^0.3.10+3
29 | shared_preferences: ^0.5.0
30 | permission_handler: ^3.2.2
31 | path_provider: ^0.4.1
32 | flutter_downloader: 1.1.9
33 | url_launcher: 5.2.7
34 | flutter_bloc: ^0.21.0
35 | bloc: ^0.15.0
36 | dio: ^2.1.16
37 |
38 | dev_dependencies:
39 | flutter_test:
40 | sdk: flutter
41 |
42 |
43 | # For information on the generic Dart part of this file, see the
44 | # following page: https://www.dartlang.org/tools/pub/pubspec
45 |
46 | # The following section is specific to Flutter.
47 | flutter:
48 |
49 | # The following line ensures that the Material Icons font is
50 | # included with your application, so that you can use the icons in
51 | # the material Icons class.
52 | uses-material-design: true
53 |
54 | # To add assets to your application, add an assets section, like this:
55 | # - 只能前后各一个空格啊。。。不然找不到
56 | assets:
57 | - assets/images/banner_1.jpg
58 | - assets/images/banner_2.jpg
59 | - assets/images/banner_3.jpg
60 | - assets/images/logo.jpg
61 | - assets/images/projector.png
62 | - assets/images/red_envelope.jpg
63 | - assets/images/news.jpg
64 | - assets/images/One-Piece/0.jpg
65 | - assets/images/One-Piece/1.jpg
66 | - assets/images/One-Piece/2.jpg
67 | - assets/images/One-Piece/2.jpg
68 | - assets/images/One-Piece/3.jpg
69 | - assets/images/One-Piece/4.jpg
70 | - assets/images/One-Piece/5.jpg
71 | - assets/images/One-Piece/6.jpg
72 | - assets/images/One-Piece/7.jpg
73 | - assets/images/One-Piece/8.jpg
74 | - assets/images/One-Piece/9.jpg
75 |
76 | # An image asset can refer to one or more resolution-specific "variants", see
77 | # https://flutter.io/assets-and-images/#resolution-aware.
78 |
79 | # For details regarding adding assets from package dependencies, see
80 | # https://flutter.io/assets-and-images/#from-packages
81 |
82 | # To add custom fonts to your application, add a fonts section here,
83 | # in this "flutter" section. Each entry in this list should have a
84 | # "family" key with the font family name, and a "fonts" key with a
85 | # list giving the asset and other descriptors for the font. For
86 | # example:
87 | # fonts:
88 | # - family: Schyler
89 | # fonts:
90 | # - asset: fonts/Schyler-Regular.ttf
91 | # - asset: fonts/Schyler-Italic.ttf
92 | # style: italic
93 | # - family: Trajan Pro
94 | # fonts:
95 | # - asset: fonts/TrajanPro.ttf
96 | # - asset: fonts/TrajanPro_Bold.ttf
97 | # weight: 700
98 | #
99 | # For details regarding fonts from package dependencies,
100 | # see https://flutter.io/custom-fonts/#from-packages
101 |
--------------------------------------------------------------------------------
/lib/plugin/carousel.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'dart:async';
4 |
5 | // Widget代码
6 | class Carousel extends StatefulWidget {
7 |
8 | final List carouselList; // 轮播图list
9 | final double height; // 轮播图高度
10 | final double tagWidth; // 屏幕宽度
11 | final double tagBottom; // 下标 位置
12 | final Color tagColor; // 下标 颜色
13 | final Color activeTagColor; // 当前 下标 颜色
14 | final double tagSize;
15 | final bool isAuto; // 是否自动轮播
16 | final int interval; // 自动轮播间隔
17 |
18 | Carousel({
19 | this.height = 150.00,
20 | @required this.carouselList,
21 | @required this.tagWidth,
22 | this.tagBottom = 6.00,
23 | this.tagColor = Colors.white,
24 | this.activeTagColor = Colors.grey,
25 | this.tagSize = 10.0,
26 | this.isAuto = true,
27 | this.interval = 3
28 | });
29 |
30 | @override
31 | State createState() => _Carousel();
32 |
33 | }
34 |
35 | class _Carousel extends State with SingleTickerProviderStateMixin{
36 |
37 | List _wrapList = [];
38 |
39 | // 页面控制器和下标控制器
40 | TabController _tabController;
41 | PageController _pageController = PageController(initialPage: 1);
42 |
43 | // 计时器
44 | Timer _timer;
45 |
46 | _onPageChanged (idx) {
47 | // 轮播实现
48 | if (idx == 0) {
49 | int _endIndex = _wrapList.length - 2;
50 | _pageController.animateToPage(
51 | _endIndex,
52 | duration: Duration(microseconds: 1688),
53 | curve: Curves.fastOutSlowIn
54 | );
55 | } else if (idx == (_wrapList.length - 1)) {
56 | int _startIndex = 1;
57 | _pageController.animateToPage(
58 | _startIndex,
59 | duration: Duration(microseconds: 1688),
60 | curve: Curves.fastOutSlowIn
61 | );
62 | } else {
63 | _tabController.animateTo(idx - 1);
64 | }
65 | }
66 |
67 | // 自动轮播
68 | _autoSwiper () {
69 | // 使用计时器
70 | _timer = new Timer.periodic(
71 | Duration(seconds: widget.interval),
72 | (timer){
73 | // 下个页面
74 | int _next = (_tabController.index ?? 1 + 1) % _tabController.length;
75 | _pageController.animateToPage(
76 | _next,
77 | duration: Duration(milliseconds: 168),
78 | curve: Curves.fastOutSlowIn,
79 | );
80 | }
81 | );
82 | }
83 |
84 | @override
85 | void initState() {
86 | // 初始化时把list前后各加一张用于无限轮播
87 | _wrapList.insert(0, widget.carouselList[widget.carouselList.length - 1]);
88 | _wrapList.addAll(widget.carouselList);
89 | _wrapList.add(widget.carouselList[0]);
90 | _tabController = TabController(vsync: this, length: widget.carouselList.length);
91 | // 自动滑动
92 | if (widget.isAuto) {
93 | _autoSwiper();
94 | }
95 | super.initState();
96 | }
97 |
98 | @override
99 | void dispose() {
100 | // 销毁 控制器
101 | _tabController.dispose();
102 | _pageController.dispose();
103 | // 清理计时器
104 | if (_timer != null) {
105 | _timer.cancel();
106 | }
107 | super.dispose();
108 | }
109 |
110 | // 利用PageView实现
111 | @override
112 | Widget build(BuildContext context) {
113 | return Stack(
114 | children: [
115 | Container(
116 | height: widget.height,
117 | child: PageView(
118 | onPageChanged: _onPageChanged,
119 | children: _wrapList,
120 | controller: _pageController
121 | ),
122 | ),
123 | Positioned(
124 | bottom: widget.tagBottom,
125 | child: Container(
126 | width: widget.tagWidth,
127 | child: Align(
128 | alignment: Alignment(0.0, 0.5),
129 | child: TabPageSelector(
130 | color: widget.tagColor,
131 | indicatorSize: widget.tagSize,
132 | selectedColor: widget.activeTagColor,
133 | controller: _tabController,
134 | ),
135 | ),
136 | )
137 | )
138 | ],
139 | );
140 | }
141 |
142 | }
--------------------------------------------------------------------------------
/lib/page/news/news_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:zmz_app/utils/event_bus.dart';
3 | // import 'package:flutter_screenutil/flutter_screenutil.dart';
4 |
5 | class NewsPage extends StatefulWidget {
6 | @override
7 | State createState() => _NewsState();
8 | }
9 |
10 | class _NewsState extends State {
11 | var products = List.generate(16, (idx) => idx);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Scaffold(
16 | // appBar: AppBar(
17 | // title: Text('Z.新闻'),
18 | // centerTitle: true, // appBar文字居中
19 | // ),
20 | body: CustomScrollView(
21 | slivers: [
22 | SliverAppBar(
23 | title: Row(
24 | children: [
25 | Text('Z.新闻')
26 | ],
27 | ),
28 | // centerTitle: true, // 让center居中,android表示变化不大
29 | // iconTheme: IconThemeData(), // Icon的样式
30 | actions: [ //导航栏右侧菜单
31 | IconButton(icon: Icon(Icons.search),
32 | onPressed: () {
33 | // x
34 | }
35 | ),
36 | ],
37 | // bottom: PreferredSize( // appBar 中间底部widget
38 | // preferredSize: Size(0.0, 0.0),
39 | // child: Text('bottom')
40 | // ),
41 | backgroundColor: Theme.of(context).accentColor,
42 | expandedHeight: 160.0, // 图片高度
43 | flexibleSpace: FlexibleSpaceBar(
44 | background: Image.asset('assets/images/news.jpg', fit: BoxFit.cover),
45 | ),
46 | floating: true,
47 | snap: true, // 必须要 floating: true 才能使用,snap时在下拉手势松开后直接展示图片
48 | pinned: true, // 图片消失时 title 是否可见
49 | ),
50 | SliverFixedExtentList(
51 | itemExtent: 66.0, // 高度
52 | delegate: SliverChildListDelegate(
53 | products.map((product) {
54 | return ListTile(
55 | leading: Icon(Icons.equalizer),
56 | title: Text('...' + product.toString()),
57 | subtitle: Text('啦啦啦'),
58 | onTap: () {
59 | eventBus.emit('showToast', '点击:' + product.toString());
60 | },
61 | );
62 | }).toList(),
63 | ),
64 | ),
65 | // SliverGrid 的使用方法
66 | // xxx
67 | // SliverGrid.count( // SliverGrid和Grid有什么区别???
68 | // crossAxisCount: 2, // 一行排列数
69 | // mainAxisSpacing: 15.0, // 主轴间隔
70 | // // crossAxisSpacing: 6.0, // 交叉轴间隔
71 | // childAspectRatio: 2.3, // 纵横比
72 | // children: products.map((product) {
73 | // return Container(
74 | // margin: EdgeInsets.symmetric(horizontal: ZFit().setWidth(12)),
75 | // decoration: BoxDecoration( // 阴影修饰
76 | // color: Colors.white,
77 | // boxShadow: [
78 | // BoxShadow(color: Colors.blue, offset: Offset(0, 5.0), blurRadius: 6.0, spreadRadius: -5.0),
79 | // BoxShadow(color: Colors.pink, offset: Offset(-5.0, 0.0), blurRadius: 6.0, spreadRadius: -5.0)
80 | // ]
81 | // ),
82 | // child: ListTile(
83 | // leading: Container(
84 | // decoration: BoxDecoration( // 渐变修饰
85 | // shape: BoxShape.circle,
86 | // gradient: RadialGradient(
87 | // colors: [Colors.orange, Colors.green, Colors.orange]
88 | // ),
89 | // ),
90 | // child: Icon(Icons.equalizer),
91 | // ),
92 | // title: Text('...' + product.toString()),
93 | // subtitle: Text('啦啦啦'),
94 | // ),
95 | // );
96 | // }).toList(),
97 | // ),
98 | ],
99 | ),
100 | );
101 | }
102 |
103 | }
--------------------------------------------------------------------------------
/lib/utils/update_app.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 | // App升级
5 | import 'package:flutter_downloader/flutter_downloader.dart';
6 | import 'package:path_provider/path_provider.dart';
7 | import 'package:permission_handler/permission_handler.dart';
8 | import 'package:url_launcher/url_launcher.dart';
9 | import 'package:zmz_app/config/base_info.dart';
10 | import 'package:zmz_app/utils/event_bus.dart';
11 |
12 | class _AppVersionInfo {
13 | String version;
14 | String url;
15 | _AppVersionInfo.formResponse(Map json) {
16 | this.version = json['version'];
17 | this.url = json['url'];
18 | }
19 | }
20 |
21 | class UpdateApp {
22 |
23 | // 检查版本是否低于某版本
24 | bool _checkVersionLowerOf (String version) {
25 | // 只有当前版本不等于最新版本,就说明版本落后了
26 | return version == Config.version;
27 | }
28 |
29 | // 获取安装地址
30 | Future<_AppVersionInfo> _getApkLocalInfo() async {
31 | // 不发请求了,下载个QQ试试
32 | final directory = {
33 | 'version': '1.0.1',
34 | 'url': 'https://qd.myapp.com/myapp/qqteam/AndroidQQi/qq_6.0.1.6600_android_r25029_GuanWang_537057608_release.apk'
35 | };
36 | return new _AppVersionInfo.formResponse(directory);
37 | }
38 |
39 | Future get _getDownloadPath async {
40 | final directory = await getExternalStorageDirectory();
41 | return directory.path;
42 | }
43 |
44 | Future checkPath(path) async{
45 | final savedDir = Directory(path);
46 | // 判断下载路径是否存在
47 | bool hasExisted = await savedDir.exists();
48 | // 不存在就新建路径
49 | if (!hasExisted) {
50 | savedDir.create();
51 | }
52 | }
53 |
54 | void _updateVersion(String url) async {
55 | if (Config.platform == ZPlatform.android) {
56 | _executeDownload(url);
57 | } else {
58 | if (await canLaunch(url)) {
59 | launch(url);
60 | } else {
61 | throw 'Could not launch $url';
62 | }
63 | }
64 | }
65 |
66 | //下载
67 | Future _executeDownload(url) async {
68 | Map permissions = await PermissionHandler().requestPermissions([PermissionGroup.storage]);
69 | if (permissions[PermissionGroup.storage] == PermissionStatus.granted) {
70 |
71 | final path = (await _getDownloadPath) + '/Download';
72 |
73 | await checkPath(path);
74 |
75 | final taskId = await FlutterDownloader.enqueue(
76 | url: url,
77 | savedDir: path,
78 | showNotification: true,
79 | openFileFromNotification: true);
80 | FlutterDownloader.registerCallback((id, status, progress) {
81 | // 当下载完成时,调用安装
82 | if (taskId == id && status == DownloadTaskStatus.complete) {
83 | FlutterDownloader.open(taskId: taskId);
84 | }
85 | });
86 | } else {
87 | eventBus.emit('showToast', '您拒绝了存储授权,无法完成版本升级');
88 | }
89 | }
90 |
91 | // 暴露方法
92 | void checkAndUpate(BuildContext context) {
93 | // 可以在第一次打开APP时执行"版本更新"的网络请求
94 | _getApkLocalInfo().then((_AppVersionInfo directory) {
95 | if (_checkVersionLowerOf(directory.version)) {
96 | // 弹出dalog询问是否升级
97 | showDialog(
98 | context: context,
99 | builder: (BuildContext context) {
100 | return AlertDialog(
101 | title: Text('提示'),
102 | content: Text('有优化更新,赶紧体验一下吧。'),
103 | actions: [
104 | RaisedButton(
105 | textColor: Colors.white,
106 | child: Text('取消'),
107 | onPressed: () {
108 | Navigator.maybePop(context);
109 | },
110 | ),
111 | RaisedButton(
112 | textColor: Colors.white,
113 | child: Text('确定'),
114 | onPressed: () {
115 | // 下载 并 安装新版本
116 | _updateVersion(directory.url);
117 | Navigator.maybePop(context);
118 | },
119 | )
120 | ]
121 | );
122 | }
123 | );
124 | }
125 | });
126 | }
127 |
128 | }
--------------------------------------------------------------------------------
/lib/view/user-info/user_assert.dart:
--------------------------------------------------------------------------------
1 | import 'package:zmz_app/compose/compose.dart';
2 |
3 | // 用户资产
4 | class UserAssertWidget extends StatelessWidget {
5 |
6 | final Map userInfo;
7 | final Function logout;
8 | UserAssertWidget({@required this.userInfo, @required this.logout});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Container(
13 | padding: EdgeInsets.symmetric(
14 | horizontal: ZFit().setWidth(20),
15 | vertical: ZFit().setWidth(12)
16 | ),
17 | child: Column(
18 | children: [
19 | Row(
20 | children: [
21 | Expanded(
22 | flex: 1,
23 | child: Text(this.userInfo['name'], style: TextStyle(fontSize: ZFit().setSp(16), color: Color(0xFF333333))),
24 | ),
25 | GestureDetector(
26 | child: Icon(
27 | Icons.settings,
28 | color: Color(0xFF333333),
29 | ),
30 | onTap: this.logout
31 | )
32 | ],
33 | ),
34 | Stack(
35 | children: [
36 | Positioned(
37 | child: Container(
38 | width: ZFit().setWidth(335),
39 | height: ZFit().setWidth(123),
40 | margin: EdgeInsets.all(ZFit().setWidth(6)),
41 | decoration: BoxDecoration(
42 | border: Border.all(color: Colors.blue),
43 | borderRadius: BorderRadius.all(Radius.circular(12))
44 | ),
45 | ),
46 | ),
47 | Container(
48 | padding: EdgeInsets.symmetric(horizontal: ZFit().setWidth(30)),
49 | child: Column(
50 | children: [
51 | Container(
52 | padding: EdgeInsets.only(top: ZFit().setWidth(18), bottom: ZFit().setWidth(10)),
53 | child: Text('总资产(元)')
54 | ),
55 | Container(
56 | margin: EdgeInsets.only(bottom: ZFit().setWidth(8)),
57 | child: Text(this.userInfo['money'], style: TextStyle(color: Colors.red, fontSize: ZFit().setSp(16))),
58 | ),
59 | Row(
60 | children: [
61 | Expanded(
62 | flex: 1,
63 | child: Column(
64 | children: [
65 | Text('累计收益'),
66 | Text('+${this.userInfo["profit"]}元', style: TextStyle(color: Color(0xFFf7b6a9), fontSize: ZFit().setSp(12)))
67 | ],
68 | ),
69 | ),
70 | Container(
71 | width: ZFit().setWidth(1),
72 | height: ZFit().setWidth(22),
73 | color: Color(0xFFc3c3c3),
74 | ),
75 | Expanded(
76 | flex: 1,
77 | child: Column(
78 | children: [
79 | Text('在途'),
80 | Text('${this.userInfo["midway"]}元', style: TextStyle(color: Color(0xFFf7b6a9), fontSize: ZFit().setSp(12)))
81 | ],
82 | ),
83 | ),
84 | ],
85 | )
86 | ],
87 | ),
88 | )
89 | ],
90 | ),
91 | Padding(
92 | padding: EdgeInsets.only(top: ZFit().setWidth(10)),
93 | child: Row(
94 | children: [
95 | _userInfoUnitWidget(icon: Icons.view_compact, name: '取现'),
96 | _userInfoUnitWidget(icon: Icons.pages, name: '充值')
97 | ],
98 | )
99 | )
100 | ],
101 | ),
102 | );
103 | }
104 | }
105 | Widget _userInfoUnitWidget ({@required icon, @required name}) {
106 | return Expanded(
107 | flex: 1,
108 | child: Container(
109 | alignment: Alignment.center,
110 | child: Text(name, style: TextStyle(color: Color(0xFF333333), fontSize: ZFit().setSp(16))),
111 | )
112 | );
113 | }
--------------------------------------------------------------------------------
/lib/page/product/product_details_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 | import 'package:zmz_app/bloc/payment/payment_bloc.dart';
4 | import 'package:zmz_app/compose/compose.dart';
5 | import 'package:zmz_app/domain/product_domain.dart';
6 | import 'package:zmz_app/page/payment/payment_page.dart';
7 | import 'package:zmz_app/routes/z_router.dart';
8 | import 'package:zmz_app/utils/event_bus.dart'; // 页面
9 |
10 | class ProductDetailsPage extends StatelessWidget {
11 |
12 | // final Product pro;
13 | // ProductDetailsPage({@required _pro});
14 | @override
15 | Widget build(BuildContext context) {
16 |
17 | Product _pro = ZRouter.getPageArguments(context, new Product());
18 |
19 | print(_pro.id);
20 |
21 | return BlocProvider(
22 | builder: (context) => PaymentNumBloc(),
23 | child: BlocBuilder(
24 | // bloc: PaymentNumBloc(), // 这样注入将限定为单个窗口小部件并且无法通过父窗口和BlocProvider当前窗口小部件访问的块
25 | builder: (context2, count) {
26 |
27 | // 灰常重要
28 | // 一定要在 BlocProvider后面
29 | PaymentNumBloc _paymentNumBloc = BlocProvider.of(context2);
30 |
31 | return Scaffold(
32 | appBar: AppBar(
33 | title: Text('Z.产品详情'),
34 | elevation: 0,
35 | ),
36 | body: Stack(
37 | children: [
38 | SafeArea(
39 | child: ListView(
40 | children: [
41 | Container(
42 | padding: ZEdge.all_15,
43 | decoration: BoxDecoration(
44 | gradient: LinearGradient(
45 | begin: Alignment.topCenter,
46 | end: Alignment.bottomCenter,
47 | colors: [
48 | Colors.blue,
49 | ZColor.defaultBackground
50 | ]
51 | )
52 | ),
53 | child: Column(
54 | children: [
55 | Text(_pro.name, style: TextStyle(fontSize: ZFit().setWidth(14)),),
56 | Container(
57 | padding: ZEdge.vertical_5,
58 | child: Text(_pro.rate, style: TextStyle(fontSize: ZFit().setWidth(42), color: Colors.white),),
59 | ),
60 | Text(_pro.rateTime, style: TextStyle(fontSize: ZFit().setWidth(16)),),
61 | ],
62 | ),
63 | ),
64 | Container(
65 | padding: ZEdge.all_15,
66 | child: _buyControl(count, _paymentNumBloc),
67 | )
68 | ],
69 | ),
70 | ),
71 | Positioned(
72 | bottom: 0,
73 | child: RaisedButton(
74 | color: ZColor.thinBlue,
75 | onPressed: (){
76 | // 让push的 子Widget 同步Bloc
77 | showModalBottomSheet(
78 | context: ZRouter.context,
79 | builder: (_) {
80 | // 使用已经存在的 bloc value
81 | return BlocProvider.value(
82 | value: _paymentNumBloc,
83 | child: PaymentPage()
84 | );
85 | }
86 | );
87 | },
88 | child: Container(
89 | padding: ZEdge.vertical_10,
90 | alignment: Alignment.center,
91 | width: ZFit().setWidth(375),
92 | child: Text('购买', style: TextStyle(color: Colors.white, fontSize: ZFit().setWidth(16)),),
93 | ),
94 | ),
95 | )
96 | ],
97 | ),
98 | );
99 | },
100 | ),
101 | );
102 | }
103 | }
104 |
105 | Column _buyControl (count, _paymentNumBloc) {
106 |
107 | // TextEditingController _controller = TextEditingController();
108 |
109 | return Column(
110 | children: [
111 | Container(
112 | padding: ZEdge.all_15,
113 | child: Row(
114 | children: [
115 | Text('购买份数', style: TextStyle(fontSize: ZFit().setWidth(22)),),
116 | Container(
117 | padding: ZEdge.horizontal_15,
118 | child: Text('$count', style: TextStyle(fontSize: 24.0),),
119 | ),
120 | ],
121 | ),
122 | ),
123 | // Container(
124 | // padding: ZEdge.all_15,
125 | // child: CupertinoTextField(
126 | // controller: _controller,
127 | // placeholder: '请输入购买金额',
128 | // clearButtonMode: OverlayVisibilityMode.editing,
129 | // keyboardType: TextInputType.number,
130 | // ),
131 | // ),
132 | Row(
133 | mainAxisAlignment: MainAxisAlignment.spaceAround,
134 | children: [
135 | Container(
136 | child: FlatButton(
137 | shape: Border.all(width: 1, color: ZColor.grey),
138 | child: Text('重置', style: TextStyle(color: ZColor.black),),
139 | onPressed: () {
140 | _paymentNumBloc.dispatch(PaymentNumEvent.reset);
141 | },
142 | ),
143 | ),
144 | Container(
145 | child: FlatButton(
146 | color: ZColor.thinBlue,
147 | child: Text('添加', style: TextStyle(color: Colors.white),),
148 | onPressed: () {
149 | eventBus.emit('showLoading');
150 | Future.delayed(Duration(milliseconds: 500)).then((val) {
151 | eventBus.emit('closeLoading');
152 | });
153 | _paymentNumBloc.dispatch(PaymentNumEvent.increment);
154 | },
155 | ),
156 | ),
157 | ],
158 | )
159 | ]
160 | );
161 | }
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | url: "https://pub.flutter-io.cn"
9 | source: hosted
10 | version: "2.3.0"
11 | bloc:
12 | dependency: "direct main"
13 | description:
14 | name: bloc
15 | url: "https://pub.flutter-io.cn"
16 | source: hosted
17 | version: "0.15.0"
18 | boolean_selector:
19 | dependency: transitive
20 | description:
21 | name: boolean_selector
22 | url: "https://pub.flutter-io.cn"
23 | source: hosted
24 | version: "1.0.5"
25 | charcode:
26 | dependency: transitive
27 | description:
28 | name: charcode
29 | url: "https://pub.flutter-io.cn"
30 | source: hosted
31 | version: "1.1.2"
32 | collection:
33 | dependency: transitive
34 | description:
35 | name: collection
36 | url: "https://pub.flutter-io.cn"
37 | source: hosted
38 | version: "1.14.11"
39 | common_utils:
40 | dependency: "direct main"
41 | description:
42 | name: common_utils
43 | url: "https://pub.flutter-io.cn"
44 | source: hosted
45 | version: "1.1.1"
46 | cookie_jar:
47 | dependency: transitive
48 | description:
49 | name: cookie_jar
50 | url: "https://pub.flutter-io.cn"
51 | source: hosted
52 | version: "1.0.1"
53 | cupertino_icons:
54 | dependency: "direct main"
55 | description:
56 | name: cupertino_icons
57 | url: "https://pub.flutter-io.cn"
58 | source: hosted
59 | version: "0.1.2"
60 | decimal:
61 | dependency: transitive
62 | description:
63 | name: decimal
64 | url: "https://pub.flutter-io.cn"
65 | source: hosted
66 | version: "0.3.3"
67 | dio:
68 | dependency: "direct main"
69 | description:
70 | name: dio
71 | url: "https://pub.flutter-io.cn"
72 | source: hosted
73 | version: "2.1.16"
74 | flutter:
75 | dependency: "direct main"
76 | description: flutter
77 | source: sdk
78 | version: "0.0.0"
79 | flutter_bloc:
80 | dependency: "direct main"
81 | description:
82 | name: flutter_bloc
83 | url: "https://pub.flutter-io.cn"
84 | source: hosted
85 | version: "0.21.0"
86 | flutter_downloader:
87 | dependency: "direct main"
88 | description:
89 | name: flutter_downloader
90 | url: "https://pub.flutter-io.cn"
91 | source: hosted
92 | version: "1.1.9"
93 | flutter_localizations:
94 | dependency: "direct main"
95 | description: flutter
96 | source: sdk
97 | version: "0.0.0"
98 | flutter_test:
99 | dependency: "direct dev"
100 | description: flutter
101 | source: sdk
102 | version: "0.0.0"
103 | intl:
104 | dependency: transitive
105 | description:
106 | name: intl
107 | url: "https://pub.flutter-io.cn"
108 | source: hosted
109 | version: "0.15.8"
110 | matcher:
111 | dependency: transitive
112 | description:
113 | name: matcher
114 | url: "https://pub.flutter-io.cn"
115 | source: hosted
116 | version: "0.12.5"
117 | meta:
118 | dependency: transitive
119 | description:
120 | name: meta
121 | url: "https://pub.flutter-io.cn"
122 | source: hosted
123 | version: "1.1.7"
124 | path:
125 | dependency: transitive
126 | description:
127 | name: path
128 | url: "https://pub.flutter-io.cn"
129 | source: hosted
130 | version: "1.6.4"
131 | path_provider:
132 | dependency: "direct main"
133 | description:
134 | name: path_provider
135 | url: "https://pub.flutter-io.cn"
136 | source: hosted
137 | version: "0.4.1"
138 | pedantic:
139 | dependency: transitive
140 | description:
141 | name: pedantic
142 | url: "https://pub.flutter-io.cn"
143 | source: hosted
144 | version: "1.8.0+1"
145 | permission_handler:
146 | dependency: "direct main"
147 | description:
148 | name: permission_handler
149 | url: "https://pub.flutter-io.cn"
150 | source: hosted
151 | version: "3.2.2"
152 | provider:
153 | dependency: transitive
154 | description:
155 | name: provider
156 | url: "https://pub.flutter-io.cn"
157 | source: hosted
158 | version: "3.1.0"
159 | quiver:
160 | dependency: transitive
161 | description:
162 | name: quiver
163 | url: "https://pub.flutter-io.cn"
164 | source: hosted
165 | version: "2.0.5"
166 | rational:
167 | dependency: transitive
168 | description:
169 | name: rational
170 | url: "https://pub.flutter-io.cn"
171 | source: hosted
172 | version: "0.3.4"
173 | rxdart:
174 | dependency: transitive
175 | description:
176 | name: rxdart
177 | url: "https://pub.flutter-io.cn"
178 | source: hosted
179 | version: "0.22.2"
180 | shared_preferences:
181 | dependency: "direct main"
182 | description:
183 | name: shared_preferences
184 | url: "https://pub.flutter-io.cn"
185 | source: hosted
186 | version: "0.5.3+1"
187 | sky_engine:
188 | dependency: transitive
189 | description: flutter
190 | source: sdk
191 | version: "0.0.99"
192 | source_span:
193 | dependency: transitive
194 | description:
195 | name: source_span
196 | url: "https://pub.flutter-io.cn"
197 | source: hosted
198 | version: "1.5.5"
199 | stack_trace:
200 | dependency: transitive
201 | description:
202 | name: stack_trace
203 | url: "https://pub.flutter-io.cn"
204 | source: hosted
205 | version: "1.9.3"
206 | stream_channel:
207 | dependency: transitive
208 | description:
209 | name: stream_channel
210 | url: "https://pub.flutter-io.cn"
211 | source: hosted
212 | version: "2.0.0"
213 | string_scanner:
214 | dependency: transitive
215 | description:
216 | name: string_scanner
217 | url: "https://pub.flutter-io.cn"
218 | source: hosted
219 | version: "1.0.5"
220 | term_glyph:
221 | dependency: transitive
222 | description:
223 | name: term_glyph
224 | url: "https://pub.flutter-io.cn"
225 | source: hosted
226 | version: "1.1.0"
227 | test_api:
228 | dependency: transitive
229 | description:
230 | name: test_api
231 | url: "https://pub.flutter-io.cn"
232 | source: hosted
233 | version: "0.2.5"
234 | typed_data:
235 | dependency: transitive
236 | description:
237 | name: typed_data
238 | url: "https://pub.flutter-io.cn"
239 | source: hosted
240 | version: "1.1.6"
241 | url_launcher:
242 | dependency: "direct main"
243 | description:
244 | name: url_launcher
245 | url: "https://pub.flutter-io.cn"
246 | source: hosted
247 | version: "5.2.7"
248 | url_launcher_platform_interface:
249 | dependency: transitive
250 | description:
251 | name: url_launcher_platform_interface
252 | url: "https://pub.flutter-io.cn"
253 | source: hosted
254 | version: "1.0.1"
255 | vector_math:
256 | dependency: transitive
257 | description:
258 | name: vector_math
259 | url: "https://pub.flutter-io.cn"
260 | source: hosted
261 | version: "2.0.8"
262 | webview_flutter:
263 | dependency: "direct main"
264 | description:
265 | name: webview_flutter
266 | url: "https://pub.flutter-io.cn"
267 | source: hosted
268 | version: "0.3.10+3"
269 | sdks:
270 | dart: ">=2.2.2 <3.0.0"
271 | flutter: ">=1.9.1+hotfix.4 <2.0.0"
272 |
--------------------------------------------------------------------------------
/lib/page/customer/customer_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:zmz_app/compose/compose.dart';
2 | import 'package:zmz_app/utils/storage.dart'; // storage
3 | import 'package:zmz_app/service/api.dart'; // 请求
4 | import 'package:zmz_app/view/user-info/shop_list.dart';
5 | import 'package:zmz_app/view/user-info/user_assert.dart';
6 |
7 | class CustomerPage extends StatefulWidget {
8 | @override
9 | _CustomerPageState createState() => _CustomerPageState();
10 | }
11 |
12 | class _CustomerPageState extends State {
13 |
14 | bool _isLogin = false;
15 | Map _userInfo;
16 | List _expandIndex = [false, false];
17 |
18 | // 获取用户数据
19 | Future _getUserInfo (phone) async {
20 | var data = await Api.getUserInfo(phone);
21 | return data;
22 | }
23 |
24 | // 检查登录
25 | void _checkoutLogin() {
26 | LocalStorage.getString('phone').then((phone) {
27 | if (phone != null) {
28 | // 获取后台数据
29 | _getUserInfo(phone).then((userInfo) {
30 | if (!mounted) return;
31 | setState(() {
32 | _isLogin = true;
33 | _userInfo = userInfo;
34 | });
35 | });
36 | }
37 | });
38 | }
39 |
40 | // 进入登录页
41 | void _loginAccount() {
42 | Navigator.pushNamed(context, '/login').then((res) {
43 | _checkoutLogin();
44 | });
45 | }
46 |
47 | // 退出登录
48 | void _logout() {
49 | LocalStorage.remove('phone').then((res) {
50 | if (!mounted) return;
51 | setState(() {
52 | _isLogin = false;
53 | _userInfo = null;
54 | });
55 | });
56 | }
57 |
58 | @override
59 | void initState() {
60 | super.initState();
61 | // 判断登录
62 | _checkoutLogin();
63 | }
64 |
65 | @override
66 | Widget build(BuildContext context) {
67 |
68 | List _account = [
69 | {
70 | 'name': '一账通账户',
71 | 'text': '未登录',
72 | }
73 | ];
74 |
75 | List dispenseWidget() {
76 | if (_isLogin) {
77 | return [
78 | UserAssertWidget(userInfo: _userInfo, logout: _logout) ,
79 | _brWidget(), // 灰色间隔
80 | ShopListWidget(),
81 | _brWidget(), // 灰色间隔
82 | _contactWidget(),
83 | _brWidget(), // 灰色间隔
84 | ];
85 | } else {
86 | return [
87 | _registeredWidget(context: context, loginAccount: _loginAccount),
88 | _brWidget(), // 灰色间隔
89 | _contactWidget(),
90 | _brWidget(), // 灰色间隔
91 | ];
92 | }
93 | }
94 |
95 | return Scaffold(
96 | appBar: AppBar(
97 | title: Text('Z.我的'),
98 | centerTitle: true, // appBar文字居中
99 | ),
100 | endDrawer: Drawer(
101 | child: Column(
102 | children: [
103 | DrawerHeader(
104 | child: Image.asset('assets/images/logo.jpg'),
105 | ),
106 | Container(
107 | margin: ZEdge.horizontal_20,
108 | child: ExpansionPanelList(
109 | expansionCallback: (int panelIndex, bool isExpanded) {
110 | setState(() {
111 | _expandIndex[panelIndex] = !isExpanded;
112 | });
113 | },
114 | children: _account.map((val) {
115 | return ExpansionPanel(
116 | isExpanded: _expandIndex[0],
117 | headerBuilder: (BuildContext context, bool isExpanded){
118 | return Container(
119 | padding: ZEdge.all_15,
120 | child: Text(val['name']),
121 | );
122 | },
123 | body: Container(
124 | alignment: Alignment.center,
125 | width: double.infinity,
126 | padding: ZEdge.all_15,
127 | color: ZColor.thinGrey,
128 | child: Text(val['text']),
129 | )
130 | );
131 | }).toList()
132 | )
133 | )
134 | ],
135 | ),
136 | ),
137 | body: ListView(
138 | children: dispenseWidget(),
139 | ),
140 | );
141 | }
142 | }
143 |
144 | // 用户未登录模块
145 | Widget _registeredWidget ({@required context, @required loginAccount}) {
146 |
147 | Widget _loginBannerWidget () {
148 |
149 | return GestureDetector(
150 | child: Stack(
151 | children: [
152 | Container(
153 | width: ZFit().setWidth(360),
154 | height: ZFit().setWidth(160),
155 | decoration: BoxDecoration(
156 | color: Colors.blue,
157 | borderRadius: ZRadius.all_5,
158 | gradient: LinearGradient(
159 | begin: Alignment.topCenter,
160 | end: Alignment.bottomCenter,
161 | colors: [
162 | Colors.pink,
163 | ZColor.thinBlue
164 | ]
165 | ),
166 | ),
167 | ),
168 | Align(
169 | alignment: Alignment.center,
170 | child: Column(
171 | children: [
172 | Padding(
173 | padding: EdgeInsets.only(top: ZFit().setWidth(20)),
174 | child: Text('互联网金融平台', style: TextStyle(color: Colors.white, fontSize: ZFit().setSp(12)))
175 | ),
176 | Padding(
177 | padding: EdgeInsets.only(top: ZFit().setWidth(30)),
178 | child: FlatButton(
179 | disabledTextColor: Colors.blue,
180 | disabledColor: Colors.blue,
181 | padding: EdgeInsets.symmetric(horizontal: ZFit().setWidth(38), vertical: ZFit().setWidth(5)),
182 | shape: RoundedRectangleBorder(borderRadius: ZRadius.all_15),
183 | child: Text("注册领红包", style: TextStyle(fontSize: ZFit().setSp(18), fontWeight: FontWeight.bold, color: Colors.white)),
184 | onPressed: null
185 | )
186 | ),
187 | Padding(
188 | padding: EdgeInsets.only(top: ZFit().setWidth(6)),
189 | child: Text('立即登录 >', style: TextStyle(color: Colors.white, fontSize: ZFit().setSp(14)))
190 | )
191 | ],
192 | )
193 | ),
194 | ],
195 | ),
196 | onTap: loginAccount
197 | );
198 | }
199 |
200 | return Container(
201 | padding: ZEdge.horizontal_15,
202 | child: Column(
203 | children: [
204 | Container(
205 | padding: ZEdge.vertical_10,
206 | width: ZFit().setWidth(375),
207 | child: Text('欢迎来到金融理财', style: TextStyle(fontSize: ZFit().setSp(16))),
208 | ),
209 | _loginBannerWidget()
210 | ],
211 | ),
212 | );
213 | }
214 |
215 |
216 | // 客服模块
217 | Widget _contactWidget () {
218 | Widget _contactStyleWidget ({@required icon, @required text}) {
219 | return Container(
220 | child: Row(
221 | children: [
222 | Padding(
223 | padding: ZEdge.horizontal_5,
224 | child:Icon(icon, color: ZColor.grey, size: ZFit().setSp(16)),
225 | ),
226 | Text(text, style: TextStyle(color: ZColor.grey, fontSize: ZFit().setSp(14)),)
227 | ]
228 | ),
229 | );
230 | }
231 | return Container(
232 | height: ZFit().setWidth(45),
233 | child: Row(
234 | mainAxisAlignment: MainAxisAlignment.spaceAround,
235 | children: [
236 | _contactStyleWidget(icon: Icons.headset_mic, text: '在线客服'),
237 | _contactStyleWidget(icon: Icons.phone_iphone, text: '电话客服'),
238 | ],
239 | ),
240 | );
241 | }
242 |
243 | // 灰色间隔
244 | Widget _brWidget ({height = 9}) {
245 | return Container(
246 | height: ZFit().setWidth(height),
247 | color: ZColor.thinGrey,
248 | );
249 | }
--------------------------------------------------------------------------------
/lib/page/home/home_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:zmz_app/compose/compose.dart';
3 | import 'package:zmz_app/domain/product_domain.dart';
4 | import 'package:zmz_app/plugin/carousel.dart'; // 功能widget
5 | import 'package:zmz_app/routes/z_router.dart';
6 | import 'package:zmz_app/service/api.dart'; // 请求
7 | import 'package:zmz_app/domain/route_argument.dart'; // 参数
8 |
9 | class HomePage extends StatefulWidget {
10 | @override
11 | _HomePageState createState() => _HomePageState();
12 | }
13 |
14 | class _HomePageState extends State {
15 |
16 | ScrollController _scrollController = ScrollController();
17 | List _choiceList = [];
18 |
19 |
20 | void getChoice() async {
21 | List data = await Api.getChoiceList();
22 | //如果当前控件已经被注销掉,则当前控件内置状态为mounted。
23 | if (!mounted) return;
24 | setState(() {
25 | _choiceList = data;
26 | });
27 | }
28 |
29 | // 下拉刷新方法
30 | Future _handleRefresh() async {
31 | await Future.delayed(Duration(seconds: 1), () { // Future.delayed()方法可以选择延迟处理任务
32 | setState(() {
33 | getChoice();
34 | return null;
35 | });
36 | });
37 | }
38 |
39 | // 下拉加载
40 | void addListenerBottomUpdate() {
41 | _scrollController.addListener(() {
42 | // 判断是否到了最底部
43 | if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
44 | setState(() {
45 | // 加载数据
46 | _choiceList.addAll(List.generate(4, (idx) {
47 | return {
48 | "id": "c",
49 | "rate": "3.45%",
50 | "pro": "下拉理财",
51 | "rateTime": "业绩基准(年化)",
52 | "desc": "中低风险",
53 | "limitDesc": "锁定期"
54 | };
55 | }));
56 | });
57 | }
58 | });
59 | }
60 |
61 | @override
62 | void initState() {
63 | super.initState();
64 | getChoice();
65 | addListenerBottomUpdate();
66 | }
67 |
68 | @override
69 | Widget build(BuildContext context) {
70 |
71 | List _activityList = [
72 | {
73 | 'id': 'a1',
74 | 'iconSrc': Icons.access_time,
75 | 'title': '加息奖励',
76 | 'desc': '挖宝享每日加息'
77 | }, {
78 | 'id': 'a2',
79 | 'iconSrc': Icons.person_add,
80 | 'title': '邀请奖励',
81 | 'desc': '每邀1人奖80元'
82 | }
83 | ];
84 |
85 | return Scaffold(
86 | body: RefreshIndicator( // 下拉刷新
87 | onRefresh: _handleRefresh,
88 | child: ListView(
89 | controller: _scrollController,
90 | children: [
91 | _bannerWidget(),
92 | _displayDataWidget(),
93 | _activityAdWidget(activityList: _activityList, context: context),
94 | _choicenessWidget(choiceList: _choiceList, context: context)
95 | ],
96 | )
97 | )
98 | );
99 | }
100 | }
101 |
102 | Widget _bannerWidget () {
103 | // 轮播
104 | return Carousel(
105 | carouselList: List.generate(3, (idx) =>
106 | Image.asset('assets/images/banner_${idx + 1}.jpg', fit: BoxFit.fill)).toList(),
107 | tagWidth: ZFit().setWidth(375),
108 | height: ZFit().setWidth(146),
109 | tagBottom: ZFit().setWidth(8),
110 | tagColor: Colors.white12,
111 | activeTagColor: Colors.white,
112 | tagSize: ZFit().setWidth(10)
113 | );
114 | }
115 |
116 | Widget _displayDataWidget () {
117 | return Stack(
118 | children: [
119 | ConstrainedBox(
120 | constraints: BoxConstraints(
121 | minWidth: double.infinity,
122 | minHeight: ZFit().setWidth(36)
123 | ),
124 | child: Row(
125 | mainAxisAlignment: MainAxisAlignment.start,
126 | children: [
127 | Padding(
128 | padding: ZEdge.horizontal_15,
129 | child: Icon(Icons.pie_chart, color: ZColor.thinBlue, size: ZFit().setWidth(19),),
130 | ),
131 | Padding(
132 | padding: EdgeInsets.only(right: ZFit().setWidth(13)),
133 | child: Text('理财成交单',
134 | style: TextStyle(fontWeight: FontWeight.w700, color: ZColor.black, fontSize: ZFit().setSp(14), height: 0.85),
135 | ),
136 | ),
137 | Text('昨日成交163人,今日已成交57人',
138 | overflow: TextOverflow.ellipsis,
139 | style: TextStyle(color: ZColor.thinBlue, fontSize: ZFit().setSp(11)),
140 | ),
141 | ],
142 | )
143 | ),
144 | Positioned(
145 | right: ZFit().setWidth(10),
146 | top: ZFit().setWidth(7),
147 | child: Icon(Icons.keyboard_arrow_right, color: ZColor.grey,)
148 | )
149 | ],
150 | );
151 | }
152 |
153 | Widget _activityAdWidget ({context, activityList}) {
154 |
155 | void _intoActivityDetail({id}) {
156 | Navigator.pushNamed(context, "/login", arguments: RouteArguments('想从活动登陆'));
157 | }
158 |
159 | final List items = [];
160 | for (int i = 0; i < activityList.length; i++) {
161 | Map item = activityList[i];
162 | items.add(Expanded(
163 | flex: 1,
164 | child: Padding(
165 | padding: ZEdge.all_15,
166 | child: GestureDetector(
167 | child: Row(
168 | children: [
169 | new Icon(item['iconSrc'], color: Colors.blue,),
170 | Padding(
171 | padding: EdgeInsets.only(left: ZFit().setWidth(10)),
172 | child: Column(
173 | children: [
174 | Text(item['title'], style: TextStyle(color: ZColor.black, fontSize: ZFit().setSp(15))),
175 | Text(item['desc'], style: TextStyle(color: ZColor.grey, fontSize: ZFit().setSp(11)))
176 | ],
177 | ),
178 | )
179 | ],
180 | ),
181 | onTap: () => {
182 | _intoActivityDetail(id: item['id'])
183 | }
184 | )
185 | ),
186 | ));
187 | }
188 |
189 | return Flex(
190 | direction: Axis.horizontal,
191 | children: items,
192 | );
193 | }
194 |
195 | Widget _choicenessWidget ({context, List choiceList}) {
196 |
197 | void _intoChoicenessDetail({Product proInfo}) {
198 | // ZRouter.pushNamed('/product_detail', arguments: RouteArguments(proInfo));
199 | Navigator.pushNamed(context, '/product_detail', arguments: RouteArguments(proInfo));
200 | }
201 |
202 | return Padding(
203 | padding: ZEdge.horizontal_15,
204 | child: Column(
205 | children: [
206 | ConstrainedBox(
207 | constraints: BoxConstraints(
208 | minWidth: double.infinity, //宽度尽可能大
209 | minHeight: ZFit().setWidth(18)
210 | ),
211 | child: Text(
212 | '热门推荐',
213 | textAlign: TextAlign.start,
214 | style: TextStyle(fontSize: ZFit().setSp(18), fontWeight: FontWeight.w700, height: 1.5),
215 | ),
216 | ),
217 | // 使用Wrap的方式展示产品
218 | Wrap(
219 | children: choiceList.map((item) {
220 | Product _pro = Product.fromJson(item);
221 | return Container(
222 | width: ZFit().setWidth(160),
223 | margin: ZEdge.all_5,
224 | padding: ZEdge.vertical_10,
225 | decoration: BoxDecoration(
226 | border: Border.all(style: BorderStyle.solid, color: Colors.blue),
227 | borderRadius: ZRadius.all_8
228 | ),
229 | child: Column(
230 | children: [
231 | Text(_pro.name, style: TextStyle(fontSize: ZFit().setSp(16))),
232 | Text(_pro.rate, style: TextStyle(fontSize: ZFit().setSp(26), fontWeight: FontWeight.w700, color: Colors.red)),
233 | Text(_pro.rateTime, style: TextStyle(color: Colors.grey, fontSize: ZFit().setSp(12)),),
234 | Container(
235 | margin: EdgeInsets.symmetric(vertical: ZFit().setWidth(6)),
236 | padding: EdgeInsets.symmetric(horizontal: ZFit().setWidth(3)),
237 | decoration: BoxDecoration(
238 | border: Border.all(style: BorderStyle.solid, color: Colors.blue)
239 | ),
240 | child: Text(_pro.desc),
241 | ),
242 | Container(
243 | width: ZFit().setWidth(110),
244 | height: ZFit().setWidth(30),
245 | child: FlatButton(
246 | color: Colors.blue,
247 | textColor: Colors.white,
248 | splashColor: Colors.white,
249 | highlightColor: Colors.white,
250 | child: Text("存入"),
251 | shape: RoundedRectangleBorder(
252 | borderRadius: BorderRadius.circular(20.0),
253 | side: BorderSide(style: BorderStyle.solid, color: Colors.blue)
254 | ),
255 | onPressed: () => {
256 | _intoChoicenessDetail(proInfo: _pro)
257 | }
258 | )
259 | )
260 | ],
261 | ),
262 | );
263 | }).toList(),
264 | ),
265 | SizedBox(
266 | height: ZFit().setWidth(36),
267 | child: Text('已经到最底部啦...', style: TextStyle(color: Colors.grey),)
268 | )
269 | ],
270 | )
271 | );
272 | }
--------------------------------------------------------------------------------
/back-end/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "requires": true,
3 | "lockfileVersion": 1,
4 | "dependencies": {
5 | "accepts": {
6 | "version": "1.3.7",
7 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
8 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
9 | "requires": {
10 | "mime-types": "~2.1.24",
11 | "negotiator": "0.6.2"
12 | }
13 | },
14 | "any-promise": {
15 | "version": "1.3.0",
16 | "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
17 | "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
18 | },
19 | "cache-content-type": {
20 | "version": "1.0.1",
21 | "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz",
22 | "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==",
23 | "requires": {
24 | "mime-types": "^2.1.18",
25 | "ylru": "^1.2.0"
26 | }
27 | },
28 | "co": {
29 | "version": "4.6.0",
30 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
31 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
32 | },
33 | "content-disposition": {
34 | "version": "0.5.3",
35 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
36 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
37 | "requires": {
38 | "safe-buffer": "5.1.2"
39 | }
40 | },
41 | "content-type": {
42 | "version": "1.0.4",
43 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
44 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
45 | },
46 | "cookies": {
47 | "version": "0.7.3",
48 | "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.3.tgz",
49 | "integrity": "sha512-+gixgxYSgQLTaTIilDHAdlNPZDENDQernEMiIcZpYYP14zgHsCt4Ce1FEjFtcp6GefhozebB6orvhAAWx/IS0A==",
50 | "requires": {
51 | "depd": "~1.1.2",
52 | "keygrip": "~1.0.3"
53 | }
54 | },
55 | "debug": {
56 | "version": "3.1.0",
57 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
58 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
59 | "requires": {
60 | "ms": "2.0.0"
61 | }
62 | },
63 | "deep-equal": {
64 | "version": "1.0.1",
65 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
66 | "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
67 | },
68 | "delegates": {
69 | "version": "1.0.0",
70 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
71 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
72 | },
73 | "depd": {
74 | "version": "1.1.2",
75 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
76 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
77 | },
78 | "destroy": {
79 | "version": "1.0.4",
80 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
81 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
82 | },
83 | "ee-first": {
84 | "version": "1.1.1",
85 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
86 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
87 | },
88 | "error-inject": {
89 | "version": "1.0.0",
90 | "resolved": "https://registry.npmjs.org/error-inject/-/error-inject-1.0.0.tgz",
91 | "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc="
92 | },
93 | "escape-html": {
94 | "version": "1.0.3",
95 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
96 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
97 | },
98 | "fresh": {
99 | "version": "0.5.2",
100 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
101 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
102 | },
103 | "http-assert": {
104 | "version": "1.4.1",
105 | "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz",
106 | "integrity": "sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==",
107 | "requires": {
108 | "deep-equal": "~1.0.1",
109 | "http-errors": "~1.7.2"
110 | }
111 | },
112 | "http-errors": {
113 | "version": "1.7.2",
114 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
115 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
116 | "requires": {
117 | "depd": "~1.1.2",
118 | "inherits": "2.0.3",
119 | "setprototypeof": "1.1.1",
120 | "statuses": ">= 1.5.0 < 2",
121 | "toidentifier": "1.0.0"
122 | }
123 | },
124 | "inherits": {
125 | "version": "2.0.3",
126 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
127 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
128 | },
129 | "is-generator-function": {
130 | "version": "1.0.7",
131 | "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz",
132 | "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw=="
133 | },
134 | "keygrip": {
135 | "version": "1.0.3",
136 | "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.3.tgz",
137 | "integrity": "sha512-/PpesirAIfaklxUzp4Yb7xBper9MwP6hNRA6BGGUFCgbJ+BM5CKBtsoxinNXkLHAr+GXS1/lSlF2rP7cv5Fl+g=="
138 | },
139 | "koa": {
140 | "version": "2.7.0",
141 | "resolved": "https://registry.npmjs.org/koa/-/koa-2.7.0.tgz",
142 | "integrity": "sha512-7ojD05s2Q+hFudF8tDLZ1CpCdVZw8JQELWSkcfG9bdtoTDzMmkRF6BQBU7JzIzCCOY3xd3tftiy/loHBUYaY2Q==",
143 | "requires": {
144 | "accepts": "^1.3.5",
145 | "cache-content-type": "^1.0.0",
146 | "content-disposition": "~0.5.2",
147 | "content-type": "^1.0.4",
148 | "cookies": "~0.7.1",
149 | "debug": "~3.1.0",
150 | "delegates": "^1.0.0",
151 | "depd": "^1.1.2",
152 | "destroy": "^1.0.4",
153 | "error-inject": "^1.0.0",
154 | "escape-html": "^1.0.3",
155 | "fresh": "~0.5.2",
156 | "http-assert": "^1.3.0",
157 | "http-errors": "^1.6.3",
158 | "is-generator-function": "^1.0.7",
159 | "koa-compose": "^4.1.0",
160 | "koa-convert": "^1.2.0",
161 | "koa-is-json": "^1.0.0",
162 | "on-finished": "^2.3.0",
163 | "only": "~0.0.2",
164 | "parseurl": "^1.3.2",
165 | "statuses": "^1.5.0",
166 | "type-is": "^1.6.16",
167 | "vary": "^1.1.2"
168 | }
169 | },
170 | "koa-compose": {
171 | "version": "4.1.0",
172 | "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz",
173 | "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw=="
174 | },
175 | "koa-convert": {
176 | "version": "1.2.0",
177 | "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz",
178 | "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=",
179 | "requires": {
180 | "co": "^4.6.0",
181 | "koa-compose": "^3.0.0"
182 | },
183 | "dependencies": {
184 | "koa-compose": {
185 | "version": "3.2.1",
186 | "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz",
187 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=",
188 | "requires": {
189 | "any-promise": "^1.1.0"
190 | }
191 | }
192 | }
193 | },
194 | "koa-is-json": {
195 | "version": "1.0.0",
196 | "resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz",
197 | "integrity": "sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ="
198 | },
199 | "media-typer": {
200 | "version": "0.3.0",
201 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
202 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
203 | },
204 | "mime-db": {
205 | "version": "1.40.0",
206 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
207 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
208 | },
209 | "mime-types": {
210 | "version": "2.1.24",
211 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
212 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
213 | "requires": {
214 | "mime-db": "1.40.0"
215 | }
216 | },
217 | "ms": {
218 | "version": "2.0.0",
219 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
220 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
221 | },
222 | "negotiator": {
223 | "version": "0.6.2",
224 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
225 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
226 | },
227 | "on-finished": {
228 | "version": "2.3.0",
229 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
230 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
231 | "requires": {
232 | "ee-first": "1.1.1"
233 | }
234 | },
235 | "only": {
236 | "version": "0.0.2",
237 | "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz",
238 | "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q="
239 | },
240 | "parseurl": {
241 | "version": "1.3.3",
242 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
243 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
244 | },
245 | "safe-buffer": {
246 | "version": "5.1.2",
247 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
248 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
249 | },
250 | "setprototypeof": {
251 | "version": "1.1.1",
252 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
253 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
254 | },
255 | "statuses": {
256 | "version": "1.5.0",
257 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
258 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
259 | },
260 | "toidentifier": {
261 | "version": "1.0.0",
262 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
263 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
264 | },
265 | "type-is": {
266 | "version": "1.6.18",
267 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
268 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
269 | "requires": {
270 | "media-typer": "0.3.0",
271 | "mime-types": "~2.1.24"
272 | }
273 | },
274 | "vary": {
275 | "version": "1.1.2",
276 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
277 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
278 | },
279 | "ylru": {
280 | "version": "1.2.1",
281 | "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz",
282 | "integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ=="
283 | }
284 | }
285 | }
286 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
14 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
15 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
16 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
17 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
18 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
19 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
20 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
21 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
22 | /* End PBXBuildFile section */
23 |
24 | /* Begin PBXCopyFilesBuildPhase section */
25 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
26 | isa = PBXCopyFilesBuildPhase;
27 | buildActionMask = 2147483647;
28 | dstPath = "";
29 | dstSubfolderSpec = 10;
30 | files = (
31 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
32 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
33 | );
34 | name = "Embed Frameworks";
35 | runOnlyForDeploymentPostprocessing = 0;
36 | };
37 | /* End PBXCopyFilesBuildPhase section */
38 |
39 | /* Begin PBXFileReference section */
40 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
41 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
42 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
43 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
44 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
45 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
46 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
47 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
48 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
49 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
50 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
51 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
52 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
53 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
54 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
55 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
56 | /* End PBXFileReference section */
57 |
58 | /* Begin PBXFrameworksBuildPhase section */
59 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
60 | isa = PBXFrameworksBuildPhase;
61 | buildActionMask = 2147483647;
62 | files = (
63 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
64 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
65 | );
66 | runOnlyForDeploymentPostprocessing = 0;
67 | };
68 | /* End PBXFrameworksBuildPhase section */
69 |
70 | /* Begin PBXGroup section */
71 | 9740EEB11CF90186004384FC /* Flutter */ = {
72 | isa = PBXGroup;
73 | children = (
74 | 3B80C3931E831B6300D905FE /* App.framework */,
75 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
76 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
77 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
78 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
79 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
80 | );
81 | name = Flutter;
82 | sourceTree = "";
83 | };
84 | 97C146E51CF9000F007C117D = {
85 | isa = PBXGroup;
86 | children = (
87 | 9740EEB11CF90186004384FC /* Flutter */,
88 | 97C146F01CF9000F007C117D /* Runner */,
89 | 97C146EF1CF9000F007C117D /* Products */,
90 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
91 | );
92 | sourceTree = "";
93 | };
94 | 97C146EF1CF9000F007C117D /* Products */ = {
95 | isa = PBXGroup;
96 | children = (
97 | 97C146EE1CF9000F007C117D /* Runner.app */,
98 | );
99 | name = Products;
100 | sourceTree = "";
101 | };
102 | 97C146F01CF9000F007C117D /* Runner */ = {
103 | isa = PBXGroup;
104 | children = (
105 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
106 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
107 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
108 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
109 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
110 | 97C147021CF9000F007C117D /* Info.plist */,
111 | 97C146F11CF9000F007C117D /* Supporting Files */,
112 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
113 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
114 | );
115 | path = Runner;
116 | sourceTree = "";
117 | };
118 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
119 | isa = PBXGroup;
120 | children = (
121 | 97C146F21CF9000F007C117D /* main.m */,
122 | );
123 | name = "Supporting Files";
124 | sourceTree = "";
125 | };
126 | /* End PBXGroup section */
127 |
128 | /* Begin PBXNativeTarget section */
129 | 97C146ED1CF9000F007C117D /* Runner */ = {
130 | isa = PBXNativeTarget;
131 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
132 | buildPhases = (
133 | 9740EEB61CF901F6004384FC /* Run Script */,
134 | 97C146EA1CF9000F007C117D /* Sources */,
135 | 97C146EB1CF9000F007C117D /* Frameworks */,
136 | 97C146EC1CF9000F007C117D /* Resources */,
137 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
138 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
139 | );
140 | buildRules = (
141 | );
142 | dependencies = (
143 | );
144 | name = Runner;
145 | productName = Runner;
146 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
147 | productType = "com.apple.product-type.application";
148 | };
149 | /* End PBXNativeTarget section */
150 |
151 | /* Begin PBXProject section */
152 | 97C146E61CF9000F007C117D /* Project object */ = {
153 | isa = PBXProject;
154 | attributes = {
155 | LastUpgradeCheck = 0910;
156 | ORGANIZATIONNAME = "The Chromium Authors";
157 | TargetAttributes = {
158 | 97C146ED1CF9000F007C117D = {
159 | CreatedOnToolsVersion = 7.3.1;
160 | };
161 | };
162 | };
163 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
164 | compatibilityVersion = "Xcode 3.2";
165 | developmentRegion = English;
166 | hasScannedForEncodings = 0;
167 | knownRegions = (
168 | en,
169 | Base,
170 | );
171 | mainGroup = 97C146E51CF9000F007C117D;
172 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
173 | projectDirPath = "";
174 | projectRoot = "";
175 | targets = (
176 | 97C146ED1CF9000F007C117D /* Runner */,
177 | );
178 | };
179 | /* End PBXProject section */
180 |
181 | /* Begin PBXResourcesBuildPhase section */
182 | 97C146EC1CF9000F007C117D /* Resources */ = {
183 | isa = PBXResourcesBuildPhase;
184 | buildActionMask = 2147483647;
185 | files = (
186 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
187 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
188 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
189 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
190 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
191 | );
192 | runOnlyForDeploymentPostprocessing = 0;
193 | };
194 | /* End PBXResourcesBuildPhase section */
195 |
196 | /* Begin PBXShellScriptBuildPhase section */
197 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
198 | isa = PBXShellScriptBuildPhase;
199 | buildActionMask = 2147483647;
200 | files = (
201 | );
202 | inputPaths = (
203 | );
204 | name = "Thin Binary";
205 | outputPaths = (
206 | );
207 | runOnlyForDeploymentPostprocessing = 0;
208 | shellPath = /bin/sh;
209 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
210 | };
211 | 9740EEB61CF901F6004384FC /* Run Script */ = {
212 | isa = PBXShellScriptBuildPhase;
213 | buildActionMask = 2147483647;
214 | files = (
215 | );
216 | inputPaths = (
217 | );
218 | name = "Run Script";
219 | outputPaths = (
220 | );
221 | runOnlyForDeploymentPostprocessing = 0;
222 | shellPath = /bin/sh;
223 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
224 | };
225 | /* End PBXShellScriptBuildPhase section */
226 |
227 | /* Begin PBXSourcesBuildPhase section */
228 | 97C146EA1CF9000F007C117D /* Sources */ = {
229 | isa = PBXSourcesBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
233 | 97C146F31CF9000F007C117D /* main.m in Sources */,
234 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
235 | );
236 | runOnlyForDeploymentPostprocessing = 0;
237 | };
238 | /* End PBXSourcesBuildPhase section */
239 |
240 | /* Begin PBXVariantGroup section */
241 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
242 | isa = PBXVariantGroup;
243 | children = (
244 | 97C146FB1CF9000F007C117D /* Base */,
245 | );
246 | name = Main.storyboard;
247 | sourceTree = "";
248 | };
249 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
250 | isa = PBXVariantGroup;
251 | children = (
252 | 97C147001CF9000F007C117D /* Base */,
253 | );
254 | name = LaunchScreen.storyboard;
255 | sourceTree = "";
256 | };
257 | /* End PBXVariantGroup section */
258 |
259 | /* Begin XCBuildConfiguration section */
260 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
261 | isa = XCBuildConfiguration;
262 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
263 | buildSettings = {
264 | ALWAYS_SEARCH_USER_PATHS = NO;
265 | CLANG_ANALYZER_NONNULL = YES;
266 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
267 | CLANG_CXX_LIBRARY = "libc++";
268 | CLANG_ENABLE_MODULES = YES;
269 | CLANG_ENABLE_OBJC_ARC = YES;
270 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
271 | CLANG_WARN_BOOL_CONVERSION = YES;
272 | CLANG_WARN_COMMA = YES;
273 | CLANG_WARN_CONSTANT_CONVERSION = YES;
274 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
275 | CLANG_WARN_EMPTY_BODY = YES;
276 | CLANG_WARN_ENUM_CONVERSION = YES;
277 | CLANG_WARN_INFINITE_RECURSION = YES;
278 | CLANG_WARN_INT_CONVERSION = YES;
279 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
280 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
281 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
282 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
283 | CLANG_WARN_STRICT_PROTOTYPES = YES;
284 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
285 | CLANG_WARN_UNREACHABLE_CODE = YES;
286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
287 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
288 | COPY_PHASE_STRIP = NO;
289 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
290 | ENABLE_NS_ASSERTIONS = NO;
291 | ENABLE_STRICT_OBJC_MSGSEND = YES;
292 | GCC_C_LANGUAGE_STANDARD = gnu99;
293 | GCC_NO_COMMON_BLOCKS = YES;
294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
296 | GCC_WARN_UNDECLARED_SELECTOR = YES;
297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
298 | GCC_WARN_UNUSED_FUNCTION = YES;
299 | GCC_WARN_UNUSED_VARIABLE = YES;
300 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
301 | MTL_ENABLE_DEBUG_INFO = NO;
302 | SDKROOT = iphoneos;
303 | TARGETED_DEVICE_FAMILY = "1,2";
304 | VALIDATE_PRODUCT = YES;
305 | };
306 | name = Profile;
307 | };
308 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
309 | isa = XCBuildConfiguration;
310 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
311 | buildSettings = {
312 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
313 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
314 | DEVELOPMENT_TEAM = S8QB4VV633;
315 | ENABLE_BITCODE = NO;
316 | FRAMEWORK_SEARCH_PATHS = (
317 | "$(inherited)",
318 | "$(PROJECT_DIR)/Flutter",
319 | );
320 | INFOPLIST_FILE = Runner/Info.plist;
321 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
322 | LIBRARY_SEARCH_PATHS = (
323 | "$(inherited)",
324 | "$(PROJECT_DIR)/Flutter",
325 | );
326 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterApp;
327 | PRODUCT_NAME = "$(TARGET_NAME)";
328 | VERSIONING_SYSTEM = "apple-generic";
329 | };
330 | name = Profile;
331 | };
332 | 97C147031CF9000F007C117D /* Debug */ = {
333 | isa = XCBuildConfiguration;
334 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
335 | buildSettings = {
336 | ALWAYS_SEARCH_USER_PATHS = NO;
337 | CLANG_ANALYZER_NONNULL = YES;
338 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
339 | CLANG_CXX_LIBRARY = "libc++";
340 | CLANG_ENABLE_MODULES = YES;
341 | CLANG_ENABLE_OBJC_ARC = YES;
342 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
343 | CLANG_WARN_BOOL_CONVERSION = YES;
344 | CLANG_WARN_COMMA = YES;
345 | CLANG_WARN_CONSTANT_CONVERSION = YES;
346 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
347 | CLANG_WARN_EMPTY_BODY = YES;
348 | CLANG_WARN_ENUM_CONVERSION = YES;
349 | CLANG_WARN_INFINITE_RECURSION = YES;
350 | CLANG_WARN_INT_CONVERSION = YES;
351 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
352 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
353 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
354 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
355 | CLANG_WARN_STRICT_PROTOTYPES = YES;
356 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
357 | CLANG_WARN_UNREACHABLE_CODE = YES;
358 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
359 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
360 | COPY_PHASE_STRIP = NO;
361 | DEBUG_INFORMATION_FORMAT = dwarf;
362 | ENABLE_STRICT_OBJC_MSGSEND = YES;
363 | ENABLE_TESTABILITY = YES;
364 | GCC_C_LANGUAGE_STANDARD = gnu99;
365 | GCC_DYNAMIC_NO_PIC = NO;
366 | GCC_NO_COMMON_BLOCKS = YES;
367 | GCC_OPTIMIZATION_LEVEL = 0;
368 | GCC_PREPROCESSOR_DEFINITIONS = (
369 | "DEBUG=1",
370 | "$(inherited)",
371 | );
372 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
373 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
374 | GCC_WARN_UNDECLARED_SELECTOR = YES;
375 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
376 | GCC_WARN_UNUSED_FUNCTION = YES;
377 | GCC_WARN_UNUSED_VARIABLE = YES;
378 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
379 | MTL_ENABLE_DEBUG_INFO = YES;
380 | ONLY_ACTIVE_ARCH = YES;
381 | SDKROOT = iphoneos;
382 | TARGETED_DEVICE_FAMILY = "1,2";
383 | };
384 | name = Debug;
385 | };
386 | 97C147041CF9000F007C117D /* Release */ = {
387 | isa = XCBuildConfiguration;
388 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
389 | buildSettings = {
390 | ALWAYS_SEARCH_USER_PATHS = NO;
391 | CLANG_ANALYZER_NONNULL = YES;
392 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
393 | CLANG_CXX_LIBRARY = "libc++";
394 | CLANG_ENABLE_MODULES = YES;
395 | CLANG_ENABLE_OBJC_ARC = YES;
396 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
397 | CLANG_WARN_BOOL_CONVERSION = YES;
398 | CLANG_WARN_COMMA = YES;
399 | CLANG_WARN_CONSTANT_CONVERSION = YES;
400 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
401 | CLANG_WARN_EMPTY_BODY = YES;
402 | CLANG_WARN_ENUM_CONVERSION = YES;
403 | CLANG_WARN_INFINITE_RECURSION = YES;
404 | CLANG_WARN_INT_CONVERSION = YES;
405 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
406 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
407 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
408 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
409 | CLANG_WARN_STRICT_PROTOTYPES = YES;
410 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
411 | CLANG_WARN_UNREACHABLE_CODE = YES;
412 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
413 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
414 | COPY_PHASE_STRIP = NO;
415 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
416 | ENABLE_NS_ASSERTIONS = NO;
417 | ENABLE_STRICT_OBJC_MSGSEND = YES;
418 | GCC_C_LANGUAGE_STANDARD = gnu99;
419 | GCC_NO_COMMON_BLOCKS = YES;
420 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
421 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
422 | GCC_WARN_UNDECLARED_SELECTOR = YES;
423 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
424 | GCC_WARN_UNUSED_FUNCTION = YES;
425 | GCC_WARN_UNUSED_VARIABLE = YES;
426 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
427 | MTL_ENABLE_DEBUG_INFO = NO;
428 | SDKROOT = iphoneos;
429 | TARGETED_DEVICE_FAMILY = "1,2";
430 | VALIDATE_PRODUCT = YES;
431 | };
432 | name = Release;
433 | };
434 | 97C147061CF9000F007C117D /* Debug */ = {
435 | isa = XCBuildConfiguration;
436 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
437 | buildSettings = {
438 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
439 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
440 | ENABLE_BITCODE = NO;
441 | FRAMEWORK_SEARCH_PATHS = (
442 | "$(inherited)",
443 | "$(PROJECT_DIR)/Flutter",
444 | );
445 | INFOPLIST_FILE = Runner/Info.plist;
446 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
447 | LIBRARY_SEARCH_PATHS = (
448 | "$(inherited)",
449 | "$(PROJECT_DIR)/Flutter",
450 | );
451 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterApp;
452 | PRODUCT_NAME = "$(TARGET_NAME)";
453 | VERSIONING_SYSTEM = "apple-generic";
454 | };
455 | name = Debug;
456 | };
457 | 97C147071CF9000F007C117D /* Release */ = {
458 | isa = XCBuildConfiguration;
459 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
460 | buildSettings = {
461 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
462 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
463 | ENABLE_BITCODE = NO;
464 | FRAMEWORK_SEARCH_PATHS = (
465 | "$(inherited)",
466 | "$(PROJECT_DIR)/Flutter",
467 | );
468 | INFOPLIST_FILE = Runner/Info.plist;
469 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
470 | LIBRARY_SEARCH_PATHS = (
471 | "$(inherited)",
472 | "$(PROJECT_DIR)/Flutter",
473 | );
474 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterApp;
475 | PRODUCT_NAME = "$(TARGET_NAME)";
476 | VERSIONING_SYSTEM = "apple-generic";
477 | };
478 | name = Release;
479 | };
480 | /* End XCBuildConfiguration section */
481 |
482 | /* Begin XCConfigurationList section */
483 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
484 | isa = XCConfigurationList;
485 | buildConfigurations = (
486 | 97C147031CF9000F007C117D /* Debug */,
487 | 97C147041CF9000F007C117D /* Release */,
488 | 249021D3217E4FDB00AE95B9 /* Profile */,
489 | );
490 | defaultConfigurationIsVisible = 0;
491 | defaultConfigurationName = Release;
492 | };
493 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
494 | isa = XCConfigurationList;
495 | buildConfigurations = (
496 | 97C147061CF9000F007C117D /* Debug */,
497 | 97C147071CF9000F007C117D /* Release */,
498 | 249021D4217E4FDB00AE95B9 /* Profile */,
499 | );
500 | defaultConfigurationIsVisible = 0;
501 | defaultConfigurationName = Release;
502 | };
503 | /* End XCConfigurationList section */
504 | };
505 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
506 | }
507 |
--------------------------------------------------------------------------------