diff --git a/CHANGELOG.md b/CHANGELOG.md index 734dd933f..67f0e3b7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed crash related to tracking delete events. [#96](https://github.com/verse-pbc/issues/issues/96) - Added feed picker view (UI only). [#103](https://github.com/verse-pbc/issues/issues/103) - Added feed source customizer drop-down view. [#102](https://github.com/verse-pbc/issues/issues/102) +- Make feed source selector work. ### Internal Changes - Upgraded to Xcode 16. [#1570](https://github.com/planetary-social/nos/issues/1570) diff --git a/Nos/Controller/FeedController.swift b/Nos/Controller/FeedController.swift index deb4092a2..5d4464f67 100644 --- a/Nos/Controller/FeedController.swift +++ b/Nos/Controller/FeedController.swift @@ -39,7 +39,29 @@ enum FeedSource: Hashable, Equatable { @ObservationIgnored @Dependency(\.currentUser) private var currentUser var enabledSources: [FeedSource] = [.following] - var selectedSource: FeedSource = .following + + private(set) var selectedList: AuthorList? + private(set) var selectedRelay: Relay? + var selectedSource: FeedSource = .following { + didSet { + switch selectedSource { + case .relay(let address, _): + if let relay = relays.first(where: { $0.host == address }) { + selectedRelay = relay + selectedList = nil + } + case .list(let title, _): + // TODO: Needs to use replaceableID instead of title + if let list = lists.first(where: { $0.title == title }) { + selectedList = list + selectedRelay = nil + } + default: + selectedList = nil + selectedRelay = nil + } + } + } private(set) var listRowItems: [FeedToggleRow.Item] = [] private(set) var relayRowItems: [FeedToggleRow.Item] = [] diff --git a/Nos/Models/CoreData/Event+Fetching.swift b/Nos/Models/CoreData/Event+Fetching.swift index ea5ea56fd..6bd48be25 100644 --- a/Nos/Models/CoreData/Event+Fetching.swift +++ b/Nos/Models/CoreData/Event+Fetching.swift @@ -321,7 +321,8 @@ extension Event { for user: Author, before: Date? = nil, after: Date? = nil, - seenOn relay: Relay? = nil + seenOn relay: Relay? = nil, + from authors: Set? = nil ) -> NSPredicate { let kind1Predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ NSPredicate(format: "kind = 1"), @@ -366,6 +367,12 @@ extension Event { NSPredicate(format: "(ANY author.followers.source = %@ OR author = %@)", user, user) ) } + + if let authors { + andPredicates.append( + NSPredicate(format: "author IN %@", authors) + ) + } return NSCompoundPredicate(andPredicateWithSubpredicates: andPredicates) } @@ -373,11 +380,12 @@ extension Event { @nonobjc public class func homeFeed( for user: Author, before: Date, - seenOn relay: Relay? = nil + seenOn relay: Relay? = nil, + from authors: Set? = nil ) -> NSFetchRequest { let fetchRequest = NSFetchRequest(entityName: "Event") fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Event.createdAt, ascending: false)] - fetchRequest.predicate = homeFeedPredicate(for: user, before: before, seenOn: relay) + fetchRequest.predicate = homeFeedPredicate(for: user, before: before, seenOn: relay, from: authors) return fetchRequest } diff --git a/Nos/Views/Home/HomeFeedView.swift b/Nos/Views/Home/HomeFeedView.swift index 1e4a759bf..1af04f8e1 100644 --- a/Nos/Views/Home/HomeFeedView.swift +++ b/Nos/Views/Home/HomeFeedView.swift @@ -22,53 +22,44 @@ struct HomeFeedView: View { /// The amount of time (in seconds) the loading indicator will be shown when showTimedLoadingIndicator is set to /// true. - static let staticLoadTime: TimeInterval = 2 + private static let staticLoadTime: TimeInterval = 2 private let stackSpacing: CGFloat = 8 let user: Author /// A tip to display at the top of the feed. - let welcomeTip = WelcomeToFeedTip() + private let welcomeTip = WelcomeToFeedTip() - @State private var showRelayPicker = false - @State private var selectedRelay: Relay? - @State private var pickerSelected = FeedSource.following - - init(user: Author) { - self.user = user - } + @State private var showFeedSelector = false - var homeFeedFetchRequest: NSFetchRequest { + private var homeFeedFetchRequest: NSFetchRequest { Event.homeFeed( for: user, before: refreshController.lastRefreshDate, - seenOn: selectedRelay + seenOn: feedController.selectedRelay, + from: feedController.selectedList?.authors ) } - var newNotesRequest: NSFetchRequest { + private var newNotesRequest: NSFetchRequest { Event.homeFeed( for: user, after: refreshController.lastRefreshDate, - seenOn: selectedRelay + seenOn: feedController.selectedRelay ) } - var homeFeedFilter: Filter { + private var homeFeedFilter: Filter { var filter = Filter(kinds: [.text, .delete, .repost, .longFormContent, .report]) - if selectedRelay == nil { - filter.authorKeys = user.followedKeys.sorted() - } - return filter - } - - var navigationBarTitle: LocalizedStringKey { - if let relayName = selectedRelay?.host { - LocalizedStringKey(stringLiteral: relayName) - } else { - "accountsIFollow" + if feedController.selectedRelay == nil { + if let list = feedController.selectedList { + filter.authorKeys = list.authors.compactMap { $0.hexadecimalPublicKey }.filter { $0.isValid } + } else { + filter.authorKeys = user.followedKeys.sorted() + } } + return filter } var body: some View { @@ -88,7 +79,7 @@ struct HomeFeedView: View { refreshController: $refreshController, databaseFilter: homeFeedFetchRequest, relayFilter: homeFeedFilter, - relay: selectedRelay, + relay: feedController.selectedRelay, managedObjectContext: viewContext, tab: .home, header: { @@ -116,13 +107,12 @@ struct HomeFeedView: View { ) } - if showRelayPicker { + if showFeedSelector { Color.black.opacity(0.5) .ignoresSafeArea() .onTapGesture { - // Close on tap withAnimation(.easeInOut(duration: 0.3)) { - showRelayPicker = false + showFeedSelector = false } } .transition(.opacity) @@ -156,17 +146,17 @@ struct HomeFeedView: View { ToolbarItem(placement: .navigationBarTrailing) { Button { withAnimation { - showRelayPicker.toggle() + showFeedSelector.toggle() } } label: { - Image(systemName: showRelayPicker ? "xmark.circle.fill" : "line.3.horizontal.decrease.circle") + Image(systemName: showFeedSelector ? "xmark.circle.fill" : "line.3.horizontal.decrease.circle") .foregroundStyle(Color.secondaryTxt) .accessibilityLabel("filter") } .frame(minWidth: 40, minHeight: 40) } } - .animation(.easeOut, value: showRelayPicker) + .animation(.easeOut, value: showFeedSelector) .toolbarBackground(.visible, for: .navigationBar) .toolbarBackground(Color.cardBgBottom, for: .navigationBar) .navigationBarTitle("", displayMode: .inline) @@ -186,7 +176,7 @@ struct HomeFeedView: View { } .onChange(of: shouldNavigateToRelaysOnAppear) { if shouldNavigateToRelaysOnAppear { - showRelayPicker = false + showFeedSelector = false DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) { router.push(RelaysDestination(author: user, relays: []))