Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 대화 히스토리 추가 #18

Merged
merged 1 commit into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading