Change settings from using SwiftUI to using UIKit
This commit is contained in:
parent
94f31b18bc
commit
effec24674
@ -9,7 +9,6 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
49F40DF82335B71000552BF4 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; };
|
49F40DF82335B71000552BF4 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; };
|
||||||
49F40DF92335B71000552BF4 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; };
|
49F40DF92335B71000552BF4 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; };
|
||||||
510BD15D232D765D002692E4 /* SettingsReaderAPIAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557EE1A522B6F4E1004206FA /* SettingsReaderAPIAccountView.swift */; };
|
|
||||||
51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */; };
|
51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */; };
|
||||||
51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */; };
|
51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */; };
|
||||||
5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */; };
|
5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */; };
|
||||||
@ -43,15 +42,11 @@
|
|||||||
513146C5235A8FDB00387FDC /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; };
|
513146C5235A8FDB00387FDC /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; };
|
||||||
51314704235C41FC00387FDC /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 51314707235C41FC00387FDC /* Intents.intentdefinition */; };
|
51314704235C41FC00387FDC /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 51314707235C41FC00387FDC /* Intents.intentdefinition */; };
|
||||||
51314705235C41FC00387FDC /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 51314707235C41FC00387FDC /* Intents.intentdefinition */; };
|
51314705235C41FC00387FDC /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 51314707235C41FC00387FDC /* Intents.intentdefinition */; };
|
||||||
51314716235C862200387FDC /* SettingsSubscriptionsImportAccountPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51314715235C862200387FDC /* SettingsSubscriptionsImportAccountPickerView.swift */; };
|
|
||||||
51314718235C89ED00387FDC /* SettingsSubscriptionsExportAccountPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51314717235C89ED00387FDC /* SettingsSubscriptionsExportAccountPickerView.swift */; };
|
|
||||||
51322855232EED360033D4ED /* VibrantSelectAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51322854232EED360033D4ED /* VibrantSelectAction.swift */; };
|
51322855232EED360033D4ED /* VibrantSelectAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51322854232EED360033D4ED /* VibrantSelectAction.swift */; };
|
||||||
51322859232FDDB80033D4ED /* VibrantButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51322858232FDDB80033D4ED /* VibrantButtonStyle.swift */; };
|
51322859232FDDB80033D4ED /* VibrantButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51322858232FDDB80033D4ED /* VibrantButtonStyle.swift */; };
|
||||||
5132285B232FF2C40033D4ED /* SettingsRefreshSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5132285A232FF2C40033D4ED /* SettingsRefreshSelectionView.swift */; };
|
|
||||||
513228FB233037630033D4ED /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513228F2233037620033D4ED /* Reachability.swift */; };
|
513228FB233037630033D4ED /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513228F2233037620033D4ED /* Reachability.swift */; };
|
||||||
513228FC233037630033D4ED /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513228F2233037620033D4ED /* Reachability.swift */; };
|
513228FC233037630033D4ED /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513228F2233037620033D4ED /* Reachability.swift */; };
|
||||||
513229312330523F0033D4ED /* AttributedStringView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513229302330523F0033D4ED /* AttributedStringView.swift */; };
|
513229312330523F0033D4ED /* AttributedStringView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513229302330523F0033D4ED /* AttributedStringView.swift */; };
|
||||||
5132293B23305D4C0033D4ED /* SettingsAboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5132293A23305D4C0033D4ED /* SettingsAboutView.swift */; };
|
|
||||||
513C5CE9232571C2003D4054 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513C5CE8232571C2003D4054 /* ShareViewController.swift */; };
|
513C5CE9232571C2003D4054 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513C5CE8232571C2003D4054 /* ShareViewController.swift */; };
|
||||||
513C5CEC232571C2003D4054 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 513C5CEA232571C2003D4054 /* MainInterface.storyboard */; };
|
513C5CEC232571C2003D4054 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 513C5CEA232571C2003D4054 /* MainInterface.storyboard */; };
|
||||||
513C5CF0232571C2003D4054 /* NetNewsWire iOS Share Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
513C5CF0232571C2003D4054 /* NetNewsWire iOS Share Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
@ -81,8 +76,6 @@
|
|||||||
5148F4552336DB7000F8CD8B /* MasterTimelineTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5148F4542336DB7000F8CD8B /* MasterTimelineTitleView.swift */; };
|
5148F4552336DB7000F8CD8B /* MasterTimelineTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5148F4542336DB7000F8CD8B /* MasterTimelineTitleView.swift */; };
|
||||||
514B7C8323205EFB00BAC947 /* RootSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514B7C8223205EFB00BAC947 /* RootSplitViewController.swift */; };
|
514B7C8323205EFB00BAC947 /* RootSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514B7C8223205EFB00BAC947 /* RootSplitViewController.swift */; };
|
||||||
514B7D1F23219F3C00BAC947 /* AddControllerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514B7D1E23219F3C00BAC947 /* AddControllerType.swift */; };
|
514B7D1F23219F3C00BAC947 /* AddControllerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514B7D1E23219F3C00BAC947 /* AddControllerType.swift */; };
|
||||||
5152E0F923248F6200E5C7AD /* SettingsLocalAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510D707D22B02A4B004E8F65 /* SettingsLocalAccountView.swift */; };
|
|
||||||
5152E1022324900D00E5C7AD /* SettingsAddAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510D707322B028E1004E8F65 /* SettingsAddAccountView.swift */; };
|
|
||||||
5154368B229404D1005E1CDF /* FaviconGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F76227716200050506E /* FaviconGenerator.swift */; };
|
5154368B229404D1005E1CDF /* FaviconGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F76227716200050506E /* FaviconGenerator.swift */; };
|
||||||
51554C24228B71910055115A /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; };
|
51554C24228B71910055115A /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; };
|
||||||
51554C25228B71910055115A /* SyncDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
51554C25228B71910055115A /* SyncDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
@ -112,14 +105,18 @@
|
|||||||
51938DF2231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
|
51938DF2231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
|
||||||
51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
|
51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
|
||||||
519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; };
|
519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; };
|
||||||
519D73FB2323FF35008BB345 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F35D0822AFD4760003CE1B /* SettingsView.swift */; };
|
|
||||||
519D740623243CC0008BB345 /* RefreshInterval-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519D740523243CC0008BB345 /* RefreshInterval-Extensions.swift */; };
|
519D740623243CC0008BB345 /* RefreshInterval-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519D740523243CC0008BB345 /* RefreshInterval-Extensions.swift */; };
|
||||||
519D740723243FE7008BB345 /* SettingsSubscriptionsExportDocumentPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5194B5F122B69FCC00144881 /* SettingsSubscriptionsExportDocumentPickerView.swift */; };
|
|
||||||
519D740823243FEA008BB345 /* SettingsSubscriptionsImportDocumentPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5194B5ED22B6965300144881 /* SettingsSubscriptionsImportDocumentPickerView.swift */; };
|
|
||||||
519E743D22C663F900A78E47 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519E743422C663F900A78E47 /* SceneDelegate.swift */; };
|
519E743D22C663F900A78E47 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519E743422C663F900A78E47 /* SceneDelegate.swift */; };
|
||||||
51AF45E123246731001742EF /* SettingsAccountLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510D708122B041CC004E8F65 /* SettingsAccountLabelView.swift */; };
|
51A16997235E10D700EB091F /* RefreshIntervalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A1698D235E10D600EB091F /* RefreshIntervalViewController.swift */; };
|
||||||
51AF460323247321001742EF /* SettingsDetailAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F772EC22B2789B0087D9D1 /* SettingsDetailAccountView.swift */; };
|
51A16998235E10D700EB091F /* SettingsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51A1698E235E10D600EB091F /* SettingsTableViewCell.xib */; };
|
||||||
51AF460C23247F11001742EF /* SettingsFeedbinAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510D707F22B02A5F004E8F65 /* SettingsFeedbinAccountView.swift */; };
|
51A16999235E10D700EB091F /* AddLocalAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A1698F235E10D600EB091F /* AddLocalAccountViewController.swift */; };
|
||||||
|
51A1699A235E10D700EB091F /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51A16990235E10D600EB091F /* Settings.storyboard */; };
|
||||||
|
51A1699B235E10D700EB091F /* DetailAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16991235E10D600EB091F /* DetailAccountViewController.swift */; };
|
||||||
|
51A1699C235E10D700EB091F /* AddAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16992235E10D600EB091F /* AddAccountViewController.swift */; };
|
||||||
|
51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16993235E10D600EB091F /* SettingsViewController.swift */; };
|
||||||
|
51A1699E235E10D700EB091F /* TimelineNumberOfLinesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16994235E10D600EB091F /* TimelineNumberOfLinesViewController.swift */; };
|
||||||
|
51A1699F235E10D700EB091F /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16995235E10D600EB091F /* AboutViewController.swift */; };
|
||||||
|
51A169A0235E10D700EB091F /* FeedbinAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */; };
|
||||||
51AF460E232488C6001742EF /* Account-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51AF460D232488C6001742EF /* Account-Extensions.swift */; };
|
51AF460E232488C6001742EF /* Account-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51AF460D232488C6001742EF /* Account-Extensions.swift */; };
|
||||||
51B62E68233186730085F949 /* MasterTimelineAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B62E67233186730085F949 /* MasterTimelineAvatarView.swift */; };
|
51B62E68233186730085F949 /* MasterTimelineAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B62E67233186730085F949 /* MasterTimelineAvatarView.swift */; };
|
||||||
51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */; };
|
51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */; };
|
||||||
@ -730,10 +727,6 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
49F40DEF2335B71000552BF4 /* newsfoot.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = newsfoot.js; sourceTree = "<group>"; };
|
49F40DEF2335B71000552BF4 /* newsfoot.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = newsfoot.js; sourceTree = "<group>"; };
|
||||||
510D707322B028E1004E8F65 /* SettingsAddAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAddAccountView.swift; sourceTree = "<group>"; };
|
|
||||||
510D707D22B02A4B004E8F65 /* SettingsLocalAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsLocalAccountView.swift; sourceTree = "<group>"; };
|
|
||||||
510D707F22B02A5F004E8F65 /* SettingsFeedbinAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFeedbinAccountView.swift; sourceTree = "<group>"; };
|
|
||||||
510D708122B041CC004E8F65 /* SettingsAccountLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAccountLabelView.swift; sourceTree = "<group>"; };
|
|
||||||
51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleExtractorButton.swift; sourceTree = "<group>"; };
|
51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleExtractorButton.swift; sourceTree = "<group>"; };
|
||||||
51121AA12265430A00BC0EC1 /* NetNewsWire_iOSapp_target.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSapp_target.xcconfig; sourceTree = "<group>"; };
|
51121AA12265430A00BC0EC1 /* NetNewsWire_iOSapp_target.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSapp_target.xcconfig; sourceTree = "<group>"; };
|
||||||
51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContainerViewController.swift; sourceTree = "<group>"; };
|
51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContainerViewController.swift; sourceTree = "<group>"; };
|
||||||
@ -754,14 +747,10 @@
|
|||||||
513146B1235A81A400387FDC /* AddFeedIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeedIntentHandler.swift; sourceTree = "<group>"; };
|
513146B1235A81A400387FDC /* AddFeedIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeedIntentHandler.swift; sourceTree = "<group>"; };
|
||||||
51314706235C41FC00387FDC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = "<group>"; };
|
51314706235C41FC00387FDC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = "<group>"; };
|
||||||
51314714235C420900387FDC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Intents.strings; sourceTree = "<group>"; };
|
51314714235C420900387FDC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Intents.strings; sourceTree = "<group>"; };
|
||||||
51314715235C862200387FDC /* SettingsSubscriptionsImportAccountPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSubscriptionsImportAccountPickerView.swift; sourceTree = "<group>"; };
|
|
||||||
51314717235C89ED00387FDC /* SettingsSubscriptionsExportAccountPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSubscriptionsExportAccountPickerView.swift; sourceTree = "<group>"; };
|
|
||||||
51322854232EED360033D4ED /* VibrantSelectAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantSelectAction.swift; sourceTree = "<group>"; };
|
51322854232EED360033D4ED /* VibrantSelectAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantSelectAction.swift; sourceTree = "<group>"; };
|
||||||
51322858232FDDB80033D4ED /* VibrantButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantButtonStyle.swift; sourceTree = "<group>"; };
|
51322858232FDDB80033D4ED /* VibrantButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantButtonStyle.swift; sourceTree = "<group>"; };
|
||||||
5132285A232FF2C40033D4ED /* SettingsRefreshSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRefreshSelectionView.swift; sourceTree = "<group>"; };
|
|
||||||
513228F2233037620033D4ED /* Reachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = "<group>"; };
|
513228F2233037620033D4ED /* Reachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = "<group>"; };
|
||||||
513229302330523F0033D4ED /* AttributedStringView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringView.swift; sourceTree = "<group>"; };
|
513229302330523F0033D4ED /* AttributedStringView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringView.swift; sourceTree = "<group>"; };
|
||||||
5132293A23305D4C0033D4ED /* SettingsAboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAboutView.swift; sourceTree = "<group>"; };
|
|
||||||
513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NetNewsWire iOS Share Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NetNewsWire iOS Share Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
513C5CE8232571C2003D4054 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
513C5CE8232571C2003D4054 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
||||||
513C5CEB232571C2003D4054 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
513C5CEB232571C2003D4054 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||||
@ -803,11 +792,19 @@
|
|||||||
51934CC1230F5963006127BE /* ThemedNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemedNavigationController.swift; sourceTree = "<group>"; };
|
51934CC1230F5963006127BE /* ThemedNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemedNavigationController.swift; sourceTree = "<group>"; };
|
||||||
51934CCD2310792F006127BE /* ActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityManager.swift; sourceTree = "<group>"; };
|
51934CCD2310792F006127BE /* ActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityManager.swift; sourceTree = "<group>"; };
|
||||||
51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTimelineFeedDelegate.swift; sourceTree = "<group>"; };
|
51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTimelineFeedDelegate.swift; sourceTree = "<group>"; };
|
||||||
5194B5ED22B6965300144881 /* SettingsSubscriptionsImportDocumentPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSubscriptionsImportDocumentPickerView.swift; sourceTree = "<group>"; };
|
|
||||||
5194B5F122B69FCC00144881 /* SettingsSubscriptionsExportDocumentPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSubscriptionsExportDocumentPickerView.swift; sourceTree = "<group>"; };
|
|
||||||
519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = "<group>"; };
|
519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = "<group>"; };
|
||||||
519D740523243CC0008BB345 /* RefreshInterval-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RefreshInterval-Extensions.swift"; sourceTree = "<group>"; };
|
519D740523243CC0008BB345 /* RefreshInterval-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RefreshInterval-Extensions.swift"; sourceTree = "<group>"; };
|
||||||
519E743422C663F900A78E47 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
519E743422C663F900A78E47 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
51A1698D235E10D600EB091F /* RefreshIntervalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshIntervalViewController.swift; sourceTree = "<group>"; };
|
||||||
|
51A1698E235E10D600EB091F /* SettingsTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsTableViewCell.xib; sourceTree = "<group>"; };
|
||||||
|
51A1698F235E10D600EB091F /* AddLocalAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddLocalAccountViewController.swift; sourceTree = "<group>"; };
|
||||||
|
51A16990235E10D600EB091F /* Settings.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = "<group>"; };
|
||||||
|
51A16991235E10D600EB091F /* DetailAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailAccountViewController.swift; sourceTree = "<group>"; };
|
||||||
|
51A16992235E10D600EB091F /* AddAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddAccountViewController.swift; sourceTree = "<group>"; };
|
||||||
|
51A16993235E10D600EB091F /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
|
||||||
|
51A16994235E10D600EB091F /* TimelineNumberOfLinesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineNumberOfLinesViewController.swift; sourceTree = "<group>"; };
|
||||||
|
51A16995235E10D600EB091F /* AboutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
|
||||||
|
51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedbinAccountViewController.swift; sourceTree = "<group>"; };
|
||||||
51AF460D232488C6001742EF /* Account-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account-Extensions.swift"; sourceTree = "<group>"; };
|
51AF460D232488C6001742EF /* Account-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account-Extensions.swift"; sourceTree = "<group>"; };
|
||||||
51B62E67233186730085F949 /* MasterTimelineAvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineAvatarView.swift; sourceTree = "<group>"; };
|
51B62E67233186730085F949 /* MasterTimelineAvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineAvatarView.swift; sourceTree = "<group>"; };
|
||||||
51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleActivityItemSource.swift; sourceTree = "<group>"; };
|
51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleActivityItemSource.swift; sourceTree = "<group>"; };
|
||||||
@ -852,8 +849,6 @@
|
|||||||
51EF0F8D2279C9260050506E /* AccountsAdd.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountsAdd.xib; sourceTree = "<group>"; };
|
51EF0F8D2279C9260050506E /* AccountsAdd.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountsAdd.xib; sourceTree = "<group>"; };
|
||||||
51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddViewController.swift; sourceTree = "<group>"; };
|
51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddViewController.swift; sourceTree = "<group>"; };
|
||||||
51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddTableCellView.swift; sourceTree = "<group>"; };
|
51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddTableCellView.swift; sourceTree = "<group>"; };
|
||||||
51F35D0822AFD4760003CE1B /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
|
||||||
51F772EC22B2789B0087D9D1 /* SettingsDetailAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDetailAccountView.swift; sourceTree = "<group>"; };
|
|
||||||
51F85BEA22724CB600C787DC /* About.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = About.rtf; sourceTree = "<group>"; };
|
51F85BEA22724CB600C787DC /* About.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = About.rtf; sourceTree = "<group>"; };
|
||||||
51F85BEC227251DF00C787DC /* Acknowledgments.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Acknowledgments.rtf; sourceTree = "<group>"; };
|
51F85BEC227251DF00C787DC /* Acknowledgments.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Acknowledgments.rtf; sourceTree = "<group>"; };
|
||||||
51F85BEE2272520B00C787DC /* Thanks.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Thanks.rtf; sourceTree = "<group>"; };
|
51F85BEE2272520B00C787DC /* Thanks.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Thanks.rtf; sourceTree = "<group>"; };
|
||||||
@ -871,7 +866,6 @@
|
|||||||
51FD40BD2341555600880194 /* UIImage-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage-Extensions.swift"; sourceTree = "<group>"; };
|
51FD40BD2341555600880194 /* UIImage-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage-Extensions.swift"; sourceTree = "<group>"; };
|
||||||
51FD413A2342BD0500880194 /* MasterTimelineUnreadCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineUnreadCountView.swift; sourceTree = "<group>"; };
|
51FD413A2342BD0500880194 /* MasterTimelineUnreadCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineUnreadCountView.swift; sourceTree = "<group>"; };
|
||||||
51FE10022345529D0056195D /* UserNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationManager.swift; sourceTree = "<group>"; };
|
51FE10022345529D0056195D /* UserNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationManager.swift; sourceTree = "<group>"; };
|
||||||
557EE1A522B6F4E1004206FA /* SettingsReaderAPIAccountView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsReaderAPIAccountView.swift; sourceTree = "<group>"; };
|
|
||||||
55E15BC1229D65A900D6602A /* AccountsReaderAPI.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsReaderAPI.xib; sourceTree = "<group>"; };
|
55E15BC1229D65A900D6602A /* AccountsReaderAPI.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsReaderAPI.xib; sourceTree = "<group>"; };
|
||||||
55E15BCA229D65A900D6602A /* AccountsReaderAPIWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsReaderAPIWindowController.swift; sourceTree = "<group>"; };
|
55E15BCA229D65A900D6602A /* AccountsReaderAPIWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsReaderAPIWindowController.swift; sourceTree = "<group>"; };
|
||||||
5F323808231DF9F000706F6B /* NNWTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NNWTableViewCell.swift; sourceTree = "<group>"; };
|
5F323808231DF9F000706F6B /* NNWTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NNWTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
@ -1265,19 +1259,6 @@
|
|||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
515E4F06232506240057B0E7 /* Account */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
510D708122B041CC004E8F65 /* SettingsAccountLabelView.swift */,
|
|
||||||
510D707322B028E1004E8F65 /* SettingsAddAccountView.swift */,
|
|
||||||
51F772EC22B2789B0087D9D1 /* SettingsDetailAccountView.swift */,
|
|
||||||
510D707F22B02A5F004E8F65 /* SettingsFeedbinAccountView.swift */,
|
|
||||||
510D707D22B02A4B004E8F65 /* SettingsLocalAccountView.swift */,
|
|
||||||
557EE1A522B6F4E1004206FA /* SettingsReaderAPIAccountView.swift */,
|
|
||||||
);
|
|
||||||
path = Account;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
5183CCDB226F1EEB0010922C /* Progress */ = {
|
5183CCDB226F1EEB0010922C /* Progress */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -1300,14 +1281,16 @@
|
|||||||
5183CCEB227117C70010922C /* Settings */ = {
|
5183CCEB227117C70010922C /* Settings */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
51F35D0822AFD4760003CE1B /* SettingsView.swift */,
|
51A16990235E10D600EB091F /* Settings.storyboard */,
|
||||||
5132293A23305D4C0033D4ED /* SettingsAboutView.swift */,
|
51A16995235E10D600EB091F /* AboutViewController.swift */,
|
||||||
5132285A232FF2C40033D4ED /* SettingsRefreshSelectionView.swift */,
|
51A16992235E10D600EB091F /* AddAccountViewController.swift */,
|
||||||
51314717235C89ED00387FDC /* SettingsSubscriptionsExportAccountPickerView.swift */,
|
51A1698F235E10D600EB091F /* AddLocalAccountViewController.swift */,
|
||||||
5194B5F122B69FCC00144881 /* SettingsSubscriptionsExportDocumentPickerView.swift */,
|
51A16991235E10D600EB091F /* DetailAccountViewController.swift */,
|
||||||
51314715235C862200387FDC /* SettingsSubscriptionsImportAccountPickerView.swift */,
|
51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */,
|
||||||
5194B5ED22B6965300144881 /* SettingsSubscriptionsImportDocumentPickerView.swift */,
|
51A1698D235E10D600EB091F /* RefreshIntervalViewController.swift */,
|
||||||
515E4F06232506240057B0E7 /* Account */,
|
51A1698E235E10D600EB091F /* SettingsTableViewCell.xib */,
|
||||||
|
51A16993235E10D600EB091F /* SettingsViewController.swift */,
|
||||||
|
51A16994235E10D600EB091F /* TimelineNumberOfLinesViewController.swift */,
|
||||||
);
|
);
|
||||||
path = Settings;
|
path = Settings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2648,6 +2631,7 @@
|
|||||||
51C452862265093600C03939 /* Add.storyboard in Resources */,
|
51C452862265093600C03939 /* Add.storyboard in Resources */,
|
||||||
511D43EF231FBDE900FB1562 /* LaunchScreenPad.storyboard in Resources */,
|
511D43EF231FBDE900FB1562 /* LaunchScreenPad.storyboard in Resources */,
|
||||||
511D43D2231FA62C00FB1562 /* GlobalKeyboardShortcuts.plist in Resources */,
|
511D43D2231FA62C00FB1562 /* GlobalKeyboardShortcuts.plist in Resources */,
|
||||||
|
51A16998235E10D700EB091F /* SettingsTableViewCell.xib in Resources */,
|
||||||
84C9FCA12262A1B300D921D6 /* Main.storyboard in Resources */,
|
84C9FCA12262A1B300D921D6 /* Main.storyboard in Resources */,
|
||||||
51BB7C312335ACDE008E8144 /* page.html in Resources */,
|
51BB7C312335ACDE008E8144 /* page.html in Resources */,
|
||||||
51F85BF32272531500C787DC /* Dedication.rtf in Resources */,
|
51F85BF32272531500C787DC /* Dedication.rtf in Resources */,
|
||||||
@ -2660,6 +2644,7 @@
|
|||||||
51F85BF12272524100C787DC /* Credits.rtf in Resources */,
|
51F85BF12272524100C787DC /* Credits.rtf in Resources */,
|
||||||
84A3EE61223B667F00557320 /* DefaultFeeds.opml in Resources */,
|
84A3EE61223B667F00557320 /* DefaultFeeds.opml in Resources */,
|
||||||
511D43CF231FA62200FB1562 /* DetailKeyboardShortcuts.plist in Resources */,
|
511D43CF231FA62200FB1562 /* DetailKeyboardShortcuts.plist in Resources */,
|
||||||
|
51A1699A235E10D700EB091F /* Settings.storyboard in Resources */,
|
||||||
49F40DF92335B71000552BF4 /* newsfoot.js in Resources */,
|
49F40DF92335B71000552BF4 /* newsfoot.js in Resources */,
|
||||||
51F85BEF2272520B00C787DC /* Thanks.rtf in Resources */,
|
51F85BEF2272520B00C787DC /* Thanks.rtf in Resources */,
|
||||||
84C9FC9D2262A1A900D921D6 /* Assets.xcassets in Resources */,
|
84C9FC9D2262A1A900D921D6 /* Assets.xcassets in Resources */,
|
||||||
@ -2913,7 +2898,6 @@
|
|||||||
5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */,
|
5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */,
|
||||||
51EAED96231363EF00A9EEE3 /* NonIntrinsicButton.swift in Sources */,
|
51EAED96231363EF00A9EEE3 /* NonIntrinsicButton.swift in Sources */,
|
||||||
51C4527B2265091600C03939 /* MasterUnreadIndicatorView.swift in Sources */,
|
51C4527B2265091600C03939 /* MasterUnreadIndicatorView.swift in Sources */,
|
||||||
5152E1022324900D00E5C7AD /* SettingsAddAccountView.swift in Sources */,
|
|
||||||
51F85BF92274AA7B00C787DC /* UIBarButtonItem-Extensions.swift in Sources */,
|
51F85BF92274AA7B00C787DC /* UIBarButtonItem-Extensions.swift in Sources */,
|
||||||
51B62E68233186730085F949 /* MasterTimelineAvatarView.swift in Sources */,
|
51B62E68233186730085F949 /* MasterTimelineAvatarView.swift in Sources */,
|
||||||
51C45296226509D300C03939 /* OPMLExporter.swift in Sources */,
|
51C45296226509D300C03939 /* OPMLExporter.swift in Sources */,
|
||||||
@ -2927,36 +2911,30 @@
|
|||||||
51FD413B2342BD0500880194 /* MasterTimelineUnreadCountView.swift in Sources */,
|
51FD413B2342BD0500880194 /* MasterTimelineUnreadCountView.swift in Sources */,
|
||||||
513146B2235A81A400387FDC /* AddFeedIntentHandler.swift in Sources */,
|
513146B2235A81A400387FDC /* AddFeedIntentHandler.swift in Sources */,
|
||||||
5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */,
|
5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */,
|
||||||
51AF45E123246731001742EF /* SettingsAccountLabelView.swift in Sources */,
|
|
||||||
51D87EE12311D34700E63F03 /* ActivityType.swift in Sources */,
|
51D87EE12311D34700E63F03 /* ActivityType.swift in Sources */,
|
||||||
51C452772265091600C03939 /* MultilineUILabelSizer.swift in Sources */,
|
51C452772265091600C03939 /* MultilineUILabelSizer.swift in Sources */,
|
||||||
51C452A522650A2D00C03939 /* SmallIconProvider.swift in Sources */,
|
51C452A522650A2D00C03939 /* SmallIconProvider.swift in Sources */,
|
||||||
51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */,
|
51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */,
|
||||||
51322859232FDDB80033D4ED /* VibrantButtonStyle.swift in Sources */,
|
51322859232FDDB80033D4ED /* VibrantButtonStyle.swift in Sources */,
|
||||||
|
51A1699C235E10D700EB091F /* AddAccountViewController.swift in Sources */,
|
||||||
|
51A16999235E10D700EB091F /* AddLocalAccountViewController.swift in Sources */,
|
||||||
514B7C8323205EFB00BAC947 /* RootSplitViewController.swift in Sources */,
|
514B7C8323205EFB00BAC947 /* RootSplitViewController.swift in Sources */,
|
||||||
5152E0F923248F6200E5C7AD /* SettingsLocalAccountView.swift in Sources */,
|
|
||||||
51FA73A52332BE110090D516 /* ArticleExtractor.swift in Sources */,
|
51FA73A52332BE110090D516 /* ArticleExtractor.swift in Sources */,
|
||||||
51314704235C41FC00387FDC /* Intents.intentdefinition in Sources */,
|
51314704235C41FC00387FDC /* Intents.intentdefinition in Sources */,
|
||||||
FF3ABF162325AF5D0074C542 /* ArticleSorter.swift in Sources */,
|
FF3ABF162325AF5D0074C542 /* ArticleSorter.swift in Sources */,
|
||||||
510BD15D232D765D002692E4 /* SettingsReaderAPIAccountView.swift in Sources */,
|
|
||||||
51C4525C226508DF00C03939 /* String-Extensions.swift in Sources */,
|
51C4525C226508DF00C03939 /* String-Extensions.swift in Sources */,
|
||||||
51C452792265091600C03939 /* MasterTimelineTableViewCell.swift in Sources */,
|
51C452792265091600C03939 /* MasterTimelineTableViewCell.swift in Sources */,
|
||||||
51FA73AB2332C2FD0090D516 /* ArticleExtractorConfig.swift in Sources */,
|
51FA73AB2332C2FD0090D516 /* ArticleExtractorConfig.swift in Sources */,
|
||||||
5132285B232FF2C40033D4ED /* SettingsRefreshSelectionView.swift in Sources */,
|
|
||||||
51C452852265093600C03939 /* FlattenedAccountFolderPickerData.swift in Sources */,
|
51C452852265093600C03939 /* FlattenedAccountFolderPickerData.swift in Sources */,
|
||||||
51C4526B226508F600C03939 /* MasterFeedViewController.swift in Sources */,
|
51C4526B226508F600C03939 /* MasterFeedViewController.swift in Sources */,
|
||||||
5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */,
|
5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */,
|
||||||
51FD40C72341555A00880194 /* UIImage-Extensions.swift in Sources */,
|
51FD40C72341555A00880194 /* UIImage-Extensions.swift in Sources */,
|
||||||
5132293B23305D4C0033D4ED /* SettingsAboutView.swift in Sources */,
|
|
||||||
84CAFCB022BC8C35007694F0 /* FetchRequestOperation.swift in Sources */,
|
84CAFCB022BC8C35007694F0 /* FetchRequestOperation.swift in Sources */,
|
||||||
51EF0F77227716200050506E /* FaviconGenerator.swift in Sources */,
|
51EF0F77227716200050506E /* FaviconGenerator.swift in Sources */,
|
||||||
51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */,
|
51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */,
|
||||||
51C4525A226508D600C03939 /* UIStoryboard-Extensions.swift in Sources */,
|
51C4525A226508D600C03939 /* UIStoryboard-Extensions.swift in Sources */,
|
||||||
519D740823243FEA008BB345 /* SettingsSubscriptionsImportDocumentPickerView.swift in Sources */,
|
|
||||||
51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */,
|
51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */,
|
||||||
51AF460C23247F11001742EF /* SettingsFeedbinAccountView.swift in Sources */,
|
|
||||||
51F85BF52273625800C787DC /* Bundle-Extensions.swift in Sources */,
|
51F85BF52273625800C787DC /* Bundle-Extensions.swift in Sources */,
|
||||||
519D740723243FE7008BB345 /* SettingsSubscriptionsExportDocumentPickerView.swift in Sources */,
|
|
||||||
51C452A622650A3500C03939 /* Node-Extensions.swift in Sources */,
|
51C452A622650A3500C03939 /* Node-Extensions.swift in Sources */,
|
||||||
5183CCDF226F1FCC0010922C /* UINavigationController+Progress.swift in Sources */,
|
5183CCDF226F1FCC0010922C /* UINavigationController+Progress.swift in Sources */,
|
||||||
51C45294226509C800C03939 /* SearchFeedDelegate.swift in Sources */,
|
51C45294226509C800C03939 /* SearchFeedDelegate.swift in Sources */,
|
||||||
@ -2991,22 +2969,24 @@
|
|||||||
84CAFCA522BC8C08007694F0 /* FetchRequestQueue.swift in Sources */,
|
84CAFCA522BC8C08007694F0 /* FetchRequestQueue.swift in Sources */,
|
||||||
51C4529C22650A1000C03939 /* SingleFaviconDownloader.swift in Sources */,
|
51C4529C22650A1000C03939 /* SingleFaviconDownloader.swift in Sources */,
|
||||||
51E595A6228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */,
|
51E595A6228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */,
|
||||||
|
51A1699F235E10D700EB091F /* AboutViewController.swift in Sources */,
|
||||||
51C45290226509C100C03939 /* PseudoFeed.swift in Sources */,
|
51C45290226509C100C03939 /* PseudoFeed.swift in Sources */,
|
||||||
51C452A922650DC600C03939 /* ArticleRenderer.swift in Sources */,
|
51C452A922650DC600C03939 /* ArticleRenderer.swift in Sources */,
|
||||||
51AF460323247321001742EF /* SettingsDetailAccountView.swift in Sources */,
|
|
||||||
5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */,
|
5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */,
|
||||||
51C45297226509E300C03939 /* DefaultFeedsImporter.swift in Sources */,
|
51C45297226509E300C03939 /* DefaultFeedsImporter.swift in Sources */,
|
||||||
512E094D2268B8AB00BDCFDD /* DeleteCommand.swift in Sources */,
|
512E094D2268B8AB00BDCFDD /* DeleteCommand.swift in Sources */,
|
||||||
51F85BFB2275D85000C787DC /* Array-Extensions.swift in Sources */,
|
51F85BFB2275D85000C787DC /* Array-Extensions.swift in Sources */,
|
||||||
51C452AC22650FD200C03939 /* AppNotifications.swift in Sources */,
|
51C452AC22650FD200C03939 /* AppNotifications.swift in Sources */,
|
||||||
51EF0F7E2277A57D0050506E /* MasterTimelineAccessibilityCellLayout.swift in Sources */,
|
51EF0F7E2277A57D0050506E /* MasterTimelineAccessibilityCellLayout.swift in Sources */,
|
||||||
|
51A1699B235E10D700EB091F /* DetailAccountViewController.swift in Sources */,
|
||||||
51C452762265091600C03939 /* MasterTimelineViewController.swift in Sources */,
|
51C452762265091600C03939 /* MasterTimelineViewController.swift in Sources */,
|
||||||
51314718235C89ED00387FDC /* SettingsSubscriptionsExportAccountPickerView.swift in Sources */,
|
|
||||||
5183CCE9226F68D90010922C /* AccountRefreshTimer.swift in Sources */,
|
5183CCE9226F68D90010922C /* AccountRefreshTimer.swift in Sources */,
|
||||||
51C452882265093600C03939 /* AddFeedViewController.swift in Sources */,
|
51C452882265093600C03939 /* AddFeedViewController.swift in Sources */,
|
||||||
|
51A169A0235E10D700EB091F /* FeedbinAccountViewController.swift in Sources */,
|
||||||
51934CCE2310792F006127BE /* ActivityManager.swift in Sources */,
|
51934CCE2310792F006127BE /* ActivityManager.swift in Sources */,
|
||||||
518651DA235621840078E021 /* ImageTransition.swift in Sources */,
|
518651DA235621840078E021 /* ImageTransition.swift in Sources */,
|
||||||
514219372352510100E07E2C /* ImageScrollView.swift in Sources */,
|
514219372352510100E07E2C /* ImageScrollView.swift in Sources */,
|
||||||
|
51A16997235E10D700EB091F /* RefreshIntervalViewController.swift in Sources */,
|
||||||
DF999FF722B5AEFA0064B687 /* SafariView.swift in Sources */,
|
DF999FF722B5AEFA0064B687 /* SafariView.swift in Sources */,
|
||||||
51C4529B22650A1000C03939 /* FaviconDownloader.swift in Sources */,
|
51C4529B22650A1000C03939 /* FaviconDownloader.swift in Sources */,
|
||||||
84DEE56622C32CA4005FC42C /* SmartFeedDelegate.swift in Sources */,
|
84DEE56622C32CA4005FC42C /* SmartFeedDelegate.swift in Sources */,
|
||||||
@ -3025,13 +3005,13 @@
|
|||||||
5148F4552336DB7000F8CD8B /* MasterTimelineTitleView.swift in Sources */,
|
5148F4552336DB7000F8CD8B /* MasterTimelineTitleView.swift in Sources */,
|
||||||
513228FC233037630033D4ED /* Reachability.swift in Sources */,
|
513228FC233037630033D4ED /* Reachability.swift in Sources */,
|
||||||
51C45259226508D300C03939 /* AppDefaults.swift in Sources */,
|
51C45259226508D300C03939 /* AppDefaults.swift in Sources */,
|
||||||
519D73FB2323FF35008BB345 /* SettingsView.swift in Sources */,
|
|
||||||
511D4419231FC02D00FB1562 /* KeyboardManager.swift in Sources */,
|
511D4419231FC02D00FB1562 /* KeyboardManager.swift in Sources */,
|
||||||
|
51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */,
|
||||||
|
51A1699E235E10D700EB091F /* TimelineNumberOfLinesViewController.swift in Sources */,
|
||||||
51C45293226509C800C03939 /* StarredFeedDelegate.swift in Sources */,
|
51C45293226509C800C03939 /* StarredFeedDelegate.swift in Sources */,
|
||||||
513229312330523F0033D4ED /* AttributedStringView.swift in Sources */,
|
513229312330523F0033D4ED /* AttributedStringView.swift in Sources */,
|
||||||
51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */,
|
51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */,
|
||||||
51934CCB230F599B006127BE /* ThemedNavigationController.swift in Sources */,
|
51934CCB230F599B006127BE /* ThemedNavigationController.swift in Sources */,
|
||||||
51314716235C862200387FDC /* SettingsSubscriptionsImportAccountPickerView.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -786,9 +786,10 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func showSettings() {
|
func showSettings() {
|
||||||
rootSplitViewController.present(style: .formSheet) {
|
let settingsNavController = UIStoryboard.settings.instantiateInitialViewController() as! UINavigationController
|
||||||
SettingsView(viewModel: SettingsView.ViewModel()).environment(\.sceneCoordinator, self)
|
settingsNavController.modalPresentationStyle = .formSheet
|
||||||
}
|
settingsNavController.preferredContentSize = SettingsViewController.preferredContentSizeForFormSheetDisplay
|
||||||
|
masterFeedViewController.present(settingsNavController, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func showFeedInspector() {
|
func showFeedInspector() {
|
||||||
|
56
iOS/Settings/AboutViewController.swift
Normal file
56
iOS/Settings/AboutViewController.swift
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// AboutViewController.swift
|
||||||
|
// NetNewsWire-iOS
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 4/25/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class AboutViewController: UITableViewController {
|
||||||
|
|
||||||
|
@IBOutlet weak var aboutTextView: UITextView!
|
||||||
|
@IBOutlet weak var creditsTextView: UITextView!
|
||||||
|
@IBOutlet weak var acknowledgmentsTextView: UITextView!
|
||||||
|
@IBOutlet weak var thanksTextView: UITextView!
|
||||||
|
@IBOutlet weak var dedicationTextView: UITextView!
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
configureCell(file: "About", textView: aboutTextView)
|
||||||
|
configureCell(file: "Credits", textView: creditsTextView)
|
||||||
|
configureCell(file: "Acknowledgments", textView: acknowledgmentsTextView)
|
||||||
|
configureCell(file: "Thanks", textView: thanksTextView)
|
||||||
|
configureCell(file: "Dedication", textView: dedicationTextView)
|
||||||
|
|
||||||
|
let buildLabel = NonIntrinsicLabel(frame: CGRect(x: 20.0, y: 0.0, width: 0.0, height: 0.0))
|
||||||
|
buildLabel.font = UIFont.systemFont(ofSize: 11.0)
|
||||||
|
buildLabel.textColor = UIColor.gray
|
||||||
|
buildLabel.text = NSLocalizedString("Copyright © 2002-2019 Ranchero Software", comment: "Copyright")
|
||||||
|
buildLabel.numberOfLines = 0
|
||||||
|
buildLabel.sizeToFit()
|
||||||
|
buildLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
tableView.tableFooterView = buildLabel
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||||
|
return UITableView.automaticDimension
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension AboutViewController {
|
||||||
|
|
||||||
|
func configureCell(file: String, textView: UITextView) {
|
||||||
|
let url = Bundle.main.url(forResource: file, withExtension: "rtf")!
|
||||||
|
let string = try! NSAttributedString(url: url, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil)
|
||||||
|
textView.attributedText = string
|
||||||
|
textView.adjustsFontForContentSizeCategory = true
|
||||||
|
textView.font = .preferredFont(forTextStyle: .body)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,34 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsAccountLabelView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 6/11/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct SettingsAccountLabelView : View {
|
|
||||||
let accountImage: String
|
|
||||||
let accountLabel: String
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack {
|
|
||||||
Image(accountImage)
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(1, contentMode: .fit)
|
|
||||||
.frame(height: 32)
|
|
||||||
Text(verbatim: accountLabel).font(.title)
|
|
||||||
}
|
|
||||||
.foregroundColor(.primary).padding(4.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
struct SettingsAccountLabelView_Previews : PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: "On My Device")
|
|
||||||
.previewLayout(.fixed(width: 300, height: 44))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsAddAccountView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 6/11/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Account
|
|
||||||
|
|
||||||
struct SettingsAddAccountView : View {
|
|
||||||
@Environment(\.presentationMode) var presentation
|
|
||||||
@State private var accountAddAction: Int? = nil
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Form {
|
|
||||||
|
|
||||||
NavigationLink(destination: SettingsLocalAccountView(name: ""), tag: 1, selection: $accountAddAction) {
|
|
||||||
SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: Account.defaultLocalAccountName)
|
|
||||||
}
|
|
||||||
.modifier(VibrantSelectAction(action: {
|
|
||||||
self.accountAddAction = 1
|
|
||||||
})).padding(.vertical, 16)
|
|
||||||
|
|
||||||
NavigationLink(destination: SettingsFeedbinAccountView(viewModel: SettingsFeedbinAccountView.ViewModel()), tag: 2, selection: $accountAddAction) {
|
|
||||||
SettingsAccountLabelView(accountImage: "accountFeedbin", accountLabel: "Feedbin")
|
|
||||||
|
|
||||||
}
|
|
||||||
.modifier(VibrantSelectAction(action: {
|
|
||||||
self.accountAddAction = 2
|
|
||||||
})).padding(.vertical, 16)
|
|
||||||
|
|
||||||
// NavigationLink(destination: SettingsReaderAPIAccountView(viewModel: SettingsReaderAPIAccountView.ViewModel(accountType: .freshRSS)), tag: 3, selection: $accountAddAction) {
|
|
||||||
// SettingsAccountLabelView(accountImage: "accountFreshRSS", accountLabel: "Fresh RSS")
|
|
||||||
// }
|
|
||||||
// .modifier(VibrantSelectAction(action: {
|
|
||||||
// self.accountAddAction = 3
|
|
||||||
// }))
|
|
||||||
|
|
||||||
}
|
|
||||||
.navigationBarTitle(Text("Add Account"), displayMode: .inline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
struct AddAccountView_Previews : PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
SettingsAddAccountView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,137 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsDetailAccountView.swift
|
|
||||||
// NetNewsWire
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 6/13/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Combine
|
|
||||||
import Account
|
|
||||||
import RSWeb
|
|
||||||
|
|
||||||
struct SettingsDetailAccountView : View {
|
|
||||||
@Environment(\.presentationMode) var presentation
|
|
||||||
@ObservedObject var viewModel: ViewModel
|
|
||||||
@State private var credentialsAction: Int? = nil
|
|
||||||
@State private var isDeleteAlertPresented = false
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Form {
|
|
||||||
Section {
|
|
||||||
HStack {
|
|
||||||
TextField("Name", text: $viewModel.name)
|
|
||||||
}
|
|
||||||
Toggle(isOn: $viewModel.isActive) {
|
|
||||||
Text("Active")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if viewModel.isCreditialsAvailable {
|
|
||||||
if viewModel.account.type == .feedbin {
|
|
||||||
NavigationLink(destination: self.settingsFeedbinAccountView, tag: 1, selection: $credentialsAction) {
|
|
||||||
Text("Credentials")
|
|
||||||
}
|
|
||||||
.modifier(VibrantSelectAction(action: {
|
|
||||||
self.credentialsAction = 1
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
if viewModel.account.type == .freshRSS {
|
|
||||||
NavigationLink(destination: self.settingsReaderAPIAccountView, tag: 1, selection: $credentialsAction) {
|
|
||||||
Text("Credentials")
|
|
||||||
}
|
|
||||||
.modifier(VibrantSelectAction(action: {
|
|
||||||
self.credentialsAction = 1
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if viewModel.isDeletable {
|
|
||||||
Section {
|
|
||||||
Button(action: {
|
|
||||||
self.isDeleteAlertPresented.toggle()
|
|
||||||
}) {
|
|
||||||
Text("Delete Account").foregroundColor(.red)
|
|
||||||
}
|
|
||||||
.alert(isPresented: $isDeleteAlertPresented) {
|
|
||||||
Alert(title: Text("Are you sure you want to delete \"\(viewModel.nameForDisplay)\"?"),
|
|
||||||
primaryButton: Alert.Button.default(Text("Delete"), action: {
|
|
||||||
self.viewModel.delete()
|
|
||||||
self.presentation.wrappedValue.dismiss()
|
|
||||||
}),
|
|
||||||
secondaryButton: Alert.Button.cancel())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.buttonStyle(VibrantButtonStyle(alignment: .center))
|
|
||||||
.navigationBarTitle(Text(verbatim: viewModel.nameForDisplay), displayMode: .inline)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var settingsFeedbinAccountView: SettingsFeedbinAccountView {
|
|
||||||
let feedbinViewModel = SettingsFeedbinAccountView.ViewModel(account: viewModel.account)
|
|
||||||
return SettingsFeedbinAccountView(viewModel: feedbinViewModel)
|
|
||||||
}
|
|
||||||
|
|
||||||
var settingsReaderAPIAccountView: SettingsReaderAPIAccountView {
|
|
||||||
let readerAPIModel = SettingsReaderAPIAccountView.ViewModel(account: viewModel.account)
|
|
||||||
return SettingsReaderAPIAccountView(viewModel: readerAPIModel)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewModel: ObservableObject {
|
|
||||||
|
|
||||||
let objectWillChange = ObservableObjectPublisher()
|
|
||||||
|
|
||||||
let account: Account
|
|
||||||
|
|
||||||
init(_ account: Account) {
|
|
||||||
self.account = account
|
|
||||||
}
|
|
||||||
|
|
||||||
var nameForDisplay: String {
|
|
||||||
account.nameForDisplay
|
|
||||||
}
|
|
||||||
|
|
||||||
var name: String {
|
|
||||||
get {
|
|
||||||
account.name ?? ""
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
objectWillChange.send()
|
|
||||||
account.name = newValue.isEmpty ? nil : newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var isActive: Bool {
|
|
||||||
get {
|
|
||||||
account.isActive
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
objectWillChange.send()
|
|
||||||
account.isActive = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var isCreditialsAvailable: Bool {
|
|
||||||
return account.type != .onMyMac
|
|
||||||
}
|
|
||||||
|
|
||||||
var isDeletable: Bool {
|
|
||||||
return AccountManager.shared.defaultAccount != account
|
|
||||||
}
|
|
||||||
|
|
||||||
func delete() {
|
|
||||||
AccountManager.shared.deleteAccount(account)
|
|
||||||
ActivityManager.cleanUp(account)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
struct SettingsDetailAccountView_Previews : PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
let viewModel = SettingsDetailAccountView.ViewModel(AccountManager.shared.defaultAccount)
|
|
||||||
return SettingsDetailAccountView(viewModel: viewModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,161 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsFeedbinAccountView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 6/11/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Combine
|
|
||||||
import Account
|
|
||||||
import RSWeb
|
|
||||||
|
|
||||||
struct SettingsFeedbinAccountView : View {
|
|
||||||
@Environment(\.presentationMode) var presentation
|
|
||||||
@ObservedObject var viewModel: ViewModel
|
|
||||||
@State var busy: Bool = false
|
|
||||||
@State var error: String = ""
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Form {
|
|
||||||
Section(header:
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
SettingsAccountLabelView(accountImage: "accountFeedbin", accountLabel: "Feedbin")
|
|
||||||
.padding()
|
|
||||||
.layoutPriority(1.0)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
TextField("Email", text: $viewModel.email)
|
|
||||||
.keyboardType(.emailAddress)
|
|
||||||
.textContentType(.emailAddress)
|
|
||||||
PasswordField(password: $viewModel.password)
|
|
||||||
}
|
|
||||||
Section(footer:
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
Text(verbatim: error).foregroundColor(.red)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Button(action: { self.addAccount() }) {
|
|
||||||
if viewModel.isUpdate {
|
|
||||||
Text("Update Account")
|
|
||||||
} else {
|
|
||||||
Text("Add Account")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.buttonStyle(VibrantButtonStyle(alignment: .center))
|
|
||||||
.disabled(!viewModel.isValid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// .disabled(busy) // Maybe someday we can do this, but right now it crashes on the iPad
|
|
||||||
.navigationBarTitle(Text(""), displayMode: .inline)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func addAccount() {
|
|
||||||
|
|
||||||
busy = true
|
|
||||||
error = ""
|
|
||||||
|
|
||||||
let emailAddress = viewModel.email.trimmingCharacters(in: .whitespaces)
|
|
||||||
let credentials = Credentials(type: .basic, username: emailAddress, secret: viewModel.password)
|
|
||||||
|
|
||||||
Account.validateCredentials(type: .feedbin, credentials: credentials) { result in
|
|
||||||
|
|
||||||
self.busy = false
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success(let authenticated):
|
|
||||||
|
|
||||||
if (authenticated != nil) {
|
|
||||||
|
|
||||||
var newAccount = false
|
|
||||||
let workAccount: Account
|
|
||||||
if self.viewModel.account == nil {
|
|
||||||
workAccount = AccountManager.shared.createAccount(type: .feedbin)
|
|
||||||
newAccount = true
|
|
||||||
} else {
|
|
||||||
workAccount = self.viewModel.account!
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
do {
|
|
||||||
try workAccount.removeCredentials(type: .basic)
|
|
||||||
} catch {}
|
|
||||||
try workAccount.storeCredentials(credentials)
|
|
||||||
|
|
||||||
if newAccount {
|
|
||||||
workAccount.refreshAll() { result in }
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dismiss()
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
self.error = "Keychain error while storing credentials."
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
self.error = "Invalid email/password combination."
|
|
||||||
}
|
|
||||||
|
|
||||||
case .failure:
|
|
||||||
self.error = "Network error. Try again later."
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private func dismiss() {
|
|
||||||
presentation.wrappedValue.dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewModel: ObservableObject {
|
|
||||||
|
|
||||||
let objectWillChange = ObservableObjectPublisher()
|
|
||||||
var account: Account? = nil
|
|
||||||
|
|
||||||
init() {
|
|
||||||
}
|
|
||||||
|
|
||||||
init(account: Account) {
|
|
||||||
self.account = account
|
|
||||||
if let credentials = try? account.retrieveCredentials(type: .basic) {
|
|
||||||
self.email = credentials.username
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var email: String = "" {
|
|
||||||
willSet {
|
|
||||||
objectWillChange.send()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var password: String = "" {
|
|
||||||
willSet {
|
|
||||||
objectWillChange.send()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var isUpdate: Bool {
|
|
||||||
return account != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var isValid: Bool {
|
|
||||||
return !email.isEmpty && !password.isEmpty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
struct SettingsFeedbinAccountView_Previews : PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
SettingsFeedbinAccountView(viewModel: SettingsFeedbinAccountView.ViewModel())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,59 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsLocalAccountView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 6/11/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Account
|
|
||||||
|
|
||||||
struct SettingsLocalAccountView : View {
|
|
||||||
@Environment(\.presentationMode) var presentation
|
|
||||||
@State var name: String
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Form {
|
|
||||||
Section(header:
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: Account.defaultLocalAccountName)
|
|
||||||
.padding()
|
|
||||||
.layoutPriority(1.0)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
HStack {
|
|
||||||
TextField("Name", text: $name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Section {
|
|
||||||
Button(action: { self.addAccount() }) {
|
|
||||||
Text("Add Account")
|
|
||||||
}
|
|
||||||
.buttonStyle(VibrantButtonStyle(alignment: .center))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.navigationBarTitle(Text(""), displayMode: .inline)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func addAccount() {
|
|
||||||
let account = AccountManager.shared.createAccount(type: .onMyMac)
|
|
||||||
account.name = name
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func dismiss() {
|
|
||||||
presentation.wrappedValue.dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
struct SettingsLocalAccountView_Previews : PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
SettingsLocalAccountView(name: "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,178 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsReaderAPIAccountView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Jeremy Beker on 5/28/2019.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Combine
|
|
||||||
import Account
|
|
||||||
import RSWeb
|
|
||||||
|
|
||||||
struct SettingsReaderAPIAccountView : View {
|
|
||||||
@Environment(\.presentationMode) var presentation
|
|
||||||
@ObservedObject var viewModel: ViewModel
|
|
||||||
|
|
||||||
@State var busy: Bool = false
|
|
||||||
@State var error: String = ""
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Form {
|
|
||||||
Section(header:
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
SettingsAccountLabelView(accountImage: "accountFreshRSS", accountLabel: "FreshRSS")
|
|
||||||
.padding()
|
|
||||||
.layoutPriority(1.0)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
TextField("Email", text: $viewModel.email)
|
|
||||||
.keyboardType(.emailAddress)
|
|
||||||
.textContentType(.emailAddress)
|
|
||||||
SecureField("Password", text: $viewModel.password)
|
|
||||||
TextField("API URL:", text: $viewModel.apiURL).textContentType(.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
Section(footer:
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
Text(verbatim: error).foregroundColor(.red)
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Button(action: { self.addAccount() }) {
|
|
||||||
if viewModel.isUpdate {
|
|
||||||
Text("Update Account")
|
|
||||||
} else {
|
|
||||||
Text("Add Account")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.buttonStyle(VibrantButtonStyle(alignment: .center))
|
|
||||||
.disabled(!viewModel.isValid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// .disabled(busy)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func addAccount() {
|
|
||||||
|
|
||||||
busy = true
|
|
||||||
error = ""
|
|
||||||
|
|
||||||
let emailAddress = viewModel.email.trimmingCharacters(in: .whitespaces)
|
|
||||||
let credentials = Credentials(type: .readerBasic, username: emailAddress, secret: viewModel.password)
|
|
||||||
guard let apiURL = URL(string: viewModel.apiURL) else {
|
|
||||||
self.error = "Invalid API URL."
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Account.validateCredentials(type: viewModel.accountType, credentials: credentials, endpoint: apiURL) { result in
|
|
||||||
|
|
||||||
self.busy = false
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success(let validatedCredentials):
|
|
||||||
|
|
||||||
guard let validatedCredentials = validatedCredentials else {
|
|
||||||
self.error = "Invalid email/password combination."
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var newAccount = false
|
|
||||||
let workAccount: Account
|
|
||||||
if self.viewModel.account == nil {
|
|
||||||
workAccount = AccountManager.shared.createAccount(type: self.viewModel.accountType)
|
|
||||||
newAccount = true
|
|
||||||
} else {
|
|
||||||
workAccount = self.viewModel.account!
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
do {
|
|
||||||
try workAccount.removeCredentials(type: .readerBasic)
|
|
||||||
try workAccount.removeCredentials(type: .readerAPIKey)
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
workAccount.endpointURL = apiURL
|
|
||||||
|
|
||||||
try workAccount.storeCredentials(credentials)
|
|
||||||
try workAccount.storeCredentials(validatedCredentials)
|
|
||||||
|
|
||||||
if newAccount {
|
|
||||||
workAccount.refreshAll() { result in }
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dismiss()
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
self.error = "Keychain error while storing credentials."
|
|
||||||
}
|
|
||||||
|
|
||||||
case .failure:
|
|
||||||
self.error = "Network error. Try again later."
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private func dismiss() {
|
|
||||||
presentation.wrappedValue.dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewModel: ObservableObject {
|
|
||||||
|
|
||||||
let objectWillChange = ObservableObjectPublisher()
|
|
||||||
var accountType: AccountType
|
|
||||||
var account: Account? = nil
|
|
||||||
|
|
||||||
init(accountType: AccountType) {
|
|
||||||
self.accountType = accountType
|
|
||||||
}
|
|
||||||
|
|
||||||
init(account: Account) {
|
|
||||||
self.account = account
|
|
||||||
self.accountType = account.type
|
|
||||||
if let credentials = try? account.retrieveCredentials(type: .readerBasic) {
|
|
||||||
self.email = credentials.username
|
|
||||||
self.apiURL = account.endpointURL?.absoluteString ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var email: String = "" {
|
|
||||||
willSet {
|
|
||||||
objectWillChange.send()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var password: String = "" {
|
|
||||||
willSet {
|
|
||||||
objectWillChange.send()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var apiURL: String = "" {
|
|
||||||
willSet {
|
|
||||||
objectWillChange.send()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var isUpdate: Bool {
|
|
||||||
return account != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var isValid: Bool {
|
|
||||||
return !email.isEmpty && !password.isEmpty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
struct SettingsReaderAPIAccountView_Previews : PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
SettingsReaderAPIAccountView(viewModel: SettingsReaderAPIAccountView.ViewModel(accountType: .freshRSS))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
49
iOS/Settings/AddAccountViewController.swift
Normal file
49
iOS/Settings/AddAccountViewController.swift
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// AddAccountViewController.swift
|
||||||
|
// NetNewsWire-iOS
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 5/16/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Account
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
protocol AddAccountDismissDelegate: UIViewController {
|
||||||
|
func dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddAccountViewController: UITableViewController, AddAccountDismissDelegate {
|
||||||
|
|
||||||
|
@IBOutlet private weak var localAccountNameLabel: UILabel!
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
localAccountNameLabel.text = Account.defaultLocalAccountName
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
switch indexPath.row {
|
||||||
|
case 0:
|
||||||
|
let navController = UIStoryboard.settings.instantiateViewController(withIdentifier: "AddLocalAccountNavigationViewController") as! UINavigationController
|
||||||
|
navController.modalPresentationStyle = .currentContext
|
||||||
|
let addViewController = navController.topViewController as! AddLocalAccountViewController
|
||||||
|
addViewController.delegate = self
|
||||||
|
present(navController, animated: true)
|
||||||
|
case 1:
|
||||||
|
let navController = UIStoryboard.settings.instantiateViewController(withIdentifier: "FeedbinAccountNavigationViewController") as! UINavigationController
|
||||||
|
navController.modalPresentationStyle = .currentContext
|
||||||
|
let addViewController = navController.topViewController as! FeedbinAccountViewController
|
||||||
|
addViewController.delegate = self
|
||||||
|
present(navController, animated: true)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dismiss() {
|
||||||
|
navigationController?.popViewController(animated: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
iOS/Settings/AddLocalAccountViewController.swift
Normal file
48
iOS/Settings/AddLocalAccountViewController.swift
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// AddLocalAccountViewController.swift
|
||||||
|
// NetNewsWire-iOS
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 5/19/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Account
|
||||||
|
|
||||||
|
class AddLocalAccountViewController: UIViewController {
|
||||||
|
|
||||||
|
@IBOutlet weak var cancelBarButtonItem: UIBarButtonItem!
|
||||||
|
@IBOutlet private weak var localAccountNameLabel: UILabel!
|
||||||
|
@IBOutlet weak var nameTextField: UITextField!
|
||||||
|
|
||||||
|
weak var delegate: AddAccountDismissDelegate?
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
localAccountNameLabel.text = Account.defaultLocalAccountName
|
||||||
|
nameTextField.delegate = self
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func cancel(_ sender: Any) {
|
||||||
|
dismiss(animated: true, completion: nil)
|
||||||
|
delegate?.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func addAccountTapped(_ sender: Any) {
|
||||||
|
let account = AccountManager.shared.createAccount(type: .onMyMac)
|
||||||
|
account.name = nameTextField.text
|
||||||
|
dismiss(animated: true, completion: nil)
|
||||||
|
delegate?.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AddLocalAccountViewController: UITextFieldDelegate {
|
||||||
|
|
||||||
|
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
|
textField.resignFirstResponder()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
135
iOS/Settings/DetailAccountViewController.swift
Normal file
135
iOS/Settings/DetailAccountViewController.swift
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
//
|
||||||
|
// DetailAccountViewController.swift
|
||||||
|
// NetNewsWire-iOS
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 5/17/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Account
|
||||||
|
|
||||||
|
class DetailAccountViewController: UITableViewController {
|
||||||
|
|
||||||
|
@IBOutlet weak var nameTextField: UITextField!
|
||||||
|
@IBOutlet weak var activeSwitch: UISwitch!
|
||||||
|
|
||||||
|
weak var account: Account?
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
guard let account = account else { return }
|
||||||
|
|
||||||
|
nameTextField.placeholder = account.defaultName
|
||||||
|
nameTextField.text = account.name
|
||||||
|
nameTextField.delegate = self
|
||||||
|
activeSwitch.isOn = account.isActive
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillDisappear(_ animated: Bool) {
|
||||||
|
account?.name = nameTextField.text
|
||||||
|
account?.isActive = activeSwitch.isOn
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DetailAccountViewController {
|
||||||
|
|
||||||
|
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||||
|
guard let account = account else { return 0 }
|
||||||
|
|
||||||
|
if account == AccountManager.shared.defaultAccount {
|
||||||
|
return 1
|
||||||
|
} else if account.type == .onMyMac {
|
||||||
|
return 2
|
||||||
|
} else {
|
||||||
|
return super.numberOfSections(in: tableView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let cell: UITableViewCell
|
||||||
|
|
||||||
|
if indexPath.section == 1, let account = account, account.type == .onMyMac {
|
||||||
|
cell = super.tableView(tableView, cellForRowAt: IndexPath(row: 0, section: 2))
|
||||||
|
} else {
|
||||||
|
cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
|
||||||
|
if indexPath.section > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
if let account = account, account.type == .onMyMac {
|
||||||
|
if indexPath.section == 1 {
|
||||||
|
deleteAccount()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch indexPath.section {
|
||||||
|
case 1:
|
||||||
|
credentials()
|
||||||
|
case 2:
|
||||||
|
deleteAccount()
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension DetailAccountViewController {
|
||||||
|
|
||||||
|
func credentials() {
|
||||||
|
guard let account = account else { return }
|
||||||
|
switch account.type {
|
||||||
|
case .feedbin:
|
||||||
|
let navController = UIStoryboard.settings.instantiateViewController(withIdentifier: "FeedbinAccountNavigationViewController") as! UINavigationController
|
||||||
|
let addViewController = navController.topViewController as! FeedbinAccountViewController
|
||||||
|
addViewController.account = account
|
||||||
|
present(navController, animated: true)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteAccount() {
|
||||||
|
let title = NSLocalizedString("Delete Account", comment: "Delete Account")
|
||||||
|
let message = NSLocalizedString("Are you sure you want to delete this account? This can not be undone.", comment: "Delete Account")
|
||||||
|
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||||
|
|
||||||
|
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
|
||||||
|
let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel)
|
||||||
|
alertController.addAction(cancelAction)
|
||||||
|
|
||||||
|
let markTitle = NSLocalizedString("Delete", comment: "Delete")
|
||||||
|
let markAction = UIAlertAction(title: markTitle, style: .default) { [weak self] (action) in
|
||||||
|
guard let account = self?.account else { return }
|
||||||
|
AccountManager.shared.deleteAccount(account)
|
||||||
|
self?.navigationController?.popViewController(animated: true)
|
||||||
|
}
|
||||||
|
alertController.addAction(markAction)
|
||||||
|
|
||||||
|
present(alertController, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DetailAccountViewController: UITextFieldDelegate {
|
||||||
|
|
||||||
|
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
|
textField.resignFirstResponder()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
137
iOS/Settings/FeedbinAccountViewController.swift
Normal file
137
iOS/Settings/FeedbinAccountViewController.swift
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
//
|
||||||
|
// AddFeedbinAccountViewController.swift
|
||||||
|
// NetNewsWire-iOS
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 5/19/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Account
|
||||||
|
import RSWeb
|
||||||
|
|
||||||
|
class FeedbinAccountViewController: UIViewController {
|
||||||
|
|
||||||
|
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
|
||||||
|
@IBOutlet weak var cancelBarButtonItem: UIBarButtonItem!
|
||||||
|
@IBOutlet weak var emailTextField: UITextField!
|
||||||
|
@IBOutlet weak var passwordTextField: UITextField!
|
||||||
|
@IBOutlet weak var actionButton: UIButton!
|
||||||
|
|
||||||
|
@IBOutlet weak var errorMessageLabel: UILabel!
|
||||||
|
|
||||||
|
weak var account: Account?
|
||||||
|
weak var delegate: AddAccountDismissDelegate?
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
activityIndicator.isHidden = true
|
||||||
|
emailTextField.delegate = self
|
||||||
|
passwordTextField.delegate = self
|
||||||
|
|
||||||
|
if let account = account, let credentials = try? account.retrieveCredentials(type: .basic) {
|
||||||
|
actionButton.setTitle(NSLocalizedString("Update Credentials", comment: "Update Credentials"), for: .normal)
|
||||||
|
emailTextField.text = credentials.username
|
||||||
|
passwordTextField.text = credentials.secret
|
||||||
|
} else {
|
||||||
|
actionButton.setTitle(NSLocalizedString("Add Account", comment: "Update Credentials"), for: .normal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func cancel(_ sender: Any) {
|
||||||
|
dismiss(animated: true, completion: nil)
|
||||||
|
delegate?.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func action(_ sender: Any) {
|
||||||
|
self.errorMessageLabel.text = nil
|
||||||
|
|
||||||
|
guard emailTextField.text != nil && passwordTextField.text != nil else {
|
||||||
|
self.errorMessageLabel.text = NSLocalizedString("Username & password required.", comment: "Credentials Error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
startAnimatingActivityIndicator()
|
||||||
|
disableNavigation()
|
||||||
|
|
||||||
|
// When you fill in the email address via auto-complete it adds extra whitespace
|
||||||
|
let emailAddress = emailTextField.text?.trimmingCharacters(in: .whitespaces)
|
||||||
|
let credentials = Credentials(type: .basic, username: emailAddress ?? "", secret: passwordTextField.text ?? "")
|
||||||
|
Account.validateCredentials(type: .feedbin, credentials: credentials) { result in
|
||||||
|
|
||||||
|
self.stopAnimtatingActivityIndicator()
|
||||||
|
self.enableNavigation()
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
case .success(let credentials):
|
||||||
|
if let credentials = credentials {
|
||||||
|
var newAccount = false
|
||||||
|
if self.account == nil {
|
||||||
|
self.account = AccountManager.shared.createAccount(type: .feedbin)
|
||||||
|
newAccount = true
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
do {
|
||||||
|
try self.account?.removeCredentials(type: .basic)
|
||||||
|
} catch {}
|
||||||
|
try self.account?.storeCredentials(credentials)
|
||||||
|
|
||||||
|
if newAccount {
|
||||||
|
self.account?.refreshAll() { result in
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
break
|
||||||
|
case .failure(let error):
|
||||||
|
self.presentError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dismiss(animated: true, completion: nil)
|
||||||
|
self.delegate?.dismiss()
|
||||||
|
} catch {
|
||||||
|
self.errorMessageLabel.text = NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.errorMessageLabel.text = NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error")
|
||||||
|
}
|
||||||
|
case .failure:
|
||||||
|
self.errorMessageLabel.text = NSLocalizedString("Network error. Try again later.", comment: "Credentials Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func enableNavigation() {
|
||||||
|
self.cancelBarButtonItem.isEnabled = true
|
||||||
|
self.actionButton.isEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func disableNavigation() {
|
||||||
|
cancelBarButtonItem.isEnabled = false
|
||||||
|
actionButton.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private func startAnimatingActivityIndicator() {
|
||||||
|
activityIndicator.isHidden = false
|
||||||
|
activityIndicator.startAnimating()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func stopAnimtatingActivityIndicator() {
|
||||||
|
self.activityIndicator.isHidden = true
|
||||||
|
self.activityIndicator.stopAnimating()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FeedbinAccountViewController: UITextFieldDelegate {
|
||||||
|
|
||||||
|
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
|
textField.resignFirstResponder()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
111
iOS/Settings/RefreshIntervalViewController.swift
Normal file
111
iOS/Settings/RefreshIntervalViewController.swift
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
//
|
||||||
|
// RefreshIntervalViewController.swift
|
||||||
|
// NetNewsWire
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 4/25/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class RefreshIntervalViewController: UITableViewController {
|
||||||
|
|
||||||
|
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
return 7
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
|
||||||
|
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
|
||||||
|
|
||||||
|
cell.textLabel?.adjustsFontForContentSizeCategory = true
|
||||||
|
|
||||||
|
let userRefreshInterval = AppDefaults.refreshInterval
|
||||||
|
|
||||||
|
switch indexPath.row {
|
||||||
|
case 0:
|
||||||
|
cell.textLabel?.text = RefreshInterval.manually.description()
|
||||||
|
if userRefreshInterval == RefreshInterval.manually {
|
||||||
|
cell.accessoryType = .checkmark
|
||||||
|
} else {
|
||||||
|
cell.accessoryType = .none
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
cell.textLabel?.text = RefreshInterval.every10Minutes.description()
|
||||||
|
if userRefreshInterval == RefreshInterval.every10Minutes {
|
||||||
|
cell.accessoryType = .checkmark
|
||||||
|
} else {
|
||||||
|
cell.accessoryType = .none
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
cell.textLabel?.text = RefreshInterval.every30Minutes.description()
|
||||||
|
if userRefreshInterval == RefreshInterval.every30Minutes {
|
||||||
|
cell.accessoryType = .checkmark
|
||||||
|
} else {
|
||||||
|
cell.accessoryType = .none
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
cell.textLabel?.text = RefreshInterval.everyHour.description()
|
||||||
|
if userRefreshInterval == RefreshInterval.everyHour {
|
||||||
|
cell.accessoryType = .checkmark
|
||||||
|
} else {
|
||||||
|
cell.accessoryType = .none
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
cell.textLabel?.text = RefreshInterval.every2Hours.description()
|
||||||
|
if userRefreshInterval == RefreshInterval.every2Hours {
|
||||||
|
cell.accessoryType = .checkmark
|
||||||
|
} else {
|
||||||
|
cell.accessoryType = .none
|
||||||
|
}
|
||||||
|
case 5:
|
||||||
|
cell.textLabel?.text = RefreshInterval.every4Hours.description()
|
||||||
|
if userRefreshInterval == RefreshInterval.every4Hours {
|
||||||
|
cell.accessoryType = .checkmark
|
||||||
|
} else {
|
||||||
|
cell.accessoryType = .none
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
cell.textLabel?.text = RefreshInterval.every8Hours.description()
|
||||||
|
if userRefreshInterval == RefreshInterval.every8Hours {
|
||||||
|
cell.accessoryType = .checkmark
|
||||||
|
} else {
|
||||||
|
cell.accessoryType = .none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
|
||||||
|
let refreshInterval: RefreshInterval
|
||||||
|
|
||||||
|
switch indexPath.row {
|
||||||
|
case 0:
|
||||||
|
refreshInterval = RefreshInterval.manually
|
||||||
|
case 1:
|
||||||
|
refreshInterval = RefreshInterval.every10Minutes
|
||||||
|
case 2:
|
||||||
|
refreshInterval = RefreshInterval.every30Minutes
|
||||||
|
case 3:
|
||||||
|
refreshInterval = RefreshInterval.everyHour
|
||||||
|
case 4:
|
||||||
|
refreshInterval = RefreshInterval.every2Hours
|
||||||
|
case 5:
|
||||||
|
refreshInterval = RefreshInterval.every4Hours
|
||||||
|
default:
|
||||||
|
refreshInterval = RefreshInterval.every8Hours
|
||||||
|
}
|
||||||
|
|
||||||
|
AppDefaults.refreshInterval = refreshInterval
|
||||||
|
self.navigationController?.popViewController(animated: true)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1003
iOS/Settings/Settings.storyboard
Normal file
1003
iOS/Settings/Settings.storyboard
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,67 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsAboutView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 9/16/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Combine
|
|
||||||
|
|
||||||
struct SettingsAboutView: View {
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: ViewModel
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
GeometryReader { geometry in
|
|
||||||
List {
|
|
||||||
Text("NetNewsWire").font(.largeTitle)
|
|
||||||
AttributedStringView(string: self.viewModel.about, preferredMaxLayoutWidth: geometry.size.width - 20)
|
|
||||||
Section(header: Text("CREDITS")) {
|
|
||||||
AttributedStringView(string: self.viewModel.credits, preferredMaxLayoutWidth: geometry.size.width - 20)
|
|
||||||
}
|
|
||||||
Section(header: Text("ACKNOWLEDGEMENTS")) {
|
|
||||||
AttributedStringView(string: self.viewModel.acknowledgements, preferredMaxLayoutWidth: geometry.size.width - 20)
|
|
||||||
}
|
|
||||||
Section(header: Text("THANKS")) {
|
|
||||||
AttributedStringView(string: self.viewModel.thanks, preferredMaxLayoutWidth: geometry.size.width - 20)
|
|
||||||
}
|
|
||||||
Section(header: Text("DEDICATION"), footer: Text("Copyright © 2002-2019 Ranchero Software").font(.footnote)) {
|
|
||||||
AttributedStringView(string: self.viewModel.dedication, preferredMaxLayoutWidth: geometry.size.width - 20)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ViewModel: ObservableObject {
|
|
||||||
let objectWillChange = ObservableObjectPublisher()
|
|
||||||
|
|
||||||
var about: NSAttributedString
|
|
||||||
var credits: NSAttributedString
|
|
||||||
var acknowledgements: NSAttributedString
|
|
||||||
var thanks: NSAttributedString
|
|
||||||
var dedication: NSAttributedString
|
|
||||||
|
|
||||||
init() {
|
|
||||||
about = ViewModel.loadResource("About")
|
|
||||||
credits = ViewModel.loadResource("Credits")
|
|
||||||
acknowledgements = ViewModel.loadResource("Acknowledgments")
|
|
||||||
thanks = ViewModel.loadResource("Thanks")
|
|
||||||
dedication = ViewModel.loadResource("Dedication")
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func loadResource(_ resource: String) -> NSAttributedString {
|
|
||||||
let url = Bundle.main.url(forResource: resource, withExtension: "rtf")!
|
|
||||||
return try! NSAttributedString(url: url, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SettingsAboutView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
SettingsAboutView(viewModel: SettingsAboutView.ViewModel())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsRefreshSelectionView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 9/16/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct SettingsRefreshSelectionView: View {
|
|
||||||
|
|
||||||
@Environment(\.presentationMode) var presentation
|
|
||||||
@Binding var selectedInterval: RefreshInterval
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Form {
|
|
||||||
ForEach(RefreshInterval.allCases) { interval in
|
|
||||||
Button(action: {
|
|
||||||
self.selectedInterval = interval
|
|
||||||
self.presentation.wrappedValue.dismiss()
|
|
||||||
}) {
|
|
||||||
HStack {
|
|
||||||
Text(interval.description())
|
|
||||||
Spacer()
|
|
||||||
if interval == self.selectedInterval {
|
|
||||||
Image(systemName: "checkmark")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.buttonStyle(VibrantButtonStyle(alignment: .leading))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsSubscriptionsExportAccountPickerView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 10/20/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Account
|
|
||||||
|
|
||||||
struct SettingsSubscriptionsExportAccountPickerView: View {
|
|
||||||
|
|
||||||
@Environment(\.presentationMode) var presentation
|
|
||||||
@State private var selectedAccount: Account?
|
|
||||||
@State private var isOPMLExportDocPickerPresented: Bool = false
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Form {
|
|
||||||
ForEach(AccountManager.shared.sortedAccounts) { account in
|
|
||||||
Button(action: {
|
|
||||||
self.selectedAccount = account
|
|
||||||
self.isOPMLExportDocPickerPresented = true
|
|
||||||
}) {
|
|
||||||
Text(verbatim: account.nameForDisplay)
|
|
||||||
}.buttonStyle(VibrantButtonStyle(alignment: .leading))
|
|
||||||
}
|
|
||||||
}.sheet(isPresented: $isOPMLExportDocPickerPresented, onDismiss: { self.presentation.wrappedValue.dismiss() }) {
|
|
||||||
SettingsSubscriptionsExportDocumentPickerView(account: self.selectedAccount!)
|
|
||||||
}
|
|
||||||
.navigationBarTitle(Text("Select Account"), displayMode: .inline)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsSubscriptionsExportDocumentPickerView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 6/16/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Account
|
|
||||||
|
|
||||||
struct SettingsSubscriptionsExportDocumentPickerView : UIViewControllerRepresentable {
|
|
||||||
var account: Account
|
|
||||||
|
|
||||||
func makeUIViewController(context: UIViewControllerRepresentableContext<SettingsSubscriptionsExportDocumentPickerView>) -> UIDocumentPickerViewController {
|
|
||||||
|
|
||||||
let accountName = account.nameForDisplay.replacingOccurrences(of: " ", with: "").trimmingCharacters(in: .whitespaces)
|
|
||||||
let filename = "Subscriptions-\(accountName).opml"
|
|
||||||
let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(filename)
|
|
||||||
|
|
||||||
let opmlString = OPMLExporter.OPMLString(with: account, title: filename)
|
|
||||||
try? opmlString.write(to: tempFile, atomically: true, encoding: String.Encoding.utf8)
|
|
||||||
|
|
||||||
return UIDocumentPickerViewController(url: tempFile, in: .exportToService)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<SettingsSubscriptionsExportDocumentPickerView>) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsSubscriptionsImportAccountPickerView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 10/20/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Account
|
|
||||||
|
|
||||||
struct SettingsSubscriptionsImportAccountPickerView: View {
|
|
||||||
|
|
||||||
@Environment(\.presentationMode) var presentation
|
|
||||||
@State private var selectedAccount: Account?
|
|
||||||
@State private var isOPMLImportDocPickerPresented: Bool = false
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Form {
|
|
||||||
ForEach(AccountManager.shared.sortedActiveAccounts) { account in
|
|
||||||
Button(action: {
|
|
||||||
self.selectedAccount = account
|
|
||||||
self.isOPMLImportDocPickerPresented = true
|
|
||||||
}) {
|
|
||||||
Text(verbatim: account.nameForDisplay)
|
|
||||||
}.buttonStyle(VibrantButtonStyle(alignment: .leading))
|
|
||||||
}
|
|
||||||
}.sheet(isPresented: $isOPMLImportDocPickerPresented, onDismiss: { self.presentation.wrappedValue.dismiss() }) {
|
|
||||||
SettingsSubscriptionsImportDocumentPickerView(account: self.selectedAccount!)
|
|
||||||
}
|
|
||||||
.navigationBarTitle(Text("Select Account"), displayMode: .inline)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsSubscriptionsImportDocumentPickerView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 6/16/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Account
|
|
||||||
|
|
||||||
struct SettingsSubscriptionsImportDocumentPickerView : UIViewControllerRepresentable {
|
|
||||||
var account: Account
|
|
||||||
|
|
||||||
func makeUIViewController(context: UIViewControllerRepresentableContext<SettingsSubscriptionsImportDocumentPickerView>) -> UIDocumentPickerViewController {
|
|
||||||
let docPicker = UIDocumentPickerViewController(documentTypes: ["public.xml", "org.opml.opml"], in: .import)
|
|
||||||
docPicker.delegate = context.coordinator
|
|
||||||
return docPicker
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<SettingsSubscriptionsImportDocumentPickerView>) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeCoordinator() -> Coordinator {
|
|
||||||
return Coordinator(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Coordinator : NSObject, UIDocumentPickerDelegate {
|
|
||||||
var parent: SettingsSubscriptionsImportDocumentPickerView
|
|
||||||
|
|
||||||
init(_ view: SettingsSubscriptionsImportDocumentPickerView) {
|
|
||||||
self.parent = view
|
|
||||||
}
|
|
||||||
|
|
||||||
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
|
||||||
for url in urls {
|
|
||||||
parent.account.importOPML(url) { result in}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
24
iOS/Settings/SettingsTableViewCell.xib
Normal file
24
iOS/Settings/SettingsTableViewCell.xib
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
|
<device id="retina6_1" orientation="portrait">
|
||||||
|
<adaptation id="fullscreen"/>
|
||||||
|
</device>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
|
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="JCb-QB-CrO">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="JCb-QB-CrO" id="FzD-t2-JGy">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="376" height="43.5"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
</tableViewCellContentView>
|
||||||
|
<point key="canvasLocation" x="7" y="-9"/>
|
||||||
|
</tableViewCell>
|
||||||
|
</objects>
|
||||||
|
</document>
|
@ -1,270 +0,0 @@
|
|||||||
//
|
|
||||||
// SettingsView.swift
|
|
||||||
// NetNewsWire-iOS
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 6/11/19.
|
|
||||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Combine
|
|
||||||
import Account
|
|
||||||
|
|
||||||
struct SettingsView : View {
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: ViewModel
|
|
||||||
|
|
||||||
@Environment(\.viewController) private var viewController: UIViewController?
|
|
||||||
@Environment(\.sceneCoordinator) private var coordinator: SceneCoordinator?
|
|
||||||
|
|
||||||
@State private var accountAction: Int? = nil
|
|
||||||
@State private var refreshAction: Int? = nil
|
|
||||||
@State private var importOPMLAction: Int? = nil
|
|
||||||
@State private var exportOPMLAction: Int? = nil
|
|
||||||
@State private var aboutAction: Int? = nil
|
|
||||||
|
|
||||||
@State private var isWebsitePresented: Bool = false
|
|
||||||
@State private var website: String? = nil
|
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
NavigationView {
|
|
||||||
Form {
|
|
||||||
buildAccountsSection()
|
|
||||||
buildTimelineSection()
|
|
||||||
buildDatabaseSection()
|
|
||||||
buildAboutSection()
|
|
||||||
}
|
|
||||||
.buttonStyle(VibrantButtonStyle(alignment: .leading))
|
|
||||||
.navigationBarTitle(Text("Settings"), displayMode: .inline)
|
|
||||||
.navigationBarItems(leading: Button(action: { self.viewController?.dismiss(animated: true) }) { Text("Done") } )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildAccountsSection() -> some View {
|
|
||||||
Section(header: Text("ACCOUNTS").padding(.top, 22.0)) {
|
|
||||||
ForEach(viewModel.accounts.indices, id: \.self) { index in
|
|
||||||
NavigationLink(destination: SettingsDetailAccountView(viewModel: SettingsDetailAccountView.ViewModel(self.viewModel.accounts[index])), tag: index, selection: self.$accountAction) {
|
|
||||||
Text(verbatim: self.viewModel.accounts[index].nameForDisplay)
|
|
||||||
}
|
|
||||||
.modifier(VibrantSelectAction(action: {
|
|
||||||
self.accountAction = index
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
NavigationLink(destination: SettingsAddAccountView(), tag: 1000, selection: $accountAction) {
|
|
||||||
Text("Add Account")
|
|
||||||
}
|
|
||||||
.modifier(VibrantSelectAction(action: {
|
|
||||||
self.accountAction = 1000
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildTimelineSection() -> some View {
|
|
||||||
Section(header: Text("TIMELINE")) {
|
|
||||||
Toggle(isOn: $viewModel.sortOldestToNewest) {
|
|
||||||
Text("Sort Newest to Oldest")
|
|
||||||
}
|
|
||||||
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")) {
|
|
||||||
|
|
||||||
NavigationLink(destination: SettingsRefreshSelectionView(selectedInterval: $viewModel.refreshInterval), tag: 1, selection: $refreshAction) {
|
|
||||||
HStack {
|
|
||||||
Text("Refresh Interval")
|
|
||||||
Spacer()
|
|
||||||
Text(verbatim: self.viewModel.refreshInterval.description()).foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.modifier(VibrantSelectAction(action: {
|
|
||||||
self.refreshAction = 1
|
|
||||||
}))
|
|
||||||
|
|
||||||
NavigationLink(destination: SettingsSubscriptionsImportAccountPickerView(), tag: 1, selection: $importOPMLAction) {
|
|
||||||
Text("Import Subscriptions")
|
|
||||||
}
|
|
||||||
.modifier(VibrantSelectAction(action: {
|
|
||||||
self.importOPMLAction = 1
|
|
||||||
}))
|
|
||||||
|
|
||||||
NavigationLink(destination: SettingsSubscriptionsExportAccountPickerView(), tag: 1, selection: $exportOPMLAction) {
|
|
||||||
Text("Export Subscriptions")
|
|
||||||
}
|
|
||||||
.modifier(VibrantSelectAction(action: {
|
|
||||||
self.exportOPMLAction = 1
|
|
||||||
}))
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildAboutSection() -> some View {
|
|
||||||
Section(header: Text("ABOUT"), footer: buildFooter()) {
|
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
Button(action: {
|
|
||||||
self.isWebsitePresented.toggle()
|
|
||||||
self.website = "https://github.com/brentsimmons/NetNewsWire"
|
|
||||||
}) {
|
|
||||||
Text("Github Repository")
|
|
||||||
}
|
|
||||||
|
|
||||||
Button(action: {
|
|
||||||
self.isWebsitePresented.toggle()
|
|
||||||
self.website = "https://github.com/brentsimmons/NetNewsWire/issues"
|
|
||||||
}) {
|
|
||||||
Text("Bug Tracker")
|
|
||||||
}
|
|
||||||
|
|
||||||
Button(action: {
|
|
||||||
self.isWebsitePresented.toggle()
|
|
||||||
self.website = "https://github.com/brentsimmons/NetNewsWire/tree/master/Technotes"
|
|
||||||
}) {
|
|
||||||
Text("Technotes")
|
|
||||||
}
|
|
||||||
|
|
||||||
Button(action: {
|
|
||||||
self.isWebsitePresented.toggle()
|
|
||||||
self.website = "https://github.com/brentsimmons/NetNewsWire/blob/master/Technotes/HowToSupportNetNewsWire.markdown"
|
|
||||||
}) {
|
|
||||||
Text("How To Support NetNewsWire")
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}.sheet(isPresented: $isWebsitePresented) {
|
|
||||||
SafariView(url: URL(string: self.website!)!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildFooter() -> some View {
|
|
||||||
return Text(verbatim: "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))")
|
|
||||||
.font(.footnote)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: ViewModel
|
|
||||||
|
|
||||||
class ViewModel: ObservableObject {
|
|
||||||
|
|
||||||
let objectWillChange = ObservableObjectPublisher()
|
|
||||||
|
|
||||||
init() {
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .UserDidAddAccount, object: nil)
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .UserDidDeleteAccount, object: nil)
|
|
||||||
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 {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var sortOldestToNewest: Bool {
|
|
||||||
get {
|
|
||||||
return AppDefaults.timelineSortDirection == .orderedDescending
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
objectWillChange.send()
|
|
||||||
if newValue == true {
|
|
||||||
AppDefaults.timelineSortDirection = .orderedDescending
|
|
||||||
} else {
|
|
||||||
AppDefaults.timelineSortDirection = .orderedAscending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var groupByFeed: Bool {
|
|
||||||
get {
|
|
||||||
return AppDefaults.timelineGroupByFeed
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
objectWillChange.send()
|
|
||||||
AppDefaults.timelineGroupByFeed = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var timelineNumberOfLines: Int {
|
|
||||||
get {
|
|
||||||
return AppDefaults.timelineNumberOfLines
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
objectWillChange.send()
|
|
||||||
AppDefaults.timelineNumberOfLines = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var refreshInterval: RefreshInterval {
|
|
||||||
get {
|
|
||||||
return AppDefaults.refreshInterval
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
objectWillChange.send()
|
|
||||||
AppDefaults.refreshInterval = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func accountsDidChange(_ notification: Notification) {
|
|
||||||
objectWillChange.send()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func displayNameDidChange(_ notification: Notification) {
|
|
||||||
objectWillChange.send()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
struct SettingsView_Previews : PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
SettingsView(viewModel: SettingsView.ViewModel())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
266
iOS/Settings/SettingsViewController.swift
Normal file
266
iOS/Settings/SettingsViewController.swift
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
//
|
||||||
|
// SettingsViewController.swift
|
||||||
|
// NetNewsWire-iOS
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 4/24/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Account
|
||||||
|
|
||||||
|
class SettingsViewController: UITableViewController {
|
||||||
|
|
||||||
|
static let preferredContentSizeForFormSheetDisplay = CGSize(width: 460.0, height: 400.0)
|
||||||
|
|
||||||
|
@IBOutlet weak var refreshIntervalLabel: UILabel!
|
||||||
|
@IBOutlet weak var timelineSortOrderSwitch: UISwitch!
|
||||||
|
@IBOutlet weak var timelineNumberOfLinesLabel: UILabel!
|
||||||
|
|
||||||
|
weak var presentingParentController: UIViewController?
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
// This hack mostly works around a bug in static tables with dynamic type. See: https://spin.atomicobject.com/2018/10/15/dynamic-type-static-uitableview/
|
||||||
|
NotificationCenter.default.removeObserver(tableView!, name: UIContentSizeCategory.didChangeNotification, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange), name: UIContentSizeCategory.didChangeNotification, object: nil)
|
||||||
|
|
||||||
|
tableView.register(UINib(nibName: "SettingsTableViewCell", bundle: nil), forCellReuseIdentifier: "SettingsTableViewCell")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
|
if AppDefaults.timelineSortDirection == .orderedAscending {
|
||||||
|
timelineSortOrderSwitch.isOn = true
|
||||||
|
} else {
|
||||||
|
timelineSortOrderSwitch.isOn = false
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshIntervalLabel.text = AppDefaults.refreshInterval.description()
|
||||||
|
|
||||||
|
let numberOfLinesText = NSLocalizedString(" lines", comment: "Lines")
|
||||||
|
timelineNumberOfLinesLabel.text = "\(AppDefaults.timelineNumberOfLines)" + numberOfLinesText
|
||||||
|
|
||||||
|
let buildLabel = NonIntrinsicLabel(frame: CGRect(x: 20.0, y: 0.0, width: 0.0, height: 0.0))
|
||||||
|
buildLabel.font = UIFont.systemFont(ofSize: 11.0)
|
||||||
|
buildLabel.textColor = UIColor.gray
|
||||||
|
buildLabel.text = "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))"
|
||||||
|
buildLabel.sizeToFit()
|
||||||
|
buildLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
tableView.tableFooterView = buildLabel
|
||||||
|
|
||||||
|
tableView.reloadData()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: UITableView
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
switch section {
|
||||||
|
case 0:
|
||||||
|
return AccountManager.shared.accounts.count + 1
|
||||||
|
case 1:
|
||||||
|
let defaultNumberOfRows = super.tableView(tableView, numberOfRowsInSection: section)
|
||||||
|
if AccountManager.shared.activeAccounts.isEmpty {
|
||||||
|
// Hide the add NetNewsWire feed row if they don't have any active accounts
|
||||||
|
return defaultNumberOfRows - 1
|
||||||
|
}
|
||||||
|
return defaultNumberOfRows
|
||||||
|
default:
|
||||||
|
return super.tableView(tableView, numberOfRowsInSection: section)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let cell: UITableViewCell
|
||||||
|
switch indexPath.section {
|
||||||
|
case 0:
|
||||||
|
|
||||||
|
cell = tableView.dequeueReusableCell(withIdentifier: "SettingsTableViewCell", for: indexPath)
|
||||||
|
cell.textLabel?.adjustsFontForContentSizeCategory = true
|
||||||
|
|
||||||
|
let sortedAccounts = AccountManager.shared.sortedAccounts
|
||||||
|
if indexPath.row == sortedAccounts.count {
|
||||||
|
cell.textLabel?.text = NSLocalizedString("Add Account", comment: "Accounts")
|
||||||
|
} else {
|
||||||
|
cell.textLabel?.text = sortedAccounts[indexPath.row].nameForDisplay
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
switch indexPath.section {
|
||||||
|
case 0:
|
||||||
|
let sortedAccounts = AccountManager.shared.sortedAccounts
|
||||||
|
if indexPath.row == sortedAccounts.count {
|
||||||
|
let controller = UIStoryboard.settings.instantiateController(ofType: AddAccountViewController.self)
|
||||||
|
self.navigationController?.pushViewController(controller, animated: true)
|
||||||
|
} else {
|
||||||
|
let controller = UIStoryboard.settings.instantiateController(ofType: DetailAccountViewController.self)
|
||||||
|
controller.account = sortedAccounts[indexPath.row]
|
||||||
|
self.navigationController?.pushViewController(controller, animated: true)
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
switch indexPath.row {
|
||||||
|
case 0:
|
||||||
|
let timeline = UIStoryboard.settings.instantiateController(ofType: AboutViewController.self)
|
||||||
|
self.navigationController?.pushViewController(timeline, animated: true)
|
||||||
|
case 1:
|
||||||
|
UIApplication.shared.open(URL(string: "https://ranchero.com/netnewswire/")!, options: [:])
|
||||||
|
case 2:
|
||||||
|
UIApplication.shared.open(URL(string: "https://github.com/brentsimmons/NetNewsWire")!, options: [:])
|
||||||
|
case 3:
|
||||||
|
UIApplication.shared.open(URL(string: "https://github.com/brentsimmons/NetNewsWire/issues")!, options: [:])
|
||||||
|
case 4:
|
||||||
|
UIApplication.shared.open(URL(string: "https://github.com/brentsimmons/NetNewsWire/tree/master/Technotes")!, options: [:])
|
||||||
|
case 5:
|
||||||
|
addFeed()
|
||||||
|
default:
|
||||||
|
UIApplication.shared.open(URL(string: "https://ranchero.com/netnewswire/")!, options: [:])
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if indexPath.row == 1 {
|
||||||
|
let timeline = UIStoryboard.settings.instantiateController(ofType: TimelineNumberOfLinesViewController.self)
|
||||||
|
self.navigationController?.pushViewController(timeline, animated: true)
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
switch indexPath.row {
|
||||||
|
case 0:
|
||||||
|
let timeline = UIStoryboard.settings.instantiateController(ofType: RefreshIntervalViewController.self)
|
||||||
|
self.navigationController?.pushViewController(timeline, animated: true)
|
||||||
|
case 1:
|
||||||
|
importOPML()
|
||||||
|
case 2:
|
||||||
|
exportOPML()
|
||||||
|
default:
|
||||||
|
print("export")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
|
||||||
|
return .none
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||||
|
if indexPath.section == 0 {
|
||||||
|
return super.tableView(tableView, heightForRowAt: IndexPath(row: 0, section: 0))
|
||||||
|
} else {
|
||||||
|
return super.tableView(tableView, heightForRowAt: indexPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: IndexPath) -> Int {
|
||||||
|
if indexPath.section == 0 {
|
||||||
|
return super.tableView(tableView, indentationLevelForRowAt: IndexPath(row: 0, section: 0))
|
||||||
|
} else {
|
||||||
|
return super.tableView(tableView, indentationLevelForRowAt: indexPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Actions
|
||||||
|
|
||||||
|
@IBAction func done(_ sender: Any) {
|
||||||
|
dismiss(animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func switchTimelineOrder(_ sender: Any) {
|
||||||
|
if timelineSortOrderSwitch.isOn {
|
||||||
|
AppDefaults.timelineSortDirection = .orderedAscending
|
||||||
|
} else {
|
||||||
|
AppDefaults.timelineSortDirection = .orderedDescending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func contentSizeCategoryDidChange() {
|
||||||
|
tableView.reloadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: OPML Document Picker
|
||||||
|
|
||||||
|
extension SettingsViewController: UIDocumentPickerDelegate {
|
||||||
|
|
||||||
|
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
||||||
|
|
||||||
|
for url in urls {
|
||||||
|
AccountManager.shared.defaultAccount.importOPML(url) { result in}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private extension SettingsViewController {
|
||||||
|
|
||||||
|
func addFeed() {
|
||||||
|
|
||||||
|
let appNewsURLString = "https://nnw.ranchero.com/feed.json"
|
||||||
|
if AccountManager.shared.anyAccountHasFeedWithURL(appNewsURLString) {
|
||||||
|
presentError(title: "Subscribe", message: "You are already subscribed to the NetNewsWire news feed.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dismiss(animated: true)
|
||||||
|
|
||||||
|
let addNavViewController = UIStoryboard.add.instantiateInitialViewController() as! UINavigationController
|
||||||
|
let addViewController = addNavViewController.topViewController as! AddContainerViewController
|
||||||
|
addNavViewController.modalPresentationStyle = .formSheet
|
||||||
|
addNavViewController.preferredContentSize = AddContainerViewController.preferredContentSizeForFormSheetDisplay
|
||||||
|
addViewController.initialFeed = appNewsURLString
|
||||||
|
addViewController.initialFeedName = "NetNewsWire News"
|
||||||
|
|
||||||
|
presentingParentController?.present(addNavViewController, animated: true)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func importOPML() {
|
||||||
|
|
||||||
|
let docPicker = UIDocumentPickerViewController(documentTypes: ["public.xml", "org.opml.opml"], in: .import)
|
||||||
|
docPicker.delegate = self
|
||||||
|
docPicker.modalPresentationStyle = .formSheet
|
||||||
|
self.present(docPicker, animated: true)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportOPML() {
|
||||||
|
|
||||||
|
let filename = "MySubscriptions.opml"
|
||||||
|
let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(filename)
|
||||||
|
let opmlString = OPMLExporter.OPMLString(with: AccountManager.shared.defaultAccount, title: filename)
|
||||||
|
do {
|
||||||
|
try opmlString.write(to: tempFile, atomically: true, encoding: String.Encoding.utf8)
|
||||||
|
} catch {
|
||||||
|
self.presentError(title: "OPML Export Error", message: error.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
let docPicker = UIDocumentPickerViewController(url: tempFile, in: .exportToService)
|
||||||
|
docPicker.modalPresentationStyle = .formSheet
|
||||||
|
self.present(docPicker, animated: true)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
iOS/Settings/TimelineNumberOfLinesViewController.swift
Normal file
41
iOS/Settings/TimelineNumberOfLinesViewController.swift
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// TimelineNumberOfLinesViewController.swift
|
||||||
|
// NetNewsWire-iOS
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 4/29/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class TimelineNumberOfLinesViewController: UITableViewController {
|
||||||
|
|
||||||
|
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
|
||||||
|
cell.textLabel?.adjustsFontForContentSizeCategory = true
|
||||||
|
cell.textLabel?.text = "\(2 + indexPath.row)" + NSLocalizedString(" lines", comment: "Lines")
|
||||||
|
|
||||||
|
let numberOfLines = AppDefaults.timelineNumberOfLines
|
||||||
|
if indexPath.row + 2 == numberOfLines {
|
||||||
|
cell.accessoryType = .checkmark
|
||||||
|
} else {
|
||||||
|
cell.accessoryType = .none
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
AppDefaults.timelineNumberOfLines = indexPath.row + 2
|
||||||
|
self.navigationController?.popViewController(animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -10,6 +10,8 @@ import UIKit
|
|||||||
|
|
||||||
extension UIStoryboard {
|
extension UIStoryboard {
|
||||||
|
|
||||||
|
static let preferredContentSizeForFormSheetDisplay = CGSize(width: 460.0, height: 400.0)
|
||||||
|
|
||||||
static var main: UIStoryboard {
|
static var main: UIStoryboard {
|
||||||
return UIStoryboard(name: "Main", bundle: nil)
|
return UIStoryboard(name: "Main", bundle: nil)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user