From 4982211e276431b5bad0b1693e7c09eac01aab38 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Tue, 14 Jul 2020 14:57:55 +0800 Subject: [PATCH] WiP on Edit Accounts and ColorScheme --- Multiplatform/Shared/AppDefaults.swift | 11 +++ Multiplatform/Shared/MainApp.swift | 3 + .../Preferences/MacPreferencesView.swift | 2 + .../Accounts/AccountsPreferencesModel.swift | 32 ++++++--- .../Accounts/AccountsPreferencesView.swift | 58 +++++++++++----- .../Edit Account/EditAccountCredentials.swift | 69 +++++++++++++++++++ .../{ => Edit Account}/EditAccountView.swift | 9 ++- .../General/GeneralPreferencesView.swift | 14 +++- NetNewsWire.xcodeproj/project.pbxproj | 14 +++- 9 files changed, 177 insertions(+), 35 deletions(-) create mode 100644 Multiplatform/macOS/Preferences/Preference Panes/Accounts/Edit Account/EditAccountCredentials.swift rename Multiplatform/macOS/Preferences/Preference Panes/Accounts/{ => Edit Account}/EditAccountView.swift (96%) diff --git a/Multiplatform/Shared/AppDefaults.swift b/Multiplatform/Shared/AppDefaults.swift index 52452c851..b5f998d46 100644 --- a/Multiplatform/Shared/AppDefaults.swift +++ b/Multiplatform/Shared/AppDefaults.swift @@ -138,6 +138,17 @@ final class AppDefaults: ObservableObject { } } + static var userInterfaceColorScheme: ColorScheme? { + switch AppDefaults.shared.userInterfaceColorPalette { + case .light: + return ColorScheme.light + case .dark: + return ColorScheme.dark + default: + return nil + } + } + // MARK: Feeds & Folders @AppStorage(Key.addWebFeedAccountID, store: store) var addWebFeedAccountID: String? diff --git a/Multiplatform/Shared/MainApp.swift b/Multiplatform/Shared/MainApp.swift index 9f60267f4..0b5a0f893 100644 --- a/Multiplatform/Shared/MainApp.swift +++ b/Multiplatform/Shared/MainApp.swift @@ -20,12 +20,14 @@ struct MainApp: App { @StateObject private var defaults = AppDefaults.shared + @SceneBuilder var body: some Scene { #if os(macOS) WindowGroup { SceneNavigationView() .frame(minWidth: 600, idealWidth: 1000, maxWidth: .infinity, minHeight: 600, idealHeight: 700, maxHeight: .infinity) .environmentObject(defaults) + .preferredColorScheme(AppDefaults.userInterfaceColorScheme) } .windowToolbarStyle(UnifiedWindowToolbarStyle()) .commands { @@ -69,6 +71,7 @@ struct MainApp: App { }) } + // Mac Preferences Settings { MacPreferencesView() diff --git a/Multiplatform/macOS/Preferences/MacPreferencesView.swift b/Multiplatform/macOS/Preferences/MacPreferencesView.swift index e663647ad..e24f8d6e9 100644 --- a/Multiplatform/macOS/Preferences/MacPreferencesView.swift +++ b/Multiplatform/macOS/Preferences/MacPreferencesView.swift @@ -66,6 +66,8 @@ struct MacPreferencesView: View { } } } + .preferredColorScheme(AppDefaults.userInterfaceColorScheme) + } } diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/AccountsPreferencesModel.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/AccountsPreferencesModel.swift index 8fdf7ecbb..74bb43a8b 100644 --- a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/AccountsPreferencesModel.swift +++ b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/AccountsPreferencesModel.swift @@ -12,6 +12,12 @@ import Combine class AccountsPreferencesModel: ObservableObject { + enum AccountConfigurationSheets { + case add, credentials, none + } + + public private(set) var account: Account? + // Configured Accounts @Published var sortedAccounts: [Account] = [] @Published var selectedConfiguredAccountID: String? = AccountManager.shared.defaultAccount.accountID { @@ -24,9 +30,17 @@ class AccountsPreferencesModel: ObservableObject { } } @Published var showAddAccountView: Bool = false + var selectedAccountIsDefault: Bool { + guard let selected = selectedConfiguredAccountID else { + return true + } + if selected == AccountManager.shared.defaultAccount.accountID { + return true + } + return false + } // Edit Account - public private(set) var account: Account? @Published var accountIsActive: Bool = false { didSet { account?.isActive = accountIsActive @@ -37,16 +51,18 @@ class AccountsPreferencesModel: ObservableObject { account?.name = accountName } } + @Published var showAddCredentialsView: Bool = false - var selectedAccountIsDefault: Bool { - guard let selected = selectedConfiguredAccountID else { - return true + // Sheets + @Published var showSheet: Bool = false + @Published var sheetToShow: AccountConfigurationSheets = .none { + didSet { + showSheet = sheetToShow != .none } - if selected == AccountManager.shared.defaultAccount.accountID { - return true - } - return false } + @Published var showDeleteConfirmation: Bool = false + + // Subscriptions var notificationSubscriptions = Set() diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/AccountsPreferencesView.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/AccountsPreferencesView.swift index 858efc679..52fca6143 100644 --- a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/AccountsPreferencesView.swift +++ b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/AccountsPreferencesView.swift @@ -18,36 +18,59 @@ struct AccountsPreferencesView: View { var body: some View { VStack { HStack(alignment: .top, spacing: 10) { - VStack(alignment: .leading) { - List(viewModel.sortedAccounts, id: \.accountID, selection: $viewModel.selectedConfiguredAccountID) { - ConfiguredAccountRow(account: $0) - .id($0.accountID) - }.overlay( - Group { - bottomButtonStack - }, alignment: .bottom) - } - .frame(width: 160, height: 300, alignment: .leading) - .border(Color.gray, width: 1) + listOfAccounts EditAccountView(viewModel: viewModel) .frame(height: 300, alignment: .leading) } Spacer() - }.sheet(isPresented: $viewModel.showAddAccountView, - onDismiss: { viewModel.showAddAccountView.toggle() }, + } + .sheet(isPresented: $viewModel.showSheet, + onDismiss: { viewModel.sheetToShow = .none }, content: { - AddAccountView(preferencesModel: viewModel) + switch viewModel.sheetToShow { + case .add: + AddAccountView(preferencesModel: viewModel) + case .credentials: + EditAccountCredentials(viewModel: viewModel) + case .none: + EmptyView() + } }) + .alert(isPresented: $viewModel.showDeleteConfirmation, content: { + Alert(title: Text("Delete \(viewModel.account!.nameForDisplay)?"), + message: Text("Are you sure you want to delete the account \"\(viewModel.account!.nameForDisplay)\"? This can not be undone."), + primaryButton: .destructive(Text("Delete"), action: { + AccountManager.shared.deleteAccount(viewModel.account!) + viewModel.showDeleteConfirmation = false + }), + secondaryButton: .cancel({ + viewModel.showDeleteConfirmation = false + })) + }) } + var listOfAccounts: some View { + VStack(alignment: .leading) { + List(viewModel.sortedAccounts, id: \.accountID, selection: $viewModel.selectedConfiguredAccountID) { + ConfiguredAccountRow(account: $0) + .id($0.accountID) + }.overlay( + Group { + bottomButtonStack + }, alignment: .bottom) + } + .frame(width: 160, height: 300, alignment: .leading) + .border(Color.gray, width: 1) + } + var bottomButtonStack: some View { VStack(alignment: .leading, spacing: 0) { Divider() HStack(alignment: .center, spacing: 4) { Button(action: { - viewModel.showAddAccountView.toggle() + viewModel.sheetToShow = .add }, label: { Image(systemName: "plus") .font(.title) @@ -63,10 +86,7 @@ struct AccountsPreferencesView: View { .help("Add Account") Button(action: { - if let account = viewModel.sortedAccounts.first(where: { $0.accountID == viewModel.selectedConfiguredAccountID }) { - AccountManager.shared.deleteAccount(account) - } - + viewModel.showDeleteConfirmation = true }, label: { Image(systemName: "minus") .font(.title) diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Edit Account/EditAccountCredentials.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Edit Account/EditAccountCredentials.swift new file mode 100644 index 000000000..fe868c12a --- /dev/null +++ b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Edit Account/EditAccountCredentials.swift @@ -0,0 +1,69 @@ +// +// EditAccountCredentials.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 14/7/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Secrets + +struct EditAccountCredentials: View { + + @ObservedObject var viewModel: AccountsPreferencesModel + @Environment(\.presentationMode) var presentationMode + + @State private var userName: String = "" + @State private var password: String = "" + @State private var apiUrl: String? + + var body: some View { + Form { + HStack { + Spacer() + Image(rsImage: viewModel.account!.smallIcon!.image) + .resizable() + .frame(width: 30, height: 30) + Text(viewModel.account?.nameForDisplay ?? "") + Spacer() + }.padding() + + HStack(alignment: .center) { + VStack(alignment: .trailing, spacing: 12) { + Text("Username: ") + Text("Password: ") + }.frame(width: 75) + + VStack(alignment: .leading, spacing: 12) { + TextField("Username", text: $userName) + SecureField("Password", text: $password) + } + }.textFieldStyle(RoundedBorderTextFieldStyle()) + + Spacer() + HStack{ + Spacer() + Button("Dismiss", action: { + presentationMode.wrappedValue.dismiss() + }) + Button("Update", action: { + presentationMode.wrappedValue.dismiss() + }) + } + }.onAppear { + let credentials = try? viewModel.account?.retrieveCredentials(type: .basic) + userName = credentials?.username ?? "" + password = credentials?.secret ?? "" + } + .frame(idealWidth: 300, idealHeight: 200, alignment: .top) + .padding() + } +} + +struct EditAccountCredentials_Previews: PreviewProvider { + static var previews: some View { + EditAccountCredentials(viewModel: AccountsPreferencesModel()) + } +} + diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/EditAccountView.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Edit Account/EditAccountView.swift similarity index 96% rename from Multiplatform/macOS/Preferences/Preference Panes/Accounts/EditAccountView.swift rename to Multiplatform/macOS/Preferences/Preference Panes/Accounts/Edit Account/EditAccountView.swift index 6999f22b0..87d4761b6 100644 --- a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/EditAccountView.swift +++ b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Edit Account/EditAccountView.swift @@ -15,7 +15,6 @@ struct EditAccountView: View { @ObservedObject var viewModel: AccountsPreferencesModel var body: some View { - ZStack { RoundedRectangle(cornerRadius: 8, style: .circular) .foregroundColor(Color.secondary.opacity(0.1)) @@ -23,11 +22,9 @@ struct EditAccountView: View { VStack { editAccountHeader - if viewModel.account != nil { editAccountForm } - Spacer() } } @@ -67,12 +64,14 @@ struct EditAccountView: View { HStack { Spacer() Button("Credentials", action: { - + viewModel.sheetToShow = .credentials }) Spacer() } } - }).padding() + }) + .padding() + } } diff --git a/Multiplatform/macOS/Preferences/Preference Panes/General/GeneralPreferencesView.swift b/Multiplatform/macOS/Preferences/Preference Panes/General/GeneralPreferencesView.swift index 8d0056150..f0bb30ded 100644 --- a/Multiplatform/macOS/Preferences/Preference Panes/General/GeneralPreferencesView.swift +++ b/Multiplatform/macOS/Preferences/Preference Panes/General/GeneralPreferencesView.swift @@ -10,7 +10,9 @@ import SwiftUI struct GeneralPreferencesView: View { @EnvironmentObject private var defaults: AppDefaults + @Environment(\.colorScheme) private var colorScheme @ObservedObject var preferences: MacPreferencesModel + private let colorPalettes = UserInterfaceColorPalette.allCases var body: some View { Form { @@ -32,8 +34,6 @@ struct GeneralPreferencesView: View { Text(preferences.rssReaders[index].nameMinusAppSuffix) .tag(index) } - - }) }) @@ -41,6 +41,16 @@ struct GeneralPreferencesView: View { Toggle("Open webpages in background in browser", isOn: $defaults.openInBrowserInBackground) Toggle("Hide Unread Count in Dock", isOn: $defaults.hideDockUnreadCount) + + Divider() + + Picker("Appearance", selection: $defaults.userInterfaceColorPalette, content: { + ForEach(colorPalettes, id: \.self, content: { + Text($0.description) + }) + }).pickerStyle(RadioGroupPickerStyle()) + + } .frame(width: 400, alignment: .center) .lineLimit(2) diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 86e7de53d..6cd60e8e0 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 1769E32924BCAFC7000E1E8E /* AddAccountPickerRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32824BCAFC7000E1E8E /* AddAccountPickerRow.swift */; }; 1769E32B24BCB030000E1E8E /* ConfiguredAccountRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32A24BCB030000E1E8E /* ConfiguredAccountRow.swift */; }; 1769E32D24BD20A0000E1E8E /* EditAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32C24BD20A0000E1E8E /* EditAccountView.swift */; }; + 1769E33024BD6271000E1E8E /* EditAccountCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32F24BD6271000E1E8E /* EditAccountCredentials.swift */; }; 1776E88E24AC5F8A00E78166 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1776E88D24AC5F8A00E78166 /* AppDefaults.swift */; }; 1776E88F24AC5F8A00E78166 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1776E88D24AC5F8A00E78166 /* AppDefaults.swift */; }; 17930ED424AF10EE00A9BA52 /* AddWebFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17930ED324AF10EE00A9BA52 /* AddWebFeedView.swift */; }; @@ -1800,6 +1801,7 @@ 1769E32824BCAFC7000E1E8E /* AddAccountPickerRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountPickerRow.swift; sourceTree = ""; }; 1769E32A24BCB030000E1E8E /* ConfiguredAccountRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfiguredAccountRow.swift; sourceTree = ""; }; 1769E32C24BD20A0000E1E8E /* EditAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAccountView.swift; sourceTree = ""; }; + 1769E32F24BD6271000E1E8E /* EditAccountCredentials.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAccountCredentials.swift; sourceTree = ""; }; 1776E88D24AC5F8A00E78166 /* AppDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDefaults.swift; sourceTree = ""; }; 17930ED324AF10EE00A9BA52 /* AddWebFeedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddWebFeedView.swift; sourceTree = ""; }; 179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsNewsBlurWindowController.swift; sourceTree = ""; }; @@ -2548,7 +2550,7 @@ 1769E32124BC5925000E1E8E /* AccountsPreferencesModel.swift */, 1729529024AA1CAA00D65E66 /* AccountsPreferencesView.swift */, 1769E32A24BCB030000E1E8E /* ConfiguredAccountRow.swift */, - 1769E32C24BD20A0000E1E8E /* EditAccountView.swift */, + 1769E32E24BD5F22000E1E8E /* Edit Account */, 1769E32324BC5A50000E1E8E /* Add Account */, ); path = Accounts; @@ -2572,6 +2574,15 @@ path = "Add Account"; sourceTree = ""; }; + 1769E32E24BD5F22000E1E8E /* Edit Account */ = { + isa = PBXGroup; + children = ( + 1769E32C24BD20A0000E1E8E /* EditAccountView.swift */, + 1769E32F24BD6271000E1E8E /* EditAccountCredentials.swift */, + ); + path = "Edit Account"; + sourceTree = ""; + }; 17930ED224AF10CD00A9BA52 /* Add */ = { isa = PBXGroup; children = ( @@ -5252,6 +5263,7 @@ 51408B7F24A9EC6F0073CF4E /* SidebarItem.swift in Sources */, 514E6BDB24ACEA0400AC6F6E /* TimelineItemView.swift in Sources */, 51E4996E24A8764C00B667CB /* ActivityManager.swift in Sources */, + 1769E33024BD6271000E1E8E /* EditAccountCredentials.swift in Sources */, 51E4995A24A873F900B667CB /* ErrorHandler.swift in Sources */, 51E4991F24A8094300B667CB /* RSImage-AppIcons.swift in Sources */, 51A5769724AE617200078888 /* ArticleContainerView.swift in Sources */,