mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-02-04 00:17:30 +01:00
Swiftformat
This commit is contained in:
parent
383eb84e98
commit
4e77669181
@ -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) {}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public struct HTMLString: Decodable, Equatable, Hashable {
|
||||
if let regex = try? NSRegularExpression(pattern: "(<span class=\"ellipsis\">(.*?)</span>)", 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()
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ public class StatusEditorViewModel: ObservableObject {
|
||||
mentionString += "@\(mention.acct)"
|
||||
}
|
||||
if !mentionString.isEmpty {
|
||||
mentionString += " "
|
||||
mentionString += " "
|
||||
}
|
||||
replyToStatus = status
|
||||
visibility = status.visibility
|
||||
|
@ -5,7 +5,7 @@ import SwiftUI
|
||||
|
||||
public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
|
||||
@EnvironmentObject private var theme: Theme
|
||||
|
||||
|
||||
@ObservedObject private var fetcher: Fetcher
|
||||
private let isRemote: Bool
|
||||
private let isEmbdedInList: Bool
|
||||
|
@ -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)
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -18,14 +18,14 @@ class TimelineViewModel: ObservableObject {
|
||||
private var statuses: [Status] = []
|
||||
private var visibileStatusesIds = Set<String>()
|
||||
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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user