├── .flutter-plugins-dependencies ├── .gitignore ├── .metadata ├── README.md ├── android ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── appshmapp │ │ │ │ └── cool_store │ │ │ │ └── MainActivity.java │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── category_image_default.jpg ├── colors.csv ├── empty.svg ├── empty_cart.png ├── list.svg ├── no_result.svg ├── shoppint_cart_empty.svg └── wishlist.png ├── fonts ├── Raleway-Black.ttf ├── Raleway-BlackItalic.ttf ├── Raleway-Bold.ttf ├── Raleway-BoldItalic.ttf ├── Raleway-ExtraBold.ttf ├── Raleway-ExtraBoldItalic.ttf ├── Raleway-ExtraLight.ttf ├── Raleway-ExtraLightItalic.ttf ├── Raleway-Italic.ttf ├── Raleway-Light.ttf ├── Raleway-LightItalic.ttf ├── Raleway-Medium.ttf ├── Raleway-MediumItalic.ttf ├── Raleway-Regular.ttf ├── Raleway-SemiBold.ttf ├── Raleway-SemiBoldItalic.ttf ├── Raleway-Thin.ttf └── Raleway-ThinItalic.ttf ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Flutter.podspec │ ├── Release.xcconfig │ └── flutter_export_environment.sh ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── main.m ├── lib ├── app.dart ├── main.dart ├── models │ ├── category.dart │ ├── order.dart │ ├── payment.dart │ ├── product.dart │ ├── shipping_methods.dart │ └── user.dart ├── screens │ ├── cart_screen.dart │ ├── category_screen.dart │ ├── checkout_screen.dart │ ├── detail_screen.dart │ ├── home_screen.dart │ ├── order_review_screen.dart │ ├── order_summary_screen.dart │ ├── product_list_screen.dart │ ├── search_screen.dart │ ├── setting_screen.dart │ ├── shipping_address_screen.dart │ ├── shipping_methods_screen.dart │ └── wishlist_screen.dart ├── services │ ├── base_services.dart │ ├── woocommerce.dart │ └── woocommerce_api.dart ├── states │ ├── app_state.dart │ ├── cart_state.dart │ ├── category_state.dart │ ├── checkout_state.dart │ ├── detail_state.dart │ ├── home_state.dart │ ├── product_list_state.dart │ ├── search_state.dart │ └── settings_state.dart ├── utils │ ├── color.dart │ └── constants.dart └── widgets │ ├── Badge.dart │ ├── CartItem.dart │ ├── ColorChooser.dart │ ├── DefaultChooser.dart │ ├── GalleryView.dart │ ├── ImageView.dart │ ├── InfoView.dart │ ├── OffersBanner.dart │ ├── ProductCard.dart │ ├── ProductDescription.dart │ ├── ProductTitle.dart │ ├── QuantityChooser.dart │ ├── RelatedProducts.dart │ ├── ShimmerGrid.dart │ ├── ShimmerList.dart │ ├── VariantChooser.dart │ ├── VariationsView.dart │ └── category_banner.dart ├── pubspec.lock └── pubspec.yaml /.flutter-plugins-dependencies: -------------------------------------------------------------------------------- 1 | {"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"connectivity","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_macos","shared_preferences_web"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]}]} -------------------------------------------------------------------------------- /.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 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | -------------------------------------------------------------------------------- /.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: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # COOL STORE (CROSS-PLATFORM E-Commerce application) 2 | 3 | A E-Commerce Flutter Application for woocommerce stores 4 | 5 | Show some ❤️ and star the repo to support the project 6 | 7 | 8 | ## Features 9 | - Supports Dynamic themes (Light/Dark) 10 | - Built with Provider achitecture 11 | - Woocommerce Backend 12 | 13 | ## Created & Maintained by 14 | [Mithlesh Parmar](https://github.com/mithilesh-parmar) ([linkedin](https://www.linkedin.com/in/mithilesh-parmar-97395712b/)) 15 | 16 | ## Screen recording of the app 17 | [YouTube](https://www.youtube.com/watch?v=TGCEG3YHbWQ) 18 | 19 | # License 20 | >MIT License 21 | > 22 | >Copyright (c) [2019] [Mithilesh Parmar] 23 | > 24 | >Permission is hereby granted, free of charge, to any person obtaining a copy 25 | >of this software and associated documentation files (the "Software"), to deal 26 | >in the Software without restriction, including without limitation the rights 27 | >to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 28 | >copies of the Software, and to permit persons to whom the Software is 29 | >furnished to do so, subject to the following conditions: 30 | > 31 | >The above copyright notice and this permission notice shall be included in all 32 | >copies or substantial portions of the Software. 33 | > 34 | >THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 35 | >IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 36 | >FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 37 | >AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 38 | >LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 39 | >OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 40 | >SOFTWARE. 41 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.appshmapp.cool_store" 37 | minSdkVersion 16 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 15 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/appshmapp/cool_store/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.appshmapp.cool_store; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.5.0' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Sep 08 20:21:20 IST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /assets/category_image_default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/assets/category_image_default.jpg -------------------------------------------------------------------------------- /assets/empty.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/empty_cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/assets/empty_cart.png -------------------------------------------------------------------------------- /assets/list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/shoppint_cart_empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 14 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /assets/wishlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/assets/wishlist.png -------------------------------------------------------------------------------- /fonts/Raleway-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-Black.ttf -------------------------------------------------------------------------------- /fonts/Raleway-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-BlackItalic.ttf -------------------------------------------------------------------------------- /fonts/Raleway-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-Bold.ttf -------------------------------------------------------------------------------- /fonts/Raleway-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-BoldItalic.ttf -------------------------------------------------------------------------------- /fonts/Raleway-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-ExtraBold.ttf -------------------------------------------------------------------------------- /fonts/Raleway-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /fonts/Raleway-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-ExtraLight.ttf -------------------------------------------------------------------------------- /fonts/Raleway-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /fonts/Raleway-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-Italic.ttf -------------------------------------------------------------------------------- /fonts/Raleway-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-Light.ttf -------------------------------------------------------------------------------- /fonts/Raleway-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-LightItalic.ttf -------------------------------------------------------------------------------- /fonts/Raleway-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-Medium.ttf -------------------------------------------------------------------------------- /fonts/Raleway-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-MediumItalic.ttf -------------------------------------------------------------------------------- /fonts/Raleway-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-Regular.ttf -------------------------------------------------------------------------------- /fonts/Raleway-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-SemiBold.ttf -------------------------------------------------------------------------------- /fonts/Raleway-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /fonts/Raleway-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-Thin.ttf -------------------------------------------------------------------------------- /fonts/Raleway-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/fonts/Raleway-ThinItalic.ttf -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: This podspec is NOT to be published. It is only used as a local source! 3 | # 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'Flutter' 7 | s.version = '1.0.0' 8 | s.summary = 'High-performance, high-fidelity mobile apps.' 9 | s.description = <<-DESC 10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. 11 | DESC 12 | s.homepage = 'https://flutter.io' 13 | s.license = { :type => 'MIT' } 14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } 15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } 16 | s.ios.deployment_target = '8.0' 17 | s.vendored_frameworks = 'Flutter.framework' 18 | end 19 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/Users/mithileshparmar/Development/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/Users/mithileshparmar/Development/Android_Projects/Flutter-store" 5 | export "FLUTTER_TARGET=/Users/mithileshparmar/Development/Android_Projects/Flutter-store/lib/main.dart" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios" 8 | export "FLUTTER_FRAMEWORK_DIR=/Users/mithileshparmar/Development/flutter/bin/cache/artifacts/engine/ios" 9 | export "FLUTTER_BUILD_NAME=1.0.0" 10 | export "FLUTTER_BUILD_NUMBER=1" 11 | export "TRACK_WIDGET_CREATION=true" 12 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | pods_ary = [] 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) { |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | pods_ary.push({:name => podname, :path => podpath}); 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | } 32 | return pods_ary 33 | end 34 | 35 | target 'Runner' do 36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 37 | # referring to absolute paths on developers' machines. 38 | system('rm -rf .symlinks') 39 | system('mkdir -p .symlinks/plugins') 40 | 41 | # Flutter Pods 42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 43 | if generated_xcode_build_settings.empty? 44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." 45 | end 46 | generated_xcode_build_settings.map { |p| 47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 48 | symlink = File.join('.symlinks', 'flutter') 49 | File.symlink(File.dirname(p[:path]), symlink) 50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 51 | end 52 | } 53 | 54 | # Plugin Pods 55 | plugin_pods = parse_KV_file('../.flutter-plugins') 56 | plugin_pods.map { |p| 57 | symlink = File.join('.symlinks', 'plugins', p[:name]) 58 | File.symlink(p[:path], symlink) 59 | pod p[:name], :path => File.join(symlink, 'ios') 60 | } 61 | end 62 | 63 | post_install do |installer| 64 | installer.pods_project.targets.each do |target| 65 | target.build_configurations.each do |config| 66 | config.build_settings['ENABLE_BITCODE'] = 'NO' 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - connectivity (0.0.1): 3 | - Flutter 4 | - Reachability 5 | - Flutter (1.0.0) 6 | - path_provider (0.0.1): 7 | - Flutter 8 | - Reachability (3.2) 9 | - shared_preferences (0.0.1): 10 | - Flutter 11 | - shared_preferences_macos (0.0.1): 12 | - Flutter 13 | - shared_preferences_web (0.0.1): 14 | - Flutter 15 | 16 | DEPENDENCIES: 17 | - connectivity (from `.symlinks/plugins/connectivity/ios`) 18 | - Flutter (from `.symlinks/flutter/ios`) 19 | - path_provider (from `.symlinks/plugins/path_provider/ios`) 20 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) 21 | - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) 22 | - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) 23 | 24 | SPEC REPOS: 25 | trunk: 26 | - Reachability 27 | 28 | EXTERNAL SOURCES: 29 | connectivity: 30 | :path: ".symlinks/plugins/connectivity/ios" 31 | Flutter: 32 | :path: ".symlinks/flutter/ios" 33 | path_provider: 34 | :path: ".symlinks/plugins/path_provider/ios" 35 | shared_preferences: 36 | :path: ".symlinks/plugins/shared_preferences/ios" 37 | shared_preferences_macos: 38 | :path: ".symlinks/plugins/shared_preferences_macos/ios" 39 | shared_preferences_web: 40 | :path: ".symlinks/plugins/shared_preferences_web/ios" 41 | 42 | SPEC CHECKSUMS: 43 | connectivity: 6e94255659cc86dcbef1d452ad3e0491bb1b3e75 44 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 45 | path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d 46 | Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 47 | shared_preferences: 430726339841afefe5142b9c1f50cb6bd7793e01 48 | shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 49 | shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 50 | 51 | PODFILE CHECKSUM: aff02bfeed411c636180d6812254b2daeea14d09 52 | 53 | COCOAPODS: 1.8.4 54 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/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/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mithilesh-parmar/Flutter-store/eed653978fdd1b9e453f083c687ec1607b5a7368/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | cool_store 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/screens/cart_screen.dart'; 2 | import 'package:cool_store/screens/home_screen.dart'; 3 | import 'package:cool_store/screens/category_screen.dart'; 4 | import 'package:cool_store/screens/setting_screen.dart'; 5 | import 'package:cool_store/states/app_state.dart'; 6 | import 'package:cool_store/states/cart_state.dart'; 7 | import 'package:cool_store/states/home_state.dart'; 8 | import 'package:cool_store/states/category_state.dart'; 9 | import 'package:cool_store/states/settings_state.dart'; 10 | import 'package:flutter/material.dart'; 11 | import 'package:provider/provider.dart'; 12 | 13 | class App extends StatelessWidget { 14 | @override 15 | Widget build(BuildContext context) { 16 | return MultiProvider( 17 | providers: [ 18 | ChangeNotifierProvider( 19 | builder: (_) => AppState(initialScreen: HomeScreen(), screens: [ 20 | HomeScreen(), 21 | CategoryScreen(), 22 | CartScreen(), 23 | SettingScreen() 24 | ]), 25 | ), 26 | ChangeNotifierProvider( 27 | builder: (_) => HomeState(), 28 | ), 29 | ChangeNotifierProvider( 30 | builder: (_) => CartState(), 31 | ), 32 | ChangeNotifierProvider( 33 | builder: (_) => CategoryState(), 34 | ), 35 | ChangeNotifierProvider( 36 | builder: (_) => SettingState(), 37 | ), 38 | ], 39 | child: Consumer( 40 | builder: (context, state, child) => MaterialApp( 41 | debugShowCheckedModeBanner: false, 42 | theme: state.getTheme(), 43 | home: Scaffold( 44 | body: state.selectedScreen, 45 | bottomNavigationBar: BottomNavigationBar( 46 | type: BottomNavigationBarType.fixed, 47 | onTap: (pos) => state.setScreenIndex(pos), 48 | currentIndex: state.selectedScreenIndex, 49 | selectedItemColor: state.getTheme().accentColor, 50 | items: [ 51 | BottomNavigationBarItem( 52 | icon: Icon(Icons.home), title: Text('Home')), 53 | BottomNavigationBarItem( 54 | icon: Icon(Icons.search), title: Text('Search')), 55 | BottomNavigationBarItem( 56 | icon: Icon(Icons.add_shopping_cart), title: Text('Cart')), 57 | BottomNavigationBarItem( 58 | icon: Icon(Icons.settings), title: Text('Setting')), 59 | ], 60 | ), 61 | ), 62 | ), 63 | ), 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/app.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:cool_store/utils/color.dart'; 4 | 5 | void main() => runApp(App()); 6 | -------------------------------------------------------------------------------- /lib/models/category.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Category { 4 | int id; 5 | String name; 6 | String image; 7 | int parent; 8 | int totalProduct; 9 | 10 | Category.fromJson(Map parsedJson) { 11 | if (parsedJson["slug"] == 'uncategorized') { 12 | return; 13 | } 14 | 15 | id = parsedJson["id"]; 16 | name = parsedJson["name"]; 17 | parent = parsedJson["parent"]; 18 | totalProduct = parsedJson["count"]; 19 | 20 | final image = parsedJson["image"]; 21 | if (image != null) { 22 | this.image = image["src"]; 23 | } else { 24 | this.image = 'category_image_default.jpg'; 25 | } 26 | } 27 | 28 | @override 29 | String toString() => 'Category { id: $id name: $name}'; 30 | } 31 | -------------------------------------------------------------------------------- /lib/models/order.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/payment.dart'; 2 | import 'package:cool_store/models/product.dart'; 3 | import 'package:cool_store/models/user.dart'; 4 | import 'package:cool_store/states/cart_state.dart'; 5 | 6 | class ProductItem { 7 | int productId; 8 | String name; 9 | int quantity; 10 | String total; 11 | 12 | ProductItem.fromJson(Map parsedJson) { 13 | productId = parsedJson["product_id"]; 14 | name = parsedJson["name"]; 15 | quantity = parsedJson["quantity"]; 16 | total = parsedJson["total"]; 17 | } 18 | } 19 | 20 | class Order { 21 | int id; 22 | String number; 23 | String status; 24 | DateTime createdAt; 25 | double total; 26 | String paymentMethodTitle; 27 | String shippingMethodTitle; 28 | List lineItems = []; 29 | Address billing; 30 | 31 | Order({this.id, this.number, this.status, this.createdAt, this.total}); 32 | 33 | Order.fromJson(Map parsedJson) { 34 | id = parsedJson["id"]; 35 | number = parsedJson["number"]; 36 | status = parsedJson["status"]; 37 | createdAt = parsedJson["date_created"] != null 38 | ? DateTime.parse(parsedJson["date_created"]) 39 | : DateTime.now(); 40 | total = 41 | parsedJson["total"] != null ? double.parse(parsedJson["total"]) : 0.0; 42 | paymentMethodTitle = parsedJson["payment_method_title"]; 43 | 44 | parsedJson["line_items"].forEach((item) { 45 | lineItems.add(ProductItem.fromJson(item)); 46 | }); 47 | 48 | billing = Address.fromJson(parsedJson["billing"]); 49 | shippingMethodTitle = parsedJson["shipping_lines"][0]["method_title"]; 50 | } 51 | 52 | Map toJson( 53 | Map productsInCart, 54 | Map productVariationsInCart, 55 | Address address, 56 | PaymentMethod paymentMethod, 57 | [userId = 1]) { 58 | var lineItems = productsInCart.keys.map((key) { 59 | var productId = int.parse(key); 60 | var item = {"product_id": productId, "quantity": productsInCart[key]}; 61 | if (productVariationsInCart[key] != null) { 62 | item['variation_id'] = productVariationsInCart[key].id; 63 | } 64 | 65 | return item; 66 | }).toList(); 67 | 68 | return { 69 | "payment_method": paymentMethod.id, 70 | "payment_method_title": paymentMethod.title, 71 | "set_paid": false, 72 | "billing": address.toJson(), 73 | "shipping": address.toJson(), 74 | "line_items": lineItems, 75 | "customer_id": userId, 76 | "shipping_lines": [ 77 | {"method_id": 'flat_rate', "method_title": 'Flat Rate'} 78 | ] 79 | }; 80 | } 81 | 82 | @override 83 | String toString() => 'Order { id: $id number: $number}'; 84 | } 85 | -------------------------------------------------------------------------------- /lib/models/payment.dart: -------------------------------------------------------------------------------- 1 | class PaymentMethod { 2 | String id; 3 | String title; 4 | String description; 5 | bool enabled; 6 | 7 | PaymentMethod({this.id, this.title, this.description, this.enabled}); 8 | 9 | PaymentMethod.fromJson(Map parsedJson) { 10 | id = parsedJson["id"]; 11 | title = parsedJson["title"]; 12 | description = parsedJson["description"]; 13 | enabled = parsedJson["enabled"]; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/models/product.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | class Product { 4 | int id; 5 | String sku; 6 | String name; 7 | String description; 8 | String permalink; 9 | String price; 10 | String regularPrice; 11 | String salePrice; 12 | bool onSale; 13 | bool inStock; 14 | double averageRating; 15 | double ratingCount; 16 | List images; 17 | String featuredImage; 18 | List attributes; 19 | int categoryId; 20 | 21 | Product.empty(int id) { 22 | this.id = id; 23 | name = 'Loading...'; 24 | price = '0.0'; 25 | featuredImage = ''; 26 | } 27 | 28 | bool isEmptyProduct() { 29 | return name == 'Loading...' && price == '0.0' && featuredImage == ''; 30 | } 31 | 32 | Product.fromJson(Map parsedJson) { 33 | id = parsedJson["id"]; 34 | name = parsedJson["name"]; 35 | description = parsedJson["description"]; 36 | permalink = parsedJson["permalink"]; 37 | price = parsedJson["price"] == 0 ? 10 : parsedJson["price"]; 38 | 39 | regularPrice = parsedJson["regular_price"]; 40 | salePrice = parsedJson["sale_price"]; 41 | onSale = parsedJson["on_sale"]; 42 | inStock = parsedJson["in_stock"]; 43 | 44 | averageRating = double.parse(parsedJson["average_rating"]); 45 | ratingCount = double.parse(parsedJson["rating_count"].toString()); 46 | categoryId = 47 | parsedJson["categories"] != null && parsedJson["categories"].length > 0 48 | ? parsedJson["categories"][0]["id"] 49 | : 0; 50 | 51 | List attributeList = []; 52 | parsedJson["attributes"].forEach((item) { 53 | attributeList.add(ProductAttribute.fromJson(item)); 54 | }); 55 | attributes = attributeList; 56 | 57 | List list = []; 58 | for (var item in parsedJson["images"]) { 59 | list.add(item["src"]); 60 | } 61 | images = list; 62 | featuredImage = images[0]; 63 | } 64 | 65 | Map toJson() { 66 | return { 67 | "id": id, 68 | "sku": sku, 69 | "name": name, 70 | "description": description, 71 | "permalink": permalink, 72 | "price": price, 73 | "regularPrice": regularPrice, 74 | "salePrice": salePrice, 75 | "onSale": onSale, 76 | "inStock": inStock, 77 | "averageRating": averageRating, 78 | "ratingCount": ratingCount, 79 | "images": images, 80 | "imageFeature": featuredImage, 81 | "attributes": attributes, 82 | "categoryId": categoryId 83 | }; 84 | } 85 | 86 | Product.fromLocalJson(Map json) { 87 | try { 88 | id = json['id']; 89 | sku = json['sku']; 90 | name = json['name']; 91 | description = json['description']; 92 | permalink = json['permalink']; 93 | price = json['price']; 94 | regularPrice = json['regularPrice']; 95 | salePrice = json['salePrice']; 96 | onSale = json['onSale']; 97 | inStock = json['inStock']; 98 | averageRating = json['averageRating']; 99 | ratingCount = json['ratingCount']; 100 | List imgs = []; 101 | for (var item in json['images']) { 102 | imgs.add(item); 103 | } 104 | images = imgs; 105 | featuredImage = json['imageFeature']; 106 | List attrs = []; 107 | for (var item in json['attributes']) { 108 | attrs.add(ProductAttribute.fromLocalJson(item)); 109 | } 110 | attributes = attrs; 111 | categoryId = json['categoryId']; 112 | } catch (e) { 113 | print(e.toString()); 114 | } 115 | } 116 | 117 | @override 118 | String toString() => 'Product { id: $id name: $name }'; 119 | } 120 | 121 | class ProductAttribute { 122 | int id; 123 | String name; 124 | List options; 125 | 126 | ProductAttribute.fromJson(Map parsedJson) { 127 | id = parsedJson["id"]; 128 | name = parsedJson["name"]; 129 | options = parsedJson["options"]; 130 | } 131 | 132 | Map toJson() { 133 | return {"id": id, "name": name, "options": options}; 134 | } 135 | 136 | @override 137 | String toString() { 138 | return 'id: $id name: $name options: $options'; 139 | } 140 | 141 | ProductAttribute.fromLocalJson(Map json) { 142 | try { 143 | id = json['id']; 144 | name = json['name']; 145 | options = json['options']; 146 | } catch (e) { 147 | print(e.toString()); 148 | } 149 | } 150 | } 151 | 152 | class Attribute { 153 | int id; 154 | String name; 155 | String option; 156 | 157 | Attribute(); 158 | 159 | Map toJson() { 160 | return {'id': id, 'name': name, 'option': option}; 161 | } 162 | 163 | Attribute.fromJson(Map parsedJson) { 164 | id = parsedJson["id"]; 165 | name = parsedJson["name"]; 166 | option = parsedJson["option"]; 167 | } 168 | 169 | @override 170 | String toString() { 171 | // TODO: implement toString 172 | return '$name: $option'; 173 | } 174 | } 175 | 176 | class ProductVariation { 177 | int id; 178 | String price; 179 | String regularPrice; 180 | String salePrice; 181 | bool onSale; 182 | bool inStock; 183 | String imageFeature; 184 | List attributes = []; 185 | 186 | ProductVariation(); 187 | 188 | Map toJson() { 189 | return { 190 | 'id': id, 191 | 'price': price, 192 | 'regularPrice': regularPrice, 193 | 'salePrice': salePrice, 194 | 'onSale': onSale, 195 | 'inStock': inStock, 196 | 'imageFeature': imageFeature, 197 | 'attributes': attributes 198 | }; 199 | } 200 | 201 | ProductVariation.fromJson(Map parsedJson) { 202 | id = parsedJson["id"]; 203 | price = parsedJson["price"]; 204 | regularPrice = parsedJson["regular_price"]; 205 | salePrice = parsedJson["sale_price"]; 206 | onSale = parsedJson["on_sale"]; 207 | inStock = parsedJson["in_stock"]; 208 | imageFeature = parsedJson["imageFeature"]; 209 | 210 | List attributeList = []; 211 | parsedJson["attributes"].forEach((item) { 212 | attributeList.add(Attribute.fromJson(item)); 213 | }); 214 | attributes = attributeList; 215 | } 216 | 217 | @override 218 | String toString() { 219 | String value = ''; 220 | attributes.forEach((attribute) { 221 | value += '${attribute.name}: ${attribute.option}, '; 222 | }); 223 | value = value.substring(0, value.length - 3); 224 | return value; 225 | } 226 | } 227 | 228 | class Review { 229 | int id, productId; 230 | String reviewer, reviewerEmail, review; 231 | int rating; 232 | 233 | Review( 234 | {this.id, 235 | this.productId, 236 | this.reviewer, 237 | this.reviewerEmail, 238 | this.review, 239 | this.rating}); 240 | 241 | Map toJson() { 242 | return { 243 | 'product_id': productId, 244 | 'reviewer': reviewer, 245 | 'reviewer_email': reviewerEmail, 246 | 'review': review, 247 | 'rating': rating 248 | }; 249 | } 250 | 251 | Review.fromJson(Map parsedJson) { 252 | id = parsedJson['id']; 253 | productId = parsedJson['product_id']; 254 | reviewer = parsedJson['reviewer']; 255 | reviewerEmail = parsedJson['reviewer_email']; 256 | review = parsedJson['review']; 257 | rating = parsedJson['rating']; 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /lib/models/shipping_methods.dart: -------------------------------------------------------------------------------- 1 | class ShippingMethods { 2 | String id; 3 | String title; 4 | String description; 5 | 6 | ShippingMethods({this.id, this.title, this.description}); 7 | 8 | toJson() { 9 | return { 10 | 'method_id': id, 11 | 'method_title': title, 12 | }; 13 | } 14 | 15 | ShippingMethods.fromJson(Map parsedjson) { 16 | id = parsedjson['id']; 17 | title = parsedjson['title']; 18 | description = parsedjson['description']; 19 | } 20 | 21 | bool isEqual(ShippingMethods item) { 22 | return id == item.id && 23 | title == item.title && 24 | description == item.description; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/models/user.dart: -------------------------------------------------------------------------------- 1 | class Address { 2 | String firstName; 3 | String lastName; 4 | String email; 5 | String street; 6 | String city; 7 | String state; 8 | String country; 9 | String phoneNumber; 10 | String zipCode; 11 | 12 | Address( 13 | {this.firstName, 14 | this.lastName, 15 | this.email, 16 | this.street, 17 | this.city, 18 | this.state, 19 | this.country, 20 | this.phoneNumber, 21 | this.zipCode}); 22 | 23 | Address.fromJson(Map parsedJson) { 24 | firstName = parsedJson["first_name"]; 25 | lastName = parsedJson["last_name"]; 26 | street = parsedJson["address_1"]; 27 | city = parsedJson["city"]; 28 | state = parsedJson["state"]; 29 | country = parsedJson["country"]; 30 | email = parsedJson["email"]; 31 | phoneNumber = parsedJson["phone"]; 32 | zipCode = parsedJson["postcode"]; 33 | } 34 | 35 | Map toJson() { 36 | return { 37 | "first_name": firstName, 38 | "last_name": lastName, 39 | "address_1": street, 40 | "address_2": '', 41 | "city": city, 42 | "state": state, 43 | "country": country, 44 | "email": email, 45 | "phone": phoneNumber, 46 | "postcode": zipCode 47 | }; 48 | } 49 | 50 | Address.fromLocalJson(Map json) { 51 | try { 52 | firstName = json['first_name']; 53 | lastName = json['last_name']; 54 | street = json['address_1']; 55 | city = json['city']; 56 | state = json['state']; 57 | country = json['country']; 58 | email = json['email']; 59 | phoneNumber = json['phone']; 60 | zipCode = json['postcode']; 61 | } catch (e) { 62 | print(e.toString()); 63 | } 64 | } 65 | 66 | bool isValid() { 67 | return firstName.isNotEmpty && 68 | lastName.isNotEmpty && 69 | email.isNotEmpty && 70 | street.isNotEmpty && 71 | city.isNotEmpty && 72 | state.isNotEmpty && 73 | country.isNotEmpty && 74 | phoneNumber.isNotEmpty; 75 | } 76 | 77 | @override 78 | String toString() { 79 | return '\nFirst Name:$firstName\nLastName:$lastName\nemail:$email\nstreet:$street\ncity:$city\nState:$state\ncountry:$country\nPhoneNumber:$phoneNumber'; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/screens/category_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/screens/product_list_screen.dart'; 2 | import 'package:cool_store/screens/search_screen.dart'; 3 | import 'package:cool_store/states/product_list_state.dart'; 4 | import 'package:cool_store/states/category_state.dart'; 5 | import 'package:cool_store/states/search_state.dart'; 6 | import 'package:cool_store/utils/constants.dart'; 7 | import 'package:cool_store/widgets/GalleryView.dart'; 8 | import 'package:cool_store/widgets/ShimmerList.dart'; 9 | import 'package:cool_store/widgets/category_banner.dart'; 10 | import 'package:flutter/material.dart'; 11 | import 'package:provider/provider.dart'; 12 | 13 | class CategoryScreen extends StatelessWidget { 14 | @override 15 | Widget build(BuildContext context) { 16 | final CategoryState state = Provider.of(context); 17 | return Scaffold( 18 | body: CustomScrollView( 19 | slivers: [ 20 | SliverAppBar( 21 | floating: true, 22 | snap: true, 23 | centerTitle: false, 24 | bottom: PreferredSize( 25 | preferredSize: Size(100, 100), 26 | child: GestureDetector( 27 | onTap: () { 28 | Navigator.of(context).push(MaterialPageRoute( 29 | fullscreenDialog: true, 30 | builder: (_) => ChangeNotifierProvider( 31 | child: SearchScreen(), 32 | builder: (_) => SearchState(), 33 | ))); 34 | }, 35 | child: Column( 36 | mainAxisAlignment: MainAxisAlignment.start, 37 | crossAxisAlignment: CrossAxisAlignment.start, 38 | children: [ 39 | Container( 40 | child: Text( 41 | 'Search', 42 | style: TextStyle( 43 | fontWeight: FontWeight.bold, 44 | fontFamily: 'Raleway', 45 | fontSize: 40), 46 | ), 47 | padding: 48 | EdgeInsets.symmetric(horizontal: 17, vertical: 8), 49 | ), 50 | Container( 51 | height: Constants.screenAwareSize(40, context), 52 | width: MediaQuery.of(context).size.width, 53 | child: Row( 54 | children: [ 55 | Align( 56 | child: Padding( 57 | padding: 58 | const EdgeInsets.symmetric(horizontal: 8.0), 59 | child: Text( 60 | 'SEARCH FOR BRAND, PRODUCTS, CATEGORY', 61 | style: TextStyle( 62 | fontFamily: 'Raleway', 63 | fontWeight: FontWeight.w200, 64 | fontSize: 12), 65 | ), 66 | ), 67 | alignment: Alignment.centerLeft, 68 | ), 69 | Spacer(), 70 | Padding( 71 | padding: 72 | const EdgeInsets.symmetric(horizontal: 8.0), 73 | child: Icon(Icons.search), 74 | ) 75 | ], 76 | ), 77 | margin: EdgeInsets.only(left: 18, right: 18), 78 | decoration: BoxDecoration( 79 | border: Border.all(color: Colors.grey[600]), 80 | ), 81 | ), 82 | ], 83 | ), 84 | ), 85 | ), 86 | ), 87 | SliverList( 88 | delegate: SliverChildListDelegate([ 89 | state.isLoading 90 | ? ShimmerList() 91 | : ListView.builder( 92 | shrinkWrap: true, 93 | physics: NeverScrollableScrollPhysics(), 94 | itemCount: state.categories.length, 95 | itemBuilder: (context, pos) { 96 | return CategoryBanner(state.categories[pos], () { 97 | Navigator.push(context, 98 | MaterialPageRoute(builder: (BuildContext context) { 99 | final item = state.categories[pos]; 100 | return ProductListScreen(category: item); 101 | })); 102 | }); 103 | }) 104 | ])) 105 | ], 106 | ), 107 | ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /lib/screens/checkout_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/screens/order_review_screen.dart'; 3 | import 'package:cool_store/screens/order_summary_screen.dart'; 4 | import 'package:cool_store/screens/shipping_address_screen.dart'; 5 | import 'package:cool_store/screens/shipping_methods_screen.dart'; 6 | import 'package:flutter/material.dart'; 7 | 8 | // Todo add layout for address input and search for shipping 9 | class Checkout extends StatefulWidget { 10 | final Map productsInCart; 11 | final Map productVariationsInCart; 12 | 13 | Checkout({this.productsInCart, this.productVariationsInCart}); 14 | 15 | @override 16 | _CheckoutState createState() => _CheckoutState(); 17 | } 18 | 19 | class _CheckoutState extends State { 20 | int _currentPage = 0; 21 | PageController _pageController = PageController(initialPage: 0); 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return Scaffold( 26 | appBar: AppBar( 27 | title: Text('CHECKOUT'), 28 | ), 29 | body: SafeArea( 30 | child: Padding( 31 | padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 18), 32 | child: PageView.builder( 33 | itemCount: 4, 34 | controller: _pageController, 35 | physics: NeverScrollableScrollPhysics(), 36 | itemBuilder: (BuildContext context, int index) { 37 | switch (index) { 38 | case 0: 39 | return ShippingAddressScreen( 40 | function: nextPage, 41 | ); 42 | case 1: 43 | return ShippingMethodsScreen( 44 | onNextPressed: nextPage, 45 | onBackPressed: previousPage, 46 | ); 47 | case 2: 48 | return OrderReview( 49 | onButtonClicked: nextPage, 50 | ); 51 | case 3: 52 | return OrderSummary(); 53 | } 54 | return Container(); 55 | }, 56 | ), 57 | )), 58 | ); 59 | } 60 | 61 | nextPage() { 62 | print('Next page $_currentPage'); 63 | if (_currentPage == 3) return; 64 | setState(() { 65 | _currentPage++; 66 | _pageController.animateToPage(_currentPage, 67 | duration: Duration(milliseconds: 400), curve: Curves.ease); 68 | }); 69 | } 70 | 71 | previousPage() { 72 | print('prev page $_currentPage'); 73 | if (_currentPage == 0) return; 74 | setState(() { 75 | _currentPage--; 76 | _pageController.animateToPage(_currentPage, 77 | duration: Duration(milliseconds: 400), curve: Curves.ease); 78 | }); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/screens/detail_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/states/detail_state.dart'; 3 | import 'package:cool_store/widgets/ShimmerList.dart'; 4 | import 'package:cool_store/widgets/ImageView.dart'; 5 | import 'package:cool_store/widgets/ProductCard.dart'; 6 | import 'package:cool_store/widgets/ProductDescription.dart'; 7 | import 'package:cool_store/widgets/ProductTitle.dart'; 8 | import 'package:cool_store/widgets/QuantityChooser.dart'; 9 | import 'package:cool_store/widgets/VariationsView.dart'; 10 | import 'package:flutter/material.dart'; 11 | import 'package:flutter/widgets.dart'; 12 | import 'package:provider/provider.dart'; 13 | 14 | class DetailScreen extends StatefulWidget { 15 | final Product _product; 16 | 17 | DetailScreen(this._product); 18 | 19 | @override 20 | _DetailScreenState createState() => _DetailScreenState(); 21 | } 22 | 23 | class _DetailScreenState extends State { 24 | @override 25 | Widget build(BuildContext context) { 26 | return ChangeNotifierProvider( 27 | builder: (_) => DetailState(widget._product.id), 28 | child: Scaffold( 29 | body: SafeArea( 30 | child: CustomScrollView( 31 | slivers: [ 32 | SliverAppBar( 33 | backgroundColor: Theme.of(context).primaryColor, 34 | elevation: 0, 35 | title: Text( 36 | widget._product.name, 37 | style: TextStyle( 38 | fontFamily: 'Raleway', fontWeight: FontWeight.w500), 39 | ), 40 | centerTitle: false, 41 | pinned: true, 42 | floating: false, 43 | ), 44 | SliverList( 45 | delegate: SliverChildListDelegate([ 46 | ImageView(), 47 | Padding( 48 | padding: 49 | const EdgeInsets.symmetric(horizontal: 15, vertical: 8), 50 | child: Column( 51 | children: [ 52 | ProductTitle(widget._product), 53 | VariationsView(widget._product), 54 | Row( 55 | children: [ 56 | Expanded( 57 | flex: 4, 58 | child: Consumer( 59 | builder: (context, state, child) { 60 | return FlatButton.icon( 61 | onPressed: () { 62 | try { 63 | state.addToCart(context); 64 | _showSnackbar(context, 'ADDED TO CART'); 65 | } catch (e) { 66 | _showSnackbar(context, e.toString()); 67 | } 68 | }, 69 | textColor: Colors.white, 70 | color: Theme.of(context).accentColor, 71 | icon: Icon( 72 | Icons.add_shopping_cart, 73 | color: Colors.white, 74 | ), 75 | label: Text( 76 | 'ADD TO CART', 77 | )); 78 | }), 79 | ), 80 | Expanded( 81 | child: QuantityChooser(), 82 | ) 83 | ], 84 | ), 85 | ProductDescription(widget._product), 86 | Column( 87 | crossAxisAlignment: CrossAxisAlignment.start, 88 | mainAxisAlignment: MainAxisAlignment.start, 89 | children: [ 90 | Padding( 91 | padding: 92 | const EdgeInsets.symmetric(vertical: 16.0), 93 | child: Text( 94 | 'YOU MIGHT LIKE', 95 | style: TextStyle( 96 | fontSize: 17, fontFamily: 'Raleway'), 97 | ), 98 | ), 99 | Consumer( 100 | builder: (context, state, child) { 101 | return Container( 102 | height: 103 | MediaQuery.of(context).size.height / 2.7, 104 | child: state.isRelatedProductsLoading 105 | ? ShimmerList( 106 | direction: Axis.horizontal, 107 | ) 108 | : ListView.builder( 109 | shrinkWrap: true, 110 | itemCount: state.relatedProducts.length, 111 | scrollDirection: Axis.horizontal, 112 | itemBuilder: (context, pos) { 113 | return ProductDisplayCard( 114 | onPressed: () { 115 | Navigator.push( 116 | context, 117 | MaterialPageRoute( 118 | fullscreenDialog: true, 119 | builder: (context) => 120 | DetailScreen(state 121 | .relatedProducts[ 122 | pos]))); 123 | }, 124 | product: state.relatedProducts[pos], 125 | margin: 2, 126 | ); 127 | }), 128 | ); 129 | }) 130 | ], 131 | ) 132 | ], 133 | ), 134 | ), 135 | ])) 136 | ], 137 | ), 138 | ), 139 | )); 140 | } 141 | 142 | _showSnackbar(BuildContext context, String text) { 143 | Scaffold.of(context).showSnackBar( 144 | SnackBar(duration: Duration(seconds: 1), content: Text(text))); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /lib/screens/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/screens/detail_screen.dart'; 2 | import 'package:cool_store/states/home_state.dart'; 3 | import 'package:cool_store/utils/constants.dart'; 4 | import 'package:cool_store/widgets/OffersBanner.dart'; 5 | import 'package:cool_store/widgets/ProductCard.dart'; 6 | import 'package:cool_store/widgets/ShimmerGrid.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:provider/provider.dart'; 9 | 10 | class HomeScreen extends StatelessWidget { 11 | @override 12 | Widget build(BuildContext context) { 13 | final HomeState state = Provider.of(context); 14 | return SafeArea( 15 | child: CustomScrollView( 16 | slivers: [ 17 | SliverAppBar( 18 | expandedHeight: Constants.screenAwareSize(300, context), 19 | flexibleSpace: FlexibleSpaceBar( 20 | background: Container( 21 | child: Column( 22 | crossAxisAlignment: CrossAxisAlignment.start, 23 | mainAxisAlignment: MainAxisAlignment.start, 24 | children: [ 25 | Padding( 26 | padding: const EdgeInsets.only( 27 | left: 18.0, right: 18, top: 18, bottom: 20), 28 | child: Text( 29 | 'COOL STORE', 30 | style: TextStyle( 31 | fontWeight: FontWeight.bold, 32 | fontFamily: 'Raleway', 33 | fontSize: 40), 34 | ), 35 | ), 36 | Container( 37 | height: Constants.screenAwareSize(200, context), 38 | width: MediaQuery.of(context).size.width, 39 | child: OffersBanner(), 40 | ) 41 | ], 42 | ), 43 | )), 44 | ), 45 | SliverList( 46 | delegate: SliverChildListDelegate([ 47 | Padding( 48 | padding: EdgeInsets.all(18), 49 | child: Row( 50 | children: [ 51 | Text( 52 | 'BEST SELLERS', 53 | style: TextStyle( 54 | fontFamily: 'Raleway', fontWeight: FontWeight.bold), 55 | ), 56 | Spacer(), 57 | FlatButton( 58 | onPressed: () {}, 59 | child: Text('SEE ALL', 60 | style: TextStyle(fontFamily: 'Raleway', fontSize: 12)), 61 | ) 62 | ], 63 | ), 64 | ), 65 | state.isLoading 66 | ? ShimmerGrid() 67 | : GridView.builder( 68 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 69 | childAspectRatio: .6, 70 | crossAxisCount: 2, 71 | crossAxisSpacing: 1, 72 | mainAxisSpacing: 1), 73 | itemBuilder: (context, pos) => ProductDisplayCard( 74 | onPressed: () { 75 | Navigator.push( 76 | context, 77 | MaterialPageRoute( 78 | builder: (_) => 79 | DetailScreen(state.products[pos]), 80 | fullscreenDialog: true)); 81 | }, 82 | product: state.products[pos], 83 | ), 84 | physics: NeverScrollableScrollPhysics(), 85 | shrinkWrap: true, 86 | itemCount: state.products.length, 87 | ), 88 | ])) 89 | ], 90 | ), 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/screens/order_review_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/states/cart_state.dart'; 3 | import 'package:cool_store/utils/constants.dart'; 4 | import 'package:cool_store/widgets/CartItem.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'detail_screen.dart'; 8 | 9 | class OrderReview extends StatelessWidget { 10 | final Function onButtonClicked; 11 | 12 | OrderReview({this.onButtonClicked}); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | final state = Provider.of(context); 17 | return SingleChildScrollView( 18 | child: Column( 19 | crossAxisAlignment: CrossAxisAlignment.start, 20 | children: [ 21 | Container( 22 | child: Text( 23 | 'Total items ${state.cartProducts.length}', 24 | style: TextStyle( 25 | fontWeight: FontWeight.w300, 26 | fontFamily: 'Raleway', 27 | ), 28 | ), 29 | padding: EdgeInsets.symmetric(horizontal: 17, vertical: 2), 30 | ), 31 | buildCartListView(state), 32 | Container( 33 | child: Column( 34 | mainAxisSize: MainAxisSize.max, 35 | mainAxisAlignment: MainAxisAlignment.end, 36 | crossAxisAlignment: CrossAxisAlignment.center, 37 | children: [ 38 | // coupon view 39 | buildCouponView(context, state), 40 | 41 | Padding( 42 | padding: const EdgeInsets.only(top: 18.0), 43 | child: ListTile( 44 | leading: Text('SUB TOTAL'), 45 | trailing: Text('...'), 46 | ), 47 | ), 48 | 49 | RawMaterialButton( 50 | onPressed: onButtonClicked, 51 | fillColor: Theme.of(context).accentColor, 52 | constraints: BoxConstraints( 53 | minWidth: MediaQuery.of(context).size.width, 54 | minHeight: 45), 55 | elevation: 0, 56 | child: Text( 57 | 'PLACE ORDER', 58 | style: 59 | TextStyle(fontFamily: 'Raleway', color: Colors.white), 60 | ), 61 | ), 62 | ], 63 | ), 64 | ), 65 | ], 66 | ), 67 | ); 68 | } 69 | 70 | ListView buildCartListView(CartState state) { 71 | return ListView.builder( 72 | shrinkWrap: true, 73 | physics: NeverScrollableScrollPhysics(), 74 | itemCount: state.cartProducts.length, 75 | itemBuilder: (context, pos) { 76 | final item = state.cartProducts[pos]; 77 | Product testProduct = state.cartProducts[pos].product; 78 | ProductVariation testProductVariation = 79 | state.cartProducts[pos].productVariation; 80 | int quantity = state.cartProducts[pos].quantity; 81 | 82 | return CartItem( 83 | product: testProduct, 84 | variation: testProductVariation, 85 | quantity: quantity, 86 | onPrimaryButtonPressed: () { 87 | state.addProductToWishList(item); 88 | }, 89 | onRemovePressed: () { 90 | state.removeProductFromCart(item); 91 | }, 92 | onTap: () { 93 | Navigator.of(context).push(MaterialPageRoute( 94 | builder: (context) => DetailScreen(testProduct), 95 | fullscreenDialog: true)); 96 | }, 97 | ); 98 | }); 99 | } 100 | 101 | Container buildCouponView(BuildContext context, CartState state) { 102 | return Container( 103 | height: Constants.screenAwareSize(35, context), 104 | decoration: BoxDecoration(border: Border.all(color: Colors.grey[600])), 105 | margin: EdgeInsets.symmetric(horizontal: 12), 106 | padding: EdgeInsets.symmetric(horizontal: 8), 107 | child: Row( 108 | mainAxisAlignment: MainAxisAlignment.center, 109 | crossAxisAlignment: CrossAxisAlignment.center, 110 | mainAxisSize: MainAxisSize.max, 111 | children: [ 112 | Expanded( 113 | flex: 2, 114 | child: TextField( 115 | onChanged: (value) { 116 | // state.setCouponCode(value); 117 | }, 118 | onSubmitted: (value) { 119 | // TODO check for code 120 | state.setCouponCode(value); 121 | }, 122 | decoration: InputDecoration( 123 | hintText: 'Coupon Code', 124 | hintStyle: TextStyle( 125 | fontFamily: 'Raleway', 126 | color: Theme.of(context).textTheme.subhead.color), 127 | focusedBorder: InputBorder.none, 128 | disabledBorder: InputBorder.none, 129 | enabledBorder: InputBorder.none, 130 | errorBorder: InputBorder.none, 131 | focusedErrorBorder: InputBorder.none), 132 | ), 133 | ), 134 | Expanded( 135 | child: FlatButton.icon( 136 | onPressed: () {}, 137 | icon: Icon(Icons.local_offer), 138 | label: Text('Apply')), 139 | ) 140 | ], 141 | ), 142 | ); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /lib/screens/order_summary_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/cart_state.dart'; 2 | import 'package:cool_store/states/checkout_state.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class OrderSummary extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | final state = Provider.of(context); 10 | return SingleChildScrollView( 11 | child: Column( 12 | mainAxisAlignment: MainAxisAlignment.center, 13 | mainAxisSize: MainAxisSize.max, 14 | crossAxisAlignment: CrossAxisAlignment.center, 15 | children: [ 16 | Text('Order placed', 17 | style: TextStyle( 18 | color: Theme.of(context).accentColor, 19 | fontFamily: 'Raleway', 20 | fontSize: 40)), 21 | SizedBox( 22 | height: 40, 23 | ), 24 | RawMaterialButton( 25 | onPressed: () { 26 | state.clearCart(); 27 | Navigator.pop(context); 28 | }, 29 | fillColor: Theme.of(context).accentColor, 30 | constraints: BoxConstraints( 31 | minWidth: MediaQuery.of(context).size.width, minHeight: 45), 32 | elevation: 0, 33 | child: Text( 34 | 'Continue Shopping', 35 | style: TextStyle(fontFamily: 'Raleway', color: Colors.white), 36 | ), 37 | ), 38 | ], 39 | ), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/screens/product_list_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/category.dart'; 2 | import 'package:cool_store/screens/detail_screen.dart'; 3 | import 'package:cool_store/states/product_list_state.dart'; 4 | import 'package:cool_store/utils/constants.dart'; 5 | import 'package:cool_store/widgets/ProductCard.dart'; 6 | import 'package:cool_store/widgets/ShimmerGrid.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:provider/provider.dart'; 9 | 10 | class ProductListScreen extends StatelessWidget { 11 | final Category category; 12 | 13 | ProductListScreen({this.category}); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | body: ChangeNotifierProvider( 19 | builder: (_) => ProductListState(category.id), 20 | child: Consumer( 21 | builder: (context, state, child) { 22 | return SafeArea( 23 | child: CustomScrollView( 24 | slivers: [ 25 | SliverAppBar( 26 | title: Text('COOL STORE'), 27 | bottom: buildPreferenceView(context, state), 28 | ), 29 | SliverList( 30 | delegate: SliverChildListDelegate([ 31 | state.isLoading 32 | ? ShimmerGrid() 33 | : Column( 34 | children: [ 35 | buildDecorationView(context), 36 | buildCategoryProductsView(state) 37 | ], 38 | ) 39 | ])) 40 | ], 41 | ), 42 | ); 43 | }, 44 | )), 45 | ); 46 | } 47 | 48 | GridView buildCategoryProductsView(ProductListState state) { 49 | return GridView.builder( 50 | itemCount: state.products.length, 51 | physics: NeverScrollableScrollPhysics(), 52 | shrinkWrap: true, 53 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 54 | crossAxisCount: 2, 55 | childAspectRatio: .6, 56 | mainAxisSpacing: 2, 57 | crossAxisSpacing: 2), 58 | itemBuilder: (context, pos) { 59 | return ProductDisplayCard( 60 | onPressed: () { 61 | Navigator.push( 62 | context, 63 | MaterialPageRoute( 64 | builder: (_) => DetailScreen(state.products[pos]), 65 | fullscreenDialog: true)); 66 | }, 67 | product: state.products[pos], 68 | ); 69 | }); 70 | } 71 | 72 | Container buildDecorationView(BuildContext context) { 73 | return Container( 74 | padding: EdgeInsets.all(17), 75 | child: Column( 76 | children: [ 77 | RichText( 78 | text: TextSpan( 79 | children: [ 80 | TextSpan( 81 | text: ' NEW ARRIVALS - ${category.name}', 82 | style: DefaultTextStyle.of(context).style.copyWith( 83 | fontFamily: 'Raleway', fontWeight: FontWeight.bold)), 84 | TextSpan( 85 | text: ' ( ${category.totalProduct} )', 86 | style: DefaultTextStyle.of(context) 87 | .style 88 | .copyWith(fontWeight: FontWeight.w100)) 89 | ], 90 | ), 91 | ), 92 | Container( 93 | margin: EdgeInsets.all(4), 94 | height: 2, 95 | width: MediaQuery.of(context).size.width / 4, 96 | color: Theme.of(context).accentColor, 97 | ) 98 | ], 99 | ), 100 | ); 101 | } 102 | 103 | PreferredSize buildPreferenceView( 104 | BuildContext context, ProductListState state) { 105 | return PreferredSize( 106 | child: Container( 107 | child: Row( 108 | children: [ 109 | Expanded( 110 | child: FlatButton.icon( 111 | onPressed: () { 112 | _showOptions(context, [ 113 | // 'SORT BY', 114 | 'POPULAR', 115 | 'NEW', 116 | 'PRICE: LOW TO HIGH', 117 | 'PRICE: HIGH TO LOW' 118 | ]); 119 | }, 120 | icon: Icon(Icons.sort), 121 | label: Text('SORT BY'), 122 | )), 123 | Container( 124 | width: 1, 125 | height: 15, 126 | color: Colors.black, 127 | ), 128 | Expanded( 129 | child: FlatButton.icon( 130 | onPressed: () {}, 131 | label: Text('FILTER'), 132 | icon: Icon(Icons.tune), 133 | )) 134 | ], 135 | ), 136 | ), 137 | preferredSize: Size(100, Constants.screenAwareSize(40, context))); 138 | } 139 | 140 | _showOptions(context, List options) { 141 | return showModalBottomSheet( 142 | context: context, 143 | builder: (context) { 144 | return SafeArea( 145 | child: Column( 146 | mainAxisSize: MainAxisSize.min, 147 | children: options 148 | .map((value) => ListTile( 149 | onTap: () { 150 | Navigator.of(context).pop(value); 151 | }, 152 | title: Center( 153 | child: Text( 154 | value, 155 | style: TextStyle(fontFamily: 'Raleway', fontSize: 14), 156 | )), 157 | )) 158 | .toList(), 159 | ), 160 | ); 161 | }); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /lib/screens/search_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/app_state.dart'; 2 | import 'package:cool_store/states/search_state.dart'; 3 | import 'package:cool_store/widgets/InfoView.dart'; 4 | import 'package:cool_store/widgets/ProductCard.dart'; 5 | import 'package:cool_store/widgets/ShimmerGrid.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_svg/svg.dart'; 8 | import 'package:provider/provider.dart'; 9 | 10 | class SearchScreen extends StatefulWidget { 11 | @override 12 | _SearchScreenState createState() => _SearchScreenState(); 13 | } 14 | 15 | class _SearchScreenState extends State { 16 | final TextEditingController _searchController = TextEditingController(); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | final state = Provider.of(context); 21 | return Scaffold( 22 | appBar: AppBar( 23 | leading: IconButton( 24 | icon: Icon(Icons.close), 25 | onPressed: () async { 26 | state.addKeywordsToStorage(); 27 | Navigator.of(context).pop(); 28 | }), 29 | ), 30 | body: SafeArea( 31 | child: CustomScrollView( 32 | slivers: [ 33 | SliverList( 34 | delegate: SliverChildListDelegate([ 35 | Container( 36 | margin: EdgeInsets.all(8), 37 | padding: EdgeInsets.symmetric(horizontal: 8), 38 | decoration: BoxDecoration( 39 | border: Border.all(color: Colors.grey[600])), 40 | child: Row( 41 | mainAxisSize: MainAxisSize.max, 42 | mainAxisAlignment: MainAxisAlignment.center, 43 | crossAxisAlignment: CrossAxisAlignment.center, 44 | children: [ 45 | Expanded( 46 | child: TextField( 47 | controller: _searchController, 48 | onChanged: (value) { 49 | state.clearResult(); 50 | }, 51 | onSubmitted: (value) { 52 | state.setKeyword(value); 53 | }, 54 | decoration: InputDecoration( 55 | focusedErrorBorder: InputBorder.none, 56 | hintText: 'Search for products', 57 | errorBorder: InputBorder.none, 58 | enabledBorder: InputBorder.none, 59 | disabledBorder: InputBorder.none, 60 | focusedBorder: InputBorder.none, 61 | ), 62 | )), 63 | IconButton( 64 | icon: Icon(Icons.clear_all), 65 | onPressed: () { 66 | state.clearResult(); 67 | _searchController.clear(); 68 | }) 69 | ], 70 | ), 71 | ), 72 | state.showKeywords 73 | ? buildKeywords(state) 74 | : state.isResultLoading 75 | ? ShimmerGrid() 76 | : state.searchResult.length > 0 77 | ? buildResultView(state) 78 | : InfoView( 79 | primaryText: 80 | 'We couldn\'t find any matches for ${state.searchKeyword} ', 81 | secondaryText: 82 | 'Maybe your search was too specific, please try searching with another term', 83 | ) 84 | ])) 85 | ], 86 | ), 87 | )); 88 | } 89 | 90 | GridView buildResultView(SearchState state) { 91 | return GridView.builder( 92 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 93 | crossAxisCount: 2, 94 | mainAxisSpacing: 2, 95 | crossAxisSpacing: 2, 96 | childAspectRatio: .6), 97 | itemCount: state.searchResult.length, 98 | shrinkWrap: true, 99 | physics: NeverScrollableScrollPhysics(), 100 | itemBuilder: (context, pos) { 101 | return ProductDisplayCard( 102 | onPressed: () {}, 103 | product: state.searchResult[pos], 104 | ); 105 | }); 106 | } 107 | 108 | ListView buildKeywords(SearchState state) { 109 | return ListView.separated( 110 | physics: NeverScrollableScrollPhysics(), 111 | shrinkWrap: true, 112 | itemCount: state.keyWords.length, 113 | itemBuilder: (context, pos) { 114 | return ListTile( 115 | onTap: () { 116 | _searchController.text = state.keyWords[pos]; 117 | state.setKeyword(state.keyWords[pos]); 118 | }, 119 | onLongPress: () { 120 | state.removeKeyword(state.keyWords[pos]); 121 | }, 122 | title: Text('${state.keyWords[pos]}'), 123 | leading: Icon(Icons.search), 124 | trailing: Icon(Icons.chevron_right), 125 | ); 126 | }, 127 | separatorBuilder: (BuildContext context, int index) => Divider(), 128 | ); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /lib/screens/setting_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/app_state.dart'; 2 | import 'package:cool_store/utils/constants.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class SettingScreen extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | final AppState appState = Provider.of(context); 10 | return SafeArea( 11 | child: CustomScrollView( 12 | slivers: [ 13 | SliverAppBar( 14 | expandedHeight: Constants.screenAwareSize(80, context), 15 | flexibleSpace: FlexibleSpaceBar( 16 | background: Column( 17 | crossAxisAlignment: CrossAxisAlignment.start, 18 | children: [ 19 | Container( 20 | child: Text( 21 | 'Setting', 22 | style: TextStyle( 23 | fontWeight: FontWeight.bold, 24 | fontFamily: 'Raleway', 25 | fontSize: 40), 26 | ), 27 | padding: EdgeInsets.symmetric(horizontal: 17, vertical: 8), 28 | ), 29 | ], 30 | ), 31 | ), 32 | ), 33 | SliverList( 34 | delegate: SliverChildListDelegate([ 35 | ListTile( 36 | onTap: () { 37 | appState.isDark 38 | ? appState.setLightTheme() 39 | : appState.setDarkTheme(); 40 | }, 41 | leading: Icon(Icons.lightbulb_outline), 42 | title: Text('Change Theme'), 43 | ) 44 | ])) 45 | ], 46 | )); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/screens/shipping_methods_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/checkout_state.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | class ShippingMethodsScreen extends StatelessWidget { 6 | final Function onNextPressed; 7 | final Function onBackPressed; 8 | 9 | ShippingMethodsScreen( 10 | {@required this.onNextPressed, @required this.onBackPressed}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | final state = Provider.of(context); 15 | 16 | return SingleChildScrollView( 17 | child: Column( 18 | children: [ 19 | Padding( 20 | padding: const EdgeInsets.all(8.0), 21 | child: Text( 22 | 'Choose Shipping Method', 23 | textAlign: TextAlign.start, 24 | style: TextStyle(fontFamily: 'Raleway-bold', fontSize: 28), 25 | ), 26 | ), 27 | state.isShippingMethodsLoading 28 | ? Center( 29 | child: CircularProgressIndicator(), 30 | ) 31 | : ListView.separated( 32 | shrinkWrap: true, 33 | itemCount: state.shippingMethods.length, 34 | physics: NeverScrollableScrollPhysics(), 35 | itemBuilder: (_, pos) { 36 | final item = state.shippingMethods[pos]; 37 | return ListTile( 38 | isThreeLine: true, 39 | leading: state.selectedShippingMethod.isEqual(item) 40 | ? Icon( 41 | Icons.check, 42 | color: Theme.of(context).accentColor, 43 | ) 44 | : Icon(Icons.radio_button_unchecked), 45 | title: Text( 46 | '${item.title}', 47 | style: TextStyle( 48 | fontFamily: "Raleway", 49 | color: state.selectedShippingMethod.isEqual(item) 50 | ? Theme.of(context).accentColor 51 | : Theme.of(context).textTheme.title.color), 52 | ), 53 | subtitle: Text( 54 | '${item.description}', 55 | style: TextStyle(fontFamily: "Raleway"), 56 | ), 57 | onTap: () { 58 | state.setShippingMethod(item); 59 | }, 60 | ); 61 | }, 62 | separatorBuilder: (__, _) => Divider(), 63 | ), 64 | SizedBox( 65 | height: 30, 66 | ), 67 | RawMaterialButton( 68 | onPressed: onNextPressed, 69 | constraints: BoxConstraints( 70 | minWidth: MediaQuery.of(context).size.width, minHeight: 45), 71 | fillColor: Theme.of(context).accentColor, 72 | elevation: 0, 73 | child: Text( 74 | 'REVIEW ORDER', 75 | style: TextStyle(fontFamily: 'Raleway', color: Colors.white), 76 | ), 77 | ), 78 | RawMaterialButton( 79 | onPressed: onBackPressed, 80 | constraints: BoxConstraints( 81 | minWidth: MediaQuery.of(context).size.width, minHeight: 25), 82 | elevation: 0, 83 | child: Text( 84 | 'EDIT ADDRESS', 85 | style: TextStyle( 86 | fontFamily: 'Raleway', color: Theme.of(context).accentColor), 87 | ), 88 | ), 89 | ], 90 | ), 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/screens/wishlist_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/app_state.dart'; 2 | import 'package:cool_store/states/cart_state.dart'; 3 | import 'package:cool_store/widgets/CartItem.dart'; 4 | import 'package:cool_store/widgets/InfoView.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:provider/provider.dart'; 7 | 8 | class WishListScreen extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | final state = Provider.of(context); 12 | final theme = Theme.of(context); 13 | return Scaffold( 14 | body: CustomScrollView( 15 | slivers: [ 16 | SliverAppBar(), 17 | SliverList( 18 | delegate: SliverChildListDelegate([ 19 | state.wishListCartProducts.length > 0 20 | ? ListView.builder( 21 | physics: NeverScrollableScrollPhysics(), 22 | shrinkWrap: true, 23 | itemCount: state.wishListCartProducts.length, 24 | itemBuilder: (context, pos) { 25 | // Product product = 26 | // state.wishListProducts.keys.elementAt(pos); 27 | // ProductVariation variation = 28 | // state.wishListProducts.values.elementAt(pos); 29 | final item = state.wishListCartProducts[pos]; 30 | final product = item.product; 31 | final variation = item.productVariation; 32 | return CartItem( 33 | product: product, 34 | variation: variation, 35 | primaryTitle: 'Move to cart', 36 | onRemovePressed: () { 37 | state.removeProductFromWishList(item); 38 | }, 39 | onPrimaryButtonPressed: () { 40 | state.removeProductAndAddToCart(item); 41 | }, 42 | ); 43 | }) 44 | : buildEmptyView(theme, context) 45 | ])) 46 | ], 47 | ), 48 | ); 49 | } 50 | 51 | Column buildEmptyView(ThemeData theme, BuildContext context) { 52 | return Column( 53 | mainAxisAlignment: MainAxisAlignment.center, 54 | crossAxisAlignment: CrossAxisAlignment.center, 55 | mainAxisSize: MainAxisSize.max, 56 | children: [ 57 | InfoView( 58 | path: 'assets/list.svg', 59 | iconColor: theme.iconTheme.color.withOpacity(.8), 60 | primaryText: 'Empty wishlist', 61 | ), 62 | Padding( 63 | padding: const EdgeInsets.all(8.0), 64 | child: FlatButton( 65 | color: theme.accentColor, 66 | onPressed: () { 67 | Navigator.pop(context); 68 | Provider.of(context).navigateToHome(); 69 | }, 70 | child: Text( 71 | 'START SHOPPING', 72 | style: TextStyle(color: Colors.white, fontFamily: 'Raleway'), 73 | )), 74 | ) 75 | ], 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/services/woocommerce_api.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import "dart:collection"; 3 | import 'dart:convert'; 4 | import "dart:core"; 5 | import 'dart:io'; 6 | import "dart:math"; 7 | import 'package:crypto/crypto.dart' as crypto; 8 | import 'package:flutter/cupertino.dart'; 9 | import 'package:http/http.dart' as http; 10 | 11 | class QueryString { 12 | static Map parse(String query) { 13 | var search = new RegExp('([^&=]+)=?([^&]*)'); 14 | var result = new Map(); 15 | 16 | // Get rid off the beginning ? in query strings. 17 | if (query.startsWith('?')) query = query.substring(1); 18 | // A custom decoder. 19 | decode(String s) => Uri.decodeComponent(s.replaceAll('+', ' ')); 20 | 21 | // Go through all the matches and build the result map. 22 | for (Match match in search.allMatches(query)) { 23 | result[decode(match.group(1))] = decode(match.group(2)); 24 | } 25 | return result; 26 | } 27 | } 28 | 29 | class WooCommerceAPI { 30 | String url; 31 | String consumerKey; 32 | String consumerSecret; 33 | bool isHttps; 34 | 35 | WooCommerceAPI({this.url, this.consumerKey, this.consumerSecret}) { 36 | if (this.url.startsWith("https")) { 37 | this.isHttps = true; 38 | } else { 39 | this.isHttps = false; 40 | } 41 | } 42 | 43 | _getOAuthURL(String requestMethod, String endpoint) { 44 | var consumerKey = this.consumerKey; 45 | var consumerSecret = this.consumerSecret; 46 | 47 | var token = ""; 48 | var url = this.url + "/wp-json/wc/v3/" + endpoint; 49 | var containsQueryParams = url.contains("?"); 50 | 51 | // If website is HTTPS based, no need for OAuth, just return the URL with CS and CK as query params 52 | if (this.isHttps == true) { 53 | return url + 54 | (containsQueryParams == true 55 | ? "&consumer_key=" + 56 | this.consumerKey + 57 | "&consumer_secret=" + 58 | this.consumerSecret 59 | : "?consumer_key=" + 60 | this.consumerKey + 61 | "&consumer_secret=" + 62 | this.consumerSecret); 63 | } 64 | 65 | var rand = new Random(); 66 | var codeUnits = new List.generate(10, (index) { 67 | return rand.nextInt(26) + 97; 68 | }); 69 | 70 | var nonce = new String.fromCharCodes(codeUnits); 71 | int timestamp = (new DateTime.now().millisecondsSinceEpoch ~/ 1000).toInt(); 72 | 73 | var method = requestMethod; 74 | var parameters = "oauth_consumer_key=" + 75 | consumerKey + 76 | "&oauth_nonce=" + 77 | nonce + 78 | "&oauth_signature_method=HMAC-SHA1&oauth_timestamp=" + 79 | timestamp.toString() + 80 | "&oauth_token=" + 81 | token + 82 | "&oauth_version=1.0&"; 83 | 84 | if (containsQueryParams == true) { 85 | parameters = parameters + url.split("?")[1]; 86 | } else { 87 | parameters = parameters.substring(0, parameters.length - 1); 88 | } 89 | 90 | Map params = QueryString.parse(parameters); 91 | Map treeMap = new SplayTreeMap(); 92 | treeMap.addAll(params); 93 | 94 | String parameterString = ""; 95 | 96 | for (var key in treeMap.keys) { 97 | parameterString = parameterString + 98 | Uri.encodeQueryComponent(key) + 99 | "=" + 100 | treeMap[key] + 101 | "&"; 102 | } 103 | 104 | parameterString = parameterString.substring(0, parameterString.length - 1); 105 | 106 | var baseString = method + 107 | "&" + 108 | Uri.encodeQueryComponent( 109 | containsQueryParams == true ? url.split("?")[0] : url) + 110 | "&" + 111 | Uri.encodeQueryComponent(parameterString); 112 | 113 | var signingKey = consumerSecret + "&" + token; 114 | 115 | var hmacSha1 = 116 | new crypto.Hmac(crypto.sha1, utf8.encode(signingKey)); // HMAC-SHA1 117 | var signature = hmacSha1.convert(utf8.encode(baseString)); 118 | 119 | var finalSignature = base64Encode(signature.bytes); 120 | 121 | var requestUrl = ""; 122 | 123 | if (containsQueryParams == true) { 124 | requestUrl = url.split("?")[0] + 125 | "?" + 126 | parameterString + 127 | "&oauth_signature=" + 128 | Uri.encodeQueryComponent(finalSignature); 129 | } else { 130 | requestUrl = url + 131 | "?" + 132 | parameterString + 133 | "&oauth_signature=" + 134 | Uri.encodeQueryComponent(finalSignature); 135 | } 136 | 137 | // print('network: $requestUrl'); 138 | 139 | return requestUrl; 140 | } 141 | 142 | Future getAsync(String endPoint, {Map data}) async { 143 | // debugPrint('int woocommerceAPI getAsync method'); 144 | var url = this._getOAuthURL("GET", endPoint); 145 | 146 | //// print('$url'); 147 | // if (data != null) { 148 | // var client = new http.Client(); 149 | // Map headers = HashMap(); 150 | // headers.update(HttpHeaders.contentTypeHeader, 151 | // (_) => 'application/json; charset=utf-8', 152 | // ifAbsent: () => 'application/json; charset=utf-8'); 153 | // headers.update(HttpHeaders.cacheControlHeader, (_) => 'no-cache', 154 | // ifAbsent: () => 'no-cache'); 155 | // print('${Uri.parse(url)} body: ${json.encode(data)}'); 156 | // var response = await client.post(Uri.parse(url), 157 | // headers: headers, body: json.encode(data)); 158 | // print('response ${response.body}'); 159 | // return json.decode(response.body); 160 | // } else { 161 | // print('$url'); 162 | final response = await http.get(url); 163 | 164 | return json.decode(response.body); 165 | // } 166 | } 167 | 168 | Future postAsync(String endPoint, Map data) async { 169 | var url = this._getOAuthURL("POST", endPoint); 170 | 171 | var client = new http.Client(); 172 | // var request = new http.Request('POST', Uri.parse(url)); 173 | // request.headers[HttpHeaders.contentTypeHeader] = 174 | // 'application/json; charset=utf-8'; 175 | // request.headers[HttpHeaders.cacheControlHeader] = "no-cache"; 176 | // request.body = json.encode(data); 177 | // 178 | // var response = 179 | // await client.send(request).then((res) => res.stream.bytesToString()); 180 | // var dataResponse = await json.decode(response); 181 | // return dataResponse; 182 | Map headers = HashMap(); 183 | headers.update( 184 | HttpHeaders.contentTypeHeader, (_) => 'application/json; charset=utf-8', 185 | ifAbsent: () => 'application/json; charset=utf-8'); 186 | headers.update(HttpHeaders.cacheControlHeader, (_) => 'no-cache', 187 | ifAbsent: () => 'no-cache'); 188 | var response = await client.post(Uri.parse(url), 189 | headers: headers, body: json.encode(data)); 190 | print('response ${response.body}'); 191 | return json.decode(response.body); 192 | } 193 | 194 | Future putAsync(String endPoint, Map data) async { 195 | var url = this._getOAuthURL("PUT", endPoint); 196 | 197 | print('url: $url'); 198 | var client = new http.Client(); 199 | // var request = new http.Request('PUT', Uri.parse(url)); 200 | // request.headers[HttpHeaders.contentTypeHeader] = 201 | // 'application/json; charset=utf-8'; 202 | // request.headers[HttpHeaders.cacheControlHeader] = "no-cache"; 203 | // request.body = json.encode(data); 204 | 205 | // print( 206 | // 'request : $request body ${request.body} headers: ${request.headers}'); 207 | // var response = 208 | // await client.send(request).then((res) => res.stream.bytesToString()); 209 | // var dataResponse = await json.decode(response); 210 | // print('data response: $dataResponse'); 211 | Map headers = HashMap(); 212 | headers.update( 213 | HttpHeaders.contentTypeHeader, (_) => 'application/json; charset=utf-8', 214 | ifAbsent: () => 'application/json; charset=utf-8'); 215 | headers.update(HttpHeaders.cacheControlHeader, (_) => 'no-cache', 216 | ifAbsent: () => 'no-cache'); 217 | var response = await client.put(Uri.parse(url), 218 | headers: headers, body: json.encode(data)); 219 | print('response ${response.body}'); 220 | return json.decode(response.body); 221 | } 222 | 223 | void dispose() {} 224 | } 225 | -------------------------------------------------------------------------------- /lib/states/app_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/utils/constants.dart'; 2 | import 'package:extended_image/extended_image.dart'; 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:shared_preferences/shared_preferences.dart'; 6 | 7 | class AppState extends ChangeNotifier { 8 | ThemeData _themeData = Constants.lightTheme; 9 | bool isDark = false; 10 | int _selectedScreenIndex = 0; 11 | Widget _selectedScreen; 12 | List _screens; 13 | 14 | AppState({@required initialScreen, @required screens}) { 15 | _selectedScreen = initialScreen; 16 | _screens = screens; 17 | _reteriveThemePreference(); 18 | } 19 | 20 | Widget get selectedScreen => _selectedScreen; 21 | 22 | List get screens => _screens; 23 | 24 | ThemeData getTheme() => _themeData; 25 | 26 | _setTheme(ThemeData themeData) { 27 | _themeData = themeData; 28 | notifyListeners(); 29 | _saveThemePreference(); 30 | } 31 | 32 | int get selectedScreenIndex => _selectedScreenIndex; 33 | 34 | setScreenIndex(int pos) { 35 | _selectedScreenIndex = pos; 36 | _selectedScreen = _screens[pos]; 37 | notifyListeners(); 38 | } 39 | 40 | changeScreenTo(Widget widget) { 41 | _selectedScreenIndex = _screens.indexOf(widget); 42 | _selectedScreen = _screens[_selectedScreenIndex]; 43 | notifyListeners(); 44 | } 45 | 46 | setDarkTheme() { 47 | isDark = true; 48 | _setTheme(Constants.darkTheme); 49 | } 50 | 51 | setLightTheme() { 52 | isDark = false; 53 | _setTheme(Constants.lightTheme); 54 | } 55 | 56 | _saveThemePreference() async { 57 | SharedPreferences preferences = await SharedPreferences.getInstance(); 58 | preferences.setBool(Constants.kLocalKey['isDarkTheme'], isDark); 59 | } 60 | 61 | _reteriveThemePreference() async { 62 | SharedPreferences preferences = await SharedPreferences.getInstance(); 63 | if (preferences.containsKey(Constants.kLocalKey['isDarkTheme'])) { 64 | isDark = preferences.getBool(Constants.kLocalKey['isDarkTheme']); 65 | isDark ? setDarkTheme() : setLightTheme(); 66 | } 67 | } 68 | 69 | void navigateToHome() { 70 | setScreenIndex(0); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/states/cart_state.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | import 'dart:convert'; 3 | 4 | import 'package:cool_store/models/payment.dart'; 5 | import 'package:cool_store/models/product.dart'; 6 | import 'package:cool_store/models/user.dart'; 7 | import 'package:cool_store/utils/constants.dart'; 8 | import 'package:flutter/foundation.dart'; 9 | import 'package:localstorage/localstorage.dart'; 10 | 11 | class CartState extends ChangeNotifier { 12 | // product and id 13 | Map _products; 14 | 15 | // product id and the quantity 16 | Map _productsInCart; 17 | 18 | Map get productsInCart => 19 | _productsInCart; // products list in cart 20 | 21 | //product id and variations 22 | Map _productVariationsInCart; 23 | 24 | Map get productVariationsInCart => 25 | _productVariationsInCart; 26 | 27 | double totalCartAmount = 0; 28 | 29 | Map get products => _products; // addProduct( 30 | 31 | Map _wishListProducts = HashMap(); 32 | 33 | Map get wishListProducts => _wishListProducts; 34 | 35 | // product id and quantity selected 36 | Map _productQuantityInCart; 37 | 38 | Map get productQuantityInCart => _productQuantityInCart; 39 | 40 | //TODO update according to shipping methods 41 | double totalCartExtraCharge = 200; 42 | double totalCartPayableAmount = 0; 43 | 44 | Address address; 45 | PaymentMethod paymentMethod; 46 | 47 | String couponCode; 48 | 49 | List cartProducts = List(); 50 | List wishListCartProducts = List(); 51 | 52 | CartState() { 53 | _products = HashMap(); 54 | _productsInCart = HashMap(); 55 | _productVariationsInCart = HashMap(); 56 | _productQuantityInCart = HashMap(); 57 | address = Address( 58 | zipCode: '343905', 59 | firstName: 'mithilesh', 60 | lastName: 'parmar', 61 | email: 'test@cool.com', 62 | street: 'vit road', 63 | city: 'jaipur', 64 | state: 'Rajasthan', 65 | country: 'in', 66 | phoneNumber: '19863921631'); 67 | paymentMethod = PaymentMethod( 68 | id: '1', title: 'cod', description: 'cash on delivery', enabled: true); 69 | _loadFromLocalStorage(); 70 | calculateTotalCartAmount(); 71 | } 72 | 73 | addProductToCart( 74 | Product product, 75 | ProductVariation variation, 76 | int quantity, 77 | ) { 78 | cartProducts.add(CartProduct( 79 | productVariation: variation, product: product, quantity: quantity)); 80 | // _productsInCart.update(product.id.toString(), (_) => quantity, 81 | // ifAbsent: () => quantity); 82 | // _products.update(product.id.toString(), (_) => product, 83 | // ifAbsent: () => product); 84 | // _productVariationsInCart.update(product.id.toString(), (_) => variation, 85 | // ifAbsent: () => variation); 86 | totalCartAmount += double.parse(variation.price); 87 | notifyListeners(); 88 | _saveProductsToLocalStorage(); 89 | } 90 | 91 | // Save products to local storage 92 | _saveProductsToLocalStorage() async { 93 | final LocalStorage _localStorage = LocalStorage( 94 | Constants.APP_FOLDER, 95 | ); 96 | 97 | try { 98 | final ready = await _localStorage.ready; 99 | if (ready) { 100 | await _localStorage.setItem( 101 | Constants.kLocalKey['productsInCart'], json.encode(cartProducts)); 102 | } 103 | } catch (e) { 104 | throw e; 105 | } 106 | } 107 | 108 | _loadFromLocalStorage() async { 109 | final LocalStorage _localStorage = LocalStorage(Constants.APP_FOLDER); 110 | try { 111 | final ready = await _localStorage.ready; 112 | if (ready) { 113 | if (await _localStorage 114 | .getItem(Constants.kLocalKey['productsInCart']) != 115 | null) { 116 | final localJson = jsonDecode(await _localStorage 117 | .getItem(Constants.kLocalKey['productsInCart'])); 118 | localJson.forEach((value) { 119 | final item = CartProduct.fromJson(value); 120 | cartProducts.add(item); 121 | 122 | // _productsInCart.update( 123 | // item.product.id.toString(), (_) => item.quantity, 124 | // ifAbsent: () => item.quantity); 125 | // _products.update(item.product.id.toString(), (_) => item.product, 126 | // ifAbsent: () => item.product); 127 | // _productVariationsInCart.update( 128 | // item.product.id.toString(), (_) => item.productVariation, 129 | // ifAbsent: () => item.productVariation); 130 | notifyListeners(); 131 | }); 132 | } 133 | } 134 | } catch (e) { 135 | throw e; 136 | } 137 | } 138 | 139 | // addProductToWishList(Product product, ProductVariation variation) { 140 | // _wishListProducts.update(product, (_) => variation, 141 | // ifAbsent: () => variation); 142 | // removeProduct(product.id); 143 | // notifyListeners(); 144 | // } 145 | 146 | addProductToWishList(CartProduct product) { 147 | wishListCartProducts.add(product); 148 | removeProductFromCart(product); 149 | // totalCartAmount -= double.parse(product.productVariation.price); 150 | notifyListeners(); 151 | } 152 | 153 | removeProductAndAddToCart(CartProduct item) { 154 | wishListCartProducts.remove(item); 155 | cartProducts.add(item); 156 | // totalCartAmount += double.parse(item.productVariation.price); 157 | notifyListeners(); 158 | } 159 | 160 | // removeProduct(int id) { 161 | // _productsInCart.remove(id.toString()); 162 | // _products.remove(id); 163 | // _productVariationsInCart.remove(id); 164 | // 165 | // notifyListeners(); 166 | // 167 | // _saveProductsToLocalStorage(); 168 | // } 169 | 170 | removeProductFromCart(item) { 171 | cartProducts.remove(item); 172 | // totalCartAmount -= double.parse(item.productVariation.price); 173 | notifyListeners(); 174 | _saveProductsToLocalStorage(); 175 | } 176 | 177 | removeProductFromWishList(item) { 178 | wishListCartProducts.remove(item); 179 | notifyListeners(); 180 | } 181 | 182 | setCouponCode(String value) { 183 | couponCode = value; 184 | } 185 | 186 | calculateTotalCartAmount() { 187 | cartProducts 188 | .forEach((item) => totalCartAmount += double.parse(item.product.price)); 189 | } 190 | 191 | clearCart() { 192 | cartProducts.clear(); 193 | notifyListeners(); 194 | _saveProductsToLocalStorage(); 195 | } 196 | 197 | updateTotalPayableAmount() => 198 | totalCartPayableAmount = totalCartAmount + totalCartExtraCharge; 199 | } 200 | 201 | // class used to save and reterive product from local storage 202 | class CartProduct { 203 | Product product; 204 | ProductVariation productVariation; 205 | int quantity; 206 | 207 | CartProduct({this.product, this.productVariation, this.quantity}); 208 | 209 | Map toJson() { 210 | return { 211 | 'product': product, 212 | 'productVariation': productVariation, 213 | 'quantity': quantity 214 | }; 215 | } 216 | 217 | CartProduct.fromJson(Map parsedJson) { 218 | product = Product.fromLocalJson(parsedJson['product']); 219 | productVariation = 220 | ProductVariation.fromJson(parsedJson['productVariation']); 221 | quantity = parsedJson['quantity']; 222 | } 223 | 224 | @override 225 | String toString() { 226 | // TODO: implement toString 227 | return '\n$product\n$productVariation\n$quantity'; 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /lib/states/category_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/category.dart' as Product; 2 | import 'package:cool_store/services/base_services.dart'; 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:cool_store/models/product.dart' as Woocommerce; 5 | 6 | class CategoryState extends ChangeNotifier { 7 | Services _services; 8 | bool isLoading; 9 | bool isSearchResultLoading; 10 | Map _categoryList; 11 | String errorMessage; 12 | List categories; 13 | List _searchResult; 14 | 15 | CategoryState() { 16 | isLoading = true; 17 | isSearchResultLoading = true; 18 | categories = List(); 19 | _categoryList = {}; 20 | _services = Services(); 21 | initCategories(); 22 | } 23 | 24 | List get searchResult => _searchResult; 25 | 26 | performSearch(String query) async { 27 | _searchResult = List(); 28 | _searchResult = await _services.searchProducts(name: query, page: 1); 29 | isSearchResultLoading = false; 30 | notifyListeners(); 31 | } 32 | 33 | initCategories() async { 34 | try { 35 | categories = await _services.getCategories(); 36 | isLoading = false; 37 | for (var cat in categories) { 38 | _categoryList[cat.id] = cat; 39 | } 40 | notifyListeners(); 41 | } catch (err) { 42 | isLoading = false; 43 | errorMessage = err.toString(); 44 | notifyListeners(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/states/checkout_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/payment.dart'; 2 | import 'package:cool_store/models/product.dart'; 3 | import 'package:cool_store/models/shipping_methods.dart'; 4 | 5 | import 'package:cool_store/models/user.dart'; 6 | import 'package:cool_store/services/base_services.dart'; 7 | import 'package:cool_store/states/cart_state.dart'; 8 | 9 | import 'package:flutter/foundation.dart'; 10 | 11 | class CheckoutState extends ChangeNotifier { 12 | bool isLoading = true; 13 | String response = ''; 14 | Services _service = Services(); 15 | List _shippingMethods = List(); 16 | bool isShippingMethodsLoading = true; 17 | ShippingMethods selectedShippingMethod; 18 | List cartProducts = List(); 19 | double subTotal = 0.0; 20 | 21 | Services get service => _service; 22 | 23 | CheckoutState() { 24 | getShippingMethods(); 25 | 26 | calculateSubTotal(); 27 | } 28 | 29 | 30 | 31 | createOrder( 32 | Map productsInCart, 33 | Map productVariationsInCart, 34 | Address address, 35 | PaymentMethod paymentMethod) { 36 | _service.createOrder( 37 | productsInCart, productVariationsInCart, address, paymentMethod); 38 | } 39 | 40 | getShippingMethods() async { 41 | _shippingMethods = await _service.getShippingMethods(); 42 | setShippingMethod(_shippingMethods[0]); 43 | isShippingMethodsLoading = false; 44 | notifyListeners(); 45 | } 46 | 47 | List get shippingMethods => _shippingMethods; 48 | 49 | setShippingMethod(item) { 50 | selectedShippingMethod = item; 51 | notifyListeners(); 52 | } 53 | 54 | calculateSubTotal() { 55 | cartProducts.forEach((item) { 56 | subTotal += double.parse(item.productVariation.price); 57 | }); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/states/detail_state.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | 3 | import 'package:cool_store/models/product.dart'; 4 | import 'package:cool_store/services/base_services.dart'; 5 | import 'package:cool_store/states/cart_state.dart'; 6 | import 'package:flutter/foundation.dart'; 7 | import 'package:provider/provider.dart'; 8 | 9 | enum Errors { variationNotSelected, productNotLoaded } 10 | 11 | class DetailState extends ChangeNotifier { 12 | bool isLoading, 13 | isRelatedProductsLoading, 14 | isVariantsLoading, 15 | isReviewsLoading, 16 | doesContainReviews; 17 | String _quantity; 18 | Services _services; 19 | ProductVariation _currentVariation; 20 | Product _product; 21 | List relatedProducts; 22 | List _productVariations; 23 | List _reviews; 24 | 25 | String _productId; 26 | int _categoryId; 27 | 28 | // contains id of variation and variation itself 29 | Map variationMap = HashMap(); 30 | 31 | // container attribute name and value 32 | Map attributesMap = HashMap(); 33 | 34 | DetailState(id) { 35 | this._productId = id.toString(); 36 | _quantity = '1'; 37 | isLoading = true; 38 | isVariantsLoading = true; 39 | isRelatedProductsLoading = true; 40 | isReviewsLoading = true; 41 | doesContainReviews = false; 42 | relatedProducts = List(); 43 | _productVariations = List(); 44 | _reviews = List(); 45 | _services = Services(); 46 | initProduct(); 47 | } 48 | 49 | String get quantity => _quantity; 50 | 51 | Product get product => _product; 52 | 53 | initProduct() async { 54 | try { 55 | _product = await _services.getProduct(_productId); 56 | _categoryId = _product.categoryId; 57 | isLoading = false; 58 | notifyListeners(); 59 | initRelatedProducts(); 60 | initProductVariations(); 61 | initReviews(); 62 | } catch (e) { 63 | print('$e'); 64 | // throw Exception('No INTERNET CONNECTION'); 65 | } 66 | } 67 | 68 | changeAttributesTo(String attribute, String value) { 69 | if (value == null) print('no value for $attribute selected'); 70 | attributesMap.update(attribute, (_) => value, ifAbsent: () => value); 71 | changeProductVariation(variationMap[attributesMap.toString()]); 72 | } 73 | 74 | void changeProductVariation(ProductVariation variation) { 75 | _currentVariation = variation; 76 | notifyListeners(); 77 | } 78 | 79 | ProductVariation get currentVariation => _currentVariation; 80 | 81 | initRelatedProducts() async { 82 | relatedProducts = await _services.fetchProductsByCategory( 83 | categoryId: _categoryId, page: 1); 84 | isRelatedProductsLoading = false; 85 | notifyListeners(); 86 | } 87 | 88 | initReviews() async { 89 | _reviews = await _services.getReviews(_product.id); 90 | if (_reviews.length > 0) doesContainReviews = true; 91 | isReviewsLoading = false; 92 | notifyListeners(); 93 | } 94 | 95 | List getTopReviews() { 96 | List topReviews = 97 | _reviews.length > 5 ? _reviews.sublist(0, 5) : _reviews; 98 | return topReviews; 99 | } 100 | 101 | initProductVariations() async { 102 | _productVariations = await _services.getProductVariations(_product); 103 | 104 | isVariantsLoading = false; 105 | notifyListeners(); 106 | 107 | _productVariations.forEach((variant) { 108 | Map map = HashMap(); 109 | variant.attributes.forEach((value) { 110 | map.update(value.name, (_) => value.option, 111 | ifAbsent: () => value.option); 112 | }); 113 | variationMap.update(map.toString(), (_) => variant, 114 | ifAbsent: () => variant); 115 | }); 116 | } 117 | 118 | List get productVariations => _productVariations; 119 | 120 | setQuantity(String value) { 121 | _quantity = value; 122 | notifyListeners(); 123 | } 124 | 125 | addToCart(context) { 126 | if (_currentVariation == null) throw 'Please select variation'; 127 | if (_product == null) throw 'product not loaded'; 128 | Provider.of(context) 129 | .addProductToCart(_product, _currentVariation, int.parse(quantity)); 130 | } 131 | 132 | @override 133 | void dispose() { 134 | // TODO: implement dispose 135 | super.dispose(); 136 | _services.dispose(); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /lib/states/home_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/services/base_services.dart'; 3 | import 'package:cool_store/utils/constants.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:localstorage/localstorage.dart'; 6 | 7 | class HomeState extends ChangeNotifier { 8 | Services _services; 9 | bool isLoading; 10 | List products; 11 | String errorMessage; 12 | bool errorOccured = false; 13 | 14 | HomeState() { 15 | isLoading = true; 16 | _services = Services(); 17 | products = List(); 18 | getProducts(); 19 | } 20 | 21 | getProducts() async { 22 | try { 23 | products = await _services.getProducts(); 24 | isLoading = false; 25 | notifyListeners(); 26 | cacheProducts(); 27 | } catch (e) { 28 | errorOccured = true; 29 | errorMessage = e.toString(); 30 | loadProductsFromCache(); 31 | } 32 | } 33 | 34 | // cached products to local storage 35 | cacheProducts() async { 36 | final LocalStorage _localStorage = LocalStorage( 37 | Constants.APP_FOLDER, 38 | ); 39 | 40 | try { 41 | final ready = await _localStorage.ready; 42 | if (ready) { 43 | await _localStorage.setItem(Constants.kLocalKey["home"], products); 44 | } 45 | } catch (e) { 46 | throw e; 47 | } 48 | } 49 | 50 | // called if there is a connection problem to load last cached products from local storage 51 | loadProductsFromCache() async { 52 | isLoading = true; 53 | final LocalStorage storage = new LocalStorage(Constants.APP_FOLDER); 54 | try { 55 | final ready = await storage.ready; 56 | if (ready) { 57 | final json = storage.getItem(Constants.kLocalKey["home"]); 58 | if (json != null) { 59 | List list = []; 60 | for (var item in json) { 61 | list.add(Product.fromLocalJson(item)); 62 | } 63 | products = list; 64 | } 65 | } 66 | } catch (err) { 67 | print(err); 68 | } 69 | isLoading = false; 70 | notifyListeners(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/states/product_list_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/services/base_services.dart'; 3 | import 'package:flutter/foundation.dart'; 4 | 5 | class ProductListState extends ChangeNotifier { 6 | bool isLoading; 7 | Services _services; 8 | List _products; 9 | int _categoryId; 10 | 11 | List get products => _products; 12 | 13 | ProductListState(categoryID) { 14 | isLoading = true; 15 | this._categoryId = categoryID; 16 | _products = List(); 17 | _services = Services(); 18 | initProducts(); 19 | } 20 | 21 | initProducts() async { 22 | _products = await _services.fetchProductsByCategory( 23 | categoryId: _categoryId, page: 1); 24 | isLoading = false; 25 | notifyListeners(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/states/search_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/services/base_services.dart'; 3 | import 'package:cool_store/utils/constants.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'package:shared_preferences/shared_preferences.dart'; 6 | 7 | class SearchState extends ChangeNotifier { 8 | bool isResultLoading = true; 9 | bool showKeywords = true; 10 | 11 | String searchKeyword; 12 | List keyWords = List(); 13 | List searchResult = List(); 14 | int currentPage = 1; 15 | Services _services = Services(); 16 | 17 | SearchState() { 18 | _getRecentSearchList(); 19 | } 20 | 21 | setKeyword(String value) { 22 | isResultLoading = true; 23 | showKeywords = false; 24 | notifyListeners(); 25 | searchKeyword = value; 26 | if (!keyWords.contains(value)) keyWords.add(value); 27 | _performSearch(); 28 | } 29 | 30 | _performSearch() async { 31 | searchResult = 32 | await _services.searchProducts(name: searchKeyword, page: currentPage); 33 | isResultLoading = false; 34 | notifyListeners(); 35 | } 36 | 37 | addKeywordsToStorage() async { 38 | try { 39 | SharedPreferences _pref = await SharedPreferences.getInstance(); 40 | await _pref.setStringList( 41 | Constants.kLocalKey['recentSearches'], keyWords); 42 | } catch (e) { 43 | print(e); 44 | } 45 | } 46 | 47 | clearResult() { 48 | showKeywords = true; 49 | searchResult.clear(); 50 | notifyListeners(); 51 | } 52 | 53 | _getRecentSearchList() async { 54 | try { 55 | SharedPreferences _pref = await SharedPreferences.getInstance(); 56 | final list = _pref.getStringList(Constants.kLocalKey['recentSearches']); 57 | if (list != null && list.length > 0) keyWords = list; 58 | } catch (e) { 59 | print(e); 60 | } 61 | notifyListeners(); 62 | } 63 | 64 | removeKeyword(String value) { 65 | keyWords.remove(value); 66 | notifyListeners(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/states/settings_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | class SettingState extends ChangeNotifier { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /lib/utils/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 | } 14 | 15 | final colors = { 16 | "aliceblue": "#f0f8ff", 17 | "antiquewhite": "#faebd7", 18 | "aqua": "#00ffff", 19 | "aquamarine": "#7fffd4", 20 | "azure": "#f0ffff", 21 | "beige": "#f5f5dc", 22 | "bisque": "#ffe4c4", 23 | "black": "#000000", 24 | "blanchedalmond": "#ffebcd", 25 | "blue": "#0000ff", 26 | "blueviolet": "#8a2be2", 27 | "brown": "#a52a2a", 28 | "burlywood": "#deb887", 29 | "cadetblue": "#5f9ea0", 30 | "chartreuse": "#7fff00", 31 | "chocolate": "#d2691e", 32 | "coral": "#ff7f50", 33 | "cornflowerblue": "#6495ed", 34 | "cornsilk": "#fff8dc", 35 | "crimson": "#dc143c", 36 | "cyan": "#00ffff", 37 | "darkblue": "#00008b", 38 | "darkcyan": "#008b8b", 39 | "darkgoldenrod": "#b8860b", 40 | "darkgray": "#a9a9a9", 41 | "darkgreen": "#006400", 42 | "darkgrey": "#a9a9a9", 43 | "darkkhaki": "#bdb76b", 44 | "darkmagenta": "#8b008b", 45 | "darkolivegreen": "#556b2f", 46 | "darkorange": "#ff8c00", 47 | "darkorchid": "#9932cc", 48 | "darkred": "#8b0000", 49 | "darksalmon": "#e9967a", 50 | "darkseagreen": "#8fbc8f", 51 | "darkslateblue": "#483d8b", 52 | "darkslategray": "#2f4f4f", 53 | "darkslategrey": "#2f4f4f", 54 | "darkturquoise": "#00ced1", 55 | "darkviolet": "#9400d3", 56 | "deeppink": "#ff1493", 57 | "deepskyblue": "#00bfff", 58 | "dimgray": "#696969", 59 | "dimgrey": "#696969", 60 | "dodgerblue": "#1e90ff", 61 | "firebrick": "#b22222", 62 | "floralwhite": "#fffaf0", 63 | "forestgreen": "#228b22", 64 | "fuchsia": "#ff00ff", 65 | "gainsboro": "#dcdcdc", 66 | "ghostwhite": "#f8f8ff", 67 | "goldenrod": "#daa520", 68 | "gold": "#ffd700", 69 | "gray": "#808080", 70 | "green": "#008000", 71 | "greenyellow": "#adff2f", 72 | "grey": "#808080", 73 | "honeydew": "#f0fff0", 74 | "hotpink": "#ff69b4", 75 | "indianred": "#cd5c5c", 76 | "indigo": "#4b0082", 77 | "ivory": "#fffff0", 78 | "khaki": "#f0e68c", 79 | "lavenderblush": "#fff0f5", 80 | "lavender": "#e6e6fa", 81 | "lawngreen": "#7cfc00", 82 | "lemonchiffon": "#fffacd", 83 | "lightblue": "#add8e6", 84 | "lightcoral": "#f08080", 85 | "lightcyan": "#e0ffff", 86 | "lightgoldenrodyellow": "#fafad2", 87 | "lightgray": "#d3d3d3", 88 | "lightgreen": "#90ee90", 89 | "lightgrey": "#d3d3d3", 90 | "lightpink": "#ffb6c1", 91 | "lightsalmon": "#ffa07a", 92 | "lightseagreen": "#20b2aa", 93 | "lightskyblue": "#87cefa", 94 | "lightslategray": "#778899", 95 | "lightslategrey": "#778899", 96 | "lightsteelblue": "#b0c4de", 97 | "lightyellow": "#ffffe0", 98 | "lime": "#00ff00", 99 | "limegreen": "#32cd32", 100 | "linen": "#faf0e6", 101 | "magenta": "#ff00ff", 102 | "maroon": "#800000", 103 | "mediumaquamarine": "#66cdaa", 104 | "mediumblue": "#0000cd", 105 | "mediumorchid": "#ba55d3", 106 | "mediumpurple": "#9370db", 107 | "mediumseagreen": "#3cb371", 108 | "mediumslateblue": "#7b68ee", 109 | "mediumspringgreen": "#00fa9a", 110 | "mediumturquoise": "#48d1cc", 111 | "mediumvioletred": "#c71585", 112 | "midnightblue": "#191970", 113 | "mintcream": "#f5fffa", 114 | "mistyrose": "#ffe4e1", 115 | "moccasin": "#ffe4b5", 116 | "navajowhite": "#ffdead", 117 | "navy": "#000080", 118 | "oldlace": "#fdf5e6", 119 | "olive": "#808000", 120 | "olivedrab": "#6b8e23", 121 | "orange": "#ffa500", 122 | "orangered": "#ff4500", 123 | "orchid": "#da70d6", 124 | "palegoldenrod": "#eee8aa", 125 | "palegreen": "#98fb98", 126 | "paleturquoise": "#afeeee", 127 | "palevioletred": "#db7093", 128 | "papayawhip": "#ffefd5", 129 | "peachpuff": "#ffdab9", 130 | "peru": "#cd853f", 131 | "pink": "#ffc0cb", 132 | "plum": "#dda0dd", 133 | "powderblue": "#b0e0e6", 134 | "purple": "#800080", 135 | "rebeccapurple": "#663399", 136 | "red": "#ff0000", 137 | "rosybrown": "#bc8f8f", 138 | "royalblue": "#4169e1", 139 | "saddlebrown": "#8b4513", 140 | "salmon": "#fa8072", 141 | "sandybrown": "#f4a460", 142 | "seagreen": "#2e8b57", 143 | "seashell": "#fff5ee", 144 | "sienna": "#a0522d", 145 | "silver": "#c0c0c0", 146 | "skyblue": "#87ceeb", 147 | "slateblue": "#6a5acd", 148 | "slategray": "#708090", 149 | "slategrey": "#708090", 150 | "snow": "#fffafa", 151 | "springgreen": "#00ff7f", 152 | "steelblue": "#4682b4", 153 | "tan": "#d2b48c", 154 | "teal": "#008080", 155 | "thistle": "#d8bfd8", 156 | "tomato": "#ff6347", 157 | "turquoise": "#40e0d0", 158 | "violet": "#ee82ee", 159 | "wheat": "#f5deb3", 160 | "white": "#ffffff", 161 | "whitesmoke": "#f5f5f5", 162 | "yellow": "#ffff00", 163 | "yellowgreen": "#9acd32" 164 | }; 165 | -------------------------------------------------------------------------------- /lib/utils/constants.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Constants { 4 | static final CONSUMER_KEY_CLOUD = 5 | 'ck_fc75eb207e9e48ecc852fbfdd9461f112ef9d860'; 6 | static final CONSUMER_SECRET_CLOUD = 7 | 'cs_998324c7091df9dd256117dcf6105865f155de78'; 8 | 9 | static final URL_CLOUD = 'https://mastigophoran-miner.000webhostapp.com'; 10 | 11 | static final APP_FOLDER = 'COOL_STORE'; 12 | 13 | // keys for localstorage 14 | static final kLocalKey = { 15 | "userInfo": "userInfo", 16 | "shippingAddress": "shippingAddress", 17 | "recentSearches": "recentSearches", 18 | "wishlist": "wishlist", 19 | "home": "home", 20 | 'isDarkTheme': 'isDarkTheme', 21 | 'productsInCart': 'productsInCart', 22 | 'cartproducts': 'products', 23 | 'productVariationsInCart': 'productVariationsInCart' 24 | }; 25 | 26 | //Colors for theme 27 | static Color lightPrimary = Color(0xfffcfcff); 28 | static Color darkPrimary = Colors.black; 29 | static Color lightAccent = Colors.orange; 30 | static Color darkAccent = Colors.orangeAccent; 31 | static Color lightBG = Color(0xfffcfcff); 32 | static Color darkBG = Colors.black; 33 | 34 | static String searchBarTag = 'searchbartag'; 35 | static String searchSubtitleTag = 'searchSubtitleTag'; 36 | static String searchIconTag = 'searchIconTag'; 37 | static double baseHeight = 640; 38 | 39 | static double screenAwareSize(double size, BuildContext context) { 40 | return size * MediaQuery.of(context).size.height / baseHeight; 41 | } 42 | 43 | static ThemeData lightTheme = ThemeData( 44 | backgroundColor: lightBG, 45 | primaryColor: lightPrimary, 46 | accentColor: lightAccent, 47 | cursorColor: lightAccent, 48 | scaffoldBackgroundColor: lightBG, 49 | appBarTheme: AppBarTheme( 50 | elevation: 0, 51 | textTheme: TextTheme( 52 | title: TextStyle( 53 | color: darkBG, 54 | fontSize: 18.0, 55 | fontWeight: FontWeight.w800, 56 | ), 57 | ), 58 | ), 59 | ); 60 | 61 | static ThemeData darkTheme = ThemeData( 62 | brightness: Brightness.dark, 63 | backgroundColor: darkBG, 64 | hintColor: darkBG, 65 | primaryColor: darkPrimary, 66 | accentColor: darkAccent, 67 | scaffoldBackgroundColor: darkBG, 68 | cursorColor: darkAccent, 69 | appBarTheme: AppBarTheme( 70 | elevation: 0, 71 | textTheme: TextTheme( 72 | title: TextStyle( 73 | color: lightBG, 74 | fontSize: 18.0, 75 | fontWeight: FontWeight.w800, 76 | ), 77 | ), 78 | ), 79 | ); 80 | } 81 | -------------------------------------------------------------------------------- /lib/widgets/Badge.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/cart_state.dart'; 2 | import 'package:cool_store/utils/constants.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class Badge extends StatelessWidget { 7 | final String count; 8 | final IconData iconData; 9 | final TextStyle style; 10 | final Color countBackgroundColor; 11 | 12 | Badge({this.count, this.iconData, this.style, this.countBackgroundColor}); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | final length = Provider.of(context).wishListProducts.length; 17 | ThemeData themeData = Theme.of(context); 18 | return Container( 19 | decoration: BoxDecoration( 20 | shape: BoxShape.circle, 21 | ), 22 | child: Center( 23 | child: Stack( 24 | children: [ 25 | Icon( 26 | iconData, 27 | size: Constants.screenAwareSize(20, context), 28 | color: themeData.iconTheme.color.withOpacity(.8), 29 | ), 30 | Positioned( 31 | bottom: 5, 32 | right: 0, 33 | child: Container( 34 | padding: EdgeInsets.all(6), 35 | decoration: BoxDecoration( 36 | shape: BoxShape.circle, 37 | color: length > 0 38 | ? countBackgroundColor ?? 39 | Colors.redAccent.withOpacity(.7) 40 | : Colors.transparent), 41 | child: Text( 42 | '${length > 0 ? length : ''}', 43 | style: style ?? 44 | TextStyle(color: Colors.white), 45 | ), 46 | )) 47 | ], 48 | ), 49 | ), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/widgets/CartItem.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/utils/constants.dart'; 3 | import 'package:extended_image/extended_image.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class CartItem extends StatelessWidget { 7 | final Function onTap, onRemovePressed, onPrimaryButtonPressed; 8 | 9 | final String primaryTitle; 10 | final Product product; 11 | final ProductVariation variation; 12 | final int quantity; 13 | 14 | CartItem( 15 | {this.onTap, 16 | this.onRemovePressed, 17 | this.onPrimaryButtonPressed, 18 | this.variation, 19 | this.product, 20 | this.primaryTitle = 'Add to wishlist', 21 | this.quantity = 1}); 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return Column( 26 | children: [ 27 | ListTile( 28 | onTap: onTap, 29 | leading: ExtendedImage.network( 30 | product.featuredImage, 31 | cache: true, 32 | fit: BoxFit.contain, 33 | constraints: BoxConstraints( 34 | maxHeight: Constants.screenAwareSize(60, context), 35 | maxWidth: Constants.screenAwareSize(60, context) 36 | ), 37 | ), 38 | subtitle: Column( 39 | mainAxisAlignment: MainAxisAlignment.start, 40 | crossAxisAlignment: CrossAxisAlignment.start, 41 | children: [Text('$variation'), Text('Qty: $quantity')], 42 | ), 43 | title: Text( 44 | product.name, 45 | style: TextStyle( 46 | fontFamily: 'Rlaleway', 47 | fontWeight: FontWeight.w400, 48 | ), 49 | ), 50 | trailing: Column( 51 | mainAxisAlignment: MainAxisAlignment.end, 52 | children: [ 53 | Text( 54 | 'Rs ${product.price}', 55 | style: TextStyle(fontWeight: FontWeight.w600, fontSize: 14), 56 | ) 57 | ], 58 | ), 59 | isThreeLine: true, 60 | ), 61 | Padding( 62 | padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 2), 63 | child: Row( 64 | children: [ 65 | Expanded( 66 | child: RawMaterialButton( 67 | onPressed: onRemovePressed, 68 | child: Text('REMOVE'), 69 | ), 70 | ), 71 | Expanded( 72 | child: RawMaterialButton( 73 | onPressed: onPrimaryButtonPressed, 74 | fillColor: Theme.of(context).accentColor, 75 | child: Text('$primaryTitle'), 76 | textStyle: TextStyle(color: Colors.white), 77 | elevation: 0, 78 | ), 79 | ), 80 | ], 81 | ), 82 | ), 83 | SizedBox( 84 | height: Constants.screenAwareSize(15, context), 85 | ) 86 | ], 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/widgets/ColorChooser.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/detail_state.dart'; 2 | import 'package:cool_store/utils/color.dart'; 3 | import 'package:cool_store/utils/constants.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:provider/provider.dart'; 6 | import 'package:shimmer/shimmer.dart'; 7 | 8 | class ColorChooser extends StatefulWidget { 9 | final String title; 10 | final List options; 11 | 12 | ColorChooser({this.title, this.options}); 13 | 14 | @override 15 | _ColorChooserState createState() => _ColorChooserState(); 16 | } 17 | 18 | class _ColorChooserState extends State { 19 | int selectedIndex = -1; 20 | int time = 1000; 21 | int offset = 50; 22 | bool isSafe = true; 23 | 24 | Color baseColor, highlightColor, borderColor, accentColor; 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | widget.options.forEach((value) { 29 | value = value.replaceAll(' ', '').toLowerCase(); 30 | if (colors.containsKey(value) == false) { 31 | setState(() { 32 | isSafe = false; 33 | }); 34 | } 35 | }); 36 | final state = Provider.of(context); 37 | final theme = Theme.of(context); 38 | baseColor = theme.iconTheme.color; 39 | highlightColor = theme.primaryColor; 40 | accentColor = theme.accentColor.withOpacity(.85); 41 | borderColor = theme.textTheme.title.color.withOpacity(.7); 42 | 43 | return Container( 44 | height: Constants.screenAwareSize(40, context), 45 | child: Row( 46 | crossAxisAlignment: CrossAxisAlignment.center, 47 | mainAxisAlignment: MainAxisAlignment.center, 48 | children: [ 49 | Expanded( 50 | flex: 1, 51 | child: Padding( 52 | padding: const EdgeInsets.all(8.0), 53 | child: Text(widget.title), 54 | )), 55 | Expanded( 56 | flex: 4, 57 | child: ListView.builder( 58 | itemCount: widget.options.length, 59 | shrinkWrap: true, 60 | scrollDirection: Axis.horizontal, 61 | itemBuilder: (_, pos) { 62 | offset += 80; 63 | time += offset; 64 | return state.isVariantsLoading 65 | ? buildLoadingContainers(pos, time) 66 | : buildVariantContainer(state, pos); 67 | }), 68 | ) 69 | ], 70 | ), 71 | ); 72 | } 73 | 74 | Widget buildLoadingContainers(pos, time) { 75 | return Shimmer.fromColors( 76 | child: Container( 77 | padding: EdgeInsets.all(8), 78 | constraints: BoxConstraints( 79 | minWidth: Constants.screenAwareSize(30, context), 80 | minHeight: Constants.screenAwareSize(35, context)), 81 | margin: EdgeInsets.all(8), 82 | decoration: BoxDecoration( 83 | border: Border.all(color: borderColor), 84 | borderRadius: BorderRadius.circular(2)), 85 | child: Center( 86 | child: Text( 87 | '${widget.options[pos]}', 88 | )), 89 | ), 90 | period: Duration(milliseconds: time), 91 | highlightColor: highlightColor, 92 | baseColor: baseColor, 93 | ); 94 | } 95 | 96 | Widget buildVariantContainer(state, pos) { 97 | return GestureDetector( 98 | onTap: () { 99 | state.changeAttributesTo(widget.title, widget.options[pos]); 100 | selectedIndex = pos; 101 | setState(() {}); 102 | }, 103 | child: Container( 104 | padding: EdgeInsets.all(8), 105 | constraints: BoxConstraints( 106 | minWidth: Constants.screenAwareSize(30, context), 107 | minHeight: Constants.screenAwareSize(35, context)), 108 | margin: EdgeInsets.all(8), 109 | decoration: BoxDecoration( 110 | color: isSafe 111 | ? HexColor(colors[widget.options[pos].toLowerCase()]) 112 | .withOpacity(.6) 113 | : Colors.transparent, 114 | borderRadius: BorderRadius.circular(2), 115 | border: Border.all( 116 | color: selectedIndex == pos ? accentColor : borderColor)), 117 | child: Center( 118 | child: Text( 119 | '${isSafe ? '' : widget.options[pos]}', 120 | )), 121 | ), 122 | ); 123 | } 124 | } 125 | 126 | class SemiClipper extends CustomClipper { 127 | @override 128 | Path getClip(Size size) { 129 | final path = Path(); 130 | //path.lineTo(size.width, 0.0); 131 | // path.lineTo(size.width / 2, size.height); 132 | path.close(); 133 | return path; 134 | } 135 | 136 | @override 137 | bool shouldReclip(CustomClipper oldClipper) { 138 | // TODO: implement shouldReclip 139 | return false; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /lib/widgets/DefaultChooser.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/detail_state.dart'; 2 | import 'package:cool_store/utils/constants.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class DefaultChooser extends StatefulWidget { 7 | final String title; 8 | final List options; 9 | 10 | DefaultChooser({this.title, this.options}); 11 | 12 | @override 13 | _DefaultChooserState createState() => _DefaultChooserState(); 14 | } 15 | 16 | class _DefaultChooserState extends State { 17 | int index = 0; 18 | String value = 'SELECT'; 19 | 20 | _DefaultChooserState(); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | final DetailState state = Provider.of(context); 25 | return GestureDetector( 26 | onTap: () async { 27 | if (state.isVariantsLoading) return; 28 | var result = await _showOptions(widget.options, state); 29 | if (result != null) { 30 | value = result; 31 | state.changeAttributesTo(widget.title, value); 32 | setState(() {}); 33 | } 34 | }, 35 | child: Container( 36 | padding: EdgeInsets.symmetric(vertical: 4), 37 | child: Row( 38 | crossAxisAlignment: CrossAxisAlignment.center, 39 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 40 | children: [ 41 | Container( 42 | width: Constants.screenAwareSize(50, context), 43 | height: Constants.screenAwareSize(25, context), 44 | child: Center( 45 | child: Text( 46 | widget.title, 47 | softWrap: true, 48 | overflow: TextOverflow.fade, 49 | textAlign: TextAlign.end, 50 | style: TextStyle(fontFamily: 'Raleway', fontSize: 16), 51 | ), 52 | ), 53 | ), 54 | SizedBox( 55 | width: 10, 56 | ), 57 | Container( 58 | height: Constants.screenAwareSize(25, context), 59 | width: Constants.screenAwareSize(50, context), 60 | decoration: 61 | BoxDecoration(border: Border.all(color: Colors.grey[600])), 62 | child: Center( 63 | child: Text(value, 64 | softWrap: true, 65 | overflow: TextOverflow.fade, 66 | style: TextStyle( 67 | fontWeight: FontWeight.w600, 68 | decorationColor: 69 | Theme.of(context).textTheme.title.color, 70 | decoration: state.isVariantsLoading 71 | ? TextDecoration.lineThrough 72 | : TextDecoration.none))), 73 | ) 74 | ], 75 | ), 76 | ), 77 | ); 78 | } 79 | 80 | _showOptions(List options, DetailState state) { 81 | return showModalBottomSheet( 82 | context: context, 83 | builder: (context) { 84 | return SafeArea( 85 | child: Column( 86 | mainAxisSize: MainAxisSize.min, 87 | children: options 88 | .map((value) => ListTile( 89 | onTap: () { 90 | Navigator.of(context).pop(value); 91 | }, 92 | title: Center( 93 | child: Text( 94 | value, 95 | style: TextStyle(fontFamily: 'Raleway'), 96 | )), 97 | )) 98 | .toList(), 99 | ), 100 | ); 101 | }); 102 | } 103 | } 104 | 105 | 106 | -------------------------------------------------------------------------------- /lib/widgets/GalleryView.dart: -------------------------------------------------------------------------------- 1 | import 'package:carousel_slider/carousel_slider.dart'; 2 | import 'package:cool_store/app.dart'; 3 | import 'package:cool_store/models/product.dart'; 4 | import 'package:cool_store/states/detail_state.dart'; 5 | import 'package:extended_image/extended_image.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:shimmer/shimmer.dart'; 9 | 10 | class GalleryView extends StatefulWidget { 11 | final Product product; 12 | 13 | GalleryView({this.product}); 14 | 15 | @override 16 | _GalleryViewState createState() => _GalleryViewState(); 17 | } 18 | 19 | class _GalleryViewState extends State { 20 | int currentIndex = 0; 21 | 22 | PageController controller = PageController(); 23 | 24 | ScrollController scrollController = ScrollController(); 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Scaffold( 29 | backgroundColor: Theme.of(context).primaryColor, 30 | appBar: AppBar(), 31 | body: SafeArea( 32 | child: Column( 33 | children: [ 34 | Expanded( 35 | child: ExtendedImageGesturePageView.builder( 36 | itemBuilder: (BuildContext context, int index) { 37 | var item = widget.product.images[index]; 38 | Widget image = ExtendedImage.network(item, 39 | fit: BoxFit.contain, initGestureConfigHandler: (state) { 40 | return GestureConfig( 41 | minScale: 0.9, 42 | animationMinScale: 0.7, 43 | maxScale: 3.0, 44 | animationMaxScale: 3.5, 45 | speed: 1.0, 46 | inertialSpeed: 100.0, 47 | initialScale: 1.0, 48 | inPageView: true); 49 | }); 50 | image = Container( 51 | child: image, 52 | padding: EdgeInsets.all(5.0), 53 | ); 54 | if (index == currentIndex) { 55 | return Hero( 56 | tag: item + index.toString(), 57 | child: image, 58 | ); 59 | } else { 60 | return image; 61 | } 62 | }, 63 | itemCount: widget.product.images.length, 64 | onPageChanged: (int index) { 65 | currentIndex = index; 66 | setState(() {}); 67 | }, 68 | controller: controller, 69 | scrollDirection: Axis.horizontal, 70 | ), 71 | ), 72 | Container( 73 | height: 10, 74 | margin: EdgeInsets.symmetric(horizontal: 18, vertical: 8), 75 | child: ListView.builder( 76 | itemCount: widget.product.images.length, 77 | scrollDirection: Axis.horizontal, 78 | itemBuilder: (_, pos) { 79 | return Container( 80 | width: 20, 81 | margin: EdgeInsets.all(8), 82 | decoration: BoxDecoration( 83 | border: Border.all( 84 | color: currentIndex == pos 85 | ? Theme.of(context).accentColor 86 | : Colors.grey[600])), 87 | ); 88 | }), 89 | ) 90 | ], 91 | ), 92 | ), 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/widgets/ImageView.dart: -------------------------------------------------------------------------------- 1 | import 'package:carousel_slider/carousel_slider.dart'; 2 | import 'package:cool_store/states/detail_state.dart'; 3 | import 'package:cool_store/utils/constants.dart'; 4 | import 'package:cool_store/widgets/GalleryView.dart'; 5 | import 'package:extended_image/extended_image.dart'; 6 | import 'package:flutter/cupertino.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:provider/provider.dart'; 9 | import 'package:shimmer/shimmer.dart'; 10 | 11 | class ImageView extends StatelessWidget { 12 | @override 13 | Widget build(BuildContext context) { 14 | final DetailState state = Provider.of(context); 15 | 16 | return GestureDetector( 17 | onTap: () { 18 | if (!state.isLoading) 19 | Navigator.push( 20 | context, 21 | MaterialPageRoute( 22 | fullscreenDialog: true, 23 | builder: (context) => GalleryView(product: state.product))); 24 | }, 25 | child: state.isLoading 26 | ? Container( 27 | height: Constants.screenAwareSize(300, context), 28 | color: Colors.grey[300], 29 | ) 30 | : CarouselSlider( 31 | viewportFraction: 0.9, 32 | aspectRatio: 1, 33 | enlargeCenterPage: true, 34 | height: Constants.screenAwareSize(280, context), 35 | items: state.product.images.map((url) { 36 | return Builder( 37 | builder: (BuildContext context) { 38 | return Container( 39 | width: MediaQuery.of(context).size.width, 40 | margin: 41 | EdgeInsets.symmetric(horizontal: 8.0, vertical: 17), 42 | decoration: BoxDecoration( 43 | color: Colors.grey[300], 44 | boxShadow: [ 45 | BoxShadow( 46 | color: Colors.blueGrey, 47 | offset: Offset(0, 10), 48 | blurRadius: 10, 49 | ) 50 | ], 51 | borderRadius: BorderRadius.all(Radius.circular(8)), 52 | // image: DecorationImage( 53 | // fit: BoxFit.cover, image: NetworkImage(url)) 54 | ), 55 | child: ExtendedImage.network( 56 | url, 57 | cache: true, 58 | // ignore: missing_return 59 | loadStateChanged: (ExtendedImageState imagestate) { 60 | switch (imagestate.extendedImageLoadState) { 61 | case LoadState.loading: 62 | //TODO add loading graphic 63 | return Shimmer( 64 | child: Center(child: Text('Loading')), 65 | gradient: LinearGradient( 66 | colors: [Colors.black, Colors.white])); 67 | break; 68 | 69 | case LoadState.failed: 70 | return GestureDetector( 71 | child: Stack( 72 | fit: StackFit.expand, 73 | children: [ 74 | Icon(Icons.error), 75 | Positioned( 76 | bottom: 0.0, 77 | left: 0.0, 78 | right: 0.0, 79 | child: Text( 80 | "load image failed, click to reload", 81 | textAlign: TextAlign.center, 82 | ), 83 | ) 84 | ], 85 | ), 86 | onTap: () { 87 | imagestate.reLoadImage(); 88 | }, 89 | ); 90 | break; 91 | case LoadState.completed: 92 | // TODO: Handle this case. 93 | break; 94 | } 95 | }, 96 | ), 97 | ); 98 | }, 99 | ); 100 | }).toList(), 101 | ), 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/widgets/InfoView.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/svg.dart'; 3 | 4 | class InfoView extends StatelessWidget { 5 | final String primaryText, secondaryText, path; 6 | final Color iconColor; 7 | 8 | InfoView( 9 | {this.primaryText, 10 | this.secondaryText, 11 | this.iconColor, 12 | this.path = 'assets/no_result.svg'}); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Column( 17 | mainAxisAlignment: MainAxisAlignment.center, 18 | crossAxisAlignment: CrossAxisAlignment.center, 19 | mainAxisSize: MainAxisSize.max, 20 | children: [ 21 | Padding( 22 | padding: const EdgeInsets.all(50.0), 23 | child: SvgPicture.asset( 24 | path, 25 | height: MediaQuery.of(context).size.height / 4, 26 | color: iconColor, 27 | ), 28 | ), 29 | Padding( 30 | padding: const EdgeInsets.all(18.0), 31 | child: Text( 32 | primaryText, 33 | textAlign: TextAlign.center, 34 | style: TextStyle( 35 | fontFamily: 'Raleway', 36 | fontSize: 35, 37 | fontWeight: FontWeight.w200), 38 | ), 39 | ), 40 | if (secondaryText != null) 41 | Padding( 42 | padding: const EdgeInsets.all(18.0), 43 | child: Text( 44 | secondaryText, 45 | textAlign: TextAlign.center, 46 | style: TextStyle( 47 | fontFamily: 'Raleway', 48 | fontSize: 16, 49 | fontWeight: FontWeight.w200), 50 | ), 51 | ), 52 | ], 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/widgets/OffersBanner.dart: -------------------------------------------------------------------------------- 1 | import 'package:carousel_slider/carousel_slider.dart'; 2 | import 'package:extended_image/extended_image.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class OffersBanner extends StatelessWidget { 6 | final imageList = [ 7 | 'https://assets.myntassets.com/w_980,c_limit,fl_progressive,dpr_2.0/assets/images/banners/2019/8/2/1f55b32d-a54f-4130-8de6-142167685e941564742794212-desktop.jpg', 8 | 'https://assets.myntassets.com/w_980,c_limit,fl_progressive,dpr_2.0/assets/images/banners/2019/8/3/8e251762-1833-4490-9612-67c11877b2d61564848407937-Gerua_Desk_Banner.jpg', 9 | 'https://assets.myntassets.com/w_980,c_limit,fl_progressive,dpr_2.0/assets/images/banners/2019/8/3/8fe43105-e031-4271-b66a-017abefd25ba1564848407967-Highlander_Desk_Banner.jpg', 10 | 'https://assets.myntassets.com/w_980,c_limit,fl_progressive,dpr_2.0/assets/images/banners/2019/8/3/c0232ddd-5017-4dbe-8cf8-108e4a111b0a1564848407994-Jockey_Desk_Banner.jpg', 11 | 'https://assets.myntassets.com/w_980,c_limit,fl_progressive,dpr_2.0/assets/images/banners/2019/8/3/71cbabc8-2fdf-42b9-8179-4cd136aa5f5b1564848408043-Only_Desk_Banner.jpg', 12 | 'https://assets.myntassets.com/w_980,c_limit,fl_progressive,dpr_2.0/assets/images/banners/2019/8/3/c27bc5ae-17dc-4326-b44c-f761da6e48fe1564848408020-Portico_Desk_Banner.jpg', 13 | ]; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return CarouselSlider( 18 | autoPlay: true, 19 | pauseAutoPlayOnTouch: Duration(seconds: 1), 20 | viewportFraction: 0.9, 21 | aspectRatio: 1, 22 | enlargeCenterPage: true, 23 | items: imageList.map((url) { 24 | return Builder( 25 | builder: (BuildContext context) { 26 | return Container( 27 | width: MediaQuery.of(context).size.width, 28 | margin: EdgeInsets.symmetric(horizontal: 4.0), 29 | decoration: BoxDecoration( 30 | image: DecorationImage( 31 | fit: BoxFit.cover, 32 | image: ExtendedNetworkImageProvider( 33 | url, 34 | cache: true, 35 | ))), 36 | ); 37 | }, 38 | ); 39 | }).toList(), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/widgets/ProductCard.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/utils/constants.dart'; 3 | import 'package:extended_image/extended_image.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class ProductDisplayCard extends StatelessWidget { 7 | final Function onPressed; 8 | final Product product; 9 | final double margin; 10 | 11 | ProductDisplayCard({@required this.onPressed, this.product, this.margin = 0}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return InkWell( 16 | onTap: onPressed, 17 | child: Container( 18 | margin: EdgeInsets.only(right: margin), 19 | decoration: BoxDecoration( 20 | gradient: LinearGradient( 21 | colors: [Colors.transparent, Constants.lightBG.withOpacity(.1)], 22 | begin: Alignment.topCenter, 23 | end: Alignment.bottomCenter), 24 | ), 25 | child: Column( 26 | crossAxisAlignment: CrossAxisAlignment.start, 27 | children: [ 28 | Expanded( 29 | child: Container( 30 | width: MediaQuery.of(context).size.width / 2, 31 | margin: EdgeInsets.all(margin), 32 | decoration: BoxDecoration( 33 | image: DecorationImage( 34 | fit: BoxFit.cover, 35 | image: ExtendedNetworkImageProvider( 36 | product.featuredImage, 37 | cache: true))), 38 | ), 39 | ), 40 | SizedBox( 41 | height: Constants.screenAwareSize(8, context), 42 | ), 43 | Padding( 44 | padding: const EdgeInsets.only(left: 8.0), 45 | child: Text( 46 | '${product.name}', 47 | style: TextStyle( 48 | fontFamily: 'Raleway', 49 | fontSize: Constants.screenAwareSize(12, context), 50 | fontWeight: FontWeight.w400), 51 | ), 52 | ), 53 | Padding( 54 | padding: const EdgeInsets.only(left: 8.0), 55 | child: Text( 56 | 'Rs. ${product.price}', 57 | style: TextStyle( 58 | fontWeight: FontWeight.bold, 59 | fontSize: Constants.screenAwareSize(10, context)), 60 | ), 61 | ), 62 | SizedBox( 63 | height: Constants.screenAwareSize(10, context), 64 | ) 65 | ], 66 | ), 67 | ), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/widgets/ProductDescription.dart: -------------------------------------------------------------------------------- 1 | import 'package:configurable_expansion_tile/configurable_expansion_tile.dart'; 2 | import 'package:cool_store/models/product.dart'; 3 | import 'package:cool_store/states/detail_state.dart'; 4 | import 'package:cool_store/utils/constants.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:smooth_star_rating/smooth_star_rating.dart'; 9 | 10 | class ProductDescription extends StatelessWidget { 11 | final Product product; 12 | final textStyle = TextStyle(fontFamily: 'Raleway'); 13 | 14 | ProductDescription(this.product); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | final state = Provider.of(context); 19 | bool enableReview = true; 20 | 21 | return Column( 22 | children: [ 23 | SizedBox(height: 15), 24 | ExpansionInfo( 25 | title: 'DESCRIPTION', 26 | children: [ 27 | Align( 28 | alignment: Alignment.topLeft, 29 | child: HtmlWidget( 30 | product.description, 31 | textStyle: textStyle, 32 | ), 33 | ), 34 | ], 35 | expand: true), 36 | if (enableReview) 37 | Container( 38 | height: 1, decoration: BoxDecoration(color: Colors.grey[200])), 39 | if (enableReview) 40 | ExpansionInfo( 41 | title: 'REVIEWS', 42 | children: state.isReviewsLoading 43 | ? [CircularProgressIndicator()] 44 | : state.doesContainReviews 45 | ? state 46 | .getTopReviews() 47 | .map((Review review) => ListTile( 48 | title: Row( 49 | mainAxisAlignment: 50 | MainAxisAlignment.spaceBetween, 51 | children: [ 52 | HtmlWidget( 53 | review.reviewer, 54 | textStyle: TextStyle( 55 | fontFamily: 'Raleway', 56 | ), 57 | bodyPadding: EdgeInsets.symmetric( 58 | horizontal: 2, vertical: 2), 59 | ), 60 | SmoothStarRating( 61 | allowHalfRating: true, 62 | starCount: review.rating, 63 | rating: product.averageRating, 64 | size: Constants.screenAwareSize( 65 | 10, context), 66 | color: Theme.of(context).accentColor, 67 | borderColor: 68 | Theme.of(context).accentColor, 69 | spacing: 0.0), 70 | ], 71 | ), 72 | subtitle: HtmlWidget( 73 | review.review, 74 | textStyle: TextStyle( 75 | fontFamily: 'Raleway', 76 | ), 77 | bodyPadding: EdgeInsets.symmetric( 78 | horizontal: 2, vertical: 2), 79 | ), 80 | dense: true, 81 | )) 82 | .toList() 83 | : [ 84 | ListTile( 85 | title: Text( 86 | 'No Reviews yet', 87 | style: TextStyle( 88 | fontFamily: 'Raleway', fontSize: 14), 89 | ), 90 | ) 91 | ] 92 | // children: [ 93 | // state.isReviewsLoading 94 | // ? CircularProgressIndicator() 95 | // : state.reviews.length > 0 96 | // ? ListView.builder( 97 | // physics: NeverScrollableScrollPhysics(), 98 | // itemBuilder: (_, pos) { 99 | // Review review = state.reviews[pos]; 100 | // return ListTile( 101 | // title: HtmlWidget(review.reviewer), 102 | // subtitle: HtmlWidget(review.review), 103 | // ); 104 | // }, 105 | // itemCount: state.reviews.length, 106 | // ) 107 | // : ListTile( 108 | // title: Text('No Reviews'), 109 | // ) 110 | // ], 111 | ), 112 | Container( 113 | height: 1, decoration: BoxDecoration(color: Colors.grey[200])), 114 | ExpansionInfo( 115 | title: 'ADDITIONAL INFO', 116 | children: [ 117 | Align( 118 | alignment: Alignment.topLeft, 119 | child: HtmlWidget( 120 | product.description, 121 | textStyle: textStyle, 122 | ), 123 | ) 124 | ], 125 | ), 126 | ], 127 | ); 128 | } 129 | } 130 | 131 | class ExpansionInfo extends StatelessWidget { 132 | final String title; 133 | final bool expand; 134 | final List children; 135 | 136 | ExpansionInfo( 137 | {@required this.title, @required this.children, this.expand = false}); 138 | 139 | @override 140 | Widget build(BuildContext context) { 141 | return ConfigurableExpansionTile( 142 | initiallyExpanded: expand, 143 | headerExpanded: Flexible( 144 | child: Padding( 145 | padding: EdgeInsets.symmetric(vertical: 17.0), 146 | child: Row( 147 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 148 | children: [ 149 | Text(title, 150 | style: TextStyle(fontSize: 17, fontFamily: 'Raleway')), 151 | Icon( 152 | Icons.keyboard_arrow_up, 153 | size: 20, 154 | ) 155 | ])), 156 | ), 157 | header: Flexible( 158 | child: Padding( 159 | padding: EdgeInsets.symmetric(vertical: 17.0), 160 | child: Row( 161 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 162 | children: [ 163 | Text(title, 164 | style: TextStyle(fontSize: 17, fontFamily: 'Raleway')), 165 | Icon( 166 | Icons.keyboard_arrow_right, 167 | size: 20, 168 | ) 169 | ])), 170 | ), 171 | children: children, 172 | ); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /lib/widgets/ProductTitle.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/states/detail_state.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:provider/provider.dart'; 5 | import 'package:smooth_star_rating/smooth_star_rating.dart'; 6 | 7 | class ProductTitle extends StatelessWidget { 8 | final Product product; 9 | 10 | ProductTitle(this.product); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | ThemeData theme = Theme.of(context); 15 | final DetailState state = Provider.of(context); 16 | ProductVariation variation = state.currentVariation; 17 | return Column( 18 | mainAxisAlignment: MainAxisAlignment.start, 19 | children: [ 20 | SizedBox(height: 10), 21 | Container( 22 | width: MediaQuery.of(context).size.width, 23 | child: Text( 24 | product.name, 25 | style: TextStyle(fontSize: 18, fontFamily: 'Raleway'), 26 | ), 27 | ), 28 | SizedBox(height: 10), 29 | Row( 30 | children: [ 31 | // Text(Tools.getCurrecyFormatted(price), 32 | // style: Theme.of(context) 33 | // .textTheme 34 | // .headline 35 | // .copyWith(fontSize: 17, color: theme.accentColor)), 36 | Text( 37 | // product.price, 38 | variation == null ? product.price : variation.price, 39 | style: TextStyle( 40 | fontSize: 17, 41 | ), 42 | ), 43 | if (product.onSale) 44 | SizedBox(width: 5), 45 | if (product.onSale) 46 | Text( 47 | variation == null 48 | ? product.regularPrice 49 | : variation.regularPrice, 50 | style: TextStyle(fontSize: 16), 51 | ), 52 | // Text(Tools.getCurrecyFormatted(regularPrice), 53 | // style: Theme.of(context).textTheme.headline.copyWith( 54 | // fontSize: 16, 55 | // color: Theme.of(context).accentColor, 56 | // decoration: TextDecoration.lineThrough)), 57 | ], 58 | ), 59 | Padding( 60 | padding: EdgeInsets.symmetric(vertical: 10.0), 61 | child: Row( 62 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 63 | children: [ 64 | SmoothStarRating( 65 | allowHalfRating: true, 66 | starCount: 5, 67 | rating: product.averageRating, 68 | size: 17.0, 69 | color: theme.accentColor, 70 | borderColor: theme.accentColor, 71 | spacing: 0.0), 72 | ], 73 | ), 74 | ), 75 | ], 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/widgets/QuantityChooser.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/detail_state.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | 5 | class QuantityChooser extends StatelessWidget { 6 | @override 7 | Widget build(BuildContext context) { 8 | return Consumer(builder: (context, state, child) { 9 | return Container( 10 | margin: EdgeInsets.symmetric(horizontal: 8), 11 | child: Center( 12 | child: DropdownButton( 13 | value: state.quantity.toString(), 14 | items: [ 15 | DropdownMenuItem( 16 | child: Center(child: Text('1')), 17 | value: '1', 18 | ), 19 | DropdownMenuItem( 20 | child: Center(child: Text('2')), 21 | value: '2', 22 | ), 23 | DropdownMenuItem( 24 | child: Center(child: Text('3')), 25 | value: '3', 26 | ), 27 | ], 28 | onChanged: (value) { 29 | state.setQuantity(value); 30 | }, 31 | ), 32 | ), 33 | ); 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/widgets/RelatedProducts.dart: -------------------------------------------------------------------------------- 1 | import 'package:async/async.dart'; 2 | import 'package:cool_store/models/product.dart'; 3 | import 'package:cool_store/services/base_services.dart'; 4 | import 'package:cool_store/widgets/ProductCard.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:provider/provider.dart'; 7 | 8 | class RelatedProduct extends StatelessWidget { 9 | final Product product; 10 | 11 | RelatedProduct(this.product); 12 | 13 | final _memoizer = AsyncMemoizer>(); 14 | final services = Services(); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | final Size screenSize = MediaQuery.of(context).size; 19 | 20 | Future> getRelativeProducts() => _memoizer.runOnce(() { 21 | return services.fetchProductsByCategory( 22 | categoryId: product.categoryId, 23 | ); 24 | }); 25 | 26 | return FutureBuilder>( 27 | future: getRelativeProducts(), 28 | builder: (BuildContext context, AsyncSnapshot> snapshot) { 29 | switch (snapshot.connectionState) { 30 | case ConnectionState.none: 31 | case ConnectionState.active: 32 | case ConnectionState.waiting: 33 | return Container( 34 | height: 100, 35 | child: CircularProgressIndicator(), 36 | ); 37 | case ConnectionState.done: 38 | if (snapshot.hasError) { 39 | return Container( 40 | height: 100, 41 | child: Center( 42 | child: Text( 43 | 'Error: ${snapshot.error}', 44 | style: TextStyle(color: Theme.of(context).accentColor), 45 | ), 46 | ), 47 | ); 48 | } else if (snapshot.data.length == 0) { 49 | return Container(); 50 | } else { 51 | return Column( 52 | crossAxisAlignment: CrossAxisAlignment.start, 53 | children: [ 54 | Padding( 55 | padding: const EdgeInsets.symmetric(vertical: 18.0), 56 | child: Text( 57 | 'You might like', 58 | style: TextStyle( 59 | fontSize: 17, color: Theme.of(context).accentColor), 60 | ), 61 | ), 62 | Container( 63 | height: MediaQuery.of(context).size.width * 0.7, 64 | child: ListView( 65 | shrinkWrap: true, 66 | scrollDirection: Axis.horizontal, 67 | children: [ 68 | for (var item in snapshot.data) 69 | if (item.id != product.id) 70 | ProductDisplayCard( 71 | onPressed: (){}, 72 | product: item, 73 | ) 74 | ], 75 | )) 76 | ], 77 | ); 78 | } 79 | } 80 | return Container(); // unreachable 81 | }, 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/widgets/ShimmerGrid.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:shimmer/shimmer.dart'; 3 | 4 | class ShimmerGrid extends StatelessWidget { 5 | int time = 600; 6 | int offset = 50; 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return SafeArea( 11 | child: GridView.builder( 12 | shrinkWrap: true, 13 | physics: NeverScrollableScrollPhysics(), 14 | itemCount: 4, 15 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 16 | childAspectRatio: .6, 17 | crossAxisCount: 2, 18 | crossAxisSpacing: 1, 19 | mainAxisSpacing: 1), 20 | itemBuilder: (context, pos) { 21 | offset += 50; 22 | time += offset; 23 | return Shimmer.fromColors( 24 | baseColor: Colors.grey[300], 25 | highlightColor: Colors.white, 26 | child: ShimmerLayout(), 27 | period: Duration(milliseconds: time), 28 | ); 29 | }), 30 | ); 31 | } 32 | } 33 | 34 | class ShimmerLayout extends StatelessWidget { 35 | @override 36 | Widget build(BuildContext context) { 37 | return Container( 38 | child: Column( 39 | mainAxisAlignment: MainAxisAlignment.center, 40 | crossAxisAlignment: CrossAxisAlignment.start, 41 | children: [ 42 | Expanded( 43 | child: Container( 44 | color: Colors.grey, 45 | ), 46 | ), 47 | Container( 48 | margin: EdgeInsets.only(top: 4, bottom: 4, left: 4, right: 40), 49 | height: 10, 50 | color: Colors.grey, 51 | ), 52 | Container( 53 | margin: EdgeInsets.only(top: 4, bottom: 4, left: 4, right: 80), 54 | height: 10, 55 | color: Colors.grey, 56 | ), 57 | ], 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/widgets/ShimmerList.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:shimmer/shimmer.dart'; 3 | 4 | class ShimmerList extends StatelessWidget { 5 | int time = 600; 6 | int offset = 50; 7 | 8 | final Axis direction; 9 | 10 | ShimmerList({this.direction = Axis.vertical}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return SafeArea( 15 | child: ListView.builder( 16 | scrollDirection: direction, 17 | physics: NeverScrollableScrollPhysics(), 18 | itemCount: 4, 19 | shrinkWrap: true, 20 | itemBuilder: (context, pos) { 21 | offset += 50; 22 | time += offset; 23 | return Shimmer.fromColors( 24 | child: direction == Axis.horizontal 25 | ? ShimmerHorizontalLayout() 26 | : ShimmerLayout(), 27 | highlightColor: Colors.white, 28 | period: Duration(milliseconds: time), 29 | baseColor: Colors.grey[300], 30 | ); 31 | }), 32 | ); 33 | } 34 | } 35 | 36 | class ShimmerHorizontalLayout extends StatelessWidget { 37 | @override 38 | Widget build(BuildContext context) { 39 | return Container( 40 | height: MediaQuery.of(context).size.height / 3, 41 | width: MediaQuery.of(context).size.width / 2, 42 | margin: EdgeInsets.symmetric(horizontal: 8), 43 | child: Column( 44 | mainAxisAlignment: MainAxisAlignment.center, 45 | crossAxisAlignment: CrossAxisAlignment.start, 46 | children: [ 47 | Expanded( 48 | child: Container( 49 | color: Colors.grey, 50 | ), 51 | ), 52 | Container( 53 | margin: EdgeInsets.only(top: 4, bottom: 4, left: 4, right: 40), 54 | height: 10, 55 | color: Colors.grey, 56 | ), 57 | Container( 58 | margin: EdgeInsets.only(top: 4, bottom: 4, left: 4, right: 80), 59 | height: 10, 60 | color: Colors.grey, 61 | ), 62 | ], 63 | ), 64 | ); 65 | } 66 | } 67 | 68 | class ShimmerLayout extends StatelessWidget { 69 | @override 70 | Widget build(BuildContext context) { 71 | double height = (MediaQuery.of(context).size.height) / 2 - 150; 72 | return Container( 73 | margin: EdgeInsets.all(4), 74 | height: height, 75 | color: Colors.grey, 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/widgets/VariantChooser.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/states/detail_state.dart'; 2 | import 'package:cool_store/utils/constants.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:provider/provider.dart'; 5 | import 'package:shimmer/shimmer.dart'; 6 | 7 | class VariantChooser extends StatefulWidget { 8 | final String title; 9 | final List options; 10 | 11 | VariantChooser({this.title, this.options}); 12 | 13 | @override 14 | _VariantChooserState createState() => _VariantChooserState(); 15 | } 16 | 17 | class _VariantChooserState extends State { 18 | int selectedIndex = -1; 19 | int time = 1000; 20 | int offset = 50; 21 | 22 | Color baseColor, highlightColor, borderColor, accentColor; 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | final state = Provider.of(context); 27 | final theme = Theme.of(context); 28 | baseColor = theme.iconTheme.color; 29 | highlightColor = theme.primaryColor; 30 | accentColor = theme.accentColor.withOpacity(.85); 31 | borderColor = theme.textTheme.title.color.withOpacity(.7); 32 | return Container( 33 | height: Constants.screenAwareSize(40, context), 34 | child: Row( 35 | crossAxisAlignment: CrossAxisAlignment.center, 36 | mainAxisAlignment: MainAxisAlignment.center, 37 | children: [ 38 | Expanded( 39 | flex: 1, 40 | child: Padding( 41 | padding: const EdgeInsets.all(8.0), 42 | child: Text(widget.title), 43 | )), 44 | Expanded( 45 | flex: 4, 46 | child: ListView.builder( 47 | itemCount: widget.options.length, 48 | shrinkWrap: true, 49 | scrollDirection: Axis.horizontal, 50 | itemBuilder: (_, pos) { 51 | offset += 80; 52 | time += offset; 53 | return state.isVariantsLoading 54 | ? buildLoadingContainers(pos, time) 55 | : buildVariantContainer(state, pos); 56 | }), 57 | ) 58 | ], 59 | ), 60 | ); 61 | } 62 | 63 | Widget buildLoadingContainers(pos, time) { 64 | return Shimmer.fromColors( 65 | child: Container( 66 | padding: EdgeInsets.all(8), 67 | constraints: BoxConstraints( 68 | minWidth: Constants.screenAwareSize(30, context), 69 | minHeight: Constants.screenAwareSize(35, context)), 70 | margin: EdgeInsets.all(8), 71 | decoration: BoxDecoration( 72 | border: Border.all(color: borderColor), 73 | borderRadius: BorderRadius.circular(2)), 74 | child: Center( 75 | child: Text( 76 | '${widget.options[pos]}', 77 | )), 78 | ), 79 | period: Duration(milliseconds: time), 80 | highlightColor: highlightColor, 81 | baseColor: baseColor, 82 | ); 83 | } 84 | 85 | Widget buildVariantContainer(state, pos) { 86 | return GestureDetector( 87 | onTap: () { 88 | state.changeAttributesTo(widget.title, widget.options[pos]); 89 | selectedIndex = pos; 90 | setState(() {}); 91 | }, 92 | child: Container( 93 | padding: EdgeInsets.all(8), 94 | constraints: BoxConstraints( 95 | minWidth: Constants.screenAwareSize(30, context), 96 | minHeight: Constants.screenAwareSize(40, context)), 97 | margin: EdgeInsets.all(8), 98 | decoration: BoxDecoration( 99 | borderRadius: BorderRadius.circular(2), 100 | border: Border.all( 101 | color: selectedIndex == pos ? accentColor : borderColor)), 102 | child: Center( 103 | child: Text( 104 | '${widget.options[pos]}', 105 | )), 106 | ), 107 | ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /lib/widgets/VariationsView.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/product.dart'; 2 | import 'package:cool_store/states/detail_state.dart'; 3 | import 'package:cool_store/widgets/ColorChooser.dart'; 4 | import 'package:cool_store/widgets/VariantChooser.dart'; 5 | import 'package:flutter/cupertino.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:provider/provider.dart'; 8 | 9 | import 'DefaultChooser.dart'; 10 | 11 | class VariationsView extends StatelessWidget { 12 | final Product product; 13 | 14 | VariationsView(this.product); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Column( 19 | mainAxisAlignment: MainAxisAlignment.spaceAround, 20 | crossAxisAlignment: CrossAxisAlignment.center, 21 | children: product.attributes.map((value) { 22 | if (value.name == 'SIZE' || value.name == 'size') 23 | return VariantChooser( 24 | title: value.name, 25 | options: value.options, 26 | ); 27 | else if (value.name == 'COLOR' || 28 | value.name == 'color' || 29 | value.name == 'colour' || 30 | value.name == 'COLOUR') 31 | return ColorChooser( 32 | title: value.name, 33 | options: value.options, 34 | ); 35 | return DefaultChooser( 36 | title: value.name, 37 | options: value.options, 38 | ); 39 | }).toList()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/widgets/category_banner.dart: -------------------------------------------------------------------------------- 1 | import 'package:cool_store/models/category.dart'; 2 | import 'package:cool_store/utils/constants.dart'; 3 | import 'package:extended_image/extended_image.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class CategoryBanner extends StatelessWidget { 7 | final Category _category; 8 | final Function _onPressed; 9 | 10 | CategoryBanner(this._category, this._onPressed); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | double height = (MediaQuery.of(context).size.height) / 4.5; 15 | return InkWell( 16 | onTap: _onPressed, 17 | child: Stack( 18 | children: [ 19 | Container( 20 | height: Constants.screenAwareSize(height, context), 21 | margin: EdgeInsets.all(4), 22 | decoration: BoxDecoration( 23 | image: DecorationImage( 24 | fit: BoxFit.cover, 25 | image: ExtendedNetworkImageProvider(_category.image, 26 | cache: true))), 27 | ), 28 | Container( 29 | height: Constants.screenAwareSize(height, context), 30 | margin: EdgeInsets.all(4), 31 | decoration: BoxDecoration( 32 | gradient: LinearGradient( 33 | begin: Alignment.topCenter, 34 | end: Alignment.bottomCenter, 35 | colors: [Colors.transparent, Colors.black54]), 36 | ), 37 | ), 38 | Container( 39 | height: Constants.screenAwareSize(height, context), 40 | margin: EdgeInsets.all(4), 41 | child: Center( 42 | child: Container( 43 | padding: EdgeInsets.all(8), 44 | decoration: 45 | BoxDecoration(border: Border.all(color: Colors.white)), 46 | child: Text( 47 | _category.name, 48 | style: TextStyle( 49 | fontSize: Constants.screenAwareSize(40, context), 50 | fontFamily: 'Raleway', 51 | color: Colors.white), 52 | ), 53 | )), 54 | ) 55 | ], 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: cool_store 2 | description: A new Flutter application. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.2.2 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | cupertino_icons: ^0.1.2 23 | crypto: ^2.1.2 24 | shimmer: ^1.0.0 25 | http: ^0.12.0+2 26 | connectivity: ^0.4.4 27 | provider: ^3.1.0 28 | carousel_slider: ^1.3.0 29 | smooth_star_rating: 1.0.3 30 | flutter_widget_from_html_core: ^0.2.2+1 31 | configurable_expansion_tile: ^1.0.0 32 | localstorage: ^2.0.0 33 | shared_preferences: ^0.5.3+4 34 | extended_image: ^0.5.6 35 | flutter_svg: ^0.14.0 36 | badges: ^1.1.0 37 | validate: ^1.7.0 38 | 39 | dev_dependencies: 40 | flutter_test: 41 | sdk: flutter 42 | 43 | 44 | # For information on the generic Dart part of this file, see the 45 | # following page: https://www.dartlang.org/tools/pub/pubspec 46 | 47 | # The following section is specific to Flutter. 48 | flutter: 49 | 50 | # The following line ensures that the Material Icons font is 51 | # included with your application, so that you can use the icons in 52 | # the material Icons class. 53 | uses-material-design: true 54 | 55 | # To add assets to your application, add an assets section, like this: 56 | assets: 57 | - category_image_default.jpg 58 | - empty_cart.png 59 | - no_result.svg 60 | - empty.svg 61 | - wishlist.png 62 | - list.svg 63 | - shoppint_cart_empty.svg 64 | - colors.csv 65 | 66 | 67 | # An image asset can refer to one or more resolution-specific "variants", see 68 | # https://flutter.dev/assets-and-images/#resolution-aware. 69 | 70 | # For details regarding adding assets from package dependencies, see 71 | # https://flutter.dev/assets-and-images/#from-packages 72 | 73 | # To add custom fonts to your application, add a fonts section here, 74 | # in this "flutter" section. Each entry in this list should have a 75 | # "family" key with the font family name, and a "fonts" key with a 76 | # list giving the asset and other descriptors for the font. For 77 | # example: 78 | fonts: 79 | - family: Raleway 80 | fonts: 81 | - asset: fonts/Raleway-Regular.ttf 82 | - asset: fonts/Raleway-Black.ttf 83 | - asset: fonts/Raleway-Bold.ttf 84 | weight: 700 85 | # 86 | # For details regarding fonts from package dependencies, 87 | # see https://flutter.dev/custom-fonts/#from-packages 88 | --------------------------------------------------------------------------------