Skip to content

Commit

Permalink
Merge pull request #18 from aengzu/feature/history
Browse files Browse the repository at this point in the history
feat: 대화 히스토리 추가
  • Loading branch information
aengzu authored Sep 29, 2024
2 parents f776ca4 + 2d4e7b8 commit 2890dc0
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'package:get/get.dart';
import 'package:palink_v2/di/locator.dart';
import 'package:palink_v2/domain/model/character/character.dart';
import 'package:palink_v2/domain/model/chat/message.dart';
import 'package:palink_v2/domain/usecase/fetch_chat_history_usecase.dart';

class ChatHistoryViewmodel extends GetxController {
final FetchChatHistoryUsecase getChatHistoryUsecase = Get.put(getIt<FetchChatHistoryUsecase>());

List<Message>? messages; // 단일 피드백 정보 저장
Character? character; // 캐릭터 정보 저장
int chatroomId; // 채팅방 ID
RxBool conversationNotFound = true.obs; // 404 처리 플래그


ChatHistoryViewmodel({
required this.chatroomId,
});

@override
void onInit() {
super.onInit();
conversationNotFound.value = true;
loadMessages();
}

// 메시지 로드
void loadMessages() async {
try {
// 메시지 가져오기
messages = await getChatHistoryUsecase.execute(chatroomId);
messages = messages!.reversed.toList();
conversationNotFound.value = false; // 404 에러가 발생하지 않은 경우 플래그 설정;
update();
} catch (e) {
// 404 에러 발생 시 처리
if (e.toString().contains('404')) {
conversationNotFound.value = true; // 404 에러가 발생한 경우 플래그 설정
} else {
Get.snackbar('Error', 'Failed to load feedback');
}
update();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'package:get/get.dart';
import 'package:palink_v2/di/locator.dart';
import 'package:palink_v2/domain/model/chat/conversation.dart';
import 'package:palink_v2/domain/usecase/get_chatroom_by_user.dart';
import 'package:palink_v2/domain/model/character/character.dart';
import 'package:palink_v2/domain/repository/character_repository.dart';

class MyconversationsViewmodel extends GetxController {
final GetChatroomByUser getChatroomByUser = Get.put(getIt<GetChatroomByUser>());
final CharacterRepository characterRepository = Get.put(getIt<CharacterRepository>());

List<Conversation> chatrooms = [];
Map<int, Character> characters = {}; // 캐릭터 정보 저장

MyconversationsViewmodel();

@override
void onInit() {
super.onInit();
_loadChatRooms();
}

void _loadChatRooms() async {
try {
var fetchedData = await getChatroomByUser.execute();
chatrooms = fetchedData;

// 캐릭터 ID에 해당하는 캐릭터 데이터 불러오기
for (var conversation in chatrooms) {
var characterId = conversation.characterId;

var character = await characterRepository.getCharacterById(characterId);
characters[characterId] = character; // 캐릭터 정보 저장
}

update(); // UI 업데이트
} catch (e) {
// 에러 발생 시 처리
Get.snackbar('Error', 'Failed to load chatrooms');
}
}
}
109 changes: 109 additions & 0 deletions lib/presentation/screens/mypage/view/chat_history_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:palink_v2/domain/model/character/character.dart';
import 'package:palink_v2/presentation/screens/chatting/view/components/messages.dart';
import 'package:palink_v2/presentation/screens/common/appbar_perferred_size.dart';
import 'package:palink_v2/presentation/screens/main_screens.dart';
import 'package:palink_v2/presentation/screens/mypage/controller/chat_history_viewmodel.dart';
import 'package:sizing/sizing.dart';

import 'feedback_history_view.dart';

class ChatHistoryView extends StatelessWidget {
final int chatroomId;
final ChatHistoryViewmodel viewModel;
final Character character;

ChatHistoryView({required this.chatroomId, required this.character})
: viewModel = Get.put(ChatHistoryViewmodel(chatroomId: chatroomId));

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
title: const Text('대화 기록'),
bottom: appBarBottomLine(),
),
body: Stack(
children: [
// 메시지 섹션이 스크롤 가능하도록 설정
Positioned.fill(
child: Obx(() {
// 대화 데이터가 로드되지 않은 경우
if (viewModel.conversationNotFound.value) {
return const Center(
child: Text(
'대화가 저장되지 않았습니다.',
style: TextStyle(fontSize: 18, color: Colors.grey),
),
);
}
// 대화가 있는 경우 메시지 리스트를 표시
return SingleChildScrollView(
child: SizedBox(
height: 0.8.sh,
child: Messages(
messages: viewModel.messages ?? [],
userId: chatroomId,
characterImg: character.image ?? '',
onReactionAdded: (message, reaction) {},
),
),
);
}),
),
// 버튼을 하단에 고정
Align(
alignment: Alignment.bottomCenter,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// 피드백 보기 버튼 추가
ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.grey,
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 30.0), // 버튼 크기 조절
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0), // 네모난 모서리
),
),
onPressed: () {
Get.off(() => const MainScreens());
},
child: const Text('홈 화면으로'),
),
const SizedBox(width: 20), // 버튼 사이의 간격 추가
// 홈 화면으로 버튼
ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.blueAccent,
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 30.0), // 버튼 크기 조절
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0), // 네모난 모서리
),
),
onPressed: () {
Get.to(() => FeedbackHistoryView(
chatroomId: chatroomId,
character: character,
));
},
child: const Text('피드백 보기'),
),
],
),
),
),
),
],
),
);
}
}
100 changes: 49 additions & 51 deletions lib/presentation/screens/mypage/view/feedback_history_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import 'package:palink_v2/core/theme/app_colors.dart';
import 'package:palink_v2/domain/model/character/character.dart';
import 'package:palink_v2/presentation/screens/chatting/view/components/liking_bar.dart';
import 'package:palink_v2/presentation/screens/common/appbar_perferred_size.dart';
import 'package:palink_v2/presentation/screens/common/custom_btn.dart';
import 'package:palink_v2/presentation/screens/main_screens.dart';
import 'package:palink_v2/presentation/screens/mypage/controller/feedback_history_viewmodel.dart';
import 'package:sizing/sizing.dart';
Expand All @@ -26,35 +25,34 @@ class FeedbackHistoryView extends StatelessWidget {
title: const Text('대화 최종 피드백'),
bottom: appBarBottomLine(),
),
body: Obx(() {
// 피드백이 없는 경우
if (viewModel.feedbackNotFound.value) {
return const Center(
child: Text(
'피드백이 저장되지 않았습니다.',
style: TextStyle(fontSize: 18, color: Colors.grey),
),
);
}
body: Column(
children: [
// Scrollable content
Expanded(
child: Obx(() {
// 피드백이 없는 경우
if (viewModel.feedbackNotFound.value) {
return const Center(
child: Text(
'피드백이 저장되지 않았습니다.',
style: TextStyle(fontSize: 18, color: Colors.grey),
),
);
}

// 피드백 데이터가 로드되지 않은 경우
if (viewModel.feedback == null) {
return const Center(child: CircularProgressIndicator());
}
// 피드백 데이터가 로드되지 않은 경우
if (viewModel.feedback == null) {
return const Center(child: CircularProgressIndicator());
}

return Column(
children: [
SizedBox(
height: 0.8.sh, // 화면 높이의 75%
child: SingleChildScrollView(
return SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
'평가',
style:
TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
),
_buildProfileImage(),
SizedBox(height: 0.045.sh),
Expand All @@ -70,72 +68,72 @@ class FeedbackHistoryView extends StatelessWidget {
SizedBox(height: 0.03.sh),
const Text(
'최종 호감도',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
LikingBar(viewModel.feedback!.finalLikingLevel),
Text(
'최종 호감도 ${viewModel.feedback!.finalLikingLevel}점'),
Text('최종 호감도 ${viewModel.feedback!.finalLikingLevel}점'),
SizedBox(height: 0.05.sh),
const Text(
'최종 거절 점수',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
Text('${viewModel.feedback!.totalRejectionScore}점'),
SizedBox(height: 0.05.sh),
CustomButton(
label: '홈 화면으로',
onPressed: () {
Get.off(() => MainScreens());
})
],
),
);
}),
),
// Fixed button at the bottom
SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.blueAccent,
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 0.3.sw),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
onPressed: () {
Get.off(() => const MainScreens());
},
child: const Text('홈 화면으로'),
),
),
],
);
}),
),
],
),
);
}

// 프로필 이미지 표시, character가 null일 경우 대체 이미지 보여주기
Widget _buildProfileImage() {
if (character == null || character!.image == null) {
if (character == null || character.image == null) {
return Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.grey.shade300, // 기본 회색 배경
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(10),
),
child: const Icon(
Icons.person,
size: 80,
color: Colors.white,
), // 기본 아이콘
),
);
}

// character가 null이 아니면 이미지 표시
return Container(
padding: const EdgeInsets.all(10),
width: 120,
height: 120,
child: Image.asset(character.image ?? ''),
);
}

// 쉼표로 구분된 문자열을 줄바꿈과 번호로 포맷하는 메서드
String _formatAsList(String commaSeparatedString) {
final items =
commaSeparatedString.split(',').map((item) => item.trim()).toList();
return items
.asMap()
.entries
.map((entry) => '${entry.key + 1}. ${entry.value}')
.join('\n');
}
}
Loading

0 comments on commit 2890dc0

Please sign in to comment.