diff --git a/ntfy/Persistence/Store.swift b/ntfy/Persistence/Store.swift index f0caadd..0529953 100644 --- a/ntfy/Persistence/Store.swift +++ b/ntfy/Persistence/Store.swift @@ -86,9 +86,9 @@ class Store: ObservableObject { try? context.save() } - func save(userBaseUrl baseUrl: String, username: String, password: String) { + func saveUser(baseUrl: String, username: String, password: String) { do { - let user = User(context: context) + let user = getUser(baseUrl: baseUrl) ?? User(context: context) user.baseUrl = baseUrl user.username = username user.password = password @@ -195,8 +195,8 @@ extension Store { } // Users - store.save(userBaseUrl: "https://ntfy.sh", username: "testuser", password: "testuser") - store.save(userBaseUrl: "https://ntfy.example.com", username: "phil", password: "phil12") + store.saveUser(baseUrl: "https://ntfy.sh", username: "testuser", password: "testuser") + store.saveUser(baseUrl: "https://ntfy.example.com", username: "phil", password: "phil12") } return store }() diff --git a/ntfy/Views/SettingsView.swift b/ntfy/Views/SettingsView.swift index cf8cb58..b5b6b62 100644 --- a/ntfy/Views/SettingsView.swift +++ b/ntfy/Views/SettingsView.swift @@ -3,37 +3,17 @@ import SwiftUI struct SettingsView: View { @EnvironmentObject private var store: Store - @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \User.baseUrl, ascending: true)]) var users: FetchedResults - + var body: some View { NavigationView { Form { /*Section(header: Text("General")) { - NavigationLink(destination: UsersView()) { - Text("Manage users") - } - }*/ - Section( - header: Text("Users") - ) { - List { - ForEach(users) { user in - HStack { - Image(systemName: "person.fill") - VStack(alignment: .leading, spacing: 0) { - Text(user.username ?? "?") - - Text(user.baseUrl ?? "?") - .font(.subheadline) - .foregroundColor(.gray) - } - } - } - HStack { - Image(systemName: "plus") - Text("Add user") - } - } + NavigationLink(destination: UsersView()) { + Text("Manage users") + } + }*/ + Section(header: Text("Users")) { + UsersView() } Section(header: Text("About")) { HStack { @@ -41,39 +21,128 @@ struct SettingsView: View { .foregroundColor(.gray) Spacer() Text("ntfy 1.1") - } + } } } .navigationTitle("Settings") - + } .navigationViewStyle(StackNavigationViewStyle()) - } } struct UsersView: View { @EnvironmentObject private var store: Store @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \User.baseUrl, ascending: true)]) var users: FetchedResults - + + @State private var selectedUser: User? + @State private var showDialog = false + + @State private var baseUrl: String = "" + @State private var username: String = "" + @State private var password: String = "" + var body: some View { + let _ = selectedUser?.username // Workaround for FB7823148, see https://developer.apple.com/forums/thread/652080 List { ForEach(users) { user in - Text(user.username ?? "") + UserRowView(user: user) + .onTapGesture { + selectedUser = user + baseUrl = user.baseUrl ?? "?" + username = user.username ?? "?" + showDialog = true + } + } + HStack { + Image(systemName: "plus") + Text("Add user") + } + .onTapGesture { + showDialog = true } } - .listStyle(PlainListStyle()) - .navigationTitle("Manage users") - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button { - //self.showingAddDialog = true - } label: { - Image(systemName: "plus") + .sheet(isPresented: $showDialog) { + NavigationView { + Form { + Section(footer: + Text("You can add a user here. All topics for the given server will use this user.") + ) { + if selectedUser == nil { + TextField("Service URL, e.g. https://ntfy.example.com", text: $baseUrl) + .disableAutocapitalization() + .disableAutocorrection(true) + } + TextField("Username", text: $username) + .disableAutocapitalization() + .disableAutocorrection(true) + TextField("Password", text: $password) + .disableAutocapitalization() + .disableAutocorrection(true) + } + } + .navigationTitle(selectedUser == nil ? "Add user" : "Edit user") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + Button(action: cancelAction) { + Text("Cancel") + } + } + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: saveAction) { + Text("Save") + } + .disabled(!isValid()) + } } } } } + + private func saveAction() { + store.saveUser(baseUrl: baseUrl, username: username, password: password) + resetAndHide() + } + + private func cancelAction() { + resetAndHide() + } + + private func isValid() -> Bool { + return true // FIXME: validate + } + + private func resetAndHide() { + selectedUser = nil + baseUrl = "" + username = "" + password = "" + showDialog = false + } +} + +struct UserRowView: View { + @ObservedObject var user: User + + var body: some View { + HStack { + Image(systemName: "person.fill") + VStack(alignment: .leading, spacing: 0) { + VStack(alignment: .leading, spacing: 0) { + Text(user.username ?? "?") + Text(user.baseUrl ?? "?") + .font(.subheadline) + .foregroundColor(.gray) + } + } + Spacer() + Image(systemName: "chevron.forward") + .font(.system(size: 12.0)) + .foregroundColor(.gray) + } + .padding(.all, 4) + } } struct SettingsView_Previews: PreviewProvider { diff --git a/ntfy/Views/SubscriptionAddView.swift b/ntfy/Views/SubscriptionAddView.swift index f39d7a0..824d944 100644 --- a/ntfy/Views/SubscriptionAddView.swift +++ b/ntfy/Views/SubscriptionAddView.swift @@ -127,7 +127,7 @@ struct SubscriptionAddView: View { ApiService.shared.checkAuth(baseUrl: selectedBaseUrl, topic: topic, user: user) { (response, error) in if response?.success == true { DispatchQueue.global(qos: .background).async { - store.save(userBaseUrl: selectedBaseUrl, username: username, password: password) + store.saveUser(baseUrl: selectedBaseUrl, username: username, password: password) subscriptionManager.subscribe(baseUrl: selectedBaseUrl, topic: sanitizedTopic) } isShowing = false