Skip to content
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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
72 changes: 57 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
Comment on lines +26 to +34
Copy link
Member

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.

```
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: <https://firebase.google.com/docs/flutter/setup?platform=web>

Expand All @@ -43,14 +51,48 @@ 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 = '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.
8 changes: 7 additions & 1 deletion firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
2 changes: 1 addition & 1 deletion firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
8 changes: 7 additions & 1 deletion lib/l10n/intl_en.arb
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"
}
8 changes: 7 additions & 1 deletion lib/l10n/intl_fr.arb
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"
}
13 changes: 10 additions & 3 deletions lib/main.dart
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';
Expand All @@ -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
Expand Down
201 changes: 201 additions & 0 deletions lib/presentation/components/src/add_post_modal_sheet.dart
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 'package:instreal/l10n/index.dart';


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),
),
)
],
),
),
);
}
}
Loading