NetNewsWire/iOS/Settings/SettingsView.swift

315 lines
8.9 KiB
Swift
Raw Normal View History

2019-06-11 23:59:16 +02:00
//
// SettingsView.swift
// NetNewsWire-iOS
//
// Created by Maurice Parker on 6/11/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import SwiftUI
2019-06-13 21:30:56 +02:00
import Combine
2019-06-11 23:59:16 +02:00
import Account
struct SettingsView : View {
@ObservedObject var viewModel: ViewModel
2019-09-07 23:43:44 +02:00
@Environment(\.viewController) private var viewController: UIViewController?
2019-09-15 19:03:28 +02:00
@Environment(\.sceneCoordinator) private var coordinator: SceneCoordinator?
@State private var accountAction: Int? = nil
2019-09-16 19:06:47 +02:00
@State private var refreshAction: Int? = nil
2019-09-17 17:34:54 +02:00
@State private var aboutAction: Int? = nil
2019-09-16 19:06:47 +02:00
2019-09-07 23:43:44 +02:00
@State private var isWebsitePresented: Bool = false
@State private var website: String? = nil
2019-09-07 22:30:54 +02:00
2019-09-07 23:43:44 +02:00
@State private var isOPMLImportPresented: Bool = false
@State private var isOPMLImportDocPickerPresented: Bool = false
@State private var isOPMLExportPresented: Bool = false
@State private var isOPMLExportDocPickerPresented: Bool = false
@State private var opmlAccount: Account? = nil
2019-06-16 01:19:20 +02:00
2019-06-11 23:59:16 +02:00
var body: some View {
NavigationView {
Form {
buildAccountsSection()
buildTimelineSection()
buildDatabaseSection()
buildAboutSection()
2019-06-11 23:59:16 +02:00
}
2019-09-16 18:35:09 +02:00
.buttonStyle(VibrantButtonStyle(alignment: .leading))
2019-06-11 23:59:16 +02:00
.navigationBarTitle(Text("Settings"), displayMode: .inline)
2019-09-07 23:43:44 +02:00
.navigationBarItems(leading: Button(action: { self.viewController?.dismiss(animated: true) }) { Text("Done") } )
2019-06-11 23:59:16 +02:00
}
}
2019-06-13 21:30:56 +02:00
func buildAccountsSection() -> some View {
Section(header: Text("ACCOUNTS").padding(.top, 22.0)) {
ForEach(viewModel.accounts.indices, id: \.self) { index in
2019-09-16 17:57:27 +02:00
NavigationLink(destination: SettingsDetailAccountView(viewModel: SettingsDetailAccountView.ViewModel(self.viewModel.accounts[index])), tag: index, selection: self.$accountAction) {
Text(verbatim: self.viewModel.accounts[index].nameForDisplay)
}
2019-09-16 17:57:27 +02:00
.modifier(VibrantSelectAction(action: {
self.accountAction = index
}))
}
2019-09-16 17:57:27 +02:00
NavigationLink(destination: SettingsAddAccountView(), tag: 1000, selection: $accountAction) {
Text("Add Account")
}
2019-09-16 17:57:27 +02:00
.modifier(VibrantSelectAction(action: {
self.accountAction = 1000
}))
}
}
func buildTimelineSection() -> some View {
Section(header: Text("TIMELINE")) {
Toggle(isOn: $viewModel.sortOldestToNewest) {
Text("Sort Newest to Oldest")
}
2019-09-09 00:41:00 +02:00
Toggle(isOn: $viewModel.groupByFeed) {
Text("Group By Feed")
}
Stepper(value: $viewModel.timelineNumberOfLines, in: 2...6) {
Text("Number of Text Lines: \(viewModel.timelineNumberOfLines)")
}
}
}
func buildDatabaseSection() -> some View {
Section(header: Text("DATABASE")) {
2019-09-16 19:06:47 +02:00
NavigationLink(destination: SettingsRefreshSelectionView(selectedInterval: $viewModel.refreshInterval), tag: 1, selection: $refreshAction) {
HStack {
Text("Refresh Interval")
Spacer()
Text(verbatim: self.viewModel.refreshInterval.description()).foregroundColor(.secondary)
}
}
2019-09-16 19:06:47 +02:00
.modifier(VibrantSelectAction(action: {
self.refreshAction = 1
}))
2019-09-16 19:06:47 +02:00
Button("Import Subscriptions...") {
2019-09-16 17:57:27 +02:00
if AccountManager.shared.activeAccounts.count == 1 {
self.opmlAccount = AccountManager.shared.activeAccounts.first
self.isOPMLImportDocPickerPresented = true
} else {
self.isOPMLImportPresented = true
}
2019-09-16 15:05:33 +02:00
}.actionSheet(isPresented: $isOPMLImportPresented) {
buildSubscriptionsImportAccounts()
}.sheet(isPresented: $isOPMLImportDocPickerPresented) {
SettingsSubscriptionsImportDocumentPickerView(account: self.opmlAccount!)
2019-09-16 17:57:27 +02:00
}
2019-09-16 15:05:33 +02:00
2019-09-16 17:57:27 +02:00
Button("Export Subscriptions...") {
if AccountManager.shared.accounts.count == 1 {
self.opmlAccount = AccountManager.shared.accounts.first
self.isOPMLImportDocPickerPresented = true
} else {
self.isOPMLExportPresented = true
}
2019-09-16 15:05:33 +02:00
}.actionSheet(isPresented: $isOPMLExportPresented) {
buildSubscriptionsExportAccounts()
}.sheet(isPresented: $isOPMLExportDocPickerPresented) {
SettingsSubscriptionsExportDocumentPickerView(account: self.opmlAccount!)
2019-09-16 17:57:27 +02:00
}
}
}
func buildAboutSection() -> some View {
Section(header: Text("ABOUT"), footer: buildFooter()) {
2019-09-17 17:34:54 +02:00
NavigationLink(destination: SettingsAboutView(viewModel: SettingsAboutView.ViewModel()), tag: 1, selection: $aboutAction) {
Text("About NetNewsWire")
}
.modifier(VibrantSelectAction(action: {
self.aboutAction = 1
}))
Button(action: {
self.isWebsitePresented.toggle()
self.website = "https://ranchero.com/netnewswire/"
}) {
Text("Website")
2019-09-16 17:57:27 +02:00
}
Button(action: {
self.isWebsitePresented.toggle()
self.website = "https://github.com/brentsimmons/NetNewsWire"
}) {
Text("Github Repository")
2019-09-16 17:57:27 +02:00
}
Button(action: {
self.isWebsitePresented.toggle()
self.website = "https://github.com/brentsimmons/NetNewsWire/issues"
}) {
Text("Bug Tracker")
2019-09-16 17:57:27 +02:00
}
Button(action: {
self.isWebsitePresented.toggle()
self.website = "https://github.com/brentsimmons/NetNewsWire/tree/master/Technotes"
}) {
Text("Technotes")
2019-09-16 17:57:27 +02:00
}
Button(action: {
self.isWebsitePresented.toggle()
self.website = "https://github.com/brentsimmons/NetNewsWire/blob/master/Technotes/HowToSupportNetNewsWire.markdown"
}) {
Text("How To Support NetNewsWire")
2019-09-16 17:57:27 +02:00
}
2019-09-15 19:03:28 +02:00
if !AccountManager.shared.anyAccountHasFeedWithURL("https://nnw.ranchero.com/feed.json") {
Button(action: {
self.viewController?.dismiss(animated: true) {
let feedName = NSLocalizedString("NetNewsWire News", comment: "NetNewsWire News")
self.coordinator?.showAdd(.feed, initialFeed: "https://nnw.ranchero.com/feed.json", initialFeedName: feedName)
}
}) {
Text("Add NetNewsWire News Feed")
2019-09-16 17:57:27 +02:00
}
2019-09-15 19:03:28 +02:00
}
}.sheet(isPresented: $isWebsitePresented) {
SafariView(url: URL(string: self.website!)!)
}
}
func buildSubscriptionsImportAccounts() -> ActionSheet {
2019-09-07 22:30:54 +02:00
var buttons = [ActionSheet.Button]()
for account in viewModel.activeAccounts {
if account.behaviors.contains(.disallowOPMLImports) {
2019-09-07 22:30:54 +02:00
continue
}
let button = ActionSheet.Button.default(Text(verbatim: account.nameForDisplay)) {
self.opmlAccount = account
self.isOPMLImportDocPickerPresented = true
}
buttons.append(button)
}
buttons.append(.cancel())
return ActionSheet(title: Text("Import Subscriptions..."), message: Text("Select the account to import your OPML file into."), buttons: buttons)
}
func buildSubscriptionsExportAccounts() -> ActionSheet {
2019-09-07 22:30:54 +02:00
var buttons = [ActionSheet.Button]()
for account in viewModel.accounts {
let button = ActionSheet.Button.default(Text(verbatim: account.nameForDisplay)) {
self.opmlAccount = account
self.isOPMLExportDocPickerPresented = true
}
buttons.append(button)
}
buttons.append(.cancel())
return ActionSheet(title: Text("Export Subscriptions..."), message: Text("Select the account to export out of."), buttons: buttons)
}
2019-06-16 01:19:20 +02:00
func buildFooter() -> some View {
return Text(verbatim: "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))")
.font(.footnote)
.foregroundColor(.secondary)
}
2019-06-17 14:20:39 +02:00
// MARK: ViewModel
class ViewModel: ObservableObject {
2019-06-13 21:30:56 +02:00
let objectWillChange = ObservableObjectPublisher()
2019-06-13 21:30:56 +02:00
init() {
NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .UserDidAddAccount, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .UserDidDeleteAccount, object: nil)
2019-06-13 21:30:56 +02:00
NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange(_:)), name: .DisplayNameDidChange, object: nil)
}
var accounts: [Account] {
get {
return AccountManager.shared.sortedAccounts
}
set {
}
}
var activeAccounts: [Account] {
get {
return AccountManager.shared.sortedActiveAccounts
}
set {
}
}
2019-06-13 21:30:56 +02:00
var sortOldestToNewest: Bool {
get {
return AppDefaults.timelineSortDirection == .orderedDescending
}
set {
objectWillChange.send()
2019-06-13 21:30:56 +02:00
if newValue == true {
AppDefaults.timelineSortDirection = .orderedDescending
} else {
AppDefaults.timelineSortDirection = .orderedAscending
}
}
}
2019-09-09 00:41:00 +02:00
var groupByFeed: Bool {
get {
return AppDefaults.timelineGroupByFeed
}
set {
objectWillChange.send()
AppDefaults.timelineGroupByFeed = newValue
}
}
2019-06-13 21:30:56 +02:00
var timelineNumberOfLines: Int {
get {
return AppDefaults.timelineNumberOfLines
}
set {
objectWillChange.send()
2019-06-13 21:30:56 +02:00
AppDefaults.timelineNumberOfLines = newValue
}
}
var refreshInterval: RefreshInterval {
get {
return AppDefaults.refreshInterval
}
set {
objectWillChange.send()
2019-06-13 21:30:56 +02:00
AppDefaults.refreshInterval = newValue
}
}
@objc func accountsDidChange(_ notification: Notification) {
objectWillChange.send()
2019-06-13 21:30:56 +02:00
}
@objc func displayNameDidChange(_ notification: Notification) {
objectWillChange.send()
2019-06-13 21:30:56 +02:00
}
}
2019-06-11 23:59:16 +02:00
}
#if DEBUG
struct SettingsView_Previews : PreviewProvider {
static var previews: some View {
2019-06-13 21:30:56 +02:00
SettingsView(viewModel: SettingsView.ViewModel())
2019-06-11 23:59:16 +02:00
}
}
#endif