aboutsummaryrefslogtreecommitdiff
path: root/Hotline/macOS/Chat
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2025-11-07 10:19:42 -0800
committerDustin Mierau <dustin@mierau.me>2025-11-07 10:19:42 -0800
commit87f08cf60a5d7c1cf618463916cbac4dab88e0f8 (patch)
treec15a94443801beff5fcb8ac5d5dbc8276726ee39 /Hotline/macOS/Chat
parentbcf36ef614aa46ae3d8e714add470f749fdf3714 (diff)
Massive refactor of transfer cients (new folder upload implementation), brand new async version of NetSocket, and a rewritten Hotline view model. New cross-server transfers UI.
Diffstat (limited to 'Hotline/macOS/Chat')
-rw-r--r--Hotline/macOS/Chat/ChatView.swift77
1 files changed, 50 insertions, 27 deletions
diff --git a/Hotline/macOS/Chat/ChatView.swift b/Hotline/macOS/Chat/ChatView.swift
index 0795856..e1ec73a 100644
--- a/Hotline/macOS/Chat/ChatView.swift
+++ b/Hotline/macOS/Chat/ChatView.swift
@@ -88,7 +88,7 @@ struct ChatMessageView: View {
}
struct ChatView: View {
- @Environment(Hotline.self) private var model: Hotline
+ @Environment(HotlineState.self) private var model: HotlineState
@Environment(\.colorScheme) var colorScheme
@Environment(\.dismiss) var dismiss
@@ -98,12 +98,14 @@ struct ChatView: View {
@State private var searchQuery: String = ""
@State private var searchResults: [ChatMessage] = []
@State private var isSearching: Bool = false
+
+ @State private var stableBannerImage: Image?
@FocusState private var focusedField: FocusedField?
@Namespace var bottomID
- private var bindableModel: Bindable<Hotline> {
+ private var bindableModel: Bindable<HotlineState> {
Bindable(model)
}
@@ -114,7 +116,36 @@ struct ChatView: View {
var displayedMessages: [ChatMessage] {
searchQuery.isEmpty ? model.chat : searchResults
}
-
+
+// private var blurredBannerImage: some View {
+// self.stableBannerImage?
+// .resizable()
+// .scaledToFit()
+// .frame(maxWidth: 468.0)
+// .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
+// .offset(y: 1.5)
+// .blur(radius: 4)
+// .opacity(0.2)
+// }
+
+ private var bannerView: some View {
+ ZStack {
+ self.stableBannerImage?
+ .resizable()
+ .scaledToFit()
+ .frame(maxWidth: 468.0)
+ .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
+ .offset(y: 1.5)
+ .blur(radius: 4)
+ .opacity(0.2)
+ self.stableBannerImage?
+ .resizable()
+ .scaledToFit()
+ .frame(maxWidth: 468.0)
+ .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
+ }
+ }
+
var body: some View {
@Bindable var bindModel = model
@@ -129,28 +160,10 @@ struct ChatView: View {
ForEach(displayedMessages) { msg in
if msg.type == .agreement {
VStack(alignment: .center, spacing: 16) {
- if let bannerImage = self.model.bannerImage {
- HStack(spacing: 0) {
- Spacer(minLength: 0)
- ZStack {
- Image(nsImage: bannerImage)
- .resizable()
- .scaledToFit()
- .frame(maxWidth: 468.0)
- .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
- .offset(y: 1.5)
- .blur(radius: 4)
- .opacity(0.2)
-
- Image(nsImage: bannerImage)
- .resizable()
- .scaledToFit()
- .frame(maxWidth: 468.0)
- .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
- }
-
- Spacer(minLength: 0)
- }
+ HStack(spacing: 0) {
+ Spacer(minLength: 0)
+ self.bannerView
+ Spacer(minLength: 0)
}
ServerAgreementView(text: msg.text)
@@ -218,7 +231,11 @@ struct ChatView: View {
.multilineTextAlignment(.leading)
.onSubmit {
if !model.chatInput.isEmpty {
- model.sendChat(model.chatInput, announce: NSEvent.modifierFlags.contains(.shift))
+ let message = model.chatInput
+ let announce = NSEvent.modifierFlags.contains(.shift)
+ Task {
+ try? await model.sendChat(message, announce: announce)
+ }
}
model.chatInput = ""
}
@@ -252,6 +269,12 @@ struct ChatView: View {
.onChange(of: searchQuery) {
performSearch()
}
+ .onChange(of: model.bannerImage) { oldValue, newValue in
+ stableBannerImage = newValue
+ }
+ .onAppear {
+ stableBannerImage = model.bannerImage
+ }
// .toolbar {
// ToolbarItem(placement: .primaryAction) {
// Button {
@@ -318,5 +341,5 @@ struct ChatView: View {
#Preview {
ChatView()
- .environment(Hotline(trackerClient: HotlineTrackerClient(), client: HotlineClient()))
+ .environment(HotlineState())
}