From 6d812a2fc007497dcba4276edbecf018ccbd85ef Mon Sep 17 00:00:00 2001 From: glasfisch3000 Date: Wed, 22 Jul 2026 18:21:40 +0200 Subject: [PATCH 1/5] fix x mark when creating new threads --- MactrixLibrary/Sources/UI/Timeline/ThreadTimelineHeader.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MactrixLibrary/Sources/UI/Timeline/ThreadTimelineHeader.swift b/MactrixLibrary/Sources/UI/Timeline/ThreadTimelineHeader.swift index 92d9bc9..5cecff3 100644 --- a/MactrixLibrary/Sources/UI/Timeline/ThreadTimelineHeader.swift +++ b/MactrixLibrary/Sources/UI/Timeline/ThreadTimelineHeader.swift @@ -12,7 +12,7 @@ public struct ThreadTimelineHeader: View { Divider() HStack(alignment: .firstTextBaseline) { Button(action: dismiss) { - Label("Close thread", systemImage: "x.circle.fill") + Label("Close thread", systemImage: "xmark.circle.fill") } .buttonStyle(.plain) .labelStyle(.iconOnly) From c989357f04607e75101a0154f935b82979e8fb4e Mon Sep 17 00:00:00 2001 From: glasfisch3000 Date: Thu, 23 Jul 2026 01:29:43 +0200 Subject: [PATCH 2/5] fix timeline equatable implementation --- Mactrix/Models/LiveTimeline.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mactrix/Models/LiveTimeline.swift b/Mactrix/Models/LiveTimeline.swift index 66e9f54..5430c0a 100644 --- a/Mactrix/Models/LiveTimeline.swift +++ b/Mactrix/Models/LiveTimeline.swift @@ -201,6 +201,6 @@ extension LiveTimeline { extension LiveTimeline: Equatable { public nonisolated static func == (lhs: LiveTimeline, rhs: LiveTimeline) -> Bool { - lhs.room.id == rhs.room.id + lhs.room.id == rhs.room.id && lhs.focusedThreadId == rhs.focusedThreadId } } From ce771ec23e79266f366001c0320ff9a50f500e9b Mon Sep 17 00:00:00 2001 From: glasfisch3000 Date: Thu, 23 Jul 2026 12:10:35 +0200 Subject: [PATCH 3/5] fix thread messages not loading --- Mactrix/Models/LiveTimeline.swift | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Mactrix/Models/LiveTimeline.swift b/Mactrix/Models/LiveTimeline.swift index 5430c0a..d3460e1 100644 --- a/Mactrix/Models/LiveTimeline.swift +++ b/Mactrix/Models/LiveTimeline.swift @@ -80,14 +80,11 @@ public final class LiveTimeline { await listenToTimelineChanges() - // Only main timelines can subscibe to back pagination status - if threadId == nil { - do { - try await listenToPaginationStatus() - } catch { - Logger.liveTimeline.error("Failed to listen to pagination status: \(error)") - } - } + do { + try await listenToPaginationStatus(threadId: threadId) + } catch { + Logger.liveTimeline.error("Failed to listen to pagination status: \(error)") + } } private func listenToTimelineChanges() async { @@ -104,11 +101,17 @@ public final class LiveTimeline { } } - private func listenToPaginationStatus() async throws { + private func listenToPaginationStatus(threadId: String?) async throws { guard let timeline else { return } let listener = AsyncSDKListener() - paginateHandle = try await timeline.subscribeToBackPaginationStatus(listener: listener) + // Only main timelines can subscibe to back pagination status + if threadId == nil { + paginateHandle = try await timeline.subscribeToBackPaginationStatus(listener: listener) + } else { + // if in a thread, instead push one initial status manually to kick off message fetching + listener.publishValue(.idle(hitTimelineStart: false)) + } Task { [weak self] in for await status in listener { From 87dfb59b8c1d90f0495b668efc8ba137b407681a Mon Sep 17 00:00:00 2001 From: glasfisch3000 Date: Thu, 23 Jul 2026 13:27:52 +0200 Subject: [PATCH 4/5] fix green text in verification request view --- Mactrix/Views/Sidebar/SidebarSessionVerification.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mactrix/Views/Sidebar/SidebarSessionVerification.swift b/Mactrix/Views/Sidebar/SidebarSessionVerification.swift index f0f59a3..58e063c 100644 --- a/Mactrix/Views/Sidebar/SidebarSessionVerification.swift +++ b/Mactrix/Views/Sidebar/SidebarSessionVerification.swift @@ -86,7 +86,7 @@ struct SessionVerificationStatusView: View { } .padding(10) .background(Color.green.opacity(0.2)) - .foregroundStyle(Color.green.mix(with: .black, by: 0.5)) + .foregroundStyle(Color.green.mix(with: colorScheme == .light ? .black : .white, by: 0.5)) .clipShape(RoundedRectangle(cornerRadius: 8)) } else { selfVerificationView From a00b2f6da08929514ac1c328480c8790aae1e26f Mon Sep 17 00:00:00 2001 From: glasfisch3000 Date: Thu, 30 Jul 2026 19:14:01 +0200 Subject: [PATCH 5/5] display m.notice events as markdown --- Mactrix/Views/ChatView/ChatMessageView.swift | 6 +-- .../Views/ChatView/FormattedBodyView.swift | 39 ++++++++++++++----- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/Mactrix/Views/ChatView/ChatMessageView.swift b/Mactrix/Views/ChatView/ChatMessageView.swift index 1cb56ed..b107d13 100644 --- a/Mactrix/Views/ChatView/ChatMessageView.swift +++ b/Mactrix/Views/ChatView/ChatMessageView.swift @@ -77,13 +77,9 @@ struct ChatMessageView: View, UI.MessageEventActions { case let .gallery(content: content): Text("Gallery: \(content.body)").textSelection(.enabled) case let .notice(content: content): - Text(content.body.formatAsMarkdown) - .textSelection(.enabled) - .foregroundColor(.secondary) - .fixedSize(horizontal: false, vertical: true) + FormattedBodyView(messageContent: content, color: .secondaryLabelColor) case let .text(content: content): FormattedBodyView(messageContent: content) - //Text(content.body.formatAsMarkdown) case let .location(content: content): Text("Location: \(content.body) \(content.geoUri)").textSelection(.enabled) case let .other(msgtype: msgtype, body: body): diff --git a/Mactrix/Views/ChatView/FormattedBodyView.swift b/Mactrix/Views/ChatView/FormattedBodyView.swift index d1c0f17..3649190 100644 --- a/Mactrix/Views/ChatView/FormattedBodyView.swift +++ b/Mactrix/Views/ChatView/FormattedBodyView.swift @@ -6,26 +6,45 @@ struct FormattedBodyView: View { @AppStorage("fontSize") private var fontSize = 13 let rawBody: String - let htmlBody: String? + var formattedBody: NSAttributedString? = nil + var color: NSColor? = nil - init(messageContent: some MessageContent) { + init(messageContent: some MessageContent) { + self.rawBody = messageContent.body + + if let formatted = messageContent.formatted, formatted.format == .html { + self.formattedBody = parseFormattedBody(formatted.body, baseFontSize: CGFloat(fontSize)) + } + } + + // accepts a custom foreground color (for use in grayed out messages) + init(messageContent: some MessageContent, color: NSColor) { self.rawBody = messageContent.body + self.color = color - if let formatted = messageContent.formatted, formatted.format == .html { - self.htmlBody = formatted.body - } else { - self.htmlBody = nil + if let formatted = messageContent.formatted, formatted.format == .html { + let parsed = parseFormattedBody(formatted.body, baseFontSize: CGFloat(fontSize)) + + let mutable = NSMutableAttributedString(attributedString: parsed) + mutable.addAttribute(.foregroundColor, value: color, range: NSRange(location: 0, length: mutable.length)) + + self.formattedBody = mutable } } var body: some View { - if let htmlBody { - AttributedTextView(attributedString: parseFormattedBody(htmlBody, baseFontSize: CGFloat(fontSize))) + if let formattedBody { + AttributedTextView(attributedString: formattedBody) .fixedSize(horizontal: false, vertical: true) - } else { + } else if let color { Text(rawBody) .textSelection(.enabled) .fixedSize(horizontal: false, vertical: true) - } + .foregroundStyle(Color(nsColor: color)) + } else { + Text(rawBody) + .textSelection(.enabled) + .fixedSize(horizontal: false, vertical: true) + } } }