Skip to content

Commit a07b680

Browse files
committed
Add Mark Unstarred as Read to iOS sidebar context menus
Extend the Mark Unstarred as Read command to iOS feed list: - Feed long-press context menu - Folder long-press context menu - Smart feed (All Unread, Today, etc.) long-press context menu - Account header long-press context menu - Feed swipe action sheet Also fix smart quote encoding in a nearby localized string. Implements #4548
1 parent c52828e commit a07b680

2 files changed

Lines changed: 96 additions & 3 deletions

File tree

iOS/MainFeed/MainFeedCollectionViewController.swift

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ final class MainFeedCollectionViewController: UICollectionViewController, Undoab
212212
alert.addAction(action)
213213
}
214214

215+
if let action = self.markUnstarredAsReadAlertAction(indexPath: indexPath, completion: completion) {
216+
alert.addAction(action)
217+
}
218+
215219
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
216220
alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel) { _ in
217221
completion(true)
@@ -860,6 +864,10 @@ extension MainFeedCollectionViewController: UIContextMenuInteractionDelegate {
860864
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markAllAction]))
861865
}
862866

867+
if let markUnstarredAction = self.markUnstarredAsReadAction(account: account, contentView: interaction.view) {
868+
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markUnstarredAction]))
869+
}
870+
863871
menuElements.append(UIMenu(title: "", options: .displayInline, children: [self.deactivateAccountAction(account: account)]))
864872

865873
return UIMenu(title: "", children: menuElements)
@@ -910,6 +918,10 @@ extension MainFeedCollectionViewController {
910918
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markAllAction]))
911919
}
912920

921+
if let markUnstarredAction = self.markUnstarredAsReadAction(indexPath: indexPath) {
922+
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markUnstarredAction]))
923+
}
924+
913925
if includeDeleteRename {
914926
menuElements.append(UIMenu(title: "",
915927
options: .displayInline,
@@ -936,6 +948,10 @@ extension MainFeedCollectionViewController {
936948
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markAllAction]))
937949
}
938950

951+
if let markUnstarredAction = self.markUnstarredAsReadAction(indexPath: indexPath) {
952+
menuElements.append(UIMenu(title: "", options: .displayInline, children: [markUnstarredAction]))
953+
}
954+
939955
menuElements.append(UIMenu(title: "",
940956
options: .displayInline,
941957
children: [
@@ -949,12 +965,21 @@ extension MainFeedCollectionViewController {
949965
}
950966

951967
func makePseudoFeedContextMenu(indexPath: IndexPath) -> UIContextMenuConfiguration? {
952-
guard let markAllAction = self.markAllAsReadAction(indexPath: indexPath) else {
968+
var actions = [UIAction]()
969+
970+
if let markAllAction = self.markAllAsReadAction(indexPath: indexPath) {
971+
actions.append(markAllAction)
972+
}
973+
if let markUnstarredAction = self.markUnstarredAsReadAction(indexPath: indexPath) {
974+
actions.append(markUnstarredAction)
975+
}
976+
977+
guard !actions.isEmpty else {
953978
return nil
954979
}
955980

956981
return UIContextMenuConfiguration(identifier: MainFeedRowIdentifier(indexPath: indexPath), previewProvider: nil, actionProvider: { _ in
957-
return UIMenu(title: "", children: [markAllAction])
982+
return UIMenu(title: "", children: actions)
958983
})
959984
}
960985

@@ -1164,6 +1189,74 @@ extension MainFeedCollectionViewController {
11641189
return action
11651190
}
11661191

1192+
func markUnstarredAsReadAction(indexPath: IndexPath) -> UIAction? {
1193+
guard let sidebarItem = dataSource.itemIdentifier(for: indexPath)?.node.representedObject as? SidebarItem,
1194+
let contentView = self.collectionView.cellForItem(at: indexPath)?.contentView,
1195+
let articles = try? sidebarItem.fetchUnreadArticles(),
1196+
Array(articles).unreadUnstarredArticles() != nil else {
1197+
return nil
1198+
}
1199+
1200+
let title = NSLocalizedString("Mark Unstarred as Read", comment: "Command")
1201+
let action = UIAction(title: title, image: Assets.Images.markAllAsRead) { [weak self] _ in
1202+
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView) { [weak self] in
1203+
if let articles = try? sidebarItem.fetchUnreadArticles(),
1204+
let unstarred = Array(articles).unreadUnstarredArticles() {
1205+
self?.coordinator.markAllAsRead(unstarred)
1206+
}
1207+
}
1208+
}
1209+
return action
1210+
}
1211+
1212+
func markUnstarredAsReadAction(account: Account, contentView: UIView?) -> UIAction? {
1213+
guard account.unreadCount > 0, let contentView else {
1214+
return nil
1215+
}
1216+
guard let articles = try? account.fetchArticles(.unread()),
1217+
Array(articles).unreadUnstarredArticles() != nil else {
1218+
return nil
1219+
}
1220+
1221+
let title = NSLocalizedString("Mark Unstarred as Read", comment: "Command")
1222+
let action = UIAction(title: title, image: Assets.Images.markAllAsRead) { [weak self] _ in
1223+
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView) { [weak self] in
1224+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
1225+
if let articles = try? account.fetchArticles(.unread()),
1226+
let unstarred = Array(articles).unreadUnstarredArticles() {
1227+
self?.coordinator.markAllAsRead(unstarred)
1228+
}
1229+
}
1230+
}
1231+
}
1232+
return action
1233+
}
1234+
1235+
func markUnstarredAsReadAlertAction(indexPath: IndexPath, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
1236+
guard let feed = dataSource.itemIdentifier(for: indexPath)?.node.representedObject as? Feed,
1237+
let articles = try? feed.fetchArticles(),
1238+
Array(articles).unreadUnstarredArticles() != nil,
1239+
let contentView = self.collectionView.cellForItem(at: indexPath)?.contentView else {
1240+
return nil
1241+
}
1242+
1243+
let title = NSLocalizedString("Mark Unstarred as Read", comment: "Command")
1244+
let cancel = {
1245+
completion(true)
1246+
}
1247+
1248+
let action = UIAlertAction(title: title, style: .default) { [weak self] _ in
1249+
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView, cancelCompletion: cancel) { [weak self] in
1250+
if let articles = try? feed.fetchArticles(),
1251+
let unstarred = Array(articles).unreadUnstarredArticles() {
1252+
self?.coordinator.markAllAsRead(unstarred)
1253+
}
1254+
completion(true)
1255+
}
1256+
}
1257+
return action
1258+
}
1259+
11671260
func rename(indexPath: IndexPath) {
11681261
guard let sidebarItem = dataSource.itemIdentifier(for: indexPath)?.node.representedObject as? SidebarItem else {
11691262
return

iOS/MainTimeline/MainTimelineModernViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1236,7 +1236,7 @@ extension MainTimelineModernViewController {
12361236
return nil
12371237
}
12381238

1239-
let localizedMenuText = NSLocalizedString("Mark All as Read in "%@"", comment: "Mark All as Read in Feed")
1239+
let localizedMenuText = NSLocalizedString("Mark All as Read in “%@”", comment: "Mark All as Read in Feed")
12401240
let title = NSString.localizedStringWithFormat(localizedMenuText as NSString, feed.nameForDisplay) as String
12411241
let cancel = {
12421242
completion(true)

0 commit comments

Comments
 (0)