mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00
Do not allow setting FeedController’s records from outside the class.
Because we want to be certain that incoming records are always correctly filtered. Fixes #1354 [BUG] Mastodon iOS App Ignores "Hide completely" Filter action Setting
This commit is contained in:
parent
d5e8300066
commit
eb5433ec2b
@ -112,18 +112,21 @@ final class HomeTimelineViewController: UIViewController, MediaPreviewableViewCo
|
||||
let showFollowingAction = UIAction(title: L10n.Scene.HomeTimeline.TimelineMenu.following, image: .init(systemName: "house")) { [weak self] _ in
|
||||
guard let self, let viewModel = self.viewModel else { return }
|
||||
|
||||
viewModel.timelineContext = .home
|
||||
viewModel.dataController.records = []
|
||||
|
||||
viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.ContextSwitch.self)
|
||||
timelineSelectorButton.setAttributedTitle(
|
||||
.init(string: L10n.Scene.HomeTimeline.TimelineMenu.following, attributes: [
|
||||
.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold))
|
||||
]),
|
||||
for: .normal)
|
||||
|
||||
timelineSelectorButton.sizeToFit()
|
||||
timelineSelectorButton.menu = generateTimelineSelectorMenu()
|
||||
Task { [weak self] in
|
||||
guard let self else { return }
|
||||
viewModel.timelineContext = .home
|
||||
await viewModel.dataController.setRecordsAfterFiltering([])
|
||||
|
||||
viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.ContextSwitch.self)
|
||||
self.timelineSelectorButton.setAttributedTitle(
|
||||
.init(string: L10n.Scene.HomeTimeline.TimelineMenu.following, attributes: [
|
||||
.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold))
|
||||
]),
|
||||
for: .normal)
|
||||
|
||||
self.timelineSelectorButton.sizeToFit()
|
||||
self.timelineSelectorButton.menu = self.generateTimelineSelectorMenu()
|
||||
}
|
||||
}
|
||||
|
||||
let showLocalTimelineAction = UIAction(title: L10n.Scene.HomeTimeline.TimelineMenu.localCommunity, image: .init(systemName: "building.2")) { [weak self] action in
|
||||
|
@ -87,7 +87,7 @@ extension HomeTimelineViewModel.LoadLatestState {
|
||||
return
|
||||
}
|
||||
|
||||
viewModel.dataController.records = []
|
||||
await viewModel.dataController.setRecordsAfterFiltering([])
|
||||
var snapshot = NSDiffableDataSourceSnapshot<StatusSection, StatusItem>()
|
||||
snapshot.appendSections([.main])
|
||||
snapshot.appendItems([.topLoader], toSection: .main)
|
||||
@ -153,7 +153,7 @@ extension HomeTimelineViewModel.LoadLatestState {
|
||||
|
||||
if statuses.isEmpty {
|
||||
// stop refresher if no new statuses
|
||||
viewModel.dataController.records = []
|
||||
await viewModel.dataController.setRecordsAfterFiltering([])
|
||||
viewModel.didLoadLatest.send()
|
||||
} else {
|
||||
var toAdd = [MastodonFeed]()
|
||||
@ -169,7 +169,8 @@ extension HomeTimelineViewModel.LoadLatestState {
|
||||
toAdd.last?.hasMore = latestFeedRecords.isNotEmpty
|
||||
}
|
||||
|
||||
viewModel.dataController.records = (toAdd + latestFeedRecords).removingDuplicates()
|
||||
let newRecords = (toAdd + latestFeedRecords).removingDuplicates()
|
||||
await viewModel.dataController.setRecordsAfterFiltering(newRecords)
|
||||
}
|
||||
|
||||
viewModel.timelineIsEmpty.value = (latestStatusIDs.isEmpty && statuses.isEmpty) ? {
|
||||
|
@ -94,9 +94,12 @@ final class HomeTimelineViewModel: NSObject {
|
||||
self.authenticationBox = authenticationBox
|
||||
self.dataController = FeedDataController(authenticationBox: authenticationBox, kind: .home(timeline: timelineContext))
|
||||
super.init()
|
||||
self.dataController.records = (try? PersistenceManager.shared.cachedTimeline(.homeTimeline(authenticationBox)).map {
|
||||
let initialRecords = (try? PersistenceManager.shared.cachedTimeline(.homeTimeline(authenticationBox)).map {
|
||||
MastodonFeed.fromStatus($0, kind: .home)
|
||||
}) ?? []
|
||||
Task {
|
||||
await self.dataController.setRecordsAfterFiltering(initialRecords)
|
||||
}
|
||||
|
||||
authenticationBox.inMemoryCache.$followingUserIds.sink { [weak self] _ in
|
||||
self?.homeTimelineNeedRefresh.send()
|
||||
@ -231,10 +234,13 @@ extension HomeTimelineViewModel {
|
||||
}
|
||||
|
||||
let combinedRecords = Array(head + feedItems + tail)
|
||||
dataController.records = combinedRecords
|
||||
|
||||
record.isLoadingMore = false
|
||||
record.hasMore = false
|
||||
Task {
|
||||
await dataController.setRecordsAfterFiltering(combinedRecords)
|
||||
|
||||
record.isLoadingMore = false
|
||||
record.hasMore = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -54,18 +54,22 @@ final class NotificationTimelineViewModel {
|
||||
self.scope = scope
|
||||
self.dataController = FeedDataController(authenticationBox: authenticationBox, kind: scope.feedKind)
|
||||
self.notificationPolicy = notificationPolicy
|
||||
|
||||
switch scope {
|
||||
case .everything:
|
||||
self.dataController.records = (try? FileManager.default.cachedNotificationsAll(for: authenticationBox))?.map({ notification in
|
||||
MastodonFeed.fromNotification(notification, relationship: nil, kind: .notificationAll)
|
||||
}) ?? []
|
||||
case .mentions:
|
||||
self.dataController.records = (try? FileManager.default.cachedNotificationsMentions(for: authenticationBox))?.map({ notification in
|
||||
MastodonFeed.fromNotification(notification, relationship: nil, kind: .notificationMentions)
|
||||
}) ?? []
|
||||
case .fromAccount(_):
|
||||
self.dataController.records = []
|
||||
|
||||
Task {
|
||||
switch scope {
|
||||
case .everything:
|
||||
let initialRecords = (try? FileManager.default.cachedNotificationsAll(for: authenticationBox))?.map({ notification in
|
||||
MastodonFeed.fromNotification(notification, relationship: nil, kind: .notificationAll)
|
||||
}) ?? []
|
||||
await self.dataController.setRecordsAfterFiltering(initialRecords)
|
||||
case .mentions:
|
||||
let initialRecords = (try? FileManager.default.cachedNotificationsMentions(for: authenticationBox))?.map({ notification in
|
||||
MastodonFeed.fromNotification(notification, relationship: nil, kind: .notificationMentions)
|
||||
}) ?? []
|
||||
await self.dataController.setRecordsAfterFiltering(initialRecords)
|
||||
case .fromAccount(_):
|
||||
await self.dataController.setRecordsAfterFiltering([])
|
||||
}
|
||||
}
|
||||
|
||||
self.dataController.$records
|
||||
|
@ -9,7 +9,7 @@ final public class FeedDataController {
|
||||
private let logger = Logger(subsystem: "FeedDataController", category: "Data")
|
||||
private static let entryNotFoundMessage = "Failed to find suitable record. Depending on the context this might result in errors (data not being updated) or can be discarded (e.g. when there are mixed data sources where an entry might or might not exist)."
|
||||
|
||||
@Published public var records: [MastodonFeed] = []
|
||||
@Published public private(set) var records: [MastodonFeed] = []
|
||||
|
||||
private let authenticationBox: MastodonAuthenticationBox
|
||||
private let kind: MastodonFeed.Kind
|
||||
@ -25,21 +25,27 @@ final public class FeedDataController {
|
||||
if let filterBox {
|
||||
Task { [weak self] in
|
||||
guard let self else { return }
|
||||
self.records = await self.filter(self.records, forFeed: kind, with: filterBox)
|
||||
await self.setRecordsAfterFiltering(self.records)
|
||||
}
|
||||
}
|
||||
}
|
||||
.store(in: &subscriptions)
|
||||
}
|
||||
|
||||
public func setRecordsAfterFiltering(_ newRecords: [MastodonFeed]) async {
|
||||
guard let filterBox = StatusFilterService.shared.activeFilterBox else { self.records = newRecords; return }
|
||||
self.records = await self.filter(self.records, forFeed: kind, with: filterBox)
|
||||
}
|
||||
|
||||
public func appendRecordsAfterFiltering(_ additionalRecords: [MastodonFeed]) async {
|
||||
guard let filterBox = StatusFilterService.shared.activeFilterBox else { self.records += additionalRecords; return }
|
||||
self.records += await self.filter(additionalRecords, forFeed: kind, with: filterBox)
|
||||
}
|
||||
|
||||
public func loadInitial(kind: MastodonFeed.Kind) {
|
||||
Task {
|
||||
let unfilteredRecords = try await load(kind: kind, maxID: nil)
|
||||
if let filterBox = StatusFilterService.shared.activeFilterBox {
|
||||
records = await filter(unfilteredRecords, forFeed: kind, with: filterBox)
|
||||
} else {
|
||||
records = unfilteredRecords
|
||||
}
|
||||
await setRecordsAfterFiltering(unfilteredRecords)
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,11 +56,7 @@ final public class FeedDataController {
|
||||
}
|
||||
|
||||
let unfiltered = try await load(kind: kind, maxID: lastId)
|
||||
if let filterBox = StatusFilterService.shared.activeFilterBox {
|
||||
records += await filter(unfiltered, forFeed: kind, with: filterBox)
|
||||
} else {
|
||||
records += unfiltered
|
||||
}
|
||||
await self.appendRecordsAfterFiltering(unfiltered)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user