├── .gitignore ├── .metadata ├── README.md ├── android ├── android.zip ├── app │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ └── com │ │ │ └── kuky │ │ │ └── demo │ │ │ └── fluttershop │ │ │ └── MainActivity.kt │ │ └── res │ │ ├── drawable │ │ └── launch_background.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── apk └── fluttershop.apk ├── images ├── avatar.jpg └── empty.png ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── main.m ├── lib ├── configs │ ├── application.dart │ └── service_url.dart ├── entities │ ├── category_entity.dart │ ├── category_goods_entity.dart │ ├── goods_detail_entity.dart │ ├── home_page_entity.dart │ ├── hot_goods_entity.dart │ └── shopping_cart_entity.dart ├── main.dart ├── pages │ ├── cartpage │ │ ├── bottom_summary.dart │ │ ├── cart_count.dart │ │ ├── cart_page.dart │ │ ├── empty_cart.dart │ │ └── shopping_cart_list.dart │ ├── category_page.dart │ ├── deatilspage │ │ ├── details_page.dart │ │ ├── goods_comments.dart │ │ ├── goods_detail.dart │ │ ├── goods_handler.dart │ │ └── sliver_header_bar.dart │ ├── homepage │ │ ├── ad_banner.dart │ │ ├── banner_diy.dart │ │ ├── floor_part.dart │ │ ├── home_page.dart │ │ ├── hot_part.dart │ │ ├── lead_phone.dart │ │ ├── mall_recommend.dart │ │ └── top_nativator.dart │ ├── index_page.dart │ ├── map_page.dart │ ├── mempage │ │ ├── mem_header.dart │ │ ├── mem_page.dart │ │ ├── mem_tile.dart │ │ └── order_grid.dart │ └── settings_page.dart ├── provides │ ├── cart_count_provide.dart │ ├── cart_provide.dart │ ├── goods_detail_provide.dart │ ├── home_provide.dart │ ├── mall_goods_provide.dart │ ├── page_index_provide.dart │ └── sub_category_provide.dart ├── router │ ├── handler.dart │ └── routers.dart ├── service │ └── service_method.dart ├── shop_app.dart └── utils │ └── preference_utils.dart ├── pubspec.yaml └── test └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.lock 4 | *.log 5 | *.pyc 6 | *.swp 7 | .DS_Store 8 | .atom/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # Visual Studio Code related 20 | .vscode/ 21 | 22 | # Flutter/Dart/Pub related 23 | **/doc/api/ 24 | .dart_tool/ 25 | .flutter-plugins 26 | .packages 27 | .pub-cache/ 28 | .pub/ 29 | build/ 30 | 31 | # Android related 32 | **/android/**/gradle-wrapper.jar 33 | **/android/.gradle 34 | **/android/captures/ 35 | **/android/gradlew 36 | **/android/gradlew.bat 37 | **/android/local.properties 38 | **/android/**/GeneratedPluginRegistrant.java 39 | 40 | # iOS/XCode related 41 | **/ios/**/*.mode1v3 42 | **/ios/**/*.mode2v3 43 | **/ios/**/*.moved-aside 44 | **/ios/**/*.pbxuser 45 | **/ios/**/*.perspectivev3 46 | **/ios/**/*sync/ 47 | **/ios/**/.sconsign.dblite 48 | **/ios/**/.tags* 49 | **/ios/**/.vagrant/ 50 | **/ios/**/DerivedData/ 51 | **/ios/**/Icon? 52 | **/ios/**/Pods/ 53 | **/ios/**/.symlinks/ 54 | **/ios/**/profile 55 | **/ios/**/xcuserdata 56 | **/ios/.generated/ 57 | **/ios/Flutter/App.framework 58 | **/ios/Flutter/Flutter.framework 59 | **/ios/Flutter/Generated.xcconfig 60 | **/ios/Flutter/app.flx 61 | **/ios/Flutter/app.zip 62 | **/ios/Flutter/flutter_assets/ 63 | **/ios/ServiceDefinitions.json 64 | **/ios/Runner/GeneratedPluginRegistrant.* 65 | 66 | # Exceptions to above rules. 67 | !**/ios/**/default.mode1v3 68 | !**/ios/**/default.mode2v3 69 | !**/ios/**/default.pbxuser 70 | !**/ios/**/default.perspectivev3 71 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 72 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_shop 2 | 3 | 本项目是一个付费课程的练习项目,项目代码不完全按照课程的代码编写,加入自己对界面的理解,重新构造一些界面以及逻辑,需要项目原代码的请移步项目 [jspang_flutter_shop](https://github.com/shenghy/flutter_shop) 进行查看 4 | 5 | 对 flutter 有兴趣可查看另一个实战项目 [flutter_weather](https://github.com/kukyxs/flutter_weather),该项目使用 [fluro](https://pub.dartlang.org/packages/fluro) 管理路由,[rxdart](https://pub.dartlang.org/packages/rxdart) 实现 BLoC 并进行状态管理,使用 [sqflite](https://pub.dartlang.org/packages/sqflite),[shared_preferences](https://pub.dartlang.org/packages/shared_preferences),[file](https://pub.dartlang.org/packages/path_provider) 实现数据持久化,使用 [dio](https://pub.dartlang.org/packages/dio) 实现网络请求,并进行相关封装。 6 | 7 | 附完整的 flutter 入门教程,请移步博客:[掘金](https://juejin.im/user/588719c72f301e0069a581f7/posts) 或者 [简书](https://www.jianshu.com/nb/34950817),博客涉及的代码请查看项目 [blog_demos](https://github.com/kukyxs/flutter_arts_demos_app) 8 | 9 | ## Getting Started 10 | 11 | This project is a starting point for a Flutter application. 12 | 13 | A few resources to get you started if this is your first Flutter project: 14 | 15 | - [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab) 16 | - [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook) 17 | 18 | For help getting started with Flutter, view our 19 | [online documentation](https://flutter.io/docs), which offers tutorials, 20 | samples, guidance on mobile development, and a full API reference. 21 | -------------------------------------------------------------------------------- /android/android.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/android/android.zip -------------------------------------------------------------------------------- /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 plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.kuky.demo.fluttershop" 42 | minSdkVersion 16 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 47 | 48 | ndk { 49 | abiFilters 'armeabi', 'armeabi-v7a', 'x86', 'x86_64', 'mips', 'mips64', 'arm64-v8a' 50 | } 51 | 52 | manifestPlaceholders = [ 53 | JPUSH_PKGNAME : applicationId, 54 | JPUSH_APPKEY : "696247cca94724deaab1cae5", 55 | JPUSH_CHANNEL : "developer-default", 56 | ] 57 | } 58 | 59 | buildTypes { 60 | release { 61 | // TODO: Add your own signing config for the release build. 62 | // Signing with the debug keys for now, so `flutter run --release` works. 63 | signingConfig signingConfigs.debug 64 | } 65 | } 66 | } 67 | 68 | flutter { 69 | source '../..' 70 | } 71 | 72 | dependencies { 73 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 74 | testImplementation 'junit:junit:4.12' 75 | androidTestImplementation 'androidx.test:runner:1.1.1' 76 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 77 | } 78 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | 10 | 11 | 16 | 21 | 22 | 25 | 26 | 33 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/kuky/demo/fluttershop/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kuky.demo.fluttershop 2 | 3 | import android.os.Bundle 4 | 5 | import io.flutter.app.FlutterActivity 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | GeneratedPluginRegistrant.registerWith(this) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.2.71' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.2.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true 3 | org.gradle.jvmargs=-Xmx1536M 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 24 10:12:52 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /apk/fluttershop.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/apk/fluttershop.apk -------------------------------------------------------------------------------- /images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/images/avatar.jpg -------------------------------------------------------------------------------- /images/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/images/empty.png -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.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 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 18 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 19 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 20 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 21 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 22 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXCopyFilesBuildPhase section */ 26 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 27 | isa = PBXCopyFilesBuildPhase; 28 | buildActionMask = 2147483647; 29 | dstPath = ""; 30 | dstSubfolderSpec = 10; 31 | files = ( 32 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 33 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 34 | ); 35 | name = "Embed Frameworks"; 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXCopyFilesBuildPhase section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 42 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 43 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 51 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 52 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXFrameworksBuildPhase section */ 71 | 72 | /* Begin PBXGroup section */ 73 | 9740EEB11CF90186004384FC /* Flutter */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 77 | 3B80C3931E831B6300D905FE /* App.framework */, 78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 79 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 80 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 81 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 82 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 83 | ); 84 | name = Flutter; 85 | sourceTree = ""; 86 | }; 87 | 97C146E51CF9000F007C117D = { 88 | isa = PBXGroup; 89 | children = ( 90 | 9740EEB11CF90186004384FC /* Flutter */, 91 | 97C146F01CF9000F007C117D /* Runner */, 92 | 97C146EF1CF9000F007C117D /* Products */, 93 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | 97C146EF1CF9000F007C117D /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 97C146EE1CF9000F007C117D /* Runner.app */, 101 | ); 102 | name = Products; 103 | sourceTree = ""; 104 | }; 105 | 97C146F01CF9000F007C117D /* Runner */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 109 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 110 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 111 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 112 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 113 | 97C147021CF9000F007C117D /* Info.plist */, 114 | 97C146F11CF9000F007C117D /* Supporting Files */, 115 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 116 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 117 | ); 118 | path = Runner; 119 | sourceTree = ""; 120 | }; 121 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 97C146F21CF9000F007C117D /* main.m */, 125 | ); 126 | name = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | /* End PBXGroup section */ 130 | 131 | /* Begin PBXNativeTarget section */ 132 | 97C146ED1CF9000F007C117D /* Runner */ = { 133 | isa = PBXNativeTarget; 134 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 135 | buildPhases = ( 136 | 9740EEB61CF901F6004384FC /* Run Script */, 137 | 97C146EA1CF9000F007C117D /* Sources */, 138 | 97C146EB1CF9000F007C117D /* Frameworks */, 139 | 97C146EC1CF9000F007C117D /* Resources */, 140 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 142 | ); 143 | buildRules = ( 144 | ); 145 | dependencies = ( 146 | ); 147 | name = Runner; 148 | productName = Runner; 149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 150 | productType = "com.apple.product-type.application"; 151 | }; 152 | /* End PBXNativeTarget section */ 153 | 154 | /* Begin PBXProject section */ 155 | 97C146E61CF9000F007C117D /* Project object */ = { 156 | isa = PBXProject; 157 | attributes = { 158 | LastUpgradeCheck = 0910; 159 | ORGANIZATIONNAME = "The Chromium Authors"; 160 | TargetAttributes = { 161 | 97C146ED1CF9000F007C117D = { 162 | CreatedOnToolsVersion = 7.3.1; 163 | }; 164 | }; 165 | }; 166 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 167 | compatibilityVersion = "Xcode 3.2"; 168 | developmentRegion = English; 169 | hasScannedForEncodings = 0; 170 | knownRegions = ( 171 | en, 172 | Base, 173 | ); 174 | mainGroup = 97C146E51CF9000F007C117D; 175 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 176 | projectDirPath = ""; 177 | projectRoot = ""; 178 | targets = ( 179 | 97C146ED1CF9000F007C117D /* Runner */, 180 | ); 181 | }; 182 | /* End PBXProject section */ 183 | 184 | /* Begin PBXResourcesBuildPhase section */ 185 | 97C146EC1CF9000F007C117D /* Resources */ = { 186 | isa = PBXResourcesBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 190 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 191 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 193 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 194 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | }; 198 | /* End PBXResourcesBuildPhase section */ 199 | 200 | /* Begin PBXShellScriptBuildPhase section */ 201 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 202 | isa = PBXShellScriptBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | ); 206 | inputPaths = ( 207 | ); 208 | name = "Thin Binary"; 209 | outputPaths = ( 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | shellPath = /bin/sh; 213 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 214 | }; 215 | 9740EEB61CF901F6004384FC /* Run Script */ = { 216 | isa = PBXShellScriptBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | ); 220 | inputPaths = ( 221 | ); 222 | name = "Run Script"; 223 | outputPaths = ( 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | shellPath = /bin/sh; 227 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 228 | }; 229 | /* End PBXShellScriptBuildPhase section */ 230 | 231 | /* Begin PBXSourcesBuildPhase section */ 232 | 97C146EA1CF9000F007C117D /* Sources */ = { 233 | isa = PBXSourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 237 | 97C146F31CF9000F007C117D /* main.m in Sources */, 238 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | }; 242 | /* End PBXSourcesBuildPhase section */ 243 | 244 | /* Begin PBXVariantGroup section */ 245 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 246 | isa = PBXVariantGroup; 247 | children = ( 248 | 97C146FB1CF9000F007C117D /* Base */, 249 | ); 250 | name = Main.storyboard; 251 | sourceTree = ""; 252 | }; 253 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 254 | isa = PBXVariantGroup; 255 | children = ( 256 | 97C147001CF9000F007C117D /* Base */, 257 | ); 258 | name = LaunchScreen.storyboard; 259 | sourceTree = ""; 260 | }; 261 | /* End PBXVariantGroup section */ 262 | 263 | /* Begin XCBuildConfiguration section */ 264 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 265 | isa = XCBuildConfiguration; 266 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 267 | buildSettings = { 268 | ALWAYS_SEARCH_USER_PATHS = NO; 269 | CLANG_ANALYZER_NONNULL = YES; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_MODULES = YES; 273 | CLANG_ENABLE_OBJC_ARC = YES; 274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 275 | CLANG_WARN_BOOL_CONVERSION = YES; 276 | CLANG_WARN_COMMA = YES; 277 | CLANG_WARN_CONSTANT_CONVERSION = YES; 278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 279 | CLANG_WARN_EMPTY_BODY = YES; 280 | CLANG_WARN_ENUM_CONVERSION = YES; 281 | CLANG_WARN_INFINITE_RECURSION = YES; 282 | CLANG_WARN_INT_CONVERSION = YES; 283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 286 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 287 | CLANG_WARN_STRICT_PROTOTYPES = YES; 288 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 292 | COPY_PHASE_STRIP = NO; 293 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 294 | ENABLE_NS_ASSERTIONS = NO; 295 | ENABLE_STRICT_OBJC_MSGSEND = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu99; 297 | GCC_NO_COMMON_BLOCKS = YES; 298 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 299 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 300 | GCC_WARN_UNDECLARED_SELECTOR = YES; 301 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 302 | GCC_WARN_UNUSED_FUNCTION = YES; 303 | GCC_WARN_UNUSED_VARIABLE = YES; 304 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 305 | MTL_ENABLE_DEBUG_INFO = NO; 306 | SDKROOT = iphoneos; 307 | TARGETED_DEVICE_FAMILY = "1,2"; 308 | VALIDATE_PRODUCT = YES; 309 | }; 310 | name = Profile; 311 | }; 312 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 313 | isa = XCBuildConfiguration; 314 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 315 | buildSettings = { 316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 317 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 318 | DEVELOPMENT_TEAM = S8QB4VV633; 319 | ENABLE_BITCODE = NO; 320 | FRAMEWORK_SEARCH_PATHS = ( 321 | "$(inherited)", 322 | "$(PROJECT_DIR)/Flutter", 323 | ); 324 | INFOPLIST_FILE = Runner/Info.plist; 325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 326 | LIBRARY_SEARCH_PATHS = ( 327 | "$(inherited)", 328 | "$(PROJECT_DIR)/Flutter", 329 | ); 330 | PRODUCT_BUNDLE_IDENTIFIER = com.kuky.demo.flutterShop; 331 | PRODUCT_NAME = "$(TARGET_NAME)"; 332 | VERSIONING_SYSTEM = "apple-generic"; 333 | }; 334 | name = Profile; 335 | }; 336 | 97C147031CF9000F007C117D /* Debug */ = { 337 | isa = XCBuildConfiguration; 338 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 339 | buildSettings = { 340 | ALWAYS_SEARCH_USER_PATHS = NO; 341 | CLANG_ANALYZER_NONNULL = YES; 342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 343 | CLANG_CXX_LIBRARY = "libc++"; 344 | CLANG_ENABLE_MODULES = YES; 345 | CLANG_ENABLE_OBJC_ARC = YES; 346 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 347 | CLANG_WARN_BOOL_CONVERSION = YES; 348 | CLANG_WARN_COMMA = YES; 349 | CLANG_WARN_CONSTANT_CONVERSION = YES; 350 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 351 | CLANG_WARN_EMPTY_BODY = YES; 352 | CLANG_WARN_ENUM_CONVERSION = YES; 353 | CLANG_WARN_INFINITE_RECURSION = YES; 354 | CLANG_WARN_INT_CONVERSION = YES; 355 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 356 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 357 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 358 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 359 | CLANG_WARN_STRICT_PROTOTYPES = YES; 360 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 361 | CLANG_WARN_UNREACHABLE_CODE = YES; 362 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 363 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 364 | COPY_PHASE_STRIP = NO; 365 | DEBUG_INFORMATION_FORMAT = dwarf; 366 | ENABLE_STRICT_OBJC_MSGSEND = YES; 367 | ENABLE_TESTABILITY = YES; 368 | GCC_C_LANGUAGE_STANDARD = gnu99; 369 | GCC_DYNAMIC_NO_PIC = NO; 370 | GCC_NO_COMMON_BLOCKS = YES; 371 | GCC_OPTIMIZATION_LEVEL = 0; 372 | GCC_PREPROCESSOR_DEFINITIONS = ( 373 | "DEBUG=1", 374 | "$(inherited)", 375 | ); 376 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 377 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 378 | GCC_WARN_UNDECLARED_SELECTOR = YES; 379 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 380 | GCC_WARN_UNUSED_FUNCTION = YES; 381 | GCC_WARN_UNUSED_VARIABLE = YES; 382 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 383 | MTL_ENABLE_DEBUG_INFO = YES; 384 | ONLY_ACTIVE_ARCH = YES; 385 | SDKROOT = iphoneos; 386 | TARGETED_DEVICE_FAMILY = "1,2"; 387 | }; 388 | name = Debug; 389 | }; 390 | 97C147041CF9000F007C117D /* Release */ = { 391 | isa = XCBuildConfiguration; 392 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 393 | buildSettings = { 394 | ALWAYS_SEARCH_USER_PATHS = NO; 395 | CLANG_ANALYZER_NONNULL = YES; 396 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 397 | CLANG_CXX_LIBRARY = "libc++"; 398 | CLANG_ENABLE_MODULES = YES; 399 | CLANG_ENABLE_OBJC_ARC = YES; 400 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 401 | CLANG_WARN_BOOL_CONVERSION = YES; 402 | CLANG_WARN_COMMA = YES; 403 | CLANG_WARN_CONSTANT_CONVERSION = YES; 404 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 405 | CLANG_WARN_EMPTY_BODY = YES; 406 | CLANG_WARN_ENUM_CONVERSION = YES; 407 | CLANG_WARN_INFINITE_RECURSION = YES; 408 | CLANG_WARN_INT_CONVERSION = YES; 409 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 413 | CLANG_WARN_STRICT_PROTOTYPES = YES; 414 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 415 | CLANG_WARN_UNREACHABLE_CODE = YES; 416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 418 | COPY_PHASE_STRIP = NO; 419 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 420 | ENABLE_NS_ASSERTIONS = NO; 421 | ENABLE_STRICT_OBJC_MSGSEND = YES; 422 | GCC_C_LANGUAGE_STANDARD = gnu99; 423 | GCC_NO_COMMON_BLOCKS = YES; 424 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 425 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 426 | GCC_WARN_UNDECLARED_SELECTOR = YES; 427 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 428 | GCC_WARN_UNUSED_FUNCTION = YES; 429 | GCC_WARN_UNUSED_VARIABLE = YES; 430 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 431 | MTL_ENABLE_DEBUG_INFO = NO; 432 | SDKROOT = iphoneos; 433 | TARGETED_DEVICE_FAMILY = "1,2"; 434 | VALIDATE_PRODUCT = YES; 435 | }; 436 | name = Release; 437 | }; 438 | 97C147061CF9000F007C117D /* Debug */ = { 439 | isa = XCBuildConfiguration; 440 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 441 | buildSettings = { 442 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 443 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 444 | ENABLE_BITCODE = NO; 445 | FRAMEWORK_SEARCH_PATHS = ( 446 | "$(inherited)", 447 | "$(PROJECT_DIR)/Flutter", 448 | ); 449 | INFOPLIST_FILE = Runner/Info.plist; 450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 451 | LIBRARY_SEARCH_PATHS = ( 452 | "$(inherited)", 453 | "$(PROJECT_DIR)/Flutter", 454 | ); 455 | PRODUCT_BUNDLE_IDENTIFIER = com.kuky.demo.flutterShop; 456 | PRODUCT_NAME = "$(TARGET_NAME)"; 457 | VERSIONING_SYSTEM = "apple-generic"; 458 | }; 459 | name = Debug; 460 | }; 461 | 97C147071CF9000F007C117D /* Release */ = { 462 | isa = XCBuildConfiguration; 463 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 464 | buildSettings = { 465 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 466 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 467 | ENABLE_BITCODE = NO; 468 | FRAMEWORK_SEARCH_PATHS = ( 469 | "$(inherited)", 470 | "$(PROJECT_DIR)/Flutter", 471 | ); 472 | INFOPLIST_FILE = Runner/Info.plist; 473 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 474 | LIBRARY_SEARCH_PATHS = ( 475 | "$(inherited)", 476 | "$(PROJECT_DIR)/Flutter", 477 | ); 478 | PRODUCT_BUNDLE_IDENTIFIER = com.kuky.demo.flutterShop; 479 | PRODUCT_NAME = "$(TARGET_NAME)"; 480 | VERSIONING_SYSTEM = "apple-generic"; 481 | }; 482 | name = Release; 483 | }; 484 | /* End XCBuildConfiguration section */ 485 | 486 | /* Begin XCConfigurationList section */ 487 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 488 | isa = XCConfigurationList; 489 | buildConfigurations = ( 490 | 97C147031CF9000F007C117D /* Debug */, 491 | 97C147041CF9000F007C117D /* Release */, 492 | 249021D3217E4FDB00AE95B9 /* Profile */, 493 | ); 494 | defaultConfigurationIsVisible = 0; 495 | defaultConfigurationName = Release; 496 | }; 497 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 498 | isa = XCConfigurationList; 499 | buildConfigurations = ( 500 | 97C147061CF9000F007C117D /* Debug */, 501 | 97C147071CF9000F007C117D /* Release */, 502 | 249021D4217E4FDB00AE95B9 /* Profile */, 503 | ); 504 | defaultConfigurationIsVisible = 0; 505 | defaultConfigurationName = Release; 506 | }; 507 | /* End XCConfigurationList section */ 508 | }; 509 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 510 | } 511 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/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/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kukyxs/flutter_shop/1b204ae6db6e8d1c625fbfa688f3abdfac643740/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_shop 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/configs/application.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:jpush_flutter/jpush_flutter.dart'; 3 | 4 | class Application { 5 | static Router router; 6 | static JPush jPush; 7 | } 8 | -------------------------------------------------------------------------------- /lib/configs/service_url.dart: -------------------------------------------------------------------------------- 1 | //const serviceUrl = 'http://test.baixingliangfan.cn/baixing'; 2 | const serviceUrl = 'http://v.jspang.com:8088/baixing/'; 3 | 4 | const servicePath = { 5 | 'homePageContent': '$serviceUrl/wxmini/homePageContent', // 商店首页 6 | 'homePageHotPart': '$serviceUrl/wxmini/homePageBelowConten', // 火爆专区 7 | 'getCategory': '$serviceUrl/wxmini/getCategory', // 获取分类列表 8 | 'getMallGoods': '$serviceUrl/wxmini/getMallGoods', // 获取分类列表 9 | 'getGoodDetailById': '$serviceUrl/wxmini/getGoodDetailById', // 获取分类列表 10 | }; 11 | -------------------------------------------------------------------------------- /lib/entities/category_entity.dart: -------------------------------------------------------------------------------- 1 | class CategoryEntity { 2 | String code; 3 | String message; 4 | List data; 5 | 6 | static CategoryEntity fromMap(Map map) { 7 | CategoryEntity category = new CategoryEntity(); 8 | category.code = map['code']; 9 | category.message = map['message']; 10 | category.data = CategoryData.fromMapList(map['data']); 11 | return category; 12 | } 13 | 14 | static List fromMapList(dynamic mapList) { 15 | List list = new List(mapList.length); 16 | for (int i = 0; i < mapList.length; i++) { 17 | list[i] = fromMap(mapList[i]); 18 | } 19 | return list; 20 | } 21 | } 22 | 23 | class CategoryData { 24 | String mallCategoryId; 25 | String mallCategoryName; 26 | String image; 27 | List bxMallSubDto; 28 | 29 | static CategoryData fromMap(Map map) { 30 | CategoryData dataListBean = new CategoryData(); 31 | dataListBean.mallCategoryId = map['mallCategoryId']; 32 | dataListBean.mallCategoryName = map['mallCategoryName']; 33 | dataListBean.image = map['image']; 34 | dataListBean.bxMallSubDto = BxMallSubDtoListBean.fromMapList(map['bxMallSubDto']); 35 | return dataListBean; 36 | } 37 | 38 | static List fromMapList(dynamic mapList) { 39 | List list = new List(mapList.length); 40 | for (int i = 0; i < mapList.length; i++) { 41 | list[i] = fromMap(mapList[i]); 42 | } 43 | return list; 44 | } 45 | } 46 | 47 | class BxMallSubDtoListBean { 48 | String mallSubId; 49 | String mallCategoryId; 50 | String mallSubName; 51 | String comments; 52 | 53 | static BxMallSubDtoListBean fromMap(Map map) { 54 | BxMallSubDtoListBean bxMallSubDtoListBean = new BxMallSubDtoListBean(); 55 | bxMallSubDtoListBean.mallSubId = map['mallSubId']; 56 | bxMallSubDtoListBean.mallCategoryId = map['mallCategoryId']; 57 | bxMallSubDtoListBean.mallSubName = map['mallSubName']; 58 | bxMallSubDtoListBean.comments = map['comments']; 59 | return bxMallSubDtoListBean; 60 | } 61 | 62 | static List fromMapList(dynamic mapList) { 63 | List list = new List(mapList.length); 64 | for (int i = 0; i < mapList.length; i++) { 65 | list[i] = fromMap(mapList[i]); 66 | } 67 | return list; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/entities/category_goods_entity.dart: -------------------------------------------------------------------------------- 1 | class CategoryGoodsEntity { 2 | String code; 3 | String message; 4 | List data; 5 | 6 | static CategoryGoodsEntity fromMap(Map map) { 7 | CategoryGoodsEntity bean = new CategoryGoodsEntity(); 8 | bean.code = map['code']; 9 | bean.message = map['message']; 10 | bean.data = CategoryGoodsInfo.fromMapList(map['data']); 11 | return bean; 12 | } 13 | 14 | static List fromMapList(dynamic mapList) { 15 | List list = new List(mapList.length); 16 | for (int i = 0; i < mapList.length; i++) { 17 | list[i] = fromMap(mapList[i]); 18 | } 19 | return list; 20 | } 21 | } 22 | 23 | class CategoryGoodsInfo { 24 | String image; 25 | String goodsId; 26 | String goodsName; 27 | double oriPrice; 28 | double presentPrice; 29 | 30 | static CategoryGoodsInfo fromMap(Map map) { 31 | CategoryGoodsInfo dataListBean = new CategoryGoodsInfo(); 32 | dataListBean.image = map['image']; 33 | dataListBean.goodsId = map['goodsId']; 34 | dataListBean.goodsName = map['goodsName']; 35 | dataListBean.oriPrice = map['oriPrice'] + 0.0; 36 | dataListBean.presentPrice = map['presentPrice'] + 0.0; 37 | return dataListBean; 38 | } 39 | 40 | static List fromMapList(dynamic mapList) { 41 | List list = new List(mapList.length); 42 | for (int i = 0; i < mapList.length; i++) { 43 | list[i] = fromMap(mapList[i]); 44 | } 45 | return list; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/entities/goods_detail_entity.dart: -------------------------------------------------------------------------------- 1 | class GoodsDetailEntity { 2 | String code; 3 | String message; 4 | GoodsDetailInfo data; 5 | 6 | static GoodsDetailEntity fromMap(Map map) { 7 | GoodsDetailEntity model = new GoodsDetailEntity(); 8 | model.code = map['code']; 9 | model.message = map['message']; 10 | model.data = GoodsDetailInfo.fromMap(map['data']); 11 | return model; 12 | } 13 | 14 | static List fromMapList(dynamic mapList) { 15 | List list = new List(mapList.length); 16 | for (int i = 0; i < mapList.length; i++) { 17 | list[i] = fromMap(mapList[i]); 18 | } 19 | return list; 20 | } 21 | } 22 | 23 | class GoodsDetailInfo { 24 | AdvertesPictureBean advertesPicture; 25 | GoodInfoBean goodInfo; 26 | List goodComments; 27 | 28 | static GoodsDetailInfo fromMap(Map map) { 29 | GoodsDetailInfo dataBean = new GoodsDetailInfo(); 30 | dataBean.advertesPicture = AdvertesPictureBean.fromMap(map['advertesPicture']); 31 | dataBean.goodInfo = GoodInfoBean.fromMap(map['goodInfo']); 32 | dataBean.goodComments = GoodCommentsListBean.fromMapList(map['goodComments']); 33 | return dataBean; 34 | } 35 | 36 | static List fromMapList(dynamic mapList) { 37 | List list = new List(mapList.length); 38 | for (int i = 0; i < mapList.length; i++) { 39 | list[i] = fromMap(mapList[i]); 40 | } 41 | return list; 42 | } 43 | } 44 | 45 | class AdvertesPictureBean { 46 | // ignore: non_constant_identifier_names 47 | String PICTURE_ADDRESS; 48 | 49 | // ignore: non_constant_identifier_names 50 | String TO_PLACE; 51 | 52 | static AdvertesPictureBean fromMap(Map map) { 53 | AdvertesPictureBean advertesPictureBean = new AdvertesPictureBean(); 54 | advertesPictureBean.PICTURE_ADDRESS = map['PICTURE_ADDRESS']; 55 | advertesPictureBean.TO_PLACE = map['TO_PLACE']; 56 | return advertesPictureBean; 57 | } 58 | 59 | static List fromMapList(dynamic mapList) { 60 | List list = new List(mapList.length); 61 | for (int i = 0; i < mapList.length; i++) { 62 | list[i] = fromMap(mapList[i]); 63 | } 64 | return list; 65 | } 66 | } 67 | 68 | class GoodInfoBean { 69 | String image5; 70 | String image3; 71 | String image4; 72 | String goodsId; 73 | String isOnline; 74 | String image1; 75 | String image2; 76 | String goodsSerialNumber; 77 | String comPic; 78 | String shopId; 79 | String goodsName; 80 | String goodsDetail; 81 | int amount; 82 | double oriPrice; 83 | double presentPrice; 84 | int state; 85 | 86 | static GoodInfoBean fromMap(Map map) { 87 | GoodInfoBean goodInfoBean = new GoodInfoBean(); 88 | goodInfoBean.image5 = map['image5']; 89 | goodInfoBean.image3 = map['image3']; 90 | goodInfoBean.image4 = map['image4']; 91 | goodInfoBean.goodsId = map['goodsId']; 92 | goodInfoBean.isOnline = map['isOnline']; 93 | goodInfoBean.image1 = map['image1']; 94 | goodInfoBean.image2 = map['image2']; 95 | goodInfoBean.goodsSerialNumber = map['goodsSerialNumber']; 96 | goodInfoBean.comPic = map['comPic']; 97 | goodInfoBean.shopId = map['shopId']; 98 | goodInfoBean.goodsName = map['goodsName']; 99 | goodInfoBean.goodsDetail = map['goodsDetail']; 100 | goodInfoBean.amount = map['amount']; 101 | goodInfoBean.oriPrice = map['oriPrice'] + 0.0; 102 | goodInfoBean.presentPrice = map['presentPrice'] + 0.0; 103 | goodInfoBean.state = map['state']; 104 | return goodInfoBean; 105 | } 106 | 107 | static List fromMapList(dynamic mapList) { 108 | List list = new List(mapList.length); 109 | for (int i = 0; i < mapList.length; i++) { 110 | list[i] = fromMap(mapList[i]); 111 | } 112 | return list; 113 | } 114 | } 115 | 116 | class GoodCommentsListBean { 117 | String comments; 118 | String userName; 119 | 120 | // ignore: non_constant_identifier_names 121 | int SCORE; 122 | int discussTime; 123 | 124 | static GoodCommentsListBean fromMap(Map map) { 125 | GoodCommentsListBean goodCommentsListBean = new GoodCommentsListBean(); 126 | goodCommentsListBean.comments = map['comments']; 127 | goodCommentsListBean.userName = map['userName']; 128 | goodCommentsListBean.SCORE = map['SCORE']; 129 | goodCommentsListBean.discussTime = map['discussTime']; 130 | return goodCommentsListBean; 131 | } 132 | 133 | static List fromMapList(dynamic mapList) { 134 | List list = new List(mapList.length); 135 | for (int i = 0; i < mapList.length; i++) { 136 | list[i] = fromMap(mapList[i]); 137 | } 138 | return list; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /lib/entities/home_page_entity.dart: -------------------------------------------------------------------------------- 1 | class HomePageEntity { 2 | String code; 3 | String message; 4 | HomeData data; 5 | 6 | HomePageEntity({this.code, this.message, this.data}); 7 | 8 | HomePageEntity.fromJson(Map json) { 9 | code = json['code']; 10 | message = json['message']; 11 | data = json['data'] != null ? new HomeData.fromJson(json['data']) : null; 12 | } 13 | 14 | Map toJson() { 15 | final Map data = new Map(); 16 | data['code'] = this.code; 17 | data['message'] = this.message; 18 | if (this.data != null) { 19 | data['data'] = this.data.toJson(); 20 | } 21 | return data; 22 | } 23 | } 24 | 25 | class HomeData { 26 | List slides; 27 | ShopInfo shopInfo; 28 | IntegralMallPic integralMallPic; 29 | ToShareCode toShareCode; 30 | List recommend; 31 | AdvertesPicture advertesPicture; 32 | List floor1; 33 | List floor2; 34 | List floor3; 35 | Saoma saoma; 36 | NewUser newUser; 37 | Floor1Pic floor1Pic; 38 | Floor2Pic floor2Pic; 39 | FloorName floorName; 40 | List category; 41 | Floor3Pic floor3Pic; 42 | 43 | HomeData( 44 | {this.slides, 45 | this.shopInfo, 46 | this.integralMallPic, 47 | this.toShareCode, 48 | this.recommend, 49 | this.advertesPicture, 50 | this.floor1, 51 | this.floor2, 52 | this.floor3, 53 | this.saoma, 54 | this.newUser, 55 | this.floor1Pic, 56 | this.floor2Pic, 57 | this.floorName, 58 | this.category, 59 | this.floor3Pic}); 60 | 61 | HomeData.fromJson(Map json) { 62 | if (json['slides'] != null) { 63 | slides = new List(); 64 | json['slides'].forEach((v) { 65 | slides.add(new Slides.fromJson(v)); 66 | }); 67 | } 68 | shopInfo = json['shopInfo'] != null ? new ShopInfo.fromJson(json['shopInfo']) : null; 69 | integralMallPic = json['integralMallPic'] != null ? new IntegralMallPic.fromJson(json['integralMallPic']) : null; 70 | toShareCode = json['toShareCode'] != null ? new ToShareCode.fromJson(json['toShareCode']) : null; 71 | if (json['recommend'] != null) { 72 | recommend = new List(); 73 | json['recommend'].forEach((v) { 74 | recommend.add(new Recommend.fromJson(v)); 75 | }); 76 | } 77 | advertesPicture = json['advertesPicture'] != null ? new AdvertesPicture.fromJson(json['advertesPicture']) : null; 78 | if (json['floor1'] != null) { 79 | floor1 = new List(); 80 | json['floor1'].forEach((v) { 81 | floor1.add(new Floor.fromJson(v)); 82 | }); 83 | } 84 | if (json['floor2'] != null) { 85 | floor2 = new List(); 86 | json['floor2'].forEach((v) { 87 | floor2.add(new Floor.fromJson(v)); 88 | }); 89 | } 90 | if (json['floor3'] != null) { 91 | floor3 = new List(); 92 | json['floor3'].forEach((v) { 93 | floor3.add(new Floor.fromJson(v)); 94 | }); 95 | } 96 | saoma = json['saoma'] != null ? new Saoma.fromJson(json['saoma']) : null; 97 | newUser = json['newUser'] != null ? new NewUser.fromJson(json['newUser']) : null; 98 | floor1Pic = json['floor1Pic'] != null ? new Floor1Pic.fromJson(json['floor1Pic']) : null; 99 | floor2Pic = json['floor2Pic'] != null ? new Floor2Pic.fromJson(json['floor2Pic']) : null; 100 | floorName = json['floorName'] != null ? new FloorName.fromJson(json['floorName']) : null; 101 | if (json['category'] != null) { 102 | category = new List(); 103 | json['category'].forEach((v) { 104 | category.add(new Category.fromJson(v)); 105 | }); 106 | } 107 | floor3Pic = json['floor3Pic'] != null ? new Floor3Pic.fromJson(json['floor3Pic']) : null; 108 | } 109 | 110 | Map toJson() { 111 | final Map data = new Map(); 112 | if (this.slides != null) { 113 | data['slides'] = this.slides.map((v) => v.toJson()).toList(); 114 | } 115 | if (this.shopInfo != null) { 116 | data['shopInfo'] = this.shopInfo.toJson(); 117 | } 118 | if (this.integralMallPic != null) { 119 | data['integralMallPic'] = this.integralMallPic.toJson(); 120 | } 121 | if (this.toShareCode != null) { 122 | data['toShareCode'] = this.toShareCode.toJson(); 123 | } 124 | if (this.recommend != null) { 125 | data['recommend'] = this.recommend.map((v) => v.toJson()).toList(); 126 | } 127 | if (this.advertesPicture != null) { 128 | data['advertesPicture'] = this.advertesPicture.toJson(); 129 | } 130 | if (this.floor1 != null) { 131 | data['floor1'] = this.floor1.map((v) => v.toJson()).toList(); 132 | } 133 | if (this.floor2 != null) { 134 | data['floor2'] = this.floor2.map((v) => v.toJson()).toList(); 135 | } 136 | if (this.floor3 != null) { 137 | data['floor3'] = this.floor3.map((v) => v.toJson()).toList(); 138 | } 139 | if (this.saoma != null) { 140 | data['saoma'] = this.saoma.toJson(); 141 | } 142 | if (this.newUser != null) { 143 | data['newUser'] = this.newUser.toJson(); 144 | } 145 | if (this.floor1Pic != null) { 146 | data['floor1Pic'] = this.floor1Pic.toJson(); 147 | } 148 | if (this.floor2Pic != null) { 149 | data['floor2Pic'] = this.floor2Pic.toJson(); 150 | } 151 | if (this.floorName != null) { 152 | data['floorName'] = this.floorName.toJson(); 153 | } 154 | if (this.category != null) { 155 | data['category'] = this.category.map((v) => v.toJson()).toList(); 156 | } 157 | if (this.floor3Pic != null) { 158 | data['floor3Pic'] = this.floor3Pic.toJson(); 159 | } 160 | return data; 161 | } 162 | } 163 | 164 | class Slides { 165 | String image; 166 | String goodsId; 167 | 168 | Slides({this.image, this.goodsId}); 169 | 170 | Slides.fromJson(Map json) { 171 | image = json['image']; 172 | goodsId = json['goodsId']; 173 | } 174 | 175 | Map toJson() { 176 | final Map data = new Map(); 177 | data['image'] = this.image; 178 | data['goodsId'] = this.goodsId; 179 | return data; 180 | } 181 | } 182 | 183 | class ShopInfo { 184 | String leaderImage; 185 | String leaderPhone; 186 | 187 | ShopInfo({this.leaderImage, this.leaderPhone}); 188 | 189 | ShopInfo.fromJson(Map json) { 190 | leaderImage = json['leaderImage']; 191 | leaderPhone = json['leaderPhone']; 192 | } 193 | 194 | Map toJson() { 195 | final Map data = new Map(); 196 | data['leaderImage'] = this.leaderImage; 197 | data['leaderPhone'] = this.leaderPhone; 198 | return data; 199 | } 200 | } 201 | 202 | class IntegralMallPic { 203 | String pICTUREADDRESS; 204 | String tOPLACE; 205 | 206 | IntegralMallPic({this.pICTUREADDRESS, this.tOPLACE}); 207 | 208 | IntegralMallPic.fromJson(Map json) { 209 | pICTUREADDRESS = json['PICTURE_ADDRESS']; 210 | tOPLACE = json['TO_PLACE']; 211 | } 212 | 213 | Map toJson() { 214 | final Map data = new Map(); 215 | data['PICTURE_ADDRESS'] = this.pICTUREADDRESS; 216 | data['TO_PLACE'] = this.tOPLACE; 217 | return data; 218 | } 219 | } 220 | 221 | class ToShareCode { 222 | String pICTUREADDRESS; 223 | String tOPLACE; 224 | 225 | ToShareCode({this.pICTUREADDRESS, this.tOPLACE}); 226 | 227 | ToShareCode.fromJson(Map json) { 228 | pICTUREADDRESS = json['PICTURE_ADDRESS']; 229 | tOPLACE = json['TO_PLACE']; 230 | } 231 | 232 | Map toJson() { 233 | final Map data = new Map(); 234 | data['PICTURE_ADDRESS'] = this.pICTUREADDRESS; 235 | data['TO_PLACE'] = this.tOPLACE; 236 | return data; 237 | } 238 | } 239 | 240 | class Recommend { 241 | String image; 242 | double mallPrice; 243 | String goodsName; 244 | String goodsId; 245 | double price; 246 | 247 | Recommend({this.image, this.mallPrice, this.goodsName, this.goodsId, this.price}); 248 | 249 | Recommend.fromJson(Map json) { 250 | image = json['image']; 251 | mallPrice = json['mallPrice'] + 0.0; 252 | goodsName = json['goodsName']; 253 | goodsId = json['goodsId']; 254 | price = json['price'] + 0.0; 255 | } 256 | 257 | Map toJson() { 258 | final Map data = new Map(); 259 | data['image'] = this.image; 260 | data['mallPrice'] = this.mallPrice; 261 | data['goodsName'] = this.goodsName; 262 | data['goodsId'] = this.goodsId; 263 | data['price'] = this.price; 264 | return data; 265 | } 266 | } 267 | 268 | class AdvertesPicture { 269 | String pICTUREADDRESS; 270 | String tOPLACE; 271 | 272 | AdvertesPicture({this.pICTUREADDRESS, this.tOPLACE}); 273 | 274 | AdvertesPicture.fromJson(Map json) { 275 | pICTUREADDRESS = json['PICTURE_ADDRESS']; 276 | tOPLACE = json['TO_PLACE']; 277 | } 278 | 279 | Map toJson() { 280 | final Map data = new Map(); 281 | data['PICTURE_ADDRESS'] = this.pICTUREADDRESS; 282 | data['TO_PLACE'] = this.tOPLACE; 283 | return data; 284 | } 285 | } 286 | 287 | class Floor { 288 | String image; 289 | String goodsId; 290 | 291 | Floor({this.image, this.goodsId}); 292 | 293 | Floor.fromJson(Map json) { 294 | image = json['image']; 295 | goodsId = json['goodsId']; 296 | } 297 | 298 | Map toJson() { 299 | final Map data = new Map(); 300 | data['image'] = this.image; 301 | data['goodsId'] = this.goodsId; 302 | return data; 303 | } 304 | } 305 | 306 | class Saoma { 307 | String pICTUREADDRESS; 308 | String tOPLACE; 309 | 310 | Saoma({this.pICTUREADDRESS, this.tOPLACE}); 311 | 312 | Saoma.fromJson(Map json) { 313 | pICTUREADDRESS = json['PICTURE_ADDRESS']; 314 | tOPLACE = json['TO_PLACE']; 315 | } 316 | 317 | Map toJson() { 318 | final Map data = new Map(); 319 | data['PICTURE_ADDRESS'] = this.pICTUREADDRESS; 320 | data['TO_PLACE'] = this.tOPLACE; 321 | return data; 322 | } 323 | } 324 | 325 | class NewUser { 326 | String pICTUREADDRESS; 327 | String tOPLACE; 328 | 329 | NewUser({this.pICTUREADDRESS, this.tOPLACE}); 330 | 331 | NewUser.fromJson(Map json) { 332 | pICTUREADDRESS = json['PICTURE_ADDRESS']; 333 | tOPLACE = json['TO_PLACE']; 334 | } 335 | 336 | Map toJson() { 337 | final Map data = new Map(); 338 | data['PICTURE_ADDRESS'] = this.pICTUREADDRESS; 339 | data['TO_PLACE'] = this.tOPLACE; 340 | return data; 341 | } 342 | } 343 | 344 | class Floor1Pic { 345 | String pICTUREADDRESS; 346 | String tOPLACE; 347 | 348 | Floor1Pic({this.pICTUREADDRESS, this.tOPLACE}); 349 | 350 | Floor1Pic.fromJson(Map json) { 351 | pICTUREADDRESS = json['PICTURE_ADDRESS']; 352 | tOPLACE = json['TO_PLACE']; 353 | } 354 | 355 | Map toJson() { 356 | final Map data = new Map(); 357 | data['PICTURE_ADDRESS'] = this.pICTUREADDRESS; 358 | data['TO_PLACE'] = this.tOPLACE; 359 | return data; 360 | } 361 | } 362 | 363 | class Floor2Pic { 364 | String pICTUREADDRESS; 365 | String tOPLACE; 366 | 367 | Floor2Pic({this.pICTUREADDRESS, this.tOPLACE}); 368 | 369 | Floor2Pic.fromJson(Map json) { 370 | pICTUREADDRESS = json['PICTURE_ADDRESS']; 371 | tOPLACE = json['TO_PLACE']; 372 | } 373 | 374 | Map toJson() { 375 | final Map data = new Map(); 376 | data['PICTURE_ADDRESS'] = this.pICTUREADDRESS; 377 | data['TO_PLACE'] = this.tOPLACE; 378 | return data; 379 | } 380 | } 381 | 382 | class FloorName { 383 | String floor1; 384 | String floor2; 385 | String floor3; 386 | 387 | FloorName({this.floor1, this.floor2, this.floor3}); 388 | 389 | FloorName.fromJson(Map json) { 390 | floor1 = json['floor1']; 391 | floor2 = json['floor2']; 392 | floor3 = json['floor3']; 393 | } 394 | 395 | Map toJson() { 396 | final Map data = new Map(); 397 | data['floor1'] = this.floor1; 398 | data['floor2'] = this.floor2; 399 | data['floor3'] = this.floor3; 400 | return data; 401 | } 402 | } 403 | 404 | class Category { 405 | String mallCategoryId; 406 | String mallCategoryName; 407 | List bxMallSubDto; 408 | Null comments; 409 | String image; 410 | 411 | Category({this.mallCategoryId, this.mallCategoryName, this.bxMallSubDto, this.comments, this.image}); 412 | 413 | Category.fromJson(Map json) { 414 | mallCategoryId = json['mallCategoryId']; 415 | mallCategoryName = json['mallCategoryName']; 416 | if (json['bxMallSubDto'] != null) { 417 | bxMallSubDto = new List(); 418 | json['bxMallSubDto'].forEach((v) { 419 | bxMallSubDto.add(new BxMallSubDto.fromJson(v)); 420 | }); 421 | } 422 | comments = json['comments']; 423 | image = json['image']; 424 | } 425 | 426 | Map toJson() { 427 | final Map data = new Map(); 428 | data['mallCategoryId'] = this.mallCategoryId; 429 | data['mallCategoryName'] = this.mallCategoryName; 430 | if (this.bxMallSubDto != null) { 431 | data['bxMallSubDto'] = this.bxMallSubDto.map((v) => v.toJson()).toList(); 432 | } 433 | data['comments'] = this.comments; 434 | data['image'] = this.image; 435 | return data; 436 | } 437 | } 438 | 439 | class BxMallSubDto { 440 | String mallSubId; 441 | String mallCategoryId; 442 | String mallSubName; 443 | String comments; 444 | 445 | BxMallSubDto({this.mallSubId, this.mallCategoryId, this.mallSubName, this.comments}); 446 | 447 | BxMallSubDto.fromJson(Map json) { 448 | mallSubId = json['mallSubId']; 449 | mallCategoryId = json['mallCategoryId']; 450 | mallSubName = json['mallSubName']; 451 | comments = json['comments']; 452 | } 453 | 454 | Map toJson() { 455 | final Map data = new Map(); 456 | data['mallSubId'] = this.mallSubId; 457 | data['mallCategoryId'] = this.mallCategoryId; 458 | data['mallSubName'] = this.mallSubName; 459 | data['comments'] = this.comments; 460 | return data; 461 | } 462 | } 463 | 464 | class Floor3Pic { 465 | String pICTUREADDRESS; 466 | String tOPLACE; 467 | 468 | Floor3Pic({this.pICTUREADDRESS, this.tOPLACE}); 469 | 470 | Floor3Pic.fromJson(Map json) { 471 | pICTUREADDRESS = json['PICTURE_ADDRESS']; 472 | tOPLACE = json['TO_PLACE']; 473 | } 474 | 475 | Map toJson() { 476 | final Map data = new Map(); 477 | data['PICTURE_ADDRESS'] = this.pICTUREADDRESS; 478 | data['TO_PLACE'] = this.tOPLACE; 479 | return data; 480 | } 481 | } 482 | -------------------------------------------------------------------------------- /lib/entities/hot_goods_entity.dart: -------------------------------------------------------------------------------- 1 | class HotGoodsEntity { 2 | String code; 3 | String message; 4 | List data; 5 | 6 | HotGoodsEntity({this.code, this.message, this.data}); 7 | 8 | HotGoodsEntity.fromJson(Map json) { 9 | code = json['code']; 10 | message = json['message']; 11 | if (json['data'] != null) { 12 | data = new List(); 13 | json['data'].forEach((v) { 14 | data.add(new HotGoodsData.fromJson(v)); 15 | }); 16 | } 17 | } 18 | 19 | Map toJson() { 20 | final Map data = new Map(); 21 | data['code'] = this.code; 22 | data['message'] = this.message; 23 | if (this.data != null) { 24 | data['data'] = this.data.map((v) => v.toJson()).toList(); 25 | } 26 | return data; 27 | } 28 | } 29 | 30 | class HotGoodsData { 31 | String name; 32 | String image; 33 | double mallPrice; 34 | String goodsId; 35 | double price; 36 | 37 | HotGoodsData({this.name, this.image, this.mallPrice, this.goodsId, this.price}); 38 | 39 | HotGoodsData.fromJson(Map json) { 40 | name = json['name']; 41 | image = json['image']; 42 | mallPrice = json['mallPrice'] + 0.0; 43 | goodsId = json['goodsId']; 44 | price = json['price'] + 0.0; 45 | } 46 | 47 | Map toJson() { 48 | final Map data = new Map(); 49 | data['name'] = this.name; 50 | data['image'] = this.image; 51 | data['mallPrice'] = this.mallPrice; 52 | data['goodsId'] = this.goodsId; 53 | data['price'] = this.price; 54 | return data; 55 | } 56 | 57 | static List fromMapList(dynamic mapList) { 58 | List list = []; 59 | mapList.forEach((map) { 60 | list.add(HotGoodsData.fromJson(map)); 61 | }); 62 | return list; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/entities/shopping_cart_entity.dart: -------------------------------------------------------------------------------- 1 | class ShoppingCartEntity { 2 | String goodsName; 3 | String goodsId; 4 | String goodsImg; 5 | double orgPrice; 6 | double price; 7 | int count; 8 | bool isChecked; 9 | 10 | ShoppingCartEntity({this.goodsName, this.goodsId, this.goodsImg, this.orgPrice, this.price, this.count, this.isChecked}); 11 | 12 | ShoppingCartEntity.fromJson(Map json) { 13 | goodsName = json['goodsName']; 14 | goodsId = json['goodsId']; 15 | goodsImg = json['goodsImg']; 16 | orgPrice = json['orgPrice'] + 0.0; 17 | price = json['price'] + 0.0; 18 | count = json['count']; 19 | isChecked = json['isChecked']; 20 | } 21 | 22 | static List fromJsonList(dynamic maps) { 23 | List list = List(maps.length); 24 | for (int i = 0; i < maps.length; i++) { 25 | list[i] = ShoppingCartEntity.fromJson(maps[i]); 26 | } 27 | return list; 28 | } 29 | 30 | Map toJson() { 31 | final Map data = new Map(); 32 | data['goodsName'] = this.goodsName; 33 | data['goodsId'] = this.goodsId; 34 | data['goodsImg'] = this.goodsImg; 35 | data['orgPrice'] = this.orgPrice; 36 | data['price'] = this.price; 37 | data['count'] = this.count; 38 | data['isChecked'] = this.isChecked; 39 | return data; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:fluro/fluro.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/services.dart'; 6 | import 'package:flutter_shop/configs/application.dart'; 7 | import 'package:flutter_shop/provides/cart_count_provide.dart'; 8 | import 'package:flutter_shop/provides/cart_provide.dart'; 9 | import 'package:flutter_shop/provides/home_provide.dart'; 10 | import 'package:flutter_shop/provides/page_index_provide.dart'; 11 | import 'package:flutter_shop/router/routers.dart'; 12 | import 'package:flutter_shop/shop_app.dart'; 13 | import 'package:provide/provide.dart'; 14 | 15 | import 'provides/goods_detail_provide.dart'; 16 | import 'provides/mall_goods_provide.dart'; 17 | import 'provides/sub_category_provide.dart'; 18 | import 'package:jpush_flutter/jpush_flutter.dart'; 19 | 20 | void main() { 21 | final providers = Providers() 22 | ..provide(Provider.function((_) => HomeProvide())) // 主页面 23 | ..provide(Provider.function((_) => PageIndexProvide())) // 主页面 tab 切换 24 | ..provide(Provider.function((_) => CartCountProvide())) // 详情页面购物车数量修改 25 | ..provide(Provider.function((_) => SubCategoryProvide())) // 分类页面切换 26 | ..provide(Provider.function((_) => MallGoodsProvide())) // 分类页面刷新加载 27 | ..provide(Provider.function((_) => GoodsDetailProvide())) // 商品详情页面 28 | ..provide(Provider.function((_) => CartProvide())); // 购物车持久化 29 | 30 | final Router router = Router(); 31 | Routers.configureRouters(router); 32 | Application.router = router; 33 | 34 | final JPush push = JPush(); 35 | Application.jPush = push; 36 | setUpJPush(push); 37 | 38 | // 强制竖屏 39 | SystemChrome.setPreferredOrientations([DeviceOrientation.portraitDown, DeviceOrientation.portraitUp]).then((_) { 40 | runApp(ProviderNode(child: ShopApp(), providers: providers)); 41 | 42 | // android 下透明状态栏 43 | if (Platform.isAndroid) { 44 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(statusBarColor: Colors.transparent)); 45 | } 46 | }); 47 | } 48 | 49 | setUpJPush(JPush jPush) { 50 | jPush.addEventHandler(onReceiveNotification: (Map message) async { 51 | print("flutter onReceiveNotification: $message"); 52 | }, onOpenNotification: (Map message) async { 53 | print("flutter onOpenNotification: $message"); 54 | }, onReceiveMessage: (Map message) async { 55 | print("flutter onReceiveMessage: $message"); 56 | }); 57 | 58 | jPush.setup(appKey: '696247cca94724deaab1cae5', channel: 'shop_dev', production: false, debug: true); 59 | jPush.getRegistrationID().then((rid) { 60 | print('jpush rid: $rid'); 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /lib/pages/cartpage/bottom_summary.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/provides/cart_provide.dart'; 3 | 4 | class BottomCartSummary extends StatelessWidget { 5 | final CartProvide cartProvide; 6 | 7 | BottomCartSummary({Key key, this.cartProvide}) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), 13 | height: 60.0, 14 | child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ 15 | Checkbox( 16 | value: cartProvide.allCheckedState, 17 | onChanged: (checkState) { 18 | cartProvide.allCheckStateChange(checkState); 19 | }, 20 | activeColor: Colors.pink), 21 | Text('全选', style: TextStyle(color: Colors.black, fontSize: 15.0)), 22 | // 合计价格 23 | Expanded( 24 | child: Container( 25 | padding: const EdgeInsets.symmetric(horizontal: 12.0), 26 | child: Column( 27 | crossAxisAlignment: CrossAxisAlignment.end, 28 | mainAxisAlignment: MainAxisAlignment.center, 29 | children: [ 30 | Row( 31 | mainAxisAlignment: MainAxisAlignment.end, 32 | children: [ 33 | Text('合计:', style: TextStyle(color: Colors.black, fontSize: 18.0)), 34 | Text('¥${cartProvide.allCheckedPrice}', style: TextStyle(color: Colors.red[700], fontSize: 16.0)), 35 | ], 36 | ), 37 | Text('满10元免费配送,预购免费配送', style: TextStyle(color: Colors.black, fontSize: 10.0)) 38 | ], 39 | ))), 40 | // 结算按钮 41 | RaisedButton( 42 | onPressed: () {}, 43 | child: Text('结算(${cartProvide.allCheckedCount})', style: TextStyle(color: Colors.white)), 44 | color: Colors.pink, 45 | ) 46 | ]), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/pages/cartpage/cart_count.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/provides/cart_provide.dart'; 3 | 4 | class CartCountWidget extends StatelessWidget { 5 | final int count; 6 | final String goodsId; 7 | final CartProvide cartProvide; 8 | 9 | CartCountWidget({Key key, this.count, this.goodsId, this.cartProvide}) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | width: 120.0, 15 | height: 30.0, 16 | decoration: ShapeDecoration( 17 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0)), side: BorderSide(color: Colors.black54)), 18 | ), 19 | child: Row( 20 | crossAxisAlignment: CrossAxisAlignment.center, 21 | children: [ 22 | // 减值操作,数量为 1 停止 23 | Expanded( 24 | child: InkWell( 25 | onTap: count == 1 ? null : () => cartProvide.increaseOrReduceOperation(goodsId, false), 26 | child: DecoratedBox( 27 | decoration: BoxDecoration( 28 | border: Border(right: BorderSide(color: Colors.black54, width: 1.0)), 29 | ), 30 | child: Center(child: Text('-', style: TextStyle(fontSize: 16.0, color: Colors.black)))), 31 | ), 32 | ), 33 | Expanded(child: Center(child: Text('$count', style: TextStyle(fontSize: 14.0, color: Colors.black))), flex: 2), 34 | // 加值操作 35 | Expanded( 36 | child: InkWell( 37 | onTap: () => cartProvide.increaseOrReduceOperation(goodsId, true), 38 | child: DecoratedBox( 39 | decoration: BoxDecoration( 40 | border: Border(left: BorderSide(color: Colors.black54, width: 1.0)), 41 | ), 42 | child: Center(child: Text('+', style: TextStyle(fontSize: 16.0, color: Colors.black)))), 43 | ), 44 | ) 45 | ], 46 | ), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/pages/cartpage/cart_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_shop/pages/cartpage/bottom_summary.dart'; 4 | import 'package:flutter_shop/pages/cartpage/empty_cart.dart'; 5 | import 'package:flutter_shop/pages/cartpage/shopping_cart_list.dart'; 6 | import 'package:flutter_shop/provides/cart_provide.dart'; 7 | import 'package:provide/provide.dart'; 8 | 9 | class CartPage extends StatelessWidget { 10 | @override 11 | Widget build(BuildContext context) { 12 | return Provide( 13 | builder: (_, child, cartProvide) => Scaffold( 14 | appBar: AppBar(title: Text('购物车'), centerTitle: true), 15 | body: cartProvide.shopCarts.isEmpty 16 | // 购物车为空情况 17 | ? EmptyShoppingCart() 18 | // 购物车非空情况 19 | : ShoppingCartList(cartProvide: cartProvide), 20 | bottomNavigationBar: cartProvide.shopCarts.isEmpty 21 | ? null 22 | : BottomAppBar( 23 | child: BottomCartSummary(cartProvide: cartProvide), 24 | ), 25 | )); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/pages/cartpage/empty_cart.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_shop/provides/page_index_provide.dart'; 4 | import 'package:provide/provide.dart'; 5 | 6 | class EmptyShoppingCart extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | return Container( 10 | alignment: Alignment.center, 11 | child: Column( 12 | mainAxisAlignment: MainAxisAlignment.center, 13 | children: [ 14 | DecoratedBox( 15 | decoration: ShapeDecoration(shape: CircleBorder(), color: Colors.black12), 16 | child: Padding( 17 | padding: const EdgeInsets.all(8.0), 18 | child: Icon(CupertinoIcons.shopping_cart, size: 50.0, color: Colors.white), 19 | )), 20 | Padding( 21 | padding: const EdgeInsets.symmetric(vertical: 4.0), 22 | child: Text('购物车还空着,快去挑选商品吧~', style: TextStyle(fontSize: 12.0, color: Colors.black26)), 23 | ), 24 | RaisedButton( 25 | onPressed: () => Provide.value(context).changePage(0), 26 | child: Text('随便逛逛', style: TextStyle(color: Colors.white)), 27 | color: Colors.pink) 28 | ], 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/pages/cartpage/shopping_cart_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_shop/entities/shopping_cart_entity.dart'; 4 | import 'package:flutter_shop/pages/cartpage/cart_count.dart'; 5 | import 'package:flutter_shop/provides/cart_provide.dart'; 6 | 7 | class ShoppingCartList extends StatelessWidget { 8 | final CartProvide cartProvide; 9 | 10 | ShoppingCartList({Key key, this.cartProvide}) : super(key: key); 11 | 12 | /// 列表小计 13 | Widget _cartSummaryItem() { 14 | return Container( 15 | color: Colors.white, 16 | padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), 17 | child: Row( 18 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 19 | children: [ 20 | Text( 21 | '共${cartProvide.allCheckedCount}件商品', 22 | style: TextStyle(color: Colors.black), 23 | ), 24 | Text( 25 | '小计:¥${cartProvide.allCheckedPrice}', 26 | style: TextStyle(color: Colors.red[700]), 27 | ) 28 | ], 29 | ), 30 | ); 31 | } 32 | 33 | /// 前置部分,checkbox image 34 | Widget _leadingPart(ShoppingCartEntity entity) { 35 | return Row( 36 | children: [ 37 | Checkbox( 38 | value: entity.isChecked, 39 | onChanged: (checkState) { 40 | // 修改商品选择状态 41 | cartProvide.changeCartState(entity.goodsId, checkState); 42 | }, 43 | activeColor: Colors.pink), 44 | // 商品图标 45 | DecoratedBox( 46 | decoration: ShapeDecoration(shape: RoundedRectangleBorder(), color: Colors.black12), 47 | child: Padding( 48 | padding: const EdgeInsets.all(1.0), 49 | child: Image.network(entity.goodsImg, height: 80.0, width: 80.0), 50 | ), 51 | ) 52 | ], 53 | ); 54 | } 55 | 56 | /// 中间部分,商品名 计数器 57 | Widget _middlePart(ShoppingCartEntity entity) { 58 | return Expanded( 59 | child: Container( 60 | height: 80.0, // 该部件同图片同高 61 | padding: const EdgeInsets.symmetric(horizontal: 8.0), 62 | child: Column( 63 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 64 | crossAxisAlignment: CrossAxisAlignment.start, 65 | children: [ 66 | Text( 67 | entity.goodsName, 68 | style: TextStyle(color: Colors.black, fontSize: 16.0), 69 | maxLines: 1, 70 | overflow: TextOverflow.ellipsis, 71 | ), 72 | // 数量管理器 73 | CartCountWidget( 74 | count: entity.count, 75 | goodsId: entity.goodsId, 76 | cartProvide: cartProvide, 77 | ) 78 | ], 79 | ), 80 | ), 81 | ); 82 | } 83 | 84 | /// 尾部价格部分 85 | Widget _trailingPart(ShoppingCartEntity entity) { 86 | return Column( 87 | crossAxisAlignment: CrossAxisAlignment.end, 88 | children: [ 89 | Text( 90 | '¥${(entity.count * entity.price).toStringAsFixed(2)}', 91 | style: TextStyle(color: Colors.black, fontSize: 16.0), 92 | ), 93 | Text( 94 | '¥${(entity.count * entity.orgPrice).toStringAsFixed(2)}', 95 | style: TextStyle(color: Colors.black54, fontSize: 14.0, decoration: TextDecoration.lineThrough), 96 | ), 97 | InkWell( 98 | child: Icon(CupertinoIcons.delete, size: 32.0), 99 | onTap: () { 100 | cartProvide.removeCarts(entity.goodsId); 101 | }) 102 | ], 103 | ); 104 | } 105 | 106 | @override 107 | Widget build(BuildContext context) { 108 | return ListView.separated( 109 | itemBuilder: (_, index) => index == cartProvide.shopCarts.length 110 | ? _cartSummaryItem() 111 | : Container( 112 | color: Colors.white, 113 | padding: const EdgeInsets.all(12.0), 114 | child: Row( 115 | children: [ 116 | _leadingPart(cartProvide.shopCarts[index]), 117 | _middlePart(cartProvide.shopCarts[index]), 118 | _trailingPart(cartProvide.shopCarts[index]) 119 | ], 120 | ), 121 | ), 122 | separatorBuilder: (_, index) => Divider(height: 1.0, color: Colors.black26), 123 | itemCount: cartProvide.shopCarts.length + 1, 124 | ); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /lib/pages/category_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_easyrefresh/ball_pulse_footer.dart'; 5 | import 'package:flutter_easyrefresh/ball_pulse_header.dart'; 6 | import 'package:flutter_easyrefresh/easy_refresh.dart'; 7 | import 'package:flutter_shop/configs/application.dart'; 8 | import 'package:flutter_shop/entities/category_entity.dart'; 9 | import 'package:flutter_shop/entities/category_goods_entity.dart'; 10 | import 'package:flutter_shop/provides/mall_goods_provide.dart'; 11 | import 'package:flutter_shop/provides/sub_category_provide.dart'; 12 | import 'package:flutter_shop/router/routers.dart'; 13 | import 'package:flutter_shop/service/service_method.dart'; 14 | import 'package:fluttertoast/fluttertoast.dart'; 15 | import 'package:provide/provide.dart'; 16 | 17 | class CategoryPage extends StatefulWidget { 18 | @override 19 | _CategoryPageState createState() => _CategoryPageState(); 20 | } 21 | 22 | class _CategoryPageState extends State { 23 | List categories = []; 24 | GlobalKey _refreshKey = GlobalKey(); 25 | GlobalKey _headerKey = GlobalKey(); 26 | GlobalKey _footerKey = GlobalKey(); 27 | ScrollController _gridController = ScrollController(); 28 | ScrollController _topNavController = ScrollController(); 29 | int selectPosition = 0; 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | _requestCategories(); 35 | } 36 | 37 | @override 38 | void dispose() { 39 | _gridController.dispose(); 40 | _topNavController.dispose(); 41 | super.dispose(); 42 | } 43 | 44 | void _requestCategories() { 45 | getCategories().then((response) { 46 | setState(() { 47 | categories.addAll(CategoryEntity.fromMap(json.decode(response.data)).data); 48 | // 默认初始值列表 49 | Provide.value(context).changeLeftHeadCategories(categories[0].bxMallSubDto); 50 | Provide.value(context).changeCategory(categories[0].mallCategoryId); 51 | _requestGoodsList(); 52 | }); 53 | }); 54 | } 55 | 56 | // 获取右侧标签下的商品列表 57 | void _requestGoodsList() { 58 | getMallGoods(Provide.value(context).categoryId, Provide.value(context).subCategoryId, 59 | Provide.value(context).page) 60 | .then((response) { 61 | Map jsonFormat = json.decode(response.data); 62 | // 返回有数据才解析 63 | if (jsonFormat['data'] != null) { 64 | CategoryGoodsEntity goods = CategoryGoodsEntity.fromMap(jsonFormat); 65 | if (Provide.value(context).page == 1) { 66 | Provide.value(context).changeGoodsList(goods.data); 67 | } else { 68 | Provide.value(context).loadMoreGoodsList(goods.data); 69 | } 70 | Provide.value(context).increasePage(); 71 | } else { 72 | // 无数据返回情况 73 | if (Provide.value(context).page == 1) 74 | Provide.value(context).changeGoodsList([]); 75 | else { 76 | Fluttertoast.showToast(msg: '没有更多啦~'); 77 | Provide.value(context).loadMoreGoodsList([]); 78 | } 79 | } 80 | }); 81 | } 82 | 83 | // 左侧大类导航列表 item 84 | InkWell _leftCategoryItem(int index, BuildContext context) { 85 | return InkWell( 86 | onTap: () { 87 | setState(() => selectPosition = index); 88 | Provide.value(context).changeLeftHeadCategories(categories[index].bxMallSubDto); 89 | Provide.value(context).changeCategory(categories[index].mallCategoryId); 90 | Provide.value(context).initialPage(); 91 | _requestGoodsList(); 92 | _gridController.animateTo(0, duration: Duration(milliseconds: 500), curve: Curves.decelerate); 93 | _topNavController.animateTo(0, duration: Duration(milliseconds: 300), curve: Curves.decelerate); 94 | }, 95 | child: Container( 96 | color: index == selectPosition ? Colors.black12 : Colors.white, 97 | height: 60.0, 98 | child: Text(categories[index].mallCategoryName, style: TextStyle(fontSize: 15.0, color: Colors.black)), 99 | alignment: Alignment.centerLeft, 100 | padding: const EdgeInsets.symmetric(horizontal: 8.0), 101 | ), 102 | ); 103 | } 104 | 105 | // 右侧头部导航列表 item 106 | Widget _subCategoryNav(int index, BxMallSubDtoListBean subDto) { 107 | return InkWell( 108 | onTap: () { 109 | Provide.value(context).changeSubCategorySelect(subDto.mallSubId); 110 | Provide.value(context).changeSubCategoryIndex(index); 111 | Provide.value(context).initialPage(); 112 | _requestGoodsList(); 113 | _gridController.animateTo(0, duration: Duration(milliseconds: 500), curve: Curves.decelerate); 114 | }, 115 | child: Container( 116 | alignment: Alignment.center, 117 | padding: const EdgeInsets.symmetric(horizontal: 8.0), 118 | child: Text( 119 | subDto.mallSubName, 120 | style: TextStyle(color: index == Provide.value(context).subIndex ? Colors.pink : Colors.black), 121 | ), 122 | )); 123 | } 124 | 125 | // 右侧商品列表 item 126 | Widget _goodsItem(CategoryGoodsInfo info, BuildContext context) { 127 | return InkWell( 128 | onTap: () => Application.router.navigateTo(context, Routers.generateDetailsRouterPath(info.goodsId)), 129 | child: Container( 130 | margin: const EdgeInsets.all(2.0), 131 | alignment: Alignment.center, 132 | color: Colors.white, 133 | child: Column( 134 | children: [ 135 | Image.network(info.image, width: MediaQuery.of(context).size.width * 0.4, height: MediaQuery.of(context).size.width * 0.4), 136 | Text('${info.goodsName}', style: TextStyle(fontSize: 14.0, color: Colors.black), overflow: TextOverflow.ellipsis), 137 | Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.end, children: [ 138 | Text('¥${info.presentPrice}', style: TextStyle(fontSize: 14.0)), 139 | Text('¥${info.oriPrice}', style: TextStyle(color: Colors.black26, decoration: TextDecoration.lineThrough, fontSize: 12.0)) 140 | ]) 141 | ], 142 | ), 143 | ), 144 | ); 145 | } 146 | 147 | @override 148 | Widget build(BuildContext context) { 149 | return Scaffold( 150 | appBar: AppBar(title: Text('商品分类'), centerTitle: true), 151 | body: Row(children: [ 152 | // 左侧栏 153 | Container( 154 | width: 100.0, 155 | child: ListView.separated( 156 | itemBuilder: (context, index) => _leftCategoryItem(index, context), 157 | separatorBuilder: (context, index) => Divider(height: 1.0, color: Colors.black12), 158 | itemCount: categories.length), 159 | ), 160 | // 分割线 161 | VerticalDivider(width: 1.0, color: Colors.black12), 162 | // 右侧栏 163 | Expanded( 164 | child: Column( 165 | children: [ 166 | // 头部导航 167 | Provide( 168 | builder: (_, child, subCategories) => Container( 169 | color: Colors.white, 170 | height: 50.0, 171 | child: ListView.builder( 172 | controller: _topNavController, 173 | scrollDirection: Axis.horizontal, 174 | itemBuilder: (_, index) => _subCategoryNav(index, subCategories.subCategories[index]), 175 | itemCount: subCategories.subCategories.length, 176 | ), 177 | ), 178 | ), 179 | Divider(height: 1.0, color: Colors.black12), 180 | // 物品展示 181 | Expanded( 182 | child: Provide( 183 | builder: (context, widget, goodsProvide) => goodsProvide.goodList.isEmpty 184 | // 当前商品分类无商品情况 185 | ? Center( 186 | child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ 187 | Image.asset('images/empty.png', width: 60.0, height: 60.0), 188 | Text('啊哦...目前未找到该分类下的商品'), 189 | ]), 190 | ) 191 | // 当前商品列表下有数据情况 192 | : EasyRefresh( 193 | key: _refreshKey, 194 | refreshHeader: BallPulseHeader(key: _headerKey, color: Colors.pink), 195 | refreshFooter: BallPulseFooter(key: _footerKey, color: Colors.pink), 196 | loadMore: () { 197 | _requestGoodsList(); 198 | }, 199 | child: GridView.builder( 200 | controller: _gridController, 201 | itemCount: goodsProvide.goodList.length, 202 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 203 | crossAxisCount: 2, childAspectRatio: 2 / 3, mainAxisSpacing: 1.0, crossAxisSpacing: 1.0), 204 | itemBuilder: (_, index) => _goodsItem(goodsProvide.goodList[index], context)), 205 | ), 206 | ), 207 | ) 208 | ], 209 | )) 210 | ]), 211 | ); 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /lib/pages/deatilspage/details_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_shop/pages/deatilspage/goods_comments.dart'; 4 | import 'package:flutter_shop/pages/deatilspage/goods_detail.dart'; 5 | import 'package:flutter_shop/pages/deatilspage/goods_handler.dart'; 6 | import 'package:flutter_shop/pages/deatilspage/sliver_header_bar.dart'; 7 | import 'package:flutter_shop/provides/goods_detail_provide.dart'; 8 | import 'package:provide/provide.dart'; 9 | 10 | class DetailsPage extends StatelessWidget { 11 | final String goodsId; 12 | final _tabs = ['详情', '评论']; 13 | 14 | DetailsPage({Key key, this.goodsId}) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | Provide.value(context) 19 | ..changeDetails(goodsId) 20 | ..changeIndex(0); 21 | 22 | return Provide(builder: (_, widget, detailProvide) { 23 | var _detail = detailProvide.detail; 24 | 25 | return Scaffold( 26 | body: Container( 27 | alignment: Alignment.center, 28 | child: _detail == null || _detail.data == null || _detail.data.goodInfo == null 29 | ? CupertinoActivityIndicator(radius: 12.0) // 无商品情况使用加载 30 | // 使用横向滑动列表展示不同页面 31 | : DefaultTabController( 32 | length: _tabs.length, 33 | child: NestedScrollView( 34 | headerSliverBuilder: (context, innerScrolled) => [ 35 | SliverOverlapAbsorber( 36 | handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), 37 | child: SliverHeaderBar(detailProvide: detailProvide, tabs: _tabs, innerScrolled: innerScrolled), 38 | ) 39 | ], 40 | // 详情页面和评论页面列表 41 | body: TabBarView( 42 | children: [GoodsDetail(detailProvide: detailProvide), GoodsComments(detailProvide: detailProvide)], 43 | ), 44 | ), 45 | ), 46 | ), 47 | bottomNavigationBar: GoodsHandler(detailProvide: detailProvide), 48 | ); 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/pages/deatilspage/goods_comments.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/provides/goods_detail_provide.dart'; 3 | 4 | class GoodsComments extends StatelessWidget { 5 | final GoodsDetailProvide detailProvide; 6 | 7 | GoodsComments({Key key, this.detailProvide}) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | var _detail = detailProvide.detail.data; 12 | 13 | return Builder(builder: (ctx) { 14 | return CustomScrollView( 15 | slivers: [ 16 | SliverOverlapInjector(handle: NestedScrollView.sliverOverlapAbsorberHandleFor(ctx)), 17 | _detail.goodComments.isEmpty 18 | // 无评论 19 | ? SliverToBoxAdapter(child: Container(alignment: Alignment.center, height: 60.0, child: Text('暂时没有评论哦~'))) 20 | // 评论列表 21 | : SliverFixedExtentList( 22 | delegate: SliverChildBuilderDelegate( 23 | (_, index) => Container( 24 | color: Colors.white, 25 | padding: const EdgeInsets.only(left: 12.0), 26 | child: Column( 27 | mainAxisAlignment: MainAxisAlignment.center, 28 | crossAxisAlignment: CrossAxisAlignment.start, 29 | children: [ 30 | Text('${_detail.goodComments[index].userName}'), // 评论者昵称 31 | Text('${_detail.goodComments[index].comments}'), // 评论信息 32 | Text('${DateTime.fromMillisecondsSinceEpoch(_detail.goodComments[index].discussTime)}'.split('.').first), // 评论时间 33 | ], 34 | ), 35 | ), 36 | childCount: _detail.goodComments.length), 37 | itemExtent: 80.0), 38 | SliverToBoxAdapter(child: Image.network(_detail.advertesPicture.PICTURE_ADDRESS)) 39 | ], 40 | ); 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/pages/deatilspage/goods_detail.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_html/flutter_html.dart'; 3 | import 'package:flutter_shop/provides/goods_detail_provide.dart'; 4 | 5 | class GoodsDetail extends StatelessWidget { 6 | final GoodsDetailProvide detailProvide; 7 | 8 | GoodsDetail({Key key, this.detailProvide}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Builder(builder: (ctx) { 13 | var _detail = detailProvide.detail.data; 14 | 15 | return CustomScrollView( 16 | slivers: [ 17 | SliverOverlapInjector(handle: NestedScrollView.sliverOverlapAbsorberHandleFor(ctx)), 18 | // H5 详情 19 | SliverToBoxAdapter(child: Html(data: _detail.goodInfo.goodsDetail)), 20 | // 广告条 21 | SliverToBoxAdapter(child: Image.network(_detail.advertesPicture.PICTURE_ADDRESS)) 22 | ], 23 | ); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/pages/deatilspage/goods_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_shop/provides/cart_count_provide.dart'; 4 | import 'package:flutter_shop/provides/cart_provide.dart'; 5 | import 'package:flutter_shop/provides/goods_detail_provide.dart'; 6 | import 'package:flutter_shop/provides/page_index_provide.dart'; 7 | import 'package:provide/provide.dart'; 8 | 9 | class GoodsHandler extends StatelessWidget { 10 | final GoodsDetailProvide detailProvide; 11 | 12 | GoodsHandler({Key key, this.detailProvide}) : super(key: key); 13 | 14 | Widget _countOperator(CartCountProvide cartCount) { 15 | return Row( 16 | crossAxisAlignment: CrossAxisAlignment.center, 17 | children: [ 18 | Expanded( 19 | child: InkWell( 20 | onTap: cartCount.shopCount == 1 ? () {} : () => cartCount.decrease(), 21 | child: DecoratedBox( 22 | decoration: BoxDecoration( 23 | border: Border(right: BorderSide(color: Colors.black54, width: 1.0)), 24 | ), 25 | child: Center(child: Text('-', style: TextStyle(fontSize: 16.0, color: Colors.black)))), 26 | ), 27 | ), 28 | Expanded(child: Center(child: Text('${cartCount.shopCount}', style: TextStyle(fontSize: 14.0, color: Colors.black))), flex: 2), 29 | Expanded( 30 | child: InkWell( 31 | onTap: () => cartCount.increase(), 32 | child: DecoratedBox( 33 | decoration: BoxDecoration( 34 | border: Border(left: BorderSide(color: Colors.black54, width: 1.0)), 35 | ), 36 | child: Center(child: Text('+', style: TextStyle(fontSize: 16.0, color: Colors.black)))), 37 | ), 38 | ) 39 | ], 40 | ); 41 | } 42 | 43 | _countModalSheet(BuildContext ctx) { 44 | Provide.value(ctx).initCount(); // 购买数量初始化为 1 45 | showModalBottomSheet( 46 | context: ctx, 47 | builder: (context) => Provide(builder: (_, child, cartCount) { 48 | return Container( 49 | padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), 50 | height: 100.0, 51 | color: Colors.white, 52 | child: Column( 53 | crossAxisAlignment: CrossAxisAlignment.start, 54 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 55 | children: [ 56 | Text('购买数量', style: TextStyle(color: Colors.black, fontSize: 12.0)), 57 | Row(children: [ 58 | Container( 59 | width: 120.0, 60 | height: 30.0, 61 | decoration: ShapeDecoration( 62 | shape: RoundedRectangleBorder( 63 | borderRadius: BorderRadius.all(Radius.circular(2.0)), 64 | side: BorderSide(color: Colors.black54), 65 | ), 66 | ), 67 | child: _countOperator(cartCount), 68 | ), 69 | 70 | // 加入购物车按钮 71 | Padding( 72 | padding: const EdgeInsets.only(left: 30.0), 73 | child: OutlineButton( 74 | child: Text('确定加入购物车'), 75 | onPressed: () { 76 | Provide.value(context).saveCarts(detailProvide.detail.data.goodInfo, cartCount.shopCount); 77 | Navigator.pop(context); 78 | }), 79 | ) 80 | ]) 81 | ], 82 | ), 83 | ); 84 | }), 85 | ); 86 | } 87 | 88 | @override 89 | Widget build(BuildContext context) { 90 | return BottomAppBar( 91 | child: Container( 92 | height: 60.0, 93 | child: Card( 94 | margin: const EdgeInsets.all(0.0), 95 | child: Row(children: [ 96 | // 购物车按钮 97 | Stack( 98 | alignment: Alignment.topRight, 99 | children: [ 100 | IconButton( 101 | icon: Icon(CupertinoIcons.shopping_cart, size: 32.0, color: Colors.pink), 102 | onPressed: () { 103 | Navigator.pop(context); 104 | Provide.value(context).changePage(2); 105 | }), 106 | Provide( 107 | builder: (_, child, carts) => DecoratedBox( 108 | decoration: BoxDecoration( 109 | color: Colors.pink, 110 | borderRadius: BorderRadius.all(Radius.circular(12.0)), 111 | ), 112 | child: Padding( 113 | padding: const EdgeInsets.only(top: 2.0, bottom: 2.0, left: 4.0, right: 4.0), 114 | child: Text('${carts.allCartCount}', style: TextStyle(color: Colors.white)), 115 | ), 116 | ), 117 | ) 118 | ], 119 | ), 120 | // 加入购物车 121 | Expanded( 122 | child: Builder( 123 | builder: (ctx) => InkWell( 124 | child: Container( 125 | color: Colors.green, 126 | alignment: Alignment.center, 127 | child: Text('加入购物车', style: TextStyle(color: Colors.white, fontSize: 18.0))), 128 | onTap: () { 129 | _countModalSheet(ctx); 130 | }, 131 | ), 132 | ), 133 | ), 134 | // 立即购买 135 | Expanded( 136 | child: InkWell( 137 | child: Container( 138 | color: Colors.red, 139 | alignment: Alignment.center, 140 | child: Text('立即购买', style: TextStyle(color: Colors.white, fontSize: 18.0)), 141 | ), 142 | onTap: () {}), 143 | ) 144 | ]), 145 | ), 146 | ), 147 | ); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /lib/pages/deatilspage/sliver_header_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/provides/goods_detail_provide.dart'; 3 | 4 | class SliverHeaderBar extends StatelessWidget { 5 | final GoodsDetailProvide detailProvide; 6 | final List tabs; 7 | final bool innerScrolled; 8 | final double _expandedHeight = 560.0; 9 | 10 | SliverHeaderBar({Key key, this.detailProvide, this.tabs, this.innerScrolled}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | var _detail = detailProvide.detail; 15 | return SliverAppBar( 16 | pinned: true, 17 | centerTitle: true, 18 | // 商品名 19 | title: Text( 20 | _detail.data.goodInfo.goodsName, 21 | maxLines: 1, 22 | overflow: TextOverflow.ellipsis, 23 | ), 24 | forceElevated: innerScrolled, 25 | // 折叠头部信息 26 | flexibleSpace: HeaderFlex(detailProvide: detailProvide, expandedHeight: _expandedHeight), 27 | // 折叠高度 28 | expandedHeight: _expandedHeight, 29 | bottom: TabBar( 30 | indicator: BoxDecoration(color: Colors.transparent), 31 | labelColor: Colors.pink, 32 | indicatorWeight: .0, 33 | indicatorColor: Colors.pink, 34 | indicatorSize: TabBarIndicatorSize.label, 35 | unselectedLabelColor: Colors.black, 36 | labelPadding: EdgeInsets.zero, 37 | tabs: tabs 38 | .map((tab) => Container( 39 | height: 60.0, 40 | color: Colors.white, 41 | alignment: Alignment.center, 42 | child: Text(tab, style: TextStyle(fontSize: 18.0)), 43 | )) 44 | .toList()), 45 | ); 46 | } 47 | } 48 | 49 | class HeaderFlex extends StatelessWidget { 50 | final GoodsDetailProvide detailProvide; 51 | final double expandedHeight; 52 | 53 | HeaderFlex({Key key, this.detailProvide, this.expandedHeight}) : super(key: key); 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | var _detail = detailProvide.detail.data; 58 | 59 | return FlexibleSpaceBar( 60 | collapseMode: CollapseMode.pin, 61 | background: Container( 62 | alignment: Alignment.center, 63 | color: Colors.white, 64 | height: expandedHeight, 65 | child: Column( 66 | children: [ 67 | Image.network(_detail.goodInfo.image1, height: 340), // 图片 68 | Column( 69 | mainAxisAlignment: MainAxisAlignment.center, 70 | crossAxisAlignment: CrossAxisAlignment.start, 71 | children: [ 72 | // 商品名 73 | Padding( 74 | padding: const EdgeInsets.only(top: 20.0, left: 12.0, right: 12.0), 75 | child: Text( 76 | _detail.goodInfo.goodsName, 77 | style: TextStyle(fontSize: 18.0, color: Colors.black), 78 | ), 79 | ), 80 | // 商品编号 81 | Padding( 82 | padding: const EdgeInsets.only(top: 12.0, left: 12.0, right: 12.0), 83 | child: Text('编号:${_detail.goodInfo.goodsSerialNumber}'), 84 | ), 85 | // 商品价格 86 | Padding( 87 | padding: const EdgeInsets.only(top: 8.0, left: 12.0, right: 12.0), 88 | child: Row(crossAxisAlignment: CrossAxisAlignment.end, children: [ 89 | Text('¥${_detail.goodInfo.presentPrice}', style: TextStyle(fontSize: 16.0, color: Colors.red)), 90 | Padding(padding: const EdgeInsets.only(left: 16.0), child: Text('市场价:', style: TextStyle(color: Colors.black))), 91 | Text('¥${_detail.goodInfo.oriPrice}', style: TextStyle(decoration: TextDecoration.lineThrough, color: Colors.black26)), 92 | ]), 93 | ), 94 | Container( 95 | height: 8.0, 96 | color: Colors.black12, 97 | margin: const EdgeInsets.only(top: 4.0), 98 | ), 99 | Container( 100 | alignment: Alignment.centerLeft, 101 | padding: const EdgeInsets.all(12.0), 102 | child: Text('说明:>急速送达 >正品保证', style: TextStyle(fontSize: 16.0, color: Colors.red)), 103 | ), 104 | Container(height: 8.0, color: Colors.black12) 105 | ], 106 | ), 107 | ], 108 | ), 109 | ), 110 | ); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /lib/pages/homepage/ad_banner.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AdBanner extends StatelessWidget { 4 | final String bannerUrl; 5 | 6 | AdBanner({Key key, @required this.bannerUrl}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return SliverToBoxAdapter(child: Image.network(bannerUrl)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/pages/homepage/banner_diy.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/configs/application.dart'; 3 | import 'package:flutter_shop/entities/home_page_entity.dart'; 4 | import 'package:flutter_shop/router/routers.dart'; 5 | import 'package:flutter_swiper/flutter_swiper.dart'; 6 | 7 | class BannerDiy extends StatelessWidget { 8 | final List bannerImages; 9 | 10 | BannerDiy({Key key, @required this.bannerImages}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return SliverToBoxAdapter( 15 | child: Container( 16 | height: 180.0, 17 | child: Swiper( 18 | itemCount: bannerImages.length, 19 | itemBuilder: (context, int index) => InkWell( 20 | child: Image.network('${bannerImages[index].image}', fit: BoxFit.fill), 21 | onTap: () => Application.router.navigateTo(context, Routers.generateDetailsRouterPath(bannerImages[index].goodsId)), 22 | ), 23 | pagination: SwiperPagination(), 24 | autoplay: true, 25 | ), 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/pages/homepage/floor_part.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/configs/application.dart'; 3 | import 'package:flutter_shop/entities/home_page_entity.dart'; 4 | import 'package:flutter_shop/router/routers.dart'; 5 | 6 | class FloorTitle extends StatelessWidget { 7 | final String floorPic; 8 | 9 | FloorTitle({Key key, @required this.floorPic}) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return SliverToBoxAdapter(child: Container(child: Image.network(floorPic), padding: const EdgeInsets.symmetric(vertical: 12.0))); 14 | } 15 | } 16 | 17 | class FloorContent extends StatelessWidget { 18 | final List floorContent; 19 | 20 | FloorContent({Key key, @required this.floorContent}) : super(key: key); 21 | 22 | Widget _goodsImg(Floor floorItem, context) { 23 | return InkWell( 24 | child: Image.network(floorItem.image, width: MediaQuery.of(context).size.width / 2), 25 | onTap: () => Application.router.navigateTo(context, Routers.generateDetailsRouterPath(floorItem.goodsId))); 26 | } 27 | 28 | Widget _topRow(context) { 29 | return Row(children: [ 30 | _goodsImg(floorContent[0], context), 31 | Column(children: [ 32 | _goodsImg(floorContent[1], context), 33 | _goodsImg(floorContent[2], context), 34 | ]) 35 | ]); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return SliverToBoxAdapter( 41 | child: InkWell( 42 | child: Container( 43 | child: Column(children: [ 44 | _topRow(context), 45 | Row(children: [ 46 | _goodsImg(floorContent[3], context), 47 | _goodsImg(floorContent[4], context), 48 | ]) 49 | ]), 50 | ), 51 | onTap: () {}, 52 | )); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/pages/homepage/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:amap_base/amap_base.dart'; 4 | import 'package:fluro/fluro.dart'; 5 | import 'package:flutter/cupertino.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_easyrefresh/ball_pulse_footer.dart'; 8 | import 'package:flutter_easyrefresh/ball_pulse_header.dart'; 9 | import 'package:flutter_easyrefresh/easy_refresh.dart'; 10 | import 'package:flutter_shop/configs/application.dart'; 11 | import 'package:flutter_shop/pages/homepage/ad_banner.dart'; 12 | import 'package:flutter_shop/pages/homepage/banner_diy.dart'; 13 | import 'package:flutter_shop/pages/homepage/floor_part.dart'; 14 | import 'package:flutter_shop/pages/homepage/hot_part.dart'; 15 | import 'package:flutter_shop/pages/homepage/lead_phone.dart'; 16 | import 'package:flutter_shop/pages/homepage/mall_recommend.dart'; 17 | import 'package:flutter_shop/pages/homepage/top_nativator.dart'; 18 | import 'package:flutter_shop/provides/home_provide.dart'; 19 | import 'package:flutter_shop/router/routers.dart'; 20 | import 'package:provide/provide.dart'; 21 | 22 | class HomePage extends StatelessWidget { 23 | final GlobalKey _refreshKey = GlobalKey(); 24 | final GlobalKey _headerKey = GlobalKey(); 25 | final GlobalKey _footerKey = GlobalKey(); 26 | final ScrollController _outController = ScrollController(); 27 | final _mapLocation = AMapLocation(); 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | _mapLocation.init(); 32 | 33 | Permissions().requestPermission().then((granted) { 34 | if (granted) { 35 | _mapLocation 36 | .getLocation(LocationClientOptions( 37 | isOnceLocation: true, 38 | isNeedAddress: true, 39 | locatingWithReGeocode: true, 40 | )) 41 | .then((location) { 42 | print('location:(${location.longitude}, ${location.latitude}), ${location.district}'); 43 | Provide.value(context) 44 | ..initHomeEntity(location.longitude, location.latitude) 45 | ..changeDistrict(location.district, location.longitude, location.latitude); 46 | }); 47 | } else { 48 | Provide.value(context).initHomeEntity(115.02932, 35.76189); 49 | } 50 | }); 51 | 52 | Provide.value(context).initHotGoodsList(); 53 | 54 | _outController.addListener(() { 55 | Provide.value(context).enableBack(_outController.position.pixels >= window.physicalSize.height); 56 | }); 57 | 58 | return Theme( 59 | data: ThemeData(primarySwatch: Colors.pink, iconTheme: IconThemeData(color: Colors.pink)), 60 | child: Provide( 61 | builder: (_, widget, homeProvide) => Scaffold( 62 | appBar: AppBar( 63 | title: Text('百姓生活+'), 64 | centerTitle: true, 65 | leading: InkWell( 66 | child: Padding( 67 | padding: const EdgeInsets.all(4.0), 68 | child: Row( 69 | children: [ 70 | Icon(Icons.location_on, color: Colors.white, size: 12.0), 71 | Expanded( 72 | child: Text(homeProvide.district, style: TextStyle(fontSize: 12.0), overflow: TextOverflow.ellipsis, maxLines: 1), 73 | ) 74 | ], 75 | ), 76 | ), 77 | onTap: () => Application.router.navigateTo(context, Routers.map, transition: TransitionType.fadeIn), 78 | ), 79 | ), 80 | body: homeProvide.homeEntity == null 81 | ? Center(child: CupertinoActivityIndicator(radius: 12.0)) 82 | : EasyRefresh( 83 | key: _refreshKey, 84 | refreshHeader: BallPulseHeader(key: _headerKey, color: Colors.pink), 85 | refreshFooter: BallPulseFooter(key: _footerKey, color: Colors.pink), 86 | loadMore: () => homeProvide.loadMoreHotGoods(), 87 | child: CustomScrollView( 88 | controller: _outController, 89 | physics: BouncingScrollPhysics(), 90 | slivers: [ 91 | BannerDiy(bannerImages: homeProvide.homeEntity.data.slides), 92 | TopNavigatorBar(categories: homeProvide.homeEntity.data.category), 93 | AdBanner(bannerUrl: homeProvide.homeEntity.data.advertesPicture.pICTUREADDRESS), 94 | LeaderPhone( 95 | imageUrl: homeProvide.homeEntity.data.shopInfo.leaderImage, 96 | phone: homeProvide.homeEntity.data.shopInfo.leaderPhone, 97 | ), 98 | RecommendWidget(recommendList: homeProvide.homeEntity.data.recommend), 99 | FloorTitle(floorPic: homeProvide.homeEntity.data.floor1Pic.pICTUREADDRESS), 100 | FloorContent(floorContent: homeProvide.homeEntity.data.floor1), 101 | FloorTitle(floorPic: homeProvide.homeEntity.data.floor2Pic.pICTUREADDRESS), 102 | FloorContent(floorContent: homeProvide.homeEntity.data.floor2), 103 | FloorTitle(floorPic: homeProvide.homeEntity.data.floor3Pic.pICTUREADDRESS), 104 | FloorContent(floorContent: homeProvide.homeEntity.data.floor3), 105 | HotGoodsTitle(), 106 | SliverGrid.count( 107 | crossAxisCount: 2, 108 | childAspectRatio: 0.7, 109 | children: homeProvide.hodGoodsList.map((hot) => HotItem(hot: hot)).toList(), 110 | ) 111 | ], 112 | ), 113 | ), 114 | floatingActionButton: homeProvide.showBack 115 | ? FloatingActionButton( 116 | onPressed: () { 117 | _outController.animateTo(0.0, duration: Duration(milliseconds: 500), curve: Curves.decelerate); 118 | }, 119 | mini: true, 120 | child: Icon(Icons.vertical_align_top)) 121 | : null, 122 | )), 123 | ); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /lib/pages/homepage/hot_part.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/configs/application.dart'; 3 | import 'package:flutter_shop/entities/hot_goods_entity.dart'; 4 | import 'package:flutter_shop/router/routers.dart'; 5 | 6 | /// 火爆专区标题 7 | class HotGoodsTitle extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return SliverToBoxAdapter( 11 | child: Container( 12 | alignment: Alignment.center, 13 | child: Text('火爆专区', style: TextStyle(color: Colors.black)), 14 | padding: const EdgeInsets.symmetric(vertical: 8.0), 15 | ), 16 | ); 17 | } 18 | } 19 | 20 | /// 火爆专区 21 | class HotItem extends StatelessWidget { 22 | final HotGoodsData hot; 23 | 24 | HotItem({Key key, this.hot}) : super(key: key); 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return InkWell( 29 | onTap: () { 30 | Application.router.navigateTo(context, Routers.generateDetailsRouterPath(hot.goodsId)); 31 | }, 32 | child: Container( 33 | color: Colors.white, 34 | alignment: Alignment.center, 35 | margin: const EdgeInsets.only(left: 4.0, right: 4.0, bottom: 8.0), 36 | padding: const EdgeInsets.all(4.0), 37 | child: Column( 38 | mainAxisAlignment: MainAxisAlignment.center, 39 | children: [ 40 | Image.network(hot.image), 41 | Text(hot.name, textAlign: TextAlign.center, maxLines: 1), 42 | Row( 43 | mainAxisAlignment: MainAxisAlignment.spaceAround, 44 | children: [ 45 | Text('¥${hot.mallPrice}'), 46 | Text('¥${hot.price}', style: TextStyle(color: Colors.black45, decoration: TextDecoration.lineThrough)) 47 | ], 48 | ) 49 | ], 50 | ), 51 | ), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/pages/homepage/lead_phone.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:url_launcher/url_launcher.dart'; 3 | 4 | class LeaderPhone extends StatelessWidget { 5 | final String imageUrl; 6 | final String phone; 7 | 8 | LeaderPhone({Key key, @required this.imageUrl, @required this.phone}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return SliverToBoxAdapter( 13 | child: Container( 14 | child: InkWell( 15 | child: Image.network(imageUrl, fit: BoxFit.cover), 16 | onTap: () async { 17 | var url = 'tel:$phone'; 18 | if (await canLaunch(url)) launch(url); 19 | }), 20 | )); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/pages/homepage/mall_recommend.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/configs/application.dart'; 3 | import 'package:flutter_shop/entities/home_page_entity.dart'; 4 | import 'package:flutter_shop/router/routers.dart'; 5 | 6 | class RecommendWidget extends StatelessWidget { 7 | final List recommendList; 8 | 9 | RecommendWidget({Key key, @required this.recommendList}) : super(key: key); 10 | 11 | Widget _recommendTitle() { 12 | return Container( 13 | alignment: Alignment.center, 14 | padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0), 15 | decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.black12, width: 1.0))), 16 | child: Text('商品推荐', style: TextStyle(color: Colors.pink)), 17 | ); 18 | } 19 | 20 | Widget _recommendItem(BuildContext context, int index) { 21 | return InkWell( 22 | onTap: () { 23 | Application.router.navigateTo(context, Routers.generateDetailsRouterPath(recommendList[index].goodsId)); 24 | }, 25 | child: Container( 26 | width: MediaQuery.of(context).size.width / 3, 27 | height: 180.0, 28 | alignment: Alignment.center, 29 | decoration: BoxDecoration( 30 | border: Border( 31 | left: BorderSide(color: Colors.black12), 32 | bottom: BorderSide(color: Colors.black12), 33 | ), 34 | color: Colors.white), 35 | child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ 36 | Image.network(recommendList[index].image, height: 120.0), 37 | Text('¥${recommendList[index].mallPrice}', style: TextStyle(fontSize: 16.0)), 38 | Text('¥${recommendList[index].price}', style: TextStyle(decoration: TextDecoration.lineThrough, decorationColor: Colors.black45)) 39 | ]), 40 | ), 41 | ); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return SliverToBoxAdapter( 47 | child: Container( 48 | alignment: Alignment.center, 49 | margin: const EdgeInsets.only(top: 6.0), 50 | child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ 51 | _recommendTitle(), 52 | SizedBox( 53 | height: 180.0, 54 | child: ListView.builder(itemBuilder: _recommendItem, itemCount: this.recommendList.length, scrollDirection: Axis.horizontal), 55 | ) 56 | ]), 57 | ), 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/pages/homepage/top_nativator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/entities/home_page_entity.dart'; 3 | import 'package:flutter_shop/provides/page_index_provide.dart'; 4 | import 'package:provide/provide.dart'; 5 | 6 | class TopNavigatorBar extends StatelessWidget { 7 | final List categories; 8 | 9 | TopNavigatorBar({Key key, @required this.categories}) : super(key: key); 10 | 11 | Widget _buildCategoryItem(BuildContext context, Category item) { 12 | return InkWell( 13 | onTap: () { 14 | Provide.value(context).changePage(1); 15 | }, 16 | child: Column( 17 | mainAxisAlignment: MainAxisAlignment.center, 18 | children: [ 19 | Image.network(item.image, width: MediaQuery.of(context).size.width / 8), 20 | Padding( 21 | padding: const EdgeInsets.only(top: 4.0), 22 | child: Text(item.mallCategoryName, style: TextStyle(color: Colors.black)), 23 | ), 24 | ], 25 | ), 26 | ); 27 | } 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | if (categories.length > 10) categories.removeRange(10, categories.length); 32 | return SliverToBoxAdapter( 33 | child: SizedBox( 34 | height: MediaQuery.of(context).size.width * 2 / 5, 35 | child: GridView.count( 36 | padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), 37 | childAspectRatio: 1.0, 38 | physics: NeverScrollableScrollPhysics(), 39 | crossAxisCount: 5, 40 | children: categories.map((item) => _buildCategoryItem(context, item)).toList(), 41 | ), 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/pages/index_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_shop/pages/cartpage/cart_page.dart'; 4 | import 'package:flutter_shop/pages/category_page.dart'; 5 | import 'package:flutter_shop/pages/homepage/home_page.dart'; 6 | import 'package:flutter_shop/pages/mempage/mem_page.dart'; 7 | import 'package:flutter_shop/provides/page_index_provide.dart'; 8 | import 'package:provide/provide.dart'; 9 | 10 | class IndexPage extends StatelessWidget { 11 | @override 12 | Widget build(BuildContext context) { 13 | final _bottomTabs = [ 14 | BottomNavigationBarItem(icon: Icon(CupertinoIcons.home), title: Text('首页')), 15 | BottomNavigationBarItem(icon: Icon(CupertinoIcons.search), title: Text('分类')), 16 | BottomNavigationBarItem(icon: Icon(CupertinoIcons.shopping_cart), title: Text('购物车')), 17 | BottomNavigationBarItem(icon: Icon(CupertinoIcons.profile_circled), title: Text('会员中心')) 18 | ]; 19 | 20 | final _tabPages = [HomePage(), CategoryPage(), CartPage(), MemPage()]; 21 | 22 | return Provide( 23 | builder: (_, child, pageProvide) => Scaffold( 24 | backgroundColor: Color.fromRGBO(244, 245, 245, 1.0), 25 | body: IndexedStack(index: pageProvide.page, children: _tabPages), 26 | bottomNavigationBar: BottomNavigationBar( 27 | items: _bottomTabs, 28 | type: BottomNavigationBarType.fixed, 29 | currentIndex: pageProvide.page, 30 | onTap: (value) { 31 | Provide.value(context).changePage(value); 32 | }, 33 | ), 34 | )); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/pages/map_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:amap_base/amap_base.dart'; 3 | import 'package:flutter_shop/provides/home_provide.dart'; 4 | import 'package:provide/provide.dart'; 5 | 6 | class MapPage extends StatefulWidget { 7 | @override 8 | _MapPageState createState() => _MapPageState(); 9 | } 10 | 11 | class _MapPageState extends State { 12 | AMapController _controller; 13 | 14 | @override 15 | void initState() { 16 | super.initState(); 17 | } 18 | 19 | @override 20 | void dispose() { 21 | _controller.dispose(); 22 | super.dispose(); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | var provide = Provide.value(context); 28 | return Scaffold( 29 | appBar: AppBar( 30 | title: Text('Map'), 31 | ), 32 | body: AMapView( 33 | onAMapViewCreated: (controller) { 34 | _controller = controller; 35 | _controller.showIndoorMap(true); 36 | _controller.setZoomLevel(19); 37 | }, 38 | amapOptions: AMapOptions( 39 | compassEnabled: false, 40 | zoomControlsEnabled: true, 41 | logoPosition: LOGO_POSITION_BOTTOM_LEFT, 42 | camera: CameraPosition(target: LatLng(provide.latitude, provide.longitude)/*, zoom: 15.0*/), 43 | ), 44 | ), 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/pages/mempage/mem_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MemHeader extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Container( 7 | alignment: Alignment.center, 8 | padding: const EdgeInsets.symmetric(vertical: 40.0), 9 | decoration: BoxDecoration( 10 | gradient: LinearGradient(colors: [Colors.pink[300], Colors.blue[200]], begin: Alignment.topLeft, end: Alignment.bottomRight), 11 | ), 12 | child: Column( 13 | children: [ 14 | ClipOval( 15 | child: Image.asset('images/avatar.jpg', width: 100.0, height: 100.0), 16 | ), 17 | Padding( 18 | padding: const EdgeInsets.all(8.0), 19 | child: Text('Kuky_xs', style: TextStyle(color: Colors.black, fontSize: 18.0)), 20 | ) 21 | ], 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/pages/mempage/mem_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/configs/application.dart'; 3 | import 'package:flutter_shop/pages/mempage/mem_header.dart'; 4 | import 'package:flutter_shop/pages/mempage/mem_tile.dart'; 5 | import 'package:flutter_shop/pages/mempage/order_grid.dart'; 6 | import 'package:flutter_shop/router/routers.dart'; 7 | 8 | class MemPage extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return Scaffold( 12 | appBar: AppBar( 13 | title: Text('会员中心'), 14 | centerTitle: true, 15 | ), 16 | body: ListView( 17 | children: [ 18 | MemHeader(), 19 | MemTile(leading: Icons.border_all, title: "我的订单", action: () {}), 20 | Divider(height: 2.0, color: Colors.black38), 21 | OrderGrid(), 22 | Container(height: 8.0, color: Colors.black12), 23 | MemTile(leading: Icons.bookmark_border, title: "领取优惠券", action: () {}), 24 | Divider(height: 2.0, color: Colors.black38), 25 | MemTile(leading: Icons.bookmark_border, title: "已领取优惠券", action: () {}), 26 | Divider(height: 2.0, color: Colors.black38), 27 | MemTile(leading: Icons.my_location, title: "地址管理", action: () {}), 28 | Container(height: 8.0, color: Colors.black12), 29 | MemTile(leading: Icons.phone, title: "客服电话", action: () {}), 30 | Divider(height: 2.0, color: Colors.black38), 31 | MemTile(leading: Icons.info_outline, title: "关于商城", action: () {}), 32 | Container(height: 8.0, color: Colors.black12), 33 | MemTile(leading: Icons.settings, title: "设置", action: () => Application.router.navigateTo(context, Routers.settings)), 34 | ], 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/pages/mempage/mem_tile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MemTile extends StatelessWidget { 4 | final IconData leading; 5 | final String title; 6 | final VoidCallback action; 7 | 8 | MemTile({Key key, this.leading, this.title, this.action}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return ListTile( 13 | leading: Icon(leading), 14 | title: Text(title, style: TextStyle(color: Colors.black, fontSize: 16.0)), 15 | trailing: Icon(Icons.arrow_forward_ios), 16 | onTap: action, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/pages/mempage/order_grid.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class OrderGrid extends StatelessWidget { 4 | final _icons = [Icons.payment, Icons.timer, Icons.airport_shuttle, Icons.textsms]; 5 | final _titles = ['待付款', '待发货', '待收货', '待评价']; 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return SizedBox( 10 | height: MediaQuery.of(context).size.width / 4, 11 | child: GridView.count( 12 | crossAxisCount: _icons.length, 13 | children: List.generate( 14 | _icons.length, 15 | (index) => InkWell( 16 | child: Column( 17 | mainAxisAlignment: MainAxisAlignment.center, 18 | children: [Icon(_icons[index]), Padding(padding: const EdgeInsets.all(4.0), child: Text(_titles[index]))], 19 | ), 20 | onTap: () {}, 21 | )), 22 | physics: NeverScrollableScrollPhysics(), 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/pages/settings_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/configs/application.dart'; 3 | 4 | class SettingsPage extends StatefulWidget { 5 | @override 6 | _SettingsPageState createState() => _SettingsPageState(); 7 | } 8 | 9 | class _SettingsPageState extends State { 10 | bool _openNotification = true; 11 | 12 | @override 13 | void initState() { 14 | super.initState(); 15 | } 16 | 17 | @override 18 | void dispose() { 19 | super.dispose(); 20 | } 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Theme( 25 | data: ThemeData(primaryColor: Colors.pink, iconTheme: IconThemeData(color: Colors.pink)), 26 | child: Scaffold( 27 | appBar: AppBar( 28 | title: Text('设置'), 29 | ), 30 | body: ListView( 31 | children: [ 32 | SwitchListTile( 33 | activeColor: Colors.pink, 34 | title: Text('是否接收通知'), 35 | value: _openNotification, 36 | onChanged: (value) { 37 | setState(() { 38 | this._openNotification = value; 39 | }); 40 | 41 | if (value) { 42 | Application.jPush.resumePush(); 43 | } else { 44 | Application.jPush.stopPush(); 45 | } 46 | }) 47 | ], 48 | ), 49 | )); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/provides/cart_count_provide.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 用于购物车的选择数量 4 | class CartCountProvide with ChangeNotifier { 5 | int _count = 1; 6 | 7 | int get shopCount => _count; 8 | 9 | initCount() { 10 | _count = 1; // 打开时候初始化 11 | notifyListeners(); 12 | } 13 | 14 | increase() { 15 | _count += 1; // 增加按钮 16 | notifyListeners(); 17 | } 18 | 19 | decrease() { 20 | _count -= 1; // 减少按钮 21 | notifyListeners(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/provides/cart_provide.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_shop/entities/goods_detail_entity.dart'; 5 | import 'package:flutter_shop/entities/shopping_cart_entity.dart'; 6 | import 'package:flutter_shop/utils/preference_utils.dart'; 7 | 8 | class CartProvide with ChangeNotifier { 9 | bool _isAllChecked = false; // 是否全选 10 | int _allSelectedCount = 0; // 选中的物品数量 11 | int _allCartCount = 0; // 购物车内全部的物品数量 12 | double _allSelectedPrice = 0.0; // 选中物品的全部价格 13 | String _shopCartList = '[]'; // 用于持久化 14 | List _shopCarts = []; // 购物车物品列表 15 | 16 | bool get allCheckedState => _isAllChecked; 17 | 18 | int get allCartCount => _allCartCount; 19 | 20 | int get allCheckedCount => _allSelectedCount; 21 | 22 | double get allCheckedPrice => _allSelectedPrice; 23 | 24 | List get shopCarts => _shopCarts; 25 | 26 | CartProvide() { 27 | PreferenceUtils.instance.getString('shop_cart', '[]').then((value) { 28 | _shopCartList = value; 29 | _shopCarts.clear(); 30 | _shopCarts.addAll(_shopCartList == '[]' ? [] : ShoppingCartEntity.fromJsonList(json.decode(_shopCartList))); 31 | _allInfoStateCheck(); 32 | notifyListeners(); 33 | }); 34 | } 35 | 36 | /// 保存物品到购物车,可随意选择数量 37 | saveCarts(GoodInfoBean info, int count) { 38 | List carts = _shopCartList == '[]' ? [] : json.decode(_shopCartList); 39 | 40 | var included = false; 41 | 42 | if (carts.isNotEmpty) { 43 | carts.forEach((cart) { 44 | // 不是空列表的情况下,判断是否已经存在该物品,存在则添加,并设置状态位 45 | if (cart['goodsId'] == info.goodsId) { 46 | cart['count'] += count; 47 | included = true; 48 | } 49 | }); 50 | } 51 | 52 | // 不存在该商品的时候则全部加入到列表 53 | if (!included) { 54 | carts.add({ 55 | 'goodsName': info.goodsName, 56 | 'goodsId': info.goodsId, 57 | 'goodsImg': info.image1, 58 | 'orgPrice': info.oriPrice, 59 | 'price': info.presentPrice, 60 | 'count': count, 61 | 'isChecked': true, 62 | }); 63 | } 64 | 65 | _notifyChanges(carts); 66 | } 67 | 68 | /// 增加/减少商品数量 69 | increaseOrReduceOperation(String goodsId, bool isIncrease) { 70 | List carts = json.decode(_shopCartList); 71 | 72 | // 已经存在的情况下才增加减少,修改数量值 73 | carts.forEach((cart) { 74 | if (cart['goodsId'] == goodsId) { 75 | if (isIncrease) { 76 | cart['count'] += 1; 77 | } else { 78 | cart['count'] -= 1; 79 | } 80 | } 81 | }); 82 | 83 | _notifyChanges(carts); 84 | } 85 | 86 | /// 移除购物车内的某个商品 87 | removeCarts(String goodsId) { 88 | List carts = _shopCartList == '[]' ? [] : json.decode(_shopCartList); 89 | 90 | if (carts.isNotEmpty) { 91 | carts.removeWhere((e) => e['goodsId'] == goodsId); 92 | } 93 | 94 | _notifyChanges(carts); 95 | } 96 | 97 | /// 修改特定商品在购物车的选中状态 98 | changeCartState(String goodsId, bool checked) { 99 | List carts = _shopCartList == '[]' ? [] : json.decode(_shopCartList); 100 | 101 | if (carts.isNotEmpty) { 102 | carts.forEach((cart) { 103 | if (cart['goodsId'] == goodsId) { 104 | cart['isChecked'] = checked; 105 | } 106 | }); 107 | } 108 | 109 | _notifyChanges(carts); 110 | } 111 | 112 | /// 全选状态修改 113 | allCheckStateChange(bool checkState) { 114 | List carts = _shopCartList == '[]' ? [] : json.decode(_shopCartList); 115 | 116 | if (carts.isNotEmpty) { 117 | carts.forEach((cart) { 118 | cart['isChecked'] = checkState; // 所有状态跟随全选修改 119 | }); 120 | } 121 | 122 | _notifyChanges(carts); 123 | } 124 | 125 | /// 更新购物车状态封装方法 126 | _notifyChanges(List carts) { 127 | PreferenceUtils.instance.saveString('shop_cart', json.encode(carts)); 128 | _shopCartList = json.encode(carts); 129 | _shopCarts.clear(); 130 | _shopCarts.addAll(carts.isEmpty ? [] : ShoppingCartEntity.fromJsonList(carts)); 131 | _allInfoStateCheck(); 132 | notifyListeners(); 133 | } 134 | 135 | /// 数量,全选状态修改封装 136 | void _allInfoStateCheck() { 137 | _allCartCount = 0; 138 | _allSelectedCount = 0; 139 | _allSelectedPrice = 0.0; 140 | _isAllChecked = true; 141 | 142 | _shopCarts.forEach((e) { 143 | _allCartCount += e.count; // 全部数量 144 | if (!e.isChecked) { 145 | _isAllChecked = false; // 如果一个未选中,则全选为 false 146 | } else { 147 | _allSelectedCount += e.count; 148 | _allSelectedPrice += e.count * e.price; 149 | } 150 | }); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /lib/provides/goods_detail_provide.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_shop/configs/service_url.dart'; 5 | import 'package:flutter_shop/entities/goods_detail_entity.dart'; 6 | import 'package:flutter_shop/service/service_method.dart'; 7 | 8 | class GoodsDetailProvide with ChangeNotifier { 9 | GoodsDetailEntity _detail; // 商品详情 10 | int _detailIndex; // 详情页的 tabIndex 11 | 12 | GoodsDetailEntity get detail => _detail; 13 | 14 | int get detailIndex => _detailIndex; 15 | 16 | changeDetails(String id) async { 17 | _detail = await getGoodsDetail(id); 18 | notifyListeners(); 19 | } 20 | 21 | changeIndex(int index) { 22 | _detailIndex = index; 23 | notifyListeners(); 24 | } 25 | 26 | Future getGoodsDetail(String id) async { 27 | var response = await request(servicePath['getGoodDetailById'], formData: {'goodId': id}); 28 | return GoodsDetailEntity.fromMap(json.decode(response.data)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/provides/home_provide.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_shop/configs/service_url.dart'; 5 | import 'package:flutter_shop/entities/home_page_entity.dart'; 6 | import 'package:flutter_shop/entities/hot_goods_entity.dart'; 7 | import 'package:flutter_shop/service/service_method.dart'; 8 | 9 | class HomeProvide with ChangeNotifier { 10 | HomePageEntity _homeEntity; // 首页显示内容 11 | List _hotGoodsList = []; // 火爆专区 12 | int _page = 0; 13 | bool _showBack = false; 14 | String _district = '定位失败'; 15 | double _longitude = 115.02932; 16 | double _latitude = 35.76189; 17 | 18 | HomePageEntity get homeEntity => _homeEntity; 19 | 20 | List get hodGoodsList => _hotGoodsList; 21 | 22 | bool get showBack => _showBack; 23 | 24 | String get district => _district; 25 | 26 | double get longitude => _longitude; 27 | 28 | double get latitude => _latitude; 29 | 30 | changeDistrict(String value, double longitude, double latitude) { 31 | _district = value; 32 | _longitude = longitude; 33 | _latitude = latitude; 34 | notifyListeners(); 35 | } 36 | 37 | initHomeEntity(double lon, double lat) async { 38 | _homeEntity = await _getHomePageContent(lon, lat); 39 | notifyListeners(); 40 | } 41 | 42 | initHotGoodsList() async { 43 | _page = 0; 44 | var hot = await _getHomePageHots(_page); 45 | _hotGoodsList.clear(); 46 | _hotGoodsList.addAll(hot.data); 47 | notifyListeners(); 48 | } 49 | 50 | loadMoreHotGoods() async { 51 | _page++; 52 | var moreHot = await _getHomePageHots(_page); 53 | _hotGoodsList.addAll(moreHot.data); 54 | notifyListeners(); 55 | } 56 | 57 | enableBack(bool state) { 58 | _showBack = state; 59 | notifyListeners(); 60 | } 61 | 62 | Future _getHomePageContent(double lon, double lat) async { 63 | var response = await request(servicePath['homePageContent'], formData: {'lon': /*'115.02932'*/ lon, 'lat': /*'35.76189'*/ lat }); 64 | return HomePageEntity.fromJson(json.decode(response.data.toString())); 65 | } 66 | 67 | Future _getHomePageHots(int page) async { 68 | var response = await request(servicePath['homePageHotPart'], formData: {'page': page}); 69 | return HotGoodsEntity.fromJson(json.decode(response.data)); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/provides/mall_goods_provide.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/entities/category_goods_entity.dart'; 3 | 4 | /// 分类页面商品列表加载 5 | class MallGoodsProvide with ChangeNotifier { 6 | var _page = 1; 7 | 8 | List _goodsList = []; 9 | 10 | List get goodList => _goodsList; 11 | 12 | int get page => _page; 13 | 14 | void increasePage() { 15 | _page++; 16 | } 17 | 18 | void initialPage() { 19 | _page = 1; 20 | } 21 | 22 | // 更换商品大小类别调用 23 | void changeGoodsList(List list) { 24 | _goodsList.clear(); 25 | _goodsList.addAll(list); 26 | notifyListeners(); 27 | } 28 | 29 | // 上拉加载更多 30 | void loadMoreGoodsList(List list) { 31 | _goodsList.addAll(list); 32 | notifyListeners(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/provides/page_index_provide.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// 首页 tab 切换 4 | class PageIndexProvide with ChangeNotifier { 5 | int _page = 0; 6 | 7 | int get page => _page; 8 | 9 | changePage(int page) { 10 | _page = page; 11 | notifyListeners(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/provides/sub_category_provide.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/entities/category_entity.dart'; 3 | 4 | class SubCategoryProvide with ChangeNotifier { 5 | // 商品列表 6 | List _bxMallSubs = []; 7 | 8 | // 大类 id 9 | var _categoryId = ''; 10 | 11 | // 小类 id 12 | var _subCategoryId = ''; 13 | 14 | // 当前选择的小类 item index 15 | var _subIndex = 0; 16 | 17 | List get subCategories => _bxMallSubs; 18 | 19 | String get categoryId => _categoryId; 20 | 21 | String get subCategoryId => _subCategoryId; 22 | 23 | int get subIndex => _subIndex; 24 | 25 | // 修改左侧栏 26 | void changeLeftHeadCategories(List categories) { 27 | BxMallSubDtoListBean allSubDto = BxMallSubDtoListBean() 28 | ..mallCategoryId = '' 29 | ..mallSubId = null 30 | ..comments = '' 31 | ..mallSubName = '全部'; 32 | 33 | _bxMallSubs.clear(); 34 | _bxMallSubs.add(allSubDto); 35 | _bxMallSubs.addAll(categories); 36 | _subCategoryId = ''; 37 | _subIndex = 0; 38 | 39 | notifyListeners(); 40 | } 41 | 42 | // 修改大类 43 | void changeCategory(String categoryId) { 44 | _categoryId = categoryId; 45 | notifyListeners(); 46 | } 47 | 48 | // 修改小类 49 | void changeSubCategorySelect(String subCategoryId) { 50 | _subCategoryId = subCategoryId; 51 | notifyListeners(); 52 | } 53 | 54 | // 小类 index 55 | void changeSubCategoryIndex(int index) { 56 | _subIndex = index; 57 | notifyListeners(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/router/handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | import 'package:flutter_shop/pages/deatilspage/details_page.dart'; 3 | import 'package:flutter_shop/pages/index_page.dart'; 4 | import 'package:flutter_shop/pages/map_page.dart'; 5 | import 'package:flutter_shop/pages/settings_page.dart'; 6 | 7 | Handler rootHandler = new Handler(handlerFunc: (_, params) => IndexPage()); 8 | 9 | Handler detailHandler = new Handler(handlerFunc: (context, param) { 10 | String goodsId = param['id']?.first; 11 | return DetailsPage(goodsId: goodsId); 12 | }); 13 | 14 | Handler mapHandler = new Handler(handlerFunc: (_, param) => MapPage()); 15 | 16 | Handler settingHandler = new Handler(handlerFunc: (_, param) => SettingsPage()); 17 | -------------------------------------------------------------------------------- /lib/router/routers.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluro/fluro.dart'; 2 | 3 | import 'handler.dart'; 4 | 5 | class Routers { 6 | static String root = '/'; 7 | static String details = '/details'; 8 | static String map = '/map'; 9 | static String settings = '/settings'; 10 | 11 | static void configureRouters(Router router) { 12 | router.notFoundHandler = Handler(handlerFunc: (_, params) { 13 | print('not found'); 14 | }); 15 | 16 | router.define(root, handler: rootHandler); 17 | 18 | router.define(details, handler: detailHandler); 19 | 20 | router.define(map, handler: mapHandler); 21 | 22 | router.define(settings, handler: settingHandler); 23 | } 24 | 25 | static String generateDetailsRouterPath(String id) => '$details?id=$id'; 26 | } 27 | -------------------------------------------------------------------------------- /lib/service/service_method.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:dio/dio.dart'; 5 | import 'package:flutter_shop/configs/service_url.dart'; 6 | 7 | Future getCategories() => request(servicePath['getCategory']); 8 | 9 | Future getMallGoods(String categoryId, String categorySubId, int page) => request(servicePath['getMallGoods'], 10 | formData: 11 | categorySubId != null ? {'categoryId': categoryId, 'categorySubId': categorySubId, 'page': page} : {'categoryId': categoryId, 'page': page}); 12 | 13 | Future request(String url, {Map formData}) async { 14 | try { 15 | Response response; 16 | Dio dio = Dio(); 17 | dio.options.contentType = ContentType.parse('application/x-www-form-urlencoded'); 18 | if (formData == null) { 19 | response = await dio.post(url); 20 | } else { 21 | response = await dio.post(url, data: formData); 22 | } 23 | if (response.statusCode == 200) { 24 | return response; 25 | } else { 26 | throw Exception('Net Error'); 27 | } 28 | } catch (e) { 29 | print('ERROR: $e'); 30 | return null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/shop_app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_shop/configs/application.dart'; 3 | 4 | class ShopApp extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Container( 8 | child: MaterialApp( 9 | onGenerateRoute: Application.router.generator, 10 | debugShowCheckedModeBanner: false, 11 | title: 'Flutter Shop', 12 | theme: ThemeData(primaryColor: Colors.pink), 13 | ), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/utils/preference_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | /// shared_preferences 管理类 4 | class PreferenceUtils { 5 | static PreferenceUtils _instance; 6 | 7 | static PreferenceUtils get instance => PreferenceUtils(); 8 | 9 | PreferenceUtils._internal(); 10 | 11 | factory PreferenceUtils() { 12 | if (_instance == null) _instance = PreferenceUtils._internal(); 13 | return _instance; 14 | } 15 | 16 | saveInteger(String key, int value) => SharedPreferences.getInstance().then((sp) => sp.setInt(key, value)); 17 | 18 | saveString(String key, String value) => SharedPreferences.getInstance().then((sp) => sp.setString(key, value)); 19 | 20 | saveBool(String key, bool value) => SharedPreferences.getInstance().then((sp) => sp.setBool(key, value)); 21 | 22 | saveDouble(String key, double value) => SharedPreferences.getInstance().then((sp) => sp.setDouble(key, value)); 23 | 24 | saveStringList(String key, List value) => SharedPreferences.getInstance().then((sp) => sp.setStringList(key, value)); 25 | 26 | Future getInteger(String key, [int defaultValue = 0]) async { 27 | var sp = await SharedPreferences.getInstance(); 28 | var value = sp.getInt(key); 29 | return value ?? defaultValue; 30 | } 31 | 32 | Future getString(String key, [String defaultValue = '']) async { 33 | var sp = await SharedPreferences.getInstance(); 34 | var value = sp.getString(key); 35 | return value ?? defaultValue; 36 | } 37 | 38 | Future getBool(String key, [bool defaultValue = false]) async { 39 | var sp = await SharedPreferences.getInstance(); 40 | var value = sp.getBool(key); 41 | return value ?? defaultValue; 42 | } 43 | 44 | Future getDouble(String key, [double defaultValue = 0.0]) async { 45 | var sp = await SharedPreferences.getInstance(); 46 | var value = sp.getDouble(key); 47 | return value ?? defaultValue; 48 | } 49 | 50 | Future> getStringList(String key, [List defaultValue = const []]) async { 51 | var sp = await SharedPreferences.getInstance(); 52 | var value = sp.getStringList(key); 53 | return value ?? defaultValue; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_shop 2 | description: A Flutter shop application. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # Read more about versioning at semver.org. 10 | version: 1.0.0+1 11 | 12 | environment: 13 | sdk: ">=2.1.0 <3.0.0" 14 | 15 | dependencies: 16 | flutter: 17 | sdk: flutter 18 | 19 | # The following adds the Cupertino Icons font to your application. 20 | # Use with the CupertinoIcons class for iOS style icons. 21 | cupertino_icons: ^0.1.2 22 | 23 | dio: ^2.1.2 24 | path_provider: ^0.5.0+1 25 | flutter_swiper: ^1.1.6 26 | url_launcher: ^5.0.2 27 | flutter_easyrefresh: ^1.2.7 28 | provide: ^1.0.2 29 | fluttertoast: ^3.0.3 30 | fluro: ^1.4.0 31 | flutter_html: ^0.9.6 32 | shared_preferences: ^0.5.2 33 | amap_base: ^0.3.5 34 | jpush_flutter: ^0.0.11 35 | 36 | dev_dependencies: 37 | flutter_test: 38 | sdk: flutter 39 | 40 | 41 | # For information on the generic Dart part of this file, see the 42 | # following page: https://www.dartlang.org/tools/pub/pubspec 43 | 44 | # The following section is specific to Flutter. 45 | flutter: 46 | 47 | # The following line ensures that the Material Icons font is 48 | # included with your application, so that you can use the icons in 49 | # the material Icons class. 50 | uses-material-design: true 51 | 52 | # To add assets to your application, add an assets section, like this: 53 | assets: 54 | - images/ 55 | # - images/a_dot_ham.jpeg 56 | 57 | # An image asset can refer to one or more resolution-specific "variants", see 58 | # https://flutter.io/assets-and-images/#resolution-aware. 59 | 60 | # For details regarding adding assets from package dependencies, see 61 | # https://flutter.io/assets-and-images/#from-packages 62 | 63 | # To add custom fonts to your application, add a fonts section here, 64 | # in this "flutter" section. Each entry in this list should have a 65 | # "family" key with the font family name, and a "fonts" key with a 66 | # list giving the asset and other descriptors for the font. For 67 | # example: 68 | # fonts: 69 | # - family: Schyler 70 | # fonts: 71 | # - asset: fonts/Schyler-Regular.ttf 72 | # - asset: fonts/Schyler-Italic.ttf 73 | # style: italic 74 | # - family: Trajan Pro 75 | # fonts: 76 | # - asset: fonts/TrajanPro.ttf 77 | # - asset: fonts/TrajanPro_Bold.ttf 78 | # weight: 700 79 | # 80 | # For details regarding fonts from package dependencies, 81 | # see https://flutter.io/custom-fonts/#from-packages 82 | -------------------------------------------------------------------------------- /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_shop/shop_app.dart'; 10 | import 'package:flutter_test/flutter_test.dart'; 11 | 12 | void main() { 13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 14 | // Build our app and trigger a frame. 15 | await tester.pumpWidget(ShopApp()); 16 | 17 | // Verify that our counter starts at 0. 18 | expect(find.text('0'), findsOneWidget); 19 | expect(find.text('1'), findsNothing); 20 | 21 | // Tap the '+' icon and trigger a frame. 22 | await tester.tap(find.byIcon(Icons.add)); 23 | await tester.pump(); 24 | 25 | // Verify that our counter has incremented. 26 | expect(find.text('0'), findsNothing); 27 | expect(find.text('1'), findsOneWidget); 28 | }); 29 | } 30 | --------------------------------------------------------------------------------