-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/post content #27
base: main
Are you sure you want to change the base?
Changes from 8 commits
f69c8ad
b12caee
7a33d9f
ded4d0f
1dba834
dad115c
eb60fae
edb1d74
358e22a
4e41554
3824e3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 Production | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if it's instruction for production. It's just a general instruction. |
||
|
||
Reference: <https://firebase.google.com/docs/flutter/setup?platform=web> | ||
|
||
|
@@ -43,14 +51,39 @@ Reference: <https://firebase.google.com/docs/flutter/setup?platform=web> | |
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 = '0.0.0.0'; | ||
FirebaseStorage.instance.useStorageEmulator(host, 9199); | ||
FirebaseFirestore.instance.useFirestoreEmulator(host, 8080); | ||
} catch (e) { | ||
// ignore: avoid_print | ||
print(e); | ||
} | ||
} | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't required since there's the |
||
|
||
## Support | ||
|
||
If you have trouble running this project. Go to our [discord group](https://discord.gg/NMc62wG7eU) and ask your questions under #stackoverflow channel. We'll be happy to lend you a hand. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we'd better encourage users to create a ticket in GitHub rather than Discord. (That doesn't mean they can't tho..) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,23 @@ | ||
{ | ||
"emulators": { | ||
"firestore": { | ||
"port": 8080 | ||
"port": 8080, | ||
"host": "0.0.0.0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need to do this. |
||
}, | ||
"ui": { | ||
"enabled": true | ||
}, | ||
"singleProjectMode": true | ||
"singleProjectMode": true, | ||
"storage": { | ||
"port": 9199, | ||
"host": "0.0.0.0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need to do this. |
||
} | ||
}, | ||
"firestore": { | ||
"rules": "firestore.rules", | ||
"indexes": "firestore.indexes.json" | ||
}, | ||
"storage": { | ||
"rules": "storage.rules" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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,12 +17,9 @@ void main() async { | |
|
||
if (kDebugMode) { | ||
try { | ||
FirebaseFirestore.instance.useFirestoreEmulator( | ||
defaultTargetPlatform == TargetPlatform.android | ||
? "10.0.2.2" | ||
: "localhost", | ||
8080, | ||
); | ||
const host = '0.0.0.0'; | ||
FirebaseStorage.instance.useStorageEmulator(host, 9199); | ||
FirebaseFirestore.instance.useFirestoreEmulator(host, 8080); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need this change. |
||
} catch (e) { | ||
// ignore: avoid_print | ||
print(e); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 '../../../l10n/index.dart'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. mind using absolute path? |
||
|
||
class AddPostModalPage extends StatefulWidget { | ||
final Reference storageRef; | ||
const AddPostModalPage({required this.storageRef, super.key}); | ||
|
||
@override | ||
State<AddPostModalPage> createState() => _AddPostModalPageState(); | ||
} | ||
|
||
class _AddPostModalPageState extends State<AddPostModalPage> { | ||
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), | ||
), | ||
) | ||
], | ||
), | ||
), | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally it should be required since it is supposed to be automatic.