이번에는 "거래 등록" 화면에 작성한 글/이미지를 Firebase 에 업로드하는것을 구현해보겠습니다.
개발환경 : 윈도우11, 안드로이드 스튜디오, flutter 3.0.1
구현 화면은 아래와 같다
./src/repo/item_service.dart - 새로운 글을 저장하는 로직 구현
import 'package:cloud_firestore/cloud_firestore.dart';
import '../constants/data_keys.dart';
import '../models/item_model.dart';
import '../utils/logger.dart';
Future createNewItem(ItemModel2 itemModel, String itemKey, String userKey) async {
// 신규 작성글을 업로드하기 위한 위치 설정
DocumentReference<Map<String, dynamic>> itemDocRef =
FirebaseFirestore.instance.collection(COL_ITEMS).doc(itemKey);
final DocumentSnapshot documentSnapshot = await itemDocRef.get();
// 신규 작성글을 사용자 정보의 하위 콜랙션에 추가, No SQL 에서는 역정규화 하는것이 좋을때가 있음,
DocumentReference<Map<String, dynamic>> userItemDocRef = FirebaseFirestore
.instance
.collection(COL_USERS)
.doc(userKey)
.collection(COL_USER_ITEMS)
.doc(itemKey);
// 신규 작성글이 없다면 저장,
if (!documentSnapshot.exists) {
// await itemDocRef.set(itemModel.toJson());
await FirebaseFirestore.instance.runTransaction((transaction) async {
// 2개중에 하나라도 오류가 발생하면 모두 롤백한다,
transaction.set(itemDocRef, itemModel.toJson());
transaction.set(userItemDocRef, itemModel.toMinJson());
});
}
}
}
./src/screens/input/input_screen.dart - 입력할 항목을 확인하고 미입력시 알림창으로 입력을 유도한다.
void attemptCreateItem() async {
if (FirebaseAuth.instance.currentUser == null) return;
// 완료 버튼 클릭
isCreatingItem = true;
// setState 해줘야 인디케이터가 동작한다,
setState(() {});
final String userKey = FirebaseAuth.instance.currentUser!.uid;
final String userPhone = FirebaseAuth.instance.currentUser!.phoneNumber!;
final String itemKey = ItemModel2.generateItemKey(userKey);
List<Uint8List> images = SelectImageController.to.images;
// final num? price = num.tryParse(_priceController.text.replaceAll('.', '').replaceAll(' 원', ''));
final num? price = num.tryParse(_priceController.text.replaceAll(RegExp(r'\D'), ''));
// UserNotifier userNotifier = context.read<UserNotifier>();
if (images.isEmpty) {
dataWarning(context, '확인', '이미지를 선택해주세요');
return;
}
if (_titleController.text.isEmpty) {
dataWarning(context, '확인', '제목을 입력해주세요');
return;
}
if (CategoryController.to.currentCategoryInEng == 'none') {
dataWarning(context, '확인', '카테고리를 선택해주세요');
return;
}
if (price == null) {
dataWarning(context, '확인', '가격을 입력해주세요');
return;
}
if (_detailController.text.isEmpty) {
dataWarning(context, '확인', '내용을 입력해주세요');
return;
}
// uploading raw data and return the Urls,
List<String> downloadUrls = await ImageStorage.uploadImage(images, itemKey);
logger.d('upload finished(${downloadUrls.length}) : $downloadUrls');
ItemModel2 itemModel = ItemModel2(
itemKey: itemKey,
userKey: userKey,
userPhone: userPhone,
imageDownloadUrls: downloadUrls,
title: _titleController.text,
category: CategoryController.to.currentCategoryInEng,
price: price,
// price ?? 0
negotiable: _suggestPriceSelected,
detail: _detailController.text,
address: UserController.to.userModel.value!.address,
//userNotifier.userModel!.address,
geoFirePoint: UserController.to.userModel.value!.geoFirePoint,
//userNotifier.userModel!.geoFirePoint,
createdDate: DateTime.now().toUtc(),
);
// await ItemService().createNewItem(itemModel, itemKey, userNotifier.user!.uid);
await ItemService().createNewItem(itemModel, itemKey, UserController.to.user.value!.uid);
Get.back();
}
Future<bool> dataWarning(BuildContext context, String title, String msg) async {
isCreatingItem = false;
return await showDialog<bool>(
context: context,
builder: (context) => WarningYesNo(
title: title,
msg: msg,
yesMsg: '확인',
),
) ??
false;
}
./src/widgets/warning_dialog.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class WarningYesNo extends StatelessWidget {
final String title;
final String msg;
final String yesMsg;
const WarningYesNo({Key? key, required this.title, required this.msg, required this.yesMsg})
: super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(
title,
textAlign: TextAlign.center,
),
content: Text(
msg,
),
actions: <Widget>[
Container(
decoration: const BoxDecoration(),
child: MaterialButton(
onPressed: () {
debugPrint('WarningYesNo >> true');
Get.back(result: true);
},
child: Text(yesMsg),
),
),
],
);
}
}
저장된 결과는 아래와 같습니다. 사용자 콜렉션 하위에 저장된 요약정보와 아이템 콜렉션 하위에 저장된 상세정보
'Flutter > 12 Clone 'Used Goods app'' 카테고리의 다른 글
[Flutter] Clone - 당근마켓37(Item read & Get.arguments) (2) | 2022.08.19 |
---|---|
[Flutter] Clone - 당근마켓36(ItemModel upload - validators) (0) | 2022.08.19 |
[Flutter] Clone - 당근마켓34(InputScreen - image uploading) (0) | 2022.08.18 |
[Flutter] Clone - 당근마켓33(InputScreen - image picker/Getx) (0) | 2022.08.17 |
[Flutter] Clone - 당근마켓32(ItemModel) (0) | 2022.08.12 |