forked from shadowfacts/Tusker
Don't fail decoding when one status fails to decode
Also remove old workaround for bad dates from #477 Closes #478
This commit is contained in:
parent
e6d9a33dbf
commit
c2232a5e14
|
@ -42,8 +42,7 @@ public struct Client: Sendable {
|
||||||
} else if let date = iso8601.date(from: str) {
|
} else if let date = iso8601.date(from: str) {
|
||||||
return date
|
return date
|
||||||
} else {
|
} else {
|
||||||
// throw DecodingError.typeMismatch(Date.self, .init(codingPath: container.codingPath, debugDescription: "unexpected date format: \(str)"))
|
throw DecodingError.typeMismatch(Date.self, .init(codingPath: container.codingPath, debugDescription: "unexpected date format: \(str)"))
|
||||||
return Date(timeIntervalSinceReferenceDate: 0)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -205,8 +204,8 @@ public struct Client: Sendable {
|
||||||
return Request<Account>(method: .get, path: "/api/v1/accounts/verify_credentials")
|
return Request<Account>(method: .get, path: "/api/v1/accounts/verify_credentials")
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getFavourites(range: RequestRange = .default) -> Request<[Status]> {
|
public static func getFavourites(range: RequestRange = .default) -> Request<[TryDecode<Status>]> {
|
||||||
var request = Request<[Status]>(method: .get, path: "/api/v1/favourites")
|
var request = Request<[TryDecode<Status>]>(method: .get, path: "/api/v1/favourites")
|
||||||
request.range = range
|
request.range = range
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
@ -457,14 +456,13 @@ public struct Client: Sendable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Timelines
|
// MARK: - Timelines
|
||||||
public static func getStatuses(timeline: Timeline, range: RequestRange = .default) -> Request<[Status]> {
|
public static func getStatuses(timeline: Timeline, range: RequestRange = .default) -> Request<[TryDecode<Status>]> {
|
||||||
return timeline.request(range: range)
|
return timeline.request(range: range)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Bookmarks
|
// MARK: - Bookmarks
|
||||||
public static func getBookmarks(range: RequestRange = .default) -> Request<[Status]> {
|
public static func getBookmarks(range: RequestRange = .default) -> Request<[TryDecode<Status>]> {
|
||||||
var request = Request<[Status]>(method: .get, path: "/api/v1/bookmarks")
|
var request = Request<[TryDecode<Status>]>(method: .get, path: "/api/v1/bookmarks")
|
||||||
request.range = range
|
request.range = range
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
@ -492,7 +490,7 @@ public struct Client: Sendable {
|
||||||
return Request<[Hashtag]>(method: .get, path: "/api/v1/trends/tags", queryParameters: parameters)
|
return Request<[Hashtag]>(method: .get, path: "/api/v1/trends/tags", queryParameters: parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getTrendingStatuses(limit: Int? = nil, offset: Int? = nil) -> Request<[Status]> {
|
public static func getTrendingStatuses(limit: Int? = nil, offset: Int? = nil) -> Request<[TryDecode<Status>]> {
|
||||||
var parameters: [Parameter] = []
|
var parameters: [Parameter] = []
|
||||||
if let limit {
|
if let limit {
|
||||||
parameters.append("limit" => limit)
|
parameters.append("limit" => limit)
|
||||||
|
|
|
@ -95,8 +95,8 @@ public final class Account: AccountProtocol, Decodable, Sendable {
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getStatuses(_ accountID: String, range: RequestRange = .default, onlyMedia: Bool? = nil, pinned: Bool? = nil, excludeReplies: Bool? = nil, excludeReblogs: Bool? = nil) -> Request<[Status]> {
|
public static func getStatuses(_ accountID: String, range: RequestRange = .default, onlyMedia: Bool? = nil, pinned: Bool? = nil, excludeReplies: Bool? = nil, excludeReblogs: Bool? = nil) -> Request<[TryDecode<Status>]> {
|
||||||
var request = Request<[Status]>(method: .get, path: "/api/v1/accounts/\(accountID)/statuses", queryParameters: [
|
var request = Request<[TryDecode<Status>]>(method: .get, path: "/api/v1/accounts/\(accountID)/statuses", queryParameters: [
|
||||||
"only_media" => onlyMedia,
|
"only_media" => onlyMedia,
|
||||||
"pinned" => pinned,
|
"pinned" => pinned,
|
||||||
"exclude_replies" => excludeReplies,
|
"exclude_replies" => excludeReplies,
|
||||||
|
|
|
@ -10,7 +10,7 @@ import Foundation
|
||||||
|
|
||||||
public struct SearchResults: Decodable, Sendable {
|
public struct SearchResults: Decodable, Sendable {
|
||||||
public let accounts: [Account]
|
public let accounts: [Account]
|
||||||
public let statuses: [Status]
|
public let statuses: [TryDecode<Status>]
|
||||||
public let hashtags: [Hashtag]
|
public let hashtags: [Hashtag]
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
|
@ -32,8 +32,8 @@ extension Timeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func request(range: RequestRange) -> Request<[Status]> {
|
func request(range: RequestRange) -> Request<[TryDecode<Status>]> {
|
||||||
var request: Request<[Status]> = Request<[Status]>(method: .get, path: endpoint)
|
var request = Request<[TryDecode<Status>]>(method: .get, path: endpoint)
|
||||||
if case .public(true) = self {
|
if case .public(true) = self {
|
||||||
request.queryParameters.append("local" => true)
|
request.queryParameters.append("local" => true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
//
|
||||||
|
// TryDecode.swift
|
||||||
|
// Pachyderm
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 6/8/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public enum TryDecode<T: Decodable>: Decodable {
|
||||||
|
case error(String)
|
||||||
|
case value(T)
|
||||||
|
|
||||||
|
public init(from decoder: any Decoder) throws {
|
||||||
|
do {
|
||||||
|
self = .value(try T(from: decoder))
|
||||||
|
} catch {
|
||||||
|
self = .error(error.localizedDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var value: T? {
|
||||||
|
if case .value(let value) = self {
|
||||||
|
value
|
||||||
|
} else {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TryDecode: Sendable where T: Sendable {
|
||||||
|
}
|
|
@ -232,7 +232,7 @@ class ConversationViewController: UIViewController {
|
||||||
let request = Client.search(query: effectiveURL, types: [.statuses], resolve: true)
|
let request = Client.search(query: effectiveURL, types: [.statuses], resolve: true)
|
||||||
do {
|
do {
|
||||||
let (results, _) = try await mastodonController.run(request)
|
let (results, _) = try await mastodonController.run(request)
|
||||||
guard let status = results.statuses.first(where: { $0.url?.serialized() == effectiveURL }) else {
|
guard let status = results.statuses.compactMap(\.value).first(where: { $0.url?.serialized() == effectiveURL }) else {
|
||||||
throw UnableToResolveError()
|
throw UnableToResolveError()
|
||||||
}
|
}
|
||||||
_ = mastodonController.persistentContainer.addOrUpdateOnViewContext(status: status)
|
_ = mastodonController.persistentContainer.addOrUpdateOnViewContext(status: status)
|
||||||
|
|
|
@ -123,7 +123,7 @@ class TrendingStatusesViewController: UIViewController, CollectionViewController
|
||||||
private func loadTrendingStatuses() async {
|
private func loadTrendingStatuses() async {
|
||||||
let statuses: [Status]
|
let statuses: [Status]
|
||||||
do {
|
do {
|
||||||
statuses = try await mastodonController.run(Client.getTrendingStatuses()).0
|
statuses = try await mastodonController.run(Client.getTrendingStatuses()).0.compactMap(\.value)
|
||||||
} catch {
|
} catch {
|
||||||
let snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
let snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
|
|
|
@ -277,7 +277,7 @@ class TrendsViewController: UIViewController, CollectionViewController {
|
||||||
let linksReq = Client.getTrendingLinks(limit: 10)
|
let linksReq = Client.getTrendingLinks(limit: 10)
|
||||||
async let links = try? mastodonController.run(linksReq).0
|
async let links = try? mastodonController.run(linksReq).0
|
||||||
let statusesReq = Client.getTrendingStatuses(limit: 10)
|
let statusesReq = Client.getTrendingStatuses(limit: 10)
|
||||||
async let statuses = try? mastodonController.run(statusesReq).0
|
async let statuses = try? mastodonController.run(statusesReq).0.compactMap(\.value)
|
||||||
|
|
||||||
if let links = await links {
|
if let links = await links {
|
||||||
if snapshot.sectionIdentifiers.contains(.profileSuggestions) {
|
if snapshot.sectionIdentifiers.contains(.profileSuggestions) {
|
||||||
|
@ -332,7 +332,7 @@ class TrendsViewController: UIViewController, CollectionViewController {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let request = Client.getTrendingStatuses(offset: origSnapshot.itemIdentifiers(inSection: .trendingStatuses).count)
|
let request = Client.getTrendingStatuses(offset: origSnapshot.itemIdentifiers(inSection: .trendingStatuses).count)
|
||||||
let (statuses, _) = try await mastodonController.run(request)
|
let statuses = try await mastodonController.run(request).0.compactMap(\.value)
|
||||||
|
|
||||||
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class LocalPredicateStatusesViewController: UIViewController, CollectionViewCont
|
||||||
let mastodonController: MastodonController
|
let mastodonController: MastodonController
|
||||||
private let predicate: (StatusMO) -> Bool
|
private let predicate: (StatusMO) -> Bool
|
||||||
private let predicateTitle: String
|
private let predicateTitle: String
|
||||||
private let request: (RequestRange) -> Request<[Status]>
|
private let request: (RequestRange) -> Request<[TryDecode<Status>]>
|
||||||
|
|
||||||
var collectionView: UICollectionView! {
|
var collectionView: UICollectionView! {
|
||||||
view as? UICollectionView
|
view as? UICollectionView
|
||||||
|
@ -28,7 +28,7 @@ class LocalPredicateStatusesViewController: UIViewController, CollectionViewCont
|
||||||
private var newer: RequestRange?
|
private var newer: RequestRange?
|
||||||
private var older: RequestRange?
|
private var older: RequestRange?
|
||||||
|
|
||||||
init(predicate: @escaping (StatusMO) -> Bool, predicateTitle: String, request: @escaping (RequestRange) -> Request<[Status]>, mastodonController: MastodonController) {
|
init(predicate: @escaping (StatusMO) -> Bool, predicateTitle: String, request: @escaping (RequestRange) -> Request<[TryDecode<Status>]>, mastodonController: MastodonController) {
|
||||||
self.mastodonController = mastodonController
|
self.mastodonController = mastodonController
|
||||||
self.predicate = predicate
|
self.predicate = predicate
|
||||||
self.predicateTitle = predicateTitle
|
self.predicateTitle = predicateTitle
|
||||||
|
@ -140,7 +140,8 @@ class LocalPredicateStatusesViewController: UIViewController, CollectionViewCont
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let req = request(.count(Self.pageSize))
|
let req = request(.count(Self.pageSize))
|
||||||
let (statuses, pagination) = try await mastodonController.run(req)
|
let (tryStatuses, pagination) = try await mastodonController.run(req)
|
||||||
|
let statuses = tryStatuses.compactMap(\.value)
|
||||||
newer = pagination?.newer
|
newer = pagination?.newer
|
||||||
older = pagination?.older
|
older = pagination?.older
|
||||||
|
|
||||||
|
@ -180,7 +181,8 @@ class LocalPredicateStatusesViewController: UIViewController, CollectionViewCont
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let req = request(older.withCount(Self.pageSize))
|
let req = request(older.withCount(Self.pageSize))
|
||||||
let (statuses, pagination) = try await mastodonController.run(req)
|
let (tryStatuses, pagination) = try await mastodonController.run(req)
|
||||||
|
let statuses = tryStatuses.compactMap(\.value)
|
||||||
self.older = pagination?.older
|
self.older = pagination?.older
|
||||||
|
|
||||||
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
||||||
|
@ -278,7 +280,8 @@ class LocalPredicateStatusesViewController: UIViewController, CollectionViewCont
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
let req = request(newer.withCount(Self.pageSize))
|
let req = request(newer.withCount(Self.pageSize))
|
||||||
let (statuses, pagination) = try await mastodonController.run(req)
|
let (tryStatuses, pagination) = try await mastodonController.run(req)
|
||||||
|
let statuses = tryStatuses.compactMap(\.value)
|
||||||
self.newer = pagination?.newer
|
self.newer = pagination?.newer
|
||||||
|
|
||||||
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
||||||
|
|
|
@ -310,7 +310,7 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
||||||
}
|
}
|
||||||
|
|
||||||
let request = Account.getStatuses(accountID, range: .default, onlyMedia: false, pinned: true, excludeReplies: false)
|
let request = Account.getStatuses(accountID, range: .default, onlyMedia: false, pinned: true, excludeReplies: false)
|
||||||
let (statuses, _) = try await mastodonController.run(request)
|
let statuses = try await mastodonController.run(request).0.compactMap(\.value)
|
||||||
|
|
||||||
await withCheckedContinuation { continuation in
|
await withCheckedContinuation { continuation in
|
||||||
mastodonController.persistentContainer.addAll(statuses: statuses) {
|
mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
|
@ -526,7 +526,7 @@ extension ProfileStatusesViewController {
|
||||||
extension ProfileStatusesViewController: TimelineLikeControllerDataSource {
|
extension ProfileStatusesViewController: TimelineLikeControllerDataSource {
|
||||||
typealias TimelineItem = String // status ID
|
typealias TimelineItem = String // status ID
|
||||||
|
|
||||||
private func request(for range: RequestRange = .default) -> Request<[Status]> {
|
private func request(for range: RequestRange = .default) -> Request<[TryDecode<Status>]> {
|
||||||
switch kind {
|
switch kind {
|
||||||
case .statuses:
|
case .statuses:
|
||||||
return Account.getStatuses(accountID, range: range, onlyMedia: false, pinned: false, excludeReplies: true)
|
return Account.getStatuses(accountID, range: range, onlyMedia: false, pinned: false, excludeReplies: true)
|
||||||
|
@ -539,7 +539,7 @@ extension ProfileStatusesViewController: TimelineLikeControllerDataSource {
|
||||||
|
|
||||||
func loadInitial() async throws -> [String] {
|
func loadInitial() async throws -> [String] {
|
||||||
let request = request()
|
let request = request()
|
||||||
let (statuses, _) = try await mastodonController.run(request)
|
let statuses = try await mastodonController.run(request).0.compactMap(\.value)
|
||||||
|
|
||||||
if !statuses.isEmpty {
|
if !statuses.isEmpty {
|
||||||
newer = .after(id: statuses.first!.id, count: nil)
|
newer = .after(id: statuses.first!.id, count: nil)
|
||||||
|
@ -559,7 +559,7 @@ extension ProfileStatusesViewController: TimelineLikeControllerDataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
let request = request(for: newer)
|
let request = request(for: newer)
|
||||||
let (statuses, _) = try await mastodonController.run(request)
|
let statuses = try await mastodonController.run(request).0.compactMap(\.value)
|
||||||
|
|
||||||
guard !statuses.isEmpty else {
|
guard !statuses.isEmpty else {
|
||||||
throw Error.allCaughtUp
|
throw Error.allCaughtUp
|
||||||
|
@ -580,7 +580,7 @@ extension ProfileStatusesViewController: TimelineLikeControllerDataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
let request = request(for: older)
|
let request = request(for: older)
|
||||||
let (statuses, _) = try await mastodonController.run(request)
|
let statuses = try await mastodonController.run(request).0.compactMap(\.value)
|
||||||
|
|
||||||
guard !statuses.isEmpty else {
|
guard !statuses.isEmpty else {
|
||||||
return []
|
return []
|
||||||
|
|
|
@ -53,7 +53,7 @@ struct ReportAddStatusView: View {
|
||||||
.task { @MainActor in
|
.task { @MainActor in
|
||||||
do {
|
do {
|
||||||
let req = Account.getStatuses(report.accountID, range: .count(40), excludeReplies: false, excludeReblogs: true)
|
let req = Account.getStatuses(report.accountID, range: .count(40), excludeReplies: false, excludeReblogs: true)
|
||||||
let (statuses, _) = try await mastodonController.run(req)
|
let statuses = try await mastodonController.run(req).0.compactMap(\.value)
|
||||||
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
||||||
self.statuses = statuses.compactMap { mastodonController.persistentContainer.status(for: $0.id) }
|
self.statuses = statuses.compactMap { mastodonController.persistentContainer.status(for: $0.id) }
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -266,7 +266,7 @@ class SearchResultsViewController: UIViewController, CollectionViewController {
|
||||||
guard self.currentQuery == query else { return }
|
guard self.currentQuery == query else { return }
|
||||||
self.mastodonController.persistentContainer.performBatchUpdates { (context, addAccounts, addStatuses) in
|
self.mastodonController.persistentContainer.performBatchUpdates { (context, addAccounts, addStatuses) in
|
||||||
addAccounts(results.accounts)
|
addAccounts(results.accounts)
|
||||||
addStatuses(results.statuses)
|
addStatuses(results.statuses.compactMap(\.value))
|
||||||
} completion: {
|
} completion: {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.showSearchResults(results)
|
self.showSearchResults(results)
|
||||||
|
@ -299,7 +299,7 @@ class SearchResultsViewController: UIViewController, CollectionViewController {
|
||||||
}
|
}
|
||||||
if !results.statuses.isEmpty && resultTypes.contains(.statuses) {
|
if !results.statuses.isEmpty && resultTypes.contains(.statuses) {
|
||||||
snapshot.appendSections([.statuses])
|
snapshot.appendSections([.statuses])
|
||||||
snapshot.appendItems(results.statuses.map { .status($0.id, .unknown) }, toSection: .statuses)
|
snapshot.appendItems(results.statuses.compactMap(\.value).map { .status($0.id, .unknown) }, toSection: .statuses)
|
||||||
}
|
}
|
||||||
|
|
||||||
dataSource.apply(snapshot)
|
dataSource.apply(snapshot)
|
||||||
|
|
|
@ -565,7 +565,8 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
do {
|
do {
|
||||||
let (marker, _) = try await mastodonController.run(TimelineMarkers.request(timeline: .home))
|
let (marker, _) = try await mastodonController.run(TimelineMarkers.request(timeline: .home))
|
||||||
async let status = try await mastodonController.run(Client.getStatus(id: marker.lastReadID)).0
|
async let status = try await mastodonController.run(Client.getStatus(id: marker.lastReadID)).0
|
||||||
async let olderStatuses = try await mastodonController.run(Client.getStatuses(timeline: .home, range: .before(id: marker.lastReadID, count: Self.pageSize))).0
|
// TODO: consider replacing undecodable statuses here with items to indicate that to the user
|
||||||
|
async let olderStatuses = try await mastodonController.run(Client.getStatuses(timeline: .home, range: .before(id: marker.lastReadID, count: Self.pageSize))).0.compactMap(\.value)
|
||||||
|
|
||||||
let allStatuses = try await [status] + olderStatuses
|
let allStatuses = try await [status] + olderStatuses
|
||||||
await mastodonController.persistentContainer.addAll(statuses: allStatuses)
|
await mastodonController.persistentContainer.addAll(statuses: allStatuses)
|
||||||
|
@ -1100,7 +1101,7 @@ extension TimelineViewController: TimelineLikeControllerDataSource {
|
||||||
|
|
||||||
func loadInitial() async throws -> [TimelineItem] {
|
func loadInitial() async throws -> [TimelineItem] {
|
||||||
let request = Client.getStatuses(timeline: timeline, range: .count(TimelineViewController.pageSize))
|
let request = Client.getStatuses(timeline: timeline, range: .count(TimelineViewController.pageSize))
|
||||||
let (statuses, _) = try await mastodonController.run(request)
|
let statuses = try await mastodonController.run(request).0.compactMap(\.value)
|
||||||
|
|
||||||
await withCheckedContinuation { continuation in
|
await withCheckedContinuation { continuation in
|
||||||
mastodonController.persistentContainer.addAll(statuses: statuses) {
|
mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
|
@ -1119,7 +1120,7 @@ extension TimelineViewController: TimelineLikeControllerDataSource {
|
||||||
let newer = RequestRange.after(id: id, count: TimelineViewController.pageSize)
|
let newer = RequestRange.after(id: id, count: TimelineViewController.pageSize)
|
||||||
|
|
||||||
let request = Client.getStatuses(timeline: timeline, range: newer)
|
let request = Client.getStatuses(timeline: timeline, range: newer)
|
||||||
let (statuses, _) = try await mastodonController.run(request)
|
let statuses = try await mastodonController.run(request).0.compactMap(\.value)
|
||||||
|
|
||||||
guard !statuses.isEmpty else {
|
guard !statuses.isEmpty else {
|
||||||
throw TimelineViewController.Error.allCaughtUp
|
throw TimelineViewController.Error.allCaughtUp
|
||||||
|
@ -1143,7 +1144,7 @@ extension TimelineViewController: TimelineLikeControllerDataSource {
|
||||||
let older = RequestRange.before(id: id, count: TimelineViewController.pageSize)
|
let older = RequestRange.before(id: id, count: TimelineViewController.pageSize)
|
||||||
|
|
||||||
let request = Client.getStatuses(timeline: timeline, range: older)
|
let request = Client.getStatuses(timeline: timeline, range: older)
|
||||||
let (statuses, _) = try await mastodonController.run(request)
|
let statuses = try await mastodonController.run(request).0.compactMap(\.value)
|
||||||
|
|
||||||
guard !statuses.isEmpty else {
|
guard !statuses.isEmpty else {
|
||||||
return []
|
return []
|
||||||
|
@ -1181,7 +1182,7 @@ extension TimelineViewController: TimelineLikeControllerDataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
let request = Client.getStatuses(timeline: timeline, range: range)
|
let request = Client.getStatuses(timeline: timeline, range: range)
|
||||||
let (statuses, _) = try await mastodonController.run(request)
|
let statuses = try await mastodonController.run(request).0.compactMap(\.value)
|
||||||
|
|
||||||
guard !statuses.isEmpty else {
|
guard !statuses.isEmpty else {
|
||||||
return []
|
return []
|
||||||
|
|
Loading…
Reference in New Issue