Render messages on watchOS

This commit is contained in:
2025-10-30 02:15:51 +08:00
parent 6fc94001b3
commit 983ae2a1fc

View File

@@ -282,10 +282,31 @@ struct ChatRoomView: View {
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
} else { } else {
List(messages) { message in ScrollViewReader { scrollView in
ChatMessageItem(message: message) ScrollView {
LazyVStack(alignment: .leading, spacing: 8) {
ForEach(messages) { message in
ChatMessageItem(message: message)
}
}
.padding(.horizontal)
.padding(.vertical, 8)
}
.onAppear {
// Scroll to bottom when messages load
if let lastMessage = messages.last {
scrollView.scrollTo(lastMessage.id, anchor: .bottom)
}
}
.onChange(of: messages.count) { _ in
// Scroll to bottom when new messages arrive
if let lastMessage = messages.last {
withAnimation {
scrollView.scrollTo(lastMessage.id, anchor: .bottom)
}
}
}
} }
.listStyle(.plain)
} }
} }
.navigationTitle(room.name ?? "Chat") .navigationTitle(room.name ?? "Chat")
@@ -306,6 +327,7 @@ struct ChatRoomView: View {
token: token, token: token,
serverUrl: serverUrl serverUrl: serverUrl
) )
// Sort with newest messages first (for flipped list, newest will appear at bottom)
self.messages = messages.sorted { $0.createdAt < $1.createdAt } self.messages = messages.sorted { $0.createdAt < $1.createdAt }
} catch { } catch {
print("[watchOS] Error loading messages: \(error.localizedDescription)") print("[watchOS] Error loading messages: \(error.localizedDescription)")
@@ -318,21 +340,61 @@ struct ChatRoomView: View {
struct ChatMessageItem: View { struct ChatMessageItem: View {
let message: SnChatMessage let message: SnChatMessage
@EnvironmentObject var appState: AppState
@StateObject private var avatarLoader = ImageLoader()
private var avatarPictureId: String? {
message.sender.account.profile.picture?.id
}
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: 4) { HStack(alignment: .top, spacing: 8) {
HStack { // Avatar
Text(message.sender.account.nick) Group {
.font(.system(size: 12, weight: .medium)) if avatarLoader.isLoading {
Spacer() ProgressView()
Text(message.createdAt, style: .time) .frame(width: 24, height: 24)
.font(.system(size: 10)) } else if let image = avatarLoader.image {
.foregroundColor(.secondary) image
.resizable()
.frame(width: 24, height: 24)
.clipShape(Circle())
} else {
Circle()
.fill(Color.gray.opacity(0.3))
.frame(width: 24, height: 24)
.overlay(
Text(message.sender.account.nick.prefix(1).uppercased())
.font(.system(size: 10, weight: .medium))
.foregroundColor(.primary)
)
}
}
.task(id: avatarPictureId) {
if let serverUrl = appState.serverUrl,
let pictureId = avatarPictureId,
let imageUrl = getAttachmentUrl(for: pictureId, serverUrl: serverUrl),
let token = appState.token {
await avatarLoader.loadImage(from: imageUrl, token: token)
}
} }
if let content = message.content { VStack(alignment: .leading, spacing: 4) {
Text(content) HStack {
.font(.system(size: 14)) Text(message.sender.account.nick)
.font(.system(size: 12, weight: .medium))
Spacer()
Text(message.createdAt, style: .time)
.font(.system(size: 10))
.foregroundColor(.secondary)
}
if let content = message.content {
Text(content)
.font(.system(size: 14))
.lineLimit(nil)
.fixedSize(horizontal: false, vertical: true)
}
} }
} }
.padding(.vertical, 4) .padding(.vertical, 4)