반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 자바공부
- nestjs공부
- nestjs스터디
- 스프링
- 코테준비
- 카프카
- nestjs
- querydsl
- 프로그래머스
- 알고리즘공부
- 스프링부트
- K8S
- DDD
- 플러터 공부
- 스프링공부
- Flutter
- JPA스터디
- 코테공부
- JPA예제
- Axon framework
- JPA공부
- Kafka
- 스프링부트공부
- 스프링 공부
- JPA 공부
- JPA
- 플러터 개발
- 자료구조공부
- 기술공부
- 기술면접공부
Archives
- Today
- Total
DevBoi
[Flutter] Firebase Storage, Database 본문
반응형
요새 앱개발로 정신이 없다.
그래서 정리할 시간도 포스팅도 없다.
하지만, 최근 요청건으로 개발한 부분에 대해서, 포스팅을 하려고한다.
대부분 앱은 backend server로 보내고 3rd db를 쓰지만,
간단하거나 백엔드 구현이 어려운 경우 파이어베이스를 많이 쓴다.
1) Firebase storage
이미지를 핸드폰에서 집어와서 파이어베이스 storage에 올리는 방법이다.
별건 없다.
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
import 'package:path/path.dart';
class ImageUploads extends StatefulWidget {
ImageUploads({Key? key}) : super(key: key);
@override
_ImageUploadsState createState() => _ImageUploadsState();
}
class _ImageUploadsState extends State<ImageUploads> {
firebase_storage.FirebaseStorage storage =
firebase_storage.FirebaseStorage.instance;
File? _photo;
final ImagePicker _picker = ImagePicker();
Future imgFromGallery() async {
final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
_photo = File(pickedFile.path);
uploadFile();
} else {
print('No image selected.');
}
});
}
Future imgFromCamera() async {
final pickedFile = await _picker.pickImage(source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
_photo = File(pickedFile.path);
uploadFile();
} else {
print('No image selected.');
}
});
}
Future uploadFile() async {
if (_photo == null) return;
final fileName = basename(_photo!.path);
final destination = 'files/$fileName';
//gs://finder-310f0.appspot.com/files/image_picker_A2C6C0E4-A9D4-4950-BCBD-02267D79E7F7-23512-0000028123B23F68.jpg
try {
final ref = firebase_storage.FirebaseStorage.instance
.ref(destination)
.child('file/');
print(_photo);
await ref.putFile(_photo!);
} catch (e) {
print('error occured');
}
}
// 1. "https://firebasestorage.googleapis.com/v0/b/"
// 2. bucket object
// 3. "/o/"
// 4. correctly encoded path object.
// 5. "?alt=media"
//
// 6. token="..."
//
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
SizedBox(
height: 32,
),
Center(
child: GestureDetector(
onTap: () {
_showPicker(context);
},
child: CircleAvatar(
radius: 55,
backgroundColor: Color(0xffFDCF09),
child: _photo != null
? ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.file(
_photo!,
width: 100,
height: 100,
fit: BoxFit.fitHeight,
),
)
: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(50)),
width: 100,
height: 100,
child: Icon(
Icons.camera_alt,
color: Colors.grey[800],
),
),
),
),
)
],
),
);
}
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Gallery'),
onTap: () {
imgFromGallery();
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () {
imgFromCamera();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
}
1) Firebase storage + form data
아래와 같이 엮어서 쓸수있다.
우선 Imageview 데이터를 바인딩하고
저장 시점에 Form과 file을 같이 save하고 뒤로 가는것이다.
db에는 이미지 Url이 저장되고 해당 주소를 호출하여 뿌려준다 (물론 느린건 어쩔수없다, 파이어베이스 자체가 느리다)
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:finder/firebase_options.dart';
import 'package:finder/view/file-upload.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
import 'package:path/path.dart';
class FindIt extends StatefulWidget {
final schoolCode;
final category;
const FindIt({required this.schoolCode,required this.category});
@override
State<StatefulWidget> createState() {
return _FindItState(schoolCode: schoolCode,category:category);
}
}
class _FindItState extends State<FindIt>{
_FindItState({required this.schoolCode,required this.category});
final schoolCode;
final category;
File? _photo;
String uploadName = '';
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final nameController = TextEditingController();
final descController = TextEditingController();
final placeController = TextEditingController();
String name='';
String description='';
String place='';
final screenWidth = MediaQuery.of(context).size.width;
firebase_storage.FirebaseStorage storage =
firebase_storage.FirebaseStorage.instance;
final ImagePicker _picker = ImagePicker();
Future uploadFile() async {
if (_photo == null) return;
final fileName = basename(_photo!.path);
final destination = 'image/$fileName';
//gs://finder-310f0.appspot.com/files/image_picker_A2C6C0E4-A9D4-4950-BCBD-02267D79E7F7-23512-0000028123B23F68.jpg
try {
final ref = firebase_storage.FirebaseStorage.instance
.ref(destination)
.child('file/');
await ref.putFile(_photo!);
} catch (e) {
print('error occured');
}
}
void save(String name,String place, String description){
uploadFile().then((value) => {
FirebaseFirestore.instance.collection(category).add({
"name":name,
"place":place,
"imgUrl":uploadName,
"description":description,
"time":Timestamp.now()
})
})..then((value) => {
Navigator.pop(context)
});
}
Future<String> imgFromGallery() async {
final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
_photo = File(pickedFile.path);
} else {
print('No image selected.');
}
});
return pickedFile!.name;
}
Future imgFromCamera() async {
final pickedFile = await _picker.pickImage(source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
_photo = File(pickedFile.path);
//uploadFile();
} else {
print('No image selected.');
}
});
}
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Gallery'),
onTap: () {
imgFromGallery().then((value) => {
setState((){
uploadName = value;
})
});
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () {
imgFromCamera();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
return Scaffold(
appBar: AppBar(
title: Text('Find it'),
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () {
Navigator.pop(context);
},),
backgroundColor: Color.fromARGB(255, 50, 64, 182)),
body: Container(
child: Padding(
padding: EdgeInsets.all(80),
child: Center(
child: Column(
children: [
TextField(
controller: nameController,
keyboardType: TextInputType.text,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: '이름을 입력해주세요',
),
onChanged: ((value){
name = nameController.text;
}),
),
SizedBox(height: 10,),
TextField(
controller: descController,
keyboardType: TextInputType.text,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: '설명을 입력해주세요',
),
onChanged: ((value){
description = descController.text;
}),
),
SizedBox(height: 10,),
TextField(
controller: placeController,
keyboardType: TextInputType.text,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: '장소를 입력해주세요',
),
onChanged: ((value){
place = placeController.text;
}),
),
//SizedBox(height: 40,),
//ImageUploads(),
SizedBox(height: 30,),
Center(
child: GestureDetector(
onTap: () {
_showPicker(context);
},
child: CircleAvatar(
radius: 55,
backgroundColor: Color(0xffFDCF09),
child: _photo != null
? ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.file(
_photo!,
width: 100,
height: 100,
fit: BoxFit.fitHeight,
),
)
: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(50)),
width: 100,
height: 100,
child: Icon(
Icons.camera_alt,
color: Colors.grey[800],
),
),
),
),
),
SizedBox(height: 30,),
ElevatedButton(
onPressed: ((){
save(name,place,description);
}),
child: Text('저장')
),
],
),
),
),
)
);
}
}
3.관련 데이터를 불러와서 리스트 뷰로 뿌려줌
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:finder/firebase_options.dart';
import 'package:finder/view/message.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
class FindMe extends StatefulWidget {
final schoolCode;
final category;
const FindMe({required this.schoolCode,required this.category});
@override
State<StatefulWidget> createState() {
return _FindMeState(schoolCode: schoolCode,category: category);
}
}
class _FindMeState extends State<FindMe>{
final schoolCode;
final category;
_FindMeState({required this.schoolCode,required this.category});
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Text('Find me'),
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () {
Navigator.pop(context);
},),
backgroundColor: Color.fromARGB(255, 50, 64, 182)),
body: Container(
padding: EdgeInsets.all(50),
child: Column(
children: [
Expanded(child: Messages(schoolCode: schoolCode,category: category,)),
],),));
}
}
실제 서비스 앱은 이런 구조가될일은 드물긴하지만.
모듈화 요청으로 인해 간단하게 한 내용을 기록한다.
반응형
'[Mobile] > [Flutter]' 카테고리의 다른 글
[Flutter] Firebase auth + Google login 구현 (0) | 2023.11.12 |
---|---|
[Flutter] Auto Serializable (0) | 2023.11.12 |
[Flutter] ios 빌드 구성 차이 (0) | 2023.10.12 |
[Flutter] Chatting 모듈 정리 (0) | 2023.10.08 |
[Flutter] IOS관련 리빌드 (0) | 2023.10.07 |