diff --git a/IceCubesApp/App/Main/AppView.swift b/IceCubesApp/App/Main/AppView.swift index 97bdf32b..7f8cb434 100644 --- a/IceCubesApp/App/Main/AppView.swift +++ b/IceCubesApp/App/Main/AppView.swift @@ -119,6 +119,7 @@ struct AppView: View { .tag(tab) } } + .id(availableTabs.count) /// Resets the TabView state when the number of tabs changes to avoid navigation bar issues and prevent crashes .introspect(.tabView, on: .iOS(.v17, .v18)) { (tabview: UITabBarController) in tabview.tabBar.isHidden = horizontalSizeClass == .regular tabview.customizableViewControllers = [] diff --git a/Packages/MediaUI/Sources/MediaUI/MediaUIAttachmentImageView.swift b/Packages/MediaUI/Sources/MediaUI/MediaUIAttachmentImageView.swift index e29f1aaf..cc5f9921 100644 --- a/Packages/MediaUI/Sources/MediaUI/MediaUIAttachmentImageView.swift +++ b/Packages/MediaUI/Sources/MediaUI/MediaUIAttachmentImageView.swift @@ -22,6 +22,23 @@ struct MediaUIAttachmentImageView: View { .progressViewStyle(.circular) } } + .draggable(MediaUIImageTransferable(url: url)) + .contextMenu { + MediaUIShareLink(url: url, type: .image) + Button { + Task { + let transferable = MediaUIImageTransferable(url: url) + UIPasteboard.general.image = UIImage(data: await transferable.fetchData()) + } + } label: { + Label("status.media.contextmenu.copy", systemImage: "doc.on.doc") + } + Button { + UIPasteboard.general.url = url + } label: { + Label("status.action.copy-link", systemImage: "link") + } + } } } } diff --git a/Packages/MediaUI/Sources/MediaUI/MediaUIShareLink.swift b/Packages/MediaUI/Sources/MediaUI/MediaUIShareLink.swift new file mode 100644 index 00000000..54e0e1f6 --- /dev/null +++ b/Packages/MediaUI/Sources/MediaUI/MediaUIShareLink.swift @@ -0,0 +1,16 @@ +import SwiftUI + +struct MediaUIShareLink: View, @unchecked Sendable { + let url: URL + let type: DisplayType + + var body: some View { + if type == .image { + let transferable = MediaUIImageTransferable(url: url) + ShareLink(item: transferable, preview: .init("status.media.contextmenu.share", + image: transferable)) + } else { + ShareLink(item: url) + } + } +} diff --git a/Packages/MediaUI/Sources/MediaUI/ShareToolbarItem.swift b/Packages/MediaUI/Sources/MediaUI/ShareToolbarItem.swift index eab146fd..dd29973f 100644 --- a/Packages/MediaUI/Sources/MediaUI/ShareToolbarItem.swift +++ b/Packages/MediaUI/Sources/MediaUI/ShareToolbarItem.swift @@ -6,13 +6,7 @@ struct ShareToolbarItem: ToolbarContent, @unchecked Sendable { var body: some ToolbarContent { ToolbarItem(placement: .topBarTrailing) { - if type == .image { - let transferable = MediaUIImageTransferable(url: url) - ShareLink(item: transferable, preview: .init("status.media.contextmenu.share", - image: transferable)) - } else { - ShareLink(item: url) - } + MediaUIShareLink(url: url, type: type) } } } diff --git a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift index eb895ad0..614fe2d6 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift @@ -124,6 +124,7 @@ public struct StatusRowView: View { } } } + .if(viewModel.url != nil) { $0.draggable(viewModel.url!) } .contextMenu { contextMenu .onAppear { diff --git a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowViewModel.swift b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowViewModel.swift index 1e149dd2..eceb66cc 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowViewModel.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowViewModel.swift @@ -105,7 +105,11 @@ import SwiftUI status.reblog?.inReplyToId != nil || status.reblog?.inReplyToAccountId != nil || status.inReplyToId != nil || status.inReplyToAccountId != nil } - + + var url: URL? { + (status.reblog?.url ?? status.url).flatMap(URL.init(string:)) + } + @ViewBuilder func makeBackgroundColor(isHomeTimeline: Bool) -> some View { if isHomeTimeline, theme.showContentGradient { diff --git a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowCardView.swift b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowCardView.swift index 332c89b8..0c69c0c8 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowCardView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowCardView.swift @@ -81,6 +81,7 @@ public struct StatusRowCardView: View { .stroke(.gray.opacity(0.35), lineWidth: 1) } } + .draggable(url) .contextMenu { ShareLink(item: url) { Label("status.card.share", systemImage: "square.and.arrow.up") diff --git a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowContextMenu.swift b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowContextMenu.swift index e44ae4b9..ad5cb675 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowContextMenu.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowContextMenu.swift @@ -88,9 +88,7 @@ struct StatusRowContextMenu: View { Divider() Menu("status.action.share-title") { - if let urlString = viewModel.status.reblog?.url ?? viewModel.status.url, - let url = URL(string: urlString) - { + if let url = viewModel.url { 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)) @@ -133,7 +131,7 @@ struct StatusRowContextMenu: View { } } - if let url = URL(string: viewModel.status.reblog?.url ?? viewModel.status.url ?? "") { + if let url = viewModel.url { Button { UIApplication.shared.open(url) } label: { Label("status.action.view-in-browser", systemImage: "safari") } @@ -152,7 +150,7 @@ struct StatusRowContextMenu: View { } Button { - UIPasteboard.general.string = viewModel.status.reblog?.url ?? viewModel.status.url + UIPasteboard.general.url = viewModel.url } label: { Label("status.action.copy-link", systemImage: "link") }