Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 37 additions & 10 deletions Mactrix/Views/ChatView/ChatInputView/ChatInputView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import OSLog
import SwiftUI

struct ChatInputView: View {
@Environment(\.accessibilityReduceTransparency) var reduceTransparency

let room: Room
let timeline: LiveTimeline
@Binding var replyTo: MatrixRustSDK.EventTimelineItem?
Expand Down Expand Up @@ -115,22 +117,21 @@ struct ChatInputView: View {
return .ready(content: replyTo.content, sender: replyTo.sender, senderProfile: replyTo.senderProfile, timestamp: replyTo.timestamp, eventOrTransactionId: replyTo.eventOrTransactionId)
}

var body: some View {
var content: some View {
VStack(alignment: .leading) {
if let replyEmbeddedDetails {
EmbeddedMessageView(embeddedEvent: replyEmbeddedDetails) {
replyTo = nil
}
}
ChatTextView(text: $chatInput, disabled: !isDraftLoaded, onSubmit: { Task { await sendMessage() }})
ChatTextView(
text: $chatInput,
placeholder: "Message \(room.displayName() ?? "room")",
disabled: !isDraftLoaded,
onSubmit: { Task { await sendMessage() } }
)
}
.font(.system(size: .init(fontSize)))
.background(Color(NSColor.textBackgroundColor))
.cornerRadius(4)
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color(NSColor.separatorColor), lineWidth: 1)
)
.task(id: chatInput) {
await chatInputChanged()
}
Expand All @@ -142,8 +143,34 @@ struct ChatInputView: View {
// (in case the draft holds a reply)
await loadDraft()
}
.pointerStyle(.horizontalText)
.padding([.horizontal, .bottom], 10)
}

@available(macOS 26.0, *)
var tahoeView: some View {
content
.glassEffect(in: .rect(cornerRadius: 16.0))
.padding(.horizontal)
.padding(.bottom, 10)
}

var oldView: some View {
content
.background(Color(NSColor.textBackgroundColor))
.cornerRadius(4)
.overlay(
RoundedRectangle(cornerRadius: 16.0)
.stroke(Color(NSColor.separatorColor), lineWidth: 1)
)
.padding(.horizontal)
.padding(.bottom, 10)
}

var body: some View {
if #available(macOS 26.0, *), !reduceTransparency {
tahoeView
} else {
oldView
}
}
}

Expand Down
24 changes: 21 additions & 3 deletions Mactrix/Views/ChatView/ChatInputView/ChatTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ struct ChatTextView: NSViewRepresentable {
typealias NSViewRepresentableType = NSTextView

let text: Binding<String>
let placeholder: String
let disabled: Bool
let onSubmit: () -> Void

Expand All @@ -14,10 +15,18 @@ struct ChatTextView: NSViewRepresentable {

textView.onSubmit = onSubmit

textView.placeholderAttributedString = NSAttributedString(
string: placeholder,
attributes: [.foregroundColor: NSColor.secondaryLabelColor]
)

textView.backgroundColor = .clear
textView.drawsBackground = false

context.coordinator.textView = textView
textView.delegate = context.coordinator

textView.textContainerInset = NSSize(width: DynamicTextView.padding, height: DynamicTextView.padding)
textView.textContainerInset = DynamicTextView.padding

textView.isVerticallyResizable = true
textView.isHorizontallyResizable = false
Expand All @@ -39,6 +48,13 @@ struct ChatTextView: NSViewRepresentable {
textView.invalidateIntrinsicContentSize()
}

if textView.placeholderAttributedString?.string != placeholder {
textView.placeholderAttributedString = NSAttributedString(
string: placeholder,
attributes: [.foregroundColor: NSColor.secondaryLabelColor]
)
}

if textView.isEditable != !disabled {
textView.isEditable = !disabled
textView.isSelectable = !disabled
Expand Down Expand Up @@ -72,7 +88,9 @@ struct ChatTextView: NSViewRepresentable {
}

class DynamicTextView: NSTextView {
static let padding = 4
@objc var placeholderAttributedString: NSAttributedString?

static let padding = NSSize(width: 10, height: 10)

var onSubmit: (() -> Void)?

Expand All @@ -86,7 +104,7 @@ class DynamicTextView: NSTextView {
let usedRect = manager.usedRect(for: container)

// Return a flexible width but a fixed height based on text
return NSSize(width: NSView.noIntrinsicMetric, height: ceil(usedRect.height) + CGFloat(2 * Self.padding))
return NSSize(width: NSView.noIntrinsicMetric, height: ceil(usedRect.height) + CGFloat(2 * Self.padding.height))
}

override func setFrameSize(_ newSize: NSSize) {
Expand Down
1 change: 1 addition & 0 deletions Mactrix/Views/ChatView/ChatView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct ChatJoinedRoom: View {

var body: some View {
TimelineViewRepresentable(timeline: timeline, items: timeline.timelineItems)
.ignoresSafeArea(edges: .top)
.safeAreaInset(edge: .bottom, spacing: 8) {
ChatInputView(room: room.room, timeline: timeline, replyTo: $timeline.sendReplyTo)
}
Expand Down
7 changes: 5 additions & 2 deletions Mactrix/Views/ChatView/TimelineView/TimelineTableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ class TimelineViewController: NSViewController {

scrollView.documentView = tableView
scrollView.hasVerticalScroller = true

scrollView.automaticallyAdjustsContentInsets = false

scrollView.drawsBackground = false
tableView.backgroundColor = .clear
view = scrollView
Expand Down Expand Up @@ -235,7 +238,7 @@ class TimelineViewController: NSViewController {
// If the IDs haven't changed, reload all rows in place (content-only update: reactions, read receipts, etc.)
// Reloads all rows rather than just visible ones to avoid stale content in NSTableView's prepared/cached views.
if oldIds == newIds {
tableView.reloadData(forRowIndexes: IndexSet(integersIn: 0..<self.timelineItems.count),
tableView.reloadData(forRowIndexes: IndexSet(integersIn: 0 ..< self.timelineItems.count),
columnIndexes: IndexSet(integer: 0))
return
}
Expand All @@ -253,7 +256,7 @@ class TimelineViewController: NSViewController {
DispatchQueue.main.async { [weak self] in
guard let self else { return }
let visibleRows = tableView.rows(in: tableView.visibleRect)
tableView.noteHeightOfRows(withIndexesChanged: IndexSet(integersIn: visibleRows.lowerBound..<visibleRows.upperBound))
tableView.noteHeightOfRows(withIndexesChanged: IndexSet(integersIn: visibleRows.lowerBound ..< visibleRows.upperBound))
}
}

Expand Down
Loading