aboutsummaryrefslogtreecommitdiff
path: root/Hotline
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2023-12-22 23:29:20 -0800
committerDustin Mierau <dustin@mierau.me>2023-12-22 23:29:20 -0800
commit8a2a78d62f1cb9a75fe3fc5254f76cc4ffdd26f7 (patch)
tree3501ad6fdef17c1823055a7186509eac5dfc76b2 /Hotline
parent141ba771eddd2e504a0f29bafd7b9f7c032b72c0 (diff)
Added Save Chat button to Chat toolbar.
Diffstat (limited to 'Hotline')
-rw-r--r--Hotline/Application.swift12
-rw-r--r--Hotline/Utility/TextDocument.swift29
-rw-r--r--Hotline/macOS/ChatView.swift85
-rw-r--r--Hotline/macOS/ServerView.swift42
4 files changed, 111 insertions, 57 deletions
diff --git a/Hotline/Application.swift b/Hotline/Application.swift
index 2e35e3c..65833f1 100644
--- a/Hotline/Application.swift
+++ b/Hotline/Application.swift
@@ -36,6 +36,18 @@ struct Application: App {
ServerView(server: s)
.frame(minWidth: 400, minHeight: 300)
.environment(Hotline(trackerClient: HotlineTrackerClient(), client: HotlineClient()))
+ .toolbar {
+ ToolbarItem(placement: .navigation) {
+ Image(systemName: "globe.americas.fill")
+ .resizable()
+ .scaledToFit()
+// .foregroundColor(.secondary)
+ .frame(width: 22)
+// .fontWeight(.light)
+// Text("􀵲")
+// .font(.system(size: 22, weight: .ultraLight))
+ }
+ }
}
}
.defaultSize(width: 700, height: 800)
diff --git a/Hotline/Utility/TextDocument.swift b/Hotline/Utility/TextDocument.swift
new file mode 100644
index 0000000..3904a21
--- /dev/null
+++ b/Hotline/Utility/TextDocument.swift
@@ -0,0 +1,29 @@
+import Foundation
+import UniformTypeIdentifiers
+import SwiftUI
+
+struct TextFile: FileDocument {
+ // tell the system we support only plain text
+ static var readableContentTypes = [UTType.plainText, UTType.utf8PlainText]
+
+ // by default our document is empty
+ var text = ""
+
+ // a simple initializer that creates new, empty documents
+ init(initialText: String = "") {
+ text = initialText
+ }
+
+ // this initializer loads data that has been saved previously
+ init(configuration: ReadConfiguration) throws {
+ if let data = configuration.file.regularFileContents {
+ text = String(decoding: data, as: UTF8.self)
+ }
+ }
+
+ // this will be called when the system wants to write our data to disk
+ func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
+ let data = Data(text.utf8)
+ return FileWrapper(regularFileWithContents: data)
+ }
+}
diff --git a/Hotline/macOS/ChatView.swift b/Hotline/macOS/ChatView.swift
index 2b6d10b..618fd12 100644
--- a/Hotline/macOS/ChatView.swift
+++ b/Hotline/macOS/ChatView.swift
@@ -16,6 +16,10 @@ struct ChatView: View {
@FocusState private var focusedField: FocusedField?
@Namespace var bottomID
+
+ @State private var showingExporter: Bool = false
+
+ @State private var chatDocument: TextFile = TextFile()
var body: some View {
NavigationStack {
@@ -32,13 +36,13 @@ struct ChatView: View {
// MARK: Agreement
if msg.type == .agreement {
- VStack(alignment: .center) {
+ VStack(alignment: .center, spacing: 16) {
FileImageView()
.environment(self.model)
.frame(maxWidth: 468.0)
- .clipShape(RoundedRectangle(cornerRadius: 8))
-
+ .clipShape(RoundedRectangle(cornerRadius: 3))
+
VStack(spacing: 0) {
ScrollView(.vertical) {
HStack {
@@ -52,28 +56,10 @@ struct ChatView: View {
}
.scrollBounceBehavior(.basedOnSize)
.frame(maxHeight: 375)
-
-// Divider()
-//
-// HStack {
-// Button("Disagree") {
-// dismiss()
-// }
-// .controlSize(.large)
-//
-// Spacer()
-//
-// Button("Agree") {
-// model.sendAgree()
-// }
-// .controlSize(.large)
-// .keyboardShortcut(.defaultAction)
-// }
-// .padding(16)
}
.background(Color(white: colorScheme == .light ? 0.0 : 1.0).opacity(0.05))
.frame(maxWidth: 468.0)
- .clipShape(RoundedRectangle(cornerRadius: 8))
+ .clipShape(RoundedRectangle(cornerRadius: 3))
}
.frame(maxWidth: .infinity)
.padding()
@@ -177,6 +163,61 @@ struct ChatView: View {
.navigationTitle(self.model.serverTitle)
.navigationSubtitle(self.model.users.count > 0 ? "^[\(self.model.users.count) user](inflect: true) online" : "")
.background(Color(nsColor: .textBackgroundColor))
+ .toolbar {
+ ToolbarItem(placement: .primaryAction) {
+ Button {
+ if prepareChatDocument() {
+ showingExporter = true
+ }
+ } label: {
+ Image(systemName: "square.and.arrow.up")
+ }.help("Save Chat")
+ }
+ }
+ .fileExporter(isPresented: $showingExporter, document: chatDocument, contentType: .utf8PlainText, defaultFilename: "\(model.serverTitle) Chat") { result in
+// switch result {
+// case .success(let url):
+// print("Saved to \(url)")
+//
+// case .failure(let error):
+// print(error.localizedDescription)
+// }
+ self.chatDocument.text = ""
+ }
+ }
+
+ private func prepareChatDocument() -> Bool {
+ var text: String = String()
+
+ self.chatDocument.text = ""
+
+ for msg in model.chat {
+ if msg.type == .agreement {
+ text.append(msg.text)
+ text.append("\n\n")
+ }
+ else if msg.type == .message {
+ if let username = msg.username {
+ text.append("\(username): \(msg.text)")
+ }
+ else {
+ text.append(msg.text)
+ }
+ text.append("\n")
+ }
+ else if msg.type == .status {
+ text.append(msg.text)
+ text.append("\n")
+ }
+ }
+
+ if text.isEmpty {
+ return false
+ }
+
+ self.chatDocument.text = text
+
+ return true
}
}
diff --git a/Hotline/macOS/ServerView.swift b/Hotline/macOS/ServerView.swift
index 7476b3c..7ad344e 100644
--- a/Hotline/macOS/ServerView.swift
+++ b/Hotline/macOS/ServerView.swift
@@ -131,32 +131,6 @@ struct ServerView: View {
var body: some View {
NavigationSplitView {
List(selection: $selection) {
-
-// VStack(spacing: 0) {
-// bannerImage
-// .resizable()
-// .aspectRatio(contentMode: .fit)
-// .frame(maxWidth: .infinity, minHeight: 60, alignment: .topLeading)
-// .clipped()
-// }
-// .frame(maxWidth: .infinity)
-// }
-// else {
-// HStack {
-// Text(server.name ?? "")
-// .fontWeight(.medium)
-// .lineLimit(2)
-// .font(.title3)
-// .multilineTextAlignment(.center)
-// .padding()
-// }
-// .selectionDisabled()
-// .frame(maxWidth: .infinity, minHeight: 60)
-// .background(VisualEffectView(material: .titlebar, blendingMode: .withinWindow).cornerRadius(16))
-// .cornerRadius(10)
-// .tag(MenuItem(name: "title", image: "", type: .banner))
-// .padding(.bottom, 16)
-// }
if model.status != .loggedIn {
HStack {
@@ -169,19 +143,17 @@ struct ServerView: View {
}
if model.status == .loggedIn {
- Section(model.serverTitle) {
- ForEach(ServerView.menuItems) { menuItem in
- if let minServerVersion = menuItem.serverVersion {
- if let v = model.serverVersion, v >= minServerVersion {
- ListItemView(icon: menuItem.image, title: menuItem.name)
- .tag(menuItem)
- }
- }
- else {
+ ForEach(ServerView.menuItems) { menuItem in
+ if let minServerVersion = menuItem.serverVersion {
+ if let v = model.serverVersion, v >= minServerVersion {
ListItemView(icon: menuItem.image, title: menuItem.name)
.tag(menuItem)
}
}
+ else {
+ ListItemView(icon: menuItem.image, title: menuItem.name)
+ .tag(menuItem)
+ }
}
if model.users.count > 0 {