diff --git a/Packages/Models/Sources/Models/Status.swift b/Packages/Models/Sources/Models/Status.swift index fa9425c6..ee19d0d2 100644 --- a/Packages/Models/Sources/Models/Status.swift +++ b/Packages/Models/Sources/Models/Status.swift @@ -54,11 +54,17 @@ public protocol AnyStatus { var language: String? { get } } -public struct Status: AnyStatus, Decodable, Identifiable, Equatable, Hashable { +protocol StatusUI { + var uiShouldHighlight: Bool? { get set } +} + +public struct Status: AnyStatus, Decodable, Identifiable, Equatable, Hashable, StatusUI { public var viewId: String { id + createdAt + (editedAt ?? "") } + public var uiShouldHighlight: Bool? + public static func == (lhs: Status, rhs: Status) -> Bool { lhs.id == rhs.id } diff --git a/Packages/Status/Sources/Status/Row/StatusRowView.swift b/Packages/Status/Sources/Status/Row/StatusRowView.swift index 0c1ef4a7..39f51aea 100644 --- a/Packages/Status/Sources/Status/Row/StatusRowView.swift +++ b/Packages/Status/Sources/Status/Row/StatusRowView.swift @@ -83,6 +83,7 @@ public struct StatusRowView: View { .contextMenu { contextMenu } + .listRowBackground(viewModel.shouldHighlightRow ? theme.secondaryBackgroundColor : theme.primaryBackgroundColor) .swipeActions(edge: .trailing) { trailinSwipeActions } diff --git a/Packages/Status/Sources/Status/Row/StatusRowViewModel.swift b/Packages/Status/Sources/Status/Row/StatusRowViewModel.swift index 515e8a35..02e6cc02 100644 --- a/Packages/Status/Sources/Status/Row/StatusRowViewModel.swift +++ b/Packages/Status/Sources/Status/Row/StatusRowViewModel.swift @@ -36,6 +36,10 @@ public class StatusRowViewModel: ObservableObject { status.reblog?.filtered?.first ?? status.filtered?.first } + var shouldHighlightRow: Bool { + status.uiShouldHighlight != nil + } + var client: Client? public init(status: Status, diff --git a/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift b/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift index 715dc705..2f6e5ec8 100644 --- a/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift +++ b/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift @@ -22,7 +22,12 @@ class TimelineViewModel: ObservableObject { private var canStreamEvents: Bool = true let pendingStatusesObserver: PendingStatusesObserver = .init() - let cache: TimelineCache = .shared + + private var accountId: String? { + CurrentAccount.shared.account?.id + } + + private let cache: TimelineCache = .shared @Published var scrollToStatus: String? @@ -57,7 +62,7 @@ class TimelineViewModel: ObservableObject { client?.server ?? "Error" } - func fetchTag(id: String) async { + private func fetchTag(id: String) async { guard let client else { return } do { tag = try await client.get(endpoint: Tags.tag(id: id)) @@ -71,7 +76,13 @@ class TimelineViewModel: ObservableObject { !statuses.contains(where: { $0.id == event.status.id }) { pendingStatusesObserver.pendingStatuses.insert(event.status.id, at: 0) - statuses.insert(event.status, at: 0) + var newStatus = event.status + if let accountId { + if newStatus.mentions.first(where: { $0.id == accountId }) != nil { + newStatus.uiShouldHighlight = true + } + } + statuses.insert(newStatus, at: 0) Task { await cacheHome() } @@ -153,7 +164,7 @@ extension TimelineViewModel: StatusesFetcher { minId: nil, offset: statuses.count)) - + updateMentionsToBeHighlighted(&statuses) ReblogCache.shared.removeDuplicateReblogs(&statuses) await cacheHome() @@ -238,6 +249,7 @@ extension TimelineViewModel: StatusesFetcher { { pagesLoaded += 1 + updateMentionsToBeHighlighted(&newStatuses) ReblogCache.shared.removeDuplicateReblogs(&newStatuses) allStatuses.insert(contentsOf: newStatuses, at: 0) @@ -259,16 +271,28 @@ extension TimelineViewModel: StatusesFetcher { minId: nil, offset: statuses.count)) + + updateMentionsToBeHighlighted(&newStatuses) ReblogCache.shared.removeDuplicateReblogs(&newStatuses) - statuses.append(contentsOf: newStatuses) + statusesState = .display(statuses: statuses, nextPageState: .hasNextPage) } catch { statusesState = .error(error: error) } } + private func updateMentionsToBeHighlighted(_ statuses: inout [Status]) { + if !statuses.isEmpty, let accountId { + for i in statuses.indices { + if statuses[i].mentions.first(where: { $0.id == accountId }) != nil { + statuses[i].uiShouldHighlight = true + } + } + } + } + func statusDidAppear(status: Status) { pendingStatusesObserver.removeStatus(status: status) visibileStatusesIds.insert(status.id)