aboutsummaryrefslogtreecommitdiff
path: root/Hotline
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2023-12-24 12:10:02 -0800
committerDustin Mierau <dustin@mierau.me>2023-12-24 12:10:02 -0800
commita4cbaea0b12b7dd42133b4bd14f1371f1000fcc0 (patch)
treee09e601d0d41024e9ed8c49c2b2c53a996cb7297 /Hotline
parente2eccde99075d2ca355a80bbbb7a3160d766b920 (diff)
New Preferences window on macOS with support for changing some basic moderation settings, plus username (finally) and user icon.1.0beta
Diffstat (limited to 'Hotline')
-rw-r--r--Hotline/Application.swift10
-rw-r--r--Hotline/Hotline.entitlements14
-rw-r--r--Hotline/Models/Hotline.swift14
-rw-r--r--Hotline/Models/Preferences.swift107
-rw-r--r--Hotline/macOS/ServerView.swift54
-rw-r--r--Hotline/macOS/SettingsView.swift94
6 files changed, 266 insertions, 27 deletions
diff --git a/Hotline/Application.swift b/Hotline/Application.swift
index 65833f1..83751c3 100644
--- a/Hotline/Application.swift
+++ b/Hotline/Application.swift
@@ -7,6 +7,8 @@ struct Application: App {
private var model = Hotline(trackerClient: HotlineTrackerClient(), client: HotlineClient())
#endif
+ private var preferences = Prefs()
+
var body: some Scene {
#if os(iOS)
WindowGroup {
@@ -36,6 +38,7 @@ struct Application: App {
ServerView(server: s)
.frame(minWidth: 400, minHeight: 300)
.environment(Hotline(trackerClient: HotlineTrackerClient(), client: HotlineClient()))
+ .environment(preferences)
.toolbar {
ToolbarItem(placement: .navigation) {
Image(systemName: "globe.americas.fill")
@@ -52,6 +55,13 @@ struct Application: App {
}
.defaultSize(width: 700, height: 800)
.defaultPosition(.center)
+
+#if os(macOS)
+ Settings {
+ SettingsView()
+ .environment(preferences)
+ }
+#endif
#endif
}
diff --git a/Hotline/Hotline.entitlements b/Hotline/Hotline.entitlements
new file mode 100644
index 0000000..1ec315d
--- /dev/null
+++ b/Hotline/Hotline.entitlements
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.app-sandbox</key>
+ <true/>
+ <key>com.apple.security.files.downloads.read-write</key>
+ <true/>
+ <key>com.apple.security.files.user-selected.read-only</key>
+ <true/>
+ <key>com.apple.security.network.client</key>
+ <true/>
+</dict>
+</plist>
diff --git a/Hotline/Models/Hotline.swift b/Hotline/Models/Hotline.swift
index 229f085..6aafdfe 100644
--- a/Hotline/Models/Hotline.swift
+++ b/Hotline/Models/Hotline.swift
@@ -71,6 +71,12 @@ import SwiftUI
2561: "πŸ‡ΈπŸ‡ͺ",
]
+// @AppStorage("username") private var username: String = "guest"
+// @AppStorage("refuse private messages") private var refusePrivateMessages = false
+// @AppStorage("refuse private chat") private var refusePrivateChat = false
+// @AppStorage("enable automatic response") private var enableAutomaticResponse = false
+// @AppStorage("automatic response") private var automaticResponse = ""
+
var status: HotlineClientStatus = .disconnected
var server: Server? {
@@ -89,8 +95,8 @@ import SwiftUI
}
}
var serverTitle: String = "Server"
- var username: String = "bolt"
- var iconID: UInt = 414
+ var username: String = "guest"
+ var iconID: Int = 414
var access: HotlineUserAccessOptions?
var agreed: Bool = false
@@ -141,7 +147,7 @@ import SwiftUI
self.trackerClient.disconnect()
}
- @MainActor func login(server: Server, login: String, password: String, username: String, iconID: UInt, callback: ((Bool) -> Void)? = nil) {
+ @MainActor func login(server: Server, login: String, password: String, username: String, iconID: Int, callback: ((Bool) -> Void)? = nil) {
self.server = server
self.serverName = server.name
self.username = username
@@ -157,7 +163,7 @@ import SwiftUI
}
}
- @MainActor func sendUserInfo(username: String, iconID: UInt, options: HotlineUserOptions = [], autoresponse: String? = nil, callback: ((Bool) -> Void)? = nil) {
+ @MainActor func sendUserInfo(username: String, iconID: Int, options: HotlineUserOptions = [], autoresponse: String? = nil, callback: ((Bool) -> Void)? = nil) {
self.username = username
self.iconID = iconID
diff --git a/Hotline/Models/Preferences.swift b/Hotline/Models/Preferences.swift
new file mode 100644
index 0000000..324c6d5
--- /dev/null
+++ b/Hotline/Models/Preferences.swift
@@ -0,0 +1,107 @@
+import SwiftUI
+
+enum PrefsKeys: String {
+ case username = "username"
+ case userIconID = "user icon id"
+ case refusePrivateMessages = "refuse private messages"
+ case refusePrivateChat = "refuse private chat"
+ case enableAutomaticMessage = "enable automatic message"
+ case automaticMessage = "automatic message"
+}
+
+@Observable
+class Prefs {
+ init() {
+ UserDefaults.standard.register(defaults:[
+ PrefsKeys.username.rawValue: "guest",
+ PrefsKeys.userIconID.rawValue: 137,
+ PrefsKeys.refusePrivateMessages.rawValue: false,
+ PrefsKeys.refusePrivateChat.rawValue: false,
+ PrefsKeys.enableAutomaticMessage.rawValue: false,
+ PrefsKeys.automaticMessage.rawValue: "",
+ ])
+
+ self.username = UserDefaults.standard.string(forKey: PrefsKeys.username.rawValue)!
+ self.userIconID = UserDefaults.standard.integer(forKey: PrefsKeys.userIconID.rawValue)
+ self.refusePrivateMessages = UserDefaults.standard.bool(forKey: PrefsKeys.refusePrivateMessages.rawValue)
+ self.refusePrivateChat = UserDefaults.standard.bool(forKey: PrefsKeys.refusePrivateChat.rawValue)
+ self.enableAutomaticMessage = UserDefaults.standard.bool(forKey: PrefsKeys.enableAutomaticMessage.rawValue)
+ self.automaticMessage = UserDefaults.standard.string(forKey: PrefsKeys.automaticMessage.rawValue)!
+ }
+
+ var username: String {
+ didSet { UserDefaults.standard.set(self.username, forKey: PrefsKeys.username.rawValue) }
+ }
+
+ var userIconID: Int {
+ didSet { UserDefaults.standard.set(self.userIconID, forKey: PrefsKeys.userIconID.rawValue) }
+ }
+
+ var refusePrivateMessages: Bool {
+ didSet { UserDefaults.standard.set(self.refusePrivateMessages, forKey: PrefsKeys.refusePrivateMessages.rawValue) }
+ }
+
+ var refusePrivateChat: Bool {
+ didSet { UserDefaults.standard.set(self.refusePrivateChat, forKey: PrefsKeys.refusePrivateChat.rawValue) }
+ }
+
+ var enableAutomaticMessage: Bool {
+ didSet { UserDefaults.standard.set(self.enableAutomaticMessage, forKey: PrefsKeys.enableAutomaticMessage.rawValue) }
+ }
+
+ var automaticMessage: String {
+ didSet { UserDefaults.standard.set(self.automaticMessage, forKey: PrefsKeys.automaticMessage.rawValue) }
+ }
+}
+
+//@Observable
+//final class Preferences {
+//
+// var username: String {
+// get {
+// access(keyPath: \.username)
+// return UserDefaults.standard.object(forKey: "username") as? String ?? "guest"
+// }
+// set {
+// withMutation(keyPath: \.username) {
+// UserDefaults.standard.set(newValue, forKey: "username")
+// }
+// }
+// }
+//
+// var refusePrivateMessages: Bool {
+// get { return UserDefaults.standard.object(forKey: "refuse private messages") as? Bool ?? false }
+// set { UserDefaults.standard.set(newValue, forKey: "refuse private messages") }
+// }
+//
+// var refusePrivateChat: Bool {
+// get { return UserDefaults.standard.object(forKey: "refuse private chat") as? Bool ?? false }
+// set { UserDefaults.standard.set(newValue, forKey: "refuse private chat") }
+// }
+//
+// var automaticResponseEnabled: Bool {
+// get { return UserDefaults.standard.object(forKey: "enable automatic response") as? Bool ?? false }
+// set { UserDefaults.standard.set(newValue, forKey: "enable automatic response") }
+// }
+//
+// var automaticResponse: String {
+// get { return UserDefaults.standard.object(forKey: "automatic response") as? String ?? "" }
+// set { UserDefaults.standard.set(newValue, forKey: "automatic response") }
+// }
+//
+// var userIconID: Int {
+// get { return UserDefaults.standard.object(forKey: "user icon") as? Int ?? 404 }
+// set { UserDefaults.standard.set(newValue, forKey: "user icon") }
+// }
+//
+//// @AppStorage("username") public var username: String = "guest"
+//// @AppStorage("refuse private messages") public var refusePrivateMessages: Bool = false
+//// @AppStorage("refuse private chat") public var refusePrivateChat: Bool = false
+//// @AppStorage("enable automatic response") public var enableAutomaticResponse: Bool = false
+//// @AppStorage("automatic response") public var automaticResponse: String = ""
+////
+//// // Icon
+//// @AppStorage("user icon id") public var iconID: Int = 404
+//
+// public static let shared = Preferences()
+//}
diff --git a/Hotline/macOS/ServerView.swift b/Hotline/macOS/ServerView.swift
index a385109..337882b 100644
--- a/Hotline/macOS/ServerView.swift
+++ b/Hotline/macOS/ServerView.swift
@@ -112,13 +112,13 @@ private func connectionStatusToProgress(status: HotlineClientStatus) -> Double {
struct ServerView: View {
@Environment(Hotline.self) private var model: Hotline
+ @Environment(Prefs.self) private var preferences: Prefs
@Environment(\.dismiss) var dismiss
@Environment(\.controlActiveState) private var controlActiveState
@State private var agreementShown: Bool = false
@State private var selection: MenuItem? = ServerView.menuItems.first
-
let server: Server
static var menuItems = [
@@ -129,6 +129,28 @@ struct ServerView: View {
// MenuItem(name: "Tasks", image: "arrow.up.circle", type: .tasks),
]
+ @MainActor func sendPreferences() {
+ if self.model.status == .loggedIn {
+ var options: HotlineUserOptions = HotlineUserOptions()
+
+ if preferences.refusePrivateMessages {
+ options.update(with: .refusePrivateMessages)
+ }
+
+ if preferences.refusePrivateChat {
+ options.update(with: .refusePrivateChat)
+ }
+
+ if preferences.enableAutomaticMessage {
+ options.update(with: .automaticResponse)
+ }
+
+ print("Updating preferences with server")
+
+ self.model.sendUserInfo(username: preferences.username, iconID: preferences.userIconID, options: options, autoresponse: preferences.automaticMessage)
+ }
+ }
+
var body: some View {
NavigationSplitView {
List(selection: $selection) {
@@ -238,13 +260,13 @@ struct ServerView: View {
.navigationTitle("")
.onAppear {
print(" YAYY")
- self.model.login(server: self.server, login: "", password: "", username: "bolt", iconID: 128) { success in
+ self.model.login(server: self.server, login: "", password: "", username: preferences.username, iconID: preferences.userIconID) { success in
if !success {
print("FAILED LOGIN??")
}
else {
print("GETTING USER LIST????!")
- self.model.sendUserInfo(username: "bolt", iconID: 128)
+ self.sendPreferences()
self.model.getUserList()
}
}
@@ -257,26 +279,12 @@ struct ServerView: View {
dismiss()
}
}
-// .onChange(of: model.agreement) {
-// if model.agreement != nil {
-// agreementShown = true
-// }
-// }
-// .sheet(isPresented: $agreementShown, onDismiss: {
-// if model.status == .disconnected {
-// dismiss()
-// }
-// }, content: {
-// if let text = model.agreement {
-// AgreementView(text: text, disagree: {
-// self.model.disconnect()
-// print("DISAGREE")
-// }, agree: {
-// print("AGREE?")
-// })
-//// .frame(minWidth: 300, maxWidth: 500, minHeight: 300)
-// }
-// })
+ .onChange(of: preferences.userIconID) { self.sendPreferences() }
+ .onChange(of: preferences.username) { self.sendPreferences() }
+ .onChange(of: preferences.refusePrivateMessages) { self.sendPreferences() }
+ .onChange(of: preferences.refusePrivateChat) { self.sendPreferences() }
+ .onChange(of: preferences.enableAutomaticMessage) { self.sendPreferences() }
+ .onChange(of: preferences.automaticMessage) { self.sendPreferences() }
}
}
diff --git a/Hotline/macOS/SettingsView.swift b/Hotline/macOS/SettingsView.swift
new file mode 100644
index 0000000..2b11ecc
--- /dev/null
+++ b/Hotline/macOS/SettingsView.swift
@@ -0,0 +1,94 @@
+import SwiftUI
+
+struct GeneralSettingsView: View {
+ @Environment(Prefs.self) private var preferences: Prefs
+
+ var body: some View {
+ @Bindable var preferences = preferences
+
+ Form {
+ TextField("Your Name", text: $preferences.username, prompt: Text("guest"))
+ Toggle("Refuse private messages", isOn: $preferences.refusePrivateMessages)
+ Toggle("Refuse private chat", isOn: $preferences.refusePrivateChat)
+ Toggle("Automatic Response", isOn: $preferences.enableAutomaticMessage)
+ if preferences.enableAutomaticMessage {
+ TextField("", text: $preferences.automaticMessage, prompt: Text("Write a response message"))
+ .lineLimit(2)
+ .multilineTextAlignment(.leading)
+// .fixedSize(horizontal: true, vertical: false)
+ .frame(maxWidth: .infinity)
+// .lineLimit(2, reservesSpace: true)
+ }
+ }
+ .padding(20)
+ .frame(width: 350)
+ }
+}
+
+struct IconSettingsView: View {
+ @Environment(Prefs.self) private var preferences: Prefs
+
+// @AppStorage(Prefs.userIconID) private var userIconID: Int = Prefs.defaultIconID
+
+ var body: some View {
+ @Bindable var preferences = preferences
+
+ Form {
+ ScrollView {
+ LazyVGrid(columns: [
+ GridItem(.flexible(minimum: 20, maximum: 50)),
+ GridItem(.flexible(minimum: 20, maximum: 50)),
+ GridItem(.flexible(minimum: 20, maximum: 50)),
+ GridItem(.flexible(minimum: 20, maximum: 50)),
+ GridItem(.flexible(minimum: 20, maximum: 50)),
+ GridItem(.flexible(minimum: 20, maximum: 50)),
+ GridItem(.flexible(minimum: 20, maximum: 50))
+ ]) {
+ ForEach(Hotline.defaultIconSet.sorted(by: >), id: \.key) { iconID, iconText in
+ Text(iconText)
+ .font(.largeTitle)
+ .frame(maxWidth: .infinity)
+ .padding(4)
+ .background(iconID == preferences.userIconID ? .blue : .clear)
+ .clipShape(RoundedRectangle(cornerRadius: 5))
+ .onTapGesture {
+ preferences.userIconID = iconID
+ }
+ }
+ }
+ .padding()
+ }
+// for (iconID, iconText) in Hotline.defaultIconSet {
+
+// Text(iconText)
+// }
+ }
+ .frame(width: 350, height: 300)
+
+ }
+}
+
+struct SettingsView: View {
+ private enum Tabs: Hashable {
+ case general, icon
+ }
+
+ var body: some View {
+ TabView {
+ GeneralSettingsView()
+ .tabItem {
+ Label("General", systemImage: "gear")
+ }
+ .tag(Tabs.general)
+ IconSettingsView()
+ .tabItem {
+ Label("Icon", systemImage: "person.crop.circle")
+ }
+ .tag(Tabs.icon)
+ }
+ }
+}
+
+#Preview {
+ SettingsView()
+}