Files
sodalive-ios/SodaLive/Sources/Chat/Talk/Room/Message/UserMessageItemView.swift
T

159 lines
5.5 KiB
Swift

//
// UserMessageItemView.swift
// SodaLive
//
// Created by klaus on 9/2/25.
//
import SwiftUI
struct UserMessageBubbleShape: Shape {
func path(in rect: CGRect) -> Path {
let path = UIBezierPath()
// 시작점 (왼쪽 상단, 16px 반지름)
path.move(to: CGPoint(x: 16, y: 0))
// 상단 라인 (오른쪽 상단 4px 반지름까지)
path.addLine(to: CGPoint(x: rect.width - 4, y: 0))
// 오른쪽 상단 모서리 (4px 반지름)
path.addArc(withCenter: CGPoint(x: rect.width - 4, y: 4),
radius: 4,
startAngle: -CGFloat.pi / 2,
endAngle: 0,
clockwise: true)
// 오른쪽 라인 (오른쪽 하단 16px 반지름까지)
path.addLine(to: CGPoint(x: rect.width, y: rect.height - 16))
// 오른쪽 하단 모서리 (16px 반지름)
path.addArc(withCenter: CGPoint(x: rect.width - 16, y: rect.height - 16),
radius: 16,
startAngle: 0,
endAngle: CGFloat.pi / 2,
clockwise: true)
// 하단 라인 (왼쪽 하단 16px 반지름까지)
path.addLine(to: CGPoint(x: 16, y: rect.height))
// 왼쪽 하단 모서리 (16px 반지름)
path.addArc(withCenter: CGPoint(x: 16, y: rect.height - 16),
radius: 16,
startAngle: CGFloat.pi / 2,
endAngle: CGFloat.pi,
clockwise: true)
// 왼쪽 라인 (왼쪽 상단 16px 반지름까지)
path.addLine(to: CGPoint(x: 0, y: 16))
// 왼쪽 상단 모서리 (16px 반지름)
path.addArc(withCenter: CGPoint(x: 16, y: 16),
radius: 16,
startAngle: CGFloat.pi,
endAngle: -CGFloat.pi / 2,
clockwise: true)
path.close()
return Path(path.cgPath)
}
}
struct UserMessageItemView: View {
let message: ServerChatMessage
var body: some View {
HStack(alignment: .bottom, spacing: 4) {
Spacer()
// 시간 표시
VStack {
Text(formatTime(from: message.createdAt))
.appFont(size: 10, weight: .regular)
.foregroundColor(.white)
}
// 메시지 버블
HStack(spacing: 9) {
VStack(alignment: .trailing, spacing: 4) {
// 메시지 텍스트
HStack(spacing: 10) {
styledMessageText(message.message)
.lineLimit(nil)
.multilineTextAlignment(.leading)
}
.padding(.horizontal, 10)
.padding(.vertical, 8)
.background(Color.button)
.clipShape(UserMessageBubbleShape())
}
}
}
.frame(maxWidth: .infinity, alignment: .trailing)
}
private func formatTime(from timestamp: Int64) -> String {
let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000))
return date.convertDateFormat(dateFormat: "a h:mm")
}
private func styledMessageText(_ message: String) -> Text {
var result = Text("")
let components = message.components(separatedBy: "(")
for (index, component) in components.enumerated() {
if index == 0 {
// 첫 번째 컴포넌트는 항상 일반 텍스트
if !component.isEmpty {
result = result + Text(component)
.appFont(size: 16, weight: .regular)
.foregroundColor(.white)
}
} else {
// "(" 이후의 텍스트 처리
if let closeIndex = component.firstIndex(of: ")") {
let beforeClose = String(component[..<closeIndex])
let afterClose = String(component[component.index(after: closeIndex)...])
// 소괄호 안의 텍스트 (특별 스타일)
result = result + Text("(\(beforeClose))")
.font(.system(size: 16, design: .default).italic())
.foregroundColor(Color(hex: "333333"))
// 소괄호 뒤의 텍스트 (일반 스타일)
if !afterClose.isEmpty {
result = result + Text(afterClose)
.appFont(size: 16, weight: .regular)
.foregroundColor(.white)
}
} else {
// 닫는 괄호가 없으면 일반 텍스트로 처리
result = result + Text("(\(component)")
.appFont(size: 16, weight: .regular)
.foregroundColor(.white)
}
}
}
return result
}
}
#Preview {
UserMessageItemView(
message: ServerChatMessage(
messageId: 1,
message: "(만약에) 멈춰 인프피",
profileImageUrl: "",
mine: true,
createdAt: Date().currentTimeMillis(),
messageType: "text",
imageUrl: nil,
price: nil,
hasAccess: true
)
)
.padding()
.background(Color.black)
}