✨ Render messages on watchOS
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user