@@ -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
0 commit comments