Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions IceCubesApp/Resources/Localization/Localizable.xcstrings
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"sourceLanguage": "en",
"strings": {
Expand Down Expand Up @@ -38247,6 +38247,142 @@
}
}
},
"notifications.content-filter.peopleYouDontFollow.subtitle": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Until you manually approve them"
}
},
"en-GB": {
"stringUnit": {
"state": "translated",
"value": "Until you manually approve them"
}
}
}
},
"notifications.content-filter.peopleNotFollowingYou.subtitle": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "And following you for less than 3 days"
}
},
"en-GB": {
"stringUnit": {
"state": "translated",
"value": "And following you for less than 3 days"
}
}
}
},
"notifications.content-filter.newAccounts.subtitle": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Created within the past 30 days"
}
},
"en-GB": {
"stringUnit": {
"state": "translated",
"value": "Created within the past 30 days"
}
}
}
},
"notifications.content-filter.privateMentions.subtitle": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Unless it's in reply to your own mention or if you follow the sender"
}
},
"en-GB": {
"stringUnit": {
"state": "translated",
"value": "Unless it's in reply to your own mention or if you follow the sender"
}
}
}
},
"notifications.content-filter.moderatedAccounts": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Moderated accounts"
}
},
"en-GB": {
"stringUnit": {
"state": "translated",
"value": "Moderated accounts"
}
}
}
},
"notifications.content-filter.moderatedAccounts.subtitle": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Limited by server moderators"
}
},
"en-GB": {
"stringUnit": {
"state": "translated",
"value": "Limited by server moderators"
}
}
}
},
"notifications.content-filter.select": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Select"
}
},
"en-GB": {
"stringUnit": {
"state": "translated",
"value": "Select"
}
}
}
},
"notifications.content-filter.select-all": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Select all"
}
},
"en-GB": {
"stringUnit": {
"state": "translated",
"value": "Select all"
}
}
}
},
"notifications.content-filter.title": {
"extractionState": "manual",
"localizations": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,23 @@ struct AnyStatusesListView: View {
case .loading:
ForEach(Status.placeholders()) { status in
StatusRowExternalView(
viewModel: .init(status: status, client: client, routerPath: routerPath)
viewModel: .init(
status: status,
client: client,
routerPath: routerPath,
filterContext: .account)
)
.redacted(reason: .placeholder)
.allowsHitTesting(false)
}
case let .display(statuses, nextPageState):
ForEach(statuses) { status in
StatusRowExternalView(
viewModel: .init(status: status, client: client, routerPath: routerPath)
viewModel: .init(
status: status,
client: client,
routerPath: routerPath,
filterContext: .account)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,11 @@ private struct StatusesTabView: View {

ForEach(fetcher.pinned) { status in
StatusRowExternalView(
viewModel: .init(status: status, client: client, routerPath: routerPath)
viewModel: .init(
status: status,
client: client,
routerPath: routerPath,
filterContext: .account)
)
}

Expand Down
6 changes: 5 additions & 1 deletion Packages/Explore/Sources/Explore/ExploreView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ public struct ExploreView: View {
private var loadingView: some View {
ForEach(Status.placeholders()) { status in
StatusRowExternalView(
viewModel: .init(status: status, client: client, routerPath: routerPath)
viewModel: .init(
status: status,
client: client,
routerPath: routerPath,
filterContext: .pub)
)
.padding(.vertical, 8)
.redacted(reason: .placeholder)
Expand Down
6 changes: 5 additions & 1 deletion Packages/Explore/Sources/Explore/SearchResultsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,11 @@ struct SearchResultsView: View {
Section("explore.section.posts") {
ForEach(results.statuses) { status in
StatusRowExternalView(
viewModel: .init(status: status, client: client, routerPath: routerPath)
viewModel: .init(
status: status,
client: client,
routerPath: routerPath,
filterContext: .pub)
)
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ struct TrendingPostsSection: View {
.prefix(upTo: trendingStatuses.count > 3 ? 3 : trendingStatuses.count)
) { status in
StatusRowExternalView(
viewModel: .init(status: status, client: client, routerPath: routerPath)
viewModel: .init(
status: status,
client: client,
routerPath: routerPath,
filterContext: .pub)
)
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
Expand Down
10 changes: 10 additions & 0 deletions Packages/Models/Sources/Models/Status.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,16 @@ public final class Status: AnyStatus, Codable, Identifiable, Equatable, Hashable
}
}

public extension AnyStatus {
func filteredEntry(matching context: Filter.Context) -> Filtered? {
filtered?.first(where: { $0.filter.context.contains(context.rawValue) })
}

func isHidden(in context: Filter.Context) -> Bool {
filteredEntry(matching: context)?.filter.filterAction == .hide
}
}

public final class ReblogStatus: AnyStatus, Codable, Identifiable, Equatable, Hashable {
public static func == (lhs: ReblogStatus, rhs: ReblogStatus) -> Bool {
lhs.id == rhs.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public final class NotificationsListDataSource {
// Internal state
private var consolidatedNotifications: [ConsolidatedNotification] = []
private var lastNotificationGroup: Models.NotificationGroup?
private var latestNotificationIdForMarker: String?

public init() {}

Expand All @@ -20,6 +21,7 @@ public final class NotificationsListDataSource {
public func reset() {
consolidatedNotifications = []
lastNotificationGroup = nil
latestNotificationIdForMarker = nil
}

public struct FetchResult {
Expand Down Expand Up @@ -131,7 +133,9 @@ public final class NotificationsListDataSource {
types: queryTypes,
limit: Constants.notificationLimit))
}
consolidatedNotifications = await notifications.consolidated(selectedType: selectedType)
latestNotificationIdForMarker = notifications.first?.id
consolidatedNotifications = filterHiddenNotifications(
await notifications.consolidated(selectedType: selectedType))
}

private func refreshNotificationsV1(
Expand All @@ -151,9 +155,11 @@ public final class NotificationsListDataSource {
newNotifications = newNotifications.filter { notification in
!consolidatedNotifications.contains(where: { $0.id == notification.id })
}
latestNotificationIdForMarker = newNotifications.first?.id ?? latestNotificationIdForMarker

consolidatedNotifications.insert(
contentsOf: await newNotifications.consolidated(selectedType: selectedType),
contentsOf: filterHiddenNotifications(
await newNotifications.consolidated(selectedType: selectedType)),
at: 0
)
}
Expand Down Expand Up @@ -182,7 +188,8 @@ public final class NotificationsListDataSource {
}

consolidatedNotifications.append(
contentsOf: await newNotifications.consolidated(selectedType: selectedType))
contentsOf: filterHiddenNotifications(
await newNotifications.consolidated(selectedType: selectedType)))
}

private func fetchNewPages(
Expand Down Expand Up @@ -232,7 +239,8 @@ public final class NotificationsListDataSource {
maxId: nil,
selectedType: selectedType
)
consolidatedNotifications = results.consolidated
latestNotificationIdForMarker = results.latestNotificationId
consolidatedNotifications = filterHiddenNotifications(results.consolidated)
lastNotificationGroup = results.lastGroup
}

Expand All @@ -247,8 +255,9 @@ public final class NotificationsListDataSource {
maxId: nil,
selectedType: selectedType
)
latestNotificationIdForMarker = results.latestNotificationId ?? latestNotificationIdForMarker

mergeV2Notifications(results.consolidated)
mergeV2Notifications(filterHiddenNotifications(results.consolidated))
}

private func fetchNextPageV2(
Expand All @@ -264,7 +273,7 @@ public final class NotificationsListDataSource {
selectedType: selectedType
)

consolidatedNotifications.append(contentsOf: results.consolidated)
consolidatedNotifications.append(contentsOf: filterHiddenNotifications(results.consolidated))
lastNotificationGroup = results.lastGroup
}

Expand Down Expand Up @@ -306,6 +315,12 @@ public final class NotificationsListDataSource {
event: StreamEventNotification,
selectedType: Models.Notification.NotificationType?
) async {
if let status = event.notification.status,
status.isHidden(in: .notifications)
{
latestNotificationIdForMarker = event.notification.id
return
}
if event.notification.isConsolidable(selectedType: selectedType),
!consolidatedNotifications.isEmpty
{
Expand Down Expand Up @@ -339,6 +354,12 @@ public final class NotificationsListDataSource {
event: StreamEventNotification,
selectedType: Models.Notification.NotificationType?
) async {
if let status = event.notification.status,
status.isHidden(in: .notifications)
{
latestNotificationIdForMarker = event.notification.id
return
}
guard let groupKey = event.notification.groupKey else { return }

let newGroup = ConsolidatedNotification(
Expand Down Expand Up @@ -366,7 +387,9 @@ public final class NotificationsListDataSource {
}

private func markAsRead(client: MastodonClient) {
guard let id = consolidatedNotifications.first?.mostRecentNotificationId else { return }
let id = latestNotificationIdForMarker
?? consolidatedNotifications.first?.mostRecentNotificationId
guard let id else { return }
Task {
do {
let _: Marker = try await client.post(endpoint: Markers.markNotifications(lastReadId: id))
Expand Down Expand Up @@ -414,6 +437,7 @@ public final class NotificationsListDataSource {
let consolidated: [ConsolidatedNotification]
let lastGroup: Models.NotificationGroup?
let hasMore: Bool
let latestNotificationId: String?
}

private func fetchGroupedNotifications(
Expand Down Expand Up @@ -467,7 +491,19 @@ public final class NotificationsListDataSource {
return GroupedNotificationsFetchResult(
consolidated: consolidated,
lastGroup: results.notificationGroups.last,
hasMore: results.notificationGroups.count >= 40
hasMore: results.notificationGroups.count >= 40,
latestNotificationId: results.notificationGroups.first.map {
String($0.mostRecentNotificationId)
}
)
}

private func filterHiddenNotifications(_ notifications: [ConsolidatedNotification])
-> [ConsolidatedNotification]
{
notifications.filter { notification in
guard let status = notification.status else { return true }
return !status.isHidden(in: .notifications)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ public struct NotificationsListView: View {
.environment(client)
.environment(theme)
}
.onChange(of: isNotificationsPolicyPresented) { _, isPresented in
guard !isPresented else { return }
Task {
policy = await dataSource.fetchPolicy(client: client)
await fetchNotifications()
}
}
.navigationBarTitleDisplayMode(.inline)
#if !os(visionOS)
.scrollContentBackground(.hidden)
Expand Down
Loading