-
Notifications
You must be signed in to change notification settings - Fork 0
20260127 #458 사진 첨부 후 채팅 전송 기능 추가 #490
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
The head ref may contain hidden characters: "20260127_#458_\uC0AC\uC9C4_\uCCA8\uBD80_\uD6C4_\uCC44\uD305_\uC804\uC1A1_\uAE30\uB2A5_\uCD94\uAC00"
Conversation
Walkthrough이 PR은 채팅에 이미지 메시징(선택, 업로드, 전송, 표시)을 추가하고, ApiPageable 모델을 pageNumber/pageSize/offset/paged/unpaged/sort 형태로 변경하며, WebSocket 전송 및 관련 UI/컨텍스트 메뉴를 업데이트합니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ChatScreen
participant ImagePicker
participant ImageApi
participant WebSocket
participant Server
User->>ChatScreen: "사진 선택하기" 선택
ChatScreen->>ImagePicker: 이미지 선택 요청
ImagePicker-->>ChatScreen: 이미지 파일 반환
ChatScreen->>ChatScreen: 로컬에 낙관적 이미지 메시지 생성
ChatScreen->>ImageApi: 이미지 업로드 요청 (multipart)
ImageApi->>Server: 업로드 전달
Server-->>ImageApi: imageUrls 반환
ImageApi-->>ChatScreen: imageUrls 전달
ChatScreen->>WebSocket: payload( chatRoomId, content, type=image, imageUrls )
WebSocket->>Server: JSON 인코딩 후 전송
Server-->>ChatScreen: 서버 메시지(확인/동기화 데이터)
ChatScreen->>ChatScreen: 로컬 메시지와 서버 메시지 병합/동기화
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/widgets/common/romrom_context_menu.dart (1)
349-382:⚠️ Potential issue | 🟡 MinorGestureDetector에 HitTestBehavior 설정은 선택사항 — 기술적 근거 재검토 필요
현재 코드에서 Container는 height와 padding을 명시적으로 정의하고 있으므로, 이미 padding 영역까지 포함한 전체 범위가 GestureDetector의 hit-test 범위로 설정됩니다. 따라서 기본 동작(HitTestBehavior.deferToChild)에서도 padding 영역의 탭이 정상적으로 감지됩니다.
다만
HitTestBehavior.opaque추가는 다음 이유로 권장됩니다:
- 코드 명확성: 의도적인 hit-test 동작을 명시적으로 표현
- 팀 일관성: 이 파일의 다른 오버레이 GestureDetector에서
translucent를 사용하는 패턴과 통일- 투명 영역 처리: 명확하게 전체 padding 영역이 탭 가능함을 보장
🤖 Fix all issues with AI agents
In `@lib/screens/chat_room_screen.dart`:
- Around line 62-64: 비동기 이미지 업로드 후 위젯이 이미 dispose될 수 있어 "_sendImage()" 호출 전과 메서드
내부의 모든 setState() 호출 직전에 mounted 여부를 검사해야 합니다; 구체적으로 ImageApi().uploadImages()를
await한 뒤 즉시 context.mounted 또는 mounted를 체크하고, setState()를 호출하는 모든 위치(예:
_sendImage 내부의 상태 업데이트 블록과 에러/성공 핸들러)에서 mounted 확인을 추가해 widget이 dispose된 경우 상태
업데이트나 Navigator/Scaffold 관련 작업을 건너뛰도록 변경하세요.
- Around line 699-725: Guard against empty or null image lists before
constructing PhotoViewerMultipleImage: check message.imageUrls (or
message.imageUrls?.isEmpty) and when it's null/empty render the existing
placeholder/error widget (e.g., the SizedBox with Center and
CircularProgressIndicator or ErrorImagePlaceholder) inside the same Container;
otherwise, pass the non-empty list into PhotoViewerMultipleImage. This change
should be applied around the MessageType.image branch where
PhotoViewerMultipleImage is created (referencing PhotoViewerMultipleImage,
message.imageUrls, and the existing placeholder/errorWidget).
In `@lib/services/apis/chat_api.dart`:
- Around line 138-145: In the catch block around
jsonDecode/ChatRoomResponse.fromJson, stop including the stackTrace in the
Exception message; instead log the stackTrace separately (e.g., debugPrint or a
logger) and rethrow or throw a concise Exception like "채팅 메시지 파싱 실패" so the
error message remains brief while the stackTrace is recorded separately for
debugging; update the catch that currently does "catch (e, stackTrace) { throw
Exception('... $e $stackTrace'); }" to log stackTrace and throw a minimal
message.
In `@lib/services/chat_websocket_service.dart`:
- Around line 203-229: sendMessage currently allows MessageType.image without
ensuring imageUrls is non-null/non-empty, which can send an invalid payload; add
an early guard in sendMessage (before building/sending payload) that when type
== MessageType.image validates imageUrls != null && imageUrls.isNotEmpty and
throws an ArgumentError (or returns) if violated, otherwise proceed to include
payload['imageUrls'] = imageUrls and call _stompClient!.send as before;
reference sendMessage, MessageType.image, imageUrls, payload and the
_stompClient!.send call so the check is placed prior to creating/sending the
payload.
In `@lib/widgets/chat_image_bubble.dart`:
- Around line 40-44: Replace the hardcoded Colors.transparent used in the
Material widget's color property with the team color constant
AppColors.transparent; locate the Material constructor in chat_image_bubble.dart
(the widget where borderRadius: BorderRadius.circular(10.r), clipBehavior:
Clip.antiAlias are set) and change color: Colors.transparent to color:
AppColors.transparent so the app uses the shared color constant.
| if (response.statusCode >= 200 && response.statusCode < 300) { | ||
| final Map<String, dynamic> responseData = jsonDecode(response.body); | ||
| chatRoomResponse = ChatRoomResponse.fromJson(responseData); | ||
| debugPrint('채팅 메시지 조회 성공: ${chatRoomResponse.messages?.content.length ?? 0}개'); | ||
| try { | ||
| final Map<String, dynamic> responseData = jsonDecode(response.body); | ||
| chatRoomResponse = ChatRoomResponse.fromJson(responseData); | ||
| debugPrint('채팅 메시지 조회 성공: ${chatRoomResponse.messages?.content.length ?? 0}개'); | ||
| } catch (e, stackTrace) { | ||
| throw Exception('채팅 메시지 파싱 실패: $e $stackTrace'); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
예외 메시지에 stackTrace 포함 지양
stackTrace를 예외 메시지에 붙이면 사용자 노출/로그 노이즈 위험이 큽니다. 로그로 분리하고 예외 메시지는 간결하게 유지하세요.
🔧 수정 제안
try {
final Map<String, dynamic> responseData = jsonDecode(response.body);
chatRoomResponse = ChatRoomResponse.fromJson(responseData);
debugPrint('채팅 메시지 조회 성공: ${chatRoomResponse.messages?.content.length ?? 0}개');
} catch (e, stackTrace) {
- throw Exception('채팅 메시지 파싱 실패: $e $stackTrace');
+ debugPrint('채팅 메시지 파싱 실패: $e\n$stackTrace');
+ throw Exception('채팅 메시지 파싱 실패');
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (response.statusCode >= 200 && response.statusCode < 300) { | |
| final Map<String, dynamic> responseData = jsonDecode(response.body); | |
| chatRoomResponse = ChatRoomResponse.fromJson(responseData); | |
| debugPrint('채팅 메시지 조회 성공: ${chatRoomResponse.messages?.content.length ?? 0}개'); | |
| try { | |
| final Map<String, dynamic> responseData = jsonDecode(response.body); | |
| chatRoomResponse = ChatRoomResponse.fromJson(responseData); | |
| debugPrint('채팅 메시지 조회 성공: ${chatRoomResponse.messages?.content.length ?? 0}개'); | |
| } catch (e, stackTrace) { | |
| throw Exception('채팅 메시지 파싱 실패: $e $stackTrace'); | |
| } | |
| if (response.statusCode >= 200 && response.statusCode < 300) { | |
| try { | |
| final Map<String, dynamic> responseData = jsonDecode(response.body); | |
| chatRoomResponse = ChatRoomResponse.fromJson(responseData); | |
| debugPrint('채팅 메시지 조회 성공: ${chatRoomResponse.messages?.content.length ?? 0}개'); | |
| } catch (e, stackTrace) { | |
| debugPrint('채팅 메시지 파싱 실패: $e\n$stackTrace'); | |
| throw Exception('채팅 메시지 파싱 실패'); | |
| } |
🤖 Prompt for AI Agents
In `@lib/services/apis/chat_api.dart` around lines 138 - 145, In the catch block
around jsonDecode/ChatRoomResponse.fromJson, stop including the stackTrace in
the Exception message; instead log the stackTrace separately (e.g., debugPrint
or a logger) and rethrow or throw a concise Exception like "채팅 메시지 파싱 실패" so the
error message remains brief while the stackTrace is recorded separately for
debugging; update the catch that currently does "catch (e, stackTrace) { throw
Exception('... $e $stackTrace'); }" to log stackTrace and throw a minimal
message.
|
✅ 프로젝트 빌드 성공 APK 빌드가 완료되었습니다. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@lib/screens/chat_room_screen.dart`:
- Around line 740-757: The outgoing message branch incorrectly applies
BoxConstraints(maxWidth: 264.w, maxHeight: 264.h) causing long text in the text
bubble to be clipped; update the ternary so that chatImageBubble(message.type ==
MessageType.image) keeps the maxHeight constraint inside the image branch (or
within chatImageBubble) while the text Container uses only
BoxConstraints(maxWidth: 264.w) (remove maxHeight) so long text can wrap; locate
the ternary around message.type, the chatImageBubble call, and the outgoing
Container with constraints to make this change.
🧹 Nitpick comments (2)
lib/widgets/chat_image_bubble.dart (1)
29-30: placeholderSizedBox크기에 ScreenUtil 미적용bubble 영역의 위젯들은
264.w,10.r등 ScreenUtil을 사용하고 있지만, placeholder의SizedBox(width: 32, height: 32)는 논리 픽셀 고정값입니다. 일관성을 위해.w를 적용하는 것을 권장합니다.♻️ 수정 제안
- placeholder: (_, __) => const Center( - child: SizedBox(width: 32, height: 32, child: CircularProgressIndicator(color: AppColors.primaryYellow)), + placeholder: (_, __) => Center( + child: SizedBox(width: 32.w, height: 32.w, child: CircularProgressIndicator(color: AppColors.primaryYellow)), ),bubble 내 placeholder도 동일하게:
- child: SizedBox( - width: 32, - height: 32, + child: SizedBox( + width: 32.w, + height: 32.w,Also applies to: 56-58
lib/services/chat_websocket_service.dart (1)
220-220: enum 직렬화 방식 개선 제안
type.toString().split('.').last.toUpperCase()보다 Dart 2.17+의.name속성을 사용하면 더 간결하고 안전합니다.♻️ 수정 제안
- 'type': type.toString().split('.').last.toUpperCase(), + 'type': type.name.toUpperCase(),
| message.type == MessageType.image | ||
| ? chatImageBubble(context, message) | ||
| : Container( | ||
| padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), | ||
| constraints: BoxConstraints(maxWidth: 264.w, maxHeight: 264.h), | ||
| decoration: BoxDecoration( | ||
| color: AppColors.primaryYellow, | ||
| borderRadius: BorderRadius.circular(10.r), | ||
| ), | ||
| child: Text( | ||
| message.content ?? '', | ||
| style: CustomTextStyles.p2.copyWith( | ||
| color: AppColors.textColorBlack, | ||
| fontWeight: FontWeight.w400, | ||
| height: 1.2, | ||
| ), | ||
| ), | ||
| ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
발신 텍스트 메시지에 maxHeight: 264.h 제약이 적용되어 긴 텍스트가 잘릴 수 있습니다
수신 메시지(Line 703)에는 maxWidth만 설정되어 있지만, 발신 메시지(Line 744)에는 maxHeight: 264.h도 추가되어 있습니다. 이미지 버블과 텍스트 버블이 ternary로 분기되면서 maxHeight가 텍스트 Container에도 적용된 것으로 보입니다. 긴 텍스트 메시지가 264.h에서 잘리게 됩니다.
🔧 수정 제안
message.type == MessageType.image
? chatImageBubble(context, message)
: Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
- constraints: BoxConstraints(maxWidth: 264.w, maxHeight: 264.h),
+ constraints: BoxConstraints(maxWidth: 264.w),
decoration: BoxDecoration(🤖 Prompt for AI Agents
In `@lib/screens/chat_room_screen.dart` around lines 740 - 757, The outgoing
message branch incorrectly applies BoxConstraints(maxWidth: 264.w, maxHeight:
264.h) causing long text in the text bubble to be clipped; update the ternary so
that chatImageBubble(message.type == MessageType.image) keeps the maxHeight
constraint inside the image branch (or within chatImageBubble) while the text
Container uses only BoxConstraints(maxWidth: 264.w) (remove maxHeight) so long
text can wrap; locate the ternary around message.type, the chatImageBubble call,
and the outgoing Container with constraints to make this change.
|
✅ 프로젝트 빌드 성공 APK 빌드가 완료되었습니다. |
Cassiiopeia
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
확인했습니다
| InkWell( | ||
| GestureDetector( | ||
| onTap: () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이게뭐예요? InkWell?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.

#458
Summary by CodeRabbit
릴리스 노트
새 기능
개선사항