├── .flutter-plugins-dependencies ├── .gitignore ├── .metadata ├── README.md ├── android ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── shahanaj │ │ │ │ └── woocommerce_app │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ ├── launch_background.xml │ │ │ └── woocom_icon.jpg │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── key.properties ├── settings.gradle └── woocommerce.jks ├── images ├── cover_photo.jpg └── woocom_icon.jpg ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner │ ├── AppDelegate.swift │ ├── 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 │ └── Runner-Bridging-Header.h ├── lib ├── bloc │ ├── cart_page_bloc.dart │ ├── customer_add_bloc.dart │ ├── customer_list_bloc.dart │ ├── home_page_bloc.dart │ ├── order_list_bloc.dart │ └── place_order_bloc.dart ├── helper │ ├── const.dart │ ├── hex_color.dart │ ├── query_string.dart │ ├── ui_helper.dart │ ├── util.dart │ └── woocommerce_api.dart ├── main.dart ├── model │ └── ordered_product.dart └── screen │ ├── cart_page.dart │ ├── customer_add.dart │ ├── cutomer_list_page.dart │ ├── home_page.dart │ ├── my_profile_page.dart │ ├── order_list_page.dart │ ├── place_order_page.dart │ └── splash_screen_page.dart ├── pubspec.lock ├── pubspec.yaml └── test └── widget_test.dart /.flutter-plugins-dependencies: -------------------------------------------------------------------------------- 1 | {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"fluttertoast","path":"C:\\\\Users\\\\Asus\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\fluttertoast-3.1.3\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"fluttertoast","path":"C:\\\\Users\\\\Asus\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\fluttertoast-3.1.3\\\\","native_build":true,"dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"fluttertoast","dependencies":[]}],"date_created":"2023-07-31 22:50:40.426469","version":"3.3.4"} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Android related 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/Flutter/flutter_export_environment.sh 65 | **/ios/ServiceDefinitions.json 66 | **/ios/Runner/GeneratedPluginRegistrant.* 67 | 68 | # Exceptions to above rules. 69 | !**/ios/**/default.mode1v3 70 | !**/ios/**/default.mode2v3 71 | !**/ios/**/default.pbxuser 72 | !**/ios/**/default.perspectivev3 73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 74 | -------------------------------------------------------------------------------- /.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: 2d2a1ffec95cc70a3218872a2cd3f8de4933c42f 8 | channel: beta 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | WooCommerce Flutter App 4 |

5 | 6 |

7 | Flutter WooCommerce App: A sleek e-commerce mobile app integrated with WooCommerce API. Built on Flutter using Bloc pattern for state management, it enables seamless browsing of products, viewing details, and smooth checkout. Delivering a modern shopping experience, it empowers users to shop effortlessly on your WooCommerce store. 8 |

9 | 10 | 11 |

12 | Logo 13 |

14 | 15 | 16 | 17 |

Overview

18 | 19 |

20 | This app demonstrates how to build a cross-platform mobile application using Flutter to interact with the WooCommerce API and manage state with the Bloc pattern. It allows users to browse products, add them to the cart, and make purchases through the WooCommerce online store. 21 |

22 | 23 |

Features

24 | 25 | 32 | 33 |

Installation

34 | 35 |

36 | Follow these steps to set up the project: 37 |

38 | 39 |
    40 |
  1. Clone the repository to your local machine.
  2. 41 | 42 |
    git clone https://github.com/your-username/woocommerce-flutter-app.git
    43 | 44 |
  3. Open the project in your preferred Flutter development environment (Android Studio, VS Code, etc.).
  4. 45 | 46 |
  5. Install the dependencies by running:
  6. 47 | 48 |
    flutter pub get
    49 | 50 |
  7. Create a new file named config.dart in the lib folder to store your WooCommerce API credentials:
  8. 51 | 52 |
    // lib/config.dart
     53 | 
     54 | const String baseUrl = 'https://your-woocommerce-store-url.com/wp-json/wc/v3/';
     55 | const String consumerKey = 'YOUR_CONSUMER_KEY';
     56 | const String consumerSecret = 'YOUR_CONSUMER_SECRET';
    57 | 58 |

    Replace YOUR_CONSUMER_KEY and YOUR_CONSUMER_SECRET with your actual WooCommerce API credentials. You can obtain these credentials from your WooCommerce store's admin panel.

    59 |
60 | 61 |

How to Use

62 | 63 |

64 | This app follows the Bloc pattern for state management, which separates the business logic from the UI. The app's main components are organized as follows: 65 |

66 | 67 | 74 | 75 |

76 | Please refer to the code and documentation in each file to understand how the different components work together. 77 |

78 | 79 |

Contributing

80 | 81 |

82 | Contributions to this project are welcome! Feel free to open issues for bugs or feature requests. If you'd like to contribute code, please fork the repository and create a pull request. 83 |

84 | 85 |

License

86 | 87 |

88 | This project is licensed under the MIT License. 89 |

90 | 91 |

Acknowledgments

92 | 93 |

94 | Thanks to the WooCommerce team for providing a powerful API to build e-commerce applications. 95 | The architecture and patterns used in this app are inspired by various open-source projects and online resources. 96 |

97 | 98 |

Contact

99 | 100 |

101 | If you have any questions or need assistance, feel free to contact the project owner at your-email@example.com. 102 |

103 | 104 |
105 | Screenshot 106 |
107 | 108 |

Screenshots

109 | 110 |
111 | Screenshot 1 112 | Screenshot 2 113 | 114 |
115 | 116 |

Tech Stack

117 | 118 | 123 | 124 |

Resources

125 | 126 |

127 | Here are some useful resources to get started with Flutter, REST API, and Bloc: 128 |

129 | 130 | 135 | 136 |

How to Contribute

137 | 138 |

139 | We welcome contributions from the community! If you'd like to contribute to this project, please follow these steps: 140 |

141 | 142 |
    143 |
  1. Fork the repository on GitHub.
  2. 144 |
  3. Create a new branch from the main branch.
  4. 145 |
  5. Make your changes and commit them.
  6. 146 |
  7. Push your changes to your forked repository.
  8. 147 |
  9. Submit a pull request to the main branch of this repository.
  10. 148 |
149 | 150 |

License

151 | 152 |

153 | This project is licensed under the MIT License - see the LICENSE file for details. 154 |

155 | 156 |

Contact

157 | 158 |

159 | For any inquiries or questions, you can reach us at putulcse9@example.com. 160 |

161 | 162 |
163 |

Powered by Flutter

164 |

Made with ❤️ by [Your Name]

165 |
166 | -------------------------------------------------------------------------------- /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 | 29 | def keystoreProperties = new Properties() 30 | def keystorePropertiesFile = rootProject.file('key.properties') 31 | if (keystorePropertiesFile.exists()) { 32 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 33 | } 34 | 35 | android { 36 | compileSdkVersion 28 37 | 38 | sourceSets { 39 | main.java.srcDirs += 'src/main/kotlin' 40 | } 41 | 42 | lintOptions { 43 | disable 'InvalidPackage' 44 | } 45 | 46 | defaultConfig { 47 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 48 | applicationId "com.shahanaj.woocommerce_app" 49 | minSdkVersion 16 50 | targetSdkVersion 28 51 | versionCode flutterVersionCode.toInteger() 52 | versionName flutterVersionName 53 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 54 | } 55 | 56 | 57 | signingConfigs { 58 | release { 59 | keyAlias keystoreProperties['keyAlias'] 60 | keyPassword keystoreProperties['keyPassword'] 61 | storeFile file(keystoreProperties['storeFile']) 62 | storePassword keystoreProperties['storePassword'] 63 | } 64 | } 65 | buildTypes { 66 | release { 67 | signingConfig signingConfigs.release 68 | //minifyEnabled false 69 | //useProguard true 70 | 71 | // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 72 | } 73 | } 74 | 75 | /* buildTypes { 76 | release { 77 | // TODO: Add your own signing config for the release build. 78 | // Signing with the debug keys for now, so `flutter run --release` works. 79 | signingConfig signingConfigs.debug 80 | } 81 | }*/ 82 | } 83 | 84 | flutter { 85 | source '../..' 86 | } 87 | 88 | dependencies { 89 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 90 | testImplementation 'junit:junit:4.12' 91 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 92 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 93 | } 94 | 95 | 96 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 11 | 15 | 22 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/shahanaj/woocommerce_app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.shahanaj.woocommerce_app 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/drawable/woocom_icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/android/app/src/main/res/drawable/woocom_icon.jpg -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 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.1' 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 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /android/key.properties: -------------------------------------------------------------------------------- 1 | storePassword=putulputul 2 | keyPassword=putulputul 3 | keyAlias=woocommerce 4 | storeFile=/Users/prismerp/Documents/code/FlutterApp/woocommerce_app/android/woocommerce.jks -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /android/woocommerce.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/android/woocommerce.jks -------------------------------------------------------------------------------- /images/cover_photo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/images/cover_photo.jpg -------------------------------------------------------------------------------- /images/woocom_icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/images/woocom_icon.jpg -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Using a CDN with CocoaPods 1.7.2 or later can save a lot of time on pod installation, but it's experimental rather than the default. 2 | # source 'https://cdn.cocoapods.org/' 3 | 4 | # Uncomment this line to define a global platform for your project 5 | # platform :ios, '9.0' 6 | 7 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 8 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 9 | 10 | project 'Runner', { 11 | 'Debug' => :debug, 12 | 'Profile' => :release, 13 | 'Release' => :release, 14 | } 15 | 16 | def parse_KV_file(file, separator='=') 17 | file_abs_path = File.expand_path(file) 18 | if !File.exists? file_abs_path 19 | return []; 20 | end 21 | pods_ary = [] 22 | skip_line_start_symbols = ["#", "/"] 23 | File.foreach(file_abs_path) { |line| 24 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 25 | plugin = line.split(pattern=separator) 26 | if plugin.length == 2 27 | podname = plugin[0].strip() 28 | path = plugin[1].strip() 29 | podpath = File.expand_path("#{path}", file_abs_path) 30 | pods_ary.push({:name => podname, :path => podpath}); 31 | else 32 | puts "Invalid plugin specification: #{line}" 33 | end 34 | } 35 | return pods_ary 36 | end 37 | 38 | target 'Runner' do 39 | use_frameworks! 40 | 41 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 42 | # referring to absolute paths on developers' machines. 43 | system('rm -rf .symlinks') 44 | system('mkdir -p .symlinks/plugins') 45 | 46 | # Flutter Pods 47 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 48 | if generated_xcode_build_settings.empty? 49 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first." 50 | end 51 | generated_xcode_build_settings.map { |p| 52 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 53 | symlink = File.join('.symlinks', 'flutter') 54 | File.symlink(File.dirname(p[:path]), symlink) 55 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 56 | end 57 | } 58 | 59 | # Plugin Pods 60 | plugin_pods = parse_KV_file('../.flutter-plugins') 61 | plugin_pods.map { |p| 62 | symlink = File.join('.symlinks', 'plugins', p[:name]) 63 | File.symlink(p[:path], symlink) 64 | pod p[:name], :path => File.join(symlink, 'ios') 65 | } 66 | end 67 | 68 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 69 | install! 'cocoapods', :disable_input_output_paths => true 70 | 71 | post_install do |installer| 72 | installer.pods_project.targets.each do |target| 73 | target.build_configurations.each do |config| 74 | config.build_settings['ENABLE_BITCODE'] = 'NO' 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 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 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 19 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 20 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXCopyFilesBuildPhase section */ 24 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 25 | isa = PBXCopyFilesBuildPhase; 26 | buildActionMask = 2147483647; 27 | dstPath = ""; 28 | dstSubfolderSpec = 10; 29 | files = ( 30 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 31 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 32 | ); 33 | name = "Embed Frameworks"; 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXCopyFilesBuildPhase section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 40 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 41 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 42 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 43 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 44 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 45 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 46 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 47 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 48 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 49 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 51 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 52 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 53 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | /* End PBXFileReference section */ 55 | 56 | /* Begin PBXFrameworksBuildPhase section */ 57 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 62 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | 9740EEB11CF90186004384FC /* Flutter */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 3B80C3931E831B6300D905FE /* App.framework */, 73 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 74 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 75 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 76 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 77 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 78 | ); 79 | name = Flutter; 80 | sourceTree = ""; 81 | }; 82 | 97C146E51CF9000F007C117D = { 83 | isa = PBXGroup; 84 | children = ( 85 | 9740EEB11CF90186004384FC /* Flutter */, 86 | 97C146F01CF9000F007C117D /* Runner */, 87 | 97C146EF1CF9000F007C117D /* Products */, 88 | ); 89 | sourceTree = ""; 90 | }; 91 | 97C146EF1CF9000F007C117D /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 97C146EE1CF9000F007C117D /* Runner.app */, 95 | ); 96 | name = Products; 97 | sourceTree = ""; 98 | }; 99 | 97C146F01CF9000F007C117D /* Runner */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 103 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 104 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 105 | 97C147021CF9000F007C117D /* Info.plist */, 106 | 97C146F11CF9000F007C117D /* Supporting Files */, 107 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 108 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 109 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 110 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 111 | ); 112 | path = Runner; 113 | sourceTree = ""; 114 | }; 115 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | ); 119 | name = "Supporting Files"; 120 | sourceTree = ""; 121 | }; 122 | /* End PBXGroup section */ 123 | 124 | /* Begin PBXNativeTarget section */ 125 | 97C146ED1CF9000F007C117D /* Runner */ = { 126 | isa = PBXNativeTarget; 127 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 128 | buildPhases = ( 129 | 9740EEB61CF901F6004384FC /* Run Script */, 130 | 97C146EA1CF9000F007C117D /* Sources */, 131 | 97C146EB1CF9000F007C117D /* Frameworks */, 132 | 97C146EC1CF9000F007C117D /* Resources */, 133 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 134 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 135 | ); 136 | buildRules = ( 137 | ); 138 | dependencies = ( 139 | ); 140 | name = Runner; 141 | productName = Runner; 142 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 143 | productType = "com.apple.product-type.application"; 144 | }; 145 | /* End PBXNativeTarget section */ 146 | 147 | /* Begin PBXProject section */ 148 | 97C146E61CF9000F007C117D /* Project object */ = { 149 | isa = PBXProject; 150 | attributes = { 151 | LastUpgradeCheck = 1020; 152 | ORGANIZATIONNAME = "The Chromium Authors"; 153 | TargetAttributes = { 154 | 97C146ED1CF9000F007C117D = { 155 | CreatedOnToolsVersion = 7.3.1; 156 | LastSwiftMigration = 0910; 157 | }; 158 | }; 159 | }; 160 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 161 | compatibilityVersion = "Xcode 3.2"; 162 | developmentRegion = en; 163 | hasScannedForEncodings = 0; 164 | knownRegions = ( 165 | en, 166 | Base, 167 | ); 168 | mainGroup = 97C146E51CF9000F007C117D; 169 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 170 | projectDirPath = ""; 171 | projectRoot = ""; 172 | targets = ( 173 | 97C146ED1CF9000F007C117D /* Runner */, 174 | ); 175 | }; 176 | /* End PBXProject section */ 177 | 178 | /* Begin PBXResourcesBuildPhase section */ 179 | 97C146EC1CF9000F007C117D /* Resources */ = { 180 | isa = PBXResourcesBuildPhase; 181 | buildActionMask = 2147483647; 182 | files = ( 183 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 184 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 185 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 186 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 187 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 188 | ); 189 | runOnlyForDeploymentPostprocessing = 0; 190 | }; 191 | /* End PBXResourcesBuildPhase section */ 192 | 193 | /* Begin PBXShellScriptBuildPhase section */ 194 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 195 | isa = PBXShellScriptBuildPhase; 196 | buildActionMask = 2147483647; 197 | files = ( 198 | ); 199 | inputPaths = ( 200 | ); 201 | name = "Thin Binary"; 202 | outputPaths = ( 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | shellPath = /bin/sh; 206 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 207 | }; 208 | 9740EEB61CF901F6004384FC /* Run Script */ = { 209 | isa = PBXShellScriptBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | ); 213 | inputPaths = ( 214 | ); 215 | name = "Run Script"; 216 | outputPaths = ( 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | shellPath = /bin/sh; 220 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 221 | }; 222 | /* End PBXShellScriptBuildPhase section */ 223 | 224 | /* Begin PBXSourcesBuildPhase section */ 225 | 97C146EA1CF9000F007C117D /* Sources */ = { 226 | isa = PBXSourcesBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 230 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXSourcesBuildPhase section */ 235 | 236 | /* Begin PBXVariantGroup section */ 237 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 238 | isa = PBXVariantGroup; 239 | children = ( 240 | 97C146FB1CF9000F007C117D /* Base */, 241 | ); 242 | name = Main.storyboard; 243 | sourceTree = ""; 244 | }; 245 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 246 | isa = PBXVariantGroup; 247 | children = ( 248 | 97C147001CF9000F007C117D /* Base */, 249 | ); 250 | name = LaunchScreen.storyboard; 251 | sourceTree = ""; 252 | }; 253 | /* End PBXVariantGroup section */ 254 | 255 | /* Begin XCBuildConfiguration section */ 256 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 257 | isa = XCBuildConfiguration; 258 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 259 | buildSettings = { 260 | ALWAYS_SEARCH_USER_PATHS = NO; 261 | CLANG_ANALYZER_NONNULL = YES; 262 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 263 | CLANG_CXX_LIBRARY = "libc++"; 264 | CLANG_ENABLE_MODULES = YES; 265 | CLANG_ENABLE_OBJC_ARC = YES; 266 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 267 | CLANG_WARN_BOOL_CONVERSION = YES; 268 | CLANG_WARN_COMMA = YES; 269 | CLANG_WARN_CONSTANT_CONVERSION = YES; 270 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 271 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 272 | CLANG_WARN_EMPTY_BODY = YES; 273 | CLANG_WARN_ENUM_CONVERSION = YES; 274 | CLANG_WARN_INFINITE_RECURSION = YES; 275 | CLANG_WARN_INT_CONVERSION = YES; 276 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 277 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 278 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 279 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 280 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 281 | CLANG_WARN_STRICT_PROTOTYPES = YES; 282 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 283 | CLANG_WARN_UNREACHABLE_CODE = YES; 284 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 285 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 286 | COPY_PHASE_STRIP = NO; 287 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 288 | ENABLE_NS_ASSERTIONS = NO; 289 | ENABLE_STRICT_OBJC_MSGSEND = YES; 290 | GCC_C_LANGUAGE_STANDARD = gnu99; 291 | GCC_NO_COMMON_BLOCKS = YES; 292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 294 | GCC_WARN_UNDECLARED_SELECTOR = YES; 295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 296 | GCC_WARN_UNUSED_FUNCTION = YES; 297 | GCC_WARN_UNUSED_VARIABLE = YES; 298 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 299 | MTL_ENABLE_DEBUG_INFO = NO; 300 | SDKROOT = iphoneos; 301 | TARGETED_DEVICE_FAMILY = "1,2"; 302 | VALIDATE_PRODUCT = YES; 303 | }; 304 | name = Profile; 305 | }; 306 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 307 | isa = XCBuildConfiguration; 308 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 309 | buildSettings = { 310 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 311 | CLANG_ENABLE_MODULES = YES; 312 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 313 | ENABLE_BITCODE = NO; 314 | FRAMEWORK_SEARCH_PATHS = ( 315 | "$(inherited)", 316 | "$(PROJECT_DIR)/Flutter", 317 | ); 318 | INFOPLIST_FILE = Runner/Info.plist; 319 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 320 | LIBRARY_SEARCH_PATHS = ( 321 | "$(inherited)", 322 | "$(PROJECT_DIR)/Flutter", 323 | ); 324 | PRODUCT_BUNDLE_IDENTIFIER = com.shahanaj.woocommerceApp; 325 | PRODUCT_NAME = "$(TARGET_NAME)"; 326 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 327 | SWIFT_VERSION = 4.0; 328 | VERSIONING_SYSTEM = "apple-generic"; 329 | }; 330 | name = Profile; 331 | }; 332 | 97C147031CF9000F007C117D /* Debug */ = { 333 | isa = XCBuildConfiguration; 334 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 335 | buildSettings = { 336 | ALWAYS_SEARCH_USER_PATHS = NO; 337 | CLANG_ANALYZER_NONNULL = YES; 338 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 339 | CLANG_CXX_LIBRARY = "libc++"; 340 | CLANG_ENABLE_MODULES = YES; 341 | CLANG_ENABLE_OBJC_ARC = YES; 342 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 343 | CLANG_WARN_BOOL_CONVERSION = YES; 344 | CLANG_WARN_COMMA = YES; 345 | CLANG_WARN_CONSTANT_CONVERSION = YES; 346 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 347 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 348 | CLANG_WARN_EMPTY_BODY = YES; 349 | CLANG_WARN_ENUM_CONVERSION = YES; 350 | CLANG_WARN_INFINITE_RECURSION = YES; 351 | CLANG_WARN_INT_CONVERSION = YES; 352 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 353 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 354 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 355 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 356 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 357 | CLANG_WARN_STRICT_PROTOTYPES = YES; 358 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 359 | CLANG_WARN_UNREACHABLE_CODE = YES; 360 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 361 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 362 | COPY_PHASE_STRIP = NO; 363 | DEBUG_INFORMATION_FORMAT = dwarf; 364 | ENABLE_STRICT_OBJC_MSGSEND = YES; 365 | ENABLE_TESTABILITY = YES; 366 | GCC_C_LANGUAGE_STANDARD = gnu99; 367 | GCC_DYNAMIC_NO_PIC = NO; 368 | GCC_NO_COMMON_BLOCKS = YES; 369 | GCC_OPTIMIZATION_LEVEL = 0; 370 | GCC_PREPROCESSOR_DEFINITIONS = ( 371 | "DEBUG=1", 372 | "$(inherited)", 373 | ); 374 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 375 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 376 | GCC_WARN_UNDECLARED_SELECTOR = YES; 377 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 378 | GCC_WARN_UNUSED_FUNCTION = YES; 379 | GCC_WARN_UNUSED_VARIABLE = YES; 380 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 381 | MTL_ENABLE_DEBUG_INFO = YES; 382 | ONLY_ACTIVE_ARCH = YES; 383 | SDKROOT = iphoneos; 384 | TARGETED_DEVICE_FAMILY = "1,2"; 385 | }; 386 | name = Debug; 387 | }; 388 | 97C147041CF9000F007C117D /* Release */ = { 389 | isa = XCBuildConfiguration; 390 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 391 | buildSettings = { 392 | ALWAYS_SEARCH_USER_PATHS = NO; 393 | CLANG_ANALYZER_NONNULL = YES; 394 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 395 | CLANG_CXX_LIBRARY = "libc++"; 396 | CLANG_ENABLE_MODULES = YES; 397 | CLANG_ENABLE_OBJC_ARC = YES; 398 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 399 | CLANG_WARN_BOOL_CONVERSION = YES; 400 | CLANG_WARN_COMMA = YES; 401 | CLANG_WARN_CONSTANT_CONVERSION = YES; 402 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 403 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 404 | CLANG_WARN_EMPTY_BODY = YES; 405 | CLANG_WARN_ENUM_CONVERSION = YES; 406 | CLANG_WARN_INFINITE_RECURSION = YES; 407 | CLANG_WARN_INT_CONVERSION = YES; 408 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 409 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = 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 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 434 | TARGETED_DEVICE_FAMILY = "1,2"; 435 | VALIDATE_PRODUCT = YES; 436 | }; 437 | name = Release; 438 | }; 439 | 97C147061CF9000F007C117D /* Debug */ = { 440 | isa = XCBuildConfiguration; 441 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 442 | buildSettings = { 443 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 444 | CLANG_ENABLE_MODULES = YES; 445 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 446 | ENABLE_BITCODE = NO; 447 | FRAMEWORK_SEARCH_PATHS = ( 448 | "$(inherited)", 449 | "$(PROJECT_DIR)/Flutter", 450 | ); 451 | INFOPLIST_FILE = Runner/Info.plist; 452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 453 | LIBRARY_SEARCH_PATHS = ( 454 | "$(inherited)", 455 | "$(PROJECT_DIR)/Flutter", 456 | ); 457 | PRODUCT_BUNDLE_IDENTIFIER = com.shahanaj.woocommerceApp; 458 | PRODUCT_NAME = "$(TARGET_NAME)"; 459 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 460 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 461 | SWIFT_VERSION = 4.0; 462 | VERSIONING_SYSTEM = "apple-generic"; 463 | }; 464 | name = Debug; 465 | }; 466 | 97C147071CF9000F007C117D /* Release */ = { 467 | isa = XCBuildConfiguration; 468 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 469 | buildSettings = { 470 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 471 | CLANG_ENABLE_MODULES = YES; 472 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 473 | ENABLE_BITCODE = NO; 474 | FRAMEWORK_SEARCH_PATHS = ( 475 | "$(inherited)", 476 | "$(PROJECT_DIR)/Flutter", 477 | ); 478 | INFOPLIST_FILE = Runner/Info.plist; 479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 480 | LIBRARY_SEARCH_PATHS = ( 481 | "$(inherited)", 482 | "$(PROJECT_DIR)/Flutter", 483 | ); 484 | PRODUCT_BUNDLE_IDENTIFIER = com.shahanaj.woocommerceApp; 485 | PRODUCT_NAME = "$(TARGET_NAME)"; 486 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 487 | SWIFT_VERSION = 4.0; 488 | VERSIONING_SYSTEM = "apple-generic"; 489 | }; 490 | name = Release; 491 | }; 492 | /* End XCBuildConfiguration section */ 493 | 494 | /* Begin XCConfigurationList section */ 495 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 496 | isa = XCConfigurationList; 497 | buildConfigurations = ( 498 | 97C147031CF9000F007C117D /* Debug */, 499 | 97C147041CF9000F007C117D /* Release */, 500 | 249021D3217E4FDB00AE95B9 /* Profile */, 501 | ); 502 | defaultConfigurationIsVisible = 0; 503 | defaultConfigurationName = Release; 504 | }; 505 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 506 | isa = XCConfigurationList; 507 | buildConfigurations = ( 508 | 97C147061CF9000F007C117D /* Debug */, 509 | 97C147071CF9000F007C117D /* Release */, 510 | 249021D4217E4FDB00AE95B9 /* Profile */, 511 | ); 512 | defaultConfigurationIsVisible = 0; 513 | defaultConfigurationName = Release; 514 | }; 515 | /* End XCConfigurationList section */ 516 | 517 | }; 518 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 519 | } 520 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahanajparvin/woocommerce_app_flutter/95c207598620dd5fa49af79e7963702ad32925ba/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 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | woocommerce_app 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /lib/bloc/cart_page_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:woocommerce_app/helper/const.dart'; 6 | import 'package:rxdart/rxdart.dart'; 7 | import 'package:woocommerce_app/model/ordered_product.dart'; 8 | import 'package:woocommerce_app/screen/customer_add.dart'; 9 | import 'package:woocommerce_app/helper/ui_helper.dart'; 10 | 11 | class CartListBloc { 12 | List cartProductList = new List(); 13 | 14 | Map customer = new Map(); 15 | 16 | final _cartProductListFetcher = BehaviorSubject(); 17 | 18 | final customerFetcher = BehaviorSubject(); 19 | 20 | final totalCreditValueFetcher = BehaviorSubject(); 21 | 22 | Observable get allCartProducts => _cartProductListFetcher.stream; 23 | 24 | CartListBloc(dynamic value, var customer) { 25 | this.cartProductList = value; 26 | this.customer = customer; 27 | } 28 | 29 | fetchCustomer() { 30 | customerFetcher.sink.add(customer); 31 | } 32 | 33 | /* 34 | * This function calculate total credit value from order items 35 | * Sink the the value 36 | */ 37 | 38 | fetchTotalCreditValue() { 39 | double totalCreditValue = 0.0; 40 | for (int i = 0; i < cartProductList.length; i++) { 41 | if (cartProductList[i].totalCreditValue != null) 42 | totalCreditValue = 43 | totalCreditValue + cartProductList[i].totalCreditValue; 44 | } 45 | totalCreditValueFetcher.sink.add(totalCreditValue); 46 | } 47 | 48 | fetchOrderedProducts() async { 49 | _cartProductListFetcher.sink.add(cartProductList); 50 | } 51 | 52 | Future createOrder(final _scaffoldKey, BuildContext context, Map paymentInfo) async { 53 | 54 | 55 | if (cartProductList.length > 0) { // Check the cart list empty or not 56 | 57 | if (customer != null) { // Before place order check customer is available or not 58 | 59 | UIHelper.showProcessingDialog(context); // Show a progress dialog during Place order http request 60 | 61 | List orderedProductList = new List(); // Prepare a product list which will be added in place order list 62 | 63 | for (int i = 0; i < cartProductList.length; i++) { 64 | Map addcartProductList = new Map(); 65 | addcartProductList.putIfAbsent( 66 | 'product_id', () => int.parse(cartProductList[i].id)); 67 | addcartProductList.putIfAbsent( 68 | 'quantity', () => cartProductList[i].orderCount); 69 | orderedProductList.add(addcartProductList); 70 | } 71 | 72 | try { 73 | var response = await Const.wc_api.postAsync("orders", { 74 | "payment_method": paymentInfo['payment_method'], 75 | "payment_method_title": paymentInfo['payment_method_title'], 76 | "set_paid": true, 77 | "billing": customer['billing'], 78 | "shipping": customer['shipping'], 79 | "line_items": orderedProductList, 80 | }); 81 | 82 | Navigator.of(context).pop(); // Processing dialog close after getting the response 83 | 84 | if (response.containsKey('message')) //if response contains message key that means customer not created and return the reason in message key 85 | { 86 | showDefaultSnackbar(_scaffoldKey, context, response['message']); 87 | } 88 | else if (response.toString().contains('id')) // if response contains id that customer created 89 | { 90 | showDefaultSnackbar(_scaffoldKey, context, 91 | 'Congratulation ! Successfully place your order'); 92 | } 93 | else 94 | { 95 | showDefaultSnackbar(_scaffoldKey, context, response.toString()); 96 | } 97 | 98 | } catch (e) { 99 | 100 | } 101 | } 102 | else 103 | { 104 | showDefaultSnackbar(_scaffoldKey, context, 'Please ! add a customer'); 105 | } 106 | } 107 | else 108 | { 109 | showDefaultSnackbar( 110 | _scaffoldKey, context, 'Please ! at least add one order'); 111 | } 112 | } 113 | 114 | /* 115 | * This function add product count in cart by productId 116 | * Update the cart product list by sink to cartProductList 117 | * Also calculate cart product credit value 118 | */ 119 | 120 | orderAdd(String productId) { 121 | for (int i = 0; i < cartProductList.length; i++) { 122 | if (productId == cartProductList[i].id) { 123 | int count = cartProductList[i].orderCount + 1; 124 | cartProductList[i].orderCount = count; 125 | if (cartProductList[i].mrp != null) 126 | cartProductList[i].totalCreditValue = 127 | double.parse(cartProductList[i].mrp) * count; 128 | break; 129 | } 130 | } 131 | _cartProductListFetcher.sink.add(cartProductList); 132 | fetchTotalCreditValue(); 133 | } 134 | 135 | /* 136 | * This function remove product count in cart by productId 137 | * Update the cart product list by sink to cartProductList 138 | * Also calculate cart product credit value 139 | */ 140 | 141 | orderRemove(String id) { 142 | for (int i = 0; i < cartProductList.length; i++) { 143 | if (id == cartProductList[i].id) { 144 | if (cartProductList[i].orderCount > 0) { 145 | int count = cartProductList[i].orderCount - 1; 146 | cartProductList[i].orderCount = count; 147 | if (cartProductList[i].mrp != null) 148 | cartProductList[i].totalCreditValue = 149 | double.parse(cartProductList[i].mrp) * count; 150 | 151 | break; 152 | } 153 | } 154 | } 155 | 156 | _cartProductListFetcher.sink.add(cartProductList); 157 | fetchTotalCreditValue(); 158 | } 159 | 160 | /* 161 | * Function Remove product by productId from cart 162 | */ 163 | 164 | orderDelete(String productId) { 165 | for (int i = 0; i < cartProductList.length; i++) { 166 | cartProductList.removeAt(i); 167 | } 168 | 169 | _cartProductListFetcher.sink.add(cartProductList); 170 | fetchTotalCreditValue(); 171 | } 172 | 173 | /* 174 | Function Route to new customer page if customer not available during place order 175 | */ 176 | 177 | routeToCustomerAddPage(BuildContext context) { 178 | Navigator.push( 179 | context, MaterialPageRoute(builder: (context) => CustomerAddPage())) 180 | .then((onValue) { 181 | if (onValue != null) { 182 | this.customer = onValue; 183 | fetchCustomer(); 184 | } 185 | }); 186 | } 187 | 188 | dispose() { 189 | _cartProductListFetcher.close(); 190 | } 191 | 192 | 193 | /* 194 | Function Display proper message to user after requesting to create a order 195 | */ 196 | 197 | void showDefaultSnackbar( 198 | final _scaffoldKey, BuildContext context, String message) { 199 | _scaffoldKey.currentState.showSnackBar( 200 | SnackBar( 201 | duration: Duration(minutes: 5), 202 | content: Text(message), 203 | action: SnackBarAction( 204 | textColor: Colors.white, 205 | label: 'Ok', 206 | onPressed: () { 207 | if (!message.contains('customer')) 208 | Navigator.of(context).pop(customer); // Back to customer list page 209 | }, 210 | ), 211 | ), 212 | ); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /lib/bloc/customer_add_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:woocommerce_app/helper/const.dart'; 4 | import 'package:woocommerce_app/helper/ui_helper.dart'; 5 | 6 | class CustomerAddBloc { 7 | 8 | 9 | Future createCustomer(Map customerBasicInfo, Map customerAddressInfo, final _scaffoldKey, BuildContext context) async { 10 | 11 | UIHelper.showProcessingDialog(context); // Show a progress dialog during network request 12 | 13 | try { 14 | var response = await Const.wc_api.postAsync("customers", { 15 | "email": customerBasicInfo['email'], 16 | "first_name": customerBasicInfo['firstName'], 17 | "username": customerBasicInfo['userName'], 18 | "billing": customerAddressInfo, 19 | "shipping": customerAddressInfo 20 | }); 21 | 22 | 23 | Navigator.of(context).pop(); // Processing dialog close after getting the response 24 | 25 | if (response.containsKey('message')) // if response contains message key that means customer not created and return the reason in message key 26 | { 27 | 28 | showSnackbarWithProperMessage( 29 | _scaffoldKey, context, response['message']); 30 | 31 | } else if (response.toString().contains('id')) // if response contains id that customer created 32 | { 33 | 34 | showSnackbarWithProperMessage(_scaffoldKey, context, 35 | 'Congratulation ! Successfully place your order'); 36 | 37 | 38 | Navigator.of(context).pop(response); // Back to customer list page 39 | 40 | } else 41 | { 42 | showSnackbarWithProperMessage(_scaffoldKey, context, 43 | response.toString()); // JSON Object with response 44 | 45 | } 46 | 47 | } catch (e) { 48 | } 49 | } 50 | 51 | /* 52 | Function Display proper message to user after requesting to create a customer 53 | */ 54 | 55 | void showSnackbarWithProperMessage(final _scaffoldKey, BuildContext context, String disPlayMessage) { 56 | 57 | _scaffoldKey.currentState.showSnackBar( 58 | SnackBar( 59 | duration: Duration(minutes: 5), 60 | content: Text(disPlayMessage), 61 | ), 62 | ); 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/bloc/customer_list_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:woocommerce_app/helper/const.dart'; 4 | import 'package:rxdart/rxdart.dart'; 5 | import 'package:woocommerce_app/screen/customer_add.dart'; 6 | import 'package:woocommerce_app/screen/place_order_page.dart'; 7 | 8 | class CustomerListBloc { 9 | final _customerListFetcher = BehaviorSubject(); 10 | 11 | Observable get allCustomers => _customerListFetcher.stream; 12 | 13 | /* 14 | * Fetch the customer list filtering by search text 15 | */ 16 | 17 | onSearchTextChanged(String searchText) async { 18 | 19 | fetchCustomers(searchText); 20 | 21 | } 22 | 23 | fetchCustomers(String search) async { 24 | 25 | var response = await Const.wc_api.getAsync("customers?search=" + search); 26 | _customerListFetcher.sink.add(response); 27 | 28 | } 29 | 30 | routeToPlaceOrderPage(BuildContext context, var customer) { 31 | 32 | Navigator.push(context, 33 | MaterialPageRoute(builder: (context) => PlaceOrderPage(customer))); 34 | 35 | } 36 | 37 | routeToCustomerAddPage(BuildContext context) { 38 | 39 | Navigator.push( 40 | context, MaterialPageRoute(builder: (context) => CustomerAddPage())) 41 | .then((onValue) { 42 | 43 | // After return the page refresh the customer list by http request to add the new order in list 44 | 45 | if (onValue != null) { 46 | fetchCustomers(''); 47 | } 48 | 49 | }); 50 | } 51 | 52 | dispose() { 53 | 54 | _customerListFetcher.close(); 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/bloc/home_page_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:rxdart/rxdart.dart'; 2 | import 'package:woocommerce_app/helper/const.dart'; 3 | 4 | class HomePageBloc { 5 | 6 | 7 | final customerCountFetcher = BehaviorSubject(); 8 | 9 | final productCountFetcher = BehaviorSubject(); 10 | 11 | final orderCountFetcher = BehaviorSubject(); 12 | 13 | final averageSalesValueFetcher = BehaviorSubject(); 14 | 15 | final netSalesValueFetcher = BehaviorSubject(); 16 | 17 | final totalSalesValueFetcher = BehaviorSubject(); 18 | 19 | 20 | fetchSalesReports() async { 21 | 22 | var response= await Const.wc_api.getAsync('reports/sales?date_min=2016-05-03&date_max=2020-05-04'); 23 | var totalSales = response[0]; 24 | averageSalesValueFetcher.sink.add(totalSales['average_sales']); 25 | netSalesValueFetcher.sink.add(totalSales['net_sales']); 26 | totalSalesValueFetcher.sink.add(totalSales['total_sales']); 27 | } 28 | 29 | fetchPerModuleCount(String value) async { 30 | 31 | var p = await Const.wc_api.getCountAsync(value); 32 | if (value == 'customers') { 33 | customerCountFetcher.sink.add(p['count']); 34 | } else if (value == 'products') { 35 | productCountFetcher.sink.add(p['count']); 36 | } else if (value == 'orders') { 37 | orderCountFetcher.sink.add(p['count']); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/bloc/order_list_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:woocommerce_app/helper/const.dart'; 4 | import 'package:rxdart/rxdart.dart'; 5 | import 'package:woocommerce_app/screen/place_order_page.dart'; 6 | 7 | class OrderListBloc { 8 | 9 | 10 | final _OrderListFetcher = BehaviorSubject(); 11 | 12 | Observable get allOrders => _OrderListFetcher.stream; 13 | 14 | /* 15 | * Fetch the Orders list filtering by search text 16 | */ 17 | 18 | onSearchTextChanged(String text) async { 19 | fetchOrders(text); 20 | } 21 | 22 | fetchOrders(String search) async { 23 | var response = await Const.wc_api.getAsync("orders?search=" + search); 24 | _OrderListFetcher.sink.add(response); 25 | } 26 | 27 | routeToNewOrderPage(BuildContext context) { 28 | Navigator.push(context, 29 | MaterialPageRoute(builder: (context) => PlaceOrderPage(null))) 30 | .then((onValue) { 31 | fetchOrders(''); 32 | }); 33 | } 34 | 35 | dispose() { 36 | _OrderListFetcher.close(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/bloc/place_order_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:woocommerce_app/helper/const.dart'; 4 | import 'package:woocommerce_app/model/ordered_product.dart'; 5 | import 'package:woocommerce_app/screen/cart_page.dart'; 6 | import 'package:rxdart/rxdart.dart'; 7 | 8 | class PlaceOrderBloc { 9 | 10 | List productList = new List(); 11 | 12 | Map orderCount = new Map(); 13 | 14 | Map categories = new Map(); 15 | 16 | var customer; 17 | 18 | final _productListFetcher = BehaviorSubject(); 19 | 20 | Observable get allProducts => _productListFetcher.stream; 21 | 22 | final totalCountProductItemInCartFetcher = BehaviorSubject(); 23 | 24 | final totalCreditValueFetcher = BehaviorSubject(); 25 | 26 | final categoriesFetcher = BehaviorSubject(); 27 | 28 | List categoriesKeys = new List(); 29 | 30 | PlaceOrderBloc(var customer) { 31 | this.customer = customer; 32 | } 33 | 34 | /* 35 | * Fetch the customer list filtering by search text 36 | */ 37 | onSearchTextChanged(String text) async { 38 | fetchProducts(text, ''); 39 | } 40 | 41 | /* 42 | * This function calculate total credit value from order items 43 | * Sink the the value 44 | */ 45 | 46 | fetchTotalProductsCreditValue() { 47 | double totalCreditValue = 0.0; 48 | for (int i = 0; i < productList.length; i++) { 49 | if (productList[i].totalCreditValue != null) 50 | totalCreditValue = totalCreditValue + productList[i].totalCreditValue; 51 | } 52 | totalCreditValueFetcher.sink.add(totalCreditValue); 53 | } 54 | 55 | fetchCategories() async { 56 | 57 | var response = await Const.wc_api.getAsync("products/categories"); 58 | 59 | categories = new Map(); 60 | 61 | categories['Select a category'] = ''; 62 | 63 | for (int i = 0; i < response.length; i++) { 64 | print(response[i]['id']); 65 | categories.putIfAbsent(response[i]['name'], () => response[i]['id'].toString()); 66 | } 67 | 68 | categoriesKeys = new List(); 69 | for (String value in categories.keys) { 70 | categoriesKeys.add(value); 71 | } 72 | 73 | if (categoriesKeys.length > 0) { 74 | Map> category = new Map>(); 75 | 76 | category[categoriesKeys[0]] = categoriesKeys; 77 | 78 | categoriesFetcher.sink.add(category); 79 | } 80 | } 81 | 82 | /* 83 | * Function return products list 84 | * Search and Filtering by product name and product category 85 | */ 86 | 87 | fetchProducts(String search, String categoryId) async { 88 | var response = await Const.wc_api 89 | .getAsync("products?search=" + search + "&category=" + categoryId); 90 | 91 | productList = new List(); 92 | 93 | 94 | // This loops keep track add to cart item after refresh the product list 95 | 96 | for (int i = 0; i < response.length; i++) { 97 | bool isTrue = true; 98 | 99 | orderCount.forEach((key, value) { 100 | if (key == response[i]['id'].toString()) { 101 | productList.add(new OrderProducts.fromJson(response[i], value.orderCount)); 102 | isTrue = false; 103 | return; 104 | } 105 | }); 106 | 107 | if (isTrue) { 108 | productList.add(new OrderProducts.fromJson(response[i], 0)); 109 | } 110 | } 111 | 112 | _productListFetcher.sink.add(productList); 113 | } 114 | 115 | /* 116 | * This function add product count in cart by productId 117 | * Update the cart product list by sink to cartProductList 118 | * Also calculate cart product credit value 119 | */ 120 | 121 | orderAdd(String id) { 122 | for (int i = 0; i < productList.length; i++) { 123 | if (id == productList[i].id) { 124 | int count = productList[i].orderCount + 1; 125 | productList[i].orderCount = count; 126 | if (productList[i].mrp != null) 127 | productList[i].totalCreditValue = 128 | double.parse(productList[i].mrp) * count; 129 | orderCount[id] = productList[i]; 130 | break; 131 | } 132 | } 133 | 134 | _productListFetcher.sink.add(productList); 135 | fetchTotalProductsCreditValue(); 136 | totalCountProductItemInCart(); 137 | } 138 | 139 | /* 140 | * This function remove product count in cart by productId 141 | * Update the cart product list by sink to cartProductList 142 | * Also calculate cart product credit value 143 | */ 144 | 145 | orderRemove(String id) { 146 | for (int i = 0; i < productList.length; i++) { 147 | if (id == productList[i].id) { 148 | if (productList[i].orderCount > 0) { 149 | int count = productList[i].orderCount - 1; 150 | productList[i].orderCount = count; 151 | if (productList[i].mrp != null) 152 | productList[i].totalCreditValue = 153 | double.parse(productList[i].mrp) * count; 154 | orderCount[id] = productList[i]; 155 | 156 | break; 157 | } 158 | } 159 | } 160 | 161 | _productListFetcher.sink.add(productList); 162 | fetchTotalProductsCreditValue(); 163 | totalCountProductItemInCart(); 164 | } 165 | 166 | searchByCategories(String value) { 167 | 168 | if (categoriesKeys.length > 0) { 169 | Map> category = new Map>(); 170 | 171 | category[value] = categoriesKeys; 172 | 173 | categoriesFetcher.sink.add(category); 174 | } 175 | 176 | fetchProducts('', categories[value].toString()); 177 | } 178 | 179 | routeToCartPage(BuildContext context, final _scaffoldKey) { 180 | 181 | List productsList = new List(); 182 | 183 | orderCount.forEach((k, v) { 184 | if (v.orderCount > 0) { 185 | productsList.add(v); 186 | } 187 | }); 188 | 189 | if (productsList.length > 0) { 190 | Navigator.push( 191 | context, 192 | MaterialPageRoute( 193 | builder: (context) => 194 | CartListPage(productsList, this.customer))).then((onValue) { 195 | 196 | if (onValue != null) { 197 | this.customer = onValue; 198 | orderCount = new Map(); 199 | fetchProducts('', ''); 200 | totalCountProductItemInCartFetcher.sink.add(0); 201 | totalCreditValueFetcher.sink.add(0.00); 202 | } 203 | }); 204 | } else { 205 | showDefaultSnackbar(_scaffoldKey); 206 | } 207 | } 208 | 209 | dispose() { 210 | _productListFetcher.close(); 211 | } 212 | 213 | totalCountProductItemInCart() { 214 | List productsList = new List(); 215 | orderCount.forEach((k, v) { 216 | if (v.orderCount > 0) { 217 | productsList.add(v); 218 | } 219 | }); 220 | 221 | totalCountProductItemInCartFetcher.sink.add(productsList.length); 222 | } 223 | 224 | /* 225 | Function Display proper message to user 226 | */ 227 | void showDefaultSnackbar(final _scaffoldKey) { 228 | _scaffoldKey.currentState.showSnackBar( 229 | SnackBar( 230 | duration: Duration(seconds: 5), 231 | content: Text('Please ! At least add one order'), 232 | ), 233 | ); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /lib/helper/const.dart: -------------------------------------------------------------------------------- 1 | import 'package:woocommerce_app/helper/woocommerce_api.dart'; 2 | 3 | class Const { 4 | static WooCommerceAPI wc_api = new WooCommerceAPI( 5 | "your_host_name", "your_consumer_key", "your_secret_key"); 6 | } 7 | -------------------------------------------------------------------------------- /lib/helper/hex_color.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | class HexColor extends Color { 4 | static int _getColorFromHex(String hexColor) { 5 | hexColor = hexColor.toUpperCase().replaceAll("#", ""); 6 | if (hexColor.length == 6) { 7 | hexColor = "FF" + hexColor; 8 | } 9 | return int.parse(hexColor, radix: 16); 10 | } 11 | 12 | HexColor(final String hexColor) : super(_getColorFromHex(hexColor)); 13 | } -------------------------------------------------------------------------------- /lib/helper/query_string.dart: -------------------------------------------------------------------------------- 1 | class QueryString { 2 | /** 3 | * Parses the given query string into a Map. 4 | */ 5 | static Map parse(String query) { 6 | var search = new RegExp('([^&=]+)=?([^&]*)'); 7 | var result = new Map(); 8 | 9 | // Get rid off the beginning ? in query strings. 10 | if (query.startsWith('?')) query = query.substring(1); 11 | 12 | // A custom decoder. 13 | decode(String s) => Uri.decodeComponent(s.replaceAll('+', ' ')); 14 | 15 | // Go through all the matches and build the result map. 16 | for (Match match in search.allMatches(query)) { 17 | result[decode(match.group(1))] = decode(match.group(2)); 18 | } 19 | 20 | return result; 21 | } 22 | } -------------------------------------------------------------------------------- /lib/helper/ui_helper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:fluttertoast/fluttertoast.dart'; 5 | import 'package:progress_hud/progress_hud.dart'; 6 | 7 | 8 | class UIHelper{ 9 | 10 | 11 | static const bool isFill = true; 12 | 13 | static const double margin = 15; 14 | 15 | static double navigateIconSize = 35; 16 | 17 | static const double detailsMargin = 10; 18 | 19 | static Color addFormContainerBodyColor = Color.fromRGBO(240,240,240,100); 20 | static Color themeColor = Colors.red; 21 | 22 | 23 | static showToast(String msg) { 24 | return Fluttertoast.showToast( 25 | msg: msg, 26 | toastLength: Toast.LENGTH_SHORT, 27 | gravity: ToastGravity.BOTTOM, 28 | timeInSecForIos: 1, 29 | backgroundColor: Colors.red, 30 | textColor: Colors.white, 31 | fontSize: 16.0); 32 | } 33 | 34 | static UnderlineInputBorder borderWeight() 35 | { 36 | 37 | UnderlineInputBorder( 38 | borderSide: BorderSide(width: 0.5), 39 | ); 40 | } 41 | 42 | 43 | 44 | static TextStyle getTextStyleForHomeScreenItem() 45 | { 46 | 47 | return new TextStyle( 48 | color: Colors.black, 49 | fontWeight: FontWeight.w400, 50 | fontSize: 12 51 | ); 52 | 53 | } 54 | 55 | 56 | static showProcessingDialog(BuildContext _context) { 57 | 58 | ProgressHUD _progressHUD = new ProgressHUD( 59 | backgroundColor: Colors.transparent, 60 | color: Colors.white, 61 | containerColor: UIHelper.themeColor, 62 | borderRadius: 5.0, 63 | text: 'Processing...', 64 | ); 65 | showDialog( 66 | context: _context, 67 | builder: (_context) { 68 | // return object of type Dialog 69 | return _progressHUD; 70 | }, 71 | ); 72 | } 73 | 74 | 75 | 76 | 77 | } -------------------------------------------------------------------------------- /lib/helper/util.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomColors { 4 | static const Color GreyBackground = Color.fromRGBO(249, 252, 255, 1); 5 | static const Color GreyBorder = Color.fromRGBO(207, 207, 207, 1); 6 | 7 | static const Color GreenLight = Color.fromRGBO(93, 230, 26, 1); 8 | static const Color GreenDark = Color.fromRGBO(57, 170, 2, 1); 9 | static const Color GreenIcon = Color.fromRGBO(30, 209, 2, 1); 10 | static const Color GreenAccent = Color.fromRGBO(30, 209, 2, 1); 11 | static const Color GreenShadow = Color.fromRGBO(30, 209, 2, 0.24); // 24% 12 | static const Color GreenBackground = Color.fromRGBO(181, 255, 155, 0.36); // 36% 13 | 14 | static const Color OrangeIcon = Color.fromRGBO(236, 108, 11, 1); 15 | static const Color OrangeBackground = Color.fromRGBO(255, 208, 155, 0.36); // 36% 16 | 17 | static const Color PurpleLight = Color.fromRGBO(248, 87, 195, 1); 18 | static const Color PurpleDark = Color.fromRGBO(224, 19, 156, 1); 19 | static const Color PurpleIcon = Color.fromRGBO(209, 2, 99, 1); 20 | static const Color PurpleAccent = Color.fromRGBO(209, 2, 99, 1); 21 | static const Color PurpleShadow = Color.fromRGBO(209, 2, 99, 0.27); // 27% 22 | static const Color PurpleBackground = Color.fromRGBO(255, 155, 205, 0.36); // 36% 23 | 24 | static const Color DeeppurlpleIcon = Color.fromRGBO(191, 0, 128, 1); 25 | static const Color DeeppurlpleBackground = Color.fromRGBO(245, 155, 255, 0.36); // 36% 26 | 27 | static const Color BlueLight = Color.fromRGBO(126, 182, 255, 1); 28 | static const Color BlueDark = Color.fromRGBO(95, 135, 231, 1); 29 | static const Color BlueIcon = Color.fromRGBO(9, 172, 206, 1); 30 | static const Color BlueBackground = Color.fromRGBO(155, 255, 248, 0.36); // 36% 31 | static const Color BlueShadow = Color.fromRGBO(104, 148, 238, 1); 32 | 33 | static const Color HeaderBlueLight = Color.fromRGBO(129, 199, 245, 1); 34 | static const Color HeaderBlueDark = Color.fromRGBO(56, 103, 213, 1); 35 | static const Color HeaderGreyLight = Color.fromRGBO(225, 255, 255, 0.31); // 31% 36 | 37 | static const Color YellowIcon = Color.fromRGBO(249, 194, 41, 1); 38 | static const Color YellowBell = Color.fromRGBO(225, 220, 0, 1); 39 | static const Color YellowAccent = Color.fromRGBO(255, 213, 6, 1); 40 | static const Color YellowShadow = Color.fromRGBO(243, 230, 37, 0.27); // 27% 41 | static const Color YellowBackground = Color.fromRGBO(255, 238, 155, 0.36); // 36% 42 | 43 | static const Color BellGrey = Color.fromRGBO(217, 217, 217, 1); 44 | static const Color BellYellow = Color.fromRGBO(255, 220, 0, 1); 45 | 46 | static const Color TrashRed = Color.fromRGBO(251, 54, 54, 1); 47 | static const Color TrashRedBackground = Color.fromRGBO(255, 207, 207, 1); 48 | 49 | static const Color TextHeader = Color.fromRGBO(85, 78, 143, 1); 50 | static const Color TextHeaderGrey = Color.fromRGBO(104, 104, 104, 1); 51 | static const Color TextSubHeaderGrey = Color.fromRGBO(161, 161, 161, 1); 52 | static const Color TextSubHeader = Color.fromRGBO(139, 135, 179, 1); 53 | static const Color TextBody = Color.fromRGBO(130, 160, 183, 1); 54 | static const Color TextGrey = Color.fromRGBO(198, 198, 200, 1); 55 | static const Color TextWhite = Color.fromRGBO(243, 243, 243, 1); 56 | static const Color HeaderCircle = Color.fromRGBO(255, 255, 255, 0.17); 57 | } -------------------------------------------------------------------------------- /lib/helper/woocommerce_api.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:async'; 3 | import "dart:collection"; 4 | import 'dart:convert'; 5 | import 'dart:io'; 6 | import "dart:math"; 7 | import "dart:core"; 8 | import 'package:crypto/crypto.dart' as crypto; 9 | import 'package:http/http.dart' as http; 10 | import 'package:woocommerce_app/helper/query_string.dart'; 11 | 12 | class WooCommerceAPI { 13 | String url; 14 | String consumerKey; 15 | String consumerSecret; 16 | bool isHttps; 17 | 18 | WooCommerceAPI(url, consumerKey, consumerSecret){ 19 | this.url = url; 20 | this.consumerKey = consumerKey; 21 | this.consumerSecret = consumerSecret; 22 | 23 | if(this.url.startsWith("https")){ 24 | this.isHttps = true; 25 | } else { 26 | this.isHttps = false; 27 | } 28 | 29 | } 30 | 31 | 32 | _getOAuthURL(String request_method, String endpoint) { 33 | var consumerKey = this.consumerKey; 34 | var consumerSecret = this.consumerSecret; 35 | 36 | var token = ""; 37 | var token_secret = ""; 38 | var url = this.url + "/wp-json/wc/v2/" + endpoint; 39 | var containsQueryParams = url.contains("?"); 40 | 41 | // If website is HTTPS based, no need for OAuth, just return the URL with CS and CK as query params 42 | if(this.isHttps == true){ 43 | return url + (containsQueryParams == true ? "&consumer_key=" + this.consumerKey + "&consumer_secret=" + this.consumerSecret : "?consumer_key=" + this.consumerKey + "&consumer_secret=" + this.consumerSecret); 44 | } 45 | 46 | var rand = new Random(); 47 | var codeUnits = new List.generate(10, (index) { 48 | return rand.nextInt(26) + 97; 49 | }); 50 | 51 | var nonce = new String.fromCharCodes(codeUnits); 52 | int timestamp = (new DateTime.now().millisecondsSinceEpoch / 1000).toInt(); 53 | 54 | //print(timestamp); 55 | //print(nonce); 56 | 57 | var method = request_method; 58 | var path = url.split("?")[0]; 59 | var parameters = "oauth_consumer_key=" + 60 | consumerKey + 61 | "&oauth_nonce=" + 62 | nonce + 63 | "&oauth_signature_method=HMAC-SHA1&oauth_timestamp=" + 64 | timestamp.toString() + 65 | "&oauth_token=" + 66 | token + 67 | "&oauth_version=1.0&"; 68 | 69 | if (containsQueryParams == true) { 70 | parameters = parameters + url.split("?")[1]; 71 | } else { 72 | parameters = parameters.substring(0, parameters.length - 1); 73 | } 74 | 75 | Map params = QueryString.parse(parameters); 76 | Map treeMap = new SplayTreeMap(); 77 | treeMap.addAll(params); 78 | 79 | String parameterString = ""; 80 | 81 | for (var key in treeMap.keys) { 82 | parameterString = parameterString + 83 | Uri.encodeQueryComponent(key) + 84 | "=" + 85 | treeMap[key] + 86 | "&"; 87 | } 88 | 89 | parameterString = parameterString.substring(0, parameterString.length - 1); 90 | 91 | var baseString = method + 92 | "&" + 93 | Uri.encodeQueryComponent( 94 | containsQueryParams == true ? url.split("?")[0] : url) + 95 | "&" + 96 | Uri.encodeQueryComponent(parameterString); 97 | 98 | //print(baseString); 99 | 100 | var signingKey = consumerSecret + "&" + token; 101 | //print(signingKey); 102 | //print(UTF8.encode(signingKey)); 103 | var hmacSha1 = 104 | new crypto.Hmac(crypto.sha1, utf8.encode(signingKey)); // HMAC-SHA1 105 | var signature = hmacSha1.convert(utf8.encode(baseString)); 106 | 107 | //print(signature); 108 | 109 | var finalSignature = base64Encode(signature.bytes); 110 | //print(finalSignature); 111 | 112 | var requestUrl = ""; 113 | 114 | if (containsQueryParams == true) { 115 | //print(url.split("?")[0] + "?" + parameterString + "&oauth_signature=" + Uri.encodeQueryComponent(finalSignature)); 116 | requestUrl = url.split("?")[0] + 117 | "?" + 118 | parameterString + 119 | "&oauth_signature=" + 120 | Uri.encodeQueryComponent(finalSignature); 121 | } else { 122 | //print(url + "?" + parameterString + "&oauth_signature=" + Uri.encodeQueryComponent(finalSignature)); 123 | requestUrl = url + 124 | "?" + 125 | parameterString + 126 | "&oauth_signature=" + 127 | Uri.encodeQueryComponent(finalSignature); 128 | } 129 | 130 | return requestUrl; 131 | } 132 | 133 | 134 | _getOAuthURLForCount(String request_method, String endpoint) { 135 | var consumerKey = this.consumerKey; 136 | var consumerSecret = this.consumerSecret; 137 | 138 | var token = ""; 139 | var token_secret = ""; 140 | var url = this.url + "/wc-api/v3/" + endpoint +"/count"; 141 | var containsQueryParams = url.contains("?"); 142 | 143 | // If website is HTTPS based, no need for OAuth, just return the URL with CS and CK as query params 144 | if(this.isHttps == true){ 145 | return url + (containsQueryParams == true ? "&consumer_key=" + this.consumerKey + "&consumer_secret=" + this.consumerSecret : "?consumer_key=" + this.consumerKey + "&consumer_secret=" + this.consumerSecret); 146 | } 147 | 148 | var rand = new Random(); 149 | var codeUnits = new List.generate(10, (index) { 150 | return rand.nextInt(26) + 97; 151 | }); 152 | 153 | var nonce = new String.fromCharCodes(codeUnits); 154 | int timestamp = (new DateTime.now().millisecondsSinceEpoch / 1000).toInt(); 155 | 156 | //print(timestamp); 157 | //print(nonce); 158 | 159 | var method = request_method; 160 | var path = url.split("?")[0]; 161 | var parameters = "oauth_consumer_key=" + 162 | consumerKey + 163 | "&oauth_nonce=" + 164 | nonce + 165 | "&oauth_signature_method=HMAC-SHA1&oauth_timestamp=" + 166 | timestamp.toString() + 167 | "&oauth_token=" + 168 | token + 169 | "&oauth_version=1.0&"; 170 | 171 | if (containsQueryParams == true) { 172 | parameters = parameters + url.split("?")[1]; 173 | } else { 174 | parameters = parameters.substring(0, parameters.length - 1); 175 | } 176 | 177 | Map params = QueryString.parse(parameters); 178 | Map treeMap = new SplayTreeMap(); 179 | treeMap.addAll(params); 180 | 181 | String parameterString = ""; 182 | 183 | for (var key in treeMap.keys) { 184 | parameterString = parameterString + 185 | Uri.encodeQueryComponent(key) + 186 | "=" + 187 | treeMap[key] + 188 | "&"; 189 | } 190 | 191 | parameterString = parameterString.substring(0, parameterString.length - 1); 192 | 193 | var baseString = method + 194 | "&" + 195 | Uri.encodeQueryComponent( 196 | containsQueryParams == true ? url.split("?")[0] : url) + 197 | "&" + 198 | Uri.encodeQueryComponent(parameterString); 199 | 200 | //print(baseString); 201 | 202 | var signingKey = consumerSecret + "&" + token; 203 | //print(signingKey); 204 | //print(UTF8.encode(signingKey)); 205 | var hmacSha1 = 206 | new crypto.Hmac(crypto.sha1, utf8.encode(signingKey)); // HMAC-SHA1 207 | var signature = hmacSha1.convert(utf8.encode(baseString)); 208 | 209 | //print(signature); 210 | 211 | var finalSignature = base64Encode(signature.bytes); 212 | //print(finalSignature); 213 | 214 | var requestUrl = ""; 215 | 216 | if (containsQueryParams == true) { 217 | //print(url.split("?")[0] + "?" + parameterString + "&oauth_signature=" + Uri.encodeQueryComponent(finalSignature)); 218 | requestUrl = url.split("?")[0] + 219 | "?" + 220 | parameterString + 221 | "&oauth_signature=" + 222 | Uri.encodeQueryComponent(finalSignature); 223 | } else { 224 | //print(url + "?" + parameterString + "&oauth_signature=" + Uri.encodeQueryComponent(finalSignature)); 225 | requestUrl = url + 226 | "?" + 227 | parameterString + 228 | "&oauth_signature=" + 229 | Uri.encodeQueryComponent(finalSignature); 230 | } 231 | 232 | return requestUrl; 233 | } 234 | 235 | Future getAsync(String endPoint) async { 236 | var url = this._getOAuthURL("GET", endPoint); 237 | 238 | final response = await http.get(url); 239 | 240 | return json.decode(response.body); 241 | } 242 | 243 | Future getCountAsync(String endPoint) async { 244 | var url = this._getOAuthURLForCount("GET", endPoint); 245 | 246 | final response = await http.get(url); 247 | 248 | return json.decode(response.body); 249 | } 250 | 251 | Future postAsync(String endPoint, Map data) async { 252 | var url = this._getOAuthURL("POST", endPoint); 253 | var client = new http.Client(); 254 | var request = new http.Request('POST', Uri.parse(url)); 255 | request.headers[HttpHeaders.contentTypeHeader] = 256 | 'application/json; charset=utf-8'; 257 | request.headers[HttpHeaders.cacheControlHeader] = "no-cache"; 258 | request.body = json.encode(data); 259 | var response = 260 | await client.send(request).then((res) => res.stream.bytesToString()); 261 | var dataResponse = await json.decode(response); 262 | return dataResponse; 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:woocommerce_app/screen/splash_screen_page.dart'; 3 | 4 | 5 | void main() => runApp(new MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return new MaterialApp( 11 | debugShowCheckedModeBanner: false, 12 | title: 'Woocom Admin', 13 | theme: new ThemeData( 14 | primarySwatch: Colors.red, 15 | ), 16 | home: SplashScreen(), 17 | ); 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /lib/model/ordered_product.dart: -------------------------------------------------------------------------------- 1 | class OrderProducts { 2 | 3 | OrderProducts( 4 | { this.id, 5 | this.name, 6 | this.imageUrl, 7 | this.mrp, 8 | this.stock, 9 | this.totalCreditValue, 10 | this.orderCount}); 11 | 12 | String id; 13 | String name; 14 | String imageUrl; 15 | String mrp; 16 | int stock; 17 | double totalCreditValue; 18 | int orderCount = 0; 19 | 20 | 21 | factory OrderProducts.fromJson(Map json,int count) { 22 | return OrderProducts( 23 | orderCount:count, 24 | totalCreditValue:0.0, 25 | id: json['id'].toString() as String, 26 | name: json['name'] as String, 27 | imageUrl: json["images"][0]["src"] as String, 28 | mrp: json['price'].toString() as String, 29 | stock: json['stock_quantity'] as int, 30 | 31 | ); 32 | } 33 | 34 | 35 | } -------------------------------------------------------------------------------- /lib/screen/cart_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:woocommerce_app/bloc/cart_page_bloc.dart'; 4 | import 'package:woocommerce_app/helper/hex_color.dart'; 5 | import 'package:woocommerce_app/helper/ui_helper.dart'; 6 | import 'package:woocommerce_app/model/ordered_product.dart'; 7 | 8 | class CartListPage extends StatefulWidget { 9 | List productList = new List(); 10 | 11 | Map customer = new Map(); 12 | 13 | CartListPage(this.productList, this.customer); 14 | 15 | @override 16 | CartListPageState createState() => new CartListPageState(this); 17 | } 18 | 19 | class CartListPageState extends State { 20 | Widget _mainFormWidget; 21 | 22 | BuildContext _context; 23 | 24 | var bloc; 25 | 26 | final _scaffoldKey = GlobalKey(); 27 | 28 | CartListPage parent; 29 | 30 | CartListPageState(this.parent); 31 | 32 | TextEditingController paymentMethodTitle = new TextEditingController(); 33 | 34 | TextEditingController paymentMethod = new TextEditingController(); 35 | 36 | Map payMethodInformation = new Map(); 37 | 38 | @override 39 | void initState() { 40 | super.initState(); 41 | bloc = CartListBloc(parent.productList, parent.customer); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | _context = context; 47 | if (_mainFormWidget == null) { 48 | _mainFormWidget = mainBody(); 49 | } 50 | return _mainFormWidget; // Show the form in the application 51 | } 52 | 53 | Widget mainBody() { 54 | return new Scaffold( 55 | key: _scaffoldKey, 56 | resizeToAvoidBottomInset: true, 57 | bottomNavigationBar: new Container( 58 | height: 45, 59 | child: Row( 60 | children: [ 61 | Expanded( 62 | flex: 5, 63 | child: Center( 64 | child: totalCreditWidget(), 65 | ), 66 | ), 67 | Expanded( 68 | flex: 5, 69 | child: InkWell( 70 | onTap: () { 71 | payMethodInformation['payment_method'] = 72 | paymentMethod.text; 73 | payMethodInformation['payment_method_title'] = 74 | paymentMethodTitle.text; 75 | bloc.createOrder( 76 | _scaffoldKey, _context, payMethodInformation); 77 | }, 78 | child: Container( 79 | color: UIHelper.themeColor, 80 | child: Center( 81 | child: Text('Place Order', 82 | style: TextStyle( 83 | fontWeight: FontWeight.w600, 84 | fontSize: 18, 85 | color: Colors.white)), 86 | )))) 87 | ], 88 | ), 89 | ), 90 | appBar: new AppBar( 91 | iconTheme: IconThemeData( 92 | color: Colors.white, //change your color here 93 | ), 94 | title: new Text("Cart", style: TextStyle(color: Colors.white)), 95 | ), 96 | body: body()); 97 | } 98 | 99 | Widget body() { 100 | return new Column(children: [ 101 | //UIHelper.searchBox(bloc,()=>searchForm()), 102 | 103 | headerDivWidget("Customer"), 104 | 105 | customerDetail(), 106 | 107 | Container( 108 | height: 0.5, 109 | width: MediaQuery.of(context).size.width * 1.0, 110 | color: Colors.grey, 111 | ), 112 | 113 | headerDivWidget("Item Details"), 114 | 115 | OrderedProductListBuild(), 116 | 117 | Container( 118 | height: 0.5, 119 | width: MediaQuery.of(context).size.width * 1.0, 120 | color: Colors.grey, 121 | ), 122 | 123 | 124 | Align( 125 | alignment: Alignment.bottomLeft, 126 | child: new Column( 127 | mainAxisAlignment: MainAxisAlignment.end, 128 | children: [ 129 | headerDivWidget("Payment Method"), 130 | Container( 131 | margin: EdgeInsets.all(5.0), 132 | padding: EdgeInsets.all(5.0), 133 | child: TextField( 134 | controller: paymentMethod, 135 | decoration: new InputDecoration( 136 | hintText: 'Please type payment method', 137 | enabledBorder: UIHelper.borderWeight(), 138 | contentPadding: EdgeInsets.all(15), 139 | ), 140 | )) 141 | ], 142 | )) 143 | ]); 144 | } 145 | 146 | Widget headerDivWidget(String name) { 147 | return Container( 148 | width: MediaQuery.of(context).size.width * 1.0, 149 | //height: 40, 150 | padding: EdgeInsets.all(15), 151 | child: Row( 152 | mainAxisAlignment: MainAxisAlignment.start, 153 | children: [ 154 | Text( 155 | name, 156 | style: TextStyle(color: Colors.grey), 157 | ), 158 | new Container( 159 | width: MediaQuery.of(context).size.width * 0.6, 160 | ), 161 | 162 | 163 | name.contains('Customer') 164 | ? addCustomer() 165 | : new Container() 166 | ], 167 | ), 168 | 169 | decoration: BoxDecoration( 170 | border: Border( 171 | bottom: BorderSide(width: 0.5, color: Colors.grey), 172 | ), 173 | color: HexColor("#FFF8F8"), 174 | ), 175 | ); 176 | } 177 | 178 | /* 179 | * If customer not available during the place order this widget to available to add customer functionality 180 | * */ 181 | 182 | Widget addCustomer() { 183 | return InkWell( 184 | onTap: () { 185 | bloc.routeToCustomerAddPage(_context); 186 | }, 187 | child: Icon(Icons.add_circle, color: Colors.green), 188 | ); 189 | } 190 | 191 | /* 192 | * Function request to the bloc for total ordered product credit and return a widget with total credit value 193 | */ 194 | 195 | Widget totalCreditWidget() { 196 | bloc.fetchTotalCreditValue(); 197 | return StreamBuilder( 198 | stream: bloc.totalCreditValueFetcher.stream, 199 | builder: (context, AsyncSnapshot snapshot) { 200 | return snapshot.hasData 201 | ? Text( 202 | '\$ ' + snapshot.data.toString(), 203 | style: TextStyle( 204 | fontWeight: FontWeight.w600, 205 | fontSize: 18, 206 | color: UIHelper.themeColor), 207 | ) 208 | : Center(child: CircularProgressIndicator()); 209 | }, 210 | ); 211 | } 212 | 213 | /* 214 | * Function check customer is available or not for place a order 215 | * If available return a widget with customer information 216 | * If not available return a widget with waring message 217 | */ 218 | 219 | Widget customerDetail() { 220 | bloc.fetchCustomer(); 221 | return StreamBuilder( 222 | stream: bloc.customerFetcher.stream, 223 | builder: (context, AsyncSnapshot snapshot) { 224 | // print(' ttt '+ snapshot.data.toString()); 225 | return snapshot.hasData 226 | ? customerDetailsView(snapshot) 227 | : Center( 228 | child: Card( 229 | child: Container( 230 | padding: EdgeInsets.all(20), 231 | child: Center( 232 | child: Text('Please add a customer!'), 233 | )))); 234 | }, 235 | ); 236 | } 237 | 238 | /* 239 | * Return a widget with customer details information 240 | */ 241 | 242 | Widget customerDetailsView(AsyncSnapshot s) { 243 | return ListTile( 244 | leading: new Container( 245 | child: new Center( 246 | child: Text( 247 | s.data["email"].substring(0, 1), 248 | style: 249 | TextStyle(color: Colors.white, fontWeight: FontWeight.w600), 250 | ), 251 | ), 252 | width: 40.0, 253 | height: 40.0, 254 | decoration: 255 | new BoxDecoration(shape: BoxShape.circle, color: Colors.red)), 256 | title: Text(s.data["email"]), 257 | subtitle: Text(s.data["shipping"]["address_1"].toString()), 258 | ); 259 | } 260 | 261 | /* 262 | * Function request ordered product list using BLoc 263 | * Return a list widget using Stream builder 264 | */ 265 | 266 | Widget OrderedProductListBuild() { 267 | bloc.fetchOrderedProducts(); 268 | return StreamBuilder( 269 | stream: bloc.allCartProducts, 270 | builder: (context, AsyncSnapshot snapshot) { 271 | // print(' ttt '+ snapshot.data.toString()); 272 | return snapshot.hasData 273 | ? orderedProductListViewWidget(snapshot) 274 | : Center(child: CircularProgressIndicator()); 275 | }, 276 | ); 277 | } 278 | 279 | /* 280 | * Function takes AsyncSnapshot data for build a ListView 281 | * Function return a ListView widget 282 | */ 283 | 284 | Widget orderedProductListViewWidget(AsyncSnapshot s) { 285 | return new Expanded( 286 | child: ListView.builder( 287 | itemCount: s.data.length, 288 | itemBuilder: (_, index) { 289 | OrderProducts product = s.data[index]; 290 | 291 | String productImageUrl = product.imageUrl; 292 | 293 | if (productImageUrl != null && 294 | !productImageUrl.contains('woocommerce-placeholder')) { 295 | productImageUrl = product.imageUrl; 296 | } else { 297 | productImageUrl = null; 298 | } 299 | 300 | return Container( 301 | margin: EdgeInsets.all(6), 302 | child: Card( 303 | child: Column( 304 | children: [ 305 | ListTile( 306 | leading: new Container( 307 | child: productImageUrl != null 308 | ? new Container() 309 | : new Center( 310 | child: Text( 311 | product.name.substring(0, 1), 312 | style: TextStyle( 313 | color: Colors.white, 314 | fontWeight: FontWeight.w600), 315 | ), 316 | ), 317 | width: 40.0, 318 | height: 40.0, 319 | decoration: productImageUrl != null 320 | ? new BoxDecoration( 321 | shape: BoxShape.circle, 322 | image: new DecorationImage( 323 | fit: BoxFit.fill, 324 | image: 325 | new NetworkImage(product.imageUrl))) 326 | : new BoxDecoration( 327 | shape: BoxShape.circle, 328 | color: UIHelper.themeColor)), 329 | title: Text(product.name), 330 | subtitle: Text("MRP : " + 331 | product.mrp.toString() + 332 | " | " + 333 | "Stock : " + 334 | product.stock.toString()), 335 | ), 336 | SizedBox( 337 | height: 15, 338 | ), 339 | new Row( 340 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 341 | children: [ 342 | SizedBox( 343 | width: 30, 344 | ), 345 | IconButton( 346 | onPressed: () { 347 | bloc.orderDelete(product.id.toString()); 348 | }, 349 | icon: Icon( 350 | Icons.delete_outline, 351 | color: Colors.red, 352 | ), 353 | ), 354 | SizedBox( 355 | width: 30, 356 | ), 357 | new Flexible( 358 | child: Container( 359 | width: 60, 360 | child: new Text( 361 | '\$ ' + product.totalCreditValue.toString()), 362 | )), 363 | Spacer(), 364 | Container( 365 | decoration: BoxDecoration( 366 | borderRadius: BorderRadius.circular(5.0), 367 | border: Border.all( 368 | color: UIHelper.themeColor, width: 2)), 369 | width: 122, 370 | height: 40, 371 | child: new Row( 372 | children: [ 373 | Container( 374 | width: 39, 375 | child: Center( 376 | child: IconButton( 377 | icon: Icon(Icons.remove, 378 | color: UIHelper.themeColor), 379 | onPressed: () { 380 | bloc.orderRemove(product.id); 381 | })), 382 | ), 383 | Container( 384 | width: 40, 385 | height: 40, 386 | child: Center( 387 | child: Text( 388 | product.orderCount.toString(), 389 | style: 390 | TextStyle(color: UIHelper.themeColor), 391 | )), 392 | decoration: BoxDecoration( 393 | border: Border( 394 | right: BorderSide( 395 | width: 1.0, 396 | color: UIHelper.themeColor), 397 | left: BorderSide( 398 | width: 1.0, 399 | color: UIHelper.themeColor), 400 | ), 401 | color: Colors.white, 402 | ), 403 | ), 404 | Container( 405 | width: 39, 406 | child: Center( 407 | child: IconButton( 408 | icon: Icon(Icons.add, 409 | color: UIHelper.themeColor), 410 | onPressed: () { 411 | bloc.orderAdd(product.id); 412 | })), 413 | ), 414 | ], 415 | ), 416 | ), 417 | SizedBox( 418 | width: 10, 419 | ), 420 | ], 421 | ), 422 | SizedBox( 423 | height: 20, 424 | ) 425 | ], 426 | ))); 427 | })); 428 | } 429 | } 430 | -------------------------------------------------------------------------------- /lib/screen/customer_add.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:woocommerce_app/bloc/customer_add_bloc.dart'; 3 | import 'package:woocommerce_app/helper/hex_color.dart'; 4 | 5 | class CustomerAddPage extends StatefulWidget { 6 | @override 7 | _CustomerAddPageState createState() => _CustomerAddPageState(); 8 | } 9 | 10 | class _CustomerAddPageState extends State { 11 | // _formKey and _autoValidate 12 | final GlobalKey _formKey = GlobalKey(); 13 | 14 | final _scaffoldKey = GlobalKey(); 15 | 16 | bool _autoValidate = false; 17 | 18 | Map customerBasicInformation = new Map(); 19 | 20 | Map customerAddressInformation = new Map(); 21 | 22 | var bloc; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | bloc = CustomerAddBloc(); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return new Scaffold( 33 | key: _scaffoldKey, 34 | appBar: new AppBar( 35 | title: new Text('New Customer'), 36 | actions: [ 37 | IconButton( 38 | icon: Icon( 39 | Icons.check, 40 | color: Colors.white, 41 | size: 36, 42 | ), 43 | onPressed: () { 44 | _validateInputs(); 45 | }, 46 | ) 47 | ], 48 | ), 49 | body: new SingleChildScrollView( 50 | child: new Container( 51 | margin: new EdgeInsets.all(0.0), 52 | child: body(), 53 | ), 54 | ), 55 | ); 56 | } 57 | 58 | Widget body() { 59 | return new Form( 60 | key: _formKey, 61 | autovalidateMode: AutovalidateMode.onUserInteraction, 62 | child: Column(children: [ 63 | headerDivWidget('Basic Information'), 64 | new Container( 65 | padding: EdgeInsets.all(20.0), 66 | child: customerBasicInformationUI()), 67 | headerDivWidget('Address Information'), 68 | Container( 69 | padding: EdgeInsets.all(20.0), 70 | child: customerAddressInformationUI()), 71 | ])); 72 | } 73 | 74 | Widget headerDivWidget(String heaterText) { 75 | return Container( 76 | width: MediaQuery.of(context).size.width * 1.0, 77 | //height: 40, 78 | padding: EdgeInsets.all(15), 79 | child: Text( 80 | heaterText, 81 | style: TextStyle(color: Colors.black, fontWeight: FontWeight.w600), 82 | ), 83 | decoration: BoxDecoration( 84 | border: Border( 85 | bottom: BorderSide(width: 0.5, color: Colors.grey), 86 | ), 87 | color: HexColor("#FFF8F8"), 88 | ), 89 | ); 90 | } 91 | 92 | // Here is our Form UI 93 | Widget customerBasicInformationUI() { 94 | return new Column( 95 | children: [ 96 | new TextFormField( 97 | decoration: const InputDecoration(labelText: 'Firstname'), 98 | keyboardType: TextInputType.text, 99 | validator: validateName, 100 | onSaved: (String val) { 101 | if (val != null) 102 | customerBasicInformation['firstName'] = val; 103 | else 104 | customerBasicInformation['firstName'] = ''; 105 | }, 106 | ), 107 | new TextFormField( 108 | decoration: const InputDecoration(labelText: 'Lastname'), 109 | keyboardType: TextInputType.text, 110 | onSaved: (String val) { 111 | if (val != null) 112 | customerBasicInformation['lastName'] = val; 113 | else 114 | customerBasicInformation['lastName'] = ''; 115 | }, 116 | ), 117 | new TextFormField( 118 | decoration: const InputDecoration(labelText: 'Username'), 119 | keyboardType: TextInputType.text, 120 | onSaved: (String val) { 121 | if (val != null) 122 | customerBasicInformation['userName'] = val; 123 | else 124 | customerBasicInformation['userName'] = ''; 125 | }, 126 | ), 127 | new TextFormField( 128 | decoration: const InputDecoration(labelText: 'Email'), 129 | keyboardType: TextInputType.emailAddress, 130 | validator: validateEmail, 131 | onSaved: (String val) { 132 | if (val != null) { 133 | customerBasicInformation['email'] = val; 134 | customerAddressInformation['email'] = val; 135 | } 136 | }, 137 | ), 138 | new SizedBox( 139 | height: 10.0, 140 | ), 141 | ], 142 | ); 143 | } 144 | 145 | Widget customerAddressInformationUI() { 146 | return new Column( 147 | children: [ 148 | new TextFormField( 149 | decoration: const InputDecoration(labelText: 'Firstname'), 150 | keyboardType: TextInputType.text, 151 | validator: validateName, 152 | onSaved: (String val) { 153 | if (val != null) 154 | customerAddressInformation['first_name'] = val; 155 | else 156 | customerAddressInformation['first_name'] = ''; 157 | }, 158 | ), 159 | new TextFormField( 160 | decoration: const InputDecoration(labelText: 'Lastname'), 161 | keyboardType: TextInputType.text, 162 | onSaved: (String val) { 163 | if (val != null) 164 | customerAddressInformation['last_name'] = val; 165 | else 166 | customerAddressInformation['last_name'] = ''; 167 | }, 168 | ), 169 | new TextFormField( 170 | decoration: const InputDecoration(labelText: 'Phone'), 171 | keyboardType: TextInputType.phone, 172 | onSaved: (String val) { 173 | if (val != null) 174 | customerBasicInformation['phone'] = val; 175 | else 176 | customerBasicInformation['phone'] = ''; 177 | }, 178 | ), 179 | new TextFormField( 180 | decoration: const InputDecoration(labelText: 'Company'), 181 | keyboardType: TextInputType.text, 182 | onSaved: (String val) { 183 | if (val != null) 184 | customerAddressInformation['Company'] = val; 185 | else 186 | customerAddressInformation['Company'] = ''; 187 | }, 188 | ), 189 | new TextFormField( 190 | decoration: const InputDecoration(labelText: 'Address Line'), 191 | keyboardType: TextInputType.text, 192 | validator: validateName, 193 | onSaved: (String val) { 194 | if (val != null) 195 | customerAddressInformation['address_1'] = val; 196 | else 197 | customerAddressInformation['address_1'] = ''; 198 | }, 199 | ), 200 | new TextFormField( 201 | decoration: const InputDecoration(labelText: 'City'), 202 | keyboardType: TextInputType.text, 203 | onSaved: (String val) { 204 | if (val != null) 205 | customerAddressInformation['city'] = val; 206 | else 207 | customerAddressInformation['city'] = ''; 208 | }, 209 | ), 210 | new TextFormField( 211 | decoration: const InputDecoration(labelText: 'State'), 212 | keyboardType: TextInputType.text, 213 | onSaved: (String val) { 214 | if (val != null) 215 | customerAddressInformation['state'] = val; 216 | else 217 | customerAddressInformation['state'] = ''; 218 | }, 219 | ), 220 | new TextFormField( 221 | decoration: const InputDecoration(labelText: 'Postcode'), 222 | keyboardType: TextInputType.text, 223 | onSaved: (String val) { 224 | if (val != null) 225 | customerAddressInformation['postcode'] = val; 226 | else 227 | customerAddressInformation['postcode'] = ''; 228 | }, 229 | ), 230 | new TextFormField( 231 | decoration: const InputDecoration(labelText: 'Country'), 232 | keyboardType: TextInputType.text, 233 | onSaved: (String val) { 234 | if (val != null) 235 | customerAddressInformation['country'] = val; 236 | else 237 | customerAddressInformation['country'] = ''; 238 | }, 239 | ), 240 | new SizedBox( 241 | height: 10.0, 242 | ), 243 | ], 244 | ); 245 | } 246 | 247 | String validateName(String value) { 248 | if (value.length < 1) 249 | return 'Field can not be empty'; 250 | else if (value.length < 3) 251 | return 'Enter a valid value'; 252 | else 253 | return null; 254 | } 255 | 256 | String validateEmail(String value) { 257 | Pattern pattern = 258 | r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; 259 | RegExp regex = new RegExp(pattern); 260 | if (!regex.hasMatch(value)) 261 | return 'Enter Valid Email'; 262 | else 263 | return null; 264 | } 265 | 266 | void _validateInputs() { 267 | if (_formKey.currentState.validate()) { 268 | //If all data are correct then save data to out variables 269 | _formKey.currentState.save(); 270 | 271 | // After save data to variable a http request to create a new customer 272 | bloc.createCustomer(customerBasicInformation, customerAddressInformation, 273 | _scaffoldKey, context); 274 | } else { 275 | //If all data are not valid then start auto validation. 276 | setState(() { 277 | _autoValidate = true; 278 | }); 279 | } 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /lib/screen/cutomer_list_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:woocommerce_app/bloc/customer_list_bloc.dart'; 4 | import 'package:woocommerce_app/helper/const.dart'; 5 | 6 | class CustomerListPage extends StatefulWidget { 7 | @override 8 | CustomerListPageState createState() => new CustomerListPageState(); 9 | } 10 | 11 | class CustomerListPageState extends State { 12 | Widget _mainFormWidget; // Save the form 13 | 14 | var bloc; // Associate bloc 15 | 16 | BuildContext _context; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | bloc = CustomerListBloc(); 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | _context = context; 27 | 28 | if (_mainFormWidget == null) { 29 | _mainFormWidget = mainBody(); 30 | } 31 | 32 | return _mainFormWidget; // Show the form in the application 33 | } 34 | 35 | Widget mainBody() { 36 | return new Scaffold( 37 | resizeToAvoidBottomInset: true, 38 | floatingActionButton: FloatingActionButton( 39 | onPressed: () { 40 | bloc.routeToCustomerAddPage(_context); 41 | }, 42 | child: Icon(Icons.people), 43 | backgroundColor: Colors.green, 44 | ), 45 | appBar: new AppBar( 46 | iconTheme: IconThemeData( 47 | color: Colors.white, //change your color here 48 | ), 49 | title: new Text("Customers", style: TextStyle(color: Colors.white)), 50 | ), 51 | body: body()); 52 | } 53 | 54 | Widget body() { 55 | return new Column(children: [ 56 | // Search Box Widget 57 | 58 | Container( 59 | height: 50, 60 | child: new Card( 61 | child: new Row( 62 | children: [ 63 | new Expanded( 64 | child: new TextField( 65 | decoration: new InputDecoration( 66 | contentPadding: EdgeInsets.fromLTRB(10.0, 15.0, 20.0, 15.0), 67 | prefixIcon: Icon(Icons.search), 68 | hintText: ' Search', 69 | border: InputBorder.none), 70 | onChanged: bloc.onSearchTextChanged, 71 | )), 72 | ], 73 | )), 74 | ), 75 | 76 | // Customer List Widget 77 | 78 | customerListBuild() 79 | ]); 80 | } 81 | 82 | /* 83 | * Function perform a http request using BLoc for all customer list 84 | * Return a list widget using Stream builder 85 | */ 86 | 87 | Widget customerListBuild() { 88 | bloc.fetchCustomers(''); 89 | return StreamBuilder( 90 | stream: bloc.allCustomers, 91 | builder: (context, AsyncSnapshot snapshot) { 92 | return snapshot.hasData 93 | ? customerListViewWidget(snapshot) 94 | : Align( 95 | alignment: Alignment.center, 96 | child: CircularProgressIndicator()); 97 | }, 98 | ); 99 | } 100 | 101 | 102 | /* 103 | * Function takes AsyncSnapshot data for build a ListView 104 | * Function return a ListView widget 105 | */ 106 | 107 | Widget customerListViewWidget(AsyncSnapshot snapshot) { 108 | return new Expanded( 109 | child: ListView.builder( 110 | itemCount: snapshot.data.length, 111 | itemBuilder: (_, index) { 112 | return InkWell( 113 | onTap: () { 114 | bloc.routeToPlaceOrderPage(_context, snapshot.data[index]); 115 | }, 116 | child: Container( 117 | margin: EdgeInsets.all(6), 118 | child: Card( 119 | child: Column( 120 | children: [ 121 | ListTile( 122 | trailing: IconButton( 123 | icon: Icon( 124 | Icons.arrow_forward_ios, 125 | size: 18, 126 | ), 127 | onPressed: () { 128 | bloc.routeToPlaceOrderPage( 129 | _context, snapshot.data[index]); 130 | }), 131 | leading: new Container( 132 | child: new Center( 133 | child: Text( 134 | snapshot.data[index]["email"].substring(0, 1), 135 | style: TextStyle( 136 | color: Colors.white, 137 | fontWeight: FontWeight.w600), 138 | ), 139 | ), 140 | width: 40.0, 141 | height: 40.0, 142 | decoration: new BoxDecoration( 143 | shape: BoxShape.circle, color: Colors.red)), 144 | title: Text(snapshot.data[index]["email"], 145 | style: TextStyle( 146 | fontSize: 14, 147 | fontWeight: FontWeight.w500, 148 | color: Colors.black)), 149 | subtitle: Text( 150 | snapshot.data[index]["shipping"]["address_1"] 151 | .toString(), 152 | style: TextStyle( 153 | fontSize: 12, 154 | fontWeight: FontWeight.w400, 155 | color: Colors.grey)), 156 | ), 157 | ], 158 | )))); 159 | })); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /lib/screen/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:woocommerce_app/bloc/home_page_bloc.dart'; 6 | import 'package:woocommerce_app/helper/const.dart'; 7 | import 'package:woocommerce_app/helper/hex_color.dart'; 8 | import 'package:woocommerce_app/screen/cutomer_list_page.dart'; 9 | import 'package:http/http.dart' as http; 10 | import 'package:woocommerce_app/screen/my_profile_page.dart'; 11 | import 'package:woocommerce_app/screen/order_list_page.dart'; 12 | import 'package:woocommerce_app/screen/place_order_page.dart'; 13 | import 'package:woocommerce_app/helper/ui_helper.dart'; 14 | 15 | 16 | class HomePage extends StatefulWidget { 17 | @override 18 | HomePagePageState createState() => new HomePagePageState(); 19 | } 20 | 21 | class HomePagePageState extends State { 22 | 23 | var bloc; 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | bloc = HomePageBloc(); 29 | 30 | // Function call for sales status report 31 | bloc.fetchSalesReports(); 32 | 33 | } 34 | 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | return new Scaffold( 39 | floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, 40 | appBar: new AppBar( 41 | iconTheme: IconThemeData( 42 | color: Colors.white, //change your color here 43 | ), 44 | title: new Text("Woocom Admin", style: TextStyle(color: Colors.white)), 45 | ), 46 | persistentFooterButtons: [ 47 | Text('Version 1.0.0'), 48 | ], 49 | drawer: Drawer( 50 | child: ListView( 51 | padding: EdgeInsets.zero, 52 | children: [ 53 | DrawerHeader( 54 | child: Column( 55 | mainAxisSize: MainAxisSize.min, 56 | mainAxisAlignment: MainAxisAlignment.center, 57 | children: [ 58 | CircleAvatar( 59 | backgroundColor: Colors.white, 60 | radius: 40.0, 61 | child: Image.asset('images/woocom_icon.jpg'), 62 | ), 63 | SizedBox(height: 20,), 64 | Text("Welcome to Woocom Admin", 65 | style: TextStyle(color: Colors.white),), 66 | SizedBox(height: 10,), 67 | ], 68 | ), 69 | decoration: BoxDecoration( 70 | color: Colors.red, 71 | ), 72 | ), 73 | 74 | ListTile( 75 | leading: Icon(Icons.library_add), 76 | title: Text('New Order'), 77 | onTap: () { 78 | 79 | // Route to Order Add Page 80 | 81 | Navigator.push( 82 | context, 83 | MaterialPageRoute( 84 | builder: (context) => 85 | PlaceOrderPage(null))); 86 | // Navigator.pop(context); 87 | }, 88 | ), 89 | 90 | ListTile( 91 | leading: Icon(Icons.border_all), 92 | title: Text('My Order'), 93 | onTap: () { 94 | 95 | // Route to Order List Page 96 | 97 | Navigator.push( 98 | context, 99 | MaterialPageRoute( 100 | builder: (context) => 101 | OrderListPage())); 102 | 103 | }, 104 | ), 105 | 106 | ListTile( 107 | leading: Icon(Icons.account_circle), 108 | title: Text('My Profile'), 109 | onTap: () { 110 | Navigator.push( 111 | context, 112 | MaterialPageRoute( 113 | builder: (context) => 114 | UserProfilePage())); 115 | // Navigator.pop(context); 116 | }, 117 | ), 118 | 119 | 120 | ], 121 | ), 122 | ), 123 | body: new Container( 124 | 125 | color: HexColor("#FFF8F8"), 126 | 127 | child: Column( 128 | 129 | children: [ 130 | 131 | 132 | Container( 133 | 134 | color: Colors.transparent, 135 | 136 | height: MediaQuery 137 | .of(context) 138 | .size 139 | .height * 0.35, 140 | 141 | 142 | child: Row( 143 | 144 | 145 | children: [ 146 | 147 | Expanded( 148 | 149 | child: Container( 150 | 151 | margin: EdgeInsets.only( 152 | left: 20, top: 30, bottom: 30, right: 15), 153 | 154 | 155 | child: InkWell( 156 | onTap: () { 157 | 158 | // Route to Customer List Page 159 | 160 | Navigator.push( 161 | context, 162 | MaterialPageRoute( 163 | builder: (context) => 164 | CustomerListPage())); 165 | }, 166 | child: Card( 167 | 168 | child: Center( 169 | 170 | 171 | child: Column( 172 | 173 | mainAxisAlignment: MainAxisAlignment 174 | .center, 175 | mainAxisSize: MainAxisSize.max, 176 | 177 | children: [ 178 | 179 | Icon( 180 | Icons.people, 181 | color: UIHelper.themeColor, 182 | size: 40, 183 | ), 184 | 185 | Container(height: 10,), 186 | 187 | Text('Customers',style: TextStyle( 188 | color: Colors.black, 189 | fontWeight: FontWeight.w400, 190 | fontSize: 14 191 | )) 192 | 193 | ] 194 | 195 | ) 196 | 197 | 198 | ), 199 | )), 200 | ) 201 | 202 | 203 | ), 204 | 205 | Expanded( 206 | 207 | child: Container( 208 | 209 | margin: EdgeInsets.only( 210 | left: 15, top: 30, bottom: 30, right: 20), 211 | 212 | 213 | child: InkWell( 214 | onTap: () { 215 | 216 | // Route to Order List Page 217 | 218 | Navigator.push( 219 | context, 220 | MaterialPageRoute( 221 | builder: (context) => 222 | OrderListPage())); 223 | }, 224 | child: Card( 225 | 226 | child: Center( 227 | 228 | 229 | child: Column( 230 | 231 | mainAxisAlignment: MainAxisAlignment 232 | .center, 233 | mainAxisSize: MainAxisSize.max, 234 | 235 | children: [ 236 | 237 | Icon( 238 | Icons.assignment, 239 | color: UIHelper.themeColor, 240 | size: 40, 241 | ), 242 | 243 | Container(height: 10,), 244 | 245 | Text('Orders',style: TextStyle( 246 | color: Colors.black, 247 | fontWeight: FontWeight.w400, 248 | fontSize: 14 249 | )) 250 | 251 | ] 252 | 253 | ) 254 | 255 | 256 | ), 257 | )), 258 | ) 259 | 260 | 261 | ) 262 | 263 | 264 | ], 265 | 266 | 267 | ) 268 | 269 | ), 270 | 271 | Container( 272 | 273 | 274 | height: MediaQuery 275 | .of(context) 276 | .size 277 | .height * 0.45, 278 | 279 | child: Container( 280 | 281 | 282 | margin: EdgeInsets.all(20.0), 283 | 284 | child: Card( 285 | 286 | 287 | elevation: 2, 288 | child: ClipPath( 289 | 290 | clipper: ShapeBorderClipper( 291 | shape: RoundedRectangleBorder( 292 | borderRadius: BorderRadius.circular(3))), 293 | 294 | child: Container( 295 | 296 | decoration: BoxDecoration( 297 | border: Border(top: BorderSide( 298 | color: Colors.red, width: 5))), 299 | 300 | child: Container( 301 | 302 | 303 | margin: EdgeInsets.all(20.0), 304 | 305 | child: 306 | 307 | Column( 308 | 309 | children: [ 310 | 311 | 312 | Flexible( 313 | 314 | flex: 5, 315 | 316 | child: new Row( 317 | 318 | children: [ 319 | 320 | 321 | Flexible( 322 | 323 | flex: 3, 324 | child: new Center( 325 | 326 | child: Column( 327 | 328 | mainAxisAlignment: MainAxisAlignment 329 | .center, 330 | mainAxisSize: MainAxisSize 331 | .max, 332 | 333 | children: < 334 | Widget>[ 335 | 336 | totalCountPerModuleWidget( 337 | 'customers'), 338 | 339 | Container( 340 | height: 5,), 341 | 342 | Text( 343 | 'Customer', 344 | style: UIHelper.getTextStyleForHomeScreenItem(),) 345 | 346 | ] 347 | 348 | ) 349 | 350 | )), 351 | 352 | 353 | new Container( 354 | color: Colors.grey, 355 | width: .5, height: 40,), 356 | 357 | Flexible( 358 | 359 | flex: 3, 360 | child: new Container( 361 | 362 | child: Column( 363 | 364 | mainAxisAlignment: MainAxisAlignment 365 | .center, 366 | mainAxisSize: MainAxisSize 367 | .max, 368 | 369 | children: < 370 | Widget>[ 371 | 372 | totalCountPerModuleWidget( 373 | 'products'), 374 | 375 | Container( 376 | height: 5,), 377 | 378 | Text( 379 | 'Products', 380 | style: UIHelper.getTextStyleForHomeScreenItem()) 381 | 382 | ] 383 | 384 | ) 385 | 386 | )), 387 | 388 | new Container( 389 | color: Colors.grey, 390 | width: .5, height: 40,), 391 | Flexible( 392 | 393 | flex: 3, 394 | child: new Container( 395 | child: Column( 396 | 397 | mainAxisAlignment: MainAxisAlignment 398 | .center, 399 | mainAxisSize: MainAxisSize 400 | .max, 401 | 402 | children: < 403 | Widget>[ 404 | 405 | totalCountPerModuleWidget( 406 | 'orders'), 407 | 408 | Container( 409 | height: 5,), 410 | 411 | Text('Orders', 412 | style: UIHelper.getTextStyleForHomeScreenItem(),) 413 | 414 | ] 415 | 416 | ))), 417 | 418 | 419 | ] 420 | )), 421 | 422 | 423 | new Container( 424 | height: .5, color: Colors.grey,), 425 | 426 | 427 | Flexible( 428 | 429 | flex: 5, 430 | 431 | child: new Row( 432 | 433 | children: [ 434 | 435 | 436 | Flexible( 437 | 438 | flex: 3, 439 | child: new Center( 440 | 441 | child: Column( 442 | 443 | mainAxisAlignment: MainAxisAlignment 444 | .center, 445 | mainAxisSize: MainAxisSize 446 | .max, 447 | 448 | children: < 449 | Widget>[ 450 | 451 | salesValueReportBySalesType('average'), 452 | 453 | Container( 454 | height: 5,), 455 | 456 | Text( 457 | 'Avg sales', 458 | style: UIHelper.getTextStyleForHomeScreenItem()) 459 | 460 | ] 461 | 462 | ) 463 | 464 | )), 465 | 466 | 467 | new Container( 468 | color: Colors.grey, 469 | width: .5, height: 40,), 470 | 471 | Flexible( 472 | 473 | flex: 3, 474 | child: new Container( 475 | 476 | child: Column( 477 | 478 | mainAxisAlignment: MainAxisAlignment 479 | .center, 480 | mainAxisSize: MainAxisSize 481 | .max, 482 | 483 | children: < 484 | Widget>[ 485 | 486 | salesValueReportBySalesType('net'), 487 | 488 | Container( 489 | height: 5,), 490 | 491 | Text( 492 | 'Net sales', 493 | style: UIHelper.getTextStyleForHomeScreenItem()) 494 | 495 | ] 496 | 497 | ) 498 | 499 | )), 500 | 501 | new Container( 502 | color: Colors.grey, 503 | width: .5, height: 40,), 504 | Flexible( 505 | 506 | flex: 3, 507 | child: new Container( 508 | child: Column( 509 | 510 | mainAxisAlignment: MainAxisAlignment 511 | .center, 512 | mainAxisSize: MainAxisSize 513 | .max, 514 | 515 | children: < 516 | Widget>[ 517 | 518 | salesValueReportBySalesType('total'), 519 | 520 | Container( 521 | height: 5,), 522 | 523 | Text( 524 | 'Total sales', 525 | style: UIHelper.getTextStyleForHomeScreenItem()) 526 | 527 | ] 528 | 529 | ))), 530 | 531 | 532 | ] 533 | )), 534 | 535 | 536 | ], 537 | 538 | 539 | ) 540 | 541 | 542 | ))), 543 | 544 | 545 | ) 546 | 547 | 548 | ) 549 | 550 | 551 | ) 552 | ], 553 | 554 | ) 555 | 556 | 557 | ) 558 | ); 559 | } 560 | 561 | /* 562 | * This function takes input module name 563 | * Perform a http request 564 | * return the total count of module 565 | * Set the count value in Text Widget 566 | * return a Widget 567 | */ 568 | 569 | 570 | Widget totalCountPerModuleWidget(String moduleName ) { 571 | 572 | bloc.fetchPerModuleCount(moduleName); 573 | 574 | Stream stream ; 575 | 576 | if(moduleName=='customers') 577 | { 578 | stream = bloc.customerCountFetcher.stream; 579 | } 580 | else if(moduleName=='products') 581 | { 582 | stream = bloc.productCountFetcher.stream; 583 | } 584 | else if(moduleName=='orders') 585 | { 586 | stream = bloc.orderCountFetcher.stream; 587 | } 588 | 589 | 590 | return StreamBuilder( 591 | stream: stream, 592 | builder: (context, AsyncSnapshot snapshot) { 593 | return snapshot.hasData 594 | ? new Container( 595 | child: Text(snapshot.data.toString(),style: TextStyle(color: UIHelper.themeColor,fontWeight: FontWeight.w600,fontSize: 14))) 596 | : new Container( 597 | height: 20, 598 | width: 20, 599 | child:CircularProgressIndicator(strokeWidth: 2,)); 600 | }, 601 | ); 602 | } 603 | 604 | Widget salesValueReportBySalesType(String salesType ) { 605 | 606 | Stream stream ; 607 | 608 | if(salesType=='average') 609 | { 610 | stream = bloc.averageSalesValueFetcher.stream; 611 | } 612 | else if(salesType=='net') 613 | { 614 | stream = bloc.netSalesValueFetcher.stream; 615 | } 616 | else if(salesType=='total') 617 | { 618 | stream = bloc.totalSalesValueFetcher.stream; 619 | } 620 | 621 | return StreamBuilder( 622 | stream: stream, 623 | builder: (context, AsyncSnapshot snapshot) { 624 | return snapshot.hasData 625 | ? new Container( 626 | child: Text('\$ '+snapshot.data.toString(),style: TextStyle(color: UIHelper.themeColor))) 627 | : new Container( 628 | height: 20, 629 | width: 20, 630 | child:CircularProgressIndicator(strokeWidth: 2,)); 631 | }, 632 | ); 633 | } 634 | 635 | 636 | } 637 | -------------------------------------------------------------------------------- /lib/screen/my_profile_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class UserProfilePage extends StatelessWidget { 4 | final String _fullName = "Shahanaj Parvin"; 5 | final String _status = "Software Developer"; 6 | final String _bio = 7 | "\"Hi, I am a Freelance developer working for hourly basis. If you wants to contact me to build your product leave a message.\""; 8 | final String _followers = "173"; 9 | final String _posts = "24"; 10 | final String _scores = "450"; 11 | 12 | Widget _buildCoverImage(Size screenSize) { 13 | return Container( 14 | height: screenSize.height / 2.6, 15 | decoration: BoxDecoration( 16 | image: DecorationImage( 17 | image: AssetImage('images/cover_photo.jpg'), 18 | fit: BoxFit.cover, 19 | ), 20 | ), 21 | ); 22 | } 23 | 24 | Widget _buildProfileImage() { 25 | return Center( 26 | child: Container( 27 | width: 120.0, 28 | height: 120.0, 29 | decoration: BoxDecoration( 30 | image: DecorationImage( 31 | image: AssetImage('images/woocom_icon.jpg'), 32 | fit: BoxFit.cover, 33 | ), 34 | borderRadius: BorderRadius.circular(80.0), 35 | border: Border.all( 36 | color: Colors.white, 37 | width: 5.0, 38 | ), 39 | ), 40 | ), 41 | ); 42 | } 43 | 44 | Widget _buildFullName() { 45 | TextStyle _nameTextStyle = TextStyle( 46 | fontFamily: 'Roboto', 47 | color: Colors.black, 48 | fontSize: 28.0, 49 | fontWeight: FontWeight.w700, 50 | ); 51 | 52 | return Text( 53 | _fullName, 54 | style: _nameTextStyle, 55 | ); 56 | } 57 | 58 | Widget _buildStatus(BuildContext context) { 59 | return Container( 60 | padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 6.0), 61 | decoration: BoxDecoration( 62 | color: Theme.of(context).scaffoldBackgroundColor, 63 | borderRadius: BorderRadius.circular(4.0), 64 | ), 65 | child: Text( 66 | _status, 67 | style: TextStyle( 68 | fontFamily: 'Spectral', 69 | color: Colors.black, 70 | fontSize: 20.0, 71 | fontWeight: FontWeight.w300, 72 | ), 73 | ), 74 | ); 75 | } 76 | 77 | Widget _buildStatItem(String label, String count) { 78 | TextStyle _statLabelTextStyle = TextStyle( 79 | fontFamily: 'Roboto', 80 | color: Colors.black, 81 | fontSize: 16.0, 82 | fontWeight: FontWeight.w200, 83 | ); 84 | 85 | TextStyle _statCountTextStyle = TextStyle( 86 | color: Colors.black54, 87 | fontSize: 24.0, 88 | fontWeight: FontWeight.bold, 89 | ); 90 | 91 | return Column( 92 | mainAxisAlignment: MainAxisAlignment.center, 93 | children: [ 94 | Text( 95 | count, 96 | style: _statCountTextStyle, 97 | ), 98 | Text( 99 | label, 100 | style: _statLabelTextStyle, 101 | ), 102 | ], 103 | ); 104 | } 105 | 106 | Widget _buildStatContainer() { 107 | return Container( 108 | height: 60.0, 109 | margin: EdgeInsets.only(top: 8.0), 110 | decoration: BoxDecoration( 111 | color: Color(0xFFEFF4F7), 112 | ), 113 | child: Row( 114 | mainAxisAlignment: MainAxisAlignment.spaceAround, 115 | children: [ 116 | _buildStatItem("Followers", _followers), 117 | _buildStatItem("Posts", _posts), 118 | _buildStatItem("Scores", _scores), 119 | ], 120 | ), 121 | ); 122 | } 123 | 124 | Widget _buildBio(BuildContext context) { 125 | TextStyle bioTextStyle = TextStyle( 126 | fontFamily: 'Spectral', 127 | fontWeight: FontWeight.w400,//try changing weight to w500 if not thin 128 | fontStyle: FontStyle.italic, 129 | color: Color(0xFF799497), 130 | fontSize: 16.0, 131 | ); 132 | 133 | return Container( 134 | color: Theme.of(context).scaffoldBackgroundColor, 135 | padding: EdgeInsets.all(8.0), 136 | child: Text( 137 | _bio, 138 | textAlign: TextAlign.center, 139 | style: bioTextStyle, 140 | ), 141 | ); 142 | } 143 | 144 | Widget _buildSeparator(Size screenSize) { 145 | return Container( 146 | width: screenSize.width / 1.6, 147 | height: 2.0, 148 | color: Colors.black54, 149 | margin: EdgeInsets.only(top: 4.0), 150 | ); 151 | } 152 | 153 | Widget _buildGetInTouch(BuildContext context) { 154 | return Container( 155 | color: Theme.of(context).scaffoldBackgroundColor, 156 | padding: EdgeInsets.only(top: 8.0), 157 | child: Text( 158 | "Get in Touch with ${_fullName.split(" ")[0]},", 159 | style: TextStyle(fontFamily: 'Roboto', fontSize: 16.0), 160 | ), 161 | ); 162 | } 163 | 164 | Widget _buildButtons() { 165 | return Padding( 166 | padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), 167 | child: Row( 168 | children: [ 169 | Expanded( 170 | child: InkWell( 171 | onTap: () => print("followed"), 172 | child: Container( 173 | height: 40.0, 174 | decoration: BoxDecoration( 175 | border: Border.all(), 176 | color: Color(0xFF404A5C), 177 | ), 178 | child: Center( 179 | child: Text( 180 | "FOLLOW", 181 | style: TextStyle( 182 | color: Colors.white, 183 | fontWeight: FontWeight.w600, 184 | ), 185 | ), 186 | ), 187 | ), 188 | ), 189 | ), 190 | SizedBox(width: 10.0), 191 | Expanded( 192 | child: InkWell( 193 | onTap: () => print("Message"), 194 | child: Container( 195 | height: 40.0, 196 | decoration: BoxDecoration( 197 | border: Border.all(), 198 | ), 199 | child: Center( 200 | child: Padding( 201 | padding: EdgeInsets.all(10.0), 202 | child: Text( 203 | "MESSAGE", 204 | style: TextStyle(fontWeight: FontWeight.w600), 205 | ), 206 | ), 207 | ), 208 | ), 209 | ), 210 | ), 211 | ], 212 | ), 213 | ); 214 | } 215 | 216 | @override 217 | Widget build(BuildContext context) { 218 | Size screenSize = MediaQuery.of(context).size; 219 | return Scaffold( 220 | body: Stack( 221 | children: [ 222 | _buildCoverImage(screenSize), 223 | SafeArea( 224 | child: SingleChildScrollView( 225 | child: Column( 226 | children: [ 227 | SizedBox(height: screenSize.height / 4), 228 | _buildProfileImage(), 229 | SizedBox(height: 20,), 230 | _buildFullName(), 231 | SizedBox(height: 10,), 232 | _buildStatus(context), 233 | SizedBox(height: 15,), 234 | _buildStatContainer(), 235 | _buildBio(context), 236 | _buildSeparator(screenSize), 237 | SizedBox(height: 10.0), 238 | _buildGetInTouch(context), 239 | SizedBox(height: 8.0), 240 | _buildButtons(), 241 | ], 242 | ), 243 | ), 244 | ), 245 | ], 246 | ), 247 | ); 248 | } 249 | } -------------------------------------------------------------------------------- /lib/screen/order_list_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:woocommerce_app/bloc/customer_list_bloc.dart'; 4 | import 'package:woocommerce_app/bloc/order_list_bloc.dart'; 5 | import 'package:woocommerce_app/helper/const.dart'; 6 | 7 | class OrderListPage extends StatefulWidget { 8 | @override 9 | OrderListPageState createState() => new OrderListPageState(); 10 | } 11 | 12 | class OrderListPageState extends State { 13 | 14 | 15 | Widget _mainFormWidget; 16 | 17 | var bloc; 18 | 19 | BuildContext _context; 20 | 21 | @override 22 | void initState() { 23 | super.initState(); 24 | bloc = OrderListBloc(); 25 | } 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | _context = context; 30 | 31 | if (_mainFormWidget == null) { 32 | _mainFormWidget = mainBody(); 33 | } 34 | return _mainFormWidget; // Show the form in the application 35 | } 36 | 37 | Widget mainBody() { 38 | return new Scaffold( 39 | resizeToAvoidBottomInset: true, 40 | floatingActionButton: FloatingActionButton( 41 | onPressed: () { 42 | bloc.routeToNewOrderPage(_context); 43 | }, 44 | child: Icon( 45 | Icons.note_add, 46 | color: Colors.white, 47 | ), 48 | backgroundColor: Colors.green, 49 | ), 50 | appBar: new AppBar( 51 | iconTheme: IconThemeData( 52 | color: Colors.white, //change your color here 53 | ), 54 | title: new Text("Orders", style: TextStyle(color: Colors.white)), 55 | ), 56 | body: body()); 57 | } 58 | 59 | Widget body() { 60 | return new Column(children: [ 61 | 62 | // Search Box Widget 63 | 64 | Container( 65 | height: 50, 66 | child: new Card( 67 | child: new Row( 68 | children: [ 69 | new Expanded( 70 | child: new TextField( 71 | // controller: controller, 72 | decoration: new InputDecoration( 73 | contentPadding: EdgeInsets.fromLTRB(10.0, 15.0, 20.0, 15.0), 74 | prefixIcon: Icon(Icons.search), 75 | hintText: ' Search', 76 | border: InputBorder.none), 77 | onChanged: bloc.onSearchTextChanged, 78 | )), 79 | ], 80 | )), 81 | ), 82 | 83 | 84 | 85 | ordersListBuild() // Orders List Widget 86 | ]); 87 | } 88 | 89 | /* 90 | * Function perform a http request using BLoc for all orders list 91 | * Return a list widget using Stream builder 92 | */ 93 | 94 | Widget ordersListBuild() { 95 | bloc.fetchOrders(''); 96 | return StreamBuilder( 97 | stream: bloc.allOrders, 98 | builder: (context, AsyncSnapshot snapshot) { 99 | return snapshot.hasData 100 | ? ordersListViewWidget(snapshot) 101 | : Align( 102 | alignment: Alignment.center, 103 | child: CircularProgressIndicator()); 104 | }, 105 | ); 106 | } 107 | 108 | /* 109 | * Function takes AsyncSnapshot data for build a ListView 110 | * Function return a ListView widget 111 | */ 112 | 113 | Widget ordersListViewWidget(AsyncSnapshot s) { 114 | return new Expanded( 115 | child: ListView.builder( 116 | itemCount: s.data.length, 117 | itemBuilder: (_, index) { 118 | return InkWell( 119 | /*onTap: () { 120 | bloc.routeToPlaceOrderPage(_context, s.data[index]); 121 | },*/ 122 | child: Container( 123 | margin: EdgeInsets.all(6), 124 | child: Card( 125 | child: Column( 126 | children: [ 127 | ListTile( 128 | trailing: statusBox(s.data[index]['status']), 129 | leading: new Container( 130 | child: new Center( 131 | child: Text( 132 | "#" + s.data[index]["id"].toString(), 133 | style: TextStyle( 134 | color: Colors.white, 135 | fontWeight: FontWeight.w600), 136 | ), 137 | ), 138 | width: 40.0, 139 | height: 40.0, 140 | decoration: new BoxDecoration( 141 | shape: BoxShape.circle, color: Colors.red)), 142 | title: Text(s.data[index]['billing']["email"], 143 | style: TextStyle( 144 | fontSize: 12, 145 | fontWeight: FontWeight.w400, 146 | color: Colors.grey)), 147 | subtitle: Text( 148 | s.data[index]["date_created"] 149 | .toString() 150 | .substring(0, 10) + 151 | " || " + 152 | s.data[index]["currency"].toString() + 153 | " " + 154 | s.data[index]["total"].toString(), 155 | style: TextStyle( 156 | fontSize: 14, 157 | fontWeight: FontWeight.w500, 158 | color: Colors.black)), 159 | ), 160 | ], 161 | )))); 162 | })); 163 | } 164 | 165 | /* 166 | * Function take order status input 167 | * Build a orders status and background color according to the status 168 | * */ 169 | 170 | Widget statusBox(String orderStatus) { 171 | Color bgColor = Colors.blueAccent; 172 | 173 | if (orderStatus == 'processing') { 174 | bgColor = Colors.blue; 175 | } else if (orderStatus == 'completed') { 176 | bgColor = Colors.green; 177 | } else if (orderStatus == 'on-hold') { 178 | bgColor = Colors.orange; 179 | } 180 | 181 | return Container( 182 | width: 70, 183 | height: 30, 184 | child: Center( 185 | child: Text(orderStatus, 186 | style: TextStyle( 187 | fontSize: 12, 188 | fontWeight: FontWeight.w400, 189 | color: Colors.white))), 190 | decoration: BoxDecoration( 191 | color: bgColor, borderRadius: BorderRadius.circular(3))); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /lib/screen/place_order_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:woocommerce_app/bloc/place_order_bloc.dart'; 4 | import 'package:woocommerce_app/helper/ui_helper.dart'; 5 | import 'package:woocommerce_app/model/ordered_product.dart'; 6 | 7 | class PlaceOrderPage extends StatefulWidget { 8 | 9 | var customer; // Order place to this customer 10 | 11 | PlaceOrderPage(this.customer); 12 | 13 | @override 14 | PlaceOrderPageState createState() => new PlaceOrderPageState(this); 15 | } 16 | 17 | class PlaceOrderPageState extends State { 18 | 19 | Widget _mainFormWidget; 20 | 21 | var bloc; 22 | 23 | BuildContext _context; 24 | 25 | final _scaffoldKey = GlobalKey(); 26 | 27 | PlaceOrderPage parent; 28 | 29 | PlaceOrderPageState(this.parent); 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | bloc = PlaceOrderBloc(parent.customer); 35 | 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | _context = context; 41 | if (_mainFormWidget == null) { 42 | _mainFormWidget = mainBody(); 43 | } 44 | return _mainFormWidget; // Show the form in the application 45 | } 46 | 47 | Widget mainBody() { 48 | return new Scaffold( 49 | key: _scaffoldKey, 50 | bottomNavigationBar: new Container( 51 | height: 45, 52 | child: Row( 53 | children: [ 54 | Expanded( 55 | flex: 5, 56 | child: InkWell( 57 | onTap: () { 58 | bloc.routeToCartPage(_context, _scaffoldKey); 59 | }, 60 | child: Container( 61 | color: UIHelper.themeColor, 62 | child: Center( 63 | child: Text('Go Cart', 64 | style: TextStyle( 65 | fontWeight: FontWeight.w600, 66 | fontSize: 18, 67 | color: Colors.white)), 68 | )))), 69 | Expanded( 70 | flex: 5, 71 | child: Center( 72 | child: totalCreditWidget(), 73 | ), 74 | ) 75 | ], 76 | ), 77 | ), 78 | resizeToAvoidBottomInset: true, 79 | appBar: new AppBar( 80 | iconTheme: IconThemeData( 81 | color: Colors.white, //change your color here 82 | ), 83 | title: new Text("New Order", style: TextStyle(color: Colors.white)), 84 | actions: [ 85 | routeToCartWidget() 86 | ]), 87 | body: body()); 88 | } 89 | 90 | /* 91 | * Function request to the bloc for total ordered product credit and return a widget with total credit value 92 | */ 93 | 94 | Widget totalCreditWidget() { 95 | bloc.fetchTotalProductsCreditValue(); 96 | return StreamBuilder( 97 | stream: bloc.totalCreditValueFetcher.stream, 98 | builder: (context, AsyncSnapshot snapshot) { 99 | return snapshot.hasData 100 | ? Text( 101 | '\$ ' + snapshot.data.toString(), 102 | style: TextStyle( 103 | fontWeight: FontWeight.w600, 104 | fontSize: 18, 105 | color: UIHelper.themeColor), 106 | ) 107 | : Center(child: CircularProgressIndicator()); 108 | }, 109 | ); 110 | } 111 | 112 | /* 113 | * Return the main widget body 114 | */ 115 | 116 | Widget body() { 117 | return new Column(children: [ 118 | 119 | // Product list search widget 120 | Container( 121 | height: 50, 122 | child: new Card( 123 | child: new Row( 124 | children: [ 125 | new Expanded( 126 | flex: 6, 127 | child: new TextField( 128 | decoration: new InputDecoration( 129 | contentPadding: 130 | EdgeInsets.fromLTRB(10.0, 15.0, 20.0, 15.0), 131 | prefixIcon: Icon(Icons.search), 132 | hintText: ' Search', 133 | border: InputBorder.none), 134 | onChanged: bloc.onSearchTextChanged, 135 | )), 136 | new Container( 137 | width: 1, 138 | height: 50, 139 | color: Colors.grey, 140 | ), 141 | categoriesWidget() 142 | ], 143 | )), 144 | ), 145 | 146 | // Product List Build 147 | productListBuild() 148 | ]); 149 | } 150 | 151 | Widget routeToCartWidget() { 152 | bloc.totalCountProductItemInCart(); 153 | return StreamBuilder( 154 | stream: bloc.totalCountProductItemInCartFetcher.stream, 155 | builder: (context, AsyncSnapshot snapshot) { 156 | return snapshot.hasData 157 | ? cartdButton(snapshot) 158 | : Center(child: Container()); 159 | }, 160 | ); 161 | } 162 | 163 | Widget cartdButton(AsyncSnapshot s) { 164 | return new Container( 165 | child: new Stack( 166 | children: [ 167 | new IconButton( 168 | padding: EdgeInsets.all(0), 169 | icon: 170 | new Icon(Icons.shopping_cart, color: Colors.white, size: 32), 171 | onPressed: () { 172 | bloc.routeToCartPage(_context, _scaffoldKey); 173 | }), 174 | new Positioned( 175 | left: 30.0, 176 | top: 5, 177 | child: Container( 178 | height: 24, 179 | width: 24, 180 | decoration: new BoxDecoration( 181 | color: Colors.green, 182 | shape: BoxShape.circle, 183 | ), 184 | child: Center( 185 | child: Text( 186 | s.data.toString(), 187 | style: TextStyle(color: Colors.white), 188 | ))), 189 | ), 190 | ], 191 | ), 192 | ); 193 | } 194 | 195 | /* 196 | * Function request categories list by bloc 197 | * Return a dropdown widget by getting value 198 | */ 199 | 200 | Widget categoriesWidget() { 201 | bloc.fetchCategories(); 202 | return StreamBuilder( 203 | stream: bloc.categoriesFetcher.stream, 204 | builder: (context, AsyncSnapshot snapshot) { 205 | return snapshot.hasData 206 | ? categoryDropDownWidget(snapshot) 207 | : Center(child: CircularProgressIndicator()); 208 | }, 209 | ); 210 | } 211 | 212 | /* 213 | * Function takes AsyncSnapshot data for build a dropdown widget 214 | * Function return a Dropdown widget 215 | */ 216 | 217 | Widget categoryDropDownWidget(AsyncSnapshot snapshot) { 218 | String selectedValue; 219 | List categoriesList; 220 | snapshot.data.forEach((key, value) { 221 | selectedValue = key; 222 | categoriesList = value; 223 | }); 224 | 225 | return new Expanded( 226 | flex: 4, 227 | child: Center( 228 | child: DropdownButtonHideUnderline( 229 | child: ButtonTheme( 230 | alignedDropdown: true, 231 | child: new DropdownButton( 232 | style: new TextStyle( 233 | inherit: false, 234 | color: Colors.black, 235 | decorationColor: Colors.white), 236 | isExpanded: true, // Not necessary for Option 1 237 | value: selectedValue, 238 | onChanged: (newValue) { 239 | bloc.searchByCategories(newValue); 240 | }, 241 | items: categoriesList.map((location) { 242 | return DropdownMenuItem( 243 | child: new Text(location), 244 | value: location, 245 | ); 246 | }).toList(), 247 | ), 248 | )), 249 | )); 250 | } 251 | 252 | /* 253 | * Function request product list using BLoc 254 | * Return a list widget using Stream builder 255 | */ 256 | 257 | Widget productListBuild() { 258 | bloc.fetchProducts('', ''); 259 | return StreamBuilder( 260 | stream: bloc.allProducts, 261 | builder: (context, AsyncSnapshot snapshot) { 262 | return snapshot.hasData 263 | ? productListViewWidget(snapshot) 264 | : Center(child: CircularProgressIndicator()); 265 | }, 266 | ); 267 | } 268 | /* 269 | * Function takes AsyncSnapshot data for build a ListView 270 | * Function return a ListView widget 271 | */ 272 | 273 | Widget productListViewWidget(AsyncSnapshot s) { 274 | return new Expanded( 275 | child: ListView.builder( 276 | itemCount: s.data.length, 277 | itemBuilder: (_, index) { 278 | OrderProducts product = s.data[index]; 279 | 280 | String productImageUrl = product.imageUrl; 281 | 282 | if (productImageUrl != null && 283 | !productImageUrl.contains('woocommerce-placeholder')) { 284 | productImageUrl = product.imageUrl; 285 | } else { 286 | productImageUrl = null; 287 | } 288 | 289 | return Container( 290 | margin: EdgeInsets.all(6), 291 | child: Card( 292 | child: Column( 293 | children: [ 294 | ListTile( 295 | leading: new Container( 296 | child: productImageUrl != null 297 | ? new Container() 298 | : new Center( 299 | child: Text( 300 | product.name.substring(0, 1), 301 | style: TextStyle( 302 | color: Colors.white, 303 | fontWeight: FontWeight.w600), 304 | ), 305 | ), 306 | width: 40.0, 307 | height: 40.0, 308 | decoration: productImageUrl != null 309 | ? new BoxDecoration( 310 | shape: BoxShape.circle, 311 | image: new DecorationImage( 312 | fit: BoxFit.fill, 313 | image: 314 | new NetworkImage(product.imageUrl))) 315 | : new BoxDecoration( 316 | shape: BoxShape.circle, 317 | color: UIHelper.themeColor)), 318 | title: Text(product.name), 319 | subtitle: Text("MRP : " + 320 | product.mrp.toString() + 321 | " | " + 322 | "Stock : " + 323 | product.stock.toString()), 324 | ), 325 | SizedBox( 326 | height: 15, 327 | ), 328 | new Row( 329 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 330 | children: [ 331 | SizedBox( 332 | width: 70, 333 | ), 334 | new Flexible( 335 | child: Container( 336 | width: 80, 337 | child: new Text( 338 | '\$ ' + product.totalCreditValue.toString()), 339 | )), 340 | Spacer(), 341 | Container( 342 | decoration: BoxDecoration( 343 | borderRadius: BorderRadius.circular(5.0), 344 | border: Border.all( 345 | color: UIHelper.themeColor, width: 2)), 346 | width: 122, 347 | height: 40, 348 | child: new Row( 349 | children: [ 350 | Container( 351 | width: 39, 352 | child: Center( 353 | child: IconButton( 354 | icon: Icon(Icons.remove, 355 | color: UIHelper.themeColor), 356 | onPressed: () { 357 | bloc.orderRemove(product.id); 358 | })), 359 | ), 360 | Container( 361 | width: 40, 362 | height: 40, 363 | child: Center( 364 | child: Text( 365 | product.orderCount.toString(), 366 | style: 367 | TextStyle(color: UIHelper.themeColor), 368 | )), 369 | decoration: BoxDecoration( 370 | border: Border( 371 | right: BorderSide( 372 | width: 1.0, 373 | color: UIHelper.themeColor), 374 | left: BorderSide( 375 | width: 1.0, 376 | color: UIHelper.themeColor), 377 | ), 378 | color: Colors.white, 379 | ), 380 | ), 381 | Container( 382 | width: 39, 383 | child: Center( 384 | child: IconButton( 385 | icon: Icon(Icons.add, 386 | color: UIHelper.themeColor), 387 | onPressed: () { 388 | bloc.orderAdd(product.id); 389 | })), 390 | ), 391 | ], 392 | ), 393 | ), 394 | SizedBox( 395 | width: 10, 396 | ), 397 | ], 398 | ), 399 | SizedBox( 400 | height: 20, 401 | ) 402 | ], 403 | ))); 404 | })); 405 | } 406 | } 407 | -------------------------------------------------------------------------------- /lib/screen/splash_screen_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/material.dart'; 3 | import 'home_page.dart'; 4 | 5 | 6 | class SplashScreen extends StatefulWidget { 7 | @override 8 | _SplashScreenState createState() => _SplashScreenState(); 9 | } 10 | 11 | class _SplashScreenState extends State { 12 | @override 13 | void initState() { 14 | super.initState(); 15 | Timer(Duration(seconds: 2), () { 16 | Navigator.pushReplacement( 17 | context, 18 | MaterialPageRoute(builder: (context) => HomePage()), 19 | ); 20 | }); 21 | } 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return Scaffold( 26 | body: Stack( 27 | fit: StackFit.expand, 28 | children: [ 29 | Container( 30 | decoration: BoxDecoration(color: Colors.red), 31 | ), 32 | Column( 33 | mainAxisAlignment: MainAxisAlignment.start, 34 | children: [ 35 | Expanded( 36 | flex: 2, 37 | child: Container( 38 | child: Column( 39 | mainAxisAlignment: MainAxisAlignment.center, 40 | children: [ 41 | CircleAvatar( 42 | backgroundColor: Colors.white, 43 | radius: 60.0, 44 | child: Image.asset('images/woocom_icon.jpg'), 45 | ), 46 | Padding( 47 | padding: EdgeInsets.all(10.0), 48 | ), 49 | Text( 50 | 'WooCom Admin', 51 | style: TextStyle( 52 | color: Colors.white, 53 | fontWeight: FontWeight.bold, 54 | fontSize: 24.0), 55 | ) 56 | ], 57 | ), 58 | ), 59 | ), 60 | Expanded( 61 | flex: 1, 62 | child: Column( 63 | mainAxisAlignment: MainAxisAlignment.center, 64 | children: [ 65 | CircularProgressIndicator(backgroundColor: Colors.white,), 66 | Padding( 67 | padding: EdgeInsets.only(top: 20.0), 68 | ), 69 | Text( 70 | "Manage Customers,Orders,\n and Track Sales with Real time", 71 | softWrap: true, 72 | textAlign: TextAlign.center, 73 | style: TextStyle( 74 | fontWeight: FontWeight.bold, 75 | fontSize: 18.0, 76 | color: Colors.white), 77 | ) 78 | ], 79 | ), 80 | ) 81 | ], 82 | ) 83 | ], 84 | ), 85 | ); 86 | } 87 | } -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.9.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.2.1" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.1.2" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.1" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.16.0" 46 | convert: 47 | dependency: transitive 48 | description: 49 | name: convert 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "2.1.1" 53 | crypto: 54 | dependency: transitive 55 | description: 56 | name: crypto 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "2.1.3" 60 | cupertino_icons: 61 | dependency: "direct main" 62 | description: 63 | name: cupertino_icons 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "0.1.2" 67 | fake_async: 68 | dependency: transitive 69 | description: 70 | name: fake_async 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.3.1" 74 | flutter: 75 | dependency: "direct main" 76 | description: flutter 77 | source: sdk 78 | version: "0.0.0" 79 | flutter_test: 80 | dependency: "direct dev" 81 | description: flutter 82 | source: sdk 83 | version: "0.0.0" 84 | fluttertoast: 85 | dependency: "direct main" 86 | description: 87 | name: fluttertoast 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "3.1.3" 91 | http: 92 | dependency: transitive 93 | description: 94 | name: http 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "0.11.3+17" 98 | http_parser: 99 | dependency: transitive 100 | description: 101 | name: http_parser 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "3.1.3" 105 | matcher: 106 | dependency: transitive 107 | description: 108 | name: matcher 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "0.12.12" 112 | material_color_utilities: 113 | dependency: transitive 114 | description: 115 | name: material_color_utilities 116 | url: "https://pub.dartlang.org" 117 | source: hosted 118 | version: "0.1.5" 119 | meta: 120 | dependency: transitive 121 | description: 122 | name: meta 123 | url: "https://pub.dartlang.org" 124 | source: hosted 125 | version: "1.8.0" 126 | path: 127 | dependency: transitive 128 | description: 129 | name: path 130 | url: "https://pub.dartlang.org" 131 | source: hosted 132 | version: "1.8.2" 133 | progress_hud: 134 | dependency: "direct main" 135 | description: 136 | name: progress_hud 137 | url: "https://pub.dartlang.org" 138 | source: hosted 139 | version: "1.1.0" 140 | rxdart: 141 | dependency: "direct main" 142 | description: 143 | name: rxdart 144 | url: "https://pub.dartlang.org" 145 | source: hosted 146 | version: "0.18.1" 147 | sky_engine: 148 | dependency: transitive 149 | description: flutter 150 | source: sdk 151 | version: "0.0.99" 152 | source_span: 153 | dependency: transitive 154 | description: 155 | name: source_span 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "1.9.0" 159 | stack_trace: 160 | dependency: transitive 161 | description: 162 | name: stack_trace 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "1.10.0" 166 | stream_channel: 167 | dependency: transitive 168 | description: 169 | name: stream_channel 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "2.1.0" 173 | string_scanner: 174 | dependency: transitive 175 | description: 176 | name: string_scanner 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "1.1.1" 180 | term_glyph: 181 | dependency: transitive 182 | description: 183 | name: term_glyph 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "1.2.1" 187 | test_api: 188 | dependency: transitive 189 | description: 190 | name: test_api 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "0.4.12" 194 | typed_data: 195 | dependency: transitive 196 | description: 197 | name: typed_data 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "1.1.6" 201 | vector_math: 202 | dependency: transitive 203 | description: 204 | name: vector_math 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "2.1.2" 208 | woocommerce_api: 209 | dependency: "direct main" 210 | description: 211 | name: woocommerce_api 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "0.0.8" 215 | sdks: 216 | dart: ">=2.17.0-0 <3.0.0" 217 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: woocommerce_app 2 | description: A new Flutter application. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.1.0 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | 23 | # The following adds the Cupertino Icons font to your application. 24 | # Use with the CupertinoIcons class for iOS style icons. 25 | cupertino_icons: ^0.1.2 26 | woocommerce_api: ^0.0.8 27 | rxdart: ^0.18.0 28 | fluttertoast: ^3.0.1 29 | progress_hud: ^1.1.0 30 | 31 | dev_dependencies: 32 | flutter_test: 33 | sdk: flutter 34 | 35 | 36 | # For information on the generic Dart part of this file, see the 37 | # following page: https://dart.dev/tools/pub/pubspec 38 | 39 | # The following section is specific to Flutter. 40 | flutter: 41 | 42 | # The following line ensures that the Material Icons font is 43 | # included with your application, so that you can use the icons in 44 | # the material Icons class. 45 | uses-material-design: true 46 | 47 | # To add assets to your application, add an assets section, like this: 48 | assets: 49 | - images/cover_photo.jpg 50 | - images/woocom_icon.jpg 51 | 52 | # An image asset can refer to one or more resolution-specific "variants", see 53 | # https://flutter.dev/assets-and-images/#resolution-aware. 54 | 55 | # For details regarding adding assets from package dependencies, see 56 | # https://flutter.dev/assets-and-images/#from-packages 57 | 58 | # To add custom fonts to your application, add a fonts section here, 59 | # in this "flutter" section. Each entry in this list should have a 60 | # "family" key with the font family name, and a "fonts" key with a 61 | # list giving the asset and other descriptors for the font. For 62 | # example: 63 | # fonts: 64 | # - family: Schyler 65 | # fonts: 66 | # - asset: fonts/Schyler-Regular.ttf 67 | # - asset: fonts/Schyler-Italic.ttf 68 | # style: italic 69 | # - family: Trajan Pro 70 | # fonts: 71 | # - asset: fonts/TrajanPro.ttf 72 | # - asset: fonts/TrajanPro_Bold.ttf 73 | # weight: 700 74 | # 75 | # For details regarding fonts from package dependencies, 76 | # see https://flutter.dev/custom-fonts/#from-packages 77 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:woocommerce_app/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | --------------------------------------------------------------------------------