├── ios
├── Flutter
│ ├── .last_build_id
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── GoogleService-Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ └── project.pbxproj
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── .gitignore
└── Podfile
├── assets
└── images
│ ├── logo.png
│ ├── beans.jpg
│ ├── market.jpg
│ ├── top_bg.png
│ └── vegetables.png
├── lib
├── src
│ ├── styles
│ │ ├── buttons.dart
│ │ ├── tabbar.dart
│ │ ├── colors.dart
│ │ ├── base.dart
│ │ ├── textfields.dart
│ │ └── text.dart
│ ├── widgets
│ │ ├── shopping_bag.dart
│ │ ├── profile_customer.dart
│ │ ├── orders.dart
│ │ ├── navbar.dart
│ │ ├── sliver_scaffold.dart
│ │ ├── vendor_scaffold.dart
│ │ ├── customer_scaffold.dart
│ │ ├── profile.dart
│ │ ├── social_button.dart
│ │ ├── alerts.dart
│ │ ├── list_tile.dart
│ │ ├── card.dart
│ │ ├── products_customer.dart
│ │ ├── button.dart
│ │ ├── textfield.dart
│ │ ├── products.dart
│ │ └── dropdown_button.dart
│ ├── models
│ │ ├── application_user.dart
│ │ ├── vendor.dart
│ │ ├── location.dart
│ │ ├── market.dart
│ │ └── product.dart
│ ├── blocs
│ │ ├── customer_bloc.dart
│ │ ├── auth_bloc.dart
│ │ ├── vendor_bloc.dart
│ │ └── product_bloc.dart
│ ├── services
│ │ ├── firebase_storage_service.dart
│ │ └── firestore_service.dart
│ ├── screens
│ │ ├── vendor.dart
│ │ ├── customer.dart
│ │ ├── landing.dart
│ │ ├── signup.dart
│ │ ├── login.dart
│ │ ├── edit_vendor.dart
│ │ └── edit_product.dart
│ ├── app.dart
│ └── routes.dart
└── main.dart
├── android
├── gradle.properties
├── .gitignore
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ └── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── julow
│ │ │ │ │ └── farmers_market
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── build.gradle
├── .metadata
├── .vscode
└── launch.json
├── .gitignore
├── README.md
├── pubspec.yaml
└── pubspec.lock
/ios/Flutter/.last_build_id:
--------------------------------------------------------------------------------
1 | 803fcb6b326d64b0986b90f4303e6e8f
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/assets/images/logo.png
--------------------------------------------------------------------------------
/lib/src/styles/buttons.dart:
--------------------------------------------------------------------------------
1 | abstract class ButtonStyles {
2 | static double get buttonHeight => 50.0;
3 | }
--------------------------------------------------------------------------------
/assets/images/beans.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/assets/images/beans.jpg
--------------------------------------------------------------------------------
/assets/images/market.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/assets/images/market.jpg
--------------------------------------------------------------------------------
/assets/images/top_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/assets/images/top_bg.png
--------------------------------------------------------------------------------
/assets/images/vegetables.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/assets/images/vegetables.png
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nhandrew/mobilefarmersmarket/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lib/src/widgets/shopping_bag.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ShoppingBag extends StatelessWidget {
4 | @override
5 | Widget build(BuildContext context) {
6 | return Container(
7 |
8 | );
9 | }
10 | }
--------------------------------------------------------------------------------
/lib/src/widgets/profile_customer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ProfileCustomer extends StatelessWidget {
4 | @override
5 | Widget build(BuildContext context) {
6 | return Container(
7 |
8 | );
9 | }
10 | }
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/app.dart';
2 | import 'package:firebase_core/firebase_core.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | void main() async {
6 | WidgetsFlutterBinding.ensureInitialized();
7 | await Firebase.initializeApp();
8 | runApp(App());
9 | }
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/src/styles/tabbar.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/colors.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | abstract class TabBarStyles {
5 |
6 | static Color get unselectedLabelColor => AppColors.lightgray;
7 | static Color get labelColor => AppColors.straw;
8 | static Color get indicatorColor => AppColors.straw;
9 | }
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: f139b11009aeb8ed2a3a3aa8b0066e482709dde3
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Flutter",
9 | "request": "launch",
10 | "type": "dart"
11 | }
12 | ]
13 | }
--------------------------------------------------------------------------------
/lib/src/models/application_user.dart:
--------------------------------------------------------------------------------
1 | class ApplicationUser {
2 | final String userId;
3 | final String email;
4 |
5 | ApplicationUser({this.email, this.userId});
6 |
7 | Map toMap(){
8 | return {
9 | 'userId': userId,
10 | 'email': email
11 | };
12 | }
13 |
14 | ApplicationUser.fromFirestore(Map firestore)
15 | : userId = firestore['userId'],
16 | email = firestore['email'];
17 | }
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/blocs/customer_bloc.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/models/market.dart';
2 | import 'package:farmers_market/src/models/product.dart';
3 | import 'package:farmers_market/src/services/firestore_service.dart';
4 |
5 | class CustomerBloc {
6 | final db = FirestoreService();
7 |
8 | //Get
9 | Stream> get fetchUpcomingMarkets => db.fetchUpcomingMarkets();
10 | Stream> get fetchAvailableProducts => db.fetchAvailableProducts();
11 |
12 | dispose(){
13 |
14 | }
15 | }
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/julow/farmers_market/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.julow.farmers_market
2 |
3 | import androidx.annotation.NonNull;
4 | import io.flutter.embedding.android.FlutterActivity
5 | import io.flutter.embedding.engine.FlutterEngine
6 | import io.flutter.plugins.GeneratedPluginRegistrant
7 |
8 | class MainActivity: FlutterActivity() {
9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
10 | GeneratedPluginRegistrant.registerWith(flutterEngine);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/lib/src/widgets/orders.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'dart:io';
5 |
6 | class Orders extends StatelessWidget{
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | if (Platform.isIOS){
11 | return CupertinoPageScaffold(
12 | child: pageBody(),
13 | );
14 | } else {
15 | return Scaffold(
16 | body: pageBody(),
17 | );
18 | }
19 | }
20 |
21 | Widget pageBody() {
22 | return Center(child: Text('Orders'),);
23 | }
24 | }
--------------------------------------------------------------------------------
/lib/src/styles/colors.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | abstract class AppColors {
4 | static Color get darkgray => const Color(0xFF4e5b60);
5 |
6 | static Color get lightgray => const Color(0xFFc8d6ef);
7 |
8 | static Color get darkblue => const Color(0xFF263a44);
9 |
10 | static Color get lightblue => const Color(0xFF48a1af);
11 |
12 | static Color get straw => const Color(0xFFe2a84b);
13 |
14 | static Color get red => const Color(0xFFee5253);
15 |
16 | static Color get green => const Color(0xFF3b7d02);
17 |
18 | static Color get facebook => const Color(0xFF3b5998);
19 |
20 | static Color get google => const Color(0xFF4285f4);
21 | }
22 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/lib/src/models/vendor.dart:
--------------------------------------------------------------------------------
1 | class Vendor {
2 | final String vendorId;
3 | final String name;
4 | final String imageUrl;
5 | final String description;
6 |
7 | Vendor({this.imageUrl, this.name, this.vendorId, this.description});
8 |
9 | Map toMap() {
10 | return {
11 | 'vendorId': vendorId,
12 | 'name': name,
13 | 'imageUrl': imageUrl,
14 | 'description': description
15 | };
16 | }
17 |
18 | factory Vendor.fromFirestore(Map firestore){
19 | if (firestore == null) return null;
20 |
21 | return Vendor(
22 | vendorId: firestore['vendorId'],
23 | name: firestore['name'],
24 | imageUrl: firestore ['imageUrl'],
25 | description: firestore['description']
26 | );
27 | }
28 | }
--------------------------------------------------------------------------------
/lib/src/services/firebase_storage_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_storage/firebase_storage.dart';
2 | import 'dart:io';
3 |
4 | class FirebaseStorageService {
5 |
6 | final storage = FirebaseStorage.instance;
7 |
8 | Future uploadProductImage(File file, String fileName) async {
9 | var snapshot = await storage.ref()
10 | .child('productImages/$fileName')
11 | .putFile(file)
12 | .onComplete;
13 |
14 | return await snapshot.ref.getDownloadURL();
15 | }
16 |
17 | Future uploadVendorImage(File file, String fileName) async {
18 | var snapshot = await storage.ref()
19 | .child('vendorImages/$fileName')
20 | .putFile(file)
21 | .onComplete;
22 |
23 | return await snapshot.ref.getDownloadURL();
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.google.gms:google-services:4.3.3' // Google Services plugin
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 | }
21 |
22 | rootProject.buildDir = '../build'
23 | subprojects {
24 | project.buildDir = "${rootProject.buildDir}/${project.name}"
25 | }
26 | subprojects {
27 | project.evaluationDependsOn(':app')
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/lib/src/models/location.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:flutter/foundation.dart';
3 |
4 | class Location {
5 | final String name;
6 | final String address;
7 | final String city;
8 | final String state;
9 | final GeoPoint geo;
10 | final String placesId;
11 |
12 | Location({
13 | @required this.name,
14 | @required this.address,
15 | @required this.city,
16 | @required this.state,
17 | this.geo,
18 | this.placesId
19 | });
20 |
21 | Location.fromFirestore(Map firestore)
22 | : name = firestore['name'],
23 | address = firestore['address'],
24 | city = firestore['city'],
25 | state = firestore['state'],
26 | geo = firestore['geo'] ?? null,
27 | placesId = firestore['placesId'] ?? null;
28 |
29 |
30 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | /build/
32 |
33 | # Web related
34 | lib/generated_plugin_registrant.dart
35 |
36 | # Exceptions to above rules.
37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
38 | android/app/google-services.json
39 | ios/Runner.xcodeproj/project.pbxproj
40 | ios/Runner.xcodeproj/project.pbxproj
41 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/src/models/market.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/models/location.dart';
2 | import 'package:flutter/foundation.dart';
3 |
4 | class Market {
5 | final String title;
6 | final String dateBegin;
7 | final String dateEnd;
8 | final Location location;
9 | final bool acceptingOrders;
10 | final String marketId;
11 |
12 | Market ({
13 | @required this.title,
14 | @required this.dateBegin,
15 | @required this.dateEnd,
16 | @required this.location,
17 | @required this.marketId,
18 | this.acceptingOrders = false
19 | });
20 |
21 | Market.fromFirestore(Map firestore)
22 | : title = firestore['title'],
23 | dateBegin = firestore['dateBegin'],
24 | dateEnd = firestore['dateEnd'],
25 | location = Location.fromFirestore(firestore['location']),
26 | marketId = firestore['marketId'],
27 | acceptingOrders = firestore['acceptingOrders'];
28 |
29 | }
--------------------------------------------------------------------------------
/lib/src/widgets/navbar.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/colors.dart';
2 | import 'package:farmers_market/src/styles/text.dart';
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | abstract class AppNavbar {
7 |
8 | static CupertinoSliverNavigationBar cupertinoNavBar ({String title, @required BuildContext context}) {
9 | return CupertinoSliverNavigationBar(
10 | largeTitle: Text(title, style: TextStyles.navTitle),
11 | backgroundColor: Colors.transparent,
12 | border: null,
13 | leading: GestureDetector(child: Icon(CupertinoIcons.back, color: AppColors.straw),onTap: () => Navigator.of(context).pop(),)
14 | );
15 | }
16 |
17 | static SliverAppBar materialNavBar({@required String title, bool pinned, TabBar tabBar}) {
18 | return SliverAppBar(
19 | title: Text(title, style: TextStyles.navTitleMaterial),
20 | backgroundColor: AppColors.darkblue,
21 | bottom: tabBar,
22 | floating: true,
23 | pinned: (pinned ==null) ? true : pinned,
24 | snap: true,
25 | );
26 |
27 | }
28 | }
--------------------------------------------------------------------------------
/lib/src/widgets/sliver_scaffold.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/widgets/navbar.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | abstract class AppSliverScaffold {
6 | static CupertinoPageScaffold cupertinoSliverScaffold(
7 | {String navTitle, Widget pageBody, BuildContext context}) {
8 | return CupertinoPageScaffold(
9 | child: NestedScrollView(
10 | headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
11 | return [
12 | AppNavbar.cupertinoNavBar(title: navTitle,context: context),
13 | ];
14 | },
15 | body: pageBody,
16 | ));
17 | }
18 |
19 | static Scaffold materialSliverScaffold(
20 | {String navTitle, Widget pageBody, BuildContext context}) {
21 | return Scaffold(
22 | body: NestedScrollView(
23 | headerSliverBuilder:
24 | (BuildContext context, bool innerBoxIsScrolled) {
25 | return [AppNavbar.materialNavBar(title: navTitle,pinned: false)];
26 | },
27 | body: pageBody));
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/src/styles/base.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/colors.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | abstract class BaseStyles{
5 |
6 | static double get borderRadius=> 25.0;
7 |
8 | static double get borderWidth=> 2.0;
9 |
10 | static double get listFieldHorizontal => 25.0;
11 |
12 | static double get listFieldVertical => 8.0;
13 |
14 | static double get animationOffset => 2.0;
15 |
16 |
17 |
18 | static EdgeInsets get listPadding {
19 | return EdgeInsets.symmetric(horizontal: listFieldHorizontal, vertical: listFieldVertical);
20 | }
21 |
22 | static List get boxShadow {
23 | return [
24 | BoxShadow(
25 | color: AppColors.darkgray.withOpacity(.5),
26 | offset: Offset(1.0, 2.0),
27 | blurRadius: 2.0,
28 | )
29 | ];
30 | }
31 |
32 | static List get boxShadowPressed {
33 | return [
34 | BoxShadow(
35 | color: AppColors.darkgray.withOpacity(.5),
36 | offset: Offset(1.0, 1.0),
37 | blurRadius: 1.0,
38 | )
39 | ];
40 | }
41 |
42 | static Widget iconPrefix(IconData icon) {
43 | return Padding(
44 | padding: const EdgeInsets.only(left: 8.0),
45 | child: Icon(icon, size: 35.0, color: AppColors.lightblue),
46 | );
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/lib/src/widgets/vendor_scaffold.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/colors.dart';
2 | import 'package:farmers_market/src/widgets/orders.dart';
3 | import 'package:farmers_market/src/widgets/products.dart';
4 | import 'package:farmers_market/src/widgets/profile.dart';
5 | import 'package:flutter/cupertino.dart';
6 |
7 | abstract class VendorScaffold {
8 | static CupertinoTabScaffold get cupertinoTabScaffold {
9 | return CupertinoTabScaffold(
10 | tabBar: _cupertinoTabBar,
11 | tabBuilder: (context, index) {
12 | return _pageSelection(index);
13 | },
14 | );
15 | }
16 |
17 | static get _cupertinoTabBar {
18 | return CupertinoTabBar(
19 | backgroundColor: AppColors.darkblue,
20 | items: [
21 | BottomNavigationBarItem(
22 | icon: Icon(CupertinoIcons.create), title: Text('Products')),
23 | BottomNavigationBarItem(
24 | icon: Icon(CupertinoIcons.shopping_cart), title: Text('Orders')),
25 | BottomNavigationBarItem(
26 | icon: Icon(CupertinoIcons.person), title: Text('Profile')),
27 | ],
28 | );
29 | }
30 |
31 | static Widget _pageSelection(int index) {
32 | if (index == 0) {
33 | return Products();
34 | }
35 |
36 | if (index == 1) {
37 | return Orders();
38 | }
39 |
40 | return Profile();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ios/Runner/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CLIENT_ID
6 | 176096730439-lqmc4tefmon0f1i20upl4nci0nnfh587.apps.googleusercontent.com
7 | REVERSED_CLIENT_ID
8 | com.googleusercontent.apps.176096730439-lqmc4tefmon0f1i20upl4nci0nnfh587
9 | ANDROID_CLIENT_ID
10 | 176096730439-jbrjftjukmud03mnkro156crhoog77qf.apps.googleusercontent.com
11 | API_KEY
12 | AIzaSyD_hOduvwxmlNaOqi9cJ6U_E6pFbPLOoAY
13 | GCM_SENDER_ID
14 | 176096730439
15 | PLIST_VERSION
16 | 1
17 | BUNDLE_ID
18 | com.julow.farmersMarket
19 | PROJECT_ID
20 | farmers-market-89c2a
21 | STORAGE_BUCKET
22 | farmers-market-89c2a.appspot.com
23 | IS_ADS_ENABLED
24 |
25 | IS_ANALYTICS_ENABLED
26 |
27 | IS_APPINVITE_ENABLED
28 |
29 | IS_GCM_ENABLED
30 |
31 | IS_SIGNIN_ENABLED
32 |
33 | GOOGLE_APP_ID
34 | 1:176096730439:ios:f48cf4c8ebd008fe720062
35 | DATABASE_URL
36 | https://farmers-market-89c2a.firebaseio.com
37 |
38 |
--------------------------------------------------------------------------------
/lib/src/widgets/customer_scaffold.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/colors.dart';
2 | import 'package:farmers_market/src/widgets/products_customer.dart';
3 | import 'package:farmers_market/src/widgets/profile_customer.dart';
4 | import 'package:farmers_market/src/widgets/shopping_bag.dart';
5 | import 'package:flutter/cupertino.dart';
6 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
7 |
8 | abstract class CustomerScaffold {
9 | static CupertinoTabScaffold get cupertinoTabScaffold {
10 | return CupertinoTabScaffold(
11 | tabBar: _cupertinoTabBar,
12 | tabBuilder: (context, index) {
13 | return _pageSelection(index);
14 | },
15 | );
16 | }
17 |
18 | static get _cupertinoTabBar {
19 | return CupertinoTabBar(
20 | backgroundColor: AppColors.darkblue,
21 | items: [
22 | BottomNavigationBarItem(
23 | icon: Icon(CupertinoIcons.create), title: Text('Products')),
24 | BottomNavigationBarItem(
25 | icon: Icon(FontAwesomeIcons.shoppingBag), title: Text('Orders')),
26 | BottomNavigationBarItem(
27 | icon: Icon(CupertinoIcons.person), title: Text('Profile')),
28 | ],
29 | );
30 | }
31 |
32 | static Widget _pageSelection(int index) {
33 | if (index == 0) {
34 | return ProductsCustomer();
35 | }
36 |
37 | if (index == 1) {
38 | return ShoppingBag();
39 | }
40 |
41 | return ProfileCustomer();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/src/widgets/profile.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/blocs/auth_bloc.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'dart:io';
5 |
6 | import 'package:provider/provider.dart';
7 |
8 | class Profile extends StatelessWidget {
9 | @override
10 | Widget build(BuildContext context) {
11 | if (Platform.isIOS) {
12 | return CupertinoPageScaffold(
13 | child: pageBody(context),
14 | );
15 | } else {
16 | return Scaffold(
17 | body: pageBody(context),
18 | );
19 | }
20 | }
21 |
22 | Widget pageBody(BuildContext context) {
23 | var authBloc = Provider.of(context);
24 | // return Center(
25 | // child: (Platform.isIOS)
26 | // ? CupertinoButton(
27 | // child: Text('Logout'),
28 | // onPressed: () => authBloc.logout(),
29 | // )
30 | // : FlatButton(
31 | // child: Text('Logout'),
32 | // onPressed: () => authBloc.logout(),
33 | // ));
34 |
35 | return Center(
36 | child: (Platform.isIOS)
37 | ? CupertinoButton(
38 | child: Text('Add'),
39 | onPressed: () => Navigator.of(context).pushNamed('/editvendor') ,
40 | )
41 | : FlatButton(
42 | child: Text('Add'),
43 | onPressed: () => Navigator.of(context).pushNamed('/editvendor'),
44 | ));
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/src/models/product.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 |
3 | class Product{
4 | final String productName;
5 | final String unitType;
6 | final double unitPrice;
7 | final int availableUnits;
8 | final String vendorId;
9 | final String productId;
10 | final String imageUrl;
11 | final bool approved;
12 | final String note;
13 |
14 | Product({
15 | @required this.approved,
16 | @required this.availableUnits,
17 | this.imageUrl = "",
18 | this.note = "",
19 | @required this.productId,
20 | @required this.productName,
21 | @required this.unitPrice,
22 | @required this.unitType,
23 | @required this.vendorId
24 | });
25 |
26 | Map toMap() {
27 | return {
28 | 'productName' : productName,
29 | 'unitType' : unitType,
30 | 'unitPrice' : unitPrice,
31 | 'availableUnits': availableUnits,
32 | 'approved': approved,
33 | 'imageUrl':imageUrl,
34 | 'note':note,
35 | 'productId':productId,
36 | 'vendorId':vendorId
37 | };
38 | }
39 |
40 | Product.fromFirestore(Map firestore)
41 | : productName = firestore['productName'],
42 | unitType = firestore['unitType'],
43 | unitPrice = firestore['unitPrice'],
44 | availableUnits = firestore['availableUnits'],
45 | approved = firestore['approved'],
46 | imageUrl = firestore['imageUrl'],
47 | note = firestore['note'],
48 | productId = firestore['productId'],
49 | vendorId = firestore['vendorId'];
50 | }
--------------------------------------------------------------------------------
/lib/src/widgets/social_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/base.dart';
2 | import 'package:farmers_market/src/styles/buttons.dart';
3 | import 'package:farmers_market/src/styles/colors.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
6 |
7 | class AppSocialButton extends StatelessWidget {
8 | final SocialType socialType;
9 |
10 | AppSocialButton({@required this.socialType});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | Color buttonColor;
15 | Color iconColor;
16 | IconData icon;
17 |
18 | switch (socialType) {
19 | case SocialType.Facebook:
20 | iconColor = Colors.white;
21 | buttonColor = AppColors.facebook;
22 | icon = FontAwesomeIcons.facebookF;
23 | break;
24 | case SocialType.Google:
25 | iconColor = Colors.white;
26 | buttonColor = AppColors.google;
27 | icon = FontAwesomeIcons.google;
28 | break;
29 | default:
30 | iconColor = Colors.white;
31 | buttonColor = AppColors.facebook;
32 | icon = FontAwesomeIcons.facebookF;
33 | break;
34 | }
35 |
36 | return Container(
37 | height: ButtonStyles.buttonHeight,
38 | width: ButtonStyles.buttonHeight,
39 | decoration: BoxDecoration(
40 | color: buttonColor,
41 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius),
42 | boxShadow: BaseStyles.boxShadow),
43 | child: Icon(icon, color: iconColor),
44 | );
45 | }
46 | }
47 |
48 | enum SocialType { Facebook, Google }
49 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
12 |
19 |
20 |
21 |
22 |
23 |
24 |
26 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/src/widgets/alerts.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/text.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | abstract class AppAlerts {
6 |
7 | static Future showErrorDialog(bool isIOS,BuildContext context, String errorMessage) async {
8 |
9 | return (isIOS)
10 | ? showCupertinoDialog(
11 | context: context,
12 | builder: (context){
13 | return CupertinoAlertDialog(
14 | title: Text('Error',style: TextStyles.subtitle,),
15 | content: SingleChildScrollView(
16 | child: ListBody(
17 | children: [
18 | Text(errorMessage, style: TextStyles.body)
19 | ],
20 | ),
21 | ),
22 | actions: [
23 | CupertinoButton(
24 | child: Text('Okay',style: TextStyles.body),
25 | onPressed: () => Navigator.of(context).pop(),
26 | )
27 | ],
28 | );
29 | }
30 | )
31 | : showDialog(
32 | context: context,
33 | barrierDismissible: false,
34 | builder: (context){
35 | return AlertDialog(
36 | title: Text('Error',style: TextStyles.subtitle,),
37 | content: SingleChildScrollView(
38 | child: ListBody(
39 | children: [
40 | Text(errorMessage, style: TextStyles.body)
41 | ],
42 | ),
43 | ),
44 | actions: [
45 | FlatButton(
46 | child: Text('Okay',style: TextStyles.body),
47 | onPressed: () => Navigator.of(context).pop(),
48 | )
49 | ],
50 | );
51 | }
52 | );
53 | }
54 |
55 | }
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | farmers_market
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 | NSPhotoLibraryUsageDescription
45 | Permission to access photos for upload
46 |
47 |
48 |
--------------------------------------------------------------------------------
/lib/src/widgets/list_tile.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/base.dart';
2 | import 'package:farmers_market/src/styles/colors.dart';
3 | import 'package:farmers_market/src/styles/text.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
6 |
7 | class AppListTile extends StatelessWidget {
8 | final String month;
9 | final String date;
10 | final String title;
11 | final String location;
12 | final bool acceptingOrders;
13 | final String marketId;
14 |
15 | AppListTile({
16 | @required this.month,
17 | @required this.date,
18 | @required this.title,
19 | @required this.location,
20 | @required this.marketId,
21 | this.acceptingOrders = false
22 | });
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return Column(
27 | children: [
28 | ListTile(
29 | leading: CircleAvatar(
30 | radius: 25.0,
31 | backgroundColor: AppColors.lightblue,
32 | child: Column(
33 | mainAxisAlignment: MainAxisAlignment.center,
34 | children: [
35 | Text(month,style: TextStyle(color:Colors.white, fontSize: 12.0),),
36 | Text(date, style: TextStyles.buttonTextLight)
37 | ],),
38 | ),
39 | title: Text(title,style:TextStyles.subtitle),
40 | subtitle: Text(location),
41 | trailing:(acceptingOrders) ? Icon(FontAwesomeIcons.shoppingBasket,color: AppColors.darkblue,): Text(''),
42 | onTap: (acceptingOrders) ? () => Navigator.of(context).pushNamed('/customer/$marketId'): null,
43 | ),
44 | Padding(
45 | padding: EdgeInsets.symmetric(horizontal: BaseStyles.listFieldHorizontal),
46 | child: Divider(color:AppColors.lightgray),
47 | )
48 | ],
49 | );
50 |
51 | }
52 | }
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply plugin: 'com.google.gms.google-services' // Google Services plugin
27 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
28 |
29 | android {
30 | compileSdkVersion 28
31 |
32 | sourceSets {
33 | main.java.srcDirs += 'src/main/kotlin'
34 | }
35 |
36 | lintOptions {
37 | disable 'InvalidPackage'
38 | }
39 |
40 | defaultConfig {
41 | applicationId "com.julow.farmers_market"
42 | minSdkVersion 21
43 | targetSdkVersion 28
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
47 | }
48 |
49 | buildTypes {
50 | release {
51 | // TODO: Add your own signing config for the release build.
52 | // Signing with the debug keys for now, so `flutter run --release` works.
53 | signingConfig signingConfigs.debug
54 | }
55 | }
56 | }
57 |
58 | flutter {
59 | source '../..'
60 | }
61 |
62 | dependencies {
63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
64 | testImplementation 'junit:junit:4.12'
65 | androidTestImplementation 'androidx.test:runner:1.1.1'
66 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
67 | }
68 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Farmer's Market Mobile Ordering Application
2 |
3 | This application will be similar to the Mobile Ordering system introduced by Walt Disney World where customers may place their order online and confirm their proximity to the market via location of the device. The vendor can confirm their order accept payment by Stripe and let the customer know where they can pickup the order. If desired, the vendor can confirm the customer by flashing the flash on their device. The entire transaction can take place without any personal contact.
4 |
5 | This will be an open source project and anyone is welcome to fork, clone and use the code for their own purposes. The application is meant to be of public use and the development is intended for educational purposes for Flutter developers. Each episode in the series will be a branch in the repository. Episode 1 contains no coding and does not have a branch
6 |
7 | Concepts introduced in the development of the application will include: Firebase, Firestore, 3rd Party Authentication, push notifications, provider, rxdart, cupertino scaffolding, plugins, geocoding, Strip, and Google Maps (and maybe more).
8 |
9 | Development of the application will be documented on my YouTube channel https://www.youtube.com/channel/UCSKeK_8IzsqwKQBJuIGJPaA
10 |
11 | ## Getting Started
12 | To run the code beyond part 5 you will need to establish a firebase project, add an IOS and Android application using the Flutter instructions here https://firebase.google.com/docs/flutter/setup?authuser=0&platform=ios
13 |
14 | To run beyond part 18, add a Firestore database to your project with rules set to allow read, write: if request.auth.uid != null;
15 | You will also need to enable email authentication in your firebase project.
16 |
17 |
18 | ## Episode History
19 |
20 | ### Part 1: Application Concept (No Branch)
21 | ### Part 2: App Setup and Routes
22 | ### Part 3: App Platform Splitting
23 | ### Part 4: Adding Firebase
24 | ### Part 5: Login Flow (No Branch)
25 | ### Part 6: Login UI
26 | ### Part 7: Cupertino TextField (in Part8 branch)
27 | ### Part 8: Material TextField
28 | ### Part 9: Application TextField
29 | ### Part 10: Application Buttons
30 | ### Part 11: Social Media Buttons
31 | ### Part 12: Signup UI
32 | ### Part 13: Why RXDart? (no branch)
33 | ### Part 14: TheAuth BLoC
34 | ### Part 15: Material Validation
35 | ### Part 16: Cupertino Validation
36 | ### Part 17: Submit Button Revisited
37 | ### Part 18: Adding the First User
38 | ### Part 19: User Story Mapping
39 | ### Part 20: Logging In
40 | ### Part 21: IOS Sliver AppBar
41 |
42 |
--------------------------------------------------------------------------------
/lib/src/widgets/card.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/base.dart';
2 | import 'package:farmers_market/src/styles/colors.dart';
3 | import 'package:farmers_market/src/styles/text.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:intl/intl.dart';
6 |
7 | class AppCard extends StatelessWidget {
8 | final String productName;
9 | final String unitType;
10 | final int availableUnits;
11 | final double price;
12 | final String note;
13 | final String imageUrl;
14 |
15 | final formatCurrency = NumberFormat.simpleCurrency();
16 |
17 | AppCard({
18 | @required this.productName,
19 | @required this.unitType,
20 | @required this.availableUnits,
21 | @required this.price,
22 | this.imageUrl,
23 | this.note = "",
24 | });
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | return Container(
29 | margin: BaseStyles.listPadding,
30 | padding: BaseStyles.listPadding,
31 | decoration: BoxDecoration(
32 | boxShadow: BaseStyles.boxShadow,
33 | color: Colors.white,
34 | border: Border.all(
35 | color: AppColors.darkblue,
36 | width: BaseStyles.borderWidth,
37 | ),
38 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius)
39 | ),
40 | child: Column(
41 | children: [
42 | Row(
43 | children: [
44 | Padding(
45 | padding: const EdgeInsets.only(right: 10.0, bottom: 10.0, top: 10.0),
46 | child: (imageUrl != null && imageUrl != "")
47 | ? ClipRRect(child: Image.network(imageUrl, height: 100.0,)
48 | ,borderRadius: BorderRadius.circular(5.0),)
49 | : Image.asset('assets/images/vegetables.png', height: 100.0,),
50 | child: Image.asset('assets/images/vegetables.png', height: 100.0,),
51 | ),
52 | Column(
53 | crossAxisAlignment: CrossAxisAlignment.start,
54 | children: [
55 | Text(productName,style: TextStyles.subtitle),
56 | Text('${formatCurrency.format(price)}/$unitType', style: TextStyles.body),
57 | (availableUnits > 0 )
58 | ? Text('In Stock', style: TextStyles.bodyLightBlue)
59 | : Text('Currently Unavailable',style: TextStyles.bodyRed)
60 | ],)
61 | ],
62 | ),
63 | Text(note, style: TextStyles.body)
64 | ],
65 | ),
66 | );
67 | }
68 | }
--------------------------------------------------------------------------------
/lib/src/styles/textfields.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/base.dart';
2 | import 'package:farmers_market/src/styles/colors.dart';
3 | import 'package:farmers_market/src/styles/text.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | abstract class TextFieldStyles {
7 | static double get textBoxHorizontal => BaseStyles.listFieldHorizontal;
8 |
9 | static double get textBoxVertical => BaseStyles.listFieldVertical;
10 |
11 | static TextStyle get text => TextStyles.body;
12 |
13 | static TextStyle get placeholder => TextStyles.suggestion;
14 |
15 | static Color get cursorColor => AppColors.darkblue;
16 |
17 | static Widget iconPrefix(IconData icon) => BaseStyles.iconPrefix(icon);
18 |
19 | static TextAlign get textAlign => TextAlign.center;
20 |
21 | static BoxDecoration get cupertinoDecoration {
22 | return BoxDecoration(
23 | border: Border.all(
24 | color: AppColors.straw,
25 | width: BaseStyles.borderWidth,
26 | ),
27 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius));
28 | }
29 |
30 | static BoxDecoration get cupertinoErrorDecoration {
31 | return BoxDecoration(
32 | border: Border.all(
33 | color: AppColors.red,
34 | width: BaseStyles.borderWidth,
35 | ),
36 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius));
37 | }
38 |
39 | static InputDecoration materialDecoration(
40 | String hintText, IconData icon, String errorText) {
41 | return InputDecoration(
42 | contentPadding: EdgeInsets.all(8.0),
43 | hintText: hintText,
44 | hintStyle: TextFieldStyles.placeholder,
45 | border: InputBorder.none,
46 | errorText: errorText,
47 | errorStyle: TextStyles.error,
48 | focusedBorder: OutlineInputBorder(
49 | borderSide:
50 | BorderSide(color: AppColors.straw, width: BaseStyles.borderWidth),
51 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius)),
52 | enabledBorder: OutlineInputBorder(
53 | borderSide:
54 | BorderSide(color: AppColors.straw, width: BaseStyles.borderWidth),
55 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius)),
56 | focusedErrorBorder: OutlineInputBorder(
57 | borderSide:
58 | BorderSide(color: AppColors.straw, width: BaseStyles.borderWidth),
59 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius)),
60 | errorBorder: OutlineInputBorder(
61 | borderSide:
62 | BorderSide(color: AppColors.red, width: BaseStyles.borderWidth),
63 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius)),
64 | prefixIcon: iconPrefix(icon),
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/src/screens/vendor.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:farmers_market/src/blocs/auth_bloc.dart';
4 | import 'package:farmers_market/src/styles/tabbar.dart';
5 | import 'package:farmers_market/src/widgets/navbar.dart';
6 | import 'package:farmers_market/src/widgets/orders.dart';
7 | import 'package:farmers_market/src/widgets/products.dart';
8 | import 'package:farmers_market/src/widgets/profile.dart';
9 | import 'package:farmers_market/src/widgets/vendor_scaffold.dart';
10 | import 'package:flutter/cupertino.dart';
11 | import 'package:flutter/material.dart';
12 | import 'dart:io';
13 |
14 | import 'package:provider/provider.dart';
15 |
16 | class Vendor extends StatefulWidget {
17 |
18 |
19 | @override
20 | _VendorState createState() => _VendorState();
21 |
22 | static TabBar get vendorTabBar {
23 | return TabBar(
24 | unselectedLabelColor: TabBarStyles.unselectedLabelColor ,
25 | labelColor: TabBarStyles.labelColor ,
26 | indicatorColor: TabBarStyles.indicatorColor ,
27 | tabs: [
28 | Tab(icon: Icon(Icons.list)),
29 | Tab(icon: Icon(Icons.shopping_cart)),
30 | Tab(icon: Icon(Icons.person)),
31 | ],
32 | );
33 | }
34 | }
35 |
36 | class _VendorState extends State {
37 | StreamSubscription _userSubscription;
38 |
39 | @override
40 | void initState() {
41 | Future.delayed(Duration.zero, (){
42 | var authBloc = Provider.of(context,listen: false);
43 | _userSubscription = authBloc.user.listen((user) {
44 | if (user == null) Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false);
45 | });
46 | });
47 |
48 | super.initState();
49 | }
50 |
51 | @override
52 | void dispose() {
53 | _userSubscription.cancel();
54 | super.dispose();
55 | }
56 |
57 | @override
58 | Widget build(BuildContext context) {
59 |
60 | if (Platform.isIOS) {
61 | return CupertinoPageScaffold(
62 | child: NestedScrollView(
63 | headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
64 | return [
65 | AppNavbar.cupertinoNavBar(title: 'Vendor Name',context: context),
66 | ];
67 | },
68 | body: VendorScaffold.cupertinoTabScaffold,
69 | ),
70 | );
71 | } else {
72 | return DefaultTabController(
73 | length: 3,
74 | child: Scaffold(
75 | body: NestedScrollView(
76 | headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
77 | return [
78 | AppNavbar.materialNavBar(title: 'Vendor Name', tabBar: Vendor.vendorTabBar)
79 | ];
80 | },
81 | body: TabBarView(children: [
82 | Products(),
83 | Orders(),
84 | Profile(),
85 | ],)
86 | )
87 | ),
88 | );
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/lib/src/styles/text.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/colors.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:google_fonts/google_fonts.dart';
4 |
5 | abstract class TextStyles {
6 | static TextStyle get title {
7 | return GoogleFonts.poppins(
8 | textStyle: TextStyle(
9 | color: AppColors.darkblue,
10 | fontWeight: FontWeight.bold,
11 | fontSize: 40.0));
12 | }
13 |
14 | static TextStyle get subtitle {
15 | return GoogleFonts.economica(
16 | textStyle: TextStyle(
17 | color: AppColors.straw,
18 | fontWeight: FontWeight.bold,
19 | fontSize: 30.0));
20 | }
21 |
22 | static TextStyle get listTitle {
23 | return GoogleFonts.economica(
24 | textStyle: TextStyle(
25 | color: AppColors.straw,
26 | fontWeight: FontWeight.bold,
27 | fontSize: 25.0));
28 | }
29 |
30 | static TextStyle get navTitle {
31 | return GoogleFonts.poppins(
32 | textStyle:
33 | TextStyle(color: AppColors.darkblue, fontWeight: FontWeight.bold));
34 | }
35 |
36 | static TextStyle get navTitleMaterial {
37 | return GoogleFonts.poppins(
38 | textStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold));
39 | }
40 |
41 | static TextStyle get body {
42 | return GoogleFonts.roboto(
43 | textStyle: TextStyle(color: AppColors.darkgray, fontSize: 16.0));
44 | }
45 |
46 | static TextStyle get bodyLightBlue {
47 | return GoogleFonts.roboto(
48 | textStyle: TextStyle(color: AppColors.lightblue, fontSize: 16.0));
49 | }
50 |
51 | static TextStyle get bodyRed {
52 | return GoogleFonts.roboto(
53 | textStyle: TextStyle(color: AppColors.red, fontSize: 16.0));
54 | }
55 |
56 | static TextStyle get picker {
57 | return GoogleFonts.roboto(
58 | textStyle: TextStyle(color: AppColors.darkgray, fontSize: 35.0));
59 | }
60 |
61 |
62 | static TextStyle get link {
63 | return GoogleFonts.roboto(
64 | textStyle: TextStyle(
65 | color: AppColors.straw,
66 | fontSize: 16.0,
67 | fontWeight: FontWeight.bold));
68 | }
69 |
70 | static TextStyle get suggestion {
71 | return GoogleFonts.roboto(
72 | textStyle: TextStyle(color: AppColors.lightgray, fontSize: 14.0));
73 | }
74 |
75 | static TextStyle get error {
76 | return GoogleFonts.roboto(
77 | textStyle: TextStyle(color: AppColors.red, fontSize: 12.0));
78 | }
79 |
80 | static TextStyle get buttonTextLight {
81 | return GoogleFonts.roboto(
82 | textStyle: TextStyle(
83 | color: Colors.white, fontSize: 17.0, fontWeight: FontWeight.bold));
84 | }
85 |
86 | static TextStyle get buttonTextDark {
87 | return GoogleFonts.roboto(
88 | textStyle: TextStyle(
89 | color: AppColors.darkgray,
90 | fontSize: 17.0,
91 | fontWeight: FontWeight.bold));
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/lib/src/widgets/products_customer.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:farmers_market/src/blocs/customer_bloc.dart';
4 | import 'package:farmers_market/src/models/product.dart';
5 | import 'package:farmers_market/src/styles/colors.dart';
6 | import 'package:farmers_market/src/styles/text.dart';
7 | import 'package:flutter/cupertino.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:intl/intl.dart';
10 | import 'package:provider/provider.dart';
11 |
12 | class ProductsCustomer extends StatelessWidget {
13 | final formatCurrency = NumberFormat.simpleCurrency();
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | var customerBloc = Provider.of(context);
18 |
19 | return StreamBuilder>(
20 | stream: customerBloc.fetchAvailableProducts,
21 | builder: (context, snapshot) {
22 | if (!snapshot.hasData)
23 | return Center(
24 | child: (Platform.isIOS)
25 | ? CupertinoActivityIndicator()
26 | : CircularProgressIndicator(),
27 | );
28 |
29 | return Scaffold(
30 | body: Column(
31 | children: [
32 | Expanded(
33 | child: ListView.builder(
34 | itemCount: snapshot.data.length,
35 | itemBuilder: (context, index) {
36 | var product = snapshot.data[index];
37 |
38 | return Column(
39 | children: [
40 | ListTile(
41 | leading: CircleAvatar(
42 | backgroundImage: (product.imageUrl != '')
43 | ? NetworkImage(product.imageUrl)
44 | : AssetImage('assets/images/vegetables.png'),
45 | radius: 25.0,
46 | ),
47 | title: Text(product.productName,style:TextStyles.listTitle),
48 | subtitle: Text('The Vendor'),
49 | trailing: Text('${formatCurrency.format(product.unitPrice)}/${product.unitType}',style:TextStyles.bodyLightBlue),
50 | ),
51 | Divider(color: AppColors.lightgray,)
52 | ],
53 | );
54 | }),
55 | ),
56 | Container(
57 | height: 50.0,
58 | width: double.infinity,
59 | color: AppColors.straw,
60 | child: (Platform.isIOS)
61 | ? Icon(IconData(0xF38B,fontFamily: CupertinoIcons.iconFont, fontPackage: CupertinoIcons.iconFontPackage),color:Colors.white, size:35.0)
62 | : Icon(Icons.filter_list,color:Colors.white, size:35.0) ,
63 | )
64 | ],
65 | ),
66 | );
67 | });
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/lib/src/services/firestore_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:farmers_market/src/models/application_user.dart';
3 | import 'package:farmers_market/src/models/market.dart';
4 | import 'package:farmers_market/src/models/product.dart';
5 | import 'package:farmers_market/src/models/vendor.dart';
6 |
7 |
8 | class FirestoreService {
9 | FirebaseFirestore _db = FirebaseFirestore.instance;
10 |
11 | Future addUser(ApplicationUser user) {
12 | return _db.collection('users').doc(user.userId).set(user.toMap());
13 | }
14 |
15 | Future fetchUser(String userId) {
16 | return _db
17 | .collection('users')
18 | .doc(userId)
19 | .get()
20 | .then((snapshot) => ApplicationUser.fromFirestore(snapshot.data()));
21 | }
22 |
23 | Stream> fetchUnitTypes() {
24 | return _db.collection('types').doc('units').snapshots().map(
25 | (snapshot) => snapshot.data()['production']
26 | .map((type) => type.toString())
27 | .toList());
28 | }
29 |
30 | Future setProduct(Product product) {
31 | var options = SetOptions(merge:true);
32 | return _db
33 | .collection('products')
34 | .doc(product.productId)
35 | .set(product.toMap(),options);
36 | }
37 |
38 | Future fetchProduct(String productId){
39 | return _db.collection('products').doc(productId)
40 | .get().then((snapshot) => Product.fromFirestore(snapshot.data()));
41 | }
42 |
43 | Stream> fetchProductsByVendorId(String vendorId) {
44 | return _db
45 | .collection('products')
46 | .where('vendorId', isEqualTo: vendorId)
47 | .snapshots()
48 | .map((query) => query.docs)
49 | .map((snapshot) =>
50 | snapshot.map((doc) => Product.fromFirestore(doc.data()))
51 | .toList());
52 | }
53 |
54 | Stream> fetchUpcomingMarkets(){
55 | return _db
56 | .collection('markets')
57 | .where('dateEnd', isGreaterThan: DateTime.now().toIso8601String())
58 | .snapshots()
59 | .map((query) => query.docs)
60 | .map((snapshot) => snapshot
61 | .map((doc) => Market.fromFirestore(doc.data()))
62 | .toList());
63 | }
64 |
65 | Stream> fetchAvailableProducts(){
66 | return _db
67 | .collection('products')
68 | .where('availableUnits', isGreaterThan: 0)
69 | .snapshots()
70 | .map((query) => query.docs)
71 | .map((snapshot) => snapshot.map((doc) => Product.fromFirestore(doc.data()))
72 | .toList());
73 | }
74 |
75 | Future fetchVendor(String vendorId){
76 | return _db
77 | .collection('vendors')
78 | .doc(vendorId)
79 | .get().then((snapshot) => Vendor.fromFirestore(snapshot.data()));
80 | }
81 |
82 | Future setVendor(Vendor vendor){
83 | var options = SetOptions(merge:true);
84 |
85 | return _db
86 | .collection('vendors')
87 | .doc(vendor.vendorId)
88 | .set(vendor.toMap(),options);
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/lib/src/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/blocs/auth_bloc.dart';
2 | import 'package:farmers_market/src/blocs/customer_bloc.dart';
3 | import 'package:farmers_market/src/blocs/product_bloc.dart';
4 | import 'package:farmers_market/src/routes.dart';
5 | import 'package:farmers_market/src/screens/landing.dart';
6 | import 'package:farmers_market/src/screens/login.dart';
7 | import 'package:farmers_market/src/services/firestore_service.dart';
8 | import 'package:farmers_market/src/styles/colors.dart';
9 | import 'package:farmers_market/src/styles/text.dart';
10 | import 'package:flutter/cupertino.dart';
11 | import 'package:flutter/material.dart';
12 | import 'dart:io';
13 |
14 | import 'package:provider/provider.dart';
15 |
16 | import 'blocs/vendor_bloc.dart';
17 | final authBloc = AuthBloc();
18 | final productBloc = ProductBloc();
19 | final customerBloc = CustomerBloc();
20 | final vendorBloc = VendorBloc();
21 | final firestoreService = FirestoreService();
22 |
23 | class App extends StatefulWidget {
24 | @override
25 | _AppState createState() => _AppState();
26 | }
27 |
28 | class _AppState extends State {
29 | @override
30 | Widget build(BuildContext context) {
31 | return MultiProvider(
32 | providers: [
33 | Provider(create: (context) => authBloc),
34 | Provider(create: (context) => productBloc),
35 | Provider(create: (context) => customerBloc,),
36 | Provider(create: (context) => vendorBloc,),
37 | FutureProvider(create: (context) => authBloc.isLoggedIn()),
38 | StreamProvider(create: (context) => firestoreService.fetchUnitTypes())
39 | ],
40 | child: PlatformApp());
41 | }
42 |
43 | @override
44 | void dispose() {
45 | authBloc.dispose();
46 | productBloc.dispose();
47 | customerBloc.dispose();
48 | vendorBloc.dispose();
49 | super.dispose();
50 | }
51 | }
52 |
53 | class PlatformApp extends StatelessWidget {
54 |
55 | @override
56 | Widget build(BuildContext context) {
57 |
58 | var isLoggedIn = Provider.of(context);
59 |
60 | if (Platform.isIOS) {
61 | return CupertinoApp(
62 | home: (isLoggedIn == null) ? loadingScreen(true) : (isLoggedIn == true ) ? Landing() : Login(),
63 | onGenerateRoute: Routes.cupertinoRoutes,
64 | theme: CupertinoThemeData(
65 | primaryColor: AppColors.straw,
66 | scaffoldBackgroundColor: Colors.white,
67 | textTheme: CupertinoTextThemeData(
68 | tabLabelTextStyle: TextStyles.suggestion
69 | )
70 | )
71 | );
72 | } else {
73 | return MaterialApp(
74 | home: (isLoggedIn == null) ? loadingScreen(false) : (isLoggedIn == true ) ? Landing() : Login(),
75 | onGenerateRoute: Routes.materialRoutes,
76 | theme: ThemeData(scaffoldBackgroundColor: Colors.white)
77 | );
78 | }
79 | }
80 |
81 | Widget loadingScreen(bool isIOS){
82 | return (isIOS)
83 | ? CupertinoPageScaffold(child: Center(child: CupertinoActivityIndicator(),),)
84 | : Scaffold(body: Center(child: CircularProgressIndicator()));
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/src/routes.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/screens/customer.dart';
2 | import 'package:farmers_market/src/screens/edit_product.dart';
3 | import 'package:farmers_market/src/screens/edit_vendor.dart';
4 | import 'package:farmers_market/src/screens/landing.dart';
5 | import 'package:farmers_market/src/screens/login.dart';
6 | import 'package:farmers_market/src/screens/signup.dart';
7 | import 'package:farmers_market/src/screens/vendor.dart';
8 | import 'package:flutter/cupertino.dart';
9 | import 'package:flutter/material.dart';
10 |
11 | abstract class Routes {
12 | static MaterialPageRoute materialRoutes(RouteSettings settings) {
13 | switch (settings.name) {
14 | case "/landing":
15 | return MaterialPageRoute(builder: (context) => Landing());
16 | case "/signup":
17 | return MaterialPageRoute(builder: (context) => Signup());
18 | case "/login":
19 | return MaterialPageRoute(builder: (context) => Login());
20 | case "/vendor":
21 | return MaterialPageRoute(builder: (context) => Vendor());
22 | case "/editproduct":
23 | return MaterialPageRoute(builder: (context) => EditProduct());
24 | case "/editvendor":
25 | return MaterialPageRoute(builder: (context) => EditVendor());
26 | default:
27 | var routeArray = settings.name.split('/');
28 | if (settings.name.contains('/editproduct/')) {
29 | return MaterialPageRoute(
30 | builder: (context) => EditProduct(
31 | productId: routeArray[2],
32 | ));
33 | } else if (settings.name.contains('/customer/')) {
34 | return MaterialPageRoute(
35 | builder: (context) => Customer(
36 | marketId: routeArray[2],
37 | ));
38 | }
39 | return MaterialPageRoute(builder: (context) => Login());
40 | }
41 | }
42 |
43 | static CupertinoPageRoute cupertinoRoutes(RouteSettings settings) {
44 | switch (settings.name) {
45 | case "/landing":
46 | return CupertinoPageRoute(builder: (context) => Landing());
47 | case "/signup":
48 | return CupertinoPageRoute(builder: (context) => Signup());
49 | case "/login":
50 | return CupertinoPageRoute(builder: (context) => Login());
51 | case "/vendor":
52 | return CupertinoPageRoute(builder: (context) => Vendor());
53 | case "/editproduct":
54 | return CupertinoPageRoute(builder: (context) => EditProduct());
55 | case "/editvendor":
56 | return CupertinoPageRoute(builder: (context) => EditVendor());
57 | default:
58 | var routeArray = settings.name.split('/');
59 | if (settings.name.contains('/editproduct/')) {
60 | return CupertinoPageRoute(
61 | builder: (context) => EditProduct(
62 | productId: routeArray[2],
63 | ));
64 | } else if (settings.name.contains('/customer/')) {
65 | return CupertinoPageRoute(
66 | builder: (context) => Customer(
67 | marketId: routeArray[2],
68 | ));
69 | }
70 | return CupertinoPageRoute(builder: (context) => Login());
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: farmers_market
2 | description: A new Flutter project.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.0.0+1
15 |
16 | environment:
17 | sdk: ">=2.1.0 <3.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 |
23 | # The following adds the Cupertino Icons font to your application.
24 | # Use with the CupertinoIcons class for iOS style icons.
25 | cupertino_icons: ^0.1.2
26 | firebase_core: ^0.5.0
27 | firebase_auth: ^0.18.0+1
28 | cloud_firestore: ^0.14.0+2
29 | google_fonts: ^1.0.0
30 | font_awesome_flutter: ^8.8.1
31 | rxdart: ^0.24.1
32 | provider: ^4.3.2+2
33 | fluttertoast: ^4.0.1
34 | uuid: ^2.0.4
35 | intl: ^0.16.1
36 | image_picker: ^0.6.7+3
37 | firebase_storage: ^4.0.0
38 | permission_handler: ^5.0.1+1
39 | flutter_native_image: ^0.0.5+2
40 | date_format: ^1.0.8
41 |
42 | dev_dependencies:
43 | flutter_test:
44 | sdk: flutter
45 |
46 |
47 | # For information on the generic Dart part of this file, see the
48 | # following page: https://dart.dev/tools/pub/pubspec
49 |
50 | # The following section is specific to Flutter.
51 | flutter:
52 |
53 | # The following line ensures that the Material Icons font is
54 | # included with your application, so that you can use the icons in
55 | # the material Icons class.
56 | uses-material-design: true
57 |
58 | # To add assets to your application, add an assets section, like this:
59 | assets:
60 | - assets/images/
61 | # - images/a_dot_ham.jpeg
62 |
63 | # An image asset can refer to one or more resolution-specific "variants", see
64 | # https://flutter.dev/assets-and-images/#resolution-aware.
65 |
66 | # For details regarding adding assets from package dependencies, see
67 | # https://flutter.dev/assets-and-images/#from-packages
68 |
69 | # To add custom fonts to your application, add a fonts section here,
70 | # in this "flutter" section. Each entry in this list should have a
71 | # "family" key with the font family name, and a "fonts" key with a
72 | # list giving the asset and other descriptors for the font. For
73 | # example:
74 | # fonts:
75 | # - family: Schyler
76 | # fonts:
77 | # - asset: fonts/Schyler-Regular.ttf
78 | # - asset: fonts/Schyler-Italic.ttf
79 | # style: italic
80 | # - family: Trajan Pro
81 | # fonts:
82 | # - asset: fonts/TrajanPro.ttf
83 | # - asset: fonts/TrajanPro_Bold.ttf
84 | # weight: 700
85 | #
86 | # For details regarding fonts from package dependencies,
87 | # see https://flutter.dev/custom-fonts/#from-packages
88 |
--------------------------------------------------------------------------------
/lib/src/widgets/button.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/base.dart';
2 | import 'package:farmers_market/src/styles/buttons.dart';
3 | import 'package:farmers_market/src/styles/colors.dart';
4 | import 'package:farmers_market/src/styles/text.dart';
5 | import 'package:flutter/material.dart';
6 |
7 | class AppButton extends StatefulWidget{
8 | final String buttonText;
9 | final ButtonType buttonType;
10 | final void Function() onPressed;
11 |
12 | AppButton({
13 | @required this.buttonText,
14 | this.buttonType,
15 | this.onPressed
16 | });
17 |
18 | @override
19 | _AppButtonState createState() => _AppButtonState();
20 | }
21 |
22 | class _AppButtonState extends State {
23 | bool pressed = false;
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | TextStyle fontStyle;
28 | Color buttonColor;
29 |
30 | switch (widget.buttonType) {
31 | case ButtonType.Straw:
32 | fontStyle = TextStyles.buttonTextLight;
33 | buttonColor = AppColors.straw;
34 | break;
35 | case ButtonType.LightBlue:
36 | fontStyle = TextStyles.buttonTextLight;
37 | buttonColor = AppColors.lightblue;
38 | break;
39 | case ButtonType.DarkBlue:
40 | fontStyle = TextStyles.buttonTextLight;
41 | buttonColor = AppColors.darkblue;
42 | break;
43 | case ButtonType.Disabled:
44 | fontStyle = TextStyles.buttonTextLight;
45 | buttonColor = AppColors.lightgray;
46 | break;
47 | case ButtonType.DarkGray:
48 | fontStyle = TextStyles.buttonTextLight;
49 | buttonColor = AppColors.darkgray;
50 | break;
51 | default:
52 | fontStyle = TextStyles.buttonTextLight;
53 | buttonColor = AppColors.lightblue;
54 | break;
55 | }
56 |
57 | return AnimatedContainer(
58 | padding: EdgeInsets.only(
59 | top: (pressed) ? BaseStyles.listFieldVertical + BaseStyles.animationOffset : BaseStyles.listFieldVertical,
60 | bottom: (pressed) ? BaseStyles.listFieldVertical - BaseStyles.animationOffset : BaseStyles.listFieldVertical,
61 | left: BaseStyles.listFieldHorizontal,
62 | right: BaseStyles.listFieldHorizontal
63 | ),
64 | child: GestureDetector(
65 | child: Container(
66 | height: ButtonStyles.buttonHeight,
67 | width: MediaQuery.of(context).size.width,
68 | decoration: BoxDecoration(
69 | color: buttonColor,
70 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius),
71 | boxShadow: pressed ? BaseStyles.boxShadowPressed : BaseStyles.boxShadow
72 | ),
73 | child: Center(child: Text(widget.buttonText,style: fontStyle,)),
74 | ),
75 | onTapDown: (details){
76 | setState(() {
77 | if (widget.buttonType != ButtonType.Disabled) pressed = !pressed;
78 | });
79 | },
80 | onTapUp: (details){
81 | setState(() {
82 | if (widget.buttonType != ButtonType.Disabled) pressed = !pressed;
83 | });
84 | },
85 | onTap: (){
86 | if (widget.buttonType != ButtonType.Disabled) {
87 | widget.onPressed();
88 | }
89 | },
90 | ),
91 | duration: Duration(milliseconds: 20),
92 | );
93 | }
94 | }
95 |
96 | enum ButtonType { LightBlue,Straw, Disabled, DarkGray, DarkBlue }
--------------------------------------------------------------------------------
/lib/src/screens/customer.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:farmers_market/src/blocs/auth_bloc.dart';
4 | import 'package:farmers_market/src/styles/tabbar.dart';
5 | import 'package:farmers_market/src/widgets/customer_scaffold.dart';
6 | import 'package:farmers_market/src/widgets/navbar.dart';
7 | import 'package:farmers_market/src/widgets/orders.dart';
8 | import 'package:farmers_market/src/widgets/products_customer.dart';
9 | import 'package:farmers_market/src/widgets/products.dart';
10 | import 'package:farmers_market/src/widgets/profile.dart';
11 | import 'package:farmers_market/src/widgets/profile_customer.dart';
12 | import 'package:farmers_market/src/widgets/shopping_bag.dart';
13 | import 'package:farmers_market/src/widgets/vendor_scaffold.dart';
14 | import 'package:flutter/cupertino.dart';
15 | import 'package:flutter/material.dart';
16 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
17 | import 'dart:io';
18 |
19 | import 'package:provider/provider.dart';
20 |
21 | class Customer extends StatefulWidget {
22 |
23 | final String marketId;
24 |
25 | Customer({@required this.marketId});
26 |
27 |
28 | @override
29 | _CustomerState createState() => _CustomerState();
30 |
31 | static TabBar get customerTabBar {
32 | return TabBar(
33 | unselectedLabelColor: TabBarStyles.unselectedLabelColor ,
34 | labelColor: TabBarStyles.labelColor ,
35 | indicatorColor: TabBarStyles.indicatorColor ,
36 | tabs: [
37 | Tab(icon: Icon(Icons.list)),
38 | Tab(icon: Icon(FontAwesomeIcons.shoppingBag)),
39 | Tab(icon: Icon(Icons.person)),
40 | ],
41 | );
42 | }
43 | }
44 |
45 | class _CustomerState extends State {
46 | StreamSubscription _userSubscription;
47 |
48 | @override
49 | void initState() {
50 | Future.delayed(Duration.zero, (){
51 | var authBloc = Provider.of(context,listen: false);
52 | _userSubscription = authBloc.user.listen((user) {
53 | if (user == null) Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false);
54 | });
55 | });
56 |
57 | super.initState();
58 | }
59 |
60 | @override
61 | void dispose() {
62 | _userSubscription.cancel();
63 | super.dispose();
64 | }
65 |
66 | @override
67 | Widget build(BuildContext context) {
68 |
69 | if (Platform.isIOS) {
70 | return CupertinoPageScaffold(
71 | child: NestedScrollView(
72 | headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
73 | return [
74 | AppNavbar.cupertinoNavBar(title: 'Customer Name',context: context),
75 | ];
76 | },
77 | body: CustomerScaffold.cupertinoTabScaffold,
78 | ),
79 | );
80 | } else {
81 | return DefaultTabController(
82 | length: 3,
83 | child: Scaffold(
84 | body: NestedScrollView(
85 | headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
86 | return [
87 | AppNavbar.materialNavBar(title: 'Customer Name', tabBar: Customer.customerTabBar)
88 | ];
89 | },
90 | body: TabBarView(children: [
91 | ProductsCustomer(),
92 | ShoppingBag(),
93 | ProfileCustomer(),
94 | ],)
95 | )
96 | ),
97 | );
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/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 | generated_key_values = {}
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) do |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 | generated_key_values[podname] = podpath
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | end
32 | generated_key_values
33 | end
34 |
35 | target 'Runner' do
36 | use_frameworks!
37 | use_modular_headers!
38 |
39 | # Flutter Pod
40 |
41 | copied_flutter_dir = File.join(__dir__, 'Flutter')
42 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
43 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
44 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
45 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
46 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
47 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
48 |
49 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
50 | unless File.exist?(generated_xcode_build_settings_path)
51 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
52 | end
53 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
54 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
55 |
56 | unless File.exist?(copied_framework_path)
57 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
58 | end
59 | unless File.exist?(copied_podspec_path)
60 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
61 | end
62 | end
63 |
64 | # Keep pod path relative so it can be checked into Podfile.lock.
65 | pod 'Flutter', :path => 'Flutter'
66 |
67 | # Plugin Pods
68 |
69 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
70 | # referring to absolute paths on developers' machines.
71 | system('rm -rf .symlinks')
72 | system('mkdir -p .symlinks/plugins')
73 | plugin_pods = parse_KV_file('../.flutter-plugins')
74 | plugin_pods.each do |name, path|
75 | symlink = File.join('.symlinks', 'plugins', name)
76 | File.symlink(path, symlink)
77 | pod name, :path => File.join(symlink, 'ios')
78 | end
79 | end
80 |
81 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
82 | install! 'cocoapods', :disable_input_output_paths => true
83 |
84 | post_install do |installer|
85 | installer.pods_project.targets.each do |target|
86 | target.build_configurations.each do |config|
87 | config.build_settings['ENABLE_BITCODE'] = 'NO'
88 | end
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/lib/src/screens/landing.dart:
--------------------------------------------------------------------------------
1 | import 'package:date_format/date_format.dart';
2 | import 'package:farmers_market/src/blocs/customer_bloc.dart';
3 | import 'package:farmers_market/src/models/market.dart';
4 | import 'package:farmers_market/src/styles/base.dart';
5 | import 'package:farmers_market/src/styles/colors.dart';
6 | import 'package:farmers_market/src/styles/text.dart';
7 | import 'package:farmers_market/src/widgets/list_tile.dart';
8 | import 'package:farmers_market/src/widgets/sliver_scaffold.dart';
9 | import 'package:flutter/cupertino.dart';
10 | import 'package:flutter/material.dart';
11 | import 'dart:io';
12 |
13 | import 'package:provider/provider.dart';
14 |
15 | class Landing extends StatelessWidget {
16 | @override
17 | Widget build(BuildContext context) {
18 | var customerBloc = Provider.of(context);
19 | if (Platform.isIOS) {
20 | return AppSliverScaffold.cupertinoSliverScaffold(
21 | navTitle: 'Upcoming Markets',
22 | pageBody: Scaffold(body: pageBody(context,customerBloc)),
23 | );
24 | } else {
25 | return AppSliverScaffold.materialSliverScaffold(
26 | navTitle: 'Upcoming Markets', pageBody: pageBody(context,customerBloc));
27 | }
28 | }
29 |
30 | Widget pageBody(BuildContext context, CustomerBloc customerBloc) {
31 | return Column(
32 | mainAxisAlignment: MainAxisAlignment.center,
33 | children: [
34 | Flexible(
35 | child: Stack(
36 | children: [
37 | Positioned(
38 | child: Image.asset('assets/images/beans.jpg'),
39 | top: -10.0,),
40 | Positioned(
41 | bottom: 10.0,
42 | right: 10.0,
43 | child: GestureDetector(
44 | child: Container(
45 | decoration: BoxDecoration(
46 | color: AppColors.lightblue,
47 | borderRadius:
48 | BorderRadius.circular(BaseStyles.borderRadius)),
49 | child: Padding(
50 | padding: const EdgeInsets.all(8.0),
51 | child: Text('Vendor Page',
52 | style: TextStyles.buttonTextLight),
53 | ),
54 | ),
55 | onTap: () => Navigator.of(context).pushNamed('/vendor'),
56 | ),
57 | )
58 | ],
59 | ),
60 | flex: 2,
61 | ),
62 | Flexible(
63 | child: StreamBuilder>(
64 | stream: customerBloc.fetchUpcomingMarkets,
65 | builder: (context, snapshot) {
66 | if (!snapshot.hasData) return Center(child: (Platform.isIOS)
67 | ? CupertinoActivityIndicator()
68 | : CircularProgressIndicator(),);
69 |
70 | return ListView.builder(
71 | itemCount: snapshot.data.length,
72 | itemBuilder: (BuildContext context, int index){
73 | var market = snapshot.data[index];
74 | var dateEnd = DateTime.parse(market.dateEnd);
75 | return AppListTile(
76 | marketId: market.marketId,
77 | month: formatDate(dateEnd, ['M']),
78 | date: formatDate(dateEnd, ['d']),
79 | title: market.title,
80 | location: '${market.location.name}, ${market.location.address}, ${market.location.city}, ${market.location.state}',
81 | acceptingOrders: market.acceptingOrders,
82 | );
83 | },
84 | );
85 | }
86 | ),
87 | flex: 3,
88 | )
89 | ],
90 | );
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/lib/src/blocs/auth_bloc.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'dart:async';
3 |
4 | import 'package:farmers_market/src/models/application_user.dart';
5 | import 'package:farmers_market/src/services/firestore_service.dart';
6 | import 'package:firebase_auth/firebase_auth.dart';
7 | import 'package:flutter/services.dart';
8 | import 'package:rxdart/rxdart.dart';
9 | import 'package:rxdart/subjects.dart';
10 |
11 | final RegExp regExpEmail = RegExp(
12 | r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$');
13 |
14 | class AuthBloc {
15 | final _email = BehaviorSubject();
16 | final _password = BehaviorSubject();
17 | final _user = BehaviorSubject();
18 | final _errorMessage = BehaviorSubject();
19 | final FirebaseAuth _auth = FirebaseAuth.instance;
20 | final FirestoreService _firestoreService = FirestoreService();
21 |
22 | //Get Data
23 | Stream get email => _email.stream.transform(validateEmail);
24 | Stream get password => _password.stream.transform(validatePassword);
25 | Stream get isValid => CombineLatestStream.combine2(email, password, (email,password)=> true);
26 | Stream get user => _user.stream;
27 | Stream get errorMessage => _errorMessage.stream;
28 | String get userId => _user.value.userId;
29 |
30 | //Set Data
31 | Function(String) get changeEmail => _email.sink.add;
32 | Function(String) get changePassword => _password.sink.add;
33 |
34 | dispose(){
35 | _email.close();
36 | _password.close();
37 | _user.close();
38 | _errorMessage.close();
39 | }
40 |
41 | //Transformers
42 | final validateEmail = StreamTransformer.fromHandlers(handleData: (email, sink){
43 | if (regExpEmail.hasMatch(email.trim())){
44 | sink.add(email.trim());
45 | }else {
46 | sink.addError('Must Be Valid Email Address');
47 | }
48 | });
49 |
50 | final validatePassword = StreamTransformer.fromHandlers(handleData: (password, sink){
51 | if (password.length >= 8){
52 | sink.add(password.trim());
53 | }else {
54 | sink.addError('8 Character Minimum');
55 | }
56 | });
57 |
58 | //Functions
59 | signupEmail() async{
60 | try{
61 | UserCredential authResult = await _auth.createUserWithEmailAndPassword(email: _email.value.trim(), password: _password.value.trim());
62 | var user = ApplicationUser(userId: authResult.user.uid, email: _email.value.trim());
63 | await _firestoreService.addUser(user);
64 | _user.sink.add(user);
65 | } on PlatformException catch (error){
66 | print(error);
67 | _errorMessage.sink.add(error.message);
68 | }
69 | }
70 |
71 | loginEmail() async{
72 | try{
73 | UserCredential authResult = await _auth.signInWithEmailAndPassword(email: _email.value.trim(), password: _password.value.trim());
74 | var user = await _firestoreService.fetchUser(authResult.user.uid);
75 | _user.sink.add(user);
76 | } on PlatformException catch (error){
77 | print(error);
78 | _errorMessage.sink.add(error.message);
79 | }
80 | }
81 |
82 | Future isLoggedIn() async {
83 | var firebaseUser = _auth.currentUser;
84 | if (firebaseUser == null) return false;
85 |
86 | var user = await _firestoreService.fetchUser(firebaseUser.uid);
87 | if (user == null) return false;
88 |
89 | _user.sink.add(user);
90 | return true;
91 | }
92 |
93 | logout() async {
94 | await _auth.signOut();
95 | _user.sink.add(null);
96 | }
97 |
98 | clearErrorMessage(){
99 | _errorMessage.sink.add('');
100 | }
101 |
102 | }
--------------------------------------------------------------------------------
/lib/src/widgets/textfield.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/text.dart';
2 | import 'package:farmers_market/src/styles/textfields.dart';
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class AppTextField extends StatefulWidget{
7 | final bool isIOS;
8 | final String hintText;
9 | final IconData materialIcon;
10 | final IconData cupertinoIcon;
11 | final TextInputType textInputType;
12 | final bool obscureText;
13 | final void Function(String) onChanged;
14 | final String errorText;
15 | final String initialText;
16 |
17 | AppTextField({
18 | @required this.isIOS,
19 | @required this.hintText,
20 | @required this.cupertinoIcon,
21 | @required this.materialIcon,
22 | this.textInputType = TextInputType.text,
23 | this.obscureText = false,
24 | this.onChanged,
25 | this.errorText,
26 | this.initialText,
27 | });
28 |
29 | @override
30 | _AppTextFieldState createState() => _AppTextFieldState();
31 | }
32 |
33 | class _AppTextFieldState extends State {
34 | FocusNode _node;
35 | bool displayCupertinoErrorBorder;
36 | TextEditingController _controller;
37 |
38 |
39 | @override
40 | void initState() {
41 | _node = FocusNode();
42 | _controller = TextEditingController();
43 | if (widget.initialText != null) _controller.text = widget.initialText;
44 | _node.addListener(_handleFocusChange);
45 | displayCupertinoErrorBorder = false;
46 | super.initState();
47 | }
48 |
49 | void _handleFocusChange(){
50 | if (_node.hasFocus==false && widget.errorText != null){
51 | displayCupertinoErrorBorder = true;
52 | } else {
53 | displayCupertinoErrorBorder = false;
54 | }
55 |
56 | widget.onChanged(_controller.text);
57 |
58 | }
59 |
60 | @override
61 | void dispose() {
62 | _node.removeListener(_handleFocusChange);
63 | _node.dispose();
64 | _controller.dispose();
65 | super.dispose();
66 | }
67 |
68 | @override
69 | Widget build(BuildContext context) {
70 | if (widget.isIOS){
71 | return Padding(
72 | padding: EdgeInsets.symmetric(horizontal: TextFieldStyles.textBoxHorizontal, vertical: TextFieldStyles.textBoxVertical),
73 | child: Column(
74 | children: [
75 | CupertinoTextField(
76 | keyboardType: widget.textInputType,
77 | padding: EdgeInsets.all(12.0),
78 | placeholder: widget.hintText,
79 | placeholderStyle: TextFieldStyles.placeholder,
80 | style: TextFieldStyles.text,
81 | textAlign: TextFieldStyles.textAlign,
82 | cursorColor: TextFieldStyles.cursorColor,
83 | decoration: (displayCupertinoErrorBorder) ? TextFieldStyles.cupertinoErrorDecoration : TextFieldStyles.cupertinoDecoration,
84 | prefix: TextFieldStyles.iconPrefix(widget.cupertinoIcon),
85 | obscureText: widget.obscureText,
86 | onChanged: widget.onChanged,
87 | focusNode: _node,
88 | controller: _controller,
89 | ),
90 | (widget.errorText !=null) ? Padding(
91 | padding: const EdgeInsets.only(top: 5.0,left:10.0),
92 | child: Row(children: [Text(widget.errorText,style: TextStyles.error,)],),
93 | ) : Container()
94 | ],
95 | ),
96 | );
97 | } else {
98 | return Padding(
99 | padding: EdgeInsets.symmetric(horizontal: TextFieldStyles.textBoxHorizontal, vertical: TextFieldStyles.textBoxVertical),
100 | child: TextField(
101 | keyboardType: widget.textInputType,
102 | cursorColor: TextFieldStyles.cursorColor,
103 | style:TextFieldStyles.text,
104 | textAlign: TextFieldStyles.textAlign,
105 | decoration: TextFieldStyles.materialDecoration(widget.hintText, widget.materialIcon,widget.errorText),
106 | obscureText: widget.obscureText,
107 | controller: _controller,
108 | onChanged: widget.onChanged,
109 | ),
110 | );
111 | }
112 | }
113 | }
--------------------------------------------------------------------------------
/lib/src/widgets/products.dart:
--------------------------------------------------------------------------------
1 | import 'package:cupertino_toolbar/cupertino_toolbar.dart';
2 | import 'package:farmers_market/src/app.dart';
3 | import 'package:farmers_market/src/blocs/auth_bloc.dart';
4 | import 'package:farmers_market/src/blocs/product_bloc.dart';
5 | import 'package:farmers_market/src/models/product.dart';
6 | import 'package:farmers_market/src/styles/colors.dart';
7 | import 'package:flutter/cupertino.dart';
8 | import 'package:flutter/material.dart';
9 | import 'dart:io';
10 |
11 | import 'package:provider/provider.dart';
12 |
13 | import 'card.dart';
14 |
15 | class Products extends StatelessWidget {
16 | @override
17 | Widget build(BuildContext context) {
18 | var productBloc = Provider.of(context);
19 | var authBloc = Provider.of(context);
20 |
21 | return pageBody(productBloc, context, authBloc.userId);
22 |
23 |
24 | Widget pageBody(
25 | ProductBloc productBloc, BuildContext context, String vendorId) {
26 | return StreamBuilder>(
27 | stream: productBloc.productByVendorId(vendorId),
28 | builder: (context, snapshot) {
29 | if (!snapshot.hasData)
30 | return (Platform.isIOS)
31 | ? CupertinoActivityIndicator()
32 | : CircularProgressIndicator();
33 |
34 | return Column(
35 | children: [
36 | Expanded(
37 | child: ListView.builder(
38 | itemCount: snapshot.data.length,
39 | itemBuilder: (context, index) {
40 | var product = snapshot.data[index];
41 | return GestureDetector(
42 | child: AppCard(
43 | availableUnits: product.availableUnits,
44 | price: product.unitPrice,
45 | productName: product.productName,
46 | unitType: product.unitType,
47 | imageUrl: product.imageUrl,
48 | ),
49 | onTap: () => Navigator.of(context)
50 | .pushNamed('/editproduct/${product.productId}'),
51 | );
52 | }),
53 | ),
54 | GestureDetector(
55 | child: Container(
56 | height: 50.0,
57 | width: double.infinity,
58 | color: AppColors.straw,
59 | child: (Platform.isIOS)
60 | ? Icon(CupertinoIcons.add,
61 | color: Colors.white, size: 35.0)
62 | : Icon(Icons.add, color: Colors.white, size: 35.0),
63 | ),
64 | onTap: () => Navigator.of(context).pushNamed('/editproduct'),
65 | )
66 | ],
67 | );
68 | });
69 | if (Platform.isIOS) {
70 | return CupertinoPageScaffold(
71 | child: CupertinoToolbar(
72 | items: [
73 | CupertinoToolbarItem(
74 | icon: CupertinoIcons.add_circled,
75 | onPressed: () =>
76 | Navigator.of(context).pushNamed('/editproduct'))
77 | ],
78 | body: pageBody(productBloc,context,authBloc.userId),
79 | ),
80 | );
81 | } else {
82 | return Scaffold(
83 | body: pageBody(productBloc,context,authBloc.userId),
84 | floatingActionButton: FloatingActionButton(
85 | backgroundColor: AppColors.straw,
86 | child: Icon(Icons.add),
87 | onPressed: () => Navigator.of(context).pushNamed('/editproduct'),
88 | ),
89 | );
90 | }
91 | }
92 |
93 | Widget pageBody(ProductBloc productBloc, BuildContext context, String vendorId) {
94 | return StreamBuilder>(
95 | stream: productBloc.productByVendorId(vendorId),
96 | builder: (context, snapshot) {
97 | if (!snapshot.hasData) return (Platform.isIOS)
98 | ? CupertinoActivityIndicator()
99 | : CircularProgressIndicator();
100 |
101 | return ListView.builder(
102 | itemCount: snapshot.data.length,
103 | itemBuilder: (context, index){
104 | var product = snapshot.data[index];
105 | return AppCard(
106 | availableUnits: product.availableUnits,
107 | price: product.unitPrice,
108 | productName: product.productName,
109 | unitType: product.unitType,
110 | );
111 | });
112 | }
113 | );
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/lib/src/widgets/dropdown_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/styles/base.dart';
2 | import 'package:farmers_market/src/styles/buttons.dart';
3 | import 'package:farmers_market/src/styles/colors.dart';
4 | import 'package:farmers_market/src/styles/text.dart';
5 | import 'package:flutter/cupertino.dart';
6 | import 'package:flutter/material.dart';
7 | import 'dart:io';
8 |
9 | class AppDropdownButton extends StatelessWidget {
10 | final List items;
11 | final String hintText;
12 | final IconData materialIcon;
13 | final IconData cupertinoIcon;
14 | final String value;
15 | final Function(String) onChanged;
16 |
17 | AppDropdownButton(
18 | {@required this.items,
19 | @required this.hintText,
20 | this.materialIcon,
21 | this.cupertinoIcon,
22 | this.value,
23 | this.onChanged});
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | if (Platform.isIOS) {
28 | return Padding(
29 | padding: BaseStyles.listPadding,
30 | child: Container(
31 | height: ButtonStyles.buttonHeight,
32 | width: MediaQuery.of(context).size.width,
33 | decoration: BoxDecoration(
34 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius),
35 | border: Border.all(
36 | color: AppColors.straw, width: BaseStyles.borderWidth)),
37 | child: Row(
38 | children: [
39 | Container(
40 | width: 35.0, child: BaseStyles.iconPrefix(materialIcon)),
41 | Expanded(
42 | child: Center(
43 | child: GestureDetector(
44 | child:(value == null) ? Text(hintText, style: TextStyles.suggestion)
45 | : Text(value, style: TextStyles.body),
46 | onTap: () {
47 | showCupertinoModalPopup(
48 | context: context, builder: (BuildContext context) {
49 | return _selectIOS(context, items, value);
50 | });
51 | },
52 | )),
53 | ),
54 | ],
55 | ),
56 | ),
57 | );
58 | } else {
59 | return Padding(
60 | padding: BaseStyles.listPadding,
61 | child: Container(
62 | height: ButtonStyles.buttonHeight,
63 | width: MediaQuery.of(context).size.width,
64 | decoration: BoxDecoration(
65 | borderRadius: BorderRadius.circular(BaseStyles.borderRadius),
66 | border: Border.all(
67 | color: AppColors.straw, width: BaseStyles.borderWidth)),
68 | child: Row(
69 | children: [
70 | Container(
71 | width: 35.0, child: BaseStyles.iconPrefix(materialIcon)),
72 | Expanded(
73 | child: Center(
74 | child: DropdownButton(
75 | items: buildMaterialItems(items),
76 | value: value,
77 | hint: Text(hintText, style: TextStyles.suggestion),
78 | style: TextStyles.body,
79 | underline: Container(),
80 | iconEnabledColor: AppColors.straw,
81 | onChanged: (value) => onChanged(value),
82 | ),
83 | ),
84 | ),
85 | ],
86 | ),
87 | ),
88 | );
89 | }
90 | }
91 |
92 | List> buildMaterialItems(List items) {
93 | return (items != null) ? items
94 | .map((item) => DropdownMenuItem(
95 | child: Text(
96 | item,
97 | textAlign: TextAlign.center,
98 | ),
99 | value: item,
100 | ))
101 | .toList() : [];
102 | }
103 |
104 | List buildCupertinoItems(List items) {
105 | return items
106 | .map((item) => Text(
107 | item,
108 | textAlign: TextAlign.center,
109 | style: TextStyles.picker,
110 | ))
111 | .toList();
112 | }
113 |
114 | _selectIOS(BuildContext context, List items, String value) {
115 | return GestureDetector(
116 | onTap: () {
117 | Navigator.of(context).pop();
118 | },
119 | child: Container(
120 | color: Colors.white,
121 | height: 200.0,
122 | child: CupertinoPicker(
123 | scrollController: FixedExtentScrollController(initialItem: items.indexWhere((item) => item == value)),
124 | itemExtent: 45.0,
125 | children: buildCupertinoItems(items),
126 | diameterRatio: 1.0,
127 | onSelectedItemChanged: (int index) => onChanged(items[index]),
128 | ),
129 | ),
130 | );
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/lib/src/screens/signup.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:farmers_market/src/blocs/auth_bloc.dart';
4 | import 'package:farmers_market/src/styles/base.dart';
5 | import 'package:farmers_market/src/styles/text.dart';
6 | import 'package:farmers_market/src/widgets/alerts.dart';
7 | import 'package:farmers_market/src/widgets/button.dart';
8 | import 'package:farmers_market/src/widgets/social_button.dart';
9 | import 'package:farmers_market/src/widgets/textfield.dart';
10 | import 'package:flutter/cupertino.dart';
11 | import 'package:flutter/gestures.dart';
12 | import 'package:flutter/material.dart';
13 | import 'dart:io';
14 |
15 | import 'package:provider/provider.dart';
16 |
17 | class Signup extends StatefulWidget{
18 |
19 |
20 | @override
21 | _SignupState createState() => _SignupState();
22 | }
23 |
24 | class _SignupState extends State {
25 | StreamSubscription _userSubscription;
26 | StreamSubscription _errorMessageSubscription;
27 |
28 | @override
29 | void initState() {
30 | final authBloc = Provider.of(context,listen: false);
31 | _userSubscription = authBloc.user.listen((user) {
32 | if (user != null) Navigator.pushReplacementNamed(context, '/landing');
33 | });
34 |
35 | _errorMessageSubscription = authBloc.errorMessage.listen((errorMessage) {
36 | if (errorMessage != '' ) {
37 | AppAlerts.showErrorDialog(Platform.isIOS, context, errorMessage).then((_) => authBloc.clearErrorMessage());
38 | }
39 | });
40 | super.initState();
41 | }
42 |
43 | @override
44 | void dispose() {
45 | _userSubscription.cancel();
46 | _errorMessageSubscription.cancel();
47 | super.dispose();
48 | }
49 |
50 |
51 | @override
52 | Widget build(BuildContext context) {
53 | final authBloc = Provider.of(context);
54 | if (Platform.isIOS){
55 | return CupertinoPageScaffold(
56 | child: pageBody(context,authBloc),
57 | );
58 | } else {
59 | return Scaffold(
60 | body: pageBody(context,authBloc),
61 | );
62 | }
63 | }
64 |
65 | Widget pageBody(BuildContext context,AuthBloc authBloc) {
66 | return ListView(
67 | padding: EdgeInsets.all(0.0),
68 | children: [
69 | Container(
70 | height: MediaQuery.of(context).size.height * .2,
71 | decoration: BoxDecoration(
72 | image: DecorationImage(
73 | image: AssetImage('assets/images/top_bg.png'),
74 | fit: BoxFit.fill)),
75 | ),
76 | Container(
77 | height: 200.0,
78 | decoration: BoxDecoration(
79 | image: DecorationImage(image: AssetImage('assets/images/logo.png')),
80 | ),
81 | ),
82 | StreamBuilder(
83 | stream: authBloc.email,
84 | builder: (context, snapshot) {
85 | return AppTextField(
86 | isIOS: Platform.isIOS,
87 | hintText: 'Email',
88 | cupertinoIcon: CupertinoIcons.mail_solid,
89 | materialIcon: Icons.email,
90 | textInputType: TextInputType.emailAddress,
91 | errorText: snapshot.error,
92 | onChanged: authBloc.changeEmail,
93 | );
94 | }
95 | ),
96 | StreamBuilder(
97 | stream: authBloc.password,
98 | builder: (context, snapshot) {
99 | return AppTextField(
100 | isIOS: Platform.isIOS,
101 | hintText: 'Password',
102 | cupertinoIcon: IconData(0xf4c9,fontFamily: CupertinoIcons.iconFont, fontPackage: CupertinoIcons.iconFontPackage),
103 | materialIcon: Icons.lock,
104 | obscureText: true,
105 | errorText: snapshot.error,
106 | onChanged: authBloc.changePassword,
107 | );
108 | }
109 | ),
110 | StreamBuilder(
111 | stream: authBloc.isValid,
112 | builder: (context, snapshot) {
113 | return AppButton(buttonText: 'Signup',buttonType: (snapshot.data == true) ? ButtonType.LightBlue : ButtonType.Disabled, onPressed: authBloc.signupEmail,);
114 | }
115 | ),
116 | SizedBox(height: 6.0,),
117 | Center(child: Text('Or',style: TextStyles.suggestion),),
118 | SizedBox(height: 6.0,),
119 | Padding(
120 | padding: BaseStyles.listPadding,
121 | child: Row(
122 | mainAxisAlignment: MainAxisAlignment.center,
123 | children: [
124 | AppSocialButton(socialType: SocialType.Facebook,),
125 | SizedBox(width:15.0),
126 | AppSocialButton(socialType: SocialType.Google),
127 | ],),
128 | ),
129 | Padding(
130 | padding: BaseStyles.listPadding,
131 | child: RichText(
132 | textAlign: TextAlign.center,
133 | text: TextSpan(
134 | text: 'Already Have an Account? ',
135 | style: TextStyles.body,
136 | children: [
137 | TextSpan(
138 | text: 'Login',
139 | style: TextStyles.link,
140 | recognizer: TapGestureRecognizer()
141 | ..onTap = () => Navigator.pushNamed(context, '/login')
142 | )
143 | ]
144 | )
145 | ),
146 | )
147 | ],
148 | );
149 | }
150 | }
--------------------------------------------------------------------------------
/lib/src/blocs/vendor_bloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 |
4 | import 'package:farmers_market/src/models/vendor.dart';
5 | import 'package:farmers_market/src/services/firebase_storage_service.dart';
6 | import 'package:farmers_market/src/services/firestore_service.dart';
7 | import 'package:flutter_native_image/flutter_native_image.dart';
8 | import 'package:image_picker/image_picker.dart';
9 | import 'package:permission_handler/permission_handler.dart';
10 | import 'package:rxdart/rxdart.dart';
11 | import 'package:rxdart/subjects.dart';
12 | import 'package:uuid/uuid.dart';
13 |
14 | class VendorBloc {
15 | final _db = FirestoreService();
16 | final _name = BehaviorSubject();
17 | final _description = BehaviorSubject();
18 | final _imageUrl = BehaviorSubject();
19 | final _vendorId = BehaviorSubject();
20 | final _vendorSaved = PublishSubject();
21 | final _vendor = BehaviorSubject();
22 | final _isUploading = BehaviorSubject();
23 |
24 | final _picker = ImagePicker();
25 | final storageService = FirebaseStorageService();
26 | var uuid = Uuid();
27 |
28 | //Getters
29 | Future fetchVendor(String userId) => _db.fetchVendor(userId);
30 | Stream get name => _name.stream.transform(validateName);
31 | Stream get description =>
32 | _description.stream.transform(validateDescription);
33 | Stream get imageUrl => _imageUrl.stream;
34 | Stream get vendorSaved => _vendorSaved.stream;
35 | Stream get vendor => _vendor.stream;
36 | Stream get isUploading => _isUploading.stream;
37 | Stream get isValid => CombineLatestStream.combine2(
38 | name, description, (a, b) => true);
39 |
40 | //Setters
41 | Function(String) get changeName => _name.sink.add;
42 | Function(String) get changeDescription => _description.sink.add;
43 | Function(String) get changeImageUrl => _imageUrl.sink.add;
44 | Function(Vendor) get changeVendor => _vendor.sink.add;
45 | Function(String) get changeVendorId => _vendorId.sink.add;
46 |
47 | //Dispose
48 | dispose() {
49 | _name.close();
50 | _description.close();
51 | _imageUrl.close();
52 | _vendorSaved.close();
53 | _vendor.close();
54 | _vendorId.close();
55 | _isUploading.close();
56 | }
57 |
58 | //Validators
59 | final validateName =
60 | StreamTransformer.fromHandlers(handleData: (name, sink) {
61 | if (name != null) {
62 | if (name.length >= 3 && name.length <= 20) {
63 | sink.add(name.trim());
64 | } else {
65 | if (name.length < 3) {
66 | sink.addError('3 Character Minimum');
67 | } else {
68 | sink.addError('20 Character Maximum');
69 | }
70 | }
71 | }
72 | });
73 |
74 | final validateDescription = StreamTransformer.fromHandlers(
75 | handleData: (description, sink) {
76 | if (description != null) {
77 | if (description.length >= 10 && description.length <= 200) {
78 | sink.add(description.trim());
79 | } else {
80 | if (description.length < 10) {
81 | sink.addError('10 Character Minimum');
82 | } else {
83 | sink.addError('200 Character Maximum');
84 | }
85 | }
86 | }
87 | });
88 |
89 | //Save Record
90 | Future saveVendor() async {
91 | var vendor = Vendor(
92 | description: _description.value,
93 | imageUrl: _imageUrl.value,
94 | name: _name.value,
95 | vendorId: _vendorId.value);
96 |
97 | return _db.setVendor(vendor).then((value) {
98 | _vendorSaved.sink.add(true);
99 | changeVendor(vendor);
100 | }).catchError((error) => _vendorSaved.sink.add(false));
101 | }
102 |
103 | pickImage() async {
104 | PickedFile image;
105 | File croppedFile;
106 |
107 | await Permission.photos.request();
108 |
109 | var permissionStatus = await Permission.photos.status;
110 | if (permissionStatus.isGranted) {
111 | //Get Image From Device
112 | image = await _picker.getImage(source: ImageSource.gallery);
113 |
114 | //Upload to Firebase
115 | if (image != null) {
116 | _isUploading.sink.add(true);
117 |
118 | //Get Image Properties
119 | ImageProperties properties =
120 | await FlutterNativeImage.getImageProperties(image.path);
121 |
122 | //CropImage
123 | if (properties.height > properties.width) {
124 | var yoffset = (properties.height - properties.width) / 2;
125 | croppedFile = await FlutterNativeImage.cropImage(image.path, 0,
126 | yoffset.toInt(), properties.width, properties.width);
127 | } else if (properties.width > properties.height) {
128 | var xoffset = (properties.width - properties.height) / 2;
129 | croppedFile = await FlutterNativeImage.cropImage(image.path,
130 | xoffset.toInt(), 0, properties.height, properties.height);
131 | } else {
132 | croppedFile = File(image.path);
133 | }
134 |
135 | //Resize
136 | File compressedFile = await FlutterNativeImage.compressImage(
137 | croppedFile.path,
138 | quality: 100,
139 | targetHeight: 600,
140 | targetWidth: 600);
141 |
142 | var imageUrl =
143 | await storageService.uploadVendorImage(compressedFile, uuid.v4());
144 | changeImageUrl(imageUrl);
145 | _isUploading.sink.add(false);
146 | } else {
147 | print('No Path Received');
148 | }
149 | } else {
150 | print('Grant Permissions and try again');
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/lib/src/screens/login.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:farmers_market/src/blocs/auth_bloc.dart';
4 | import 'package:farmers_market/src/styles/base.dart';
5 | import 'package:farmers_market/src/styles/text.dart';
6 | import 'package:farmers_market/src/widgets/alerts.dart';
7 | import 'package:farmers_market/src/widgets/button.dart';
8 | import 'package:farmers_market/src/widgets/social_button.dart';
9 | import 'package:farmers_market/src/widgets/textfield.dart';
10 | import 'package:flutter/cupertino.dart';
11 | import 'package:flutter/gestures.dart';
12 | import 'package:flutter/material.dart';
13 | import 'dart:io';
14 |
15 | import 'package:provider/provider.dart';
16 |
17 | class Login extends StatefulWidget {
18 |
19 |
20 | @override
21 | _LoginState createState() => _LoginState();
22 | }
23 |
24 | class _LoginState extends State {
25 | StreamSubscription _userSubscription;
26 | StreamSubscription _errorMessageSubscription;
27 |
28 | @override
29 | void initState() {
30 | final authBloc = Provider.of(context,listen: false);
31 | _userSubscription = authBloc.user.listen((user) {
32 | if (user != null) Navigator.pushReplacementNamed(context, '/landing');
33 | });
34 |
35 | _errorMessageSubscription = authBloc.errorMessage.listen((errorMessage) {
36 | if (errorMessage != '' ) {
37 | AppAlerts.showErrorDialog(Platform.isIOS, context, errorMessage).then((_) => authBloc.clearErrorMessage());
38 | }
39 | });
40 | super.initState();
41 | }
42 |
43 | @override
44 | void dispose() {
45 | _userSubscription.cancel();
46 | _errorMessageSubscription.cancel();
47 | super.dispose();
48 | }
49 |
50 | @override
51 | Widget build(BuildContext context) {
52 | final authBloc = Provider.of(context);
53 |
54 | if (Platform.isIOS) {
55 | return CupertinoPageScaffold(
56 | child: pageBody(context, authBloc),
57 | );
58 | } else {
59 | return Scaffold(
60 | body: pageBody(context, authBloc),
61 | );
62 | }
63 | }
64 |
65 | Widget pageBody(BuildContext context, AuthBloc authBloc) {
66 | return ListView(
67 | padding: EdgeInsets.all(0.0),
68 | children: [
69 | Container(
70 | height: MediaQuery.of(context).size.height * .2,
71 | decoration: BoxDecoration(
72 | image: DecorationImage(
73 | image: AssetImage('assets/images/top_bg.png'),
74 | fit: BoxFit.fill)),
75 | ),
76 | Container(
77 | height: 200.0,
78 | decoration: BoxDecoration(
79 | image: DecorationImage(image: AssetImage('assets/images/logo.png')),
80 | ),
81 | ),
82 | StreamBuilder(
83 | stream: authBloc.email,
84 | builder: (context, snapshot) {
85 | return AppTextField(
86 | isIOS: Platform.isIOS,
87 | hintText: 'Email',
88 | cupertinoIcon: CupertinoIcons.mail_solid,
89 | materialIcon: Icons.email,
90 | textInputType: TextInputType.emailAddress,
91 | errorText: snapshot.error,
92 | onChanged: authBloc.changeEmail,
93 | );
94 | }),
95 | StreamBuilder(
96 | stream: authBloc.password,
97 | builder: (context, snapshot) {
98 | return AppTextField(
99 | isIOS: Platform.isIOS,
100 | hintText: 'Password',
101 | cupertinoIcon: IconData(0xf4c9,
102 | fontFamily: CupertinoIcons.iconFont,
103 | fontPackage: CupertinoIcons.iconFontPackage),
104 | materialIcon: Icons.lock,
105 | obscureText: true,
106 | errorText: snapshot.error,
107 | onChanged: authBloc.changePassword,
108 | );
109 | }),
110 | StreamBuilder(
111 | stream: authBloc.isValid,
112 | builder: (context, snapshot) {
113 | return AppButton(
114 | buttonText: 'Login',
115 | buttonType: (snapshot.data == true)
116 | ? ButtonType.LightBlue
117 | : ButtonType.Disabled,
118 | onPressed: authBloc.loginEmail,
119 | );
120 | }),
121 | SizedBox(
122 | height: 6.0,
123 | ),
124 | Center(
125 | child: Text('Or', style: TextStyles.suggestion),
126 | ),
127 | SizedBox(
128 | height: 6.0,
129 | ),
130 | Padding(
131 | padding: BaseStyles.listPadding,
132 | child: Row(
133 | mainAxisAlignment: MainAxisAlignment.center,
134 | children: [
135 | AppSocialButton(
136 | socialType: SocialType.Facebook,
137 | ),
138 | SizedBox(width: 15.0),
139 | AppSocialButton(socialType: SocialType.Google),
140 | ],
141 | ),
142 | ),
143 | Padding(
144 | padding: BaseStyles.listPadding,
145 | child: RichText(
146 | textAlign: TextAlign.center,
147 | text: TextSpan(
148 | text: 'New Here? ',
149 | style: TextStyles.body,
150 | children: [
151 | TextSpan(
152 | text: 'Signup',
153 | style: TextStyles.link,
154 | recognizer: TapGestureRecognizer()
155 | ..onTap =
156 | () => Navigator.pushNamed(context, '/signup'))
157 | ])),
158 | )
159 | ],
160 | );
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/lib/src/blocs/product_bloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 |
4 | import 'package:farmers_market/src/models/product.dart';
5 | import 'package:farmers_market/src/services/firebase_storage_service.dart';
6 | import 'package:farmers_market/src/services/firestore_service.dart';
7 | import 'package:flutter_native_image/flutter_native_image.dart';
8 | import 'package:image_picker/image_picker.dart';
9 | import 'package:permission_handler/permission_handler.dart';
10 | import 'package:rxdart/rxdart.dart';
11 | import 'package:rxdart/subjects.dart';
12 | import 'package:uuid/uuid.dart';
13 |
14 | class ProductBloc {
15 | final _productName = BehaviorSubject();
16 | final _unitType = BehaviorSubject();
17 | final _unitPrice = BehaviorSubject();
18 | final _availableUnits = BehaviorSubject();
19 | final _imageUrl = BehaviorSubject();
20 | final _vendorId = BehaviorSubject();
21 | final _productSaved = PublishSubject();
22 | final _product = BehaviorSubject();
23 | final _isUploading = BehaviorSubject();
24 |
25 | final db = FirestoreService();
26 | var uuid = Uuid();
27 | final _picker = ImagePicker();
28 | final storageService = FirebaseStorageService();
29 |
30 | //Get
31 | Stream get productName =>
32 | _productName.stream.transform(validateProductName);
33 | Stream get unitType => _unitType.stream;
34 | Stream get unitPrice =>
35 | _unitPrice.stream.transform(validateUnitPrice);
36 | Stream get availableUnits =>
37 | _availableUnits.stream.transform(validateAvailableUnits);
38 | Stream get imageUrl => _imageUrl.stream;
39 | Stream get isValid => CombineLatestStream.combine4(
40 | productName, unitType, unitPrice, availableUnits, (a, b, c, d) => true);
41 | Stream> productByVendorId(String vendorId) =>
42 | db.fetchProductsByVendorId(vendorId);
43 | Stream get productSaved => _productSaved.stream;
44 | Future fetchProduct(String productId) => db.fetchProduct(productId);
45 | Stream get isUploading => _isUploading.stream;
46 |
47 |
48 | //Set
49 | Function(String) get changeProductName => _productName.sink.add;
50 | Function(String) get changeUnitType => _unitType.sink.add;
51 | Function(String) get changeUnitPrice => _unitPrice.sink.add;
52 | Function(String) get changeAvailableUnits => _availableUnits.sink.add;
53 | Function(String) get changeImageUrl => _imageUrl.sink.add;
54 | Function(String) get changeVendorId => _vendorId.sink.add;
55 | Function(Product) get changeProduct => _product.sink.add;
56 |
57 | dispose() {
58 | _productName.close();
59 | _unitType.close();
60 | _unitPrice.close();
61 | _availableUnits.close();
62 | _vendorId.close();
63 | _productSaved.close();
64 | _product.close();
65 | _imageUrl.close();
66 | _isUploading.close();
67 | }
68 |
69 | //Functions
70 | Future saveProduct() async {
71 | var product = Product(
72 | approved: (_product.value == null) ? true : _product.value.approved,
73 | availableUnits: int.parse(_availableUnits.value),
74 | productId:
75 | (_product.value == null) ? uuid.v4() : _product.value.productId,
76 | productName: _productName.value.trim(),
77 | unitPrice: double.parse(_unitPrice.value),
78 | unitType: _unitType.value,
79 | vendorId: _vendorId.value,
80 | imageUrl: _imageUrl.value
81 | );
82 |
83 | return db
84 | .setProduct(product)
85 | .then((value) => _productSaved.sink.add(true))
86 | .catchError((error) => _productSaved.sink.add(false));
87 | }
88 |
89 | pickImage() async {
90 | PickedFile image;
91 | File croppedFile;
92 |
93 | await Permission.photos.request();
94 |
95 | var permissionStatus = await Permission.photos.status;
96 | if (permissionStatus.isGranted) {
97 | //Get Image From Device
98 | image = await _picker.getImage(source: ImageSource.gallery);
99 |
100 | //Upload to Firebase
101 | if (image != null) {
102 | _isUploading.sink.add(true);
103 |
104 | //Get Image Properties
105 | ImageProperties properties = await FlutterNativeImage.getImageProperties(image.path);
106 |
107 | //CropImage
108 | if (properties.height > properties.width){
109 | var yoffset = (properties.height - properties.width)/2;
110 | croppedFile = await FlutterNativeImage.cropImage(image.path, 0, yoffset.toInt(), properties.width, properties.width);
111 | } else if (properties.width > properties.height) {
112 | var xoffset = (properties.width- properties.height)/2;
113 | croppedFile = await FlutterNativeImage.cropImage(image.path, xoffset.toInt(), 0, properties.height, properties.height);
114 | } else {
115 | croppedFile = File(image.path);
116 | }
117 |
118 | //Resize
119 | File compressedFile = await FlutterNativeImage.compressImage(croppedFile.path,quality: 100, targetHeight: 600, targetWidth: 600);
120 |
121 | var imageUrl = await storageService.uploadProductImage(
122 | compressedFile, uuid.v4());
123 | changeImageUrl(imageUrl);
124 | _isUploading.sink.add(false);
125 | } else {
126 | print('No Path Received');
127 | }
128 | } else {
129 | print('Grant Permissions and try again');
130 | }
131 | }
132 |
133 | //Validators
134 | final validateUnitPrice = StreamTransformer.fromHandlers(
135 | handleData: (unitPrice, sink) {
136 | if (unitPrice != null) {
137 | try {
138 | sink.add(double.parse(unitPrice));
139 | } catch (error) {
140 | sink.addError('Must be a number');
141 | }
142 | }
143 | });
144 |
145 | final validateAvailableUnits = StreamTransformer.fromHandlers(
146 | handleData: (availableUnits, sink) {
147 | if (availableUnits != null) {
148 | try {
149 | sink.add(int.parse(availableUnits));
150 | } catch (error) {
151 | sink.addError('Must be a whole number');
152 | }
153 | }
154 | });
155 |
156 | final validateProductName = StreamTransformer.fromHandlers(
157 | handleData: (productName, sink) {
158 | if (productName != null) {
159 | if (productName.length >= 3 && productName.length <= 20) {
160 | sink.add(productName.trim());
161 | } else {
162 | if (productName.length < 3) {
163 | sink.addError('3 Character Minimum');
164 | } else {
165 | sink.addError('20 Character Maximum');
166 | }
167 | }
168 | }
169 | });
170 | }
171 |
--------------------------------------------------------------------------------
/lib/src/screens/edit_vendor.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 |
4 | import 'package:farmers_market/src/blocs/auth_bloc.dart';
5 | import 'package:farmers_market/src/blocs/product_bloc.dart';
6 | import 'package:farmers_market/src/blocs/vendor_bloc.dart';
7 | import 'package:farmers_market/src/models/vendor.dart';
8 | import 'package:farmers_market/src/styles/base.dart';
9 | import 'package:farmers_market/src/styles/colors.dart';
10 | import 'package:farmers_market/src/styles/text.dart';
11 | import 'package:farmers_market/src/widgets/button.dart';
12 | import 'package:farmers_market/src/widgets/sliver_scaffold.dart';
13 | import 'package:farmers_market/src/widgets/textfield.dart';
14 | import 'package:flutter/cupertino.dart';
15 | import 'package:flutter/material.dart';
16 | import 'package:fluttertoast/fluttertoast.dart';
17 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
18 | import 'package:provider/provider.dart';
19 |
20 | class EditVendor extends StatefulWidget {
21 | final String vendorId;
22 |
23 | EditVendor({this.vendorId});
24 |
25 | @override
26 | _EditVendorState createState() => _EditVendorState();
27 | }
28 |
29 | class _EditVendorState extends State {
30 | StreamSubscription _savedSubscription;
31 | @override
32 | void initState() {
33 | var vendorBloc = Provider.of(context, listen: false);
34 | _savedSubscription = vendorBloc.vendorSaved.listen((saved) {
35 | if (saved != null && saved == true && context != null) {
36 | Fluttertoast.showToast(
37 | msg: "Vendor Saved",
38 | toastLength: Toast.LENGTH_SHORT,
39 | gravity: ToastGravity.CENTER,
40 | timeInSecForIosWeb: 2,
41 | backgroundColor: AppColors.lightblue,
42 | textColor: Colors.white,
43 | fontSize: 16.0);
44 |
45 | Navigator.of(context).pop();
46 | }
47 | });
48 | super.initState();
49 | }
50 |
51 | @override
52 | void dispose() {
53 | _savedSubscription.cancel();
54 | super.dispose();
55 | }
56 |
57 | @override
58 | Widget build(BuildContext context) {
59 | var vendorBloc = Provider.of(context);
60 | var authBloc = Provider.of(context);
61 |
62 | return StreamBuilder(
63 | stream: vendorBloc.vendor,
64 | builder: (context, snapshot) {
65 | if (!snapshot.hasData && widget.vendorId != null) {
66 | return Scaffold(
67 | body: Center(
68 | child: (Platform.isIOS)
69 | ? CupertinoActivityIndicator()
70 | : CircularProgressIndicator()),
71 | );
72 | }
73 |
74 | Vendor vendor = snapshot.data;
75 |
76 | if (vendor != null) {
77 | //Edit Logic
78 | loadValues(vendorBloc, vendor, authBloc.userId);
79 | } else {
80 | //Add Logic
81 | loadValues(vendorBloc, null, authBloc.userId);
82 | }
83 |
84 | return (Platform.isIOS)
85 | ? AppSliverScaffold.cupertinoSliverScaffold(
86 | navTitle: '',
87 | pageBody: pageBody(true, vendorBloc, context, vendor),
88 | context: context)
89 | : AppSliverScaffold.materialSliverScaffold(
90 | navTitle: '',
91 | pageBody: pageBody(false, vendorBloc, context, vendor),
92 | context: context);
93 | },
94 | );
95 | }
96 |
97 | Widget pageBody(bool isIOS, VendorBloc vendorBloc, BuildContext context,
98 | Vendor existingVendor) {
99 | var pageLabel = (existingVendor != null) ? 'Edit Profile' : 'Add Profile';
100 | return ListView(
101 | children: [
102 | Text(
103 | pageLabel,
104 | style: TextStyles.subtitle,
105 | textAlign: TextAlign.center,
106 | ),
107 | Padding(
108 | padding: BaseStyles.listPadding,
109 | child: Divider(color: AppColors.darkblue),
110 | ),
111 | StreamBuilder(
112 | stream: vendorBloc.name,
113 | builder: (context, snapshot) {
114 | return AppTextField(
115 | hintText: 'Vendor Name',
116 | cupertinoIcon: FontAwesomeIcons.shoppingBasket,
117 | materialIcon: FontAwesomeIcons.shoppingBasket,
118 | isIOS: isIOS,
119 | errorText: snapshot.error,
120 | initialText:
121 | (existingVendor != null) ? existingVendor.name : null,
122 | onChanged: vendorBloc.changeName,
123 | );
124 | }),
125 | StreamBuilder(
126 | stream: vendorBloc.description,
127 | builder: (context, snapshot) {
128 | return AppTextField(
129 | hintText: 'Description',
130 | cupertinoIcon: FontAwesomeIcons.shoppingBasket,
131 | materialIcon: FontAwesomeIcons.shoppingBasket,
132 | isIOS: isIOS,
133 | errorText: snapshot.error,
134 | initialText: (existingVendor != null)
135 | ? existingVendor.description
136 | : null,
137 | onChanged: vendorBloc.changeDescription,
138 | );
139 | }),
140 | StreamBuilder(
141 | stream: vendorBloc.isUploading,
142 | builder: (context, snapshot) {
143 | return (!snapshot.hasData || snapshot.data == false)
144 | ? Container()
145 | : Center(
146 | child: (Platform.isIOS)
147 | ? CupertinoActivityIndicator()
148 | : CircularProgressIndicator(),
149 | );
150 | },
151 | ),
152 | StreamBuilder(
153 | stream: vendorBloc.imageUrl,
154 | builder: (context, snapshot) {
155 | if (!snapshot.hasData || snapshot.data == "")
156 | return AppButton(
157 | buttonType: ButtonType.Straw,
158 | buttonText: 'Add Image',
159 | onPressed: vendorBloc.pickImage,
160 | );
161 |
162 | return Column(
163 | children: [
164 | Padding(
165 | padding: BaseStyles.listPadding,
166 | child: Image.network(snapshot.data),
167 | ),
168 | AppButton(
169 | buttonType: ButtonType.Straw,
170 | buttonText: 'Change Image',
171 | onPressed: vendorBloc.pickImage,
172 | )
173 | ],
174 | );
175 | }),
176 | StreamBuilder(
177 | stream: vendorBloc.isValid,
178 | builder: (context, snapshot) {
179 | return AppButton(
180 | buttonType: (snapshot.data == true)
181 | ? ButtonType.DarkBlue
182 | : ButtonType.Disabled,
183 | buttonText: 'Save Profile',
184 | onPressed: vendorBloc.saveVendor,
185 | );
186 | }),
187 | ],
188 | );
189 | }
190 |
191 | loadValues(VendorBloc vendorBloc, Vendor vendor, String vendorId) {
192 | vendorBloc.changeVendorId(vendorId);
193 |
194 | if (vendor != null) {
195 | //Edit
196 | vendorBloc.changeName(vendor.name);
197 | vendorBloc.changeDescription(vendor.description);
198 | vendorBloc.changeImageUrl(vendor.imageUrl ?? '');
199 | } else {
200 | //Add
201 | vendorBloc.changeName(null);
202 | vendorBloc.changeDescription(null);
203 | vendorBloc.changeImageUrl('');
204 | }
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/lib/src/screens/edit_product.dart:
--------------------------------------------------------------------------------
1 | import 'package:farmers_market/src/app.dart';
2 | import 'package:farmers_market/src/blocs/auth_bloc.dart';
3 | import 'package:farmers_market/src/blocs/product_bloc.dart';
4 | import 'package:farmers_market/src/models/product.dart';
5 | import 'package:farmers_market/src/models/application_user.dart';
6 | import 'package:farmers_market/src/styles/base.dart';
7 | import 'package:farmers_market/src/styles/colors.dart';
8 | import 'package:farmers_market/src/styles/text.dart';
9 | import 'package:farmers_market/src/widgets/button.dart';
10 | import 'package:farmers_market/src/widgets/dropdown_button.dart';
11 | import 'package:farmers_market/src/widgets/sliver_scaffold.dart';
12 | import 'package:farmers_market/src/widgets/textfield.dart';
13 | import 'package:flutter/cupertino.dart';
14 | import 'package:flutter/material.dart';
15 | import 'package:fluttertoast/fluttertoast.dart';
16 | import 'dart:io';
17 |
18 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
19 | import 'package:provider/provider.dart';
20 |
21 | class EditProduct extends StatefulWidget {
22 | final String productId;
23 |
24 | EditProduct({this.productId});
25 |
26 | @override
27 | _EditProductState createState() => _EditProductState();
28 | }
29 |
30 | class _EditProductState extends State {
31 | @override
32 | void initState() {
33 | var productBloc = Provider.of(context, listen: false);
34 | productBloc.productSaved.listen((saved) {
35 | if (saved != null && saved == true && context != null) {
36 | Fluttertoast.showToast(
37 | msg: "Product Saved",
38 | toastLength: Toast.LENGTH_SHORT,
39 | gravity: ToastGravity.CENTER,
40 | timeInSecForIosWeb: 2,
41 | backgroundColor: AppColors.lightblue,
42 | textColor: Colors.white,
43 | fontSize: 16.0);
44 |
45 | Navigator.of(context).pop();
46 | }
47 | });
48 | super.initState();
49 | }
50 |
51 | @override
52 | Widget build(BuildContext context) {
53 | var productBloc = Provider.of(context);
54 | var authBloc = Provider.of(context);
55 |
56 | return FutureBuilder(
57 | future: productBloc.fetchProduct(widget.productId),
58 | builder: (context, snapshot) {
59 | if (!snapshot.hasData && widget.productId != null) {
60 | return Scaffold(
61 | body: Center(
62 | child: (Platform.isIOS)
63 | ? CupertinoActivityIndicator()
64 | : CircularProgressIndicator()),
65 | );
66 | }
67 |
68 | Product existingProduct;
69 |
70 | if (widget.productId != null) {
71 | //Edit Logic
72 | existingProduct = snapshot.data;
73 | loadValues(productBloc, existingProduct, authBloc.userId);
74 | } else {
75 | //Add Logic
76 | loadValues(productBloc, null, authBloc.userId);
77 | }
78 |
79 | return (Platform.isIOS)
80 | ? AppSliverScaffold.cupertinoSliverScaffold(
81 | navTitle: '',
82 | pageBody: pageBody(true, productBloc, context, existingProduct),
83 | context: context)
84 | : AppSliverScaffold.materialSliverScaffold(
85 | navTitle: '',
86 | pageBody:
87 | pageBody(false, productBloc, context, existingProduct),
88 | context: context);
89 | },
90 | );
91 | }
92 |
93 | Widget pageBody(bool isIOS, ProductBloc productBloc, BuildContext context,
94 | Product existingProduct) {
95 | var items = Provider.of>(context);
96 | var pageLabel = (existingProduct != null) ? 'Edit Product' : 'Add Product';
97 | return ListView(
98 | children: [
99 | Text(
100 | pageLabel,
101 | style: TextStyles.subtitle,
102 | textAlign: TextAlign.center,
103 | ),
104 | Padding(
105 | padding: BaseStyles.listPadding,
106 | child: Divider(color: AppColors.darkblue),
107 | ),
108 | StreamBuilder(
109 | stream: productBloc.productName,
110 | builder: (context, snapshot) {
111 | return AppTextField(
112 | hintText: 'Product Name',
113 | cupertinoIcon: FontAwesomeIcons.shoppingBasket,
114 | materialIcon: FontAwesomeIcons.shoppingBasket,
115 | isIOS: isIOS,
116 | errorText: snapshot.error,
117 | initialText: (existingProduct != null)
118 | ? existingProduct.productName
119 | : null,
120 | onChanged: productBloc.changeProductName,
121 | );
122 | }),
123 | StreamBuilder(
124 | stream: productBloc.unitType,
125 | builder: (context, snapshot) {
126 | return AppDropdownButton(
127 | hintText: 'Unit Type',
128 | items: items,
129 | value: snapshot.data,
130 | materialIcon: FontAwesomeIcons.balanceScale,
131 | cupertinoIcon: FontAwesomeIcons.balanceScale,
132 | onChanged: productBloc.changeUnitType,
133 | );
134 | }),
135 | StreamBuilder(
136 | stream: productBloc.unitPrice,
137 | builder: (context, snapshot) {
138 | return AppTextField(
139 | hintText: 'Unit Price',
140 | cupertinoIcon: FontAwesomeIcons.tag,
141 | materialIcon: FontAwesomeIcons.tag,
142 | isIOS: isIOS,
143 | textInputType: TextInputType.number,
144 | errorText: snapshot.error,
145 | initialText: (existingProduct != null)
146 | ? existingProduct.unitPrice.toString()
147 | : null,
148 | onChanged: productBloc.changeUnitPrice,
149 | );
150 | }),
151 | StreamBuilder(
152 | stream: productBloc.availableUnits,
153 | builder: (context, snapshot) {
154 | return AppTextField(
155 | hintText: 'Available Units',
156 | cupertinoIcon: FontAwesomeIcons.cubes,
157 | materialIcon: FontAwesomeIcons.cubes,
158 | isIOS: isIOS,
159 | textInputType: TextInputType.number,
160 | errorText: snapshot.error,
161 | initialText: (existingProduct != null)
162 | ? existingProduct.availableUnits.toString()
163 | : null,
164 | onChanged: productBloc.changeAvailableUnits,
165 | );
166 | }),
167 | StreamBuilder(
168 | stream: productBloc.isUploading,
169 | builder: (context,snapshot){
170 | return (!snapshot.hasData || snapshot.data == false)
171 | ? Container()
172 | : Center(child: (Platform.isIOS)
173 | ? CupertinoActivityIndicator()
174 | : CircularProgressIndicator(),);
175 | },),
176 | StreamBuilder(
177 | stream: productBloc.imageUrl,
178 | builder: (context, snapshot) {
179 | if (!snapshot.hasData || snapshot.data == "")
180 | return AppButton(buttonType: ButtonType.Straw, buttonText: 'Add Image',onPressed: productBloc.pickImage,);
181 |
182 | return Column(children: [
183 | Padding(
184 | padding: BaseStyles.listPadding,
185 | child: Image.network(snapshot.data),
186 | ),
187 | AppButton(buttonType: ButtonType.Straw, buttonText: 'Change Image',onPressed: productBloc.pickImage,)
188 | ],);
189 | }
190 | ),
191 | StreamBuilder(
192 | stream: productBloc.isValid,
193 | builder: (context, snapshot) {
194 | return AppButton(
195 | buttonType: (snapshot.data == true)
196 | ? ButtonType.DarkBlue
197 | : ButtonType.Disabled,
198 | buttonText: 'Save Product',
199 | onPressed: productBloc.saveProduct,
200 | );
201 | }),
202 | ],
203 | );
204 | }
205 |
206 | loadValues(ProductBloc productBloc, Product product, String vendorId) {
207 | productBloc.changeProduct(product);
208 | productBloc.changeVendorId(vendorId);
209 |
210 | if (product != null) {
211 | //Edit
212 | productBloc.changeUnitType(product.unitType);
213 | productBloc.changeProductName(product.productName);
214 | productBloc.changeUnitPrice(product.unitPrice.toString());
215 | productBloc.changeAvailableUnits(product.availableUnits.toString());
216 | productBloc.changeImageUrl(product.imageUrl ?? '');
217 | } else {
218 | //Add
219 | productBloc.changeUnitType(null);
220 | productBloc.changeProductName(null);
221 | productBloc.changeUnitPrice(null);
222 | productBloc.changeAvailableUnits(null);
223 | productBloc.changeImageUrl('');
224 | }
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "2.4.2"
11 | boolean_selector:
12 | dependency: transitive
13 | description:
14 | name: boolean_selector
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "2.0.0"
18 | characters:
19 | dependency: transitive
20 | description:
21 | name: characters
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "1.0.0"
25 | charcode:
26 | dependency: transitive
27 | description:
28 | name: charcode
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "1.1.3"
32 | clock:
33 | dependency: transitive
34 | description:
35 | name: clock
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "1.0.1"
39 | cloud_firestore:
40 | dependency: "direct main"
41 | description:
42 | name: cloud_firestore
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "0.14.0+2"
46 | cloud_firestore_platform_interface:
47 | dependency: transitive
48 | description:
49 | name: cloud_firestore_platform_interface
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "2.0.1"
53 | cloud_firestore_web:
54 | dependency: transitive
55 | description:
56 | name: cloud_firestore_web
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "0.2.0+1"
60 | collection:
61 | dependency: transitive
62 | description:
63 | name: collection
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "1.14.13"
67 | convert:
68 | dependency: transitive
69 | description:
70 | name: convert
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "2.1.1"
74 | crypto:
75 | dependency: transitive
76 | description:
77 | name: crypto
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "2.1.4"
81 | cupertino_icons:
82 | dependency: "direct main"
83 | description:
84 | name: cupertino_icons
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "0.1.3"
88 | date_format:
89 | dependency: "direct main"
90 | description:
91 | name: date_format
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "1.0.8"
95 | fake_async:
96 | dependency: transitive
97 | description:
98 | name: fake_async
99 | url: "https://pub.dartlang.org"
100 | source: hosted
101 | version: "1.1.0"
102 | firebase:
103 | dependency: transitive
104 | description:
105 | name: firebase
106 | url: "https://pub.dartlang.org"
107 | source: hosted
108 | version: "7.3.0"
109 | firebase_auth:
110 | dependency: "direct main"
111 | description:
112 | name: firebase_auth
113 | url: "https://pub.dartlang.org"
114 | source: hosted
115 | version: "0.18.0+1"
116 | firebase_auth_platform_interface:
117 | dependency: transitive
118 | description:
119 | name: firebase_auth_platform_interface
120 | url: "https://pub.dartlang.org"
121 | source: hosted
122 | version: "2.0.1"
123 | firebase_auth_web:
124 | dependency: transitive
125 | description:
126 | name: firebase_auth_web
127 | url: "https://pub.dartlang.org"
128 | source: hosted
129 | version: "0.3.0+1"
130 | firebase_core:
131 | dependency: "direct main"
132 | description:
133 | name: firebase_core
134 | url: "https://pub.dartlang.org"
135 | source: hosted
136 | version: "0.5.0"
137 | firebase_core_platform_interface:
138 | dependency: transitive
139 | description:
140 | name: firebase_core_platform_interface
141 | url: "https://pub.dartlang.org"
142 | source: hosted
143 | version: "2.0.0"
144 | firebase_core_web:
145 | dependency: transitive
146 | description:
147 | name: firebase_core_web
148 | url: "https://pub.dartlang.org"
149 | source: hosted
150 | version: "0.2.0"
151 | firebase_storage:
152 | dependency: "direct main"
153 | description:
154 | name: firebase_storage
155 | url: "https://pub.dartlang.org"
156 | source: hosted
157 | version: "4.0.0"
158 | flutter:
159 | dependency: "direct main"
160 | description: flutter
161 | source: sdk
162 | version: "0.0.0"
163 | flutter_native_image:
164 | dependency: "direct main"
165 | description:
166 | name: flutter_native_image
167 | url: "https://pub.dartlang.org"
168 | source: hosted
169 | version: "0.0.5+2"
170 | flutter_plugin_android_lifecycle:
171 | dependency: transitive
172 | description:
173 | name: flutter_plugin_android_lifecycle
174 | url: "https://pub.dartlang.org"
175 | source: hosted
176 | version: "1.0.8"
177 | flutter_test:
178 | dependency: "direct dev"
179 | description: flutter
180 | source: sdk
181 | version: "0.0.0"
182 | flutter_web_plugins:
183 | dependency: transitive
184 | description: flutter
185 | source: sdk
186 | version: "0.0.0"
187 | fluttertoast:
188 | dependency: "direct main"
189 | description:
190 | name: fluttertoast
191 | url: "https://pub.dartlang.org"
192 | source: hosted
193 | version: "4.0.1"
194 | font_awesome_flutter:
195 | dependency: "direct main"
196 | description:
197 | name: font_awesome_flutter
198 | url: "https://pub.dartlang.org"
199 | source: hosted
200 | version: "8.8.1"
201 | google_fonts:
202 | dependency: "direct main"
203 | description:
204 | name: google_fonts
205 | url: "https://pub.dartlang.org"
206 | source: hosted
207 | version: "1.0.0"
208 | http:
209 | dependency: transitive
210 | description:
211 | name: http
212 | url: "https://pub.dartlang.org"
213 | source: hosted
214 | version: "0.12.1"
215 | http_parser:
216 | dependency: transitive
217 | description:
218 | name: http_parser
219 | url: "https://pub.dartlang.org"
220 | source: hosted
221 | version: "3.1.4"
222 | image_picker:
223 | dependency: "direct main"
224 | description:
225 | name: image_picker
226 | url: "https://pub.dartlang.org"
227 | source: hosted
228 | version: "0.6.7+3"
229 | image_picker_platform_interface:
230 | dependency: transitive
231 | description:
232 | name: image_picker_platform_interface
233 | url: "https://pub.dartlang.org"
234 | source: hosted
235 | version: "1.1.0"
236 | intl:
237 | dependency: "direct main"
238 | description:
239 | name: intl
240 | url: "https://pub.dartlang.org"
241 | source: hosted
242 | version: "0.16.1"
243 | js:
244 | dependency: transitive
245 | description:
246 | name: js
247 | url: "https://pub.dartlang.org"
248 | source: hosted
249 | version: "0.6.1+1"
250 | matcher:
251 | dependency: transitive
252 | description:
253 | name: matcher
254 | url: "https://pub.dartlang.org"
255 | source: hosted
256 | version: "0.12.8"
257 | meta:
258 | dependency: transitive
259 | description:
260 | name: meta
261 | url: "https://pub.dartlang.org"
262 | source: hosted
263 | version: "1.1.8"
264 | nested:
265 | dependency: transitive
266 | description:
267 | name: nested
268 | url: "https://pub.dartlang.org"
269 | source: hosted
270 | version: "0.0.4"
271 | path:
272 | dependency: transitive
273 | description:
274 | name: path
275 | url: "https://pub.dartlang.org"
276 | source: hosted
277 | version: "1.7.0"
278 | path_provider:
279 | dependency: transitive
280 | description:
281 | name: path_provider
282 | url: "https://pub.dartlang.org"
283 | source: hosted
284 | version: "1.6.7"
285 | path_provider_macos:
286 | dependency: transitive
287 | description:
288 | name: path_provider_macos
289 | url: "https://pub.dartlang.org"
290 | source: hosted
291 | version: "0.0.4+1"
292 | path_provider_platform_interface:
293 | dependency: transitive
294 | description:
295 | name: path_provider_platform_interface
296 | url: "https://pub.dartlang.org"
297 | source: hosted
298 | version: "1.0.1"
299 | pedantic:
300 | dependency: transitive
301 | description:
302 | name: pedantic
303 | url: "https://pub.dartlang.org"
304 | source: hosted
305 | version: "1.8.0+1"
306 | permission_handler:
307 | dependency: "direct main"
308 | description:
309 | name: permission_handler
310 | url: "https://pub.dartlang.org"
311 | source: hosted
312 | version: "5.0.1+1"
313 | permission_handler_platform_interface:
314 | dependency: transitive
315 | description:
316 | name: permission_handler_platform_interface
317 | url: "https://pub.dartlang.org"
318 | source: hosted
319 | version: "2.0.1"
320 | platform:
321 | dependency: transitive
322 | description:
323 | name: platform
324 | url: "https://pub.dartlang.org"
325 | source: hosted
326 | version: "2.2.1"
327 | plugin_platform_interface:
328 | dependency: transitive
329 | description:
330 | name: plugin_platform_interface
331 | url: "https://pub.dartlang.org"
332 | source: hosted
333 | version: "1.0.2"
334 | provider:
335 | dependency: "direct main"
336 | description:
337 | name: provider
338 | url: "https://pub.dartlang.org"
339 | source: hosted
340 | version: "4.3.2+2"
341 | quiver:
342 | dependency: transitive
343 | description:
344 | name: quiver
345 | url: "https://pub.dartlang.org"
346 | source: hosted
347 | version: "2.1.3"
348 | rxdart:
349 | dependency: "direct main"
350 | description:
351 | name: rxdart
352 | url: "https://pub.dartlang.org"
353 | source: hosted
354 | version: "0.24.1"
355 | sky_engine:
356 | dependency: transitive
357 | description: flutter
358 | source: sdk
359 | version: "0.0.99"
360 | source_span:
361 | dependency: transitive
362 | description:
363 | name: source_span
364 | url: "https://pub.dartlang.org"
365 | source: hosted
366 | version: "1.7.0"
367 | stack_trace:
368 | dependency: transitive
369 | description:
370 | name: stack_trace
371 | url: "https://pub.dartlang.org"
372 | source: hosted
373 | version: "1.9.5"
374 | stream_channel:
375 | dependency: transitive
376 | description:
377 | name: stream_channel
378 | url: "https://pub.dartlang.org"
379 | source: hosted
380 | version: "2.0.0"
381 | string_scanner:
382 | dependency: transitive
383 | description:
384 | name: string_scanner
385 | url: "https://pub.dartlang.org"
386 | source: hosted
387 | version: "1.0.5"
388 | term_glyph:
389 | dependency: transitive
390 | description:
391 | name: term_glyph
392 | url: "https://pub.dartlang.org"
393 | source: hosted
394 | version: "1.1.0"
395 | test_api:
396 | dependency: transitive
397 | description:
398 | name: test_api
399 | url: "https://pub.dartlang.org"
400 | source: hosted
401 | version: "0.2.17"
402 | typed_data:
403 | dependency: transitive
404 | description:
405 | name: typed_data
406 | url: "https://pub.dartlang.org"
407 | source: hosted
408 | version: "1.2.0"
409 | uuid:
410 | dependency: "direct main"
411 | description:
412 | name: uuid
413 | url: "https://pub.dartlang.org"
414 | source: hosted
415 | version: "2.0.4"
416 | vector_math:
417 | dependency: transitive
418 | description:
419 | name: vector_math
420 | url: "https://pub.dartlang.org"
421 | source: hosted
422 | version: "2.0.8"
423 | sdks:
424 | dart: ">=2.9.0-14.0.dev <3.0.0"
425 | flutter: ">=1.16.0 <2.0.0"
426 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3915B9972454B544000BD821 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3915B9962454B544000BD821 /* GoogleService-Info.plist */; };
12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
13 | 68A0E9B6A28F5130E373EEE2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FE17B991E2D6714A5E1D4FF5 /* Pods_Runner.framework */; };
14 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
15 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
16 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
17 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXCopyFilesBuildPhase section */
21 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
22 | isa = PBXCopyFilesBuildPhase;
23 | buildActionMask = 2147483647;
24 | dstPath = "";
25 | dstSubfolderSpec = 10;
26 | files = (
27 | );
28 | name = "Embed Frameworks";
29 | runOnlyForDeploymentPostprocessing = 0;
30 | };
31 | /* End PBXCopyFilesBuildPhase section */
32 |
33 | /* Begin PBXFileReference section */
34 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
35 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
36 | 3915B9962454B544000BD821 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
37 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
38 | 4B20A56B8C0449CF4994B84D /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
39 | 65A2F69D4D2E6DBD65A20F91 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
40 | 6CE5340600B65B28702F21B5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
41 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
42 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
43 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
44 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
45 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
46 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
47 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
48 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
49 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
50 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
51 | FE17B991E2D6714A5E1D4FF5 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
52 | /* End PBXFileReference section */
53 |
54 | /* Begin PBXFrameworksBuildPhase section */
55 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
56 | isa = PBXFrameworksBuildPhase;
57 | buildActionMask = 2147483647;
58 | files = (
59 | 68A0E9B6A28F5130E373EEE2 /* Pods_Runner.framework in Frameworks */,
60 | );
61 | runOnlyForDeploymentPostprocessing = 0;
62 | };
63 | /* End PBXFrameworksBuildPhase section */
64 |
65 | /* Begin PBXGroup section */
66 | 5DD5AAD190E733AFF61C2C33 /* Frameworks */ = {
67 | isa = PBXGroup;
68 | children = (
69 | FE17B991E2D6714A5E1D4FF5 /* Pods_Runner.framework */,
70 | );
71 | name = Frameworks;
72 | sourceTree = "";
73 | };
74 | 9740EEB11CF90186004384FC /* Flutter */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
78 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
79 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
80 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
81 | );
82 | name = Flutter;
83 | sourceTree = "";
84 | };
85 | 97C146E51CF9000F007C117D = {
86 | isa = PBXGroup;
87 | children = (
88 | 9740EEB11CF90186004384FC /* Flutter */,
89 | 97C146F01CF9000F007C117D /* Runner */,
90 | 97C146EF1CF9000F007C117D /* Products */,
91 | B177B850C742BF807655567F /* Pods */,
92 | 5DD5AAD190E733AFF61C2C33 /* Frameworks */,
93 | );
94 | sourceTree = "";
95 | };
96 | 97C146EF1CF9000F007C117D /* Products */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 97C146EE1CF9000F007C117D /* Runner.app */,
100 | );
101 | name = Products;
102 | sourceTree = "";
103 | };
104 | 97C146F01CF9000F007C117D /* Runner */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 3915B9962454B544000BD821 /* GoogleService-Info.plist */,
108 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
109 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
110 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
111 | 97C147021CF9000F007C117D /* Info.plist */,
112 | 97C146F11CF9000F007C117D /* Supporting Files */,
113 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
114 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
115 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
116 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
117 | );
118 | path = Runner;
119 | sourceTree = "";
120 | };
121 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
122 | isa = PBXGroup;
123 | children = (
124 | );
125 | name = "Supporting Files";
126 | sourceTree = "";
127 | };
128 | B177B850C742BF807655567F /* Pods */ = {
129 | isa = PBXGroup;
130 | children = (
131 | 65A2F69D4D2E6DBD65A20F91 /* Pods-Runner.debug.xcconfig */,
132 | 6CE5340600B65B28702F21B5 /* Pods-Runner.release.xcconfig */,
133 | 4B20A56B8C0449CF4994B84D /* Pods-Runner.profile.xcconfig */,
134 | );
135 | path = Pods;
136 | sourceTree = "";
137 | };
138 | /* End PBXGroup section */
139 |
140 | /* Begin PBXNativeTarget section */
141 | 97C146ED1CF9000F007C117D /* Runner */ = {
142 | isa = PBXNativeTarget;
143 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
144 | buildPhases = (
145 | 8431FA21782795D8D0012351 /* [CP] Check Pods Manifest.lock */,
146 | 9740EEB61CF901F6004384FC /* Run Script */,
147 | 97C146EA1CF9000F007C117D /* Sources */,
148 | 97C146EB1CF9000F007C117D /* Frameworks */,
149 | 97C146EC1CF9000F007C117D /* Resources */,
150 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
151 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
152 | 79635FBF6A90A2364C399DB8 /* [CP] Embed Pods Frameworks */,
153 | );
154 | buildRules = (
155 | );
156 | dependencies = (
157 | );
158 | name = Runner;
159 | productName = Runner;
160 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
161 | productType = "com.apple.product-type.application";
162 | };
163 | /* End PBXNativeTarget section */
164 |
165 | /* Begin PBXProject section */
166 | 97C146E61CF9000F007C117D /* Project object */ = {
167 | isa = PBXProject;
168 | attributes = {
169 | LastUpgradeCheck = 1020;
170 | ORGANIZATIONNAME = "The Chromium Authors";
171 | TargetAttributes = {
172 | 97C146ED1CF9000F007C117D = {
173 | CreatedOnToolsVersion = 7.3.1;
174 | DevelopmentTeam = K6BTRK3UFD;
175 | LastSwiftMigration = 1100;
176 | };
177 | };
178 | };
179 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
180 | compatibilityVersion = "Xcode 3.2";
181 | developmentRegion = en;
182 | hasScannedForEncodings = 0;
183 | knownRegions = (
184 | en,
185 | Base,
186 | );
187 | mainGroup = 97C146E51CF9000F007C117D;
188 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
189 | projectDirPath = "";
190 | projectRoot = "";
191 | targets = (
192 | 97C146ED1CF9000F007C117D /* Runner */,
193 | );
194 | };
195 | /* End PBXProject section */
196 |
197 | /* Begin PBXResourcesBuildPhase section */
198 | 97C146EC1CF9000F007C117D /* Resources */ = {
199 | isa = PBXResourcesBuildPhase;
200 | buildActionMask = 2147483647;
201 | files = (
202 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
203 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
204 | 3915B9972454B544000BD821 /* GoogleService-Info.plist in Resources */,
205 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
206 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
207 | );
208 | runOnlyForDeploymentPostprocessing = 0;
209 | };
210 | /* End PBXResourcesBuildPhase section */
211 |
212 | /* Begin PBXShellScriptBuildPhase section */
213 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
214 | isa = PBXShellScriptBuildPhase;
215 | buildActionMask = 2147483647;
216 | files = (
217 | );
218 | inputPaths = (
219 | );
220 | name = "Thin Binary";
221 | outputPaths = (
222 | );
223 | runOnlyForDeploymentPostprocessing = 0;
224 | shellPath = /bin/sh;
225 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
226 | };
227 | 79635FBF6A90A2364C399DB8 /* [CP] Embed Pods Frameworks */ = {
228 | isa = PBXShellScriptBuildPhase;
229 | buildActionMask = 2147483647;
230 | files = (
231 | );
232 | inputPaths = (
233 | );
234 | name = "[CP] Embed Pods Frameworks";
235 | outputPaths = (
236 | );
237 | runOnlyForDeploymentPostprocessing = 0;
238 | shellPath = /bin/sh;
239 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
240 | showEnvVarsInLog = 0;
241 | };
242 | 8431FA21782795D8D0012351 /* [CP] Check Pods Manifest.lock */ = {
243 | isa = PBXShellScriptBuildPhase;
244 | buildActionMask = 2147483647;
245 | files = (
246 | );
247 | inputFileListPaths = (
248 | );
249 | inputPaths = (
250 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
251 | "${PODS_ROOT}/Manifest.lock",
252 | );
253 | name = "[CP] Check Pods Manifest.lock";
254 | outputFileListPaths = (
255 | );
256 | outputPaths = (
257 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
258 | );
259 | runOnlyForDeploymentPostprocessing = 0;
260 | shellPath = /bin/sh;
261 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
262 | showEnvVarsInLog = 0;
263 | };
264 | 9740EEB61CF901F6004384FC /* Run Script */ = {
265 | isa = PBXShellScriptBuildPhase;
266 | buildActionMask = 2147483647;
267 | files = (
268 | );
269 | inputPaths = (
270 | );
271 | name = "Run Script";
272 | outputPaths = (
273 | );
274 | runOnlyForDeploymentPostprocessing = 0;
275 | shellPath = /bin/sh;
276 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
277 | };
278 | /* End PBXShellScriptBuildPhase section */
279 |
280 | /* Begin PBXSourcesBuildPhase section */
281 | 97C146EA1CF9000F007C117D /* Sources */ = {
282 | isa = PBXSourcesBuildPhase;
283 | buildActionMask = 2147483647;
284 | files = (
285 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
286 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
287 | );
288 | runOnlyForDeploymentPostprocessing = 0;
289 | };
290 | /* End PBXSourcesBuildPhase section */
291 |
292 | /* Begin PBXVariantGroup section */
293 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
294 | isa = PBXVariantGroup;
295 | children = (
296 | 97C146FB1CF9000F007C117D /* Base */,
297 | );
298 | name = Main.storyboard;
299 | sourceTree = "";
300 | };
301 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
302 | isa = PBXVariantGroup;
303 | children = (
304 | 97C147001CF9000F007C117D /* Base */,
305 | );
306 | name = LaunchScreen.storyboard;
307 | sourceTree = "";
308 | };
309 | /* End PBXVariantGroup section */
310 |
311 | /* Begin XCBuildConfiguration section */
312 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
313 | isa = XCBuildConfiguration;
314 | buildSettings = {
315 | ALWAYS_SEARCH_USER_PATHS = NO;
316 | CLANG_ANALYZER_NONNULL = YES;
317 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
318 | CLANG_CXX_LIBRARY = "libc++";
319 | CLANG_ENABLE_MODULES = YES;
320 | CLANG_ENABLE_OBJC_ARC = YES;
321 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
322 | CLANG_WARN_BOOL_CONVERSION = YES;
323 | CLANG_WARN_COMMA = YES;
324 | CLANG_WARN_CONSTANT_CONVERSION = YES;
325 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
326 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
327 | CLANG_WARN_EMPTY_BODY = YES;
328 | CLANG_WARN_ENUM_CONVERSION = YES;
329 | CLANG_WARN_INFINITE_RECURSION = YES;
330 | CLANG_WARN_INT_CONVERSION = YES;
331 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
332 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
333 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
334 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
335 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
336 | CLANG_WARN_STRICT_PROTOTYPES = YES;
337 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
338 | CLANG_WARN_UNREACHABLE_CODE = YES;
339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
340 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
341 | COPY_PHASE_STRIP = NO;
342 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
343 | ENABLE_NS_ASSERTIONS = NO;
344 | ENABLE_STRICT_OBJC_MSGSEND = YES;
345 | GCC_C_LANGUAGE_STANDARD = gnu99;
346 | GCC_NO_COMMON_BLOCKS = YES;
347 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
348 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
349 | GCC_WARN_UNDECLARED_SELECTOR = YES;
350 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
351 | GCC_WARN_UNUSED_FUNCTION = YES;
352 | GCC_WARN_UNUSED_VARIABLE = YES;
353 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
354 | MTL_ENABLE_DEBUG_INFO = NO;
355 | SDKROOT = iphoneos;
356 | SUPPORTED_PLATFORMS = iphoneos;
357 | TARGETED_DEVICE_FAMILY = "1,2";
358 | VALIDATE_PRODUCT = YES;
359 | };
360 | name = Profile;
361 | };
362 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
363 | isa = XCBuildConfiguration;
364 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
365 | buildSettings = {
366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
367 | CLANG_ENABLE_MODULES = YES;
368 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
369 | DEVELOPMENT_TEAM = K6BTRK3UFD;
370 | ENABLE_BITCODE = NO;
371 | FRAMEWORK_SEARCH_PATHS = (
372 | "$(inherited)",
373 | "$(PROJECT_DIR)/Flutter",
374 | );
375 | INFOPLIST_FILE = Runner/Info.plist;
376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
377 | LIBRARY_SEARCH_PATHS = (
378 | "$(inherited)",
379 | "$(PROJECT_DIR)/Flutter",
380 | );
381 | PRODUCT_BUNDLE_IDENTIFIER = com.julow.farmersMarket;
382 | PRODUCT_NAME = "$(TARGET_NAME)";
383 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
384 | SWIFT_VERSION = 5.0;
385 | VERSIONING_SYSTEM = "apple-generic";
386 | };
387 | name = Profile;
388 | };
389 | 97C147031CF9000F007C117D /* Debug */ = {
390 | isa = XCBuildConfiguration;
391 | buildSettings = {
392 | ALWAYS_SEARCH_USER_PATHS = NO;
393 | CLANG_ANALYZER_NONNULL = YES;
394 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
395 | CLANG_CXX_LIBRARY = "libc++";
396 | CLANG_ENABLE_MODULES = YES;
397 | CLANG_ENABLE_OBJC_ARC = YES;
398 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
399 | CLANG_WARN_BOOL_CONVERSION = YES;
400 | CLANG_WARN_COMMA = YES;
401 | CLANG_WARN_CONSTANT_CONVERSION = YES;
402 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
403 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
404 | CLANG_WARN_EMPTY_BODY = YES;
405 | CLANG_WARN_ENUM_CONVERSION = YES;
406 | CLANG_WARN_INFINITE_RECURSION = YES;
407 | CLANG_WARN_INT_CONVERSION = YES;
408 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
409 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
413 | CLANG_WARN_STRICT_PROTOTYPES = YES;
414 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
415 | CLANG_WARN_UNREACHABLE_CODE = YES;
416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
418 | COPY_PHASE_STRIP = NO;
419 | DEBUG_INFORMATION_FORMAT = dwarf;
420 | ENABLE_STRICT_OBJC_MSGSEND = YES;
421 | ENABLE_TESTABILITY = YES;
422 | GCC_C_LANGUAGE_STANDARD = gnu99;
423 | GCC_DYNAMIC_NO_PIC = NO;
424 | GCC_NO_COMMON_BLOCKS = YES;
425 | GCC_OPTIMIZATION_LEVEL = 0;
426 | GCC_PREPROCESSOR_DEFINITIONS = (
427 | "DEBUG=1",
428 | "$(inherited)",
429 | );
430 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
431 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
432 | GCC_WARN_UNDECLARED_SELECTOR = YES;
433 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
434 | GCC_WARN_UNUSED_FUNCTION = YES;
435 | GCC_WARN_UNUSED_VARIABLE = YES;
436 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
437 | MTL_ENABLE_DEBUG_INFO = YES;
438 | ONLY_ACTIVE_ARCH = YES;
439 | SDKROOT = iphoneos;
440 | TARGETED_DEVICE_FAMILY = "1,2";
441 | };
442 | name = Debug;
443 | };
444 | 97C147041CF9000F007C117D /* Release */ = {
445 | isa = XCBuildConfiguration;
446 | buildSettings = {
447 | ALWAYS_SEARCH_USER_PATHS = NO;
448 | CLANG_ANALYZER_NONNULL = YES;
449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
450 | CLANG_CXX_LIBRARY = "libc++";
451 | CLANG_ENABLE_MODULES = YES;
452 | CLANG_ENABLE_OBJC_ARC = YES;
453 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
454 | CLANG_WARN_BOOL_CONVERSION = YES;
455 | CLANG_WARN_COMMA = YES;
456 | CLANG_WARN_CONSTANT_CONVERSION = YES;
457 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
458 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
459 | CLANG_WARN_EMPTY_BODY = YES;
460 | CLANG_WARN_ENUM_CONVERSION = YES;
461 | CLANG_WARN_INFINITE_RECURSION = YES;
462 | CLANG_WARN_INT_CONVERSION = YES;
463 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
464 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
465 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
467 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
468 | CLANG_WARN_STRICT_PROTOTYPES = YES;
469 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
470 | CLANG_WARN_UNREACHABLE_CODE = YES;
471 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
472 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
473 | COPY_PHASE_STRIP = NO;
474 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
475 | ENABLE_NS_ASSERTIONS = NO;
476 | ENABLE_STRICT_OBJC_MSGSEND = YES;
477 | GCC_C_LANGUAGE_STANDARD = gnu99;
478 | GCC_NO_COMMON_BLOCKS = YES;
479 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
480 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
481 | GCC_WARN_UNDECLARED_SELECTOR = YES;
482 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
483 | GCC_WARN_UNUSED_FUNCTION = YES;
484 | GCC_WARN_UNUSED_VARIABLE = YES;
485 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
486 | MTL_ENABLE_DEBUG_INFO = NO;
487 | SDKROOT = iphoneos;
488 | SUPPORTED_PLATFORMS = iphoneos;
489 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
490 | TARGETED_DEVICE_FAMILY = "1,2";
491 | VALIDATE_PRODUCT = YES;
492 | };
493 | name = Release;
494 | };
495 | 97C147061CF9000F007C117D /* Debug */ = {
496 | isa = XCBuildConfiguration;
497 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
498 | buildSettings = {
499 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
500 | CLANG_ENABLE_MODULES = YES;
501 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
502 | DEVELOPMENT_TEAM = K6BTRK3UFD;
503 | ENABLE_BITCODE = NO;
504 | FRAMEWORK_SEARCH_PATHS = (
505 | "$(inherited)",
506 | "$(PROJECT_DIR)/Flutter",
507 | );
508 | INFOPLIST_FILE = Runner/Info.plist;
509 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
510 | LIBRARY_SEARCH_PATHS = (
511 | "$(inherited)",
512 | "$(PROJECT_DIR)/Flutter",
513 | );
514 | PRODUCT_BUNDLE_IDENTIFIER = com.julow.farmersMarket;
515 | PRODUCT_NAME = "$(TARGET_NAME)";
516 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
517 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
518 | SWIFT_VERSION = 5.0;
519 | VERSIONING_SYSTEM = "apple-generic";
520 | };
521 | name = Debug;
522 | };
523 | 97C147071CF9000F007C117D /* Release */ = {
524 | isa = XCBuildConfiguration;
525 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
526 | buildSettings = {
527 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
528 | CLANG_ENABLE_MODULES = YES;
529 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
530 | DEVELOPMENT_TEAM = K6BTRK3UFD;
531 | ENABLE_BITCODE = NO;
532 | FRAMEWORK_SEARCH_PATHS = (
533 | "$(inherited)",
534 | "$(PROJECT_DIR)/Flutter",
535 | );
536 | INFOPLIST_FILE = Runner/Info.plist;
537 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
538 | LIBRARY_SEARCH_PATHS = (
539 | "$(inherited)",
540 | "$(PROJECT_DIR)/Flutter",
541 | );
542 | PRODUCT_BUNDLE_IDENTIFIER = com.julow.farmersMarket;
543 | PRODUCT_NAME = "$(TARGET_NAME)";
544 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
545 | SWIFT_VERSION = 5.0;
546 | VERSIONING_SYSTEM = "apple-generic";
547 | };
548 | name = Release;
549 | };
550 | /* End XCBuildConfiguration section */
551 |
552 | /* Begin XCConfigurationList section */
553 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
554 | isa = XCConfigurationList;
555 | buildConfigurations = (
556 | 97C147031CF9000F007C117D /* Debug */,
557 | 97C147041CF9000F007C117D /* Release */,
558 | 249021D3217E4FDB00AE95B9 /* Profile */,
559 | );
560 | defaultConfigurationIsVisible = 0;
561 | defaultConfigurationName = Release;
562 | };
563 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
564 | isa = XCConfigurationList;
565 | buildConfigurations = (
566 | 97C147061CF9000F007C117D /* Debug */,
567 | 97C147071CF9000F007C117D /* Release */,
568 | 249021D4217E4FDB00AE95B9 /* Profile */,
569 | );
570 | defaultConfigurationIsVisible = 0;
571 | defaultConfigurationName = Release;
572 | };
573 | /* End XCConfigurationList section */
574 | };
575 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
576 | }
577 |
--------------------------------------------------------------------------------