WiP on Edit Accounts and ColorScheme

This commit is contained in:
Stuart Breckenridge 2020-07-14 14:57:55 +08:00
parent 64848a9421
commit 4982211e27
No known key found for this signature in database
GPG Key ID: 79BD673276AE83CE
9 changed files with 177 additions and 35 deletions

View File

@ -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?

View File

@ -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()

View File

@ -66,6 +66,8 @@ struct MacPreferencesView: View {
}
}
}
.preferredColorScheme(AppDefaults.userInterfaceColorScheme)
}
}

View File

@ -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<AnyCancellable>()

View File

@ -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)

View File

@ -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())
}
}

View File

@ -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()
}
}

View File

@ -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)

View File

@ -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 = "<group>"; };
1769E32A24BCB030000E1E8E /* ConfiguredAccountRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfiguredAccountRow.swift; sourceTree = "<group>"; };
1769E32C24BD20A0000E1E8E /* EditAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAccountView.swift; sourceTree = "<group>"; };
1769E32F24BD6271000E1E8E /* EditAccountCredentials.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAccountCredentials.swift; sourceTree = "<group>"; };
1776E88D24AC5F8A00E78166 /* AppDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDefaults.swift; sourceTree = "<group>"; };
17930ED324AF10EE00A9BA52 /* AddWebFeedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddWebFeedView.swift; sourceTree = "<group>"; };
179DBBA2B22A659F81EED6F9 /* AccountsNewsBlurWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsNewsBlurWindowController.swift; sourceTree = "<group>"; };
@ -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 = "<group>";
};
1769E32E24BD5F22000E1E8E /* Edit Account */ = {
isa = PBXGroup;
children = (
1769E32C24BD20A0000E1E8E /* EditAccountView.swift */,
1769E32F24BD6271000E1E8E /* EditAccountCredentials.swift */,
);
path = "Edit Account";
sourceTree = "<group>";
};
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 */,