├── lib ├── bloc │ ├── home │ │ └── home_bloc.dart │ ├── main_bloc.dart │ ├── theme_bloc.dart │ └── payment │ │ └── payment_bloc.dart ├── domain │ ├── route_argument.dart │ ├── metadata.dart │ └── product_domain.dart ├── main.dart ├── main_dev.dart ├── main_test.dart ├── compose │ └── compose.dart ├── styles │ ├── color_style.dart │ ├── radius_style.dart │ └── edge_style.dart ├── service │ ├── api.dart │ └── service.dart ├── config │ └── base_info.dart ├── routes │ └── z_router.dart ├── utils │ ├── provider.dart │ ├── storage.dart │ ├── center_nav.dart │ ├── event_bus.dart │ ├── z_fit.dart │ └── update_app.dart ├── view │ ├── user-info │ │ ├── shop_list.dart │ │ └── user_assert.dart │ ├── common │ │ ├── search_bar.dart │ │ └── my_search.dart │ └── bank_product.dart ├── page │ ├── treasure │ │ ├── selection │ │ │ ├── dealer_selection_page.dart │ │ │ ├── fund_selection_page.dart │ │ │ └── bank_selection_page.dart │ │ └── treasure_page.dart │ ├── payment │ │ └── payment_page.dart │ ├── manager_page.dart │ ├── welcome │ │ └── splash_page.dart │ ├── login │ │ └── login_page.dart │ ├── nav_page.dart │ ├── news │ │ └── news_page.dart │ ├── product │ │ └── product_details_page.dart │ ├── customer │ │ └── customer_page.dart │ └── home │ │ └── home_page.dart ├── plugin │ ├── toast.dart │ ├── loading.dart │ └── carousel.dart └── app.dart ├── web └── index.html ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ ├── flutter_export_environment.sh │ └── AppFrameworkInfo.plist ├── Runner │ ├── AppDelegate.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── 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-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── main.m │ ├── AppDelegate.m │ ├── Info.plist │ └── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner.xcodeproj │ ├── project.xcworkspace │ └── contents.xcworkspacedata │ ├── xcshareddata │ └── xcschemes │ │ └── Runner.xcscheme │ └── project.pbxproj ├── android ├── gradle.properties ├── .settings │ └── org.eclipse.buildship.core.prefs ├── app │ ├── .settings │ │ └── org.eclipse.buildship.core.prefs │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── 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 │ │ │ │ └── drawable │ │ │ │ │ └── launch_background.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── flutter_app │ │ │ │ │ └── MainActivity.java │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── .classpath │ ├── .project │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .project ├── settings.gradle └── build.gradle ├── preview ├── 00.png ├── 11.png ├── 22.png ├── 33.png ├── 44.png ├── 55.png ├── 66.png ├── 77.png ├── 88.png ├── 99.png ├── meihong1.jpg ├── reorder1.gif ├── search1.gif └── update1.gif ├── assets └── images │ ├── logo.jpg │ ├── news.jpg │ ├── banner_1.jpg │ ├── banner_2.jpg │ ├── banner_3.jpg │ ├── projector.png │ ├── One-Piece │ ├── 0.jpg │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.jpg │ └── 9.jpg │ └── red_envelope.jpg ├── .github └── ISSUE_TEMPLATE │ ├── custom.md │ ├── feature_request.md │ └── bug_report.md ├── back-end ├── mock │ ├── user_info.js │ ├── choice_list.js │ └── bank_product_list.js ├── router.js ├── package.json ├── server.js └── package-lock.json ├── .metadata ├── test └── widget_test.dart ├── .gitignore ├── README.md ├── pubspec.yaml └── pubspec.lock /lib/bloc/home/home_bloc.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | -------------------------------------------------------------------------------- /preview/00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/00.png -------------------------------------------------------------------------------- /preview/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/11.png -------------------------------------------------------------------------------- /preview/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/22.png -------------------------------------------------------------------------------- /preview/33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/33.png -------------------------------------------------------------------------------- /preview/44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/44.png -------------------------------------------------------------------------------- /preview/55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/55.png -------------------------------------------------------------------------------- /preview/66.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/66.png -------------------------------------------------------------------------------- /preview/77.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/77.png -------------------------------------------------------------------------------- /preview/88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/88.png -------------------------------------------------------------------------------- /preview/99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/99.png -------------------------------------------------------------------------------- /preview/meihong1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/meihong1.jpg -------------------------------------------------------------------------------- /preview/reorder1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/reorder1.gif -------------------------------------------------------------------------------- /preview/search1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/search1.gif -------------------------------------------------------------------------------- /preview/update1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/preview/update1.gif -------------------------------------------------------------------------------- /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /assets/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/logo.jpg -------------------------------------------------------------------------------- /assets/images/news.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/news.jpg -------------------------------------------------------------------------------- /android/app/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /assets/images/banner_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/banner_1.jpg -------------------------------------------------------------------------------- /assets/images/banner_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/banner_2.jpg -------------------------------------------------------------------------------- /assets/images/banner_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/banner_3.jpg -------------------------------------------------------------------------------- /assets/images/projector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/projector.png -------------------------------------------------------------------------------- /assets/images/One-Piece/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/0.jpg -------------------------------------------------------------------------------- /assets/images/One-Piece/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/1.jpg -------------------------------------------------------------------------------- /assets/images/One-Piece/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/2.jpg -------------------------------------------------------------------------------- /assets/images/One-Piece/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/3.jpg -------------------------------------------------------------------------------- /assets/images/One-Piece/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/4.jpg -------------------------------------------------------------------------------- /assets/images/One-Piece/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/5.jpg -------------------------------------------------------------------------------- /assets/images/One-Piece/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/6.jpg -------------------------------------------------------------------------------- /assets/images/One-Piece/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/7.jpg -------------------------------------------------------------------------------- /assets/images/One-Piece/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/8.jpg -------------------------------------------------------------------------------- /assets/images/One-Piece/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/One-Piece/9.jpg -------------------------------------------------------------------------------- /assets/images/red_envelope.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/assets/images/red_envelope.jpg -------------------------------------------------------------------------------- /lib/domain/route_argument.dart: -------------------------------------------------------------------------------- 1 | 2 | class RouteArguments { 3 | final T args; 4 | 5 | RouteArguments(this.args); 6 | } -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/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/zhongmeizhi/fultter-example-app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:zmz_app/app.dart'; 2 | import 'package:zmz_app/compose/compose.dart'; 3 | import 'package:zmz_app/config/base_info.dart'; 4 | 5 | void main() => runApp(MyApp(Env.prod)); 6 | -------------------------------------------------------------------------------- /lib/main_dev.dart: -------------------------------------------------------------------------------- 1 | import 'package:zmz_app/app.dart'; 2 | import 'package:zmz_app/compose/compose.dart'; 3 | import 'package:zmz_app/config/base_info.dart'; 4 | 5 | void main() => runApp(MyApp(Env.dev)); 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhongmeizhi/fultter-example-app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /lib/main_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:zmz_app/app.dart'; 2 | import 'package:zmz_app/compose/compose.dart'; 3 | import 'package:zmz_app/config/base_info.dart'; 4 | 5 | void main() => runApp(MyApp(Env.test)); 6 | -------------------------------------------------------------------------------- /lib/domain/metadata.dart: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | 页面注解 4 | 利用元数据实现 5 | 目前Flutter无法使用dart:mirrors获取注解的东西。暂时没太大用处 6 | */ 7 | class ZMeta { 8 | final String message; 9 | 10 | const ZMeta(this.message); 11 | } -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /back-end/mock/user_info.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | result: { 3 | 'name': '蘑菇碳', 4 | 'money': '33,214,617.35', 5 | 'profit': '21301.32', 6 | 'midway': '253888.33' 7 | }, 8 | code: '000' 9 | } -------------------------------------------------------------------------------- /back-end/router.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | '/choice-list': require('./mock/choice_list.js'), 4 | '/bank_product_list': require('./mock/bank_product_list.js'), 5 | '/user-info': require('./mock/user_info.js'), 6 | } -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /lib/compose/compose.dart: -------------------------------------------------------------------------------- 1 | library compose; 2 | 3 | export 'package:flutter/material.dart'; 4 | export 'package:zmz_app/utils/z_fit.dart'; 5 | export 'package:zmz_app/styles/color_style.dart'; 6 | export 'package:zmz_app/styles/edge_style.dart'; 7 | export 'package:zmz_app/styles/radius_style.dart'; 8 | export 'package:zmz_app/domain/metadata.dart'; 9 | -------------------------------------------------------------------------------- /.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: 8661d8aecd626f7f57ccbcb735553edc05a2e713 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /android/app/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /back-end/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xxx", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "router.js", 6 | "dependencies": { 7 | "koa": "^2.7.0" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "start": "node server.js" 13 | }, 14 | "author": "", 15 | "license": "ISC" 16 | } 17 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /lib/styles/color_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ZColor { 4 | 5 | static Color get defaultBackground => Color(0xFFf7f7f7); 6 | 7 | static Color get black => Color(0xFF333333); 8 | 9 | static Color get red => Color(0xFFED4E39); 10 | 11 | static Color get grey => Color(0xFFB8B8B8); 12 | static Color get thinGrey => Color(0xFFf6f6f6); 13 | 14 | static Color get thinBlue => Color(0xFF5ca0fd); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/example/flutter_app/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.zmz_app; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/domain/product_domain.dart: -------------------------------------------------------------------------------- 1 | class Product { 2 | String id = ''; 3 | String rate = ''; 4 | String name = ''; 5 | String rateTime = ''; 6 | String desc = ''; 7 | String limitDesc = ''; 8 | 9 | Product(); 10 | 11 | Product.fromJson(Map json) { 12 | this.id = json['id']; 13 | this.rate = json['rate']; 14 | this.name = json['pro']; 15 | this.rateTime = json['rateTime']; 16 | this.desc = json['desc']; 17 | this.limitDesc = json['limitDesc']; 18 | } 19 | } -------------------------------------------------------------------------------- /lib/service/api.dart: -------------------------------------------------------------------------------- 1 | import 'package:zmz_app/service/service.dart'; 2 | 3 | class Api { 4 | 5 | // 获取用户信息 6 | static Function get getUserInfo => (phone) => service.fetch('/user-info?phone=$phone', isShowLoading: true); 7 | 8 | // 获取 热门推荐 9 | static Function get getChoiceList => () => service.fetch('/choice-list', isShowLoading: true); 10 | 11 | // 获取 银行精选 12 | static Function get getBankProductList => () => service.fetch('/bank_product_list', isShowLoading: true); 13 | 14 | } -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /lib/bloc/main_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | 3 | enum CounterEvent { increment, decrement } 4 | 5 | class CounterBloc extends Bloc { 6 | @override 7 | int get initialState => 0; 8 | 9 | @override 10 | Stream mapEventToState(CounterEvent event) async* { 11 | switch (event) { 12 | case CounterEvent.decrement: 13 | yield currentState - 1; 14 | break; 15 | case CounterEvent.increment: 16 | yield currentState + 1; 17 | break; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=C:\Users\zmz\Downloads\flutter" 4 | export "FLUTTER_APPLICATION_PATH=C:\Users\zmz\AndroidStudioProjects\fultter-example-app" 5 | export "FLUTTER_TARGET=lib\main.dart" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "SYMROOT=${SOURCE_ROOT}/../build\ios" 8 | export "FLUTTER_FRAMEWORK_DIR=C:\Users\zmz\Downloads\flutter\bin\cache\artifacts\engine\ios" 9 | export "FLUTTER_BUILD_NAME=1.0.0" 10 | export "FLUTTER_BUILD_NUMBER=1" 11 | -------------------------------------------------------------------------------- /lib/bloc/theme_bloc.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:zmz_app/compose/compose.dart'; 3 | import 'package:bloc/bloc.dart'; 4 | 5 | enum ThemeEvent { toggle } 6 | 7 | class ThemeBloc extends Bloc { 8 | @override 9 | ThemeData get initialState => ThemeData.light(); 10 | 11 | @override 12 | Stream mapEventToState(ThemeEvent event) async* { 13 | switch (event) { 14 | case ThemeEvent.toggle: 15 | yield currentState == ThemeData.light() 16 | ? ThemeData.dark() 17 | : ThemeData.light(); 18 | break; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lib/styles/radius_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:zmz_app/utils/z_fit.dart'; 3 | 4 | class ZRadius { 5 | 6 | static BorderRadius get all_3 => BorderRadius.all(Radius.circular(ZFit().setWidth(3))); 7 | 8 | static BorderRadius get all_5 => BorderRadius.all(Radius.circular(ZFit().setWidth(5))); 9 | 10 | static BorderRadius get all_8 => BorderRadius.all(Radius.circular(ZFit().setWidth(8))); 11 | 12 | static BorderRadius get all_10 => BorderRadius.all(Radius.circular(ZFit().setWidth(10))); 13 | 14 | static BorderRadius get all_15 => BorderRadius.all(Radius.circular(ZFit().setWidth(15))); 15 | 16 | } -------------------------------------------------------------------------------- /back-end/server.js: -------------------------------------------------------------------------------- 1 | const Koa = require('koa'); 2 | const app = new Koa(); 3 | 4 | const router = require('./router.js'); 5 | 6 | app.use(ctx => { 7 | const _path = ctx.request.path; 8 | let _data = router[_path]; 9 | if (_data) { 10 | console.log('获取:' + _path); 11 | ctx.response.body = _data; 12 | } else { 13 | ctx.response.body = { 14 | data: {}, 15 | status: 'fail' 16 | }; 17 | } 18 | }); 19 | 20 | app.listen(2333, function() { 21 | console.log('---------------------------'); 22 | console.log('运行 2333 端口'); 23 | console.log('---------------------------'); 24 | }); -------------------------------------------------------------------------------- /android/app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /lib/config/base_info.dart: -------------------------------------------------------------------------------- 1 | enum Env { 2 | dev, 3 | test, 4 | prod 5 | } 6 | 7 | enum ZPlatform { 8 | ios, 9 | android 10 | } 11 | 12 | class Config { 13 | 14 | // 模拟器的浏览器中输入127.0.0.1所代表的是Android模拟器 15 | static String get baseUrl => 'http://10.93.157.7:2333'; 16 | 17 | // app版本 18 | static String get version => '1.0.0'; 19 | 20 | 21 | /* 22 | * 环境 23 | */ 24 | static Env _env; // 私有 25 | static Env get env => _env; // 暴露get 26 | static set setEnv(Env env) => _env = env; // 暴露set 27 | 28 | /* 29 | 平台 30 | */ 31 | static ZPlatform _platform; 32 | static ZPlatform get platform => _platform; 33 | static set setPlatform(ZPlatform p) => _platform = p; 34 | 35 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /lib/bloc/payment/payment_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | 3 | // decrement 4 | enum PaymentNumEvent { increment, reset, setVal } 5 | 6 | 7 | class PaymentNumBloc extends Bloc { 8 | 9 | int _initNum = 1; 10 | 11 | @override 12 | int get initialState => _initNum; 13 | 14 | @override 15 | Stream mapEventToState(PaymentNumEvent event, [args]) async* { 16 | switch (event) { 17 | case PaymentNumEvent.reset: 18 | yield _initNum; 19 | break; 20 | case PaymentNumEvent.increment: 21 | yield currentState + 1; 22 | break; 23 | case PaymentNumEvent.setVal: 24 | yield args; 25 | break; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /lib/routes/z_router.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:zmz_app/compose/compose.dart'; 3 | import 'package:zmz_app/domain/route_argument.dart'; 4 | import 'package:zmz_app/page/login/login_page.dart'; 5 | import 'package:zmz_app/page/nav_page.dart'; 6 | import 'package:zmz_app/page/product/product_details_page.dart'; 7 | import 'package:zmz_app/page/welcome/splash_page.dart'; 8 | 9 | class ZRouter { 10 | 11 | static BuildContext _context; 12 | static BuildContext get context => _context; 13 | static set setContext(_c) => _context = _c; 14 | 15 | 16 | // SPA 路由表 17 | static Map get routerStore => { 18 | '/': SplashPage(), 19 | '/main_page': NavPage(), 20 | '/login': LoginPage(), 21 | '/product_detail': ProductDetailsPage() 22 | }; 23 | 24 | 25 | /* 26 | 获取页面参数 27 | @context 28 | @defaultData 29 | */ 30 | static T getPageArguments(context, defaultData) { 31 | RouteArguments _args = ModalRoute.of(context).settings.arguments ?? RouteArguments(defaultData); 32 | return _args.args; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | maven{ url 'https://maven.aliyun.com/repository/google'} 4 | maven{ url 'https://maven.aliyun.com/repository/gradle-plugin'} 5 | maven{ url 'https://maven.aliyun.com/repository/public'} 6 | maven{ url 'https://maven.aliyun.com/repository/jcenter'} 7 | google() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.2.1' 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | maven{ url 'https://maven.aliyun.com/repository/google'} 19 | maven{ url 'https://maven.aliyun.com/repository/gradle-plugin'} 20 | maven{ url 'https://maven.aliyun.com/repository/public'} 21 | maven{ url 'https://maven.aliyun.com/repository/jcenter'} 22 | google() 23 | jcenter() 24 | } 25 | } 26 | 27 | rootProject.buildDir = '../build' 28 | subprojects { 29 | project.buildDir = "${rootProject.buildDir}/${project.name}" 30 | } 31 | subprojects { 32 | project.evaluationDependsOn(':app') 33 | } 34 | 35 | task clean(type: Delete) { 36 | delete rootProject.buildDir 37 | } 38 | -------------------------------------------------------------------------------- /lib/utils/provider.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter/material.dart'; 2 | 3 | // // 必须被重写的抽象接口 4 | // abstract class BlocBase { 5 | // void dispose(); 6 | // } 7 | 8 | // // Provider 9 | // class BlocProvider extends StatefulWidget { 10 | // final T bloc; 11 | // final Widget child; 12 | 13 | // BlocProvider({ 14 | // Key key, 15 | // @required this.child, 16 | // @required this.bloc, 17 | // }): super(key: key); 18 | 19 | // static T of(BuildContext context){ 20 | 21 | // final type = _typeOf>(); 22 | // BlocProvider provider = context.ancestorWidgetOfExactType(type); 23 | // return provider.bloc; 24 | // } 25 | 26 | // static Type _typeOf() => T; 27 | 28 | // @override 29 | // _BlocProviderState createState() => _BlocProviderState(); 30 | 31 | // } 32 | 33 | // class _BlocProviderState extends State>{ 34 | // @override 35 | // void dispose(){ 36 | // widget.bloc.dispose(); 37 | // super.dispose(); 38 | // } 39 | 40 | // @override 41 | // Widget build(BuildContext context){ 42 | // return widget.child; 43 | // } 44 | // } -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | import 'package:zmz_app/app.dart'; 11 | import 'package:zmz_app/config/base_info.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp(Env.test)); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /lib/utils/storage.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | // 增、改 4 | // sharedPreferences.setString(key, value); 5 | // 删 6 | // sharedPreferences.remove(key); 7 | // 查 8 | // sharedPreferences.get(key); 9 | 10 | class LocalStorage { 11 | 12 | static Future getString(String key) async { 13 | SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); 14 | return sharedPreferences.getString(key); 15 | } 16 | 17 | static Future setString(String key, String value) async { 18 | SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); 19 | sharedPreferences.setString(key, value); 20 | } 21 | 22 | static Future getBool(String key) async { 23 | SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); 24 | return sharedPreferences.getBool(key); 25 | } 26 | 27 | static Future setBool(String key, bool value) async { 28 | SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); 29 | sharedPreferences.setBool(key, value); 30 | } 31 | 32 | static Future remove(String key) async { 33 | SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); 34 | sharedPreferences.remove(key); 35 | } 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /lib/view/user-info/shop_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:zmz_app/compose/compose.dart'; 2 | 3 | // 用户产品清单 4 | class ShopListWidget extends StatelessWidget { 5 | 6 | // String title; 7 | // String subtitle; 8 | // ShopListWidget({@required this.title, @required this.subtitle}); 9 | 10 | Widget _shoppingUnitWidget ({@required title, @required subtitle}) { 11 | return Container( 12 | width: ZFit().setWidth(174), 13 | child: ListTile( 14 | title: Text(title), 15 | subtitle: Text(subtitle), 16 | ), 17 | ); 18 | } 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Column( 23 | children: [ 24 | Wrap( 25 | alignment: WrapAlignment.start, 26 | children: [ 27 | _shoppingUnitWidget(title: '零钱理财', subtitle: '53412.21元'), 28 | _shoppingUnitWidget(title: '期限理财', subtitle: '346342.21元'), 29 | _shoppingUnitWidget(title: '网贷', subtitle: '233523.21元'), 30 | _shoppingUnitWidget(title: '基金', subtitle: '5476.21元'), 31 | _shoppingUnitWidget(title: '养老', subtitle: '949764.21元'), 32 | _shoppingUnitWidget(title: '银行精选', subtitle: '23416.21元'), 33 | _shoppingUnitWidget(title: '私募', subtitle: '756423.21元'), 34 | _shoppingUnitWidget(title: '资产管理', subtitle: '645212.21元'), 35 | ], 36 | ) 37 | ], 38 | ); 39 | } 40 | } -------------------------------------------------------------------------------- /lib/styles/edge_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:zmz_app/utils/z_fit.dart'; 3 | 4 | class ZEdge { 5 | 6 | static EdgeInsets get all_5 => EdgeInsets.all(ZFit().setWidth(5)); 7 | static EdgeInsets get all_8 => EdgeInsets.all(ZFit().setWidth(8)); 8 | static EdgeInsets get all_10 => EdgeInsets.all(ZFit().setWidth(10)); 9 | static EdgeInsets get all_15 => EdgeInsets.all(ZFit().setWidth(15)); 10 | 11 | // 水平方向 12 | static EdgeInsets get horizontal_5 => EdgeInsets.symmetric(horizontal: ZFit().setWidth(5)); 13 | static EdgeInsets get horizontal_8 => EdgeInsets.symmetric(horizontal: ZFit().setWidth(8)); 14 | static EdgeInsets get horizontal_10 => EdgeInsets.symmetric(horizontal: ZFit().setWidth(10)); 15 | static EdgeInsets get horizontal_15 => EdgeInsets.symmetric(horizontal: ZFit().setWidth(15)); 16 | static EdgeInsets get horizontal_20 => EdgeInsets.symmetric(horizontal: ZFit().setWidth(20)); 17 | 18 | // 垂直方向 19 | static EdgeInsets get vertical_5 => EdgeInsets.symmetric(vertical: ZFit().setWidth(5)); 20 | static EdgeInsets get vertical_8 => EdgeInsets.symmetric(vertical: ZFit().setWidth(8)); 21 | static EdgeInsets get vertical_10 => EdgeInsets.symmetric(vertical: ZFit().setWidth(10)); 22 | static EdgeInsets get vertical_15 => EdgeInsets.symmetric(vertical: ZFit().setWidth(15)); 23 | static EdgeInsets get vertical_20 => EdgeInsets.symmetric(vertical: ZFit().setWidth(20)); 24 | 25 | } -------------------------------------------------------------------------------- /back-end/mock/choice_list.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | code: '000', 3 | result: [ 4 | { 5 | "id": "c1", 6 | "rate": "4.32%", 7 | "pro": "招招利", 8 | "rateTime": "业绩基准(年化)", 9 | "desc": "中低风险", 10 | "limitDesc": "10元起投" 11 | }, 12 | { 13 | "id": "c2", 14 | "rate": "4.21%", 15 | "pro": "农加利", 16 | "rateTime": "业绩基准(年化)", 17 | "desc": "中低风险", 18 | "limitDesc": "锁定期" 19 | }, 20 | { 21 | "id": "c3", 22 | "rate": "5.55%", 23 | "pro": "宇宙行理财", 24 | "rateTime": "业绩基准(年化)", 25 | "desc": "中低风险", 26 | "limitDesc": "锁定期1天" 27 | }, 28 | { 29 | "id": "c4", 30 | "rate": "3.66%", 31 | "pro": "小招理财", 32 | "rateTime": "保本收益率", 33 | "desc": "中低风险", 34 | "limitDesc": "无限制" 35 | }, 36 | { 37 | "id": "c5", 38 | "rate": "4.11%", 39 | "pro": "中招理财", 40 | "rateTime": "业绩基准(年化)", 41 | "desc": "中低风险", 42 | "limitDesc": "1000元起投" 43 | }, 44 | { 45 | "id": "c6", 46 | "rate": "3.33%", 47 | "pro": "大招理财", 48 | "rateTime": "业绩基准(年化)", 49 | "desc": "中低风险", 50 | "limitDesc": "锁定期1天" 51 | } 52 | ] 53 | } -------------------------------------------------------------------------------- /lib/view/common/search_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:zmz_app/compose/compose.dart'; 2 | import 'package:zmz_app/view/common/my_search.dart'; 3 | 4 | class SearchBar extends StatelessWidget { 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | 9 | var _searchValue = ''; 10 | 11 | return Row( 12 | mainAxisAlignment: MainAxisAlignment.center, 13 | children: [ 14 | ActionChip( 15 | backgroundColor: Colors.white, 16 | avatar: Icon(Icons.search, color: Colors.grey), 17 | label: Container( 18 | alignment: Alignment.center, 19 | width: ZFit().setWidth(200), 20 | height: ZFit().setWidth(22), 21 | child: Text('搜索') 22 | ), 23 | onPressed: () { 24 | showSearch( 25 | context: context, 26 | query: _searchValue, 27 | delegate: MySearch(_searchValue) 28 | ); 29 | }, 30 | ), 31 | Container( 32 | child: MaterialButton( 33 | padding: EdgeInsets.symmetric(horizontal: ZFit().setWidth(15)), 34 | minWidth: ZFit().setWidth(25), 35 | child: Text('提问', style: TextStyle(color: Colors.white, fontSize: ZFit().setSp(14))), 36 | onPressed: () { 37 | Scaffold.of(context).showSnackBar(const SnackBar( 38 | content: Text("不给你提问."), 39 | )); 40 | } 41 | ) 42 | ) 43 | ], 44 | ); 45 | } 46 | } -------------------------------------------------------------------------------- /lib/page/treasure/selection/dealer_selection_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DealerSelectionPage extends StatefulWidget { 4 | @override 5 | _DealerSelectionPageState createState() => _DealerSelectionPageState(); 6 | } 7 | 8 | class _DealerSelectionPageState extends State { 9 | 10 | List letterList = [ 11 | "A", "B", "C", "D", 12 | "E", "F", "G", "H", "I" 13 | ]; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | // 如果ReorderableListView在Container中,上层还用个TabsView 18 | // 会产生多个ScrollAble的Widget。导致ReorderableListView不能滚动 19 | return Scaffold( 20 | // 可再次排序的 ListView 21 | body: ReorderableListView( 22 | header: Text('拖动式重新排序', style: TextStyle(fontSize: 26),), 23 | children: letterList.map(_buildCard).toList(), 24 | onReorder: _onReorder, 25 | ), 26 | ); 27 | } 28 | 29 | // 排序方式 30 | _onReorder(int oldIndex, int newIndex) { 31 | setState(() { 32 | if (oldIndex < newIndex) newIndex -= 1; 33 | var item = letterList.removeAt(oldIndex); 34 | letterList.insert(newIndex, item); 35 | }); 36 | } 37 | } 38 | 39 | Widget _buildCard(String name) { 40 | return Container( 41 | key: ObjectKey(name), 42 | height: 78, 43 | width: 200, 44 | child: Card( 45 | color: Colors.cyan.withAlpha(111), 46 | child: Center( 47 | child: Text( 48 | '$name', 49 | style: TextStyle(fontSize: 24, color: Colors.white,), 50 | ), 51 | ), 52 | ), 53 | ); 54 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | back-end/node_modules/ 13 | 14 | # IntelliJ related 15 | *.iml 16 | *.ipr 17 | *.iws 18 | .idea/ 19 | 20 | # Visual Studio Code related 21 | .vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Android related 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/ServiceDefinitions.json 65 | **/ios/Runner/GeneratedPluginRegistrant.* 66 | 67 | # Exceptions to above rules. 68 | !**/ios/**/default.mode1v3 69 | !**/ios/**/default.mode2v3 70 | !**/ios/**/default.pbxuser 71 | !**/ios/**/default.perspectivev3 72 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 73 | -------------------------------------------------------------------------------- /lib/utils/center_nav.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | // math 4 | import 'dart:math' as math; 5 | 6 | // 重写 Flutter 类 7 | abstract class _BottomNavLocation extends FloatingActionButtonLocation { 8 | 9 | const _BottomNavLocation(); 10 | 11 | @protected 12 | double getDockedY(ScaffoldPrelayoutGeometry scaffoldGeometry) { 13 | final double contentBottom = scaffoldGeometry.contentBottom; 14 | final double bottomSheetHeight = scaffoldGeometry.bottomSheetSize.height; 15 | final double fabHeight = scaffoldGeometry.floatingActionButtonSize.height; 16 | final double snackBarHeight = scaffoldGeometry.snackBarSize.height; 17 | 18 | double fabY = contentBottom - fabHeight / 2.0 + 15; 19 | if (snackBarHeight > 0.0) 20 | fabY = math.min(fabY, contentBottom - snackBarHeight - fabHeight - kFloatingActionButtonMargin); 21 | if (bottomSheetHeight > 0.0) 22 | fabY = math.min(fabY, contentBottom - bottomSheetHeight - fabHeight / 2.0); 23 | 24 | final double maxFabY = scaffoldGeometry.scaffoldSize.height - fabHeight; 25 | return math.min(maxFabY, fabY); 26 | } 27 | } 28 | 29 | 30 | // 重写 Flutter 类 31 | class CenterNav extends _BottomNavLocation { 32 | const CenterNav(); 33 | 34 | @override 35 | Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) { 36 | final double fabX = (scaffoldGeometry.scaffoldSize.width - 37 | scaffoldGeometry.floatingActionButtonSize.width) / 38 | 2.0; 39 | return Offset(fabX, getDockedY(scaffoldGeometry)); 40 | } 41 | 42 | @override 43 | String toString() => 'FloatingActionButtonLocation.endDocked'; 44 | } 45 | -------------------------------------------------------------------------------- /lib/utils/event_bus.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Flutter中文网 3 | * 此代码 系 copy 4 | * 出处见 页头 5 | * 仅学习使用。mark 6 | */ 7 | 8 | //订阅者回调签名 9 | typedef void EventCallback(arg); 10 | 11 | class _EventBus { 12 | // //私有构造函数 13 | // EventBus._internal(); 14 | 15 | // // Dart中实现单例模式的标准做法就是:使用static变量 + 工厂构造函数的方式 16 | // // 这样就可以保证new EventBus()始终返回都是同一个实例 17 | 18 | // //保存单例 19 | // static EventBus _singleton = new EventBus._internal(); 20 | // //工厂构造函数 21 | // factory EventBus() => _singleton; 22 | 23 | //保存事件订阅者队列,key:事件名(id),value: 对应事件的订阅者队列 24 | var _emap = new Map>(); 25 | 26 | //添加订阅者 27 | void on(eventName, EventCallback f) { 28 | if (eventName == null || f == null) return; 29 | _emap[eventName] ??= new List(); 30 | _emap[eventName].add(f); 31 | } 32 | 33 | //移除订阅者 34 | void off(eventName, [EventCallback f]) { 35 | var list = _emap[eventName]; 36 | if (eventName == null || list == null) return; 37 | if (f == null) { 38 | _emap[eventName] = null; 39 | } else { 40 | list.remove(f); 41 | } 42 | } 43 | 44 | //触发事件,事件触发后该事件所有订阅者会被调用 45 | void emit(eventName, [arg]) { 46 | var list = _emap[eventName]; 47 | if (list == null) return; 48 | int len = list.length - 1; 49 | //反向遍历,防止在订阅者在回调中移除自身带来的下标错位 50 | for (var i = len; i > -1; --i) { 51 | list[i](arg); 52 | } 53 | } 54 | } 55 | 56 | _EventBus eventBus = new _EventBus(); 57 | 58 | /** 59 | * // 页面A中 60 | * 监听登录事件 61 | * bus.on("login", (arg) { 62 | * doFunction 63 | * }); 64 | * 65 | * 登录页B中 66 | * 登录成功后触发登录事件,页面A中订阅者会被调用 67 | * bus.emit("login", userInfo); 68 | * 69 | */ -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | zmz_app 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /back-end/mock/bank_product_list.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | code: '000', 3 | result: [ 4 | { 5 | 'bankName': '鸭梨理财', 6 | 'productList': [ 7 | { 8 | 'id': 'c8', 9 | 'rate': '4.32%', 10 | 'rateTime': '综合利率', 11 | 'desc': '中低风险', 12 | 'limitDesc': '0元起投' 13 | } 14 | ] 15 | }, { 16 | 'bankName': '苹果理财', 17 | 'productList': [ 18 | { 19 | 'id': 'c1', 20 | 'rate': '4.32%', 21 | 'rateTime': '七日年化收益率', 22 | 'desc': '中低风险', 23 | 'limitDesc': '10元起投' 24 | }, { 25 | 'id': 'c6', 26 | 'rate': '4.11%', 27 | 'rateTime': '七日年化收益率', 28 | 'desc': '中低风险', 29 | 'limitDesc': '锁定期1天' 30 | }, { 31 | 'id': 'c4', 32 | 'rate': '4.72%', 33 | 'rateTime': '七日年化收益率', 34 | 'desc': '中低风险', 35 | 'limitDesc': '1000元起投' 36 | } 37 | ] 38 | }, { 39 | 'bankName': '菠萝理财', 40 | 'productList': [ 41 | { 42 | 'id': 'c3', 43 | 'rate': '5.55%', 44 | 'rateTime': '七日年化收益率', 45 | 'desc': '中低风险', 46 | 'limitDesc': '锁定期1天' 47 | }, { 48 | 'id': 'c5', 49 | 'rate': '5.12%', 50 | 'rateTime': '七日年化收益率', 51 | 'desc': '中低风险', 52 | 'limitDesc': '锁定期1天' 53 | } 54 | ] 55 | } 56 | ] 57 | } -------------------------------------------------------------------------------- /lib/plugin/toast.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Toast { 4 | 5 | static OverlayEntry _overlayEntry; // toast靠它加到屏幕上 6 | static bool _showing = false; // toast是否正在showing 7 | static DateTime _startedTime; // 开启一个新toast的当前时间,用于对比是否已经展示了足够时间 8 | static String _msg; 9 | 10 | static void show( 11 | BuildContext context, 12 | String msg, 13 | ) async { 14 | 15 | _msg = msg; 16 | 17 | if(_msg == null || _msg.length < 1){ 18 | _msg = '处理中'; 19 | } 20 | _startedTime = DateTime.now(); 21 | _showing = true; 22 | 23 | //获取OverlayState 24 | OverlayState overlayState = Overlay.of(context); 25 | if (_overlayEntry == null) { 26 | 27 | // 没有Overlay 那么造一个 28 | _overlayEntry = OverlayEntry( 29 | builder: (BuildContext context) => Center( 30 | // 动画效果 31 | child: AnimatedOpacity( 32 | opacity: _showing ? 1.0 : 0.0, //目标透明度 33 | duration: _showing ? Duration(milliseconds: 100) : Duration(milliseconds: 400), 34 | child: Card( 35 | color: Colors.black54, 36 | child: Padding( 37 | padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), 38 | child: Text(_msg, style: TextStyle(fontSize: 16.0, color: Colors.white ), 39 | ), 40 | ), 41 | ), 42 | ) 43 | ) 44 | ); 45 | 46 | // 将Overlay塞到State中 47 | overlayState.insert(_overlayEntry); 48 | 49 | } else { 50 | // 重新绘制UI,类似setState 51 | _overlayEntry.markNeedsBuild(); 52 | } 53 | 54 | await Future.delayed(Duration(milliseconds: 2000)); //等待两秒 55 | 56 | // 2秒后 到底消失不消失 57 | if (DateTime.now().difference(_startedTime).inMilliseconds >= 2000) { 58 | try { 59 | _showing = false; 60 | // 移除Overlay 61 | _overlayEntry.remove(); 62 | _overlayEntry = null; 63 | } catch (e) { 64 | } 65 | } 66 | 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /lib/page/payment/payment_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:zmz_app/bloc/payment/payment_bloc.dart'; 4 | import 'package:zmz_app/domain/route_argument.dart'; 5 | import 'package:zmz_app/routes/z_router.dart'; 6 | import 'package:zmz_app/styles/edge_style.dart'; 7 | import 'package:zmz_app/utils/event_bus.dart'; 8 | import 'package:zmz_app/utils/z_fit.dart'; 9 | // 参数 10 | 11 | class PaymentPage extends StatefulWidget { 12 | 13 | @override 14 | _PaymentPageState createState() => _PaymentPageState(); 15 | } 16 | 17 | class _PaymentPageState extends State { 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | 22 | PaymentNumBloc _paymentNumBloc = BlocProvider.of(context); 23 | 24 | return BlocBuilder( 25 | builder: (context2, count) { 26 | return Container( 27 | padding: ZEdge.all_15, 28 | child: Column( 29 | crossAxisAlignment: CrossAxisAlignment.start, 30 | children: [ 31 | Text('购买份数:${count.toString()}', style: TextStyle(fontSize: ZFit().setWidth(28),)), 32 | // Text('选择支付方式'), 33 | Row( 34 | mainAxisAlignment: MainAxisAlignment.spaceAround, 35 | children: [ 36 | RaisedButton( 37 | onPressed: () { 38 | _paymentNumBloc.dispatch(PaymentNumEvent.increment); 39 | }, 40 | child: Text('再多买一份'), 41 | ), 42 | RaisedButton( 43 | onPressed: () { 44 | Navigator.pushNamed(context, '/login', arguments: RouteArguments('从购买页进入')); 45 | }, 46 | child: Text('确认'), 47 | ), 48 | ], 49 | ) 50 | ], 51 | ), 52 | ); 53 | } 54 | ); 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /lib/page/manager_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:zmz_app/compose/compose.dart'; 3 | import 'package:zmz_app/plugin/loading.dart'; 4 | import 'package:zmz_app/plugin/toast.dart'; 5 | import 'package:zmz_app/routes/z_router.dart'; 6 | import 'package:zmz_app/utils/event_bus.dart'; 7 | 8 | @ZMeta('管理页面') 9 | class ManagerPage extends StatelessWidget { 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | 14 | // 初始化页面 width=375; height=812; 15 | ZFit.instance = ZFit(width: 375, height: 812)..init(context); 16 | 17 | eventBus.on('showToast', (message) { 18 | Future.microtask(() => Toast.show(context, message)); 19 | }); 20 | 21 | eventBus.on('showLoading', (message) { 22 | Future.microtask(() => Loading.show(context, message)); 23 | }); 24 | 25 | eventBus.on('closeLoading', (message) { 26 | Future.microtask(() => Loading.close()); 27 | }); 28 | 29 | DateTime _lastPressedAt; //上次点击时间 30 | 31 | return WillPopScope( // 导航返回拦截 32 | onWillPop: () async { 33 | if (_lastPressedAt == null || 34 | DateTime.now().difference(_lastPressedAt) > Duration(milliseconds: 500)) { 35 | //两次点击间隔超过1秒则重新计时 36 | _lastPressedAt = DateTime.now(); 37 | 38 | // 点击手机的下发回退键盘,触发pop 39 | Navigator.maybePop(ZRouter.context); 40 | return false; 41 | } 42 | return true; 43 | }, 44 | child: Navigator( // 实现SPA 45 | initialRoute: '/', 46 | onGenerateRoute: (RouteSettings settings) { 47 | // 路由表对应单页 48 | Widget _page = ZRouter.routerStore[settings.name]; 49 | 50 | // Cupertino路由动画 51 | return CupertinoPageRoute( 52 | settings: settings, // 参数 53 | builder: (context) { 54 | // 每一个子页面的context 55 | ZRouter.setContext = context; 56 | return _page; 57 | } 58 | ); 59 | } 60 | ) 61 | ); 62 | } 63 | 64 | } 65 | 66 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.example.zmz_app" 37 | minSdkVersion 16 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'compose/compose.dart'; 4 | import 'package:zmz_app/config/base_info.dart'; 5 | import 'package:zmz_app/page/manager_page.dart'; 6 | import 'package:bloc/bloc.dart'; 7 | import 'package:flutter_bloc/flutter_bloc.dart'; 8 | import 'package:zmz_app/bloc/theme_bloc.dart'; 9 | import 'package:flutter_localizations/flutter_localizations.dart'; // 国际化 10 | 11 | class SimpleBlocDelegate extends BlocDelegate { 12 | @override 13 | void onEvent(Bloc bloc, Object event) { 14 | super.onEvent(bloc, event); 15 | print(event); 16 | } 17 | 18 | @override 19 | void onTransition(Bloc bloc, Transition transition) { 20 | super.onTransition(bloc, transition); 21 | print(transition); 22 | } 23 | 24 | @override 25 | void onError(Bloc bloc, Object error, StackTrace stacktrace) { 26 | super.onError(bloc, error, stacktrace); 27 | print(error); 28 | } 29 | } 30 | 31 | @ZMeta('这是一个入口') 32 | class MyApp extends StatelessWidget { 33 | 34 | MyApp(Env env) { 35 | // bloc控制 36 | BlocSupervisor.delegate = SimpleBlocDelegate(); 37 | // 设置环境变量 38 | Config.setEnv = env; 39 | 40 | if (Platform.isIOS) { 41 | Config.setPlatform = ZPlatform.ios; 42 | } else if (Platform.isAndroid) { 43 | Config.setPlatform = ZPlatform.android; 44 | } 45 | } 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | 50 | 51 | return BlocProvider( 52 | builder: (context) => ThemeBloc(), 53 | child: BlocBuilder( 54 | builder: (context, theme) { 55 | return MaterialApp( 56 | title: 'Z.金融理财', 57 | theme: theme, 58 | home: ManagerPage(), 59 | localizationsDelegates: [ // 国际化代理 60 | GlobalMaterialLocalizations.delegate, 61 | GlobalWidgetsLocalizations.delegate, 62 | ], 63 | supportedLocales: [ 64 | const Locale('zh', 'CN'), // 中文简体 65 | // const Locale('en', 'US'), // 美国英语 66 | ], 67 | // routes: ZRouter.routerStore, //注册路由表 68 | ); 69 | }, 70 | ), 71 | ); 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /lib/page/treasure/selection/fund_selection_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:webview_flutter/webview_flutter.dart'; 3 | import 'dart:async'; 4 | 5 | import 'package:zmz_app/utils/event_bus.dart'; 6 | // import 'package:zmz_app/view/my_search.dart'; 7 | 8 | class FundSelectionPage extends StatefulWidget { 9 | @override 10 | State createState() => FundState(); 11 | } 12 | 13 | class FundState extends State with AutomaticKeepAliveClientMixin { 14 | 15 | @override 16 | bool get wantKeepAlive => true; 17 | 18 | // var _searchValue; 19 | 20 | final Completer _controller = Completer(); 21 | 22 | JavascriptChannel _toasterJavascriptChannel(BuildContext context) { 23 | // 在JS中可用调用 Toaster.postMessage('msg'); 24 | return JavascriptChannel( 25 | name: 'Toaster', 26 | onMessageReceived: (JavascriptMessage message) { 27 | Scaffold.of(context).showSnackBar( 28 | SnackBar(content: Text(message.message)), 29 | ); 30 | }); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | super.build(context); 36 | 37 | eventBus.emit('showLoading', '加载中...'); 38 | 39 | return Container( 40 | width: 300, 41 | height: 400, 42 | child: WebView( 43 | initialUrl: 'https://zhongmeizhi.github.io/FED-note/', 44 | javascriptMode: JavascriptMode.unrestricted, 45 | onWebViewCreated: (WebViewController webViewController) { 46 | _controller.complete(webViewController); 47 | }, 48 | javascriptChannels: [ 49 | _toasterJavascriptChannel(context), 50 | ].toSet(), 51 | navigationDelegate: (NavigationRequest request) { 52 | // URL拦截 53 | if (request.url == 'https://www.baidu.com/') { 54 | // 组织链接跳转 55 | return NavigationDecision.prevent; 56 | } 57 | return NavigationDecision.navigate; 58 | }, 59 | onPageFinished: (String url) { 60 | eventBus.emit('closeLoading'); 61 | }, 62 | ) 63 | ); 64 | } 65 | } -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /lib/plugin/loading.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:zmz_app/compose/compose.dart'; 3 | import 'package:zmz_app/utils/z_fit.dart'; 4 | 5 | class Loading { 6 | 7 | static OverlayEntry _overlayEntry; // 靠它加到屏幕上 8 | static String _msg; 9 | 10 | static void show( 11 | BuildContext context, 12 | String msg, 13 | ) async { 14 | 15 | _msg = msg; 16 | if(_msg == null || _msg.length < 1){ 17 | _msg = '处理中...'; 18 | } 19 | 20 | //获取OverlayState 21 | OverlayState overlayState = Overlay.of(context); 22 | if (_overlayEntry == null) { 23 | // 没有Overlay 那么造一个 24 | _overlayEntry = OverlayEntry( 25 | builder: (BuildContext context) => Material( 26 | color: ZColor.grey.withAlpha(23), 27 | child: Center( 28 | child: Container( 29 | width: ZFit().setWidth(123), 30 | height: ZFit().setWidth(123), 31 | padding: ZEdge.all_10, 32 | decoration: BoxDecoration( 33 | color: Color(0xff565656), 34 | boxShadow: [ 35 | BoxShadow(color: ZColor.grey, blurRadius: ZFit().setWidth(2)) 36 | ], 37 | borderRadius: ZRadius.all_8 38 | ), 39 | child: Column( 40 | mainAxisAlignment: MainAxisAlignment.spaceAround, 41 | children: [ 42 | Container( 43 | padding: ZEdge.all_15, 44 | width: ZFit().setWidth(66), 45 | height: ZFit().setWidth(66), 46 | child: CircularProgressIndicator( 47 | strokeWidth: 3.0 48 | ), 49 | ), 50 | Text(_msg, style: TextStyle(color: Colors.white, fontSize: ZFit().setSp(16))), 51 | ], 52 | ), 53 | ), 54 | ), 55 | ) 56 | ); 57 | 58 | // 将Overlay塞到State中 59 | overlayState.insert(_overlayEntry); 60 | } else { 61 | // 重新绘制UI,类似setState 62 | _overlayEntry.markNeedsBuild(); 63 | } 64 | 65 | } 66 | 67 | static void close() { 68 | try { 69 | // 移除Overlay 70 | _overlayEntry.remove(); 71 | _overlayEntry = null; 72 | } catch (e) { 73 | } 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /lib/view/bank_product.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:zmz_app/compose/compose.dart'; 3 | 4 | class BankProductWidget extends StatelessWidget { 5 | 6 | final item; 7 | final Function intoChoicenessDetail; 8 | 9 | BankProductWidget({@required this.item, this.intoChoicenessDetail}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | padding: ZEdge.vertical_8, 15 | child: Column( 16 | children: [ 17 | GestureDetector( 18 | onTap: () { 19 | this.intoChoicenessDetail(); 20 | }, 21 | child: Row( 22 | children: [ 23 | Container( 24 | width: ZFit().setWidth(120), 25 | alignment: Alignment.topLeft, 26 | padding: ZEdge.horizontal_10, 27 | decoration: BoxDecoration( 28 | border: Border(right: BorderSide(width: 1, color: ZColor.grey)) 29 | ), 30 | child: Column( 31 | children: [ 32 | Text(item['rate'], 33 | style: TextStyle(fontSize: ZFit().setSp(26), color: Colors.red) 34 | ), 35 | Text(item['rateTime'], 36 | style: TextStyle(fontSize: ZFit().setSp(11), color: ZColor.black) 37 | ) 38 | ], 39 | ), 40 | ), 41 | Expanded( 42 | flex: 1, 43 | child: ListTile( 44 | title: Text(item['desc'], 45 | style: TextStyle(fontSize: ZFit().setSp(14)) 46 | ), 47 | subtitle: Text(item['limitDesc'], 48 | style: TextStyle(fontSize: ZFit().setSp(12), color: ZColor.grey) 49 | ), 50 | trailing: Container( 51 | width: ZFit().setWidth(63), 52 | child: Row( 53 | children: [ 54 | Icon(Icons.error, color: Colors.blue,), 55 | Text('已售罄') 56 | ], 57 | ) 58 | ), 59 | ), 60 | ) 61 | ] 62 | ), 63 | ) 64 | ], 65 | ) 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/page/welcome/splash_page.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:zmz_app/compose/compose.dart'; 3 | import 'package:common_utils/common_utils.dart'; 4 | 5 | class SplashPage extends StatefulWidget { 6 | @override 7 | _SplashPageState createState() => _SplashPageState(); 8 | } 9 | 10 | class _SplashPageState extends State with SingleTickerProviderStateMixin{ 11 | 12 | int _count = 5; 13 | TimerUtil _timerUtil; 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | _doCountDown(); 19 | } 20 | 21 | // 开屏广告结束,跳转到首页 22 | void _goMain() { 23 | Navigator.of(context).pushReplacementNamed('/main_page'); 24 | } 25 | 26 | void _doCountDown() { 27 | _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); 28 | _timerUtil.setOnTimerTickCallback((int tick) { 29 | // 如果已经被销毁,那么不执行 30 | if (!mounted) { 31 | return; 32 | } 33 | double _tick = tick / 1000; 34 | setState(() { 35 | _count = _tick.toInt(); 36 | }); 37 | if (_tick == 0) { 38 | _goMain(); 39 | } 40 | }); 41 | _timerUtil.startCountDown(); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | 47 | return new Material( 48 | child: new Stack( 49 | children: [ 50 | new Image.asset( 51 | 'assets/images/projector.png', 52 | width: double.infinity, 53 | height: double.infinity, 54 | fit: BoxFit.fill, 55 | ), 56 | Positioned( 57 | top: ZFit().setWidth(33), 58 | right: ZFit().setWidth(11), 59 | child: new Container( 60 | alignment: Alignment.bottomRight, 61 | child: InkWell( 62 | onTap: _goMain, 63 | child: new Container( 64 | padding: EdgeInsets.all(12), 65 | child: new Text('跳过 $_count s', style: new TextStyle(fontSize: ZFit().setSp(12), color: Colors.white),), 66 | decoration: new BoxDecoration( 67 | color: Color(0x66000000), 68 | borderRadius: ZRadius.all_5, 69 | border: new Border.all( 70 | width: ZFit().setWidth(1), 71 | color: Colors.blue[50], 72 | ), 73 | ), 74 | ), 75 | ), 76 | ), 77 | ) 78 | ], 79 | ), 80 | ); 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/page/treasure/treasure_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:zmz_app/compose/compose.dart'; 2 | // 页面 3 | import 'package:zmz_app/page/treasure/selection/bank_selection_page.dart'; 4 | import 'package:zmz_app/page/treasure/selection/fund_selection_page.dart'; 5 | import 'package:zmz_app/page/treasure/selection/dealer_selection_page.dart'; 6 | import 'package:zmz_app/view/common/search_bar.dart'; 7 | 8 | class TreasurePage extends StatefulWidget { 9 | @override 10 | _TreasurePageState createState() => _TreasurePageState(); 11 | } 12 | 13 | class _TreasurePageState extends State 14 | with SingleTickerProviderStateMixin { 15 | 16 | List tabs = [ 17 | { 18 | 'id': 't1', 19 | 'label': '小书房' 20 | }, { 21 | 'id': 't2', 22 | 'label': '银行精选' 23 | }, { 24 | 'id': 't3', 25 | 'label': '券商' 26 | }, { 27 | 'id': 't4', 28 | 'label': '转让' 29 | } 30 | ]; 31 | TabController _tabController; 32 | 33 | _pickTab (val) { 34 | // x 35 | } 36 | 37 | @override 38 | void initState() { 39 | super.initState(); 40 | // 只有 with SingleTickerProviderStateMixin 后才有 TickerProvider,也就是 this 41 | _tabController = TabController(length: tabs.length, vsync: this); 42 | } 43 | 44 | @override 45 | void dispose() { 46 | _tabController.dispose(); 47 | super.dispose(); 48 | } 49 | 50 | // 使用 TabBar + TabBarView 51 | @override 52 | Widget build(BuildContext context) { 53 | return Scaffold( 54 | appBar: AppBar( 55 | automaticallyImplyLeading: false, // 防止自动出现返回键 56 | title: SearchBar(), 57 | bottom: TabBar( 58 | controller: _tabController, 59 | labelPadding: ZEdge.horizontal_5, 60 | isScrollable: true, 61 | tabs: tabs.map((tab) { 62 | return Container( 63 | width: ZFit().setWidth(90), 64 | child: Tab(text: tab['label']), 65 | ); 66 | }).toList(), 67 | onTap: _pickTab, 68 | ), 69 | centerTitle: true, // appBar文字居中 70 | ), 71 | body: 72 | new TabBarView( 73 | key: new Key('treasure_page'), 74 | controller: _tabController, 75 | children: tabs.map((tab) { 76 | switch (tab['id']) { 77 | case 't1': 78 | return FundSelectionPage(); 79 | break; 80 | case 't2': 81 | return BankSelectionPage(item: tab); 82 | break; 83 | case 't3': 84 | return DealerSelectionPage(); 85 | break; 86 | default: 87 | return Center( 88 | child: Text('这里是 -> ' + tab['label']), 89 | ); 90 | break; 91 | } 92 | }).toList(), 93 | ), 94 | ); 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /lib/utils/z_fit.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by 李卓原 on 2018/9/29. 3 | * email: zhuoyuan93@gmail.com 4 | * 5 | * 此代码 系 参考 flutter_screenutil 6 | */ 7 | 8 | import 'package:flutter/material.dart'; 9 | 10 | class ZFit { 11 | static ZFit instance = new ZFit(); 12 | 13 | //设计稿的设备尺寸修改 14 | int width; 15 | int height; 16 | bool allowFontScaling; 17 | 18 | static MediaQueryData _mediaQueryData; 19 | static double _screenWidth; 20 | static double _screenHeight; 21 | static double _pixelRatio; 22 | static double _statusBarHeight; 23 | static double _bottomBarHeight; 24 | 25 | static double _textScaleFactor; 26 | 27 | ZFit({ 28 | this.width = 375, 29 | this.height = 812, 30 | this.allowFontScaling = false, 31 | }); 32 | 33 | static ZFit getInstance() { 34 | return instance; 35 | } 36 | 37 | void init(BuildContext context) { 38 | MediaQueryData mediaQuery = MediaQuery.of(context); 39 | _mediaQueryData = mediaQuery; 40 | _pixelRatio = mediaQuery.devicePixelRatio; 41 | _screenWidth = mediaQuery.size.width; 42 | _screenHeight = mediaQuery.size.height; 43 | _statusBarHeight = mediaQuery.padding.top; 44 | _bottomBarHeight = _mediaQueryData.padding.bottom; 45 | _textScaleFactor = mediaQuery.textScaleFactor; 46 | } 47 | 48 | static MediaQueryData get mediaQueryData => _mediaQueryData; 49 | 50 | ///每个逻辑像素的字体像素数,字体的缩放比例 51 | static double get textScaleFactory => _textScaleFactor; 52 | 53 | ///设备的像素密度 54 | static double get pixelRatio => _pixelRatio; 55 | 56 | ///当前设备宽度 dp 57 | static double get screenWidthDp => _screenWidth; 58 | ///当前设备高度 dp 59 | static double get screenHeightDp => _screenHeight; 60 | 61 | ///当前设备宽度 px 62 | static double get screenWidth => _screenWidth * _pixelRatio; 63 | ///当前设备高度 px 64 | static double get screenHeight => _screenHeight * _pixelRatio; 65 | 66 | // ///状态栏高度 刘海屏会更高 67 | static double get statusBarHeight => _statusBarHeight * _pixelRatio; 68 | // ///底部安全区距离 69 | static double get bottomBarHeight => _bottomBarHeight * _pixelRatio; 70 | 71 | ///实际的dp与设计稿px的比例 72 | double get _scaleWidth => _screenWidth / instance.width; 73 | double get _scaleHeight => _screenHeight / instance.height; 74 | 75 | ///根据设计稿的设备宽度适配 76 | ///高度也根据这个来做适配可以保证不变形 77 | setWidth(int width) => width * _scaleWidth; 78 | 79 | /// 根据设计稿的设备高度适配 80 | /// 当发现设计稿中的一屏显示的与当前样式效果不符合时, 81 | /// 或者形状有差异时,高度适配建议使用此方法 82 | /// 高度适配主要针对想根据设计稿的一屏展示一样的效果 83 | setHeight(int height) => height * _scaleHeight; 84 | 85 | ///字体大小适配方法 86 | ///@param fontSize 传入设计稿上字体的px , 87 | ///@param allowFontScaling 控制字体是否要根据系统的“字体大小”辅助选项来进行缩放。默认值为true。 88 | ///@param allowFontScaling Specifies whether fonts should scale to respect Text Size accessibility settings. The default is true. 89 | setSp(int fontSize) => allowFontScaling 90 | ? setWidth(fontSize) 91 | : setWidth(fontSize) / _textScaleFactor; 92 | } 93 | -------------------------------------------------------------------------------- /lib/service/service.dart: -------------------------------------------------------------------------------- 1 | // import 'dart:convert'; 2 | // import 'dart:io'; 3 | // import 'package:flutter/cupertino.dart'; 4 | 5 | // class Service { 6 | // // 基础URL 7 | // String baseUrl; 8 | // Service({ @required this.baseUrl}); 9 | // // get请求 10 | // $get(String url) async { 11 | // var responseBody; 12 | // var httpClient = new HttpClient(); 13 | // var request = await httpClient.getUrl(Uri.parse(this.baseUrl + url)); 14 | // var response = await request.close(); 15 | // if (response.statusCode == 200) { 16 | // // 序列化 response 17 | // responseBody = await response.transform(utf8.decoder).join(); 18 | // responseBody = json.decode(responseBody); 19 | // } else { 20 | // print("error"); 21 | // } 22 | // return responseBody['data']; 23 | // } 24 | // // 其他请求类型待续 25 | // // 以后要加拦截器 26 | // // 异常捕获也需要完善 27 | // } 28 | 29 | import 'dart:collection'; 30 | import 'package:dio/dio.dart'; 31 | import 'package:zmz_app/config/base_info.dart'; 32 | import 'package:zmz_app/utils/event_bus.dart'; 33 | 34 | class _Service { 35 | 36 | _Service() { 37 | _initDio(); 38 | } 39 | 40 | Dio _dio = new Dio(); 41 | 42 | void _initDio () { 43 | _dio.interceptors.add(InterceptorsWrapper( 44 | onRequest: (RequestOptions options){ 45 | // 超时时间 46 | options.connectTimeout = 3000; 47 | // 在请求被发送之前做一些事情 48 | return options; 49 | }, 50 | onResponse: (Response response) { 51 | // 在返回响应数据之前做一些预处理 52 | if (response.data['code'] != '000') { 53 | eventBus.emit('showToast', '系统繁忙请稍后再试...'); 54 | } 55 | return response; 56 | }, 57 | onError: (DioError error) { 58 | // 当请求失败时做一些预处理 59 | eventBus.emit('showToast', '程序员GG正在想问题...'); 60 | return error; 61 | }, 62 | )); 63 | } 64 | 65 | // 真正发请求的地方 66 | Future fetch(url, { 67 | dynamic params, 68 | Map header, 69 | Options option, 70 | bool isShowLoading = false 71 | }) async{ 72 | 73 | Map headers = new HashMap(); 74 | if (header != null) { 75 | headers.addAll(header); 76 | } 77 | 78 | if (option != null) { 79 | option.headers = headers; 80 | } else { 81 | option = new Options(method: "get"); 82 | option.headers = headers; 83 | } 84 | 85 | // 是否需要 loading 86 | if (isShowLoading) { 87 | eventBus.emit('showLoading', '加载中...'); 88 | } 89 | try { 90 | // 发送请求获取结果 91 | Response _response = await _dio.request('${Config.baseUrl}$url', data: params, options: option); 92 | // 返回真正结果 93 | // print(_response.data['result']); 94 | return _response.data['result']; 95 | } catch (error) { 96 | // 异常提示 97 | eventBus.emit('showToast', '程序员GG正在想问题...'); 98 | } finally { 99 | // 不管结果怎么样 都需要结束Loading 100 | if (isShowLoading) { 101 | eventBus.emit('closeLoading'); 102 | } 103 | } 104 | 105 | } 106 | 107 | } 108 | 109 | final _Service service = new _Service(); -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/page/login/login_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:zmz_app/compose/compose.dart'; 2 | import 'package:zmz_app/routes/z_router.dart'; 3 | // storage 4 | import 'package:zmz_app/utils/storage.dart'; 5 | 6 | class LoginPage extends StatefulWidget { 7 | final String title; 8 | LoginPage({Key key, this.title}) : super(key: key); 9 | 10 | @override 11 | _LoginPageState createState() => _LoginPageState(); 12 | } 13 | 14 | class _LoginPageState extends State { 15 | 16 | String _phoneNum = ''; 17 | 18 | void _checkPhoneNum(val) { 19 | setState(() { 20 | _phoneNum = val; 21 | }); 22 | } 23 | 24 | _submitLogin () { 25 | if (_phoneNum.length == 11) { 26 | return () { 27 | LocalStorage.setString('phone', _phoneNum); 28 | // 登录成功 29 | Navigator.pop(context); 30 | }; 31 | } else { 32 | return null; 33 | } 34 | } 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | 39 | String _formTip = ZRouter.getPageArguments(context, '亲,没内容呢'); 40 | 41 | return Scaffold( 42 | appBar: AppBar( 43 | title: Text('Z.登陆'), 44 | ), 45 | backgroundColor: Colors.white, 46 | body: new ListView( 47 | children: [ 48 | _loginFormWidget(_checkPhoneNum, _submitLogin), 49 | ] 50 | ), 51 | // 小角落里面打印进入的地方,方便以后使用 52 | bottomSheet: Container( 53 | width: ZFit().setWidth(375), 54 | height: ZFit().setWidth(30), 55 | padding: ZEdge.vertical_5, 56 | alignment: Alignment.center, 57 | child: Text(_formTip), 58 | ) 59 | ); 60 | } 61 | } 62 | 63 | Widget _loginFormWidget (_checkPhoneNum, _submitLogin) { 64 | 65 | return Center( 66 | child: Padding( 67 | padding: ZEdge.all_15, 68 | child: Column( 69 | children: [ 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 | ![meihong](https://zhongmeizhi.github.io/fultter-example-app/preview/meihong1.jpg) 6 | 7 | [![zmz-logo](https://img.shields.io/badge/Example-@zmz-blue.svg?style=flat)](https://github.com/zhongmeizhi/fultter-example-app) [![zmz-logo](https://img.shields.io/badge/App-Flutter-pink.svg?style=flat)](https://github.com/zhongmeizhi/fultter-example-app) [![zmz-logo](https://img.shields.io/badge/fork-35-blue.svg?style=social&logo=github)](https://github.com/zhongmeizhi/fultter-example-app) [![zmz-logo](https://img.shields.io/badge/star-110-blue.svg?style=social&logo=github)](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 | |![1](https://zhongmeizhi.github.io/fultter-example-app/preview/11.png)|![2](https://zhongmeizhi.github.io/fultter-example-app/preview/22.png)|![3](https://zhongmeizhi.github.io/fultter-example-app/preview/33.png)|![4](https://zhongmeizhi.github.io/fultter-example-app/preview/44.png)| 23 | |:--:|:--:|:--:|:--:| 24 | ![5](https://zhongmeizhi.github.io/fultter-example-app/preview/55.png)|![6](https://zhongmeizhi.github.io/fultter-example-app/preview/66.png)|![7](https://zhongmeizhi.github.io/fultter-example-app/preview/77.png)|![8](https://zhongmeizhi.github.io/fultter-example-app/preview/88.png)| 25 | |![9](https://zhongmeizhi.github.io/fultter-example-app/preview/99.png)|![update](https://zhongmeizhi.github.io/fultter-example-app/preview/update1.gif)|![search](https://zhongmeizhi.github.io/fultter-example-app/preview/search1.gif)|![reorder](https://zhongmeizhi.github.io/fultter-example-app/preview/reorder1.gif)| 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 | --------------------------------------------------------------------------------