diff --git a/README.md b/README.md index 0a1ef42..aa176b1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A new Flutter project. ## Getting Started -### How to start the Firebase emulator +### How to start the Firebase emulator environment The application requires the Firebase to run. The debug build connects to the local emulator by default while the production build connects to the production Firebase. @@ -15,20 +15,28 @@ The application requires the Firebase to run. The debug build connects to the lo firebase emulators:start ``` -**To disable the emulator in the dev environment, disable the line of codes in `lib/main.dart` or build in production mode** +### Connect to a Android Device + +1. Make sure firebase emulators is running. + +2. Connect your device via USB and enable developer mode. + +3. Head over to your Android SDK platform-tools folder `android_sdk/platform-tools/` + +4. Connect your Android device with Firebase Emulator Servers: + + Firestore + ```bash + adb reverse tcp:8080 tcp:8080 + ``` + Storage + ```bash + adb reverse tcp:9199 tcp:9199 + ``` +5. Run the app from your IDE. -```dart - if (kDebugMode) { - try { - FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080); - } catch (e) { - // ignore: avoid_print - print(e); - } - } -``` -### How to initialize Firebase +### How to initialize Firebase server environment Reference: @@ -43,14 +51,48 @@ Reference: firebase login ``` -4. Install FlutterFire +4. Configure with your firebase project + ```bash + firebase init + ``` + +5. Install FlutterFire ```bash dart pub global activate flutterfire_cli ``` -5. Configure it using this command in the Project +6. Configure it using this command in the Project ```bash flutterfire configure ``` + +7. Disable the firebase emulator dev environment + +**disable the following lines of codes in `lib/main.dart` or build in production mode** +```dart +if (kDebugMode) { + try { + const host = 'localhost'; + const bool autoMapping = false; + FirebaseStorage.instance.useStorageEmulator( + host, + 9199, + automaticHostMapping: autoMapping, + ); + FirebaseFirestore.instance.useFirestoreEmulator( + host, + 8080, + automaticHostMapping: autoMapping, + ); + } catch (e) { + // ignore: avoid_print + print(e); + } + } +``` + +## Support + +If you have trouble running this project, open a [issue](https://github.com/fluttermtl/instreal/issues/new) and we'll be happy to lend you a hand. You could also ask questions to our discord group. \ No newline at end of file diff --git a/firebase.json b/firebase.json index 9df8d43..c389860 100644 --- a/firebase.json +++ b/firebase.json @@ -6,10 +6,16 @@ "ui": { "enabled": true }, - "singleProjectMode": true + "singleProjectMode": true, + "storage": { + "port": 9199 + } }, "firestore": { "rules": "firestore.rules", "indexes": "firestore.indexes.json" + }, + "storage": { + "rules": "storage.rules" } } diff --git a/firestore.rules b/firestore.rules index 71bd24b..a3eeb31 100644 --- a/firestore.rules +++ b/firestore.rules @@ -13,7 +13,7 @@ service cloud.firestore { // all client requests to your Firestore database will be denied until you Update // your rules match /{document=**} { - allow read, write: if request.time < timestamp.date(2023, 7, 26); + allow read, write: if request.time < timestamp.date(2024, 7, 26); } } } \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 1dc345b..da4d77f 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,5 +1,11 @@ { "@@locale": "en", "whatsUpIn": "What's up in", - "montreal": "Montréal" + "montreal": "Montreal", + "add":"Add", + "title":"title", + "upload":"Upload", + "selectPicture":"Select Picture", + "or":"OR", + "takePicture": "Take Picture" } diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index f15cabe..8b7fa23 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,5 +1,11 @@ { "@@locale": "fr", "whatsUpIn": "Quoi de neuf à", - "montreal": "Montréal" + "montreal": "Montréal", + "add": "Ajouter", + "title":"titre", + "upload":"Téléverser", + "selectPicture":"Choisir une Image", + "or":"OU", + "takePicture":"Prendre une Photo" } diff --git a/lib/main.dart b/lib/main.dart index d4540ff..58dac6c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -16,11 +17,17 @@ void main() async { if (kDebugMode) { try { + const host = 'localhost'; + const bool autoMapping = false; + FirebaseStorage.instance.useStorageEmulator( + host, + 9199, + automaticHostMapping: autoMapping, + ); FirebaseFirestore.instance.useFirestoreEmulator( - defaultTargetPlatform == TargetPlatform.android - ? "10.0.2.2" - : "localhost", + host, 8080, + automaticHostMapping: autoMapping, ); } catch (e) { // ignore: avoid_print diff --git a/lib/presentation/components/src/add_post_modal_sheet.dart b/lib/presentation/components/src/add_post_modal_sheet.dart new file mode 100644 index 0000000..883216d --- /dev/null +++ b/lib/presentation/components/src/add_post_modal_sheet.dart @@ -0,0 +1,201 @@ +import 'dart:io'; + +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:instreal/features/posts/post_entity.dart'; +import 'package:instreal/l10n/index.dart'; + + +class AddPostModalPage extends StatefulWidget { + final Reference storageRef; + const AddPostModalPage({required this.storageRef, super.key}); + + @override + State createState() => _AddPostModalPageState(); +} + +class _AddPostModalPageState extends State { + XFile? image; + final ImagePicker picker = ImagePicker(); + final TextEditingController textEditName = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Row( + children: [ + Text(InstrealLocalizations.of(context)!.add), + const Spacer(), + const Align( + alignment: Alignment.centerRight, child: CloseButton()), + ], + ), + const SizedBox(height: 8), + if (image != null) + ImageView( + imagePath: image!.path, + onPressedRemoveImage: () { + image = null; + setState(() {/*Remove Image*/}); + }, + ) + else + ImagePickerView( + onPressedCamera: () async { + image = await picker.pickImage(source: ImageSource.camera); + setState(() {/*Update Image*/}); + }, + onPressedGallery: () async { + image = await picker.pickImage(source: ImageSource.gallery); + setState(() {/*Update Image*/}); + }, + ), + TextField( + decoration: InputDecoration( + label: Text(InstrealLocalizations.of(context)!.title), + ), + controller: textEditName, + ), + const SizedBox(height: 16), + Row( + children: [ + OutlinedButton( + onPressed: () async { + final storage = + widget.storageRef.child('images/instreal.jpg'); + + late String fileUrl; + //TODO may need a proper implementation + + try { + await storage.putFile(File(image!.path)); + fileUrl = await storage.getDownloadURL(); + } on FirebaseException catch (e) { + debugPrint(e.message); + } + + if (context.mounted) { + Navigator.pop( + context, + Post( + id: '', + title: textEditName.text, + author: 'author', // get name from firebase auth V3 + imageUrl: fileUrl, + ), + ); + } + }, + child: Text(InstrealLocalizations.of(context)!.upload)), + //add loading indicator when uploading + ], + ) + ], + ), + ); + } +} + +class ImagePickerView extends StatelessWidget { + final double? iconSize = 96; + final VoidCallback onPressedCamera; + final VoidCallback onPressedGallery; + + const ImagePickerView({ + required this.onPressedCamera, + required this.onPressedGallery, + super.key, + }); + + @override + Widget build(BuildContext context) { + return AspectRatio( + aspectRatio: 4 / 3, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16.0), + border: Border.all( + color: Colors.grey, + style: BorderStyle.solid, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton.outlined( + padding: const EdgeInsets.all(16), + onPressed: onPressedGallery, + icon: Icon( + Icons.photo, + size: iconSize, + ), + ), + Text(InstrealLocalizations.of(context)!.selectPicture) + ], + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Text(InstrealLocalizations.of(context)!.or)), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton.outlined( + padding: const EdgeInsets.all(16), + onPressed: onPressedCamera, + icon: Icon( + Icons.photo_camera, + size: iconSize, + ), + ), + Text(InstrealLocalizations.of(context)!.takePicture) + ], + ), + ], + ), + ), + ); + } +} + +class ImageView extends StatelessWidget { + final VoidCallback onPressedRemoveImage; + final String imagePath; + const ImageView({ + required this.imagePath, + required this.onPressedRemoveImage, + super.key, + }); + + @override + Widget build(BuildContext context) { + return AspectRatio( + aspectRatio: 4 / 3, + child: ClipRRect( + borderRadius: BorderRadius.circular(16.0), + child: Stack( + fit: StackFit.expand, + children: [ + Image.file( + File(imagePath), + fit: BoxFit.cover, + ), + Align( + alignment: Alignment.bottomRight, + child: IconButton( + onPressed: onPressedRemoveImage, + icon: const Icon(Icons.delete), + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/presentation/screens/home/home.dart b/lib/presentation/screens/home/home.dart index c47bce4..8a4286b 100644 --- a/lib/presentation/screens/home/home.dart +++ b/lib/presentation/screens/home/home.dart @@ -1,3 +1,4 @@ +import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:instreal/features/posts/post_entity.dart'; @@ -5,6 +6,7 @@ import 'package:instreal/features/posts/posts_firestore.dart'; import 'package:instreal/features/posts/posts_repository.dart'; import 'package:instreal/l10n/index.dart'; import 'package:instreal/presentation/components/index.dart'; +import 'package:instreal/presentation/components/src/add_post_modal_sheet.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @@ -15,68 +17,75 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { final postingsRepo = PostsRepositoryImpl(firestore: PostFirestoreImpl()); + // need to define an Impl like a repository + final storageRef = FirebaseStorage.instance.ref(); + @override Widget build(BuildContext context) { return Scaffold( - body: NestedScrollView( - headerSliverBuilder: (context, innerBoxIsScrolled) => [ - SliverAppBar( - expandedHeight: 200, - collapsedHeight: 200, - flexibleSpace: FlexibleSpaceBar( - background: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 32.0), - Text( - InstrealLocalizations.of(context)!.whatsUpIn, - style: Theme.of(context).textTheme.displayLarge, - ), - Text( - InstrealLocalizations.of(context)!.montreal, - style: Theme.of(context).textTheme.displayLarge!.copyWith( - color: Theme.of(context).colorScheme.primary, - fontFamily: GoogleFonts.caveat().fontFamily, - ), - ), - ], + body: SafeArea( + child: NestedScrollView( + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverAppBar( + expandedHeight: 200, + collapsedHeight: 200, + flexibleSpace: FlexibleSpaceBar( + background: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 32.0), + Text( + InstrealLocalizations.of(context)!.whatsUpIn, + style: Theme.of(context).textTheme.displayLarge, + ), + Text( + InstrealLocalizations.of(context)!.montreal, + style: Theme.of(context).textTheme.displayLarge!.copyWith( + color: Theme.of(context).colorScheme.primary, + fontFamily: GoogleFonts.caveat().fontFamily, + ), + ), + ], + ), ), ), + floating: false, + pinned: false, ), - floating: false, - pinned: false, + ], + body: FutureBuilder>( + future: postingsRepo.posts, + builder: (context, snapshot) => switch (snapshot) { + AsyncSnapshot(connectionState: ConnectionState.done, :final data) => + ListView.builder( + itemBuilder: (context, index) => PostCard(posting: data[index]), + itemCount: data!.length, + padding: const EdgeInsets.symmetric(horizontal: 16), + ), + _ => const Center( + child: CircularProgressIndicator(), + ), + }, ), - ], - body: FutureBuilder>( - future: postingsRepo.posts, - builder: (context, snapshot) => switch (snapshot) { - AsyncSnapshot(connectionState: ConnectionState.done, :final data) => - ListView.builder( - itemBuilder: (context, index) => PostCard(posting: data[index]), - itemCount: data!.length, - padding: const EdgeInsets.symmetric(horizontal: 16), - ), - _ => const Center( - child: CircularProgressIndicator(), - ), - }, ), ), floatingActionButton: FloatingActionButton( onPressed: () async { - await postingsRepo.add( - const Post( - id: "", - title: 'title', - author: 'author', - imageUrl: - 'https://i1.wp.com/www.suitcasescholar.com/wp-content/uploads/2012/08/DSC_2583.jpg', - ), + // returns a Post + final post = await showModalBottomSheet( + context: context, + builder: (context) => AddPostModalPage(storageRef: storageRef), + isScrollControlled: true, + useSafeArea: true, ); - setState(() {}); + + if (post != null) { + await postingsRepo.add(post); + setState(() {/*The List has changed*/}); + } }, child: const Icon(Icons.add), ), diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..64a0ece 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2e1de87..2db3c22 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 6d06bd4..e566b43 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,11 +6,15 @@ import FlutterMacOS import Foundation import cloud_firestore +import file_selector_macos import firebase_core +import firebase_storage import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 5865055..b20bcd1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: a742f71d7f3484253a623b30e19256aa4668ecbb3de6ad1beb0bcf8d4777ecd8 + sha256: f5628cd9c92ed11083f425fd1f8f1bc60ecdda458c81d73b143aeda036c35fe7 url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.16" async: dependency: transitive description: @@ -45,34 +45,42 @@ packages: dependency: "direct main" description: name: cloud_firestore - sha256: "988351d4fcc58c47578d95d014018888b2ce7a228f84ce322fea4a127707a0d4" + sha256: "8bfbb5a2edbc6052452326d60de0113fea2bcbf081d34a3f8e45c8b38307b31c" url: "https://pub.dev" source: hosted - version: "4.8.1" + version: "4.14.0" cloud_firestore_platform_interface: dependency: transitive description: name: cloud_firestore_platform_interface - sha256: b6652ce95507e604f00cb0c9c9be2363d21746e82667f2f3d61edf2d33cad3bf + sha256: "73ff438fe46028f0e19f55da18b6ddc6906ab750562cd7d9ffab77ff8c0c4307" url: "https://pub.dev" source: hosted - version: "5.15.1" + version: "6.1.0" cloud_firestore_web: dependency: transitive description: name: cloud_firestore_web - sha256: "22d02595eb7a304c0f1b4a717e78cc054522e8f237eb7b1122886f93130f3f7a" + sha256: "232e45e95970d3a6baab8f50f9c3a6e2838d145d9d91ec9a7392837c44296397" url: "https://pub.dev" source: hosted - version: "3.6.1" + version: "3.9.0" collection: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.18.0" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + url: "https://pub.dev" + source: hosted + version: "0.3.3+8" crypto: dependency: transitive description: @@ -85,10 +93,10 @@ packages: dependency: "direct main" description: name: cupertino_icons - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.6" fake_async: dependency: transitive description: @@ -113,30 +121,86 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.4" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" + url: "https://pub.dev" + source: hosted + version: "0.9.2+1" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" firebase_core: dependency: "direct main" description: name: firebase_core - sha256: a4a99204da264a0aa9d54a332ea0315ce7b0768075139c77abefe98093dd98be + sha256: "96607c0e829a581c2a483c658f04e8b159964c3bae2730f73297070bc85d40bb" url: "https://pub.dev" source: hosted - version: "2.14.0" + version: "2.24.2" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: b63e3be6c96ef5c33bdec1aab23c91eb00696f6452f0519401d640938c94cba2 + sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63 url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "5.0.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "0fd5c4b228de29b55fac38aed0d9e42514b3d3bd47675de52bf7f8fccaf922fa" + sha256: d585bdf3c656c3f7821ba1bd44da5f13365d22fcecaf5eb75c4295246aaa83c0 + url: "https://pub.dev" + source: hosted + version: "2.10.0" + firebase_storage: + dependency: "direct main" + description: + name: firebase_storage + sha256: "75e6cb6bed65138b5bbd86bfd7cf9bc9a175fb0c31aacc400e9203df117ffbe6" + url: "https://pub.dev" + source: hosted + version: "11.6.0" + firebase_storage_platform_interface: + dependency: transitive + description: + name: firebase_storage_platform_interface + sha256: "545a3a8edf337850403bb0fa03c8074a53deb87c0107d19755c77a82ce07919e" + url: "https://pub.dev" + source: hosted + version: "5.1.3" + firebase_storage_web: + dependency: transitive + description: + name: firebase_storage_web + sha256: ee6870ff79aa304b8996ba18a4aefe1e8b3fc31fd385eab6574180267aa8d393 url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "3.6.17" flutter: dependency: "direct main" description: flutter @@ -146,15 +210,23 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" flutter_localizations: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + url: "https://pub.dev" + source: hosted + version: "2.0.17" flutter_test: dependency: "direct dev" description: flutter @@ -169,10 +241,10 @@ packages: dependency: "direct main" description: name: google_fonts - sha256: db5efba8106bd784a92c96cfd81716f4e06baab54e37de858488e9a00a764cad + sha256: f0b8d115a13ecf827013ec9fc883390ccc0e87a96ed5347a3114cac177ef18e8 url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.1.0" http: dependency: transitive description: @@ -189,14 +261,78 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "26222b01a0c9a2c8fe02fc90b8208bd3325da5ed1f4a2acabf75939031ac0bdd" + url: "https://pub.dev" + source: hosted + version: "1.0.7" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" + url: "https://pub.dev" + source: hosted + version: "0.8.9+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: e2423c53a68b579a7c37a1eda967b8ae536c3d98518e5db95ca1fe5719a730a3 + url: "https://pub.dev" + source: hosted + version: "3.0.2" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: eac0a62104fa12feed213596df0321f57ce5a572562f72a68c4ff81e9e4caacf + url: "https://pub.dev" + source: hosted + version: "0.8.9" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "0e827c156e3a90edd3bbe7f6de048b39247b16e58173b08a835b7eb00aba239e" + url: "https://pub.dev" + source: hosted + version: "2.9.2" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" intl: dependency: "direct main" description: name: intl - sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" url: "https://pub.dev" source: hosted - version: "0.18.0" + version: "0.18.1" js: dependency: transitive description: @@ -209,34 +345,42 @@ packages: dependency: transitive description: name: lints - sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015" + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "3.0.0" matcher: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" path: dependency: transitive description: @@ -326,26 +470,26 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -366,10 +510,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.1" typed_data: dependency: transitive description: @@ -386,6 +530,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + url: "https://pub.dev" + source: hosted + version: "0.3.0" win32: dependency: transitive description: @@ -403,5 +555,5 @@ packages: source: hosted version: "1.0.0" sdks: - dart: ">=3.0.0 <4.0.0" - flutter: ">=3.3.0" + dart: ">=3.2.3 <4.0.0" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 5c6a284..9fa4b23 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,23 +4,25 @@ publish_to: 'none' version: 1.0.0+1 environment: - sdk: ^3.0.0 + sdk: ^3.2.3 dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter - intl: any - cupertino_icons: ^1.0.5 - google_fonts: ^5.0.0 - cloud_firestore: ^4.8.1 + intl: ^0.18.1 + cupertino_icons: ^1.0.6 + google_fonts: ^6.1.0 + cloud_firestore: ^4.14.0 firebase_core: ^2.14.0 + image_picker: ^1.0.7 + firebase_storage: ^11.6.0 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.1 + flutter_lints: ^3.0.1 flutter: uses-material-design: true diff --git a/storage.rules b/storage.rules new file mode 100644 index 0000000..cdbd6b2 --- /dev/null +++ b/storage.rules @@ -0,0 +1,12 @@ +rules_version = '2'; + +// Craft rules based on data in your Firestore database +// allow write: if firestore.get( +// /databases/(default)/documents/users/$(request.auth.uid)).data.isAdmin; +service firebase.storage { + match /b/{bucket}/o { + match /{allPaths=**} { + allow read, write: if true; // TODO needs proper rule + } + } +} \ No newline at end of file diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 1a82e7d..ca05a30 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,18 @@ #include "generated_plugin_registrant.h" +#include +#include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + CloudFirestorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("CloudFirestorePluginCApi")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); FirebaseCorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + FirebaseStoragePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index fa8a39b..ec13ce6 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,7 +3,10 @@ # list(APPEND FLUTTER_PLUGIN_LIST + cloud_firestore + file_selector_windows firebase_core + firebase_storage ) list(APPEND FLUTTER_FFI_PLUGIN_LIST