mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Merge branch 'main' into localize_strings
# Conflicts: # Shared/Timer/AccountRefreshTimer.swift
This commit is contained in:
@@ -35,16 +35,24 @@ public class AddWebFeedIntentHandler: NSObject, AddWebFeedIntentHandling {
|
||||
completion(.success(with: url))
|
||||
}
|
||||
|
||||
public func provideAccountNameOptions(for intent: AddWebFeedIntent, with completion: @escaping ([String]?, Error?) -> Void) {
|
||||
public func resolveTitle(for intent: AddWebFeedIntent, with completion: @escaping (INStringResolutionResult) -> Void) {
|
||||
guard let title = intent.title else {
|
||||
completion(INStringResolutionResult.notRequired())
|
||||
return
|
||||
}
|
||||
completion(.success(with: title))
|
||||
}
|
||||
|
||||
public func provideAccountNameOptionsCollection(for intent: AddWebFeedIntent, with completion: @escaping (INObjectCollection<NSString>?, Error?) -> Void) {
|
||||
guard let extensionContainers = ExtensionContainersFile.read() else {
|
||||
completion(nil, AddWebFeedIntentHandlerError.communicationFailure)
|
||||
return
|
||||
}
|
||||
|
||||
let accountNames = extensionContainers.accounts.map { $0.name }
|
||||
completion(accountNames, nil)
|
||||
completion(INObjectCollection(items: accountNames as [NSString]), nil)
|
||||
}
|
||||
|
||||
|
||||
public func resolveAccountName(for intent: AddWebFeedIntent, with completion: @escaping (AddWebFeedAccountNameResolutionResult) -> Void) {
|
||||
guard let accountName = intent.accountName else {
|
||||
completion(AddWebFeedAccountNameResolutionResult.notRequired())
|
||||
@@ -78,6 +86,21 @@ public class AddWebFeedIntentHandler: NSObject, AddWebFeedIntentHandling {
|
||||
completion(folderNames, nil)
|
||||
}
|
||||
|
||||
public func provideFolderNameOptionsCollection(for intent: AddWebFeedIntent, with completion: @escaping (INObjectCollection<NSString>?, Error?) -> Void) {
|
||||
guard let extensionContainers = ExtensionContainersFile.read() else {
|
||||
completion(nil, AddWebFeedIntentHandlerError.communicationFailure)
|
||||
return
|
||||
}
|
||||
|
||||
guard let accountName = intent.accountName, let account = extensionContainers.findAccount(forName: accountName) else {
|
||||
completion(INObjectCollection(items: [NSString]()), nil)
|
||||
return
|
||||
}
|
||||
|
||||
let folderNames = account.folders.map { $0.name }
|
||||
completion(INObjectCollection(items: folderNames as [NSString]), nil)
|
||||
}
|
||||
|
||||
public func resolveFolderName(for intent: AddWebFeedIntent, with completion: @escaping (AddWebFeedFolderNameResolutionResult) -> Void) {
|
||||
guard let accountName = intent.accountName, let folderName = intent.folderName else {
|
||||
completion(AddWebFeedFolderNameResolutionResult.notRequired())
|
||||
@@ -135,7 +158,7 @@ public class AddWebFeedIntentHandler: NSObject, AddWebFeedIntentHandling {
|
||||
return
|
||||
}
|
||||
|
||||
let request = ExtensionFeedAddRequest(name: nil, feedURL: url, destinationContainerID: containerID)
|
||||
let request = ExtensionFeedAddRequest(name: intent.title, feedURL: url, destinationContainerID: containerID)
|
||||
ExtensionFeedAddRequestFile.save(request)
|
||||
completion(AddWebFeedIntentResponse(code: .success, userActivity: nil))
|
||||
}
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
<key>INEnums</key>
|
||||
<array/>
|
||||
<key>INIntentDefinitionModelVersion</key>
|
||||
<string>1.1</string>
|
||||
<string>1.2</string>
|
||||
<key>INIntentDefinitionNamespace</key>
|
||||
<string>U6u7RF</string>
|
||||
<key>INIntentDefinitionSystemVersion</key>
|
||||
<string>19D76</string>
|
||||
<string>22A400</string>
|
||||
<key>INIntentDefinitionToolsBuildVersion</key>
|
||||
<string>11B53</string>
|
||||
<string>14B47b</string>
|
||||
<key>INIntentDefinitionToolsVersion</key>
|
||||
<string>11.2.1</string>
|
||||
<string>14.1</string>
|
||||
<key>INIntents</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -32,21 +32,10 @@
|
||||
<key>INIntentKeyParameter</key>
|
||||
<string>url</string>
|
||||
<key>INIntentLastParameterTag</key>
|
||||
<integer>4</integer>
|
||||
<integer>5</integer>
|
||||
<key>INIntentManagedParameterCombinations</key>
|
||||
<dict>
|
||||
<key>url,accountName</key>
|
||||
<dict>
|
||||
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
|
||||
<true/>
|
||||
<key>INIntentParameterCombinationTitle</key>
|
||||
<string>Add ${url} to ${accountName}</string>
|
||||
<key>INIntentParameterCombinationTitleID</key>
|
||||
<string>kaKsEY</string>
|
||||
<key>INIntentParameterCombinationUpdatesLinked</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>url,accountName,folderName</key>
|
||||
<key>url,accountName,folderName,title</key>
|
||||
<dict>
|
||||
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
|
||||
<true/>
|
||||
@@ -57,12 +46,25 @@
|
||||
<key>INIntentParameterCombinationUpdatesLinked</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>url,accountName,title</key>
|
||||
<dict>
|
||||
<key>INIntentParameterCombinationSupportsBackgroundExecution</key>
|
||||
<true/>
|
||||
<key>INIntentParameterCombinationTitle</key>
|
||||
<string>Add ${url} to ${accountName}</string>
|
||||
<key>INIntentParameterCombinationTitleID</key>
|
||||
<string>kaKsEY</string>
|
||||
<key>INIntentParameterCombinationUpdatesLinked</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>INIntentName</key>
|
||||
<string>AddWebFeed</string>
|
||||
<key>INIntentParameters</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentParameterConfigurable</key>
|
||||
<true/>
|
||||
<key>INIntentParameterDisplayName</key>
|
||||
<string>URL</string>
|
||||
<key>INIntentParameterDisplayNameID</key>
|
||||
@@ -105,6 +107,52 @@
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterConfigurable</key>
|
||||
<true/>
|
||||
<key>INIntentParameterDisplayName</key>
|
||||
<string>Title</string>
|
||||
<key>INIntentParameterDisplayNameID</key>
|
||||
<string>Ac5RHN</string>
|
||||
<key>INIntentParameterDisplayPriority</key>
|
||||
<integer>2</integer>
|
||||
<key>INIntentParameterMetadata</key>
|
||||
<dict>
|
||||
<key>INIntentParameterMetadataCapitalization</key>
|
||||
<string>Words</string>
|
||||
<key>INIntentParameterMetadataDefaultValueID</key>
|
||||
<string>SVcvQb</string>
|
||||
</dict>
|
||||
<key>INIntentParameterName</key>
|
||||
<string>title</string>
|
||||
<key>INIntentParameterPromptDialogs</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>Configuration</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
<key>INIntentParameterPromptDialogFormatString</key>
|
||||
<string>What is the ${title}of the feed?</string>
|
||||
<key>INIntentParameterPromptDialogFormatStringID</key>
|
||||
<string>IGNcSh</string>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>Primary</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>INIntentParameterSupportsResolution</key>
|
||||
<true/>
|
||||
<key>INIntentParameterTag</key>
|
||||
<integer>5</integer>
|
||||
<key>INIntentParameterType</key>
|
||||
<string>String</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterConfigurable</key>
|
||||
<true/>
|
||||
<key>INIntentParameterCustomDisambiguation</key>
|
||||
<true/>
|
||||
<key>INIntentParameterDisplayName</key>
|
||||
@@ -112,7 +160,7 @@
|
||||
<key>INIntentParameterDisplayNameID</key>
|
||||
<string>CSrgUY</string>
|
||||
<key>INIntentParameterDisplayPriority</key>
|
||||
<integer>2</integer>
|
||||
<integer>3</integer>
|
||||
<key>INIntentParameterMetadata</key>
|
||||
<dict>
|
||||
<key>INIntentParameterMetadataCapitalization</key>
|
||||
@@ -138,14 +186,6 @@
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>DisambiguationIntroduction</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogFormatString</key>
|
||||
<string>Which one?</string>
|
||||
<key>INIntentParameterPromptDialogFormatStringID</key>
|
||||
<string>fWs3li</string>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>DisambiguationSelection</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
@@ -190,6 +230,8 @@
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterConfigurable</key>
|
||||
<true/>
|
||||
<key>INIntentParameterCustomDisambiguation</key>
|
||||
<true/>
|
||||
<key>INIntentParameterDisplayName</key>
|
||||
@@ -197,7 +239,7 @@
|
||||
<key>INIntentParameterDisplayNameID</key>
|
||||
<string>zXhMPF</string>
|
||||
<key>INIntentParameterDisplayPriority</key>
|
||||
<integer>3</integer>
|
||||
<integer>4</integer>
|
||||
<key>INIntentParameterMetadata</key>
|
||||
<dict>
|
||||
<key>INIntentParameterMetadataCapitalization</key>
|
||||
@@ -223,14 +265,6 @@
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>DisambiguationIntroduction</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogFormatString</key>
|
||||
<string>Which one?</string>
|
||||
<key>INIntentParameterPromptDialogFormatStringID</key>
|
||||
<string>gEzXaM</string>
|
||||
<key>INIntentParameterPromptDialogType</key>
|
||||
<string>DisambiguationSelection</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>INIntentParameterPromptDialogCustom</key>
|
||||
<true/>
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>OrganizationIdentifier</key>
|
||||
<string>$(ORGANIZATION_IDENTIFIER)</string>
|
||||
<key>AppGroup</key>
|
||||
<string>group.$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS</string>
|
||||
<key>AppIdentifierPrefix</key>
|
||||
@@ -44,5 +42,7 @@
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).IntentHandler</string>
|
||||
</dict>
|
||||
<key>OrganizationIdentifier</key>
|
||||
<string>$(ORGANIZATION_IDENTIFIER)</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -693,6 +693,9 @@ extension MasterFeedViewController: UIContextMenuInteractionDelegate {
|
||||
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markAllAction]))
|
||||
}
|
||||
|
||||
if let catchUpAction = self.catchUpActionMenu(account: account, contentView: interaction.view) {
|
||||
menuElements.append(catchUpAction)
|
||||
}
|
||||
menuElements.append(UIMenu(title: "", options: .displayInline, children: [self.deactivateAccountAction(account: account)]))
|
||||
|
||||
return UIMenu(title: "", children: menuElements)
|
||||
@@ -921,6 +924,11 @@ private extension MasterFeedViewController {
|
||||
|
||||
if let markAllAction = self.markAllAsReadAction(indexPath: indexPath) {
|
||||
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markAllAction]))
|
||||
|
||||
}
|
||||
|
||||
if let catchUpAction = self.catchUpActionMenu(indexPath: indexPath) {
|
||||
menuElements.append(catchUpAction)
|
||||
}
|
||||
|
||||
if includeDeleteRename {
|
||||
@@ -948,6 +956,10 @@ private extension MasterFeedViewController {
|
||||
if let markAllAction = self.markAllAsReadAction(indexPath: indexPath) {
|
||||
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markAllAction]))
|
||||
}
|
||||
|
||||
if let catchUpAction = self.catchUpActionMenu(indexPath: indexPath) {
|
||||
menuElements.append(catchUpAction)
|
||||
}
|
||||
|
||||
menuElements.append(UIMenu(title: "",
|
||||
options: .displayInline,
|
||||
@@ -961,13 +973,22 @@ private extension MasterFeedViewController {
|
||||
})
|
||||
}
|
||||
|
||||
func makePseudoFeedContextMenu(indexPath: IndexPath) -> UIContextMenuConfiguration? {
|
||||
guard let markAllAction = self.markAllAsReadAction(indexPath: indexPath) else {
|
||||
return nil
|
||||
}
|
||||
func makePseudoFeedContextMenu(indexPath: IndexPath) -> UIContextMenuConfiguration {
|
||||
return UIContextMenuConfiguration(identifier: MasterFeedRowIdentifier(indexPath: indexPath), previewProvider: nil, actionProvider: { [weak self] suggestedActions in
|
||||
|
||||
return UIContextMenuConfiguration(identifier: MasterFeedRowIdentifier(indexPath: indexPath), previewProvider: nil, actionProvider: { suggestedActions in
|
||||
return UIMenu(title: "", children: [markAllAction])
|
||||
guard let self = self else { return nil }
|
||||
|
||||
var menuElements = [UIMenuElement]()
|
||||
|
||||
if let markAllAction = self.markAllAsReadAction(indexPath: indexPath) {
|
||||
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markAllAction]))
|
||||
}
|
||||
|
||||
if let catchUpAction = self.catchUpActionMenu(indexPath: indexPath) {
|
||||
menuElements.append(catchUpAction)
|
||||
}
|
||||
|
||||
return UIMenu(title: "", children: menuElements)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1151,6 +1172,97 @@ private extension MasterFeedViewController {
|
||||
return action
|
||||
}
|
||||
|
||||
func catchUpActionMenu(indexPath: IndexPath) -> UIMenu? {
|
||||
guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? Feed,
|
||||
let contentView = self.tableView.cellForRow(at: indexPath)?.contentView,
|
||||
feed.unreadCount > 0 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Doesn't make sense to mark articles newer than a day with catch up with first option being older than a day
|
||||
if let maybeSmartFeed = feed as? SmartFeed {
|
||||
if maybeSmartFeed.delegate is TodayFeedDelegate {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
let title = NSLocalizedString("Mark as Read Older Than", comment: "Command")
|
||||
let oneDayAction = UIAction(title: "1 Day") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 1 Day as Read", sourceType: contentView) { [weak self] in
|
||||
let cutoff = Calendar.current.date(byAdding: .day, value: -1, to: Date())
|
||||
if let articles = try? feed.fetchUnreadArticlesBetween(before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
let twoDayAction = UIAction(title: "2 Days") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 2 Days as Read", sourceType: contentView) { [weak self] in
|
||||
let cutoff = Calendar.current.date(byAdding: .day, value: -2, to: Date())
|
||||
if let articles = try? feed.fetchUnreadArticlesBetween(before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
let threeDayAction = UIAction(title: "3 Days") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 3 Days as Read", sourceType: contentView) { [weak self] in
|
||||
let cutoff = Calendar.current.date(byAdding: .day, value: -3, to: Date())
|
||||
if let articles = try? feed.fetchUnreadArticlesBetween(before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
let oneWeekAction = UIAction(title: "1 Week") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 1 Week as Read", sourceType: contentView) { [weak self] in
|
||||
let cutoff = Calendar.current.date(byAdding: .weekOfYear, value: -1, to: Date())
|
||||
if let articles = try? feed.fetchUnreadArticlesBetween(before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
let twoWeekAction = UIAction(title: "2 Weeks") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 2 Weeks as Read", sourceType: contentView) { [weak self] in
|
||||
let cutoff = Calendar.current.date(byAdding: .weekOfYear, value: -2, to: Date())
|
||||
if let articles = try? feed.fetchUnreadArticlesBetween(before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
let oneMonthAction = UIAction(title: "1 Month") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 1 Month as Read", sourceType: contentView) { [weak self] in
|
||||
let cutoff = Calendar.current.date(byAdding: .month, value: -1, to: Date())
|
||||
if let articles = try? feed.fetchUnreadArticlesBetween(before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
let oneYearAction = UIAction(title: "1 Year") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 1 Year as Read", sourceType: contentView) { [weak self] in
|
||||
let cutoff = Calendar.current.date(byAdding: .year, value: -1, to: Date())
|
||||
if let articles = try? feed.fetchUnreadArticlesBetween(before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
var markActions = [UIAction]()
|
||||
markActions.append(oneDayAction)
|
||||
markActions.append(twoDayAction)
|
||||
markActions.append(threeDayAction)
|
||||
markActions.append(oneWeekAction)
|
||||
markActions.append(twoWeekAction)
|
||||
markActions.append(oneMonthAction)
|
||||
markActions.append(oneYearAction)
|
||||
let majorMenu = UIMenu(title: title, image: getMarkOlderImageDirection(), children: markActions)
|
||||
|
||||
return majorMenu
|
||||
}
|
||||
|
||||
func getMarkOlderImageDirection() -> UIImage {
|
||||
if AppDefaults.shared.timelineSortDirection == .orderedDescending {
|
||||
return AppAssets.markBelowAsReadImage
|
||||
} else {
|
||||
return AppAssets.markAboveAsReadImage
|
||||
}
|
||||
}
|
||||
func markAllAsReadAction(account: Account, contentView: UIView?) -> UIAction? {
|
||||
guard account.unreadCount > 0, let contentView = contentView else {
|
||||
return nil
|
||||
@@ -1171,6 +1283,102 @@ private extension MasterFeedViewController {
|
||||
return action
|
||||
}
|
||||
|
||||
func catchUpActionMenu(account: Account, contentView: UIView?) -> UIMenu? {
|
||||
guard account.unreadCount > 0, let contentView = contentView else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let title = NSLocalizedString("Mark as Read Older Than", comment: "Command")
|
||||
let oneDayAction = UIAction(title: "1 Day") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 1 Day as Read", sourceType: contentView) { [weak self] in
|
||||
// If you don't have this delay the screen flashes when it executes this code
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
let cutoff = Calendar.current.date(byAdding: .day, value: -1, to: Date())
|
||||
if let articles = try? account.fetchUnreadArticlesBetween(limit: nil, before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let twoDayAction = UIAction(title: "2 Days") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 2 Days as Read", sourceType: contentView) { [weak self] in
|
||||
// If you don't have this delay the screen flashes when it executes this code
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
let cutoff = Calendar.current.date(byAdding: .day, value: -2, to: Date())
|
||||
if let articles = try? account.fetchUnreadArticlesBetween(limit: nil, before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let threeDayAction = UIAction(title: "3 Days") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 3 Days as Read", sourceType: contentView) { [weak self] in
|
||||
// If you don't have this delay the screen flashes when it executes this code
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
let cutoff = Calendar.current.date(byAdding: .day, value: -3, to: Date())
|
||||
if let articles = try? account.fetchUnreadArticlesBetween(limit: nil, before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let oneWeekAction = UIAction(title: "1 Week") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 1 Week as Read", sourceType: contentView) { [weak self] in
|
||||
// If you don't have this delay the screen flashes when it executes this code
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
let cutoff = Calendar.current.date(byAdding: .weekOfYear, value: -1, to: Date())
|
||||
if let articles = try? account.fetchUnreadArticlesBetween(limit: nil, before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let twoWeekAction = UIAction(title: "2 Weeks") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 2 Weeks as Read", sourceType: contentView) { [weak self] in
|
||||
// If you don't have this delay the screen flashes when it executes this code
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
let cutoff = Calendar.current.date(byAdding: .weekOfYear, value: -2, to: Date())
|
||||
if let articles = try? account.fetchUnreadArticlesBetween(limit: nil, before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let oneMonthAction = UIAction(title: "1 Month") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 1 Month as Read", sourceType: contentView) { [weak self] in
|
||||
// If you don't have this delay the screen flashes when it executes this code
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
let cutoff = Calendar.current.date(byAdding: .month, value: -1, to: Date())
|
||||
if let articles = try? account.fetchUnreadArticlesBetween(limit: nil, before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let oneYearAction = UIAction(title: "1 Year") { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: "Mark Older Than 1 Year as Read", sourceType: contentView) { [weak self] in
|
||||
// If you don't have this delay the screen flashes when it executes this code
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
let cutoff = Calendar.current.date(byAdding: .year, value: -1, to: Date())
|
||||
if let articles = try? account.fetchUnreadArticlesBetween(limit: nil, before: cutoff, after: nil) {
|
||||
self?.coordinator.markAllAsRead(Array(articles))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var markActions = [UIAction]()
|
||||
markActions.append(oneDayAction)
|
||||
markActions.append(twoDayAction)
|
||||
markActions.append(threeDayAction)
|
||||
markActions.append(oneWeekAction)
|
||||
markActions.append(twoWeekAction)
|
||||
markActions.append(oneMonthAction)
|
||||
markActions.append(oneYearAction)
|
||||
let majorMenu = UIMenu(title: title, image: getMarkOlderImageDirection(), children: markActions)
|
||||
|
||||
return majorMenu
|
||||
}
|
||||
|
||||
|
||||
func rename(indexPath: IndexPath) {
|
||||
guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? Feed else { return }
|
||||
|
||||
@@ -6,14 +6,33 @@
|
||||
<string>group.$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS</string>
|
||||
<key>AppIdentifierPrefix</key>
|
||||
<string>$(AppIdentifierPrefix)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>com.ranchero.NetNewsWire.FeedRefresh</string>
|
||||
</array>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>nnwtheme</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>NetNewsWire Theme</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Owner</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>com.ranchero.netnewswire.theme</string>
|
||||
</array>
|
||||
<key>LSTypeIsPackage</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -54,6 +73,8 @@
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>DeveloperEntitlements</key>
|
||||
<string>$(DEVELOPER_ENTITLEMENTS)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>mailto</string>
|
||||
@@ -61,6 +82,8 @@
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<false/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
@@ -195,29 +218,6 @@
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>nnwtheme</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>NetNewsWire Theme</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Owner</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>com.ranchero.netnewswire.theme</string>
|
||||
</array>
|
||||
<key>LSTypeIsPackage</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</array>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<false/>
|
||||
<key>UserAgent</key>
|
||||
<string>NetNewsWire (RSS Reader; https://netnewswire.com/)</string>
|
||||
</dict>
|
||||
|
||||
@@ -352,6 +352,12 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let isSidebarHidden = windowState[UserInfoKey.isSidebarHidden] as? Bool, isSidebarHidden {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||
self.rootSplitViewController.preferredDisplayMode = .secondaryOnly
|
||||
}
|
||||
}
|
||||
|
||||
rebuildBackingStores(initialLoad: true)
|
||||
|
||||
@@ -2124,7 +2130,8 @@ private extension SceneCoordinator {
|
||||
return [
|
||||
UserInfoKey.readFeedsFilterState: isReadFeedsFiltered,
|
||||
UserInfoKey.containerExpandedWindowState: containerExpandedWindowState,
|
||||
UserInfoKey.readArticlesFilterState: readArticlesFilterState
|
||||
UserInfoKey.readArticlesFilterState: readArticlesFilterState,
|
||||
UserInfoKey.isSidebarHidden: rootSplitViewController.displayMode == .secondaryOnly
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user