mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Adds Mac Preferences
This makes use of `@AppStorage` for preferences. Severeral more need to migrated from AppDefaults etc.
This commit is contained in:
96
Multiplatform/macOS/Preferences/Model/MacPreferences.swift
Normal file
96
Multiplatform/macOS/Preferences/Model/MacPreferences.swift
Normal file
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// MacPreferences.swift
|
||||
// macOS
|
||||
//
|
||||
// Created by Stuart Breckenridge on 27/6/20.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
enum FontSize: Int {
|
||||
case small = 0
|
||||
case medium = 1
|
||||
case large = 2
|
||||
case veryLarge = 3
|
||||
}
|
||||
|
||||
/// The `MacPreferences` object stores all macOS specific user preferences.
|
||||
class MacPreferences: ObservableObject {
|
||||
|
||||
private struct AppKeys {
|
||||
static let refreshInterval = "refreshInterval"
|
||||
static let openInBackground = "openInBrowserInBackground"
|
||||
static let showUnreadCountInDock = "showUnreadCountInDock"
|
||||
static let checkForUpdatesAutomatically = "checkForAppUpdates"
|
||||
static let downloadTestBuilds = "downloadTestBuilds"
|
||||
static let sendCrashLogs = "sendCrashLogs"
|
||||
}
|
||||
|
||||
// Refresh Interval
|
||||
public let refreshIntervals:[String] = RefreshFrequencies.allCases.map({ $0.description })
|
||||
@AppStorage(wrappedValue: 0, AppKeys.refreshInterval) var refreshFrequency {
|
||||
didSet {
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
// Open in background
|
||||
@AppStorage(wrappedValue: false, AppKeys.openInBackground) var openInBackground {
|
||||
didSet {
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
// Unread Count in Dock
|
||||
@AppStorage(wrappedValue: true, AppKeys.showUnreadCountInDock) var showUnreadCountInDock {
|
||||
didSet {
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
// Check for App Updates
|
||||
@AppStorage(wrappedValue: true, AppKeys.checkForUpdatesAutomatically) var checkForUpdatesAutomatically {
|
||||
didSet {
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
// Test builds
|
||||
@AppStorage(wrappedValue: false, AppKeys.downloadTestBuilds) var downloadTestBuilds {
|
||||
didSet {
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
// Crash Logs
|
||||
@AppStorage(wrappedValue: false, AppKeys.sendCrashLogs) var sendCrashLogs {
|
||||
didSet {
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum RefreshFrequencies: CaseIterable, CustomStringConvertible {
|
||||
|
||||
case refreshEvery10Mins, refreshEvery20Mins, refreshHourly, refreshEvery2Hours, refreshEvery4Hours, refreshEvery8Hours, none
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .refreshEvery10Mins:
|
||||
return "Every 10 minutes"
|
||||
case .refreshEvery20Mins:
|
||||
return "Every 20 minutes"
|
||||
case .refreshHourly:
|
||||
return "Every hour"
|
||||
case .refreshEvery2Hours:
|
||||
return "Every 2 hours"
|
||||
case .refreshEvery4Hours:
|
||||
return "Every 4 hours"
|
||||
case .refreshEvery8Hours:
|
||||
return "Every 8 hours"
|
||||
case .none:
|
||||
return "Manually"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// AccountsPreferencesView.swift
|
||||
// macOS
|
||||
//
|
||||
// Created by Stuart Breckenridge on 27/6/20.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct AccountPreferencesViewModel {
|
||||
let accountTypes = ["On My Mac", "FeedBin"]
|
||||
var selectedAccount = Int?.none
|
||||
}
|
||||
|
||||
struct AccountsPreferencesView: View {
|
||||
|
||||
@State private var viewModel = AccountPreferencesViewModel()
|
||||
@State private var addAccountViewModel = AccountPreferencesViewModel()
|
||||
@State private var showAddAccountView: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack(alignment: .top, spacing: 10) {
|
||||
VStack(alignment: .leading) {
|
||||
List(selection: $viewModel.selectedAccount, content: {
|
||||
ForEach(0..<viewModel.accountTypes.count, content: { i in
|
||||
AccountDetailRow(imageName: "desktopcomputer", accountName: viewModel.accountTypes[i]).padding(.vertical, 8)
|
||||
})
|
||||
})
|
||||
HStack {
|
||||
Button("+", action: {
|
||||
showAddAccountView.toggle()
|
||||
})
|
||||
Button("-", action: {})
|
||||
.disabled(viewModel.selectedAccount == nil)
|
||||
Spacer()
|
||||
}
|
||||
}.frame(width: 225, height: 300, alignment: .leading)
|
||||
VStack(alignment: .leading) {
|
||||
viewModel.selectedAccount == nil ? Text("Select Account") : Text(viewModel.accountTypes[viewModel.selectedAccount!])
|
||||
Spacer()
|
||||
}.frame(width: 225, height: 300, alignment: .leading)
|
||||
}
|
||||
Spacer()
|
||||
}.sheet(isPresented: $showAddAccountView,
|
||||
onDismiss: { showAddAccountView.toggle() },
|
||||
content: {
|
||||
AddAccountView()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct AccountDetailRow: View {
|
||||
|
||||
var imageName: String
|
||||
var accountName: String
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Image(systemName: imageName).font(.headline)
|
||||
Text(accountName).font(.headline)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct AddAccountView: View {
|
||||
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
let accountTypes = ["On My Mac", "FeedBin"]
|
||||
@State var selectedAccount: Int = 0
|
||||
@State private var userName: String = ""
|
||||
@State private var password: String = ""
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text("Add an Account").font(.headline)
|
||||
Form {
|
||||
Picker("Account Type",
|
||||
selection: $selectedAccount,
|
||||
content: {
|
||||
ForEach(0..<accountTypes.count, content: {
|
||||
AccountDetailRow(imageName: "desktopcomputer", accountName: accountTypes[$0])
|
||||
})
|
||||
})
|
||||
|
||||
if selectedAccount == 1 {
|
||||
TextField("Email", text: $userName)
|
||||
SecureField("Password", text: $password)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
|
||||
Button(action: { presentationMode.wrappedValue.dismiss() }, label: {
|
||||
Text("Cancel")
|
||||
})
|
||||
|
||||
if selectedAccount == 0 {
|
||||
Button("Add", action: {})
|
||||
}
|
||||
|
||||
if selectedAccount != 0 {
|
||||
Button("Create", action: {})
|
||||
.disabled(userName.count == 0 || password.count == 0)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}.frame(width: 300, alignment: .top).padding()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class AddAccountModel: ObservableObject {
|
||||
let accountTypes = ["On My Mac", "FeedBin"]
|
||||
@Published var selectedAccount = Int?.none
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// AdvancedPreferencesView.swift
|
||||
// macOS
|
||||
//
|
||||
// Created by Stuart Breckenridge on 27/6/20.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct AdvancedPreferencesView: View {
|
||||
|
||||
@StateObject var preferences: MacPreferences
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Form {
|
||||
Toggle("Check for app updates automatically", isOn: $preferences.checkForUpdatesAutomatically)
|
||||
|
||||
Toggle("Download Test Builds", isOn: $preferences.downloadTestBuilds)
|
||||
HStack {
|
||||
Spacer()
|
||||
Text("If you’re not sure, don't enable test builds. Test builds may have bugs, which may include crashing bugs and data loss.").foregroundColor(.secondary)
|
||||
Spacer()
|
||||
}
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
Button("Check for Updates", action: {})
|
||||
Spacer()
|
||||
}.padding(.vertical, 12)
|
||||
|
||||
|
||||
Toggle("Send Crash Logs Automatically", isOn: $preferences.sendCrashLogs)
|
||||
|
||||
Spacer()
|
||||
HStack {
|
||||
Spacer()
|
||||
Button("Privacy Policy", action: {})
|
||||
Spacer()
|
||||
}.padding(.top, 12)
|
||||
|
||||
|
||||
}
|
||||
Spacer()
|
||||
}.frame(width: 300, alignment: .center)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// GeneralPreferencesView.swift
|
||||
// macOS
|
||||
//
|
||||
// Created by Stuart Breckenridge on 27/6/20.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct GeneralPreferencesView: View {
|
||||
|
||||
@ObservedObject private var preferences = MacPreferences()
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Form {
|
||||
Picker("Refresh Feeds",
|
||||
selection: $preferences.refreshFrequency,
|
||||
content: {
|
||||
ForEach(0..<preferences.refreshIntervals.count, content: {
|
||||
Text(preferences.refreshIntervals[$0])
|
||||
})
|
||||
}).frame(width: 300, alignment: .center)
|
||||
|
||||
Toggle("Open webpages in background in browser", isOn: $preferences.openInBackground)
|
||||
|
||||
Toggle("Show Unread Count in Dock", isOn: $preferences.showUnreadCountInDock)
|
||||
}
|
||||
Spacer()
|
||||
}.frame(width: 300, alignment: .center)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// MacPreferencesView.swift
|
||||
// macOS
|
||||
//
|
||||
// Created by Stuart Breckenridge on 27/6/20.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MacPreferenceViewModel {
|
||||
|
||||
enum PreferencePane: Int, CaseIterable {
|
||||
case general = 0
|
||||
case accounts = 1
|
||||
case advanced = 2
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .general:
|
||||
return "General"
|
||||
case .accounts:
|
||||
return "Accounts"
|
||||
case .advanced:
|
||||
return "Advanced"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var currentPreferencePane: PreferencePane = PreferencePane.general
|
||||
|
||||
}
|
||||
|
||||
struct MacPreferencesView: View {
|
||||
|
||||
@EnvironmentObject var preferences: MacPreferences
|
||||
@State private var viewModel = MacPreferenceViewModel()
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
if viewModel.currentPreferencePane == .general {
|
||||
AnyView(GeneralPreferencesView())
|
||||
}
|
||||
else if viewModel.currentPreferencePane == .accounts {
|
||||
AnyView(AccountsPreferencesView())
|
||||
}
|
||||
else {
|
||||
AnyView(AdvancedPreferencesView(preferences: preferences))
|
||||
}
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem {
|
||||
Button(action: {
|
||||
viewModel.currentPreferencePane = .general
|
||||
}, label: {
|
||||
Image(systemName: "checkmark.rectangle")
|
||||
Text("General")
|
||||
})
|
||||
}
|
||||
ToolbarItem {
|
||||
Button(action: {
|
||||
viewModel.currentPreferencePane = .accounts
|
||||
}, label: {
|
||||
Image(systemName: "network")
|
||||
Text("Accounts")
|
||||
})
|
||||
}
|
||||
ToolbarItem {
|
||||
Button(action: {
|
||||
viewModel.currentPreferencePane = .advanced
|
||||
}, label: {
|
||||
Image(systemName: "gearshape.fill")
|
||||
Text("Advanced")
|
||||
})
|
||||
}
|
||||
}
|
||||
.presentedWindowToolbarStyle(UnifiedCompactWindowToolbarStyle())
|
||||
.presentedWindowStyle(TitleBarWindowStyle())
|
||||
.navigationTitle(Text(viewModel.currentPreferencePane.description))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct MacPreferencesView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MacPreferencesView()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user