diff --git a/.metadata b/.metadata index 784ce129..90eabcff 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3" + revision: "80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819" channel: "stable" project_type: app @@ -13,11 +13,26 @@ project_type: app migration: platforms: - platform: root - create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 - base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + - platform: android + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + - platform: ios + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + - platform: linux + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + - platform: macos + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 - platform: web - create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 - base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + - platform: windows + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 # User provided section diff --git a/.vscode/settings.json b/.vscode/settings.json index e0120650..3da905aa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "java.compile.nullAnalysis.mode": "automatic", - "java.configuration.updateBuildConfiguration": "interactive" + "java.configuration.updateBuildConfiguration": "interactive", + "cmake.sourceDirectory": "D:/Sahil/flutter-apps/Sharekhan/get_flutter_fire/windows/flutter" } \ No newline at end of file diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..eda0a863 --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,46 @@ +{ + "project_info": { + "project_number": "784525273637", + "project_id": "sharekhan-project", + "storage_bucket": "sharekhan-project.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:784525273637:android:c1966d53b8f4eb96626dcc", + "android_client_info": { + "package_name": "com.example.get_flutter_fire" + } + }, + "oauth_client": [ + { + "client_id": "784525273637-605r9ms12s7lbjikujvcvb8nsrqbebmr.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCeBbH7YPz08UZsiirSsJQ0mDtFqYezHsQ" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "784525273637-605r9ms12s7lbjikujvcvb8nsrqbebmr.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "784525273637-a5miokt96an7utjtb3dntpaag9ifb9i9.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.example.getFlutterFire" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt b/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt new file mode 100644 index 00000000..018e286b --- /dev/null +++ b/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.get_flutter_fire + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/assets/icons/images.jpg b/assets/icons/images.jpg new file mode 100644 index 00000000..0ab6605d Binary files /dev/null and b/assets/icons/images.jpg differ diff --git a/assets/icons/sharekhan_logo.png b/assets/icons/sharekhan_logo.png new file mode 100644 index 00000000..8631d74a Binary files /dev/null and b/assets/icons/sharekhan_logo.png differ diff --git a/firebase.json b/firebase.json new file mode 100644 index 00000000..cf30bb38 --- /dev/null +++ b/firebase.json @@ -0,0 +1 @@ +{"flutter":{"platforms":{"android":{"default":{"projectId":"sharekhan-project","appId":"1:784525273637:android:c1966d53b8f4eb96626dcc","fileOutput":"android/app/google-services.json"}},"dart":{"lib/firebase_options.dart":{"projectId":"sharekhan-project","configurations":{"android":"1:784525273637:android:c1966d53b8f4eb96626dcc","ios":"1:784525273637:ios:0d855743258edd6e626dcc","macos":"1:784525273637:ios:0d855743258edd6e626dcc","web":"1:784525273637:web:b34a7d2fd4f32969626dcc","windows":"1:784525273637:web:90330fbc8bedc31e626dcc"}}}}}} \ No newline at end of file diff --git a/lib/app/modules/cart/bindings/cart_binding.dart b/lib/app/modules/cart/bindings/cart_binding.dart index 009c52ae..a2fa356c 100644 --- a/lib/app/modules/cart/bindings/cart_binding.dart +++ b/lib/app/modules/cart/bindings/cart_binding.dart @@ -5,8 +5,8 @@ import '../controllers/cart_controller.dart'; class CartBinding extends Bindings { @override void dependencies() { - Get.lazyPut( - () => CartController(), - ); + // Get.lazyPut( + // () => CartController(), + // ); } } diff --git a/lib/app/modules/cart/controllers/cart_controller.dart b/lib/app/modules/cart/controllers/cart_controller.dart index c938ec4c..c201afe4 100644 --- a/lib/app/modules/cart/controllers/cart_controller.dart +++ b/lib/app/modules/cart/controllers/cart_controller.dart @@ -1,23 +1,30 @@ import 'package:get/get.dart'; +import 'package:get_flutter_fire/models/products_admin.dart'; class CartController extends GetxController { - //TODO: Implement CartController + var cartItems = {}.obs; // Map of product to quantity - final count = 0.obs; - @override - void onInit() { - super.onInit(); + void addToCart(Product product, int quantity) { + if (cartItems.containsKey(product)) { + cartItems[product] = cartItems[product]! + quantity; + } else { + cartItems[product] = quantity; + } + update(); } - @override - void onReady() { - super.onReady(); + void removeFromCart(Product product) { + if (cartItems.containsKey(product)) { + if (cartItems[product]! > 1) { + cartItems[product] = cartItems[product]! - 1; // Decrease quantity + } else { + cartItems.remove(product); // Remove if quantity is 1 or less + } + update(); + } } - @override - void onClose() { - super.onClose(); - } - - void increment() => count.value++; + double get totalPrice => cartItems.entries + .map((entry) => entry.key.price! * entry.value) + .fold(0, (sum, price) => sum + price); } diff --git a/lib/app/modules/cart/views/cart_view.dart b/lib/app/modules/cart/views/cart_view.dart index 3e048c79..bae263bc 100644 --- a/lib/app/modules/cart/views/cart_view.dart +++ b/lib/app/modules/cart/views/cart_view.dart @@ -8,20 +8,47 @@ import '../controllers/cart_controller.dart'; class CartView extends GetView { const CartView({super.key}); + @override Widget build(BuildContext context) { - return ScreenWidget( - appBar: AppBar( - title: Text('${AuthService.to.userName} Cart'), - centerTitle: true, - ), - body: const Center( - child: Text( - 'CartView is working', - style: TextStyle(fontSize: 20), + return GetBuilder(builder: (cartController) { + return Scaffold( + body: Obx(() { + if (cartController.cartItems.isEmpty) { + return const Center(child: Text('No items in cart')); + } + return ListView.builder( + itemCount: cartController.cartItems.length, + itemBuilder: (context, index) { + var product = cartController.cartItems.keys.toList()[index]; + var quantity = cartController.cartItems[product]!; + return ListTile( + title: Text(product.name ?? 'Product'), + subtitle: Text('Quantity: $quantity'), + trailing: Text('Rs. ${product.price! * quantity}'), + onTap: () { + // Navigate to product description or allow editing quantity + }, + ); + }, + ); + }), + bottomNavigationBar: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Total: Rs. ${cartController.totalPrice}'), + ElevatedButton( + onPressed: () { + // Proceed to payment or checkout + }, + child: const Text('Proceed to Payment'), + ), + ], + ), ), - ), - screen: screen!, - ); + ); + }); } } diff --git a/lib/app/modules/products/controllers/products_controller.dart b/lib/app/modules/products/controllers/products_controller.dart index 118c7dc8..c2324521 100644 --- a/lib/app/modules/products/controllers/products_controller.dart +++ b/lib/app/modules/products/controllers/products_controller.dart @@ -1,28 +1,113 @@ import 'package:get/get.dart'; - -import '../../../../models/product.dart'; +import 'package:get_flutter_fire/models/product_category.dart'; +import 'package:get_flutter_fire/models/products_admin.dart'; +import 'package:flutter/material.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; class ProductsController extends GetxController { - final products = [].obs; + FirebaseFirestore firestore = FirebaseFirestore.instance; + late CollectionReference prodCollection; + late CollectionReference categoryCollection; - void loadDemoProductsFromSomeWhere() { - products.add( - Product( - name: 'Product added on: ${DateTime.now().toString()}', - id: DateTime.now().millisecondsSinceEpoch.toString(), - ), - ); - } + List products = []; + List productsInUI = []; + List categories = []; + + // Map to track quantities of each product in the UI + RxMap productQuantities = {}.obs; @override - void onReady() { - super.onReady(); - loadDemoProductsFromSomeWhere(); + Future onInit() async { + prodCollection = firestore.collection('products'); + categoryCollection = firestore.collection('category'); + await fetchCategory(); + await fetchProducts(); + super.onInit(); } - @override - void onClose() { - Get.printInfo(info: 'Products: onClose'); - super.onClose(); + // Fetch products from Firestore + fetchProducts() async { + try { + QuerySnapshot productSnapshot = await prodCollection.get(); + final List retrievedProducts = productSnapshot.docs + .map((doc) => Product.fromJson(doc.data() as Map)) + .toList(); + products.clear(); + products.assignAll(retrievedProducts); + productsInUI.clear(); + productsInUI.assignAll(products); + + // Initialize product quantities to 0 for all products + for (var product in products) { + if (!productQuantities.containsKey(product)) { + productQuantities[product] = 0; + } + } + } on Exception catch (e) { + Get.snackbar('Error', e.toString(), colorText: Colors.red); + } finally { + update(); + } + } + + // Fetch categories from Firestore + fetchCategory() async { + try { + QuerySnapshot categorySnapshot = await categoryCollection.get(); + final List retrievedCategories = categorySnapshot.docs + .map((doc) => + ProductCategory.fromJson(doc.data() as Map)) + .toList(); + categories.clear(); + categories.assignAll(retrievedCategories); + } on Exception catch (e) { + Get.snackbar('Error', e.toString(), colorText: Colors.red); + } finally { + update(); + } + } + + // Filter products by category + filterByCategory(String category) { + productsInUI.clear(); + productsInUI = + products.where((product) => product.category == category).toList(); + update(); + } + + // Filter products by brand + filterByBrand(List brands) { + if (brands.isEmpty) { + productsInUI = products; + } else { + productsInUI = + products.where((product) => brands.contains(product.brand)).toList(); + } + update(); + } + + // Sort products by price + sortByPrice({required bool ascending}) { + List sortedProducts = List.from(productsInUI); + sortedProducts.sort((a, b) => ascending + ? a.price!.compareTo(b.price!) + : b.price!.compareTo(a.price!)); + productsInUI = sortedProducts; + update(); + } + + // Increment the quantity of a product + void incrementProductQuantity(Product product) { + productQuantities[product] = (productQuantities[product]!) + 1; + update(); + } + + // Decrement the quantity of a product + void decrementProductQuantity(Product product) { + final currentQuantity = productQuantities[product]!; + if (currentQuantity > 0) { + productQuantities[product] = currentQuantity - 1; + update(); + } } } diff --git a/lib/app/modules/products/views/products_descriptions_view.dart b/lib/app/modules/products/views/products_descriptions_view.dart new file mode 100644 index 00000000..c8aed8e6 --- /dev/null +++ b/lib/app/modules/products/views/products_descriptions_view.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_flutter_fire/models/products_admin.dart'; + +class ProductsDescriptionsView extends StatelessWidget { + final Product product; + const ProductsDescriptionsView({super.key, required this.product}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Product Details'), + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Image.network( + product.image ?? '', + fit: BoxFit.cover, + width: double.infinity, + height: 300, + )), + const SizedBox( + height: 20, + ), + Text(product.name ?? '', + style: + const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)), + const SizedBox( + height: 20, + ), + Text( + product.description ?? '', + style: TextStyle(fontSize: 16, height: 1.5), + ), + const SizedBox( + height: 20, + ), + Text( + 'Rs. ${product.price}', + style: TextStyle( + fontSize: 20, + color: Colors.orange, + fontWeight: FontWeight.bold), + ), + const SizedBox( + height: 20, + ), + TextField( + maxLines: 3, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + ), + labelText: 'Enter Your Billing Address'), + ), + const SizedBox( + height: 20, + ), + SizedBox( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + padding: EdgeInsets.symmetric(vertical: 15), + backgroundColor: Colors.orange, + ), + child: const Text( + 'Buy Now', + style: TextStyle(fontSize: 18, color: Colors.white), + ), + onPressed: () {}, + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/app/modules/products/views/products_view.dart b/lib/app/modules/products/views/products_view.dart index 5b190a6a..69fc9221 100644 --- a/lib/app/modules/products/views/products_view.dart +++ b/lib/app/modules/products/views/products_view.dart @@ -2,9 +2,11 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; - -import '../../../../models/role.dart'; -import '../../../routes/app_pages.dart'; +import 'package:get_flutter_fire/app/modules/cart/controllers/cart_controller.dart'; +import 'package:get_flutter_fire/app/modules/products/views/products_descriptions_view.dart'; +import 'package:get_flutter_fire/app/widgets/drop_down_button.dart'; +import 'package:get_flutter_fire/app/widgets/drop_down_checklist.dart'; +import 'package:get_flutter_fire/app/widgets/product_card.dart'; import '../controllers/products_controller.dart'; class ProductsView extends GetView { @@ -12,47 +14,97 @@ class ProductsView extends GetView { @override Widget build(BuildContext context) { - var arg = Get.rootDelegate.arguments(); - return Scaffold( - floatingActionButton: - (arg != null && Get.rootDelegate.arguments()["role"] == Role.seller) - ? FloatingActionButton.extended( - onPressed: controller.loadDemoProductsFromSomeWhere, - label: const Text('Add'), - ) - : null, - body: Column( - children: [ - const Hero( - tag: 'heroLogo', - child: FlutterLogo(), - ), - Expanded( - child: Obx( - () => RefreshIndicator( - onRefresh: () async { - controller.products.clear(); - controller.loadDemoProductsFromSomeWhere(); - }, + var cartController = Get.find(); + return GetBuilder(builder: (ctrl) { + return RefreshIndicator( + onRefresh: () async { + ctrl.fetchProducts(); + }, + child: Scaffold( + body: Column( + children: [ + SizedBox( + height: 50, child: ListView.builder( - itemCount: controller.products.length, + scrollDirection: Axis.horizontal, + itemCount: ctrl.categories.length, + itemBuilder: (context, index) { + return InkWell( + onTap: () { + ctrl.filterByCategory( + ctrl.categories[index].name ?? ''); + }, + child: Padding( + padding: EdgeInsets.all(6), + child: Chip( + label: Text(ctrl.categories[index].name ?? ''), + ), + ), + ); + })), + Row( + children: [ + Flexible( + child: DropDownBtn( + items: ['Rs: low to high', 'Rs: high to low'], + selectedItemsText: 'Sort', + onSelected: (selected) { + print(selected); + ctrl.sortByPrice( + ascending: + selected == 'Rs: low to high' ? true : false); + }), + ), + Flexible( + child: DropDownChecklist( + items: ['Nike', 'Zara', 'H&M', 'Samsung', 'Bata'], + onSelectionChanged: (selectedItems) { + ctrl.filterByBrand(selectedItems); + }, + )) + ], + ), + Expanded( + child: GridView.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: 0.6, + crossAxisSpacing: 8, + mainAxisSpacing: 8), + itemCount: ctrl.productsInUI.length, itemBuilder: (context, index) { - final item = controller.products[index]; - return ListTile( - onTap: () { - Get.rootDelegate.toNamed(Routes.PRODUCT_DETAILS( - item.id)); //we could use Get Parameters + return ProductCard( + name: ctrl.productsInUI[index].name ?? 'Name', + imageUrl: ctrl.productsInUI[index].image ?? 'url', + price: ctrl.productsInUI[index].price ?? 200, + offerTag: '20% off', + quantity: ctrl.productQuantities[ + ctrl.productsInUI[index]]!, // Show product quantity + onIncrease: () { + ctrl.incrementProductQuantity(ctrl.productsInUI[index]); + cartController.addToCart(ctrl.productsInUI[index], 1); + }, + onDecrease: () { + if (ctrl.productQuantities[ctrl.productsInUI[index]]! > + 0) { + ctrl.decrementProductQuantity( + ctrl.productsInUI[index]); + cartController + .removeFromCart(ctrl.productsInUI[index]); + } + }, + productTap: () { + Get.to( + ProductsDescriptionsView( + product: ctrl.productsInUI[index]), + ); }, - title: Text(item.name), - subtitle: Text(item.id), ); - }, - ), - ), - ), - ), - ], - ), - ); + }), + ) + ], + )), + ); + }); } } diff --git a/lib/app/modules/products_admin/bindings/products_admin_binding.dart b/lib/app/modules/products_admin/bindings/products_admin_binding.dart new file mode 100644 index 00000000..46eefcd8 --- /dev/null +++ b/lib/app/modules/products_admin/bindings/products_admin_binding.dart @@ -0,0 +1,9 @@ +import 'package:get/get.dart'; +import '../controllers/products_admin_controller.dart'; + +class ProductsAdminBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => ProductsAdminController()); + } +} diff --git a/lib/app/modules/products_admin/controllers/products_admin_controller.dart b/lib/app/modules/products_admin/controllers/products_admin_controller.dart new file mode 100644 index 00000000..040b0d43 --- /dev/null +++ b/lib/app/modules/products_admin/controllers/products_admin_controller.dart @@ -0,0 +1,86 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_flutter_fire/models/products_admin.dart'; + +class ProductsAdminController extends GetxController { + FirebaseFirestore firestore = FirebaseFirestore.instance; + late CollectionReference prodCollection; + TextEditingController productNameCtrl = TextEditingController(); + TextEditingController productDescriptionCtrl = TextEditingController(); + TextEditingController productImgCtrl = TextEditingController(); + TextEditingController productPriceCtrl = TextEditingController(); + String category = 'Category'; + String brand = 'Brand'; + bool offer = false; + + List products = []; + @override + Future onInit() async { + prodCollection = firestore.collection('products'); + await fetchProducts(); + super.onInit(); + } + + addProduct() { + try { + DocumentReference doc = prodCollection.doc(); + Product product = Product( + id: doc.id, + name: productNameCtrl.text, + category: category, + description: productDescriptionCtrl.text, + price: double.tryParse(productPriceCtrl.text), + brand: brand, + image: productImgCtrl.text, + offer: offer, + ); + final productJson = product.toJson(); + doc.set(productJson); + Get.snackbar('Success', 'Product Added Successfully', + colorText: Colors.green); + setDefaultValues(); + fetchProducts(); + } on Exception catch (e) { + Get.snackbar('Error', e.toString(), colorText: Colors.green); + print(e); + } + } + + setDefaultValues() { + productNameCtrl.clear(); + productDescriptionCtrl.clear(); + productPriceCtrl.clear(); + productImgCtrl.clear(); + category = 'Category'; + brand = 'Brand'; + offer = false; + update(); + } + + fetchProducts() async { + try { + QuerySnapshot productSnapshot = await prodCollection.get(); + final List retrievedProducts = productSnapshot.docs + .map((doc) => Product.fromJson(doc.data() as Map)) + .toList(); + products.clear(); + products.assignAll(retrievedProducts); + } on Exception catch (e) { + Get.snackbar('Error', e.toString(), colorText: Colors.red); + } finally { + update(); + } + } + + deleteProduct(String id) async { + try { + await prodCollection.doc(id).delete(); + fetchProducts(); + Get.snackbar('Success', 'Products Deleted Successfully', + colorText: Colors.green); + } on Exception catch (e) { + Get.snackbar('Error', e.toString(), colorText: Colors.red); + } + } +} diff --git a/lib/app/modules/products_admin/views/add_product_view.dart b/lib/app/modules/products_admin/views/add_product_view.dart new file mode 100644 index 00000000..6780506d --- /dev/null +++ b/lib/app/modules/products_admin/views/add_product_view.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_flutter_fire/app/modules/products_admin/controllers/products_admin_controller.dart'; +import 'package:get_flutter_fire/app/widgets/drop_down_button.dart'; + +class AddProductView extends StatelessWidget { + const AddProductView({super.key}); + + @override + Widget build(BuildContext context) { + return GetBuilder(builder: (ctrl) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: const Text( + 'Add New Product', + style: TextStyle( + fontSize: 30, + color: Colors.orange, + fontWeight: FontWeight.bold), + ), + ), + body: SingleChildScrollView( + child: Container( + margin: EdgeInsets.all(10), + width: double.maxFinite, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + TextField( + controller: ctrl.productNameCtrl, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10)), + label: const Text("Product Name"), + hintStyle: const TextStyle( + color: Color.fromARGB(255, 160, 160, 160)), + hintText: "Enter Your Product Name"), + ), + SizedBox(height: 10), + TextField( + controller: ctrl.productDescriptionCtrl, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10)), + label: const Text("Product Description"), + hintStyle: const TextStyle( + color: Color.fromARGB(255, 160, 160, 160)), + hintText: "Enter Your Product Description"), + maxLines: 4, + ), + SizedBox(height: 10), + TextField( + controller: ctrl.productImgCtrl, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10)), + label: const Text("Image URL"), + hintStyle: const TextStyle( + color: Color.fromARGB(255, 160, 160, 160)), + hintText: "Enter Your Product's Image"), + ), + SizedBox(height: 10), + TextField( + controller: ctrl.productPriceCtrl, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10)), + label: const Text("Product Price"), + hintStyle: const TextStyle( + color: Color.fromARGB(255, 160, 160, 160)), + hintText: "Enter Your Product's Price"), + ), + const SizedBox(height: 10), + Row( + children: [ + Flexible( + child: DropDownBtn( + items: const [ + 'Clothing', + 'Shoes', + 'Electronics', + 'Sports' + ], + selectedItemsText: ctrl.category, + onSelected: (selectedValue) { + ctrl.category = selectedValue ?? 'Category'; + ctrl.update(); + }, + )), + Flexible( + child: DropDownBtn( + items: const [ + 'Nike', + 'Zara', + 'H&M', + 'Samsung', + 'Bata' + ], + selectedItemsText: ctrl.brand, + onSelected: (selectedValue) { + ctrl.brand = selectedValue ?? 'Brand'; + ctrl.update(); + })), + ], + ), + Text("Offer Products"), + DropDownBtn( + items: ['true', 'false'], + selectedItemsText: ctrl.offer == true ? 'yes' : 'no', + onSelected: (selectedValue) { + ctrl.offer = + bool.tryParse(selectedValue ?? 'false') ?? false; + ctrl.update(); + }), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.orange, + foregroundColor: Colors.white), + onPressed: () { + ctrl.addProduct(); + }, + child: const Text("Add Product")) + ], + ), + ), + ), + ); + }); + } +} diff --git a/lib/app/modules/products_admin/views/products_admin_view.dart b/lib/app/modules/products_admin/views/products_admin_view.dart new file mode 100644 index 00000000..72d4e1a6 --- /dev/null +++ b/lib/app/modules/products_admin/views/products_admin_view.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_flutter_fire/app/modules/products_admin/views/add_product_view.dart'; +import '../controllers/products_admin_controller.dart'; + +class ProductsAdminView extends GetView { + const ProductsAdminView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return GetBuilder(builder: (ctrl) { + return Scaffold( + body: ListView.builder( + itemCount: ctrl.products.length, + itemBuilder: (context, index) { + return ListTile( + title: Text(ctrl.products[index].name ?? ''), + subtitle: Text((ctrl.products[index].price ?? '').toString()), + trailing: IconButton( + onPressed: () { + ctrl.deleteProduct(ctrl.products[index].id ?? ''); + }, + icon: Icon(Icons.delete)), + ); + }), + floatingActionButton: FloatingActionButton( + backgroundColor: Colors.orange, + onPressed: () { + Get.to(AddProductView()); + }, + child: Icon(Icons.add), + ), + ); + }); + } +} diff --git a/lib/app/modules/root/views/drawer.dart b/lib/app/modules/root/views/drawer.dart index 908d0223..7beddff6 100644 --- a/lib/app/modules/root/views/drawer.dart +++ b/lib/app/modules/root/views/drawer.dart @@ -38,12 +38,32 @@ class DrawerWidget extends StatelessWidget { height: 100, color: Colors.red, //adding content in the highlighted part of the drawer - child: Align( - alignment: Alignment.centerLeft, - child: Container( - margin: const EdgeInsets.only(left: 15), - child: const Text('User Name', //Profile Icon also - style: TextStyle(fontWeight: FontWeight.bold)))), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: CircleAvatar( + backgroundColor: Colors.white, + backgroundImage: AuthService.to.user != null && + AuthService.to.user!.photoURL != null + ? NetworkImage(AuthService.to.user!.photoURL!) + : null, + child: AuthService.to.user == null || + AuthService.to.user!.photoURL == null + ? Icon(Icons.person, color: Colors.grey[800]) + : null, + radius: 30, + ), + ), + Expanded( + child: Align( + alignment: Alignment.centerLeft, + child: Text('${AuthService.to.userName}', // Profile Icon also + style: TextStyle(fontWeight: FontWeight.bold)), + ), + ), + ], + ), ) ]; diff --git a/lib/app/modules/root/views/root_view.dart b/lib/app/modules/root/views/root_view.dart index 2bbf228c..37d2cef5 100644 --- a/lib/app/modules/root/views/root_view.dart +++ b/lib/app/modules/root/views/root_view.dart @@ -22,7 +22,9 @@ class RootView extends GetView { appBar: AppBar( title: Text(title ?? ''), centerTitle: true, - leading: GetPlatform.isIOS // Since Web and Android have back button + leading: (GetPlatform.isIOS || + GetPlatform + .isAndroid) // Since Web and Android have back button && current.locationString.contains(RegExp(r'(\/[^\/]*){3,}')) ? BackButton( @@ -30,9 +32,8 @@ class RootView extends GetView { Get.rootDelegate.popRoute(), //Navigator.pop(context), ) : IconButton( - icon: ImageIcon( - const AssetImage("icons/logo.png"), - color: Colors.grey.shade800, + icon: Image( + image: new AssetImage("assets/icons/sharekhan_logo.png"), ), onPressed: () => AuthService.to.isLoggedInValue ? controller.openDrawer() diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index 7269755d..62457c0a 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:get_flutter_fire/app/modules/products_admin/bindings/products_admin_binding.dart'; +import 'package:get_flutter_fire/app/modules/products_admin/views/products_admin_view.dart'; import '../../models/access_level.dart'; import '../../models/role.dart'; @@ -72,6 +74,10 @@ class AppPages { page: () => const SettingsView(), binding: SettingsBinding(), ), + Screen.PRODUCTS_ADMIN.getPage( + page: () => const ProductsAdminView(), + binding: ProductsAdminBinding(), + ), Screen.HOME.getPage( page: () => const HomeView(), bindings: [ @@ -145,7 +151,7 @@ class AppPages { binding: TaskDetailsBinding(), ), ], - ), + ) ], ) ], diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index f3129d21..29fb888d 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -17,7 +17,6 @@ abstract class Routes { // static const TASKS = _Paths.HOME + _Paths.TASKS; // static const USERS = _Paths.HOME + _Paths.USERS; // static const MY_PRODUCTS = _Paths.HOME + _Paths.MY_PRODUCTS; - static String PRODUCT_DETAILS(String productId) => '${Screen.PRODUCTS.route}/$productId'; static String CART_DETAILS(String productId) => diff --git a/lib/app/widgets/drop_down_button.dart b/lib/app/widgets/drop_down_button.dart new file mode 100644 index 00000000..b3d608ab --- /dev/null +++ b/lib/app/widgets/drop_down_button.dart @@ -0,0 +1,58 @@ +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:flutter/material.dart'; + +String? selectedValue; + +class DropDownBtn extends StatelessWidget { + final List items; + final String selectedItemsText; + final Function(String?) onSelected; + const DropDownBtn( + {super.key, + required this.items, + required this.selectedItemsText, + required this.onSelected}); + + @override + Widget build(BuildContext context) { + return Card( + child: Center( + child: DropdownButtonHideUnderline( + child: DropdownButton2( + isExpanded: true, + hint: Text( + selectedItemsText, + style: TextStyle( + fontSize: 14, + color: Theme.of(context).hintColor, + ), + ), + items: items + .map((String item) => DropdownMenuItem( + value: item, + child: Text( + item, + style: const TextStyle( + fontSize: 14, + ), + ), + )) + .toList(), + value: selectedValue, + onChanged: (String? value) { + onSelected(value); + }, + buttonStyleData: const ButtonStyleData( + padding: EdgeInsets.symmetric(horizontal: 16), + height: 40, + width: 140, + ), + menuItemStyleData: const MenuItemStyleData( + height: 40, + ), + ), + ), + ), + ); + } +} diff --git a/lib/app/widgets/drop_down_checklist.dart b/lib/app/widgets/drop_down_checklist.dart new file mode 100644 index 00000000..d6b4ef5c --- /dev/null +++ b/lib/app/widgets/drop_down_checklist.dart @@ -0,0 +1,102 @@ +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:flutter/material.dart'; + +List selectedItems = []; + +class DropDownChecklist extends StatelessWidget { + final List items; + final Function(List) onSelectionChanged; + const DropDownChecklist( + {super.key, required this.items, required this.onSelectionChanged}); + + @override + Widget build(BuildContext context) { + return Card( + child: Center( + child: DropdownButtonHideUnderline( + child: DropdownButton2( + isExpanded: true, + hint: Text( + 'Brand', + style: TextStyle( + fontSize: 14, + color: Theme.of(context).hintColor, + ), + ), + items: items.map((item) { + return DropdownMenuItem( + value: item, + //disable default onTap to avoid closing menu when selecting an item + enabled: false, + child: StatefulBuilder( + builder: (context, menuSetState) { + final isSelected = selectedItems.contains(item); + return InkWell( + onTap: () { + isSelected + ? selectedItems.remove(item) + : selectedItems.add(item); + onSelectionChanged(selectedItems); + menuSetState(() {}); + }, + child: Container( + height: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + children: [ + if (isSelected) + const Icon(Icons.check_box_outlined) + else + const Icon(Icons.check_box_outline_blank), + const SizedBox(width: 16), + Expanded( + child: Text( + item, + style: const TextStyle( + fontSize: 14, + ), + ), + ), + ], + ), + ), + ); + }, + ), + ); + }).toList(), + //Use last selected item as the current value so if we've limited menu height, it scroll to last item. + value: selectedItems.isEmpty ? null : selectedItems.last, + onChanged: (value) {}, + selectedItemBuilder: (context) { + return items.map( + (item) { + return Container( + alignment: AlignmentDirectional.center, + child: Text( + selectedItems.join(', '), + style: const TextStyle( + fontSize: 14, + overflow: TextOverflow.ellipsis, + ), + maxLines: 1, + ), + ); + }, + ).toList(); + }, + buttonStyleData: const ButtonStyleData( + padding: EdgeInsets.only(left: 16, right: 8), + height: 40, + width: 140, + ), + menuItemStyleData: const MenuItemStyleData( + height: 40, + padding: EdgeInsets.zero, + ), + ), + ), + ), + ); + } +} diff --git a/lib/app/widgets/image_picker_button.dart b/lib/app/widgets/image_picker_button.dart index d6e87ff4..72f5a509 100644 --- a/lib/app/widgets/image_picker_button.dart +++ b/lib/app/widgets/image_picker_button.dart @@ -74,8 +74,11 @@ class ImagePickerButton extends MenuSheetButton { Iterable get values => ImageSources.values; @override - void callbackFunc(act) { - if (callback != null) callback!(act); + void callbackFunc(dynamic act) { + if (callback != null) { + String? path = act as String?; + callback!(path!); + } } @override diff --git a/lib/app/widgets/product_card.dart b/lib/app/widgets/product_card.dart new file mode 100644 index 00000000..6995d331 --- /dev/null +++ b/lib/app/widgets/product_card.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; + +class ProductCard extends StatelessWidget { + const ProductCard({ + super.key, + required this.name, + required this.imageUrl, + required this.offerTag, + required this.price, + required this.quantity, + required this.onIncrease, + required this.onDecrease, + required this.productTap, + }); + + final String name; + final String imageUrl; + final double price; + final String offerTag; + final int quantity; + final Function onIncrease; + final Function onDecrease; + final Function productTap; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () { + productTap(); + }, + child: Card( + elevation: 2, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.network( + imageUrl, + fit: BoxFit.cover, + width: double.maxFinite, + height: 170, + // alignment: Alignment.topCenter, + ), + ), + const SizedBox(height: 8), + Text( + name, + style: const TextStyle(fontSize: 16), + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 8), + Text( + 'Rs. $price', + style: const TextStyle(fontSize: 16), + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 4), + Container( + padding: const EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + color: Colors.green, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + offerTag, + style: const TextStyle(color: Colors.white), + ), + ), + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + onPressed: () => onDecrease(), + icon: const Icon(Icons.remove), + ), + Text(quantity.toString()), + IconButton( + onPressed: () => onIncrease(), + icon: const Icon(Icons.add), + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index 30c258f2..33d75b7e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:get_flutter_fire/app/modules/cart/controllers/cart_controller.dart'; import 'package:get_storage/get_storage.dart'; import 'app/routes/app_pages.dart'; @@ -23,6 +24,7 @@ void main() async { title: 'Application', initialBinding: BindingsBuilder( () { + Get.put(CartController(), permanent: true); Get.put(AuthService()); }, ), diff --git a/lib/models/product_category.dart b/lib/models/product_category.dart new file mode 100644 index 00000000..95fc3d80 --- /dev/null +++ b/lib/models/product_category.dart @@ -0,0 +1,20 @@ +import 'package:json_annotation/json_annotation.dart'; +part 'product_category.g.dart'; + +@JsonSerializable() +class ProductCategory { + @JsonKey(name: "id") + String? id; + + @JsonKey(name: "name") + String? name; + + ProductCategory({ + this.id, + this.name, + }); + + factory ProductCategory.fromJson(Map json) => + _$ProductCategoryFromJson(json); + Map toJson() => _$ProductCategoryToJson(this); +} diff --git a/lib/models/product_category.g.dart b/lib/models/product_category.g.dart new file mode 100644 index 00000000..ed3fa193 --- /dev/null +++ b/lib/models/product_category.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'product_category.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ProductCategory _$ProductCategoryFromJson(Map json) => + ProductCategory( + id: json['id'] as String?, + name: json['name'] as String?, + ); + +Map _$ProductCategoryToJson(ProductCategory instance) => + { + 'id': instance.id, + 'name': instance.name, + }; diff --git a/lib/models/products_admin.dart b/lib/models/products_admin.dart new file mode 100644 index 00000000..54a64e6b --- /dev/null +++ b/lib/models/products_admin.dart @@ -0,0 +1,44 @@ +import 'package:json_annotation/json_annotation.dart'; +part 'products_admin.g.dart'; + +@JsonSerializable() +class Product { + @JsonKey(name: "id") + String? id; + + @JsonKey(name: "name") + String? name; + + @JsonKey(name: "description") + String? description; + + @JsonKey(name: "category") + String? category; + + @JsonKey(name: "image") + String? image; + + @JsonKey(name: "price") + double? price; + + @JsonKey(name: "brand") + String? brand; + + @JsonKey(name: "offer") + bool? offer; + + Product({ + this.id, + this.name, + this.description, + this.category, + this.image, + this.offer, + this.price, + this.brand, + }); + + factory Product.fromJson(Map json) => + _$ProductFromJson(json); + Map toJson() => _$ProductToJson(this); +} diff --git a/lib/models/products_admin.g.dart b/lib/models/products_admin.g.dart new file mode 100644 index 00000000..58d707f2 --- /dev/null +++ b/lib/models/products_admin.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'products_admin.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Product _$ProductFromJson(Map json) => Product( + id: json['id'] as String?, + name: json['name'] as String?, + description: json['description'] as String?, + category: json['category'] as String?, + image: json['image'] as String?, + offer: json['offer'] as bool?, + price: (json['price'] as num?)?.toDouble(), + brand: json['brand'] as String?, + ); + +Map _$ProductToJson(Product instance) => { + 'id': instance.id, + 'name': instance.name, + 'description': instance.description, + 'category': instance.category, + 'image': instance.image, + 'price': instance.price, + 'brand': instance.brand, + 'offer': instance.offer, + }; diff --git a/lib/models/screens.dart b/lib/models/screens.dart index 24dee39f..74f24de5 100644 --- a/lib/models/screens.dart +++ b/lib/models/screens.dart @@ -101,6 +101,11 @@ enum Screen implements ActionEnum { label: "Logout", accessor_: AccessedVia.bottomSheet, accessLevel: AccessLevel.authenticated), + PRODUCTS_ADMIN('/products-admin', + icon: Icons.admin_panel_settings, + label: "Products List", + accessor_: AccessedVia.drawer, + accessLevel: AccessLevel.authenticated), ; const Screen(this.path, diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 8bf72aaa..22ab9415 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid_print - import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_ui_auth/firebase_ui_auth.dart' as fbui; import 'package:firebase_ui_localizations/firebase_ui_localizations.dart'; @@ -24,7 +22,7 @@ class AuthService extends GetxService { Role get maxRole => _userRole.value; @override - onInit() { + void onInit() { super.onInit(); if (useEmulator) _auth.useAuthEmulator(emulatorHost, 9099); _firebaseUser.bindStream(_auth.authStateChanges()); @@ -52,53 +50,30 @@ class AuthService extends GetxService { ? (user!.displayName ?? user!.email) : 'Guest'; - void login() { - // this is not needed as we are using Firebase UI for the login part - } - void sendVerificationMail({EmailAuthCredential? emailAuth}) async { if (sendMailFromClient) { if (_auth.currentUser != null) { await _auth.currentUser?.sendEmailVerification(); } else if (emailAuth != null) { - // Approach 1: sending email auth link requires deep linking which is - // a TODO as the current Flutter methods are deprecated - // sendSingInLink(emailAuth); - - // Approach 2: This is a hack. - // We are using createUser to send the verification link from the server side by adding suffix .verify in the email - // if the user already exists and the password is also same and sign in occurs via custom token on server side try { await _auth.createUserWithEmailAndPassword( email: "${credential.value!.email}.verify", password: credential.value!.password!); } on FirebaseAuthException catch (e) { - int i = e.message!.indexOf("message") + 10; - int j = e.message!.indexOf('"', i); Get.snackbar( - e.message!.substring(i, j), - 'Please verify your email by clicking the link on the Email sent', + 'Error', + 'Please verify your email by clicking the link sent to ${e.message}', ); } } } } - void sendSingInLink(EmailAuthCredential emailAuth) { + void sendSignInLink(EmailAuthCredential emailAuth) { var acs = ActionCodeSettings( - // URL you want to redirect back to. The domain (www.example.com) for this - // URL must be whitelisted in the Firebase Console. url: '$baseUrl:5001/flutterfast-92c25/us-central1/handleEmailLinkVerification', - // // This must be true if deep linking. - // // If deeplinking. See [https://firebase.google.com/docs/dynamic-links/flutter/receive] handleCodeInApp: true, - // iOSBundleId: '$bundleID.ios', - // androidPackageName: '$bundleID.android', - // // installIfNotAvailable - // androidInstallApp: true, - // // minimumVersion - // androidMinimumVersion: '12' ); _auth .sendSignInLinkToEmail(email: emailAuth.email, actionCodeSettings: acs) @@ -109,11 +84,9 @@ class AuthService extends GetxService { void register() { registered.value = true; - // logout(); // Uncomment if we need to enforce relogin final thenTo = Get.rootDelegate.currentConfiguration!.currentPage!.parameters?['then']; - Get.rootDelegate - .offAndToNamed(thenTo ?? Screen.PROFILE.route); //Profile has the forms + Get.rootDelegate.offAndToNamed(thenTo ?? Screen.PROFILE.route); } void logout() { @@ -141,12 +114,10 @@ class AuthService extends GetxService { 'Signed in with temporary account.', ); } on FirebaseAuthException catch (e) { - switch (e.code) { - case "operation-not-allowed": - print("Anonymous auth hasn't been enabled for this project."); - break; - default: - print("Unknown error."); + if (e.code == "operation-not-allowed") { + print("Anonymous auth hasn't been enabled for this project."); + } else { + print("Unknown error."); } Get.back(result: false); } @@ -158,15 +129,11 @@ class AuthService extends GetxService { (BuildContext context, FirebaseAuthException e) { final defaultLabels = FirebaseUILocalizations.labelsOf(context); - // for verification error, also set a boolean flag to trigger button visibility to resend verification mail String? verification; if (e.code == "internal-error" && e.message!.contains('"status":"UNAUTHENTICATED"')) { - // Note that (possibly in Emulator only) the e.email is always coming as null - // String? email = e.email ?? parseEmail(e.message!); callback(true, credential.value); - verification = - "Please verify email id by clicking the link on the email sent"; + verification = "Please verify your email by clicking the link sent."; } else { callback(false, credential.value); } @@ -194,7 +161,7 @@ class MyCredential extends AuthCredential { } } -parseEmail(String message) { +String parseEmail(String message) { int i = message.indexOf('"message":') + 13; int j = message.indexOf('"', i); return message.substring(i, j - 1); diff --git a/pubspec.lock b/pubspec.lock index 877fc75e..8cc6581b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + url: "https://pub.dev" + source: hosted + version: "72.0.0" _flutterfire_internals: dependency: transitive description: @@ -9,6 +17,19 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.35" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + url: "https://pub.dev" + source: hosted + version: "6.7.0" args: dependency: transitive description: @@ -33,6 +54,70 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04 + url: "https://pub.dev" + source: hosted + version: "2.4.12" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 + url: "https://pub.dev" + source: hosted + version: "7.3.2" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" characters: dependency: transitive description: @@ -41,6 +126,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" clock: dependency: transitive description: @@ -49,6 +142,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + cloud_firestore: + dependency: "direct main" + description: + name: cloud_firestore + sha256: a0f161b92610e078b4962d7e6ebeb66dc9cce0ada3514aeee442f68165d78185 + url: "https://pub.dev" + source: hosted + version: "4.17.5" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + sha256: "6a55b319f8d33c307396b9104512e8130a61904528ab7bd8b5402678fca54b81" + url: "https://pub.dev" + source: hosted + version: "6.2.5" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + sha256: "89dfa1304d3da48b3039abbb2865e3d30896ef858e569a16804a99f4362283a9" + url: "https://pub.dev" + source: hosted + version: "3.12.5" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" collection: dependency: transitive description: @@ -57,22 +182,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" cross_file: dependency: transitive description: name: cross_file - sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted - version: "0.3.4+1" + version: "0.3.4+2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" cupertino_icons: dependency: "direct main" description: @@ -81,6 +214,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" desktop_webview_auth: dependency: transitive description: @@ -89,6 +230,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.15" + dropdown_button2: + dependency: "direct main" + description: + name: dropdown_button2 + sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1 + url: "https://pub.dev" + source: hosted + version: "2.3.9" email_validator: dependency: transitive description: @@ -109,18 +258,26 @@ packages: dependency: transitive description: name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" file_picker: dependency: "direct main" description: name: file_picker - sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a" + sha256: "825aec673606875c33cd8d3c4083f1a3c3999015a84178b317b7ef396b7384f3" url: "https://pub.dev" source: hosted - version: "8.0.3" + version: "8.0.7" file_selector_linux: dependency: transitive description: @@ -149,10 +306,10 @@ packages: dependency: transitive description: name: file_selector_windows - sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 + sha256: "2ad726953f6e8affbc4df8dc78b77c3b4a060967a291e528ef72ae846c60fb69" url: "https://pub.dev" source: hosted - version: "0.9.3+1" + version: "0.9.3+2" firebase_analytics: dependency: "direct main" description: @@ -181,26 +338,26 @@ packages: dependency: "direct main" description: name: firebase_auth - sha256: f0a75f61992d036e4c46ad0e9febd364d98aa2c092690a5475cb1421a8243cfe + sha256: cfc2d970829202eca09e2896f0a5aa7c87302817ecc0bdfa954f026046bf10ba url: "https://pub.dev" source: hosted - version: "4.19.5" + version: "4.20.0" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface - sha256: feb77258404309ffc7761c78e1c0ad2ed5e4fdc378e035619e2cc13be4397b62 + sha256: a0270e1db3b2098a14cb2a2342b3cd2e7e458e0c391b1f64f6f78b14296ec093 url: "https://pub.dev" source: hosted - version: "7.2.6" + version: "7.3.0" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - sha256: "6d527f357da2bf93a67a42b423aa92943104a0c290d1d72ad9a42c779d501cd2" + sha256: "64e067e763c6378b7e774e872f0f59f6812885e43020e25cde08f42e9459837b" url: "https://pub.dev" source: hosted - version: "5.11.5" + version: "5.12.0" firebase_core: dependency: "direct main" description: @@ -213,34 +370,34 @@ packages: dependency: transitive description: name: firebase_core_platform_interface - sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63 + sha256: "3c3a1e92d6f4916c32deea79c4a7587aa0e9dbbe5889c7a16afcf005a485ee02" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.2.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "43d9e951ac52b87ae9cc38ecdcca1e8fa7b52a1dd26a96085ba41ce5108db8e9" + sha256: e8d1e22de72cb21cdcfc5eed7acddab3e99cd83f3b317f54f7a96c32f25fd11e url: "https://pub.dev" source: hosted - version: "2.17.0" + version: "2.17.4" firebase_dynamic_links: dependency: transitive description: name: firebase_dynamic_links - sha256: f704859abc17d99e74b47eaf47455b45a88ab7e2973f03e6130ff666b45fe11f + sha256: "47b8c8a8546d8a7f9000edb90848549f20b137d814ee7e0407b3d43b8445e282" url: "https://pub.dev" source: hosted - version: "5.5.5" + version: "5.5.7" firebase_dynamic_links_platform_interface: dependency: transitive description: name: firebase_dynamic_links_platform_interface - sha256: f86992605b50e2f0ce6c24993430affc98021da8d8a74d5596b7a2c84196c110 + sha256: "72e7810635f908ce060c5803c7acb29116c5b6befc73e90446c52722bc9506a2" url: "https://pub.dev" source: hosted - version: "0.2.6+33" + version: "0.2.6+35" firebase_remote_config: dependency: "direct main" description: @@ -269,26 +426,26 @@ packages: dependency: "direct main" description: name: firebase_storage - sha256: da76ca9c11d795c4bae1bd13b31d54bb9eb9ccbee7eb5f6b86b8294370e9d488 + sha256: "2ae478ceec9f458c1bcbf0ee3e0100e4e909708979e83f16d5d9fba35a5b42c1" url: "https://pub.dev" source: hosted - version: "11.7.5" + version: "11.7.7" firebase_storage_platform_interface: dependency: transitive description: name: firebase_storage_platform_interface - sha256: be17bfa9110a6429b40dd3760c755034079fd734aa1dd2476d5638ab780cc508 + sha256: "4e18662e6a66e2e0e181c06f94707de06d5097d70cfe2b5141bf64660c5b5da9" url: "https://pub.dev" source: hosted - version: "5.1.20" + version: "5.1.22" firebase_storage_web: dependency: transitive description: name: firebase_storage_web - sha256: "5219c20c0768a8e2ffedf0a116b7bc80ab32fcc6e2cbd50cbde14f8c4575c3f4" + sha256: "3a44aacd38a372efb159f6fe36bb4a7d79823949383816457fd43d3d47602a53" url: "https://pub.dev" source: hosted - version: "3.9.5" + version: "3.9.7" firebase_ui_auth: dependency: "direct main" description: @@ -329,6 +486,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter: dependency: "direct main" description: flutter @@ -351,10 +516,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" + sha256: "9d98bd47ef9d34e803d438f17fd32b116d31009f534a6fa5ce3a1167f189a6de" url: "https://pub.dev" source: hosted - version: "2.0.19" + version: "2.0.21" flutter_svg: dependency: transitive description: @@ -373,6 +538,14 @@ packages: description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" get: dependency: "direct main" description: @@ -389,6 +562,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" google_fonts: dependency: "direct main" description: @@ -401,10 +582,10 @@ packages: dependency: transitive description: name: google_identity_services_web - sha256: "9482364c9f8b7bd36902572ebc3a7c2b5c8ee57a9c93e6eb5099c1a9ec5265d8" + sha256: "5be191523702ba8d7a01ca97c17fca096822ccf246b0a9f11923a6ded06199b6" url: "https://pub.dev" source: hosted - version: "0.3.1+1" + version: "0.3.1+4" google_sign_in: dependency: "direct main" description: @@ -417,10 +598,10 @@ packages: dependency: transitive description: name: google_sign_in_android - sha256: "7647893c65e6720973f0e579051c8f84b877b486614d9f70a404259c41a4632e" + sha256: "5a47ebec9af97daf0822e800e4f101c3340b5ebc3f6898cf860c1a71b53cf077" url: "https://pub.dev" source: hosted - version: "6.1.23" + version: "6.1.28" google_sign_in_ios: dependency: transitive description: @@ -441,18 +622,34 @@ packages: dependency: transitive description: name: google_sign_in_web - sha256: fc0f14ed45ea616a6cfb4d1c7534c2221b7092cc4f29a709f0c3053cc3e821bd + sha256: "042805a21127a85b0dc46bba98a37926f17d2439720e8a459d27045d8ef68055" + url: "https://pub.dev" + source: hosted + version: "0.12.4+2" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "0.12.4" + version: "2.3.2" http: dependency: transitive description: name: http - sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" http_parser: dependency: transitive description: @@ -465,34 +662,34 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "33974eca2e87e8b4e3727f1b94fa3abcb25afe80b6bc2c4d449a0e150aedf720" + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "79455f6cff4cbef583b2b524bbf0d4ec424e5959f4d464e36ef5323715b98370" + sha256: c0a6763d50b354793d0192afd0a12560b823147d3ded7c6b77daf658fa05cc85 url: "https://pub.dev" source: hosted - version: "0.8.12" + version: "0.8.12+13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3" + sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.5" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: cb0db0ec0d3e2cd49674f2e6053be25ccdb959832607c1cbd215dd6cf10fb0dd + sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447" url: "https://pub.dev" source: hosted - version: "0.8.11" + version: "0.8.12" image_picker_linux: dependency: transitive description: @@ -533,22 +730,54 @@ packages: url: "https://pub.dev" source: hosted version: "0.19.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b + url: "https://pub.dev" + source: hosted + version: "6.8.0" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -565,6 +794,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" matcher: dependency: transitive description: @@ -577,18 +822,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" mime: dependency: transitive description: @@ -597,6 +842,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" path: dependency: "direct main" description: @@ -617,18 +870,18 @@ packages: dependency: transitive description: name: path_provider - sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.10" path_provider_foundation: dependency: transitive description: @@ -657,10 +910,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: @@ -673,10 +926,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -685,11 +938,67 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" + url: "https://pub.dev" + source: hosted + version: "2.0.0" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" source_span: dependency: transitive description: @@ -714,6 +1023,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: @@ -734,10 +1051,18 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "1.0.1" typed_data: dependency: transitive description: @@ -782,10 +1107,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "1.1.0" web: dependency: transitive description: @@ -794,14 +1127,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" + url: "https://pub.dev" + source: hosted + version: "3.0.1" win32: dependency: transitive description: name: win32 - sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" + sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "5.5.4" xdg_directories: dependency: transitive description: @@ -818,6 +1167,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: - dart: ">=3.3.4 <4.0.0" - flutter: ">=3.19.2" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 2909a374..41d8b7be 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,42 +2,46 @@ name: get_flutter_fire version: 1.0.0+1 publish_to: none description: Boilerplate for Flutter with GetX, showing sample utilization of Firebase capabilities -environment: - sdk: '>=3.3.4 <4.0.0' +environment: + sdk: ">=3.3.4 <4.0.0" -dependencies: - cupertino_icons: ^1.0.6 - get: 4.6.6 - flutter: - sdk: flutter - firebase_core: ^2.31.0 - firebase_ui_auth: ^1.14.0 - firebase_auth: ^4.19.5 - google_sign_in: ^6.2.1 - firebase_ui_oauth_google: ^1.3.2 - google_fonts: ^6.2.1 - firebase_storage: ^11.7.5 - image_picker: ^1.1.1 - file_picker: ^8.0.3 - path: ^1.9.0 - get_storage: ^2.1.1 - firebase_ui_localizations: ^1.12.0 - firebase_remote_config: ^4.4.7 - firebase_analytics: ^10.10.7 - -dev_dependencies: - flutter_lints: 3.0.2 - flutter_test: - sdk: flutter - -flutter: - fonts: - - family: SocialIcons - fonts: - - asset: packages/firebase_ui_auth/fonts/SocialIcons.ttf - assets: - - assets/images/flutterfire_300x.png - - assets/images/dash.png - - assets/icons/logo.png - uses-material-design: true +dependencies: + cupertino_icons: ^1.0.6 + get: 4.6.6 + flutter: + sdk: flutter + firebase_core: ^2.31.0 + firebase_ui_auth: ^1.14.0 + firebase_auth: ^4.19.5 + google_sign_in: ^6.2.1 + firebase_ui_oauth_google: ^1.3.2 + cloud_firestore: ^4.17.5 + google_fonts: ^6.2.1 + firebase_storage: ^11.7.5 + image_picker: ^1.1.1 + file_picker: ^8.0.3 + json_annotation: ^4.9.0 + path: ^1.9.0 + get_storage: ^2.1.1 + firebase_ui_localizations: ^1.12.0 + firebase_remote_config: ^4.4.7 + firebase_analytics: ^10.10.7 + dropdown_button2: ^2.3.9 +dev_dependencies: + json_serializable: ^6.8.0 + build_runner: ^2.4.12 + flutter_lints: 3.0.2 + flutter_test: + sdk: flutter +flutter: + fonts: + - family: SocialIcons + fonts: + - asset: packages/firebase_ui_auth/fonts/SocialIcons.ttf + assets: + - assets/images/flutterfire_300x.png + - assets/images/dash.png + - assets/icons/logo.png + - assets/icons/sharekhan_logo.png + uses-material-design: true