aboutsummaryrefslogtreecommitdiff
path: root/Hotline/macOS/Board
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2025-11-27 23:38:04 +0100
committerRuben Beltran del Rio <git@r.bdr.sh>2025-11-27 23:38:04 +0100
commit213710bf5bd6413c747bf126db50816ef5de5a6e (patch)
tree912f8cf87955a08077c92fea8ad934f50b7ab975 /Hotline/macOS/Board
parentf466b21dc02f78c984ba6748e703f6780a7a0db4 (diff)
parent6a95b53616a4abfa306ddce43151cf4fefbd20ed (diff)
Merge remote-tracking branch 'upstream/main'
Diffstat (limited to 'Hotline/macOS/Board')
-rw-r--r--Hotline/macOS/Board/MessageBoardEditorView.swift121
-rw-r--r--Hotline/macOS/Board/MessageBoardView.swift91
2 files changed, 212 insertions, 0 deletions
diff --git a/Hotline/macOS/Board/MessageBoardEditorView.swift b/Hotline/macOS/Board/MessageBoardEditorView.swift
new file mode 100644
index 0000000..34a4bbb
--- /dev/null
+++ b/Hotline/macOS/Board/MessageBoardEditorView.swift
@@ -0,0 +1,121 @@
+import SwiftUI
+
+private enum FocusFields {
+ case body
+}
+
+struct MessageBoardEditorView: View {
+ @Environment(\.controlActiveState) private var controlActiveState
+ @Environment(\.colorScheme) private var colorScheme
+ @Environment(\.dismiss) private var dismiss
+ @Environment(HotlineState.self) private var model: HotlineState
+
+ @State private var text: String = ""
+ @State private var sending: Bool = false
+
+ @FocusState private var focusedField: FocusFields?
+
+ func sendPost() async {
+ sending = true
+
+ let cleanedText = text.trimmingCharacters(in: .whitespacesAndNewlines)
+
+ try? await model.postToMessageBoard(text: cleanedText)
+ let _ = try? await model.getMessageBoard()
+
+// let success = await model.postNewsArticle(title: title, body: text, at: path, parentID: parentID)
+// if success {
+// await model.getNewsList(at: path)
+// }
+
+ sending = false
+ }
+
+ var body: some View {
+ VStack(alignment: .leading, spacing: 0) {
+ HStack(alignment: .center, spacing: 0) {
+ Button {
+ dismiss()
+ } label: {
+ Image(systemName: "xmark")
+ .resizable()
+ .scaledToFit()
+ .frame(width: 14, height: 14)
+ .opacity(0.5)
+ }
+ .buttonStyle(.plain)
+ .frame(width: 16, height: 16)
+
+ Spacer()
+
+ // Image("Message Board Post")
+ // .resizable()
+ // .scaledToFit()
+ // .frame(width: 16, height: 16)
+ // .padding(.trailing, 6)
+
+ Text("New Post")
+ .fontWeight(.semibold)
+ .lineLimit(1)
+ .truncationMode(.middle)
+
+ Spacer()
+
+ if sending {
+ ProgressView()
+ .controlSize(.small)
+ .frame(width: 22, height: 22)
+ } else {
+ Button {
+ sending = true
+ Task {
+ try? await model.postToMessageBoard(text: text)
+ let _ = try? await model.getMessageBoard()
+ Task { @MainActor in
+ sending = false
+ dismiss()
+ }
+ }
+ } label: {
+ Image(systemName: "arrow.up.circle.fill")
+ .resizable()
+ .renderingMode(.template)
+ .scaledToFit()
+ .foregroundColor(
+ text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
+ ? .secondary : .accentColor)
+ }
+ .buttonStyle(.plain)
+ .frame(width: 22, height: 22)
+ .help("Post to Message Board")
+ .disabled(text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
+ }
+ }
+ .frame(maxWidth: .infinity)
+ .padding()
+
+ Divider()
+
+ BetterTextEditor(text: $text)
+ .betterEditorFont(NSFont.systemFont(ofSize: 14.0))
+ .betterEditorAutomaticSpellingCorrection(true)
+ .betterEditorTextInset(.init(width: 16, height: 18))
+ .lineSpacing(20)
+ .background(Color(nsColor: .textBackgroundColor))
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
+ .focused($focusedField, equals: .body)
+ }
+ .frame(
+ minWidth: 300, idealWidth: 450, maxWidth: .infinity, minHeight: 300, idealHeight: 500,
+ maxHeight: .infinity
+ )
+ .background(Color(nsColor: .textBackgroundColor))
+ .presentationCompactAdaptation(.sheet)
+ .onAppear {
+ focusedField = .body
+ }
+ .onDisappear {
+ dismiss()
+ }
+ }
+}
diff --git a/Hotline/macOS/Board/MessageBoardView.swift b/Hotline/macOS/Board/MessageBoardView.swift
new file mode 100644
index 0000000..be039d8
--- /dev/null
+++ b/Hotline/macOS/Board/MessageBoardView.swift
@@ -0,0 +1,91 @@
+import SwiftUI
+
+struct MessageBoardView: View {
+ @Environment(HotlineState.self) private var model: HotlineState
+
+ @State private var composerDisplayed: Bool = false
+ @State private var composerText: String = ""
+
+ var body: some View {
+ NavigationStack {
+ if self.model.access?.contains(.canReadMessageBoard) != true {
+ self.disabledBoardView
+ }
+ else if self.model.messageBoardLoaded && self.model.messageBoard.isEmpty {
+ self.emptyBoardView
+ }
+ else {
+ self.messageBoardView
+ }
+ }
+ .sheet(isPresented: $composerDisplayed) {
+ MessageBoardEditorView()
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
+ .frame(idealWidth: 450, idealHeight: 350)
+ }
+ .toolbar {
+ ToolbarItem(placement:.primaryAction) {
+ Button {
+ self.composerDisplayed.toggle()
+ } label: {
+ Image(systemName: "square.and.pencil")
+ }
+ .disabled((self.model.access?.contains(.canPostMessageBoard) != true) || (self.model.access?.contains(.canReadMessageBoard) != true))
+ .help("Post to Message Board")
+ }
+ }
+ .task {
+ if !self.model.messageBoardLoaded {
+ let _ = try? await self.model.getMessageBoard()
+ }
+ }
+ }
+
+ private var disabledBoardView: some View {
+ ContentUnavailableView {
+ Label("No Message Board", systemImage: "quote.bubble")
+ } description: {
+ Text("This server has turned off their message board")
+ }
+ }
+
+ private var emptyBoardView: some View {
+ ContentUnavailableView {
+ Label("No Posts", systemImage: "quote.bubble")
+ } description: {
+ Text("Message board posts will appear here")
+ }
+ }
+
+ private var messageBoardView: some View {
+ ScrollView {
+ LazyVStack(alignment: .leading) {
+ ForEach(self.model.messageBoard, id: \.self) { msg in
+ Text(LocalizedStringKey(msg))
+ .tint(Color("Link Color"))
+ .lineLimit(100)
+ .lineSpacing(4)
+ .padding()
+ .textSelection(.enabled)
+ Divider()
+ }
+ }
+ Spacer()
+ }
+ .overlay {
+ if !self.model.messageBoardLoaded {
+ VStack {
+ ProgressView()
+ .controlSize(.large)
+ }
+ .frame(maxWidth: .infinity)
+ }
+ }
+ .background(Color(nsColor: .textBackgroundColor))
+ }
+}
+
+#Preview {
+ MessageBoardView()
+ .environment(HotlineState())
+}