diff --git a/Packages/Account/Sources/Account/AccountDetailViewModel.swift b/Packages/Account/Sources/Account/AccountDetailViewModel.swift
index 1ea0d714..360689ae 100644
--- a/Packages/Account/Sources/Account/AccountDetailViewModel.swift
+++ b/Packages/Account/Sources/Account/AccountDetailViewModel.swift
@@ -246,8 +246,8 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
}
}
}
-
- func statusDidAppear(status: Models.Status) { }
-
- func statusDidDisappear(status: Status) { }
+
+ func statusDidAppear(status _: Models.Status) {}
+
+ func statusDidDisappear(status _: Status) {}
}
diff --git a/Packages/Models/Sources/Models/Alias/HTMLString.swift b/Packages/Models/Sources/Models/Alias/HTMLString.swift
index d4b46697..37254f96 100644
--- a/Packages/Models/Sources/Models/Alias/HTMLString.swift
+++ b/Packages/Models/Sources/Models/Alias/HTMLString.swift
@@ -36,7 +36,7 @@ public struct HTMLString: Decodable, Equatable, Hashable {
if let regex = try? NSRegularExpression(pattern: "((.*?))", options: .caseInsensitive) {
htmlValue = regex.stringByReplacingMatches(in: htmlValue, options: [], range: NSRange(location: 0, length: htmlValue.count), withTemplate: "$2…")
}
-
+
do {
asMarkdown = try HTMLParser().parse(html: htmlValue)
.toMarkdown()
diff --git a/Packages/Network/Sources/Network/Client.swift b/Packages/Network/Sources/Network/Client.swift
index 39ebcb8a..2a5b7754 100644
--- a/Packages/Network/Sources/Network/Client.swift
+++ b/Packages/Network/Sources/Network/Client.swift
@@ -17,11 +17,11 @@ public class Client: ObservableObject, Equatable, Identifiable, Hashable {
case missingApp
case invalidRedirectURL
}
-
+
public var id: String {
"\(isAuth)\(server)\(oauthToken?.accessToken ?? "")"
}
-
+
public func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
diff --git a/Packages/Status/Sources/Status/Editor/StatusEditorViewModel.swift b/Packages/Status/Sources/Status/Editor/StatusEditorViewModel.swift
index b68bf039..2804ee63 100644
--- a/Packages/Status/Sources/Status/Editor/StatusEditorViewModel.swift
+++ b/Packages/Status/Sources/Status/Editor/StatusEditorViewModel.swift
@@ -201,7 +201,7 @@ public class StatusEditorViewModel: ObservableObject {
mentionString += "@\(mention.acct)"
}
if !mentionString.isEmpty {
- mentionString += " "
+ mentionString += " "
}
replyToStatus = status
visibility = status.visibility
diff --git a/Packages/Status/Sources/Status/List/StatusesListView.swift b/Packages/Status/Sources/Status/List/StatusesListView.swift
index 133e7d9c..c566557e 100644
--- a/Packages/Status/Sources/Status/List/StatusesListView.swift
+++ b/Packages/Status/Sources/Status/List/StatusesListView.swift
@@ -5,7 +5,7 @@ import SwiftUI
public struct StatusesListView: View where Fetcher: StatusesFetcher {
@EnvironmentObject private var theme: Theme
-
+
@ObservedObject private var fetcher: Fetcher
private let isRemote: Bool
private let isEmbdedInList: Bool
diff --git a/Packages/Timeline/Sources/Timeline/PendingStatusesObserver.swift b/Packages/Timeline/Sources/Timeline/PendingStatusesObserver.swift
index 4b3faeff..759ae48d 100644
--- a/Packages/Timeline/Sources/Timeline/PendingStatusesObserver.swift
+++ b/Packages/Timeline/Sources/Timeline/PendingStatusesObserver.swift
@@ -1,29 +1,29 @@
import Foundation
-import SwiftUI
import Models
+import SwiftUI
@MainActor
class PendingStatusesObserver: ObservableObject {
let feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
-
+
@Published var pendingStatusesCount: Int = 0
-
+
var disableUpdate: Bool = false
-
+
var pendingStatuses: [String] = [] {
didSet {
pendingStatusesCount = pendingStatuses.count
}
}
-
+
func removeStatus(status: Status) {
if !disableUpdate, let index = pendingStatuses.firstIndex(of: status.id) {
- pendingStatuses.removeSubrange(index...(pendingStatuses.count - 1))
+ pendingStatuses.removeSubrange(index ... (pendingStatuses.count - 1))
feedbackGenerator.impactOccurred()
}
}
-
- init() { }
+
+ init() {}
}
struct PendingStatusesObserverView: View {
@@ -32,7 +32,7 @@ struct PendingStatusesObserverView: View {
if observer.pendingStatusesCount > 0 {
HStack(spacing: 6) {
Spacer()
- Button { } label: {
+ Button {} label: {
Text("\(observer.pendingStatusesCount)")
}
.buttonStyle(.bordered)
diff --git a/Packages/Timeline/Sources/Timeline/TimelineCache.swift b/Packages/Timeline/Sources/Timeline/TimelineCache.swift
index aafc1c28..5a5f5ff2 100644
--- a/Packages/Timeline/Sources/Timeline/TimelineCache.swift
+++ b/Packages/Timeline/Sources/Timeline/TimelineCache.swift
@@ -1,18 +1,18 @@
-import SwiftUI
import Models
import Network
+import SwiftUI
actor TimelineCache {
static let shared: TimelineCache = .init()
-
+
private var memoryCache: [Client: [Status]] = [:]
-
+
private init() {}
-
+
func set(statuses: [Status], client: Client) {
- memoryCache[client] = statuses.prefix(upTo: min(100, (statuses.count - 1))).map{ $0 }
+ memoryCache[client] = statuses.prefix(upTo: min(100, statuses.count - 1)).map { $0 }
}
-
+
func getStatuses(for client: Client) -> [Status]? {
memoryCache[client]
}
diff --git a/Packages/Timeline/Sources/Timeline/TimelineView.swift b/Packages/Timeline/Sources/Timeline/TimelineView.swift
index 26088b7d..ae3419df 100644
--- a/Packages/Timeline/Sources/Timeline/TimelineView.swift
+++ b/Packages/Timeline/Sources/Timeline/TimelineView.swift
@@ -19,9 +19,9 @@ public struct TimelineView: View {
@EnvironmentObject private var routerPath: RouterPath
@StateObject private var viewModel = TimelineViewModel()
-
+
@State private var wasBackgrounded: Bool = false
-
+
@Binding var timeline: TimelineFilter
@Binding var scrollToTopSignal: Int
@@ -111,7 +111,7 @@ public struct TimelineView: View {
}
case .background:
wasBackgrounded = true
-
+
default:
break
}
@@ -154,9 +154,9 @@ public struct TimelineView: View {
trailing: .layoutPadding))
}
}
-
+
private var scrollToTopView: some View {
- HStack{ EmptyView() }
+ HStack { EmptyView() }
.listRowBackground(theme.primaryBackgroundColor)
.listRowSeparator(.hidden)
.listRowInsets(.init())
diff --git a/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift b/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift
index f4b2bca5..78b3209e 100644
--- a/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift
+++ b/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift
@@ -18,14 +18,14 @@ class TimelineViewModel: ObservableObject {
private var statuses: [Status] = []
private var visibileStatusesIds = Set()
var scrollToTopVisible: Bool = false
-
+
private var canStreamEvents: Bool = true
-
+
let pendingStatusesObserver: PendingStatusesObserver = .init()
let cache: TimelineCache = .shared
@Published var scrollToStatus: String?
-
+
@Published var statusesState: StatusesState = .loading
@Published var timeline: TimelineFilter = .federated {
didSet {
@@ -57,7 +57,6 @@ class TimelineViewModel: ObservableObject {
client?.server ?? "Error"
}
-
func fetchTag(id: String) async {
guard let client else { return }
do {
@@ -65,7 +64,7 @@ class TimelineViewModel: ObservableObject {
} catch {}
}
- func handleEvent(event: any StreamEvent, currentAccount: CurrentAccount) {
+ func handleEvent(event: any StreamEvent, currentAccount _: CurrentAccount) {
if let event = event as? StreamEventUpdate,
canStreamEvents,
pendingStatusesEnabled,
@@ -91,13 +90,14 @@ class TimelineViewModel: ObservableObject {
}
// MARK: - Cache
+
extension TimelineViewModel {
private func cache(statuses: [Status]) async {
if let client {
await cache.set(statuses: statuses, client: client)
}
}
-
+
private func getCachedStatuses() async -> [Status]? {
if let client {
return await cache.getStatuses(for: client)
@@ -107,6 +107,7 @@ extension TimelineViewModel {
}
// MARK: - StatusesFetcher
+
extension TimelineViewModel: StatusesFetcher {
func fetchStatuses() async {
guard let client else { return }
@@ -122,12 +123,12 @@ extension TimelineViewModel: StatusesFetcher {
print("timeline parse error: \(error)")
}
}
-
+
// Hydrate statuses in the Timeline when statuses are empty.
private func fetchFirstPage(client: Client) async throws {
pendingStatusesObserver.pendingStatuses = []
statusesState = .loading
-
+
// If we get statuses from the cache for the home timeline, we displays those.
// Else we fetch top most page from the API.
if let cachedStatuses = await getCachedStatuses(), timeline == .home {
@@ -150,34 +151,34 @@ extension TimelineViewModel: StatusesFetcher {
}
}
}
-
+
// Fetch pages from the top most status of the tomeline.
- private func fetchNewPagesFrom(latestStatus: Status, client: Client) async throws {
+ private func fetchNewPagesFrom(latestStatus: Status, client _: Client) async throws {
canStreamEvents = false
var newStatuses: [Status] = await fetchNewPages(minId: latestStatus.id, maxPages: 10)
-
+
// Dedup statuses, a status with the same id could have been streamed in.
newStatuses = newStatuses.filter { status in
!statuses.contains(where: { $0.id == status.id })
}
-
+
// If no new statuses, resume streaming and exit.
guard !newStatuses.isEmpty else {
canStreamEvents = true
return
}
-
+
// Keep track of the top most status, so we can scroll back to it after view update.
let topStatusId = statuses.first?.id
-
+
// Insert new statuses in internal datasource.
statuses.insert(contentsOf: newStatuses, at: 0)
-
+
// Cache statuses for home timeline.
if timeline == .home {
await cache(statuses: statuses)
}
-
+
// If pending statuses are not enabled, we simply load status on the top regardless of the current position.
if !pendingStatusesEnabled {
pendingStatusesObserver.pendingStatuses = []
@@ -187,9 +188,9 @@ extension TimelineViewModel: StatusesFetcher {
}
} else {
// Append new statuses in the timeline indicator.
- pendingStatusesObserver.pendingStatuses.insert(contentsOf: newStatuses.map{ $0.id }, at: 0)
+ pendingStatusesObserver.pendingStatuses.insert(contentsOf: newStatuses.map { $0.id }, at: 0)
pendingStatusesObserver.feedbackGenerator.impactOccurred()
-
+
// High chance the user is scrolled to the top.
// We need to update the statuses state, and then scroll to the previous top most status.
if let topStatusId, visibileStatusesIds.contains(topStatusId), scrollToTopVisible {
@@ -209,7 +210,7 @@ extension TimelineViewModel: StatusesFetcher {
}
}
}
-
+
private func fetchNewPages(minId: String, maxPages: Int) async -> [Status] {
guard let client else { return [] }
var pagesLoaded = 0
@@ -232,7 +233,7 @@ extension TimelineViewModel: StatusesFetcher {
}
return allStatuses
}
-
+
func fetchNextPage() async {
guard let client else { return }
do {
@@ -248,12 +249,12 @@ extension TimelineViewModel: StatusesFetcher {
statusesState = .error(error: error)
}
}
-
+
func statusDidAppear(status: Status) {
pendingStatusesObserver.removeStatus(status: status)
visibileStatusesIds.insert(status.id)
}
-
+
func statusDidDisappear(status: Status) {
visibileStatusesIds.remove(status.id)
}