2024-01-08 11:17:40 +01:00
|
|
|
import Foundation
|
|
|
|
import UIKit
|
|
|
|
import Combine
|
|
|
|
import MastodonSDK
|
|
|
|
|
|
|
|
final public class FeedDataController {
|
|
|
|
|
|
|
|
@Published public var records: [MastodonFeed] = []
|
|
|
|
|
|
|
|
private let context: AppContext
|
|
|
|
private let authContext: AuthContext
|
|
|
|
|
|
|
|
public init(context: AppContext, authContext: AuthContext) {
|
|
|
|
self.context = context
|
|
|
|
self.authContext = authContext
|
|
|
|
}
|
|
|
|
|
|
|
|
public func loadInitial(kind: MastodonFeed.Kind) {
|
|
|
|
Task {
|
|
|
|
records = try await load(kind: kind, sinceId: nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public func loadNext(kind: MastodonFeed.Kind) {
|
|
|
|
Task {
|
|
|
|
guard let lastId = records.last?.status?.id else {
|
|
|
|
return loadInitial(kind: kind)
|
|
|
|
}
|
|
|
|
|
|
|
|
records = try await load(kind: kind, sinceId: lastId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public func update(status: MastodonStatus) {
|
|
|
|
var newRecords = Array(records)
|
|
|
|
for (i, record) in newRecords.enumerated() {
|
|
|
|
if record.status?.id == status.id {
|
|
|
|
newRecords[i] = .fromStatus(status, kind: record.kind)
|
|
|
|
} else if let reblog = status.reblog, reblog.id == record.status?.id {
|
|
|
|
newRecords[i] = .fromStatus(status, kind: record.kind)
|
|
|
|
} else if let reblog = record.status?.reblog, reblog.id == status.id {
|
|
|
|
// Handle reblogged state
|
|
|
|
let isRebloggedByAnyOne: Bool = records[i].status!.reblog != nil
|
|
|
|
|
|
|
|
let newStatus: MastodonStatus
|
|
|
|
if isRebloggedByAnyOne {
|
|
|
|
// if status was previously reblogged by me: remove reblogged status
|
|
|
|
if records[i].status!.entity.reblogged == true && status.entity.reblogged == false {
|
|
|
|
newStatus = .fromEntity(status.entity)
|
|
|
|
} else {
|
|
|
|
newStatus = .fromEntity(records[i].status!.entity)
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
newStatus = .fromEntity(status.entity)
|
|
|
|
}
|
|
|
|
|
|
|
|
newStatus.isSensitiveToggled = status.isSensitiveToggled
|
|
|
|
newStatus.reblog = isRebloggedByAnyOne ? .fromEntity(status.entity) : nil
|
|
|
|
|
|
|
|
newRecords[i] = .fromStatus(newStatus, kind: record.kind)
|
|
|
|
|
|
|
|
} else if let reblog = record.status?.reblog, reblog.id == status.reblog?.id {
|
|
|
|
// Handle re-reblogged state
|
|
|
|
newRecords[i] = .fromStatus(status, kind: record.kind)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
records = newRecords
|
|
|
|
}
|
|
|
|
|
|
|
|
public func delete(status: MastodonStatus) {
|
|
|
|
self.records.removeAll { $0.id == status.id }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private extension FeedDataController {
|
|
|
|
func load(kind: MastodonFeed.Kind, sinceId: MastodonStatus.ID?) async throws -> [MastodonFeed] {
|
|
|
|
switch kind {
|
2024-01-16 15:17:09 +01:00
|
|
|
case .home:
|
|
|
|
await context.authenticationService.authenticationServiceProvider.fetchAccounts(apiService: context.apiService)
|
|
|
|
return try await context.apiService.homeTimeline(sinceID: sinceId, authenticationBox: authContext.mastodonAuthenticationBox)
|
|
|
|
.value.map { .fromStatus(.fromEntity($0), kind: .home) }
|
|
|
|
case .notificationAll:
|
|
|
|
return try await getFeeds(with: .everything)
|
|
|
|
case .notificationMentions:
|
|
|
|
return try await getFeeds(with: .mentions)
|
2024-01-08 11:17:40 +01:00
|
|
|
}
|
|
|
|
}
|
2024-01-16 15:17:09 +01:00
|
|
|
|
|
|
|
private func getFeeds(with scope: APIService.MastodonNotificationScope) async throws -> [MastodonFeed] {
|
|
|
|
|
|
|
|
let notifications = try await context.apiService.notifications(maxID: nil, scope: scope, authenticationBox: authContext.mastodonAuthenticationBox).value
|
|
|
|
|
|
|
|
let accounts = notifications.map { $0.account }
|
|
|
|
let relationships = try await context.apiService.relationship(forAccounts: accounts, authenticationBox: authContext.mastodonAuthenticationBox).value
|
|
|
|
|
|
|
|
let notificationsWithRelationship: [(notification: Mastodon.Entity.Notification, relationship: Mastodon.Entity.Relationship?)] = notifications.compactMap { notification in
|
|
|
|
guard let relationship = relationships.first(where: {$0.id == notification.account.id }) else { return (notification: notification, relationship: nil)}
|
|
|
|
|
|
|
|
return (notification: notification, relationship: relationship)
|
|
|
|
}
|
|
|
|
|
|
|
|
let feeds = notificationsWithRelationship.compactMap({ (notification: Mastodon.Entity.Notification, relationship: Mastodon.Entity.Relationship?) in
|
|
|
|
MastodonFeed.fromNotification(notification, relationship: relationship, kind: .notificationAll)
|
|
|
|
})
|
|
|
|
|
|
|
|
return feeds
|
|
|
|
}
|
|
|
|
|
2024-01-08 11:17:40 +01:00
|
|
|
}
|
2024-01-16 15:17:09 +01:00
|
|
|
|