이번에는 채팅 화면에 입력창(하단)과 아이템 간략 정보(상단)를 표시해 보겠습니다.
개발환경 : 윈도우11, 안드로이드 스튜디오, flutter 3.0.1
화면 구현은 아래와 같습니다.
./src/models/chat_model.dart - 구현중 수정이 필요한 부분이 있어서 수정함
class ChatModel2 {
String? chatKey; // 자동생성되므로 ? 처리
String msg;
DateTime createdDate;
String userKey;
DocumentReference? reference;
ChatModel2({
// required this.chatKey, // 자동생성되므로 필수처리 제외.
required this.msg,
required this.createdDate,
required this.userKey,
this.reference,
});
factory ChatModel2.fromJson(Map<String, dynamic> json) => ChatModel2(
// chatKey: json[DOC_CHATKEY], // 자동생성되므로 필수처리 제외.
msg: json[DOC_MSG],
createdDate: json[DOC_CREATEDDATE] == null
? DateTime.now().toUtc()
: (json[DOC_CREATEDDATE] as Timestamp).toDate(),
userKey: json[DOC_USERKEY],
// reference: json["reference"],
);
Map<String, dynamic> toJson() => {
// DOC_CHATKEY: chatKey, // 자동생성되므로 필수처리 제외.
DOC_MSG: msg,
DOC_CREATEDDATE: createdDate,
DOC_USERKEY: userKey,
// "reference": reference,
};
}
./src/screens/chat/chatroom_screen.dart - 정보 및 입력 창 구현
import 'package:apple_market3/src/states/user_controller.dart';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:shimmer/shimmer.dart';
import '../../models/chat_model.dart';
import '../../models/user_model.dart';
import '../../repo/chat_service.dart';
import '../../utils/logger.dart';
class ChatroomScreen extends StatefulWidget {
const ChatroomScreen({Key? key}) : super(key: key);
@override
State<ChatroomScreen> createState() => _ChatroomScreenState();
}
class _ChatroomScreenState extends State<ChatroomScreen> {
late String chatroomKey;
final TextEditingController _textEditingController = TextEditingController();
@override
void initState() {
// TODO: implement initState
chatroomKey = Get.parameters['chatroomKey']!;
super.initState();
}
@override
Widget build(BuildContext context) {
logger.d('${Get.parameters['chatroomKey']}');
UserModel1 userModel = UserController.to.userModel.value!;
return Scaffold(
appBar: AppBar(),
backgroundColor: Colors.grey[200],
// 화면 하단의 메뉴바 때문에 SafeArea 로 wrapping 해야 오동작을 방지함.
body: SafeArea(
child: Column(
children: [
// 게시글 정보를 간략히 표시
_buildItemInfo(context),
// 채팅 메시지 표시 부분
Expanded(
child: Container(
color: Colors.white,
),
),
const Padding(padding: EdgeInsets.all(4)),
// 메시지 입력 창
_buildInputBar(userModel)
],
),
),
);
}
// 컬럼내부에 리스트타일(높이 관련 오류가 있어서 나중에 row+column 조함으로 변경함)과 버튼으로 구성 예정
MaterialBanner _buildItemInfo(BuildContext context) {
return MaterialBanner(
// 공간 조절을 위해서 패딩을 수정함
padding: EdgeInsets.zero,
leadingPadding: EdgeInsets.zero,
// actions 는 빈칸
actions: [Container()],
// content 에만 위젯을 넣어서 표시 예정임.
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 16, right: 8, top: 8, bottom: 8),
child:
ExtendedImage.network(
'https://randomuser.me/api/portraits/lego/4.jpg', // lego pic
width: 48,
height: 48,
fit: BoxFit.cover,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
text: TextSpan(
text: '거래완료',
style: Theme.of(context).textTheme.bodyText1,
children: [
TextSpan(
// text: chatroomModel == null ? '' : ' ' + chatroomModel.itemTitle,
text: ' 복숭아 떨이',
style: Theme.of(context).textTheme.bodyText2)
]),
),
RichText(
text: TextSpan(
text: '30,000원',
style: Theme.of(context).textTheme.bodyText1,
children: [
TextSpan(
text: ' (가격제한불가)',
style: Theme.of(context)
.textTheme
.bodyText2!
.copyWith(color: Colors.black26))
]),
),
],
),
],
),
Padding(
padding: const EdgeInsets.only(left: 16, bottom: 8),
// 버튼 사이즈를 줄이기 위해서 SizedBox 추가
child: SizedBox(
height: 32,
child: TextButton.icon(
onPressed: () { debugPrint('후기남기기 클릭~~');},
icon: const Icon(
Icons.edit,
// 버튼 사이즈를 줄이기 위해서 size 추가 설정,
size: 16,
color: Colors.black87,
),
label: Text(
'후기 남기기',
style: Theme.of(context).textTheme.bodyText1!.copyWith(color: Colors.black87),
),
style: TextButton.styleFrom(
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
side: BorderSide(color: Colors.grey[300]!, width: 2),
),
),
),
),
),
],
),
);
}
Widget _buildInputBar(UserModel1 userModel) {
return SizedBox(
height: 48,
child: Row(
children: [
IconButton(
onPressed: () {},
icon: const Icon(
Icons.add,
color: Colors.grey,
),
),
Expanded(
child: TextFormField(
controller: _textEditingController,
decoration: InputDecoration(
hintText: '메시지를 입력하세요',
// 메시지 입력박스를 조금 작게 줄임,
isDense: true,
// fillColor & filled 동시에 설정해야함.
fillColor: Colors.white,
filled: true,
suffixIcon: GestureDetector(
onTap: () {
logger.d('Icon clicked');
},
child: const Icon(
Icons.emoji_emotions_outlined,
color: Colors.grey,
),
),
// 아이콘때문에 입력 박스가 커져서 줄여줌 설정,
suffixIconConstraints: BoxConstraints.tight(const Size(40, 40)),
// 입력 박스의 패딩 공간을 줄임, 미설정시 16쯤 됨,
contentPadding: const EdgeInsets.all(10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Colors.redAccent),
),
),
),
),
IconButton(
onPressed: () async {
ChatModel2 chatModel = ChatModel2(
userKey: userModel.userKey,
msg: _textEditingController.text,
createdDate: DateTime.now().toUtc(),
);
await ChatService().createNewChat(chatroomKey, chatModel);
logger.d(_textEditingController.text.toString());
_textEditingController.clear();
},
icon: const Icon(
Icons.send,
color: Colors.grey,
),
)
],
),
);
}
}
'Flutter > 12 Clone 'Used Goods app'' 카테고리의 다른 글
[Flutter] Clone - 당근마켓52(Chat - 4) 메시지 스타일 (0) | 2022.09.07 |
---|---|
[Flutter] Clone - 당근마켓51(Chat - 3) 메시지 표시 (0) | 2022.09.06 |
[Flutter] Clone - 당근마켓49(Chat - 1) (1) | 2022.09.01 |
[Flutter] Clone - 당근마켓48(chatroomModel, chatModel) (0) | 2022.08.31 |
[Flutter] Clone - 당근마켓47 번외(googleMap - 1) (0) | 2022.08.30 |