Swiftformat

This commit is contained in:
Thomas Ricouard 2023-02-21 07:23:42 +01:00
parent 94d50fafc4
commit b259b6739e
31 changed files with 164 additions and 165 deletions

View file

@ -3,12 +3,12 @@ import AppAccount
import Conversations
import DesignSystem
import Env
import LinkPresentation
import Lists
import Models
import Status
import SwiftUI
import Timeline
import LinkPresentation
import Models
@MainActor
extension View {
@ -46,7 +46,7 @@ extension View {
}
}
}
func withSheetDestinations(sheetDestinations: Binding<SheetDestinations?>) -> some View {
sheet(item: sheetDestinations) { destination in
switch destination {
@ -99,7 +99,7 @@ extension View {
}
}
}
func withEnvironments() -> some View {
environmentObject(CurrentAccount.shared)
.environmentObject(UserPreferences.shared)
@ -114,38 +114,39 @@ extension View {
struct ActivityView: UIViewControllerRepresentable {
let image: UIImage
let status: Status
class LinkDelegate: NSObject, UIActivityItemSource {
let image: UIImage
let status: Status
init(image: UIImage, status: Status) {
self.image = image
self.status = status
}
func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
func activityViewControllerLinkMetadata(_: UIActivityViewController) -> LPLinkMetadata? {
let imageProvider = NSItemProvider(object: image)
let metadata = LPLinkMetadata()
metadata.imageProvider = imageProvider
metadata.title = status.reblog?.content.asRawText ?? status.content.asRawText
return metadata
}
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
func activityViewControllerPlaceholderItem(_: UIActivityViewController) -> Any {
image
}
func activityViewController(_ activityViewController: UIActivityViewController,
itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
func activityViewController(_: UIActivityViewController,
itemForActivityType _: UIActivity.ActivityType?) -> Any?
{
nil
}
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
func makeUIViewController(context _: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
return UIActivityViewController(activityItems: [image, LinkDelegate(image: image, status: status)],
applicationActivities: nil)
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityView>) {}
func updateUIViewController(_: UIActivityViewController, context _: UIViewControllerRepresentableContext<ActivityView>) {}
}

View file

@ -100,7 +100,8 @@ struct IceCubesApp: App {
private func badgeFor(tab: Tab) -> Int {
if tab == .notifications && selectedTab != tab,
let token = appAccountsManager.currentAccount.oauthToken {
let token = appAccountsManager.currentAccount.oauthToken
{
return watcher.unreadNotificationsCount + userPreferences.getNotificationsCount(for: token)
}
return 0
@ -169,7 +170,8 @@ struct IceCubesApp: App {
}
selectedTab = newTab
if selectedTab == .notifications,
let token = appAccountsManager.currentAccount.oauthToken {
let token = appAccountsManager.currentAccount.oauthToken
{
userPreferences.setNotification(count: 0, token: token)
watcher.unreadNotificationsCount = 0
}

View file

@ -15,7 +15,7 @@ private struct SafariRouter: ViewModifier {
@EnvironmentObject private var routerPath: RouterPath
@StateObject private var safariManager = InAppSafariManager()
func body(content: Content) -> some View {
content
.environment(\.openURL, OpenURLAction { url in
@ -58,48 +58,48 @@ private struct SafariRouter: ViewModifier {
private class InAppSafariManager: NSObject, ObservableObject, SFSafariViewControllerDelegate {
var windowScene: UIWindowScene?
let viewController: UIViewController = UIViewController()
let viewController: UIViewController = .init()
var window: UIWindow?
@MainActor
func open(_ url: URL) -> OpenURLAction.Result {
guard let windowScene = windowScene else { return .systemAction }
self.window = setupWindow(windowScene: windowScene)
window = setupWindow(windowScene: windowScene)
let configuration = SFSafariViewController.Configuration()
configuration.entersReaderIfAvailable = UserPreferences.shared.inAppBrowserReaderView
let safari = SFSafariViewController(url: url, configuration: configuration)
safari.preferredBarTintColor = UIColor(Theme.shared.primaryBackgroundColor)
safari.preferredControlTintColor = UIColor(Theme.shared.tintColor)
safari.delegate = self
DispatchQueue.main.async { [weak self] in
self?.viewController.present(safari, animated: true)
}
return .handled
}
func setupWindow(windowScene: UIWindowScene) -> UIWindow {
let window = self.window ?? UIWindow(windowScene: windowScene)
window.rootViewController = viewController
window.makeKeyAndVisible()
switch Theme.shared.selectedScheme {
case .dark:
window.overrideUserInterfaceStyle = .dark
case .light:
window.overrideUserInterfaceStyle = .light
}
self.window = window
return window
}
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
func safariViewControllerDidFinish(_: SFSafariViewController) {
window?.resignKey()
window?.isHidden = false
window = nil
@ -109,31 +109,30 @@ private class InAppSafariManager: NSObject, ObservableObject, SFSafariViewContro
private struct WindowReader: UIViewRepresentable {
var onUpdate: (UIWindow) -> Void
func makeUIView(context: Context) -> InjectView {
func makeUIView(context _: Context) -> InjectView {
InjectView(onUpdate: onUpdate)
}
func updateUIView(_ uiView: InjectView, context: Context) {
}
func updateUIView(_: InjectView, context _: Context) {}
class InjectView: UIView {
var onUpdate: (UIWindow) -> Void
init(onUpdate: @escaping (UIWindow) -> Void) {
self.onUpdate = onUpdate
super.init(frame: .zero)
isHidden = true
isUserInteractionEnabled = false
}
@available(*, unavailable)
required init?(coder: NSCoder) {
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func willMove(toWindow newWindow: UIWindow?) {
super.willMove(toWindow: newWindow)
if let window = newWindow {
onUpdate(window)
} else {

View file

@ -20,12 +20,13 @@ struct SideBarView<Content: View>: View {
private func badgeFor(tab: Tab) -> Int {
if tab == .notifications && selectedTab != tab,
let token = appAccounts.currentAccount.oauthToken {
let token = appAccounts.currentAccount.oauthToken
{
return watcher.unreadNotificationsCount + userPreferences.getNotificationsCount(for: token)
}
return 0
}
private func makeIconForTab(tab: Tab) -> some View {
ZStack(alignment: .topTrailing) {
SideBarIcon(systemIconName: tab.iconName,
@ -37,7 +38,7 @@ struct SideBarView<Content: View>: View {
.contentShape(Rectangle())
.frame(width: .sidebarWidth, height: 50)
}
private func makeBadgeView(count: Int) -> some View {
ZStack {
Circle()
@ -78,8 +79,9 @@ struct SideBarView<Content: View>: View {
ZStack(alignment: .topTrailing) {
AppAccountView(viewModel: .init(appAccount: account, isCompact: true))
if showBadge,
let token = account.oauthToken,
userPreferences.getNotificationsCount(for: token) > 0 {
let token = account.oauthToken,
userPreferences.getNotificationsCount(for: token) > 0
{
makeBadgeView(count: userPreferences.getNotificationsCount(for: token))
}
}

View file

@ -60,7 +60,7 @@ struct DisplaySettingsView: View {
theme.chosenFont = UIFont(name: "OpenDyslexic", size: 1)
case .hyperLegible:
theme.chosenFont = UIFont(name: "Atkinson Hyperlegible", size: 1)
case.SFRounded:
case .SFRounded:
theme.chosenFont = UIFont.systemFont(ofSize: 1).rounded()
case .custom:
isFontSelectorPresented = true

View file

@ -64,7 +64,7 @@ class NotificationService: UNNotificationServiceExtension {
bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "glass.caf"))
let preferences = UserPreferences.shared
if let token = AppAccountsManager.shared.availableAccounts.first(where: { $0.oauthToken?.accessToken == notification.accessToken})?.oauthToken {
if let token = AppAccountsManager.shared.availableAccounts.first(where: { $0.oauthToken?.accessToken == notification.accessToken })?.oauthToken {
var currentCount = preferences.getNotificationsCount(for: token)
currentCount += 1
preferences.setNotification(count: currentCount, token: token)

View file

@ -150,9 +150,10 @@ struct AccountDetailHeaderView: View {
}
}
}
if let note = viewModel.relationship?.note, !note.isEmpty,
!viewModel.isCurrentUser {
!viewModel.isCurrentUser
{
makeNoteView(note)
}
@ -162,7 +163,7 @@ struct AccountDetailHeaderView: View {
.environment(\.openURL, OpenURLAction { url in
routerPath.handle(url: url)
})
fieldsView
}
.padding(.horizontal, .layoutPadding)
@ -204,7 +205,7 @@ struct AccountDetailHeaderView: View {
.padding(.top, 6)
}
}
@ViewBuilder
private func makeNoteView(_ note: String) -> some View {
VStack(alignment: .leading, spacing: 4) {
@ -221,7 +222,7 @@ struct AccountDetailHeaderView: View {
)
}
}
@ViewBuilder
private var fieldsView: some View {
if !viewModel.fields.isEmpty {

View file

@ -485,8 +485,7 @@ public struct AccountDetailView: View {
private extension View {
func applyAccountDetailsRowStyle(theme: Theme) -> some View {
self
.listRowInsets(.init())
listRowInsets(.init())
.listRowSeparator(.hidden)
.listRowBackground(theme.primaryBackgroundColor)
}

View file

@ -6,12 +6,12 @@ public struct EditRelationshipNoteView: View {
@Environment(\.dismiss) private var dismiss
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var client: Client
// need this model to refresh after storing the new note on mastodon
var accountDetailViewModel: AccountDetailViewModel
@StateObject private var viewModel = EditRelationshipNoteViewModel()
public var body: some View {
NavigationStack {
Form {
@ -31,8 +31,8 @@ public struct EditRelationshipNoteView: View {
.alert("account.relation.note.edit.error.save.title",
isPresented: $viewModel.saveError,
actions: {
Button("alert.button.ok", action: {})
}, message: { Text("account.relation.note.edit.error.save.message") })
Button("alert.button.ok", action: {})
}, message: { Text("account.relation.note.edit.error.save.message") })
.task {
viewModel.client = client
viewModel.relatedAccountId = accountDetailViewModel.accountId
@ -40,7 +40,7 @@ public struct EditRelationshipNoteView: View {
}
}
}
@ToolbarContentBuilder
private var toolbarContent: some ToolbarContent {
ToolbarItem(placement: .navigationBarLeading) {
@ -48,7 +48,7 @@ public struct EditRelationshipNoteView: View {
dismiss()
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button {
Task {

View file

@ -6,15 +6,16 @@ class EditRelationshipNoteViewModel: ObservableObject {
public var note: String = ""
public var relatedAccountId: String?
public var client: Client?
@Published var isSaving: Bool = false
@Published var saveError: Bool = false
init() {}
func save() async {
if relatedAccountId != nil,
client != nil {
client != nil
{
isSaving = true
do {
let _ = try await client!.post(endpoint: Accounts.relationshipNote(id: relatedAccountId!, json: RelationshipNoteData(note: note)))

View file

@ -92,7 +92,8 @@ public struct AppAccountsSelectorView: View {
Image(uiImage: image)
}
if let token = viewModel.appAccount.oauthToken,
preferences.getNotificationsCount(for: token) > 0 {
preferences.getNotificationsCount(for: token) > 0
{
Text("\(viewModel.account?.displayName ?? "") (\(preferences.getNotificationsCount(for: token)))")
} else {
Text("\(viewModel.account?.displayName ?? "")")

View file

@ -15,12 +15,10 @@ public extension Font {
private static let onMac = ProcessInfo.processInfo.isiOSAppOnMac
private static func customFont(size: CGFloat, relativeTo textStyle: TextStyle) -> Font {
if let chosenFont = Theme.shared.chosenFont {
if chosenFont.fontName == ".AppleSystemUIFontRounded-Regular" {
return .system(size: size, design: .rounded)
}
else {
} else {
return .custom(chosenFont.fontName, size: size, relativeTo: textStyle)
}
}
@ -72,13 +70,11 @@ public extension Font {
}
}
extension UIFont {
public func rounded() -> UIFont {
guard let descriptor = fontDescriptor.withDesign(.rounded) else {
return self
}
return UIFont(descriptor: descriptor, size: pointSize)
public extension UIFont {
func rounded() -> UIFont {
guard let descriptor = fontDescriptor.withDesign(.rounded) else {
return self
}
return UIFont(descriptor: descriptor, size: pointSize)
}
}

View file

@ -27,7 +27,7 @@ public class Theme: ObservableObject {
case .hyperLegible:
return "Hyper Legible"
case .SFRounded:
return "SF Rounded"
return "SF Rounded"
case .custom:
return "settings.display.font.custom"
}
@ -87,7 +87,7 @@ public class Theme: ObservableObject {
}
}
}
public var chosenFont: UIFont? {
get {
guard let chosenFontData,

View file

@ -1,5 +1,5 @@
import NukeUI
import Nuke
import NukeUI
import Shimmer
import SwiftUI
@ -97,17 +97,17 @@ public struct AvatarView: View {
}
private struct AvatarPlaceholderView: View {
let size: AvatarView.Size
let size: AvatarView.Size
var body: some View {
if size == .badge {
Circle()
.fill(.gray)
.frame(width: size.size.width, height: size.size.height)
} else {
RoundedRectangle(cornerRadius: size.cornerRadius)
.fill(.gray)
.frame(width: size.size.width, height: size.size.height)
}
var body: some View {
if size == .badge {
Circle()
.fill(.gray)
.frame(width: size.size.width, height: size.size.height)
} else {
RoundedRectangle(cornerRadius: size.cornerRadius)
.fill(.gray)
.frame(width: size.size.width, height: size.size.height)
}
}
}

View file

@ -32,7 +32,7 @@ public extension EnvironmentValues {
get { self[IsCompact.self] }
set { self[IsCompact.self] = newValue }
}
var isInCaptureMode: Bool {
get { self[IsInCaptureMode.self] }
set { self[IsInCaptureMode.self] = newValue }

View file

@ -96,13 +96,13 @@ public class UserPreferences: ObservableObject {
public func setNotification(count: Int, token: OauthToken) {
Self.sharedDefault?.set(count, forKey: "push_notifications_count_\(token.createdAt)")
}
public func getNotificationsCount(for token: OauthToken) -> Int {
Self.sharedDefault?.integer(forKey: "push_notifications_count_\(token.createdAt)") ?? 0
}
public func getNotificationsTotalCount(for tokens: [OauthToken]) -> Int {
var count: Int = 0
var count = 0
for token in tokens {
count += getNotificationsCount(for: token)
}
@ -134,6 +134,3 @@ public class UserPreferences: ObservableObject {
recentlyUsedLanguages = Array(copy.prefix(3))
}
}

View file

@ -28,13 +28,11 @@ public struct Poll: Codable, Equatable, Hashable {
public let voted: Bool?
public let ownVotes: [Int]?
public let options: [Option]
// the votersCount can be null according to the docs when multiple is false.
// Didn't find that to be true, but we make sure
public var safeVotersCount: Int {
get {
return votersCount ?? votesCount
}
public var safeVotersCount: Int {
return votersCount ?? votesCount
}
}

View file

@ -56,8 +56,8 @@ public protocol AnyStatus {
}
public struct StatusViewId: Hashable {
let id: String
let editedAt: ServerDate?
let id: String
let editedAt: ServerDate?
}
public extension AnyStatus {

View file

@ -164,7 +164,7 @@ public struct MuteData: Encodable, Sendable {
public struct RelationshipNoteData: Encodable, Sendable {
public let comment: String
public init(note comment: String) {
self.comment = comment
}

View file

@ -26,7 +26,7 @@ public struct StatusPollView: View {
return 0
}
}
private func percentForOption(option: Poll.Option) -> Int {
let percent = ratioForOption(option: option) * 100
return Int(round(percent))

View file

@ -43,10 +43,10 @@ public class StatusRowViewModel: ObservableObject {
var filter: Filtered? {
status.reblog?.filtered?.first ?? status.filtered?.first
}
var isThread: Bool {
status.reblog?.inReplyToId != nil || status.reblog?.inReplyToAccountId != nil ||
status.inReplyToId != nil || status.inReplyToAccountId != nil
status.inReplyToId != nil || status.inReplyToAccountId != nil
}
var highlightRowColor: Color {

View file

@ -8,11 +8,11 @@ struct StatusRowActionsView: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentAccount: CurrentAccount
@ObservedObject var viewModel: StatusRowViewModel
func privateBoost() -> Bool {
return self.viewModel.status.visibility == .priv && self.viewModel.status.account.id == self.currentAccount.account?.id
return viewModel.status.visibility == .priv && viewModel.status.account.id == currentAccount.account?.id
}
@MainActor
enum Actions: CaseIterable {
case respond, boost, favorite, bookmark, share
@ -22,10 +22,10 @@ struct StatusRowActionsView: View {
case .respond:
return "arrowshape.turn.up.left"
case .boost:
if (privateBoost) {
if privateBoost {
return viewModel.isReblogged ? "arrow.left.arrow.right.circle.fill" : "lock.rotation"
}
return viewModel.isReblogged ? "arrow.left.arrow.right.circle.fill" : "arrow.left.arrow.right.circle"
case .favorite:
return viewModel.isFavorited ? "star.fill" : "star"
@ -96,7 +96,7 @@ struct StatusRowActionsView: View {
}
.buttonStyle(.borderless)
.disabled(action == .boost &&
(viewModel.status.visibility == .direct || viewModel.status.visibility == .priv && viewModel.status.account.id != currentAccount.account?.id))
(viewModel.status.visibility == .direct || viewModel.status.visibility == .priv && viewModel.status.account.id != currentAccount.account?.id))
Spacer()
}
}

View file

@ -8,7 +8,7 @@ import SwiftUI
public struct StatusRowCardView: View {
@Environment(\.openURL) private var openURL
@Environment(\.isInCaptureMode) private var isInCaptureMode: Bool
@EnvironmentObject private var theme: Theme
let card: Card

View file

@ -1,19 +1,19 @@
import DesignSystem
import Env
import Foundation
import SwiftUI
import DesignSystem
import Network
import SwiftUI
struct StatusRowContextMenu: View {
@Environment(\.displayScale) var displayScale
@EnvironmentObject private var sceneDelegate: SceneDelegate
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var account: CurrentAccount
@EnvironmentObject private var currentInstance: CurrentInstance
@ObservedObject var viewModel: StatusRowViewModel
var boostLabel: some View {
if self.viewModel.status.visibility == .priv && self.viewModel.status.account.id == self.account.account?.id {
if self.viewModel.isReblogged {
@ -21,13 +21,13 @@ struct StatusRowContextMenu: View {
}
return Label("status.action.boost-to-followers", systemImage: "lock.rotation")
}
if self.viewModel.isReblogged {
return Label("status.action.unboost", systemImage: "arrow.left.arrow.right.circle")
}
return Label("status.action.boost", systemImage: "arrow.left.arrow.right.circle")
}
var body: some View {
if !viewModel.isRemote {
Button { Task {
@ -85,11 +85,11 @@ struct StatusRowContextMenu: View {
message: Text(viewModel.status.reblog?.content.asRawText ?? viewModel.status.content.asRawText)) {
Label("status.action.share", systemImage: "square.and.arrow.up")
}
ShareLink(item: url) {
Label("status.action.share-link", systemImage: "link")
}
Button {
let view = HStack {
StatusRowView(viewModel: viewModel)
@ -200,10 +200,10 @@ struct StatusRowContextMenu: View {
struct ActivityView: UIViewControllerRepresentable {
let image: Image
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
func makeUIViewController(context _: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
return UIActivityViewController(activityItems: [image], applicationActivities: nil)
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityView>) {}
func updateUIViewController(_: UIActivityViewController, context _: UIViewControllerRepresentableContext<ActivityView>) {}
}

View file

@ -1,7 +1,7 @@
import DesignSystem
import Env
import Models
import SwiftUI
import Env
struct StatusRowHeaderView: View {
@Environment(\.isInCaptureMode) private var isInCaptureMode: Bool
@ -57,19 +57,19 @@ struct StatusRowHeaderView: View {
}
if theme.avatarPosition == .top {
dateView
.font(.scaledFootnote)
.foregroundColor(.gray)
.lineLimit(1)
.font(.scaledFootnote)
.foregroundColor(.gray)
.lineLimit(1)
}
}
}
}
private var dateView: Text {
Text(viewModel.status.account.bot ? "🤖 " : "") +
Text(status.createdAt.relativeFormatted) +
Text("") +
Text(Image(systemName: viewModel.status.visibility.iconName))
Text(status.createdAt.relativeFormatted) +
Text("") +
Text(Image(systemName: viewModel.status.visibility.iconName))
}
@ViewBuilder

View file

@ -156,7 +156,8 @@ public struct StatusRowMediaPreviewView: View {
case .image:
if isInCaptureMode,
let image = Nuke.ImagePipeline.shared.cache.cachedImage(for: .init(url: attachment.url,
processors: processors))?.image {
processors: processors))?.image
{
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fill)
@ -243,10 +244,11 @@ public struct StatusRowMediaPreviewView: View {
cornerSensitiveButton
}
if !isInCaptureMode,
let alt = attachment.description,
let alt = attachment.description,
!alt.isEmpty,
!isNotifications,
preferences.showAltTextForMedia {
preferences.showAltTextForMedia
{
Button {
altTextDisplayed = alt
isAltAlertDisplayed = true

View file

@ -4,7 +4,7 @@ import SwiftUI
struct StatusRowTextView: View {
@EnvironmentObject private var theme: Theme
let status: AnyStatus
let viewModel: StatusRowViewModel

View file

@ -5,7 +5,7 @@ import SwiftUI
struct StatusRowTranslateView: View {
@Environment(\.isInCaptureMode) private var isInCaptureMode: Bool
@EnvironmentObject private var preferences: UserPreferences
let status: AnyStatus
@ -27,7 +27,7 @@ struct StatusRowTranslateView: View {
var body: some View {
if !isInCaptureMode,
let userLang = preferences.serverPreferences?.postLanguage,
let userLang = preferences.serverPreferences?.postLanguage,
shouldShowTranslateButton
{
Button {

View file

@ -3,51 +3,51 @@ import Models
actor TimelineDatasource {
private var statuses: [Status] = []
var isEmpty: Bool {
statuses.isEmpty
}
func get() -> [Status] {
statuses
}
func reset() {
statuses = []
}
func indexOf(statusId: String) -> Int? {
statuses.firstIndex(where: { $0.id == statusId })
}
func contains(statusId: String) -> Bool {
statuses.contains(where: { $0.id == statusId })
}
func set(_ statuses: [Status]) {
self.statuses = statuses
}
func append(_ status: Status) {
statuses.append(status)
}
func append(contentOf: [Status]) {
statuses.append(contentsOf: contentOf)
}
func insert(_ status: Status, at: Int) {
statuses.insert(status, at: at)
}
func insert(contentOf: [Status], at: Int) {
statuses.insert(contentsOf: contentOf, at: at)
}
func replace(_ status: Status, at: Int) {
statuses[at] = status
}
func remove(_ statusId: String) {
statuses.removeAll(where: { $0.id == statusId })
}

View file

@ -1,25 +1,25 @@
import SwiftUI
import UIKit
import Models
import Nuke
import SwiftUI
import UIKit
final class TimelinePrefetcher: NSObject, ObservableObject, UICollectionViewDataSourcePrefetching {
private let prefetcher = ImagePrefetcher()
weak var viewModel: TimelineViewModel?
func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
func collectionView(_: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
let imageURLs = getImageURLs(for: indexPaths)
prefetcher.startPrefetching(with: imageURLs)
}
func collectionView(_ collectionView: UICollectionView, cancelPrefetchingForItemsAt indexPaths: [IndexPath]) {
func collectionView(_: UICollectionView, cancelPrefetchingForItemsAt indexPaths: [IndexPath]) {
let imageURLs = getImageURLs(for: indexPaths)
prefetcher.stopPrefetching(with: imageURLs)
}
private func getImageURLs(for indexPaths: [IndexPath]) -> [URL] {
guard let viewModel, case .display(let statuses, _) = viewModel.statusesState else {
guard let viewModel, case let .display(statuses, _) = viewModel.statusesState else {
return []
}
return indexPaths.compactMap {

View file

@ -92,7 +92,7 @@ class TimelineViewModel: ObservableObject {
tag = try await client.get(endpoint: Tags.tag(id: id))
} catch {}
}
func reset() async {
await datasource.reset()
}
@ -214,7 +214,7 @@ extension TimelineViewModel: StatusesFetcher {
updateMentionsToBeHighlighted(&statuses)
ReblogCache.shared.removeDuplicateReblogs(&statuses)
await datasource.set(statuses)
await cacheHome()
@ -231,7 +231,7 @@ extension TimelineViewModel: StatusesFetcher {
var newStatuses: [Status] = await fetchNewPages(minId: latestStatus.id, maxPages: 10)
// Dedup statuses, a status with the same id could have been streamed in.
let ids = await datasource.get().map{ $0.id }
let ids = await datasource.get().map { $0.id }
newStatuses = newStatuses.filter { status in
!ids.contains(where: { $0 == status.id })
}
@ -322,10 +322,10 @@ extension TimelineViewModel: StatusesFetcher {
var latestMinId = minId
do {
while var newStatuses: [Status] =
try await client.get(endpoint: timeline.endpoint(sinceId: nil,
maxId: nil,
minId: latestMinId,
offset: datasource.get().count)),
try await client.get(endpoint: timeline.endpoint(sinceId: nil,
maxId: nil,
minId: latestMinId,
offset: datasource.get().count)),
!newStatuses.isEmpty,
pagesLoaded < maxPages
{