diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index eab5f9426..a6cd26935 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -139,7 +139,7 @@ 51EF0F902279C9500050506E /* AccountsAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */; }; 51EF0F922279CA620050506E /* AccountsAddTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */; }; 51F35D0922AFD4760003CE1B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F35D0822AFD4760003CE1B /* SettingsView.swift */; }; - 51F35D1B22B001010003CE1B /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F35D1A22B001010003CE1B /* SettingsViewModel.swift */; }; + 51F772F622B279570087D9D1 /* SettingsDetailAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F772EC22B2789B0087D9D1 /* SettingsDetailAccountView.swift */; }; 51F85BE5227217D000C787DC /* RefreshIntervalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BDB2272162F00C787DC /* RefreshIntervalViewController.swift */; }; 51F85BE7227245FC00C787DC /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BE6227245FC00C787DC /* AboutViewController.swift */; }; 51F85BEB22724CB600C787DC /* About.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 51F85BEA22724CB600C787DC /* About.rtf */; }; @@ -730,7 +730,7 @@ 51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddViewController.swift; sourceTree = ""; }; 51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddTableCellView.swift; sourceTree = ""; }; 51F35D0822AFD4760003CE1B /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; - 51F35D1A22B001010003CE1B /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = ""; }; + 51F772EC22B2789B0087D9D1 /* SettingsDetailAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDetailAccountView.swift; sourceTree = ""; }; 51F85BDB2272162F00C787DC /* RefreshIntervalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshIntervalViewController.swift; sourceTree = ""; }; 51F85BE6227245FC00C787DC /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; 51F85BEA22724CB600C787DC /* About.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = About.rtf; sourceTree = ""; }; @@ -1040,13 +1040,13 @@ 5183CCEB227117C70010922C /* Settings */ = { isa = PBXGroup; children = ( - 51F35CFD22AFD0350003CE1B /* UIKit */, - 51F35D0822AFD4760003CE1B /* SettingsView.swift */, - 51F35D1A22B001010003CE1B /* SettingsViewModel.swift */, 510D708122B041CC004E8F65 /* SettingsAccountLabelView.swift */, 510D707322B028E1004E8F65 /* SettingsAddAccountView.swift */, - 510D707D22B02A4B004E8F65 /* SettingsLocalAccountView.swift */, + 51F772EC22B2789B0087D9D1 /* SettingsDetailAccountView.swift */, 510D707F22B02A5F004E8F65 /* SettingsFeedbinAccountView.swift */, + 510D707D22B02A4B004E8F65 /* SettingsLocalAccountView.swift */, + 51F35D0822AFD4760003CE1B /* SettingsView.swift */, + 51F35CFD22AFD0350003CE1B /* UIKit */, ); path = Settings; sourceTree = ""; @@ -1935,12 +1935,12 @@ ORGANIZATIONNAME = "Ranchero Software"; TargetAttributes = { 6581C73220CED60000F4AD34 = { - DevelopmentTeam = M8L2WTLA8W; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Manual; }; 840D617B2029031C009BC708 = { CreatedOnToolsVersion = 9.3; - DevelopmentTeam = M8L2WTLA8W; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.BackgroundModes = { @@ -1950,7 +1950,7 @@ }; 849C645F1ED37A5D003D8FC0 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = M8L2WTLA8W; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Manual; SystemCapabilities = { com.apple.HardenedRuntime = { @@ -1960,7 +1960,7 @@ }; 849C64701ED37A5D003D8FC0 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = 9C84TZ7Q6Z; + DevelopmentTeam = SHJK2V3AJG; ProvisioningStyle = Automatic; TestTargetID = 849C645F1ED37A5D003D8FC0; }; @@ -2324,6 +2324,7 @@ 510D707422B028E1004E8F65 /* SettingsAddAccountView.swift in Sources */, 51C45294226509C800C03939 /* SearchFeedDelegate.swift in Sources */, 512E09352268B25900BDCFDD /* UISplitViewController-Extensions.swift in Sources */, + 51F772F622B279570087D9D1 /* SettingsDetailAccountView.swift in Sources */, 510D707E22B02A4B004E8F65 /* SettingsLocalAccountView.swift in Sources */, 51C452A022650A1900C03939 /* FeedIconDownloader.swift in Sources */, 51F85BE7227245FC00C787DC /* AboutViewController.swift in Sources */, @@ -2348,7 +2349,6 @@ 51C4529922650A0000C03939 /* ArticleStylesManager.swift in Sources */, 51EF0F802277A8330050506E /* MasterTimelineCellLayout.swift in Sources */, 51F85BF722749FA100C787DC /* UIFont-Extensions.swift in Sources */, - 51F35D1B22B001010003CE1B /* SettingsViewModel.swift in Sources */, 515436882291D75D005E1CDF /* AddLocalAccountViewController.swift in Sources */, 51C452AF2265108300C03939 /* ArticleArray.swift in Sources */, 51C4528E2265099C00C03939 /* SmartFeedsController.swift in Sources */, diff --git a/iOS/MasterFeed/MasterFeedViewController.swift b/iOS/MasterFeed/MasterFeedViewController.swift index f91f0ca6a..13eca1c11 100644 --- a/iOS/MasterFeed/MasterFeedViewController.swift +++ b/iOS/MasterFeed/MasterFeedViewController.swift @@ -394,7 +394,7 @@ class MasterFeedViewController: ProgressTableViewController, UndoableCommandRunn @IBAction func settings(_ sender: UIBarButtonItem) { - let settings = UIHostingController(rootView: SettingsView(viewModel: SettingsViewModel())) + let settings = UIHostingController(rootView: SettingsView(viewModel: SettingsView.ViewModel())) self.present(settings, animated: true) } diff --git a/iOS/Settings/SettingsAddAccountView.swift b/iOS/Settings/SettingsAddAccountView.swift index ae18edabc..fde5175f0 100644 --- a/iOS/Settings/SettingsAddAccountView.swift +++ b/iOS/Settings/SettingsAddAccountView.swift @@ -7,11 +7,12 @@ // import SwiftUI +import Account struct SettingsAddAccountView : View { var body: some View { List { - PresentationButton(SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: "On My Device"), + PresentationButton(SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: Account.defaultLocalAccountName), destination: SettingsLocalAccountView(name: "")).padding(.all, 4) PresentationButton(SettingsAccountLabelView(accountImage: "accountFeedbin", accountLabel: "Feedbin"), destination: SettingsFeedbinAccountView(viewModel: SettingsFeedbinAccountView.ViewModel())).padding(.all, 4) diff --git a/iOS/Settings/SettingsDetailAccountView.swift b/iOS/Settings/SettingsDetailAccountView.swift new file mode 100644 index 000000000..75f4fe1fe --- /dev/null +++ b/iOS/Settings/SettingsDetailAccountView.swift @@ -0,0 +1,114 @@ +// +// SettingsDetailAccountView.swift +// NetNewsWire +// +// Created by Maurice Parker on 6/13/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Combine +import Account + +struct SettingsDetailAccountView : View { + @ObjectBinding var viewModel: ViewModel + @State private var verifyDelete = false + + var body: some View { + List { + Section { + HStack { + Text("Name") + Divider() + TextField($viewModel.name, placeholder: Text("(Optional)")) + } + Toggle(isOn: $viewModel.isActive) { + Text("Active") + } + } + Section { + HStack { + Spacer() + Button(action: { + + }) { + Text("Credentials") + } + Spacer() + } + } + if viewModel.isDeletable { + Section { + HStack { + Spacer() + Button(action: { + self.verifyDelete = true + }) { + Text("Delete Account") + .foregroundColor(.red) + } + .presentation($verifyDelete) { + Alert(title: Text("Are you sure you want to delete \"\(viewModel.nameForDisplay)\"?"), + primaryButton: Alert.Button.default(Text("Delete"), onTrigger: { self.viewModel.delete() }), + secondaryButton: Alert.Button.cancel()) + } + Spacer() + } + } + } + } + .listStyle(.grouped) + .navigationBarTitle(Text(verbatim: viewModel.nameForDisplay), displayMode: .inline) + + } + + class ViewModel: BindableObject { + let didChange = PassthroughSubject() + let account: Account + + init(_ account: Account) { + self.account = account + } + + var nameForDisplay: String { + account.nameForDisplay + } + + var name: String { + get { + account.name ?? "" + } + set { + account.name = newValue.isEmpty ? nil : newValue + didChange.send(self) + } + } + + var isActive: Bool { + get { + account.isActive + } + set { + account.isActive = newValue + didChange.send(self) + } + } + + var isDeletable: Bool { + return AccountManager.shared.defaultAccount != account + } + + func delete() { + AccountManager.shared.deleteAccount(account) + } + } +} + +#if DEBUG +struct SettingsDetailAccountView_Previews : PreviewProvider { + static var previews: some View { + let viewModel = SettingsDetailAccountView.ViewModel(AccountManager.shared.defaultAccount) + return SettingsDetailAccountView(viewModel: viewModel) + } +} +#endif diff --git a/iOS/Settings/SettingsLocalAccountView.swift b/iOS/Settings/SettingsLocalAccountView.swift index e39edcec4..40f671661 100644 --- a/iOS/Settings/SettingsLocalAccountView.swift +++ b/iOS/Settings/SettingsLocalAccountView.swift @@ -17,7 +17,7 @@ struct SettingsLocalAccountView : View { NavigationView { List { Section(header: - SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: "On My Device").padding() + SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: Account.defaultLocalAccountName).padding() ) { HStack { Spacer() diff --git a/iOS/Settings/SettingsView.swift b/iOS/Settings/SettingsView.swift index 629e78b25..d0ddae653 100644 --- a/iOS/Settings/SettingsView.swift +++ b/iOS/Settings/SettingsView.swift @@ -7,10 +7,11 @@ // import SwiftUI +import Combine import Account struct SettingsView : View { - @ObjectBinding var viewModel: SettingsViewModel + @ObjectBinding var viewModel: ViewModel var body: some View { NavigationView { @@ -18,7 +19,9 @@ struct SettingsView : View { Section(header: Text("ACCOUNTS")) { ForEach(viewModel.accounts.identified(by: \.self)) { account in - Text(verbatim: account.nameForDisplay) + NavigationButton(destination: SettingsDetailAccountView(viewModel: SettingsDetailAccountView.ViewModel(account)), isDetail: false) { + Text(verbatim: account.nameForDisplay) + } } NavigationButton(destination: SettingsAddAccountView(), isDetail: false) { Text("Add Account") @@ -83,12 +86,74 @@ struct SettingsView : View { } } + + class ViewModel: BindableObject { + + let didChange = PassthroughSubject() + + init() { + NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .AccountsDidChange, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange(_:)), name: .DisplayNameDidChange, object: nil) + } + + var accounts: [Account] { + get { + return AccountManager.shared.sortedAccounts + } + set { + } + } + + var sortOldestToNewest: Bool { + get { + return AppDefaults.timelineSortDirection == .orderedDescending + } + set { + if newValue == true { + AppDefaults.timelineSortDirection = .orderedDescending + } else { + AppDefaults.timelineSortDirection = .orderedAscending + } + didChange.send(self) + } + } + + var timelineNumberOfLines: Int { + get { + return AppDefaults.timelineNumberOfLines + } + set { + AppDefaults.timelineNumberOfLines = newValue + didChange.send(self) + } + } + + var refreshInterval: RefreshInterval { + get { + return AppDefaults.refreshInterval + } + set { + AppDefaults.refreshInterval = newValue + didChange.send(self) + } + } + + @objc func accountsDidChange(_ notification: Notification) { + didChange.send(self) + } + + @objc func displayNameDidChange(_ notification: Notification) { + didChange.send(self) + } + + } + } #if DEBUG struct SettingsView_Previews : PreviewProvider { static var previews: some View { - SettingsView(viewModel: SettingsViewModel()) + SettingsView(viewModel: SettingsView.ViewModel()) } } #endif diff --git a/iOS/Settings/SettingsViewModel.swift b/iOS/Settings/SettingsViewModel.swift deleted file mode 100644 index d51735fa4..000000000 --- a/iOS/Settings/SettingsViewModel.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// SettingsViewModel.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 6/11/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import Foundation -import SwiftUI -import Combine -import Account - -class SettingsViewModel: BindableObject { - - let didChange = PassthroughSubject() - - init() { - NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .AccountsDidChange, object: nil) - } - - var accounts: [Account] { - get { - return AccountManager.shared.accounts - } - set { - } - } - - var sortOldestToNewest: Bool { - get { - return AppDefaults.timelineSortDirection == .orderedDescending - } - set { - if newValue == true { - AppDefaults.timelineSortDirection = .orderedDescending - } else { - AppDefaults.timelineSortDirection = .orderedAscending - } - didChange.send(self) - } - } - - var timelineNumberOfLines: Int { - get { - return AppDefaults.timelineNumberOfLines - } - set { - AppDefaults.timelineNumberOfLines = newValue - didChange.send(self) - } - } - - var refreshInterval: RefreshInterval { - get { - return AppDefaults.refreshInterval - } - set { - AppDefaults.refreshInterval = newValue - didChange.send(self) - } - } - - @objc func accountsDidChange(_ notification: Notification) { - didChange.send(self) - } - -}