목표
provider과 Firebase를 기반으로 일회용 chat이 가능한 Application을 만들어보고 활용법을 알아본다.
해당 내용은 도그풋님의 #2 플러터 + 파이어베이스 채팅앱 만들기를 기초로 study를 진행하였으며, 일부 부분과 다르게 UI 및 기능적인 측면에서 추가를 하였습니다. 또한 Firebase와 Firecloud 등이 업데이트 됨에 따라 firebase 코드 관련 부분등은 수정된 부분이 있으니 참고하여 주시기 바랍니다.
또한 해당내용에 있어서 공부를 진행하는 부분이 있으므로 코드상에 문의가 있거나, 수정사항이 발견이 되면 알려주시면 감사하겠습니다.
해당 코드의 github
https://github.com/riris01/flutter_firebase_chat_provider
원본 코드의 github
https://github.com/wownsdl13/flutter_firebase_chatting_example
최종적으로 만들 파일 트리는 다음과 같다.
자 그럼 보통 가장 먼저 시작하는 main.dart 부터 시작을 해보자.
1. @ main.dart
일단 가장 먼저 전체적인 코드를 보면 크게 필요한 패키지들을 import 해준다음 void main(){runApp(MyApp());}을 넣고 난 다음에 추가적으로 WidgetsFlutterBinding.ensureInitialized()를 적어두었다. 이는 Widgets과 Flutter의 binding 순서를 initialize 하기 위해 작성하였다. 그외에 Firebase.initializeApp의 경우 Firebase를 사용하는 어플리케이션에 있어 initialize 순서가 가장 먼저 필요하므로 initializeApp을 작성하였다.
그다음은 일반적인 순서와 동일하다. statelessWidget으로 가장먼저 MaterialApp()을 부른다음 그 그릇안에 home: MyHomePage()를 생성하여 어플리케이션 실행시 EntrancePage()로 이동할 수 있도록 하였다. 여기서 ChangeNotifierProvider를 사용한 것을 볼 수 있는데, 이는 상태를 자동 추적하여 필요한 경우 위젯을 다시 렌더링 하기 위해 사용하였다. 어렵게 말했지만 사실 쉽게 말하면 ChangeNotifier 클래스가 create로 콜백이 되면 EntrancePage()의 하위 위젯사에서도 EntranceProvider의 상태를 사용할 수 있도록 만들수 있도록 코드를 작성하였다. 이를 통해 ChangeNotifierProvider는 계속해서 EntranceProvider에 액세스 하여 앱의 필요한 부분에 상태 업데이르를 할 수 있게 된다.
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:provider/provider.dart';
import 'views/entrance_page/entrance_page.dart';
import 'views/entrance_page/local_utils/EntranceProvider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => EntranceProvider(), child: EntrancePage());
}
}
자 그럼 EntranceProvider는 기본적으로 제공되는 Provider인가? 아니다.
이제, lib/views/entrance_page/local_utils/EntranceProvider.dart를 생성하자.
2. @EntranceProvider.dart
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class EntranceProvider extends ChangeNotifier {}
매우 간단하다 하지만 중요하다. 왜 EntranceProvider가 ChangeNotifier의 클래스를 사용하여 확장한다는 것이다. ChangeNotifier 클래스라고 하는 것은 보통 Listenable 인터페이스를 구현한다고 보면 된다. 즉, ChangeNotifier 클래스를 확장한 클래스는 상태 변경을 하면 notifyListeners() 메서드로 알림을 전송하는것이 가능하다. 이 부분을 생성함으로써 ChangeNotifierProvider의 객체를 생성한 후에 EntranceProvider의 인스턴스로 EntranceProvider의 상태를 활용 가능하다.
3. @entrance_page.dart
자 그럼 main.dart에서 이어지는 EntrancePage() 클래스를 만들어야 한다. views/entrance_page/entrance_page.dart를 생성하자.
그다음 필요한 패키지들을 import 한다. 물론 처음부터 필요한 패키지를 모두 import를 한다는 것은 어렵다. 하지만, 기본적인 패키지나 사용될법한 패키지들은 미리 import 해두는것이 습관이 되어 있어 저자는 보통 처음에 import를 하는 편이다.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
import 'package:flutter_firebase_chat/screens/chatting_page/chatting_page.dart';
import 'package:flutter_firebase_chat/screens/chatting_page/local_utils/ChattingProvider.dart';
StatefulWidget을 사용해서 일단 EntrancePage 클래스를 생성하여 준다.
(...)
class EntrancePage extends StatefulWidget {
@override
_EntrancePageState createState() => _EntrancePageState();
}
class _EntrancePageState extends State<EntrancePage> {
late TextEditingController _controller;
@override
void initState() {
_controller = TextEditingController();
super.initState();
}
(...)
그런데 여기서는 TextEditingController를 쓸거다. 여기서 TextEditingController를 쓰는 이유는 nickname을 임의로 부여해서 채팅방에 입장하게 만들기 위해서다. ID로 로그인을 하는 절차가 이 어플리케이션에서는 없다보니 임의로 nickname을 부여하는 방식으로 간소하게 나마 ID를 부여해본다. 그래서 TestingEditingController 클래스의 인스턴스를 사용할 것이며, 이를 _controller이라는 변수에 부여했다.
그리고 다시 State객체를 초기화 하기 위해서 initState()를 만들고 initState()가 호출될때, _controller 변수에 TextEditingController 객체를 생성하여 할당하도록 하였다.
자 이제 어떻게 보일지 body를 구성해보자.
일단 먼저 색과 nickname을 입력할 부분이다.
- 가장 먼저 Scaffold 내에 appBar와 body를 생성한다. appBar에는 자기가 원하는 색 혹은 이름을 넣어준다. 그리고 body부분에는 TextField()를 삽입하여 nickname을 작성할 부분을 생성하여 준다. 이때 물론 controllers는 _controller 변수를 사용한다.
- GestureDetector로 Scaffold를 감싸주었는데 이는 키보드가 팝업된 상태에서 해당 행위를 취소하고자 할때 focus된 지역의 외 지역을 누르면 자동으로 키보드가 숨김이 될 수 있도록 하기 위해서 이렇게 작성하였다.
(...)
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
}, // Textfieldform에서 unfocus 하기
child: Scaffold(
backgroundColor: Colors.blue[200],
appBar: AppBar(
title: Text('Berry talk'),
centerTitle: true,
backgroundColor: Colors.blue[600],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
controller: _controller,
style: TextStyle(fontSize: 16),
textAlign: TextAlign.center,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter your nickname',
hintStyle: TextStyle(color: Colors.white)),
),
),
(...)
그다음은 버튼 부분이다. nickname도 생성하였으니 이제 버튼을 눌러 채팅방에 입장을 할 수 있도록 설정해보자. 먼저 버튼을 만들자면 다음과 같이 만들수 있다.
(...)
child: Container(
padding: EdgeInsets.all(13),
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(12)),
child: Text(
'Enter the room',
style: TextStyle(fontSize: 16, color: Colors.white),
)),
(...)
Container를 만들어서 Color와 BorderRadius를 설정해주고 Text도 붙여두었다.
자 그럼 이 버튼을 눌렀을때, 채팅방으로 이동할 수 있도록 하자.
(...)
GestureDetector(
onTap: () async {
var u = Uuid().v1();
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ChangeNotifierProvider(
create: (context) =>
ChattingProvider(u, _controller.text),
child: ChattingPage(),
)));
},
(...)
버튼을 누르게 되면 Uuid()에 의해서 nickname이 u라는 변수에 담겨 ChangttingPage()로 이동하게 된다. 이를 통해 nickname처럼 사용할 수 있게 된다. 버튼으로 페이지를 이동하는 방식은 Flutter에 기본으로 탑재되어있는 Navigator.of(context).push를 통해 이동하도록 하였다.
그럼 오늘까지 만든 화면을 확인하면 다음과 같다.
다음에는 chattingpage를 구성해보자.
'Flutter' 카테고리의 다른 글
[Firebase+provider]Chp4. Chat App 채팅 기능 구현하기 I (0) | 2023.05.14 |
---|---|
[Firebase+provider]Chp3. Chat App 채팅 페이지 만들기 (0) | 2023.05.12 |
[Firebase] FCM에 대해서 알아보자 - 작성중 (0) | 2023.05.09 |
[Firebase+provider]Chp1. Chat App 환경 준비 (0) | 2023.05.04 |
[이론] MVC, MVP 패턴 + MVVM 패턴과 비교 (0) | 2023.05.02 |