From a72f2900385dda2a52b70f40724060d33578b4ef Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Thu, 1 Aug 2024 08:58:54 +0200 Subject: [PATCH] Lint --- IceCubesApp/App/SideBarView.swift | 4 +- .../App/Tabs/Settings/AddAccountsView.swift | 2 +- .../App/Tabs/Settings/SettingsTab.swift | 40 ++++++------ IceCubesAppIntents/ListEntity.swift | 10 +-- .../AccountWidget/AccountWidget.swift | 6 +- .../AccountWidget/AccountWidgetView.swift | 1 - .../Account/AccountDetailContextMenu.swift | 12 ++-- .../Sources/Account/AccountDetailView.swift | 14 ++-- .../Account/AccountDetailViewModel.swift | 2 +- .../AccountsList/AccountsListRow.swift | 2 +- .../AccountsList/AccountsListView.swift | 4 +- .../Account/Edit/EditAccountView.swift | 18 +++--- .../Account/Edit/EditAccountViewModel.swift | 64 +++++++++---------- .../AccountDetailMediaGridView.swift | 31 ++++----- .../Sources/DesignSystem/Theme.swift | 2 +- .../Env/Sources/Env/CurrentInstance.swift | 2 +- .../Env/Sources/Env/Ext/TranslationView.swift | 4 +- Packages/Env/Sources/Env/Router.swift | 2 +- .../Explore/Sources/Explore/ExploreView.swift | 2 +- .../Sources/Explore/ExploreViewModel.swift | 18 +++--- .../Sources/MediaUI/MediaUIShareLink.swift | 2 +- .../MediaUI/MediaUITransferableImage.swift | 2 +- .../Sources/Models/Alias/HTMLString.swift | 4 +- Packages/Models/Sources/Models/Card.swift | 3 +- .../Models/Sources/Models/MediaStatus.swift | 4 +- Packages/Models/Sources/Models/Status.swift | 4 +- .../Sources/Network/Endpoint/Profile.swift | 1 - .../Sources/Network/Endpoint/Search.swift | 2 +- .../Editor/Components/Compressor.swift | 8 +-- .../Editor/Components/MediaEditView.swift | 6 +- .../Editor/Components/MediaView.swift | 2 +- .../StatusKit/Row/StatusRowExternalView.swift | 4 +- .../Sources/StatusKit/Row/StatusRowView.swift | 4 +- .../StatusKit/Row/StatusRowViewModel.swift | 40 ++++++------ .../Row/Subviews/StatusRowCardView.swift | 4 +- .../Row/Subviews/StatusRowHeaderView.swift | 8 +-- .../Subviews/StatusRowMediaPreviewView.swift | 40 ++++++------ .../Timeline/View/TimelineViewModel.swift | 38 +++++------ 38 files changed, 209 insertions(+), 207 deletions(-) diff --git a/IceCubesApp/App/SideBarView.swift b/IceCubesApp/App/SideBarView.swift index d5f5b69b..290ded33 100644 --- a/IceCubesApp/App/SideBarView.swift +++ b/IceCubesApp/App/SideBarView.swift @@ -101,12 +101,12 @@ struct SideBarView: View { } label: { ZStack(alignment: .topTrailing) { if userPreferences.isSidebarExpanded { - AppAccountView(viewModel: .init(appAccount: account, + AppAccountView(viewModel: .init(appAccount: account, isCompact: false, isInSettings: false), isParentPresented: .constant(false)) } else { - AppAccountView(viewModel: .init(appAccount: account, + AppAccountView(viewModel: .init(appAccount: account, isCompact: true, isInSettings: false), isParentPresented: .constant(false)) diff --git a/IceCubesApp/App/Tabs/Settings/AddAccountsView.swift b/IceCubesApp/App/Tabs/Settings/AddAccountsView.swift index 2d0a84ce..325dca87 100644 --- a/IceCubesApp/App/Tabs/Settings/AddAccountsView.swift +++ b/IceCubesApp/App/Tabs/Settings/AddAccountsView.swift @@ -1,4 +1,5 @@ import AppAccount +import AuthenticationServices import Combine import DesignSystem import Env @@ -7,7 +8,6 @@ import Network import NukeUI import SafariServices import SwiftUI -import AuthenticationServices @MainActor struct AddAccountView: View { diff --git a/IceCubesApp/App/Tabs/Settings/SettingsTab.swift b/IceCubesApp/App/Tabs/Settings/SettingsTab.swift index 7f9a822a..9b8410db 100644 --- a/IceCubesApp/App/Tabs/Settings/SettingsTab.swift +++ b/IceCubesApp/App/Tabs/Settings/SettingsTab.swift @@ -31,9 +31,9 @@ struct SettingsTabs: View { @Binding var popToRootTab: Tab let isModal: Bool - + @State private var startingPoint: SettingsStartingPoint? = nil - + var body: some View { NavigationStack(path: $routerPath.path) { Form { @@ -72,24 +72,24 @@ struct SettingsTabs: View { } .navigationDestination(item: $startingPoint) { targetView in switch targetView { - case .display: - DisplaySettingsView() - case .haptic: - HapticSettingsView() - case .remoteTimelines: - RemoteTimelinesSettingView() - case .tagGroups: - TagsGroupSettingView() - case .recentTags: - RecenTagsSettingView() - case .content: - ContentSettingsView() - case .swipeActions: - SwipeActionsSettingsView() - case .tabAndSidebarEntries: - EmptyView() - case .translation: - TranslationSettingsView() + case .display: + DisplaySettingsView() + case .haptic: + HapticSettingsView() + case .remoteTimelines: + RemoteTimelinesSettingView() + case .tagGroups: + TagsGroupSettingView() + case .recentTags: + RecenTagsSettingView() + case .content: + ContentSettingsView() + case .swipeActions: + SwipeActionsSettingsView() + case .tabAndSidebarEntries: + EmptyView() + case .translation: + TranslationSettingsView() } } } diff --git a/IceCubesAppIntents/ListEntity.swift b/IceCubesAppIntents/ListEntity.swift index cb752998..bfe0a3d5 100644 --- a/IceCubesAppIntents/ListEntity.swift +++ b/IceCubesAppIntents/ListEntity.swift @@ -22,24 +22,24 @@ public struct ListEntity: Identifiable, AppEntity { public struct DefaultListEntityQuery: EntityQuery { public init() {} - + @IntentParameterDependency( \.$account ) var account - + public func entities(for _: [ListEntity.ID]) async throws -> [ListEntity] { - await fetchLists().map{ .init(list: $0 )} + await fetchLists().map { .init(list: $0) } } public func suggestedEntities() async throws -> [ListEntity] { - await fetchLists().map{ .init(list: $0 )} + await fetchLists().map { .init(list: $0) } } public func defaultResult() async -> ListEntity? { nil } - + private func fetchLists() async -> [Models.List] { guard let account = account?.account.account else { return [] diff --git a/IceCubesAppWidgetsExtension/AccountWidget/AccountWidget.swift b/IceCubesAppWidgetsExtension/AccountWidget/AccountWidget.swift index 315bb925..3fa869f9 100644 --- a/IceCubesAppWidgetsExtension/AccountWidget/AccountWidget.swift +++ b/IceCubesAppWidgetsExtension/AccountWidget/AccountWidget.swift @@ -10,18 +10,18 @@ struct AccountWidgetProvider: AppIntentTimelineProvider { .init(date: Date(), account: .placeholder(), avatar: nil) } - func snapshot(for configuration: AccountWidgetConfiguration, in context: Context) async -> AccountWidgetEntry { + func snapshot(for configuration: AccountWidgetConfiguration, in _: Context) async -> AccountWidgetEntry { let account = await fetchAccount(configuration: configuration) return .init(date: Date(), account: account, avatar: nil) } - func timeline(for configuration: AccountWidgetConfiguration, in context: Context) async -> Timeline { + func timeline(for configuration: AccountWidgetConfiguration, in _: Context) async -> Timeline { let account = await fetchAccount(configuration: configuration) let images = try? await loadImages(urls: [account.avatar]) return .init(entries: [.init(date: Date(), account: account, avatar: images?.first?.value)], policy: .atEnd) } - + private func fetchAccount(configuration: AccountWidgetConfiguration) async -> Account { let client = Client(server: configuration.account.account.server, oauthToken: configuration.account.account.oauthToken) diff --git a/IceCubesAppWidgetsExtension/AccountWidget/AccountWidgetView.swift b/IceCubesAppWidgetsExtension/AccountWidget/AccountWidgetView.swift index 6ac66577..161b2820 100644 --- a/IceCubesAppWidgetsExtension/AccountWidget/AccountWidgetView.swift +++ b/IceCubesAppWidgetsExtension/AccountWidget/AccountWidgetView.swift @@ -11,7 +11,6 @@ struct AccountWidgetView: View { @Environment(\.widgetFamily) var family @Environment(\.redactionReasons) var redacted - var body: some View { VStack(alignment: .center, spacing: 4) { if let avatar = entry.avatar { diff --git a/Packages/Account/Sources/Account/AccountDetailContextMenu.swift b/Packages/Account/Sources/Account/AccountDetailContextMenu.swift index d4fdd01b..9d193278 100644 --- a/Packages/Account/Sources/Account/AccountDetailContextMenu.swift +++ b/Packages/Account/Sources/Account/AccountDetailContextMenu.swift @@ -138,13 +138,13 @@ public struct AccountDetailContextMenu: View { } #if canImport(_Translation_SwiftUI) - if #available(iOS 17.4, *) { - Button { - showTranslateView = true - } label: { - Label("status.action.translate", systemImage: "captions.bubble") - } + if #available(iOS 17.4, *) { + Button { + showTranslateView = true + } label: { + Label("status.action.translate", systemImage: "captions.bubble") } + } #endif if viewModel.relationship?.following == true { diff --git a/Packages/Account/Sources/Account/AccountDetailView.swift b/Packages/Account/Sources/Account/AccountDetailView.swift index e876e622..cc4f269c 100644 --- a/Packages/Account/Sources/Account/AccountDetailView.swift +++ b/Packages/Account/Sources/Account/AccountDetailView.swift @@ -85,14 +85,14 @@ public struct AccountDetailView: View { Spacer() Image(systemName: "chevron.right") } - .onTapGesture { - if let account = viewModel.account { - routerPath.navigate(to: .accountMediaGridView(account: account, - initialMediaStatuses: viewModel.statusesMedias)) - } + .onTapGesture { + if let account = viewModel.account { + routerPath.navigate(to: .accountMediaGridView(account: account, + initialMediaStatuses: viewModel.statusesMedias)) } + } #if !os(visionOS) - .listRowBackground(theme.primaryBackgroundColor) + .listRowBackground(theme.primaryBackgroundColor) #endif } StatusesListView(fetcher: viewModel, @@ -302,7 +302,7 @@ public struct AccountDetailView: View { } Menu { - AccountDetailContextMenu(showBlockConfirmation: $showBlockConfirmation, + AccountDetailContextMenu(showBlockConfirmation: $showBlockConfirmation, showTranslateView: $showTranslateView, viewModel: viewModel) diff --git a/Packages/Account/Sources/Account/AccountDetailViewModel.swift b/Packages/Account/Sources/Account/AccountDetailViewModel.swift index fae5d3c9..679ae511 100644 --- a/Packages/Account/Sources/Account/AccountDetailViewModel.swift +++ b/Packages/Account/Sources/Account/AccountDetailViewModel.swift @@ -85,7 +85,7 @@ import SwiftUI private(set) var statuses: [Status] = [] var statusesMedias: [MediaStatus] { - statuses.filter{ !$0.mediaAttachments.isEmpty }.flatMap{ $0.asMediaStatus} + statuses.filter { !$0.mediaAttachments.isEmpty }.flatMap { $0.asMediaStatus } } var boosts: [Status] = [] diff --git a/Packages/Account/Sources/Account/AccountsList/AccountsListRow.swift b/Packages/Account/Sources/Account/AccountsList/AccountsListRow.swift index ce124b49..4cc58d73 100644 --- a/Packages/Account/Sources/Account/AccountsList/AccountsListRow.swift +++ b/Packages/Account/Sources/Account/AccountsList/AccountsListRow.swift @@ -113,7 +113,7 @@ public struct AccountsListRow: View { .addTranslateView(isPresented: $showTranslateView, text: viewModel.account.note.asRawText) #endif .contextMenu { - AccountDetailContextMenu(showBlockConfirmation: $showBlockConfirmation, + AccountDetailContextMenu(showBlockConfirmation: $showBlockConfirmation, showTranslateView: $showTranslateView, viewModel: .init(account: viewModel.account)) } preview: { diff --git a/Packages/Account/Sources/Account/AccountsList/AccountsListView.swift b/Packages/Account/Sources/Account/AccountsList/AccountsListView.swift index 2623da4d..c8b794e0 100644 --- a/Packages/Account/Sources/Account/AccountsList/AccountsListView.swift +++ b/Packages/Account/Sources/Account/AccountsList/AccountsListView.swift @@ -128,7 +128,7 @@ public struct AccountsListView: View { PlaceholderView(iconName: "person.icloud", title: "No accounts found", message: "This list of accounts is empty") - .listRowSeparator(.hidden) + .listRowSeparator(.hidden) } else { ForEach(accounts) { account in if let relationship = relationships.first(where: { $0.id == account.id }) { @@ -139,7 +139,7 @@ public struct AccountsListView: View { } } #if !os(visionOS) - .listRowBackground(theme.primaryBackgroundColor) + .listRowBackground(theme.primaryBackgroundColor) #endif switch nextPageState { diff --git a/Packages/Account/Sources/Account/Edit/EditAccountView.swift b/Packages/Account/Sources/Account/Edit/EditAccountView.swift index fea5dc28..8904d019 100644 --- a/Packages/Account/Sources/Account/Edit/EditAccountView.swift +++ b/Packages/Account/Sources/Account/Edit/EditAccountView.swift @@ -99,21 +99,21 @@ public struct EditAccountView: View { viewModel.isPhotoPickerPresented = true } if viewModel.avatar != nil || viewModel.header != nil { - Divider() + Divider() } if viewModel.avatar != nil { - Button("account.edit.avatar.delete", role: .destructive) { - Task { - await viewModel.deleteAvatar() - } + Button("account.edit.avatar.delete", role: .destructive) { + Task { + await viewModel.deleteAvatar() } + } } if viewModel.header != nil { - Button("account.edit.header.delete", role: .destructive) { - Task { - await viewModel.deleteHeader() - } + Button("account.edit.header.delete", role: .destructive) { + Task { + await viewModel.deleteHeader() } + } } } label: { Image(systemName: "photo.badge.plus") diff --git a/Packages/Account/Sources/Account/Edit/EditAccountViewModel.swift b/Packages/Account/Sources/Account/Edit/EditAccountViewModel.swift index ddf2fd97..715c4f0d 100644 --- a/Packages/Account/Sources/Account/Edit/EditAccountViewModel.swift +++ b/Packages/Account/Sources/Account/Edit/EditAccountViewModel.swift @@ -51,19 +51,19 @@ import SwiftUI didSet { if let item = mediaPickers.first { Task { - if isChangingAvatar { - if let data = await getItemImageData(item: item, for: .avatar) { - _ = await uploadAvatar(data: data) - } - isChangingAvatar = false - } else if isChangingHeader { - if let data = await getItemImageData(item: item, for: .header) { - _ = await uploadHeader(data: data) - } - isChangingHeader = false + if isChangingAvatar { + if let data = await getItemImageData(item: item, for: .avatar) { + _ = await uploadAvatar(data: data) } - await fetchAccount() - mediaPickers = [] + isChangingAvatar = false + } else if isChangingHeader { + if let data = await getItemImageData(item: item, for: .header) { + _ = await uploadHeader(data: data) + } + isChangingHeader = false + } + await fetchAccount() + mediaPickers = [] } } } @@ -186,26 +186,26 @@ import SwiftUI } extension EditAccountViewModel { - private enum ItemType { - case avatar - case header + private enum ItemType { + case avatar + case header - var maxHeight: CGFloat { - switch self { - case .avatar: - 400 - case .header: - 500 - } - } - - var maxWidth: CGFloat { - switch self { - case .avatar: - 400 - case .header: - 1500 - } - } + var maxHeight: CGFloat { + switch self { + case .avatar: + 400 + case .header: + 500 + } } + + var maxWidth: CGFloat { + switch self { + case .avatar: + 400 + case .header: + 1500 + } + } + } } diff --git a/Packages/Account/Sources/Account/MediaGrid/AccountDetailMediaGridView.swift b/Packages/Account/Sources/Account/MediaGrid/AccountDetailMediaGridView.swift index ddf0af33..3fe520c6 100644 --- a/Packages/Account/Sources/Account/MediaGrid/AccountDetailMediaGridView.swift +++ b/Packages/Account/Sources/Account/MediaGrid/AccountDetailMediaGridView.swift @@ -1,10 +1,10 @@ -import SwiftUI import DesignSystem -import NukeUI import Env import MediaUI import Models import Network +import NukeUI +import SwiftUI @MainActor public struct AccountDetailMediaGridView: View { @@ -12,21 +12,22 @@ public struct AccountDetailMediaGridView: View { @Environment(RouterPath.self) private var routerPath @Environment(Client.self) private var client @Environment(QuickLook.self) private var quickLook - + let account: Account @State var mediaStatuses: [MediaStatus] - + public init(account: Account, initialMediaStatuses: [MediaStatus]) { self.account = account - self.mediaStatuses = initialMediaStatuses + mediaStatuses = initialMediaStatuses } - + public var body: some View { ScrollView(.vertical) { LazyVGrid(columns: [.init(.flexible(minimum: 100), spacing: 4), .init(.flexible(minimum: 100), spacing: 4), .init(.flexible(minimum: 100), spacing: 4)], - spacing: 4) { + spacing: 4) + { ForEach(mediaStatuses) { status in GeometryReader { proxy in if let url = status.attachment.url { @@ -35,7 +36,7 @@ public struct AccountDetailMediaGridView: View { case .image: LazyImage(url: url, transaction: Transaction(animation: .easeIn)) { state in if let image = state.image { - image + image .resizable() .scaledToFill() .frame(width: proxy.size.width, height: proxy.size.width) @@ -84,7 +85,7 @@ public struct AccountDetailMediaGridView: View { .clipped() .aspectRatio(1, contentMode: .fit) } - + VStack { Spacer() NextPageView { @@ -96,21 +97,21 @@ public struct AccountDetailMediaGridView: View { } .navigationTitle(account.displayName ?? "") #if !os(visionOS) - .scrollContentBackground(.hidden) - .background(theme.primaryBackgroundColor) + .scrollContentBackground(.hidden) + .background(theme.primaryBackgroundColor) #endif } - + private func fetchNextPage() async throws { let client = client let newStatuses: [Status] = - try await client.get(endpoint: Accounts.statuses(id: account.id, - sinceId: mediaStatuses.last?.id, + try await client.get(endpoint: Accounts.statuses(id: account.id, + sinceId: mediaStatuses.last?.id, tag: nil, onlyMedia: true, excludeReplies: true, excludeReblogs: true, pinned: nil)) - mediaStatuses.append(contentsOf: newStatuses.flatMap{ $0.asMediaStatus }) + mediaStatuses.append(contentsOf: newStatuses.flatMap { $0.asMediaStatus }) } } diff --git a/Packages/DesignSystem/Sources/DesignSystem/Theme.swift b/Packages/DesignSystem/Sources/DesignSystem/Theme.swift index 71cfb006..e23a29dd 100644 --- a/Packages/DesignSystem/Sources/DesignSystem/Theme.swift +++ b/Packages/DesignSystem/Sources/DesignSystem/Theme.swift @@ -284,7 +284,7 @@ public final class Theme { themeStorage.chosenFontData = chosenFontData } } - + public var showContentGradient: Bool { didSet { themeStorage.showContentGradient = showContentGradient diff --git a/Packages/Env/Sources/Env/CurrentInstance.swift b/Packages/Env/Sources/Env/CurrentInstance.swift index 69e41bb5..06a3f608 100644 --- a/Packages/Env/Sources/Env/CurrentInstance.swift +++ b/Packages/Env/Sources/Env/CurrentInstance.swift @@ -38,7 +38,7 @@ import Observation public var isNotificationsFilterSupported: Bool { version >= 4.3 } - + public var isLinkTimelineSupported: Bool { version >= 4.3 } diff --git a/Packages/Env/Sources/Env/Ext/TranslationView.swift b/Packages/Env/Sources/Env/Ext/TranslationView.swift index 1f629f92..d107f99e 100644 --- a/Packages/Env/Sources/Env/Ext/TranslationView.swift +++ b/Packages/Env/Sources/Env/Ext/TranslationView.swift @@ -3,8 +3,8 @@ import SwiftUI #if canImport(_Translation_SwiftUI) import Translation - extension View { - public func addTranslateView(isPresented: Binding, text: String) -> some View { + public extension View { + func addTranslateView(isPresented: Binding, text: String) -> some View { if #available(iOS 17.4, *) { return self.translationPresentation(isPresented: isPresented, text: text) } else { diff --git a/Packages/Env/Sources/Env/Router.swift b/Packages/Env/Sources/Env/Router.swift index ac6f6ff7..15e9f0f7 100644 --- a/Packages/Env/Sources/Env/Router.swift +++ b/Packages/Env/Sources/Env/Router.swift @@ -137,7 +137,7 @@ public enum SettingsStartingPoint { public var path: [RouterDestination] = [] public var presentedSheet: SheetDestination? - public static var settingsStartingPoint: SettingsStartingPoint? = nil + public static var settingsStartingPoint: SettingsStartingPoint? public init() {} diff --git a/Packages/Explore/Sources/Explore/ExploreView.swift b/Packages/Explore/Sources/Explore/ExploreView.swift index 4a02ac70..7209118a 100644 --- a/Packages/Explore/Sources/Explore/ExploreView.swift +++ b/Packages/Explore/Sources/Explore/ExploreView.swift @@ -354,7 +354,7 @@ public struct ExploreView: View { viewModel.scrollToTopVisible = false } } - + private func makeNextPageView(for type: Search.EntityType) -> some View { NextPageView { await viewModel.fetchNextPage(of: type) diff --git a/Packages/Explore/Sources/Explore/ExploreViewModel.swift b/Packages/Explore/Sources/Explore/ExploreViewModel.swift index cb36f77c..6b995704 100644 --- a/Packages/Explore/Sources/Explore/ExploreViewModel.swift +++ b/Packages/Explore/Sources/Explore/ExploreViewModel.swift @@ -115,7 +115,7 @@ import SwiftUI isSearching = false } } - + func fetchNextPage(of type: Search.EntityType) async { guard let client, !searchQuery.isEmpty, let results = results[searchQuery] else { return } @@ -128,18 +128,18 @@ import SwiftUI case .statuses: results.statuses.count } - + var newPageResults: SearchResults = try await client.get(endpoint: Search.search(query: searchQuery, - type: type, - offset: offset, - following: nil), - forceVersion: .v2) + type: type, + offset: offset, + following: nil), + forceVersion: .v2) if type == .accounts { let relationships: [Relationship] = try await client.get(endpoint: Accounts.relationships(ids: newPageResults.accounts.map(\.id))) newPageResults.relationships = relationships } - + switch type { case .accounts: self.results[searchQuery]?.accounts.append(contentsOf: newPageResults.accounts) @@ -149,8 +149,6 @@ import SwiftUI case .statuses: self.results[searchQuery]?.statuses.append(contentsOf: newPageResults.statuses) } - } catch { - - } + } catch {} } } diff --git a/Packages/MediaUI/Sources/MediaUI/MediaUIShareLink.swift b/Packages/MediaUI/Sources/MediaUI/MediaUIShareLink.swift index 5ab0e198..848502c4 100644 --- a/Packages/MediaUI/Sources/MediaUI/MediaUIShareLink.swift +++ b/Packages/MediaUI/Sources/MediaUI/MediaUIShareLink.swift @@ -8,7 +8,7 @@ public struct MediaUIShareLink: View, @unchecked Sendable { self.url = url self.type = type } - + public var body: some View { if type == .image { let transferable = MediaUIImageTransferable(url: url) diff --git a/Packages/MediaUI/Sources/MediaUI/MediaUITransferableImage.swift b/Packages/MediaUI/Sources/MediaUI/MediaUITransferableImage.swift index 78c46113..11325da3 100644 --- a/Packages/MediaUI/Sources/MediaUI/MediaUITransferableImage.swift +++ b/Packages/MediaUI/Sources/MediaUI/MediaUITransferableImage.swift @@ -8,7 +8,7 @@ public struct MediaUIImageTransferable: Codable, Transferable { public init(url: URL) { self.url = url } - + public func fetchData() async -> Data { do { return try await URLSession.shared.data(from: url).0 diff --git a/Packages/Models/Sources/Models/Alias/HTMLString.swift b/Packages/Models/Sources/Models/Alias/HTMLString.swift index 69b65438..96b99d45 100644 --- a/Packages/Models/Sources/Models/Alias/HTMLString.swift +++ b/Packages/Models/Sources/Models/Alias/HTMLString.swift @@ -175,9 +175,9 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable { return } else if node.nodeName() == "#text" { var txt = node.description - + txt = (try? Entities.unescape(txt)) ?? txt - + if let underscore_regex, let main_regex { // This is the markdown escaper txt = main_regex.stringByReplacingMatches(in: txt, options: [], range: NSRange(location: 0, length: txt.count), withTemplate: "\\\\$1") diff --git a/Packages/Models/Sources/Models/Card.swift b/Packages/Models/Sources/Models/Card.swift index 9dd6f555..1bd5ba81 100644 --- a/Packages/Models/Sources/Models/Card.swift +++ b/Packages/Models/Sources/Models/Card.swift @@ -4,11 +4,12 @@ public struct Card: Codable, Identifiable, Equatable, Hashable { public var id: String { url } - + public struct CardAuthor: Codable, Sendable, Identifiable, Equatable, Hashable { public var id: String { url } + public let name: String public let url: String public let account: Account? diff --git a/Packages/Models/Sources/Models/MediaStatus.swift b/Packages/Models/Sources/Models/MediaStatus.swift index 69088738..069554d3 100644 --- a/Packages/Models/Sources/Models/MediaStatus.swift +++ b/Packages/Models/Sources/Models/MediaStatus.swift @@ -4,10 +4,10 @@ public struct MediaStatus: Sendable, Identifiable, Hashable { public var id: String { attachment.id } - + public let status: Status public let attachment: MediaAttachment - + public init(status: Status, attachment: MediaAttachment) { self.status = status self.attachment = attachment diff --git a/Packages/Models/Sources/Models/Status.swift b/Packages/Models/Sources/Models/Status.swift index 449809b5..e24bfdf3 100644 --- a/Packages/Models/Sources/Models/Status.swift +++ b/Packages/Models/Sources/Models/Status.swift @@ -77,9 +77,9 @@ public final class Status: AnyStatus, Codable, Identifiable, Equatable, Hashable public var isHidden: Bool { filtered?.first?.filter.filterAction == .hide } - + public var asMediaStatus: [MediaStatus] { - mediaAttachments.map{ .init(status: self, attachment: $0)} + mediaAttachments.map { .init(status: self, attachment: $0) } } public init(id: String, content: HTMLString, account: Account, createdAt: ServerDate, editedAt: ServerDate?, reblog: ReblogStatus?, mediaAttachments: [MediaAttachment], mentions: [Mention], repliesCount: Int, reblogsCount: Int, favouritesCount: Int, card: Card?, favourited: Bool?, reblogged: Bool?, pinned: Bool?, bookmarked: Bool?, emojis: [Emoji], url: String?, application: Application?, inReplyToId: String?, inReplyToAccountId: String?, visibility: Visibility, poll: Poll?, spoilerText: HTMLString, filtered: [Filtered]?, sensitive: Bool, language: String?) { diff --git a/Packages/Network/Sources/Network/Endpoint/Profile.swift b/Packages/Network/Sources/Network/Endpoint/Profile.swift index c7aa3936..1b8478f3 100644 --- a/Packages/Network/Sources/Network/Endpoint/Profile.swift +++ b/Packages/Network/Sources/Network/Endpoint/Profile.swift @@ -4,7 +4,6 @@ public enum Profile: Endpoint { case deleteAvatar case deleteHeader - public func path() -> String { switch self { case .deleteAvatar: diff --git a/Packages/Network/Sources/Network/Endpoint/Search.swift b/Packages/Network/Sources/Network/Endpoint/Search.swift index 1b1b5a4a..0bf160bc 100644 --- a/Packages/Network/Sources/Network/Endpoint/Search.swift +++ b/Packages/Network/Sources/Network/Endpoint/Search.swift @@ -4,7 +4,7 @@ public enum Search: Endpoint { public enum EntityType: String, Sendable { case accounts, hashtags, statuses } - + case search(query: String, type: EntityType?, offset: Int?, following: Bool?) case accountsSearch(query: String, type: EntityType?, offset: Int?, following: Bool?) diff --git a/Packages/StatusKit/Sources/StatusKit/Editor/Components/Compressor.swift b/Packages/StatusKit/Sources/StatusKit/Editor/Components/Compressor.swift index d4029a22..4d8fe9c0 100644 --- a/Packages/StatusKit/Sources/StatusKit/Editor/Components/Compressor.swift +++ b/Packages/StatusKit/Sources/StatusKit/Editor/Components/Compressor.swift @@ -58,10 +58,10 @@ public extension StatusEditor { } public func compressImageForUpload( - _ image: UIImage, - maxSize: Int = 10 * 1024 * 1024, - maxHeight: Double = 5000, - maxWidth: Double = 5000 + _ image: UIImage, + maxSize: Int = 10 * 1024 * 1024, + maxHeight: Double = 5000, + maxWidth: Double = 5000 ) async throws -> Data { var image = image diff --git a/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaEditView.swift b/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaEditView.swift index db8cc625..529b0c2f 100644 --- a/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaEditView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaEditView.swift @@ -38,9 +38,9 @@ extension StatusEditor { generateButton } #if canImport(_Translation_SwiftUI) - if #available(iOS 17.4, *), !imageDescription.isEmpty { - translateButton - } + if #available(iOS 17.4, *), !imageDescription.isEmpty { + translateButton + } #endif } .listRowBackground(theme.primaryBackgroundColor) diff --git a/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaView.swift b/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaView.swift index b9d86fb9..880f10ca 100644 --- a/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaView.swift @@ -194,7 +194,7 @@ extension StatusEditor { } } - private func makeErrorView(error: ServerError) -> some View { + private func makeErrorView(error _: ServerError) -> some View { ZStack { placeholderView Text("status.editor.error.upload") diff --git a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowExternalView.swift b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowExternalView.swift index 4f75e536..d1a5667c 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowExternalView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowExternalView.swift @@ -3,12 +3,12 @@ import SwiftUI public struct StatusRowExternalView: View { @State private var viewModel: StatusRowViewModel private let context: StatusRowView.Context - + public init(viewModel: StatusRowViewModel, context: StatusRowView.Context = .timeline) { _viewModel = .init(initialValue: viewModel) self.context = context } - + public var body: some View { StatusRowView(viewModel: viewModel, context: context) } diff --git a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift index 3add988d..0d2d2359 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift @@ -16,7 +16,7 @@ public struct StatusRowView: View { @Environment(\.isStatusFocused) private var isFocused @Environment(\.indentationLevel) private var indentationLevel @Environment(\.isHomeTimeline) private var isHomeTimeline - + @Environment(RouterPath.self) private var routerPath: RouterPath @Environment(QuickLook.self) private var quickLook @@ -27,7 +27,7 @@ public struct StatusRowView: View { @State private var isBlockConfirmationPresented = false public enum Context { case timeline, detail } - + @State public var viewModel: StatusRowViewModel public let context: Context diff --git a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowViewModel.swift b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowViewModel.swift index cac0d16e..9b1c86c3 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowViewModel.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowViewModel.swift @@ -18,7 +18,7 @@ import SwiftUI let client: Client let routerPath: RouterPath - + let userFollowedTag: HTMLString.Link? private let theme = Theme.shared @@ -118,7 +118,7 @@ import SwiftUI backgroundColor } } - + @ViewBuilder var homeBackgroundColor: some View { if status.visibility == .direct { @@ -146,7 +146,7 @@ import SwiftUI theme.primaryBackgroundColor } } - + func makeDecorativeGradient(startColor: Color, endColor: Color) -> some View { LinearGradient(stops: [ .init(color: startColor.opacity(0.2), location: 0.03), @@ -155,8 +155,8 @@ import SwiftUI .init(color: startColor.opacity(0.02), location: 0.15), .init(color: endColor, location: 0.25), ], - startPoint: .topLeading, - endPoint: .bottomTrailing) + startPoint: .topLeading, + endPoint: .bottomTrailing) } public init(status: Status, @@ -191,7 +191,7 @@ import SwiftUI } else { userMentionned = false } - + userFollowedTag = finalStatus.content.links.first(where: { link in link.type == .hashtag && CurrentAccount.shared.tags.contains(where: { $0.name.lowercased() == link.title.lowercased() }) }) @@ -366,29 +366,31 @@ import SwiftUI if preferredTranslationType != .useDeepl { await translateWithInstance(userLang: userLang) - + if translation == nil { await translateWithDeepL(userLang: userLang) } } else { await translateWithDeepL(userLang: userLang) - + if translation == nil { await translateWithInstance(userLang: userLang) } } - + var hasShown = false -#if canImport(_Translation_SwiftUI) - if translation == nil, - #available(iOS 17.4, *) { - showAppleTranslation = true - hasShown = true - } -#endif - + #if canImport(_Translation_SwiftUI) + if translation == nil, + #available(iOS 17.4, *) + { + showAppleTranslation = true + hasShown = true + } + #endif + if !hasShown, - translation == nil { + translation == nil + { if preferredTranslationType == .useDeepl { deeplTranslationError = true } else { @@ -410,7 +412,7 @@ import SwiftUI isLoadingTranslation = false } } - + func translateWithInstance(userLang: String) async { withAnimation { isLoadingTranslation = true diff --git a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowCardView.swift b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowCardView.swift index 2ad79d6f..e23d830f 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowCardView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowCardView.swift @@ -186,7 +186,7 @@ public struct StatusRowCardView: View { } } .buttonStyle(.bordered) - + Spacer() Button { #if targetEnvironment(macCatalyst) @@ -248,7 +248,7 @@ public struct StatusRowCardView: View { }.padding(16) } } - + @ViewBuilder private func moreFromAccountView(_ account: Account, divider: Bool = true) -> some View { if divider { diff --git a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowHeaderView.swift b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowHeaderView.swift index 2a706560..4b99f711 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowHeaderView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowHeaderView.swift @@ -95,9 +95,9 @@ struct StatusRowHeaderView: View { private var dateView: some View { Text("\(Image(systemName: viewModel.finalStatus.visibility.iconName)) βΈ± \(viewModel.finalStatus.createdAt.relativeFormatted)") - .fixedSize(horizontal: false, vertical: true) - .font(.scaledFootnote) - .foregroundStyle(.secondary) - .lineLimit(1) + .fixedSize(horizontal: false, vertical: true) + .font(.scaledFootnote) + .foregroundStyle(.secondary) + .lineLimit(1) } } diff --git a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowMediaPreviewView.swift b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowMediaPreviewView.swift index 8e49fd89..cbdb30db 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowMediaPreviewView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowMediaPreviewView.swift @@ -280,32 +280,32 @@ struct AltTextButton: View { .padding(EdgeInsets(top: 5, leading: 7, bottom: 5, trailing: 7)) .background(.thinMaterial) #if canImport(_Translation_SwiftUI) - .addTranslateView(isPresented: $isDisplayingTranslation, text: text) + .addTranslateView(isPresented: $isDisplayingTranslation, text: text) #endif #if os(visionOS) - .clipShape(Capsule()) + .clipShape(Capsule()) #endif - .cornerRadius(4) - .padding(theme.statusDisplayStyle == .compact ? 0 : 10) - .alert( - "status.editor.media.image-description", - isPresented: $isDisplayingAlert - ) { - Button("alert.button.ok", action: {}) - Button("status.action.copy-text", action: { UIPasteboard.general.string = text }) - #if canImport(_Translation_SwiftUI) + .cornerRadius(4) + .padding(theme.statusDisplayStyle == .compact ? 0 : 10) + .alert( + "status.editor.media.image-description", + isPresented: $isDisplayingAlert + ) { + Button("alert.button.ok", action: {}) + Button("status.action.copy-text", action: { UIPasteboard.general.string = text }) + #if canImport(_Translation_SwiftUI) if #available(iOS 17.4, *) { Button("status.action.translate", action: { isDisplayingTranslation = true }) } - #endif - } message: { - Text(text) - } - .frame( - maxWidth: .infinity, - maxHeight: .infinity, - alignment: .bottomTrailing - ) + #endif + } message: { + Text(text) + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .bottomTrailing + ) } } } diff --git a/Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift b/Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift index 6dccb7f8..dbe18632 100644 --- a/Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift +++ b/Packages/Timeline/Sources/Timeline/View/TimelineViewModel.swift @@ -307,25 +307,26 @@ extension TimelineViewModel: StatusesFetcher { private func fetchNewPagesFrom(latestStatus: String, client: Client) async throws { canStreamEvents = false let initialTimeline = timeline - + let newStatuses = await fetchAndDedupNewStatuses(latestStatus: latestStatus, client: client) - + guard !newStatuses.isEmpty, isTimelineVisible, !Task.isCancelled, - initialTimeline == timeline else { + initialTimeline == timeline + else { canStreamEvents = true return } - + await updateTimelineWithNewStatuses(newStatuses) - + if !Task.isCancelled, let latest = await datasource.get().first { pendingStatusesObserver.isLoadingNewStatuses = true try await fetchNewPagesFrom(latestStatus: latest.id, client: client) } } - + private func fetchAndDedupNewStatuses(latestStatus: String, client: Client) async -> [Status] { var newStatuses = await fetchNewPages(minId: latestStatus, maxPages: 5) let ids = await datasource.get().map(\.id) @@ -335,38 +336,39 @@ extension TimelineViewModel: StatusesFetcher { StatusDataControllerProvider.shared.updateDataControllers(for: newStatuses, client: client) return newStatuses } - + private func updateTimelineWithNewStatuses(_ newStatuses: [Status]) async { let topStatus = await datasource.getFiltered().first await datasource.insert(contentOf: newStatuses, at: 0) await cache() pendingStatusesObserver.pendingStatuses.insert(contentsOf: newStatuses.map(\.id), at: 0) - + let statuses = await datasource.getFiltered() let nextPageState: StatusesState.PagingState = statuses.count < 20 ? .none : .hasNextPage - + if let topStatus = topStatus, visibileStatuses.contains(where: { $0.id == topStatus.id }), - scrollToTopVisible { + scrollToTopVisible + { updateTimelineWithScrollToTop(newStatuses: newStatuses, statuses: statuses, nextPageState: nextPageState) } else { updateTimelineWithAnimation(statuses: statuses, nextPageState: nextPageState) } } - + // Refresh the timeline while keeping the scroll position to the top status. private func updateTimelineWithScrollToTop(newStatuses: [Status], statuses: [Status], nextPageState: StatusesState.PagingState) { pendingStatusesObserver.disableUpdate = true statusesState = .display(statuses: statuses, nextPageState: nextPageState) scrollToIndexAnimated = false scrollToIndex = newStatuses.count + 1 - + DispatchQueue.main.async { [weak self] in self?.pendingStatusesObserver.disableUpdate = false self?.canStreamEvents = true } } - + // Refresh the timeline while keeping the user current position. // It works because a side effect of withAnimation is that it keep scroll position IF the List is not scrolled to the top. private func updateTimelineWithAnimation(statuses: [Status], nextPageState: StatusesState.PagingState) { @@ -381,18 +383,18 @@ extension TimelineViewModel: StatusesFetcher { var allStatuses: [Status] = [] var latestMinId = minId do { - for _ in 1...maxPages { + for _ in 1 ... maxPages { if Task.isCancelled { break } - + let newStatuses: [Status] = try await client.get(endpoint: timeline.endpoint( sinceId: nil, maxId: nil, minId: latestMinId, offset: nil )) - + if newStatuses.isEmpty { break } - + StatusDataControllerProvider.shared.updateDataControllers(for: newStatuses, client: client) allStatuses.insert(contentsOf: newStatuses, at: 0) latestMinId = newStatuses.first?.id ?? latestMinId @@ -400,7 +402,7 @@ extension TimelineViewModel: StatusesFetcher { } catch { return allStatuses } - + return allStatuses }