diff --git a/IceCubesApp/App/AppRouter.swift b/IceCubesApp/App/AppRouter.swift index 583de5a4..1daa9319 100644 --- a/IceCubesApp/App/AppRouter.swift +++ b/IceCubesApp/App/AppRouter.swift @@ -7,6 +7,8 @@ import Lists import Status import SwiftUI import Timeline +import LinkPresentation +import Models @MainActor extension View { @@ -44,7 +46,7 @@ extension View { } } } - + func withSheetDestinations(sheetDestinations: Binding) -> some View { sheet(item: sheetDestinations) { destination in switch destination { @@ -92,10 +94,12 @@ extension View { case let .report(status): ReportView(status: status) .withEnvironments() + case let .shareImage(image, status): + ActivityView(image: image, status: status) } } } - + func withEnvironments() -> some View { environmentObject(CurrentAccount.shared) .environmentObject(UserPreferences.shared) @@ -106,3 +110,42 @@ extension View { .environmentObject(AppAccountsManager.shared.currentClient) } } + +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? { + 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 { + image + } + + func activityViewController(_ activityViewController: UIActivityViewController, + itemForActivityType activityType: UIActivity.ActivityType?) -> Any? { + nil + } + } + + func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIActivityViewController { + return UIActivityViewController(activityItems: [image, LinkDelegate(image: image, status: status)], + applicationActivities: nil) + } + + func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext) {} +} diff --git a/IceCubesApp/Resources/Localization/be.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/be.lproj/Localizable.strings index dd096553..ad8b9e3e 100644 --- a/IceCubesApp/Resources/Localization/be.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/be.lproj/Localizable.strings @@ -372,6 +372,9 @@ "status.action.reply" = "Адказаць"; "status.action.section.your-post" = "Ваш допіс"; "status.action.share" = "Падзяліцца гэтым допісам"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Скасаваць закладку"; "status.action.unboost" = "Адмяніць павышэнне"; "status.action.unfavorite" = "Выдаліць з улюбенага"; diff --git a/IceCubesApp/Resources/Localization/ca.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/ca.lproj/Localizable.strings index ab27de14..01838838 100644 --- a/IceCubesApp/Resources/Localization/ca.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/ca.lproj/Localizable.strings @@ -382,6 +382,9 @@ "status.action.reply" = "Respon"; "status.action.section.your-post" = "La vostra publicació"; "status.action.share" = "Comparteix la publicació"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Elimina dels marcadors"; "status.action.unboost" = "Desfés l'impulsa"; "status.action.unfavorite" = "Desfés el preferit"; diff --git a/IceCubesApp/Resources/Localization/de.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/de.lproj/Localizable.strings index 38a7fcef..9e468da5 100644 --- a/IceCubesApp/Resources/Localization/de.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/de.lproj/Localizable.strings @@ -379,6 +379,9 @@ "status.action.reply" = "Antworten"; "status.action.section.your-post" = "Dein Beitrag"; "status.action.share" = "Diesen Beitrag teilen"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Lesezeichen entfernen"; "status.action.unboost" = "Boost entfernen"; "status.action.unfavorite" = "Favorit entfernen"; diff --git a/IceCubesApp/Resources/Localization/en-GB.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/en-GB.lproj/Localizable.strings index f79a90a0..59c3027b 100644 --- a/IceCubesApp/Resources/Localization/en-GB.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/en-GB.lproj/Localizable.strings @@ -385,6 +385,9 @@ "status.action.reply" = "Reply"; "status.action.section.your-post" = "Your post"; "status.action.share" = "Share this post"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Unbookmark"; "status.action.unboost" = "Unboost"; "status.action.unfavorite" = "Unfavourite"; diff --git a/IceCubesApp/Resources/Localization/en.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/en.lproj/Localizable.strings index 91ebfcf8..7605b6b8 100644 --- a/IceCubesApp/Resources/Localization/en.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/en.lproj/Localizable.strings @@ -384,6 +384,9 @@ "status.action.reply" = "Reply"; "status.action.section.your-post" = "Your post"; "status.action.share" = "Share this post"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Unbookmark"; "status.action.unboost" = "Unboost"; "status.action.unfavorite" = "Unfavorite"; diff --git a/IceCubesApp/Resources/Localization/es.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/es.lproj/Localizable.strings index 5168ef77..0cdb9042 100644 --- a/IceCubesApp/Resources/Localization/es.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/es.lproj/Localizable.strings @@ -384,6 +384,9 @@ "status.action.reply" = "Responder"; "status.action.section.your-post" = "Tus publicaciones"; "status.action.share" = "Compartir esta publicación"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Quitar de marcadores"; "status.action.unboost" = "Deshacer Retoot"; "status.action.unfavorite" = "Eliminar de favoritos"; diff --git a/IceCubesApp/Resources/Localization/eu.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/eu.lproj/Localizable.strings index 30024411..b39937c1 100644 --- a/IceCubesApp/Resources/Localization/eu.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/eu.lproj/Localizable.strings @@ -377,6 +377,9 @@ "status.action.reply" = "Erantzun"; "status.action.section.your-post" = "Zure bidalketa"; "status.action.share" = "Partekatu bidalketa"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Kendu laster-marka"; "status.action.unboost" = "Kendu bultzada"; "status.action.unfavorite" = "Kendu gogokoa"; diff --git a/IceCubesApp/Resources/Localization/fr.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/fr.lproj/Localizable.strings index 82f87922..05b9fcba 100644 --- a/IceCubesApp/Resources/Localization/fr.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/fr.lproj/Localizable.strings @@ -379,6 +379,9 @@ "status.action.reply" = "Répondre"; "status.action.section.your-post" = "Votre publication"; "status.action.share" = "Partager cette publication"; +"status.action.share-link" = "Partager le lien"; +"status.action.share-image" = "Partager comme image"; +"status.action.share-title" = "Partager"; "status.action.unbookmark" = "Démarquer"; "status.action.unboost" = "Annuler la promotion"; "status.action.unfavorite" = "Retirer des favoris"; diff --git a/IceCubesApp/Resources/Localization/it.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/it.lproj/Localizable.strings index b9d9ae40..f76be021 100644 --- a/IceCubesApp/Resources/Localization/it.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/it.lproj/Localizable.strings @@ -384,6 +384,9 @@ "status.action.reply" = "Rispondi"; "status.action.section.your-post" = "I tuoi post"; "status.action.share" = "Condividi questo post"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Rimuovi il segnalibro"; "status.action.unboost" = "Rimuovi la condivisione"; "status.action.unfavorite" = "Rimuovi l'apprezzamento"; diff --git a/IceCubesApp/Resources/Localization/ja.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/ja.lproj/Localizable.strings index a42c4f16..b12ec4a8 100644 --- a/IceCubesApp/Resources/Localization/ja.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/ja.lproj/Localizable.strings @@ -383,6 +383,9 @@ "status.action.reply" = "リプライ"; "status.action.section.your-post" = "あなたの投稿"; "status.action.share" = "投稿を共有する"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "ブックマークを外す"; "status.action.unboost" = "ブーストをやめる"; "status.action.unfavorite" = "お気に入りから外す"; diff --git a/IceCubesApp/Resources/Localization/ko.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/ko.lproj/Localizable.strings index ef497dbb..645e3835 100644 --- a/IceCubesApp/Resources/Localization/ko.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/ko.lproj/Localizable.strings @@ -385,6 +385,9 @@ "status.action.reply" = "댓글"; "status.action.section.your-post" = "내 글"; "status.action.share" = "공유"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "보관함에서 제거"; "status.action.unboost" = "부스트 취소"; "status.action.unfavorite" = "좋아요 취소"; diff --git a/IceCubesApp/Resources/Localization/nb.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/nb.lproj/Localizable.strings index e2356d3c..e258a4f7 100644 --- a/IceCubesApp/Resources/Localization/nb.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/nb.lproj/Localizable.strings @@ -383,6 +383,9 @@ "status.action.reply" = "Svar"; "status.action.section.your-post" = "Ditt innlegg"; "status.action.share" = "Del dette innlegget"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Fjern bokmerke"; "status.action.unboost" = "Opphev forsterkningen"; "status.action.unfavorite" = "Ikke favoritt"; diff --git a/IceCubesApp/Resources/Localization/nl.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/nl.lproj/Localizable.strings index f82e7ac8..e819c8f9 100644 --- a/IceCubesApp/Resources/Localization/nl.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/nl.lproj/Localizable.strings @@ -377,6 +377,9 @@ "status.action.reply" = "Antwoord"; "status.action.section.your-post" = "Jouw post"; "status.action.share" = "Deel deze post"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Verwijder bladwijzer"; "status.action.unboost" = "Maak boost ongedaan"; "status.action.unfavorite" = "Verwijder favoriet"; diff --git a/IceCubesApp/Resources/Localization/pl.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/pl.lproj/Localizable.strings index 63c9eb47..09a8f74b 100644 --- a/IceCubesApp/Resources/Localization/pl.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/pl.lproj/Localizable.strings @@ -379,6 +379,9 @@ "status.action.reply" = "Odpowiedz"; "status.action.section.your-post" = "Twój post"; "status.action.share" = "Udostępnij ten post"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Usuń zakładkę"; "status.action.unboost" = "Cofnij podbicie"; "status.action.unfavorite" = "Usuń z polubionych"; diff --git a/IceCubesApp/Resources/Localization/pt-BR.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/pt-BR.lproj/Localizable.strings index b67e4972..465cb599 100644 --- a/IceCubesApp/Resources/Localization/pt-BR.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/pt-BR.lproj/Localizable.strings @@ -383,6 +383,9 @@ "status.action.reply" = "Responder"; "status.action.section.your-post" = "Sua postagem"; "status.action.share" = "Compartilhe esta postagem"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Remover dos salvos"; "status.action.unboost" = "Unboost"; "status.action.unfavorite" = "Desfavoritar"; diff --git a/IceCubesApp/Resources/Localization/tr.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/tr.lproj/Localizable.strings index 515b4b27..eb1ea021 100644 --- a/IceCubesApp/Resources/Localization/tr.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/tr.lproj/Localizable.strings @@ -379,6 +379,9 @@ "status.action.reply" = "Cevapla"; "status.action.section.your-post" = "Senin gönderin"; "status.action.share" = "Bu gönderiyi paylaş"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "Yer İmini Kaldır"; "status.action.unboost" = "Yükseltmeyi Kaldır"; "status.action.unfavorite" = "Favoriyi Kaldır"; diff --git a/IceCubesApp/Resources/Localization/zh-Hans.lproj/Localizable.strings b/IceCubesApp/Resources/Localization/zh-Hans.lproj/Localizable.strings index a468d50d..1f2b5eed 100644 --- a/IceCubesApp/Resources/Localization/zh-Hans.lproj/Localizable.strings +++ b/IceCubesApp/Resources/Localization/zh-Hans.lproj/Localizable.strings @@ -384,6 +384,9 @@ "status.action.reply" = "回复"; "status.action.section.your-post" = "你的嘟文"; "status.action.share" = "分享嘟文"; +"status.action.share-link" = "Share post link"; +"status.action.share-image" = "Share post as image"; +"status.action.share-title" = "Share"; "status.action.unbookmark" = "取消书签"; "status.action.unboost" = "取消转发"; "status.action.unfavorite" = "取消收藏"; diff --git a/Packages/DesignSystem/Sources/DesignSystem/Views/AvatarView.swift b/Packages/DesignSystem/Sources/DesignSystem/Views/AvatarView.swift index 6f033bb2..376fbeee 100644 --- a/Packages/DesignSystem/Sources/DesignSystem/Views/AvatarView.swift +++ b/Packages/DesignSystem/Sources/DesignSystem/Views/AvatarView.swift @@ -1,8 +1,10 @@ import NukeUI +import Nuke import Shimmer import SwiftUI public struct AvatarView: View { + @Environment(\.isInCaptureMode) private var isInCaptureMode: Bool @Environment(\.redactionReasons) private var reasons @EnvironmentObject private var theme: Theme @@ -54,16 +56,24 @@ public struct AvatarView: View { .fill(.gray) .frame(width: size.size.width, height: size.size.height) } else { - LazyImage(url: url) { state in - if let image = state.image { - image - .resizable() - .aspectRatio(contentMode: .fit) - } else { - placeholderView + if isInCaptureMode, let image = Nuke.ImagePipeline.shared.cache.cachedImage(for: .init(url: url))?.image { + Image(uiImage: image) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: size.size.width, height: size.size.height) + } else { + LazyImage(url: url) { state in + if let image = state.image { + image + .resizable() + .aspectRatio(contentMode: .fit) + } else { + placeholderView + } } + .animation(nil) + .frame(width: size.size.width, height: size.size.height) } - .frame(width: size.size.width, height: size.size.height) } } .clipShape(clipShape) diff --git a/Packages/Env/Sources/Env/CustomEnvValues.swift b/Packages/Env/Sources/Env/CustomEnvValues.swift index fb8e177a..95684881 100644 --- a/Packages/Env/Sources/Env/CustomEnvValues.swift +++ b/Packages/Env/Sources/Env/CustomEnvValues.swift @@ -13,6 +13,10 @@ private struct IsCompact: EnvironmentKey { static let defaultValue: Bool = false } +private struct IsInCaptureMode: EnvironmentKey { + static let defaultValue: Bool = false +} + public extension EnvironmentValues { var isSecondaryColumn: Bool { get { self[SecondaryColumnKey.self] } @@ -28,4 +32,9 @@ public extension EnvironmentValues { get { self[IsCompact.self] } set { self[IsCompact.self] = newValue } } + + var isInCaptureMode: Bool { + get { self[IsInCaptureMode.self] } + set { self[IsInCaptureMode.self] = newValue } + } } diff --git a/Packages/Env/Sources/Env/Router.swift b/Packages/Env/Sources/Env/Router.swift index 8827b8de..f27f39c2 100644 --- a/Packages/Env/Sources/Env/Router.swift +++ b/Packages/Env/Sources/Env/Router.swift @@ -34,6 +34,7 @@ public enum SheetDestinations: Identifiable { case settings case accountPushNotficationsSettings case report(status: Status) + case shareImage(image: UIImage, status: Status) public var id: String { switch self { @@ -52,6 +53,8 @@ public enum SheetDestinations: Identifiable { return "statusEditHistory" case .report: return "report" + case .shareImage: + return "shareImage" } } } diff --git a/Packages/Status/Sources/Status/Row/Subviews/StatusRowCardView.swift b/Packages/Status/Sources/Status/Row/Subviews/StatusRowCardView.swift index 6e61c960..b647a2d2 100644 --- a/Packages/Status/Sources/Status/Row/Subviews/StatusRowCardView.swift +++ b/Packages/Status/Sources/Status/Row/Subviews/StatusRowCardView.swift @@ -1,12 +1,15 @@ import DesignSystem import Models +import Nuke import NukeUI import Shimmer import SwiftUI public struct StatusRowCardView: View { - @EnvironmentObject private var theme: Theme @Environment(\.openURL) private var openURL + @Environment(\.isInCaptureMode) private var isInCaptureMode: Bool + + @EnvironmentObject private var theme: Theme let card: Card public init(card: Card) { @@ -16,8 +19,10 @@ public struct StatusRowCardView: View { public var body: some View { if let title = card.title, let url = URL(string: card.url) { VStack(alignment: .leading) { - if let imageURL = card.image { + if let imageURL = card.image, !isInCaptureMode { GeometryReader { proxy in + let processors: [ImageProcessing] = [.resize(size: .init(width: proxy.frame(in: .local).width, + height: 200))] LazyImage(url: imageURL) { state in if let image = state.image { image @@ -32,6 +37,7 @@ public struct StatusRowCardView: View { .frame(height: 200) } } + .processors(processors) } .frame(height: 200) } diff --git a/Packages/Status/Sources/Status/Row/Subviews/StatusRowContextMenu.swift b/Packages/Status/Sources/Status/Row/Subviews/StatusRowContextMenu.swift index 717b5d70..af79a485 100644 --- a/Packages/Status/Sources/Status/Row/Subviews/StatusRowContextMenu.swift +++ b/Packages/Status/Sources/Status/Row/Subviews/StatusRowContextMenu.swift @@ -1,14 +1,19 @@ import Env import Foundation import SwiftUI +import DesignSystem +import Network 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 body: some View { if !viewModel.isRemote { Button { Task { @@ -56,13 +61,45 @@ struct StatusRowContextMenu: View { Divider() - if let urlString = viewModel.status.reblog?.url ?? viewModel.status.url, - let url = URL(string: urlString) - { - ShareLink(item: url, - subject: Text(viewModel.status.reblog?.account.safeDisplayName ?? viewModel.status.account.safeDisplayName), - message: Text(viewModel.status.reblog?.content.asRawText ?? viewModel.status.content.asRawText)) { - Label("status.action.share", systemImage: "square.and.arrow.up") + Menu("status.action.share-title") { + if let urlString = viewModel.status.reblog?.url ?? viewModel.status.url, + let url = URL(string: urlString) + { + ShareLink(item: url, + subject: Text(viewModel.status.reblog?.account.safeDisplayName ?? viewModel.status.account.safeDisplayName), + 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) + .padding(16) + } + .environment(\.isInCaptureMode, true) + .environmentObject(Theme.shared) + .environmentObject(preferences) + .environmentObject(account) + .environmentObject(currentInstance) + .environmentObject(SceneDelegate()) + .environmentObject(QuickLook()) + .environmentObject(viewModel.client) + .preferredColorScheme(Theme.shared.selectedScheme == .dark ? .dark : .light) + .background(Theme.shared.primaryBackgroundColor) + .cornerRadius(4) + .frame(width: sceneDelegate.windowWidth) + let renderer = ImageRenderer(content: view) + renderer.scale = displayScale + if let image = renderer.uiImage { + viewModel.routerPath.presentedSheet = .shareImage(image: image, status: viewModel.status) + } + } label: { + Label("status.action.share-image", systemImage: "photo") + } } } @@ -144,3 +181,13 @@ struct StatusRowContextMenu: View { } } } + +struct ActivityView: UIViewControllerRepresentable { + let image: Image + + func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIActivityViewController { + return UIActivityViewController(activityItems: [image], applicationActivities: nil) + } + + func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext) {} +} diff --git a/Packages/Status/Sources/Status/Row/Subviews/StatusRowHeaderView.swift b/Packages/Status/Sources/Status/Row/Subviews/StatusRowHeaderView.swift index 974b0b0c..e161800c 100644 --- a/Packages/Status/Sources/Status/Row/Subviews/StatusRowHeaderView.swift +++ b/Packages/Status/Sources/Status/Row/Subviews/StatusRowHeaderView.swift @@ -3,6 +3,7 @@ import Models import SwiftUI struct StatusRowHeaderView: View { + @Environment(\.isInCaptureMode) private var isInCaptureMode: Bool @EnvironmentObject private var theme: Theme let status: AnyStatus @@ -17,8 +18,10 @@ struct StatusRowHeaderView: View { } .buttonStyle(.plain) Spacer() - threadIcon - contextMenuButton + if !isInCaptureMode { + threadIcon + contextMenuButton + } } .accessibilityElement() .accessibilityLabel(Text("\(status.account.displayName)")) diff --git a/Packages/Status/Sources/Status/Row/Subviews/StatusRowMediaPreviewView.swift b/Packages/Status/Sources/Status/Row/Subviews/StatusRowMediaPreviewView.swift index 5590abc0..c6d4e79a 100644 --- a/Packages/Status/Sources/Status/Row/Subviews/StatusRowMediaPreviewView.swift +++ b/Packages/Status/Sources/Status/Row/Subviews/StatusRowMediaPreviewView.swift @@ -7,8 +7,9 @@ import SwiftUI public struct StatusRowMediaPreviewView: View { @Environment(\.openURL) private var openURL - @Environment(\.isSecondaryColumn) private var isSecondaryColumn + @Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool @Environment(\.extraLeadingInset) private var extraLeadingInset: CGFloat + @Environment(\.isInCaptureMode) private var isInCaptureMode: Bool @EnvironmentObject var sceneDelegate: SceneDelegate @EnvironmentObject private var preferences: UserPreferences @@ -150,24 +151,36 @@ public struct StatusRowMediaPreviewView: View { let size: CGSize = size(for: attachment) ?? .init(width: imageMaxHeight, height: imageMaxHeight) let newSize = imageSize(from: size, newWidth: availableWidth - appLayoutWidth) + let processors: [ImageProcessing] = [.resize(size: .init(width: newSize.width, height: newSize.height))] switch attachment.supportedType { case .image: - LazyImage(url: attachment.url) { state in - if let image = state.image { - image - .resizable() - .aspectRatio(contentMode: .fill) - .frame(width: newSize.width, height: newSize.height) - .clipped() - .cornerRadius(4) - } else { - RoundedRectangle(cornerRadius: 4) - .fill(Color.gray) - .frame(width: newSize.width, height: newSize.height) + if isInCaptureMode, + let image = Nuke.ImagePipeline.shared.cache.cachedImage(for: .init(url: attachment.url, + processors: processors))?.image { + Image(uiImage: image) + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: newSize.width, height: newSize.height) + .clipped() + .cornerRadius(4) + } else { + LazyImage(url: attachment.url) { state in + if let image = state.image { + image + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: newSize.width, height: newSize.height) + .clipped() + .cornerRadius(4) + } else { + RoundedRectangle(cornerRadius: 4) + .fill(Color.gray) + .frame(width: newSize.width, height: newSize.height) + } } + .processors([.resize(size: .init(width: newSize.width, height: newSize.height))]) + .frame(width: newSize.width, height: newSize.height) } - .processors([.resize(size: .init(width: newSize.width, height: newSize.height))]) - .frame(width: newSize.width, height: newSize.height) case .gifv, .video, .audio: if let url = attachment.url { @@ -177,10 +190,10 @@ public struct StatusRowMediaPreviewView: View { case .none: EmptyView() } - if sensitive { + if !isInCaptureMode, sensitive { cornerSensitiveButton } - if let alt = attachment.description, !alt.isEmpty, !isNotifications, preferences.showAltTextForMedia { + if !isInCaptureMode, let alt = attachment.description, !alt.isEmpty, !isNotifications, preferences.showAltTextForMedia { Group { Button { altTextDisplayed = alt @@ -207,28 +220,44 @@ public struct StatusRowMediaPreviewView: View { switch type { case .image: let width = isNotifications ? imageMaxHeight : proxy.frame(in: .local).width + let processors: [ImageProcessing] = [.resize(size: .init(width: width, height: imageMaxHeight))] ZStack(alignment: .bottomTrailing) { - LazyImage(url: attachment.previewUrl ?? attachment.url) { state in - if let image = state.image { - image - .resizable() - .aspectRatio(contentMode: .fill) - .frame(maxWidth: width) - .frame(maxHeight: imageMaxHeight) - .clipped() - .cornerRadius(4) - } else if state.isLoading { - RoundedRectangle(cornerRadius: 4) - .fill(Color.gray) - .frame(maxHeight: imageMaxHeight) - .frame(maxWidth: width) + if isInCaptureMode, + let image = Nuke.ImagePipeline.shared.cache.cachedImage(for: .init(url: attachment.previewUrl ?? attachment.url, processors: processors))?.image { + Image(uiImage: image) + .resizable() + .aspectRatio(contentMode: .fill) + .frame(maxWidth: width) + .frame(maxHeight: imageMaxHeight) + .clipped() + .cornerRadius(4) + } else { + LazyImage(url: attachment.previewUrl ?? attachment.url) { state in + if let image = state.image { + image + .resizable() + .aspectRatio(contentMode: .fill) + .frame(maxWidth: width) + .frame(maxHeight: imageMaxHeight) + .clipped() + .cornerRadius(4) + } else if state.isLoading { + RoundedRectangle(cornerRadius: 4) + .fill(Color.gray) + .frame(maxHeight: imageMaxHeight) + .frame(maxWidth: width) + } } + .processors(processors) } - .processors([.resize(size: .init(width: width, height: imageMaxHeight))]) - if sensitive { + if sensitive, !isInCaptureMode { cornerSensitiveButton } - if let alt = attachment.description, !alt.isEmpty, !isNotifications, preferences.showAltTextForMedia { + if !isInCaptureMode, + let alt = attachment.description, + !alt.isEmpty, + !isNotifications, + preferences.showAltTextForMedia { Button { altTextDisplayed = alt isAltAlertDisplayed = true