mirror of
https://github.com/stoatchat/for-ios.git
synced 2026-07-19 16:43:34 -04:00
203 lines
8.3 KiB
Swift
203 lines
8.3 KiB
Swift
//
|
|
// Message.swift
|
|
// Revolt
|
|
//
|
|
// Created by Zomatree on 21/04/2023.
|
|
//
|
|
|
|
import Foundation
|
|
import SwiftUI
|
|
import Types
|
|
|
|
struct MessageView: View {
|
|
private enum AvatarSize {
|
|
case regular
|
|
case compact
|
|
|
|
var sizes: (CGFloat, CGFloat, CGFloat) {
|
|
switch self {
|
|
case .regular:
|
|
return (32, 16, 4)
|
|
case .compact:
|
|
return (16, 8, 2)
|
|
}
|
|
}
|
|
}
|
|
@StateObject var viewModel: MessageContentsViewModel
|
|
|
|
@EnvironmentObject var viewState: ViewState
|
|
|
|
@State var showReportSheet: Bool = false
|
|
@State var isStatic: Bool = false
|
|
@State var onlyShowContent: Bool = false
|
|
|
|
var isCompactMode: (Bool, Bool) {
|
|
return TEMP_IS_COMPACT_MODE
|
|
}
|
|
|
|
private func pfpView(size: AvatarSize) -> some View {
|
|
ZStack(alignment: .topLeading) {
|
|
Avatar(user: viewModel.author, member: viewModel.member, masquerade: viewModel.message.masquerade, webhook: viewModel.message.webhook, width: size.sizes.0, height: size.sizes.0)
|
|
.onTapGesture {
|
|
if !isStatic || viewModel.message.webhook != nil {
|
|
viewState.openUserSheet(withId: viewModel.author.id, server: viewModel.server?.id)
|
|
}
|
|
}
|
|
|
|
if viewModel.message.masquerade != nil {
|
|
Avatar(user: viewModel.author, member: viewModel.member, webhook: viewModel.message.webhook, width: size.sizes.1, height: size.sizes.1)
|
|
.padding(.leading, -size.sizes.2)
|
|
.padding(.top, -size.sizes.2)
|
|
}
|
|
}
|
|
}
|
|
|
|
private var nameView: some View {
|
|
let name = viewModel.message.webhook?.name
|
|
?? viewModel.message.masquerade?.name
|
|
?? viewModel.member?.nickname
|
|
?? viewModel.author.display_name
|
|
?? viewModel.author.username
|
|
|
|
return Text(verbatim: name)
|
|
.onTapGesture {
|
|
if !isStatic || viewModel.message.webhook != nil {
|
|
viewState.openUserSheet(withId: viewModel.author.id, server: viewModel.server?.id)
|
|
}
|
|
}
|
|
.foregroundStyle(viewModel.member?.displayColour(theme: viewState.theme, server: viewModel.server!) ?? AnyShapeStyle(viewState.theme.foreground.color))
|
|
.font(.body)
|
|
.fontWeight(.bold)
|
|
}
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
if let replies = viewModel.message.replies {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
ForEach(replies, id: \.self) { id in
|
|
MessageReplyView(
|
|
mentions: viewModel.$message.mentions,
|
|
channelScrollPosition: viewModel.channelScrollPosition,
|
|
id: id,
|
|
server: viewModel.server,
|
|
channel: viewModel.channel
|
|
)
|
|
.padding(.leading, 48)
|
|
}
|
|
}
|
|
}
|
|
|
|
if viewModel.message.system != nil {
|
|
SystemMessageView(message: $viewModel.message)
|
|
} else {
|
|
if isCompactMode.0 {
|
|
HStack(alignment: .top, spacing: 4) {
|
|
HStack(alignment: .center, spacing: 4) {
|
|
Text(createdAt(id: viewModel.message.id).formatted(Date.FormatStyle().hour(.twoDigits(amPM: .omitted)).minute(.twoDigits)))
|
|
.font(.caption)
|
|
.foregroundStyle(viewState.theme.foreground2)
|
|
|
|
if isCompactMode.1 {
|
|
pfpView(size: .compact)
|
|
}
|
|
|
|
nameView
|
|
|
|
if viewModel.author.bot != nil {
|
|
MessageBadge(text: String(localized: "Bot"), color: viewState.theme.accent.color)
|
|
}
|
|
}
|
|
|
|
MessageContentsView(viewModel: viewModel, isStatic: isStatic, onlyShowContent: onlyShowContent)
|
|
|
|
if viewModel.message.edited != nil {
|
|
Text("(edited)")
|
|
.font(.caption)
|
|
.foregroundStyle(.gray)
|
|
}
|
|
}
|
|
} else {
|
|
HStack(alignment: .top) {
|
|
pfpView(size: .regular)
|
|
.padding(.top, 2)
|
|
.padding(.trailing, 8)
|
|
|
|
VStack(alignment: .leading, spacing: 0) {
|
|
HStack {
|
|
nameView
|
|
|
|
if viewModel.author.bot != nil {
|
|
MessageBadge(text: String(localized: "Bot"), color: viewState.theme.accent.color)
|
|
}
|
|
|
|
if viewModel.message.webhook != nil {
|
|
MessageBadge(text: String(localized: "Webhook"), color: viewState.theme.accent.color)
|
|
|
|
}
|
|
|
|
Text(createdAt(id: viewModel.message.id).formatted(Date.FormatStyle().hour(.twoDigits(amPM: .omitted)).minute(.twoDigits)))
|
|
.font(.caption)
|
|
.foregroundStyle(viewState.theme.foreground2)
|
|
|
|
if viewModel.message.edited != nil {
|
|
Text("(edited)")
|
|
.font(.caption)
|
|
.foregroundStyle(.gray)
|
|
}
|
|
}
|
|
|
|
MessageContentsView(viewModel: viewModel, isStatic: isStatic, onlyShowContent: onlyShowContent)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.font(Font.system(size: 14.0))
|
|
.listRowSeparator(.hidden)
|
|
.environment(\.currentMessage, viewModel)
|
|
}
|
|
}
|
|
|
|
//struct GhostMessageView: View {
|
|
// @EnvironmentObject var viewState: ViewState
|
|
//
|
|
// var message: QueuedMessage
|
|
//
|
|
// var body: some View {
|
|
// HStack(alignment: .top) {
|
|
// Avatar(user: viewState.currentUser!, width: 16, height: 16)
|
|
// VStack(alignment: .leading) {
|
|
// HStack {
|
|
// Text(viewState.currentUser!.username)
|
|
// .fontWeight(.heavy)
|
|
// Text(createdAt(id: message.nonce).formatted())
|
|
// }
|
|
// Contents(text: message.content)
|
|
// //.frame(maxWidth: .infinity, alignment: .leading)
|
|
// }
|
|
// //.frame(maxWidth: .infinity, alignment: .leading)
|
|
// }
|
|
// .listRowSeparator(.hidden)
|
|
// }
|
|
//}
|
|
|
|
struct MessageView_Previews: PreviewProvider {
|
|
static var viewState: ViewState = ViewState.preview()
|
|
@State static var message = viewState.messages["01HDEX6M2E3SHY8AC2S6B9SEAW"]!
|
|
@State static var author = viewState.users[message.author]!
|
|
@State static var member = viewState.members["0"]!["0"]
|
|
@State static var channel = viewState.channels["0"]!
|
|
@State static var server = viewState.servers["0"]
|
|
@State static var replies: [Reply] = []
|
|
@State static var highlighted: String? = nil
|
|
|
|
static var previews: some View {
|
|
ScrollViewReader { p in
|
|
List {
|
|
MessageView(viewModel: MessageContentsViewModel(viewState: viewState, message: $message, author: $author, member: $member, server: $server, channel: $channel, replies: $replies, channelScrollPosition: ChannelScrollController(proxy: p, highlighted: $highlighted), editing: .constant(nil)), isStatic: false)
|
|
}
|
|
}
|
|
.applyPreviewModifiers(withState: viewState)
|
|
}
|
|
}
|