What to do?
회원가입(On Boarding) 기능 개발하기
- 프로필 사진 업로드 기능을 위해 이미지 업로드용 Server를 생성
- 이미지 업로드 기능 구현
- 상태 관리를 위해 Multi Provider 생성
Reference
라이브러리 설치
pubspec.yaml 파일 수정
dependencies:
...
flutter_bloc: ^7.0.1
google_fonts: ^1.1.2
http: ^0.12.2
image_picker: ^0.6.7+22
rethink_db_ns: ^0.0.4
shared_preferences: ^2.0.6
State
OnBoardingState(회원가입 상태)
- 회원가입 로딩중
- props : None
- 회원가입 성공
- props : 회원가입 성공한 유저
state_management/on_board/on_boarding_state.dart
import 'package:chat/chat.dart';
import 'package:equatable/equatable.dart';
abstract class OnBoardingState extends Equatable {}
class OnBoardingInitial extends OnBoardingState {
@override
List<Object> get props => [];
}
class OnBoardingLoading extends OnBoardingState {
@override
List<Object> get props => [];
}
class OnBoardingSuccess extends OnBoardingState {
final User _user;
OnBoardingSuccess(this._user);
@override
List<Object> get props => [_user];
}
ProfileImageCubit(프로필 사진)
- 선택한 이미지 경로를 UI에 전달하는 역할
state_management/on_board/profile_image_cubit.dart
import 'dart:io';
import 'package:bloc/bloc.dart';
import 'package:image_picker/image_picker.dart';
class ProfileImageCubit extends Cubit<File> {
ProfileImageCubit() : super(null);
final _imagePicker = ImagePicker();
Future<void> getImage() async {
PickedFile image = await _imagePicker.getImage(
source: ImageSource.gallery, imageQuality: 50);
if (image == null) return;
emit(File(image.path));
}
}
OnBoardingCubit(프로필 사진)
state_management/on_board/on_boarding_cubit.dart
import 'dart:io';
import 'package:bloc/bloc.dart';
import 'package:chat/chat.dart';
import 'package:flutter_prj/states_management/on_board/on_boarding_state.dart';
import '../../service/image_upload_service.dart';
class OnBoardingCubit extends Cubit<OnBoardingState> {
final IUserService _userService;
final ImageUploadService _imageUploader;
OnBoardingCubit(this._userService, this._imageUploader)
: super(OnBoardingInitial());
Future<void> connect(String username, File profileImage) async {
// UI에 로딩중 state를 전달
emit(OnBoardingLoading());
// 선택한 이미지 경로 가져오기
final profileImageUrl = await _imageUploader.uploadImage(profileImage);
// 유저 생성하기
final user = User(
username: username,
photoUrl: profileImageUrl,
active: true,
lastSeen: DateTime.now());
// 회원가입을 수행하고, 회원가입 성공 state를 UI에 전달
emit(OnBoardingSuccess(await _userService.connect(user)));
}
}
이미지 업로드 서버
- Express를 사용해 이미지 업로드용 서버 생성
- 이미지 업로드 경로 : server/images/profile
- 서버 파일 : app.js
- 라이브러리 설치
# server라는 폴더 생성
mkdir server
# server라는 폴더로 이동
cd server
# 라이브러리 설치
npm init
npm install i express
npm install i express-fileupload
- 서버
- express를 사용해 서버 생성
- server/images/profile 경로에 업로드된 이미지 저장
- /upload 경로로 POST요청 발생 시 이미지 업로드
- 3000번 포트 사용
server/images/profile/app.js
const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
app.use(fileUpload());
app.use('/images/profile', express.static('images/profile'));
app.post('/upload', (req, res)=>{
let uploadFile = req.files?.picture;
let uploadPath = `${__dirname}/images/profile/${uploadFile.name}`;
uploadFile.mv(uploadPath, (err)=>{
if (err) return res.status(500).send(err);
console.log('err')
res.send(`/images/profile/${uploadFile.name}`);
});
})
app.listen(3000, ()=>{
return console.log('Server for image upload is running on port 3000...')
});
- 서버 실행
node server/app.js
이미지 업로드 기능
위에서는 Server가 업로드된 이미지를 받아서 저장하는 기능을 만듬
이제 Client 쪽에서 이미지 업로드 요청을 보내는 기능 구현 해야함
service/image_upload.dart
import 'dart:io';
import 'package:http/http.dart';
class ImageUploadService {
final String _url;
ImageUploadService(this._url);
Future<String> uploadImage(File image) async {
final req = MultipartRequest('POST', Uri.parse(_url));
req.files.add(await MultipartFile.fromPath('picture', image.path));
final result = await req.send();
if (result.statusCode != 200) return null;
final response = await Response.fromStream(result);
return Uri.parse(_url).origin + response.body;
}
}
Provider 세팅
- OnBoardUI(회원가입화면)에서 Cubit(OnBoardingCubit, ProfileCubit)을 사용할 수 있도록 세팅
- Connection 생성시 host명을 10.0.2.2로 함
- └ localhost로 하면 DB 연결에 문제가 생겨서, 아래 블로그 글에 방법을 따라함
[flutter] flutter socketexception os error connection refused errno = 111
문제 상황 로컬에서 flask로 간단하게 만든 서버에 요청을 보냈더니 이러한 에러가 발생했다. 문제 원인 원인은 안드로이드 에뮬레이터가 localhost 대신 10.0.2.2를 사용하기 때문이다. 해결 방법 loca
g0n1.tistory.com
view_model/compositon_root.dart
import 'package:chat/chat.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_prj/screen/pages/on_board/on_board_page.dart';
import 'package:flutter_prj/service/image_upload_service.dart';
import 'package:flutter_prj/states_management/on_board/on_boarding_cubit.dart';
import 'package:flutter_prj/states_management/on_board/profile_image_cubit.dart';
import 'package:rethink_db_ns/rethink_db_ns.dart';
class CompositionRoot {
static RethinkDb _db;
static Connection _connection;
static IUserService _userService;
static configure() async {
_db = RethinkDb();
_connection = await _db.connect(
// 에뮬레이터는 host를 localhost지정하면 에러발생...
host: '10.0.2.2',
port: 28015,
);
_userService = UserService(_db, _connection);
}
static Widget composeOnBoardingUi() {
ImageUploadService imageUploader =
// 에뮬레이터는 host를 localhost지정하면 에러발생...
ImageUploadService('http://10.0.2.2:3000/upload');
OnBoardingCubit onBoardingCubit =
OnBoardingCubit(_userService, imageUploader);
ProfileImageCubit profileImageCubit = ProfileImageCubit();
return MultiBlocProvider(
providers: [
BlocProvider(create: (BuildContext context) => onBoardingCubit),
BlocProvider(create: (BuildContext context) => profileImageCubit),
],
child: const OnBoarding(),
);
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_prj/screen/custom_desgin/theme.dart';
import 'package:flutter_prj/view_model/composition_root.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await CompositionRoot.configure();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Chat App",
theme: lightTheme(context),
darkTheme: darkTheme(context),
home: CompositionRoot.composeOnBoardingUi());
}
const MyApp({key}) : super(key: key);
}
'Flutter' 카테고리의 다른 글
[Flutter] 채팅앱 만들기 #10 (0) | 2023.03.11 |
---|---|
[Flutter] 채팅앱 만들기 #9 (0) | 2023.03.08 |
[Flutter] 채팅앱 만들기 #7 (0) | 2023.03.05 |
[Flutter] 채팅앱 만들기 #6 (0) | 2023.03.05 |
[Flutter] 채팅앱 만들기 #5 (0) | 2023.03.04 |