mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-04-26 18:04:44 +00:00
Status detail info view + better single image preview
This commit is contained in:
parent
840461caeb
commit
25a80eea65
2 changed files with 91 additions and 26 deletions
|
@ -36,8 +36,9 @@ public struct StatusDetailView: View {
|
||||||
}
|
}
|
||||||
StatusRowView(viewModel: .init(status: status, isEmbed: false))
|
StatusRowView(viewModel: .init(status: status, isEmbed: false))
|
||||||
.id(status.id)
|
.id(status.id)
|
||||||
|
makeStatusInfoDetailView(status: status)
|
||||||
Divider()
|
Divider()
|
||||||
.padding(.vertical, DS.Constants.dividerPadding)
|
.padding(.vertical, DS.Constants.dividerPadding * 2)
|
||||||
if !context.descendants.isEmpty {
|
if !context.descendants.isEmpty {
|
||||||
ForEach(context.descendants) { descendant in
|
ForEach(context.descendants) { descendant in
|
||||||
StatusRowView(viewModel: .init(status: descendant, isEmbed: false))
|
StatusRowView(viewModel: .init(status: descendant, isEmbed: false))
|
||||||
|
@ -65,4 +66,15 @@ public struct StatusDetailView: View {
|
||||||
.navigationTitle(viewModel.title)
|
.navigationTitle(viewModel.title)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func makeStatusInfoDetailView(status: Status) -> some View {
|
||||||
|
HStack {
|
||||||
|
Text(status.createdAt.asDate, style: .date)
|
||||||
|
Text(status.createdAt.asDate, style: .time)
|
||||||
|
Spacer()
|
||||||
|
Text(status.application?.name ?? "")
|
||||||
|
}
|
||||||
|
.font(.caption)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,16 @@ private class VideoPlayerViewModel: ObservableObject {
|
||||||
func preparePlayer() {
|
func preparePlayer() {
|
||||||
player = .init(url: url)
|
player = .init(url: url)
|
||||||
player?.play()
|
player?.play()
|
||||||
|
guard let player else { return }
|
||||||
|
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
|
||||||
|
object: player.currentItem, queue: .main) { [weak self] _ in
|
||||||
|
self?.player?.seek(to: CMTime.zero)
|
||||||
|
self?.player?.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: self.player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,33 +52,77 @@ public struct StatusMediaPreviewView: View {
|
||||||
@StateObject private var selectedMediaSheetManager = SelectedMediaSheetManager()
|
@StateObject private var selectedMediaSheetManager = SelectedMediaSheetManager()
|
||||||
|
|
||||||
@State private var isQuickLookLoading: Bool = false
|
@State private var isQuickLookLoading: Bool = false
|
||||||
|
|
||||||
|
private var imageMaxHeight: CGFloat {
|
||||||
|
if attachements.count == 1 {
|
||||||
|
return 300
|
||||||
|
}
|
||||||
|
return attachements.count > 2 ? 100 : 200
|
||||||
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
VStack {
|
Group {
|
||||||
HStack {
|
if attachements.count == 1, let attachement = attachements.first {
|
||||||
if let firstAttachement = attachements.first {
|
makeFeaturedImagePreview(attachement: attachement)
|
||||||
makePreview(attachement: firstAttachement)
|
.onTapGesture {
|
||||||
}
|
Task {
|
||||||
if attachements.count > 1, let secondAttachement = attachements[1] {
|
await quickLook.prepareFor(urls: attachements.map{ $0.url }, selectedURL: attachement.url)
|
||||||
makePreview(attachement: secondAttachement)
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
HStack {
|
VStack {
|
||||||
if attachements.count > 2, let secondAttachement = attachements[2] {
|
HStack {
|
||||||
makePreview(attachement: secondAttachement)
|
if let firstAttachement = attachements.first {
|
||||||
}
|
makePreview(attachement: firstAttachement)
|
||||||
if attachements.count > 3, let secondAttachement = attachements[3] {
|
}
|
||||||
makePreview(attachement: secondAttachement)
|
if attachements.count > 1, let secondAttachement = attachements[1] {
|
||||||
|
makePreview(attachement: secondAttachement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HStack {
|
||||||
|
if attachements.count > 2, let secondAttachement = attachements[2] {
|
||||||
|
makePreview(attachement: secondAttachement)
|
||||||
|
}
|
||||||
|
if attachements.count > 3, let secondAttachement = attachements[3] {
|
||||||
|
makePreview(attachement: secondAttachement)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.overlay {
|
.overlay {
|
||||||
if quickLook.isPreparing {
|
if quickLook.isPreparing {
|
||||||
quickLookLoadingView
|
quickLookLoadingView
|
||||||
.transition(.opacity)
|
.transition(.opacity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func makeFeaturedImagePreview(attachement: MediaAttachement) -> some View {
|
||||||
|
switch attachement.supportedType {
|
||||||
|
case .image:
|
||||||
|
AsyncImage(
|
||||||
|
url: attachement.url,
|
||||||
|
content: { image in
|
||||||
|
image
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.cornerRadius(4)
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
RoundedRectangle(cornerRadius: 4)
|
||||||
|
.fill(Color.gray)
|
||||||
|
.frame(height: imageMaxHeight)
|
||||||
|
.shimmering()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
case .gifv:
|
||||||
|
VideoPlayerView(viewModel: .init(url: attachement.url))
|
||||||
|
.frame(height: imageMaxHeight)
|
||||||
|
case .none:
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
|
@ -83,14 +137,15 @@ public struct StatusMediaPreviewView: View {
|
||||||
content: { image in
|
content: { image in
|
||||||
image
|
image
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: attachements.count == 1 ? .fit : .fill)
|
||||||
.frame(height: attachements.count > 2 ? 100 : 200)
|
.frame(height: imageMaxHeight)
|
||||||
.frame(width: proxy.frame(in: .local).width)
|
.frame(width: proxy.frame(in: .local).width)
|
||||||
|
.cornerRadius(4)
|
||||||
},
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
RoundedRectangle(cornerRadius: 4)
|
RoundedRectangle(cornerRadius: 4)
|
||||||
.fill(Color.gray)
|
.fill(Color.gray)
|
||||||
.frame(height: attachements.count > 2 ? 100 : 200)
|
.frame(maxHeight: imageMaxHeight)
|
||||||
.frame(width: proxy.frame(in: .local).width)
|
.frame(width: proxy.frame(in: .local).width)
|
||||||
.shimmering()
|
.shimmering()
|
||||||
}
|
}
|
||||||
|
@ -98,13 +153,11 @@ public struct StatusMediaPreviewView: View {
|
||||||
case .gifv:
|
case .gifv:
|
||||||
VideoPlayerView(viewModel: .init(url: attachement.url))
|
VideoPlayerView(viewModel: .init(url: attachement.url))
|
||||||
.frame(width: proxy.frame(in: .local).width)
|
.frame(width: proxy.frame(in: .local).width)
|
||||||
.frame(height: attachements.count > 2 ? 100 : 200)
|
.frame(height: imageMaxHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(height: attachements.count > 2 ? 100 : 200)
|
.frame(height: imageMaxHeight)
|
||||||
}
|
}
|
||||||
.cornerRadius(4)
|
|
||||||
.contentShape(Rectangle())
|
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
Task {
|
Task {
|
||||||
await quickLook.prepareFor(urls: attachements.map{ $0.url }, selectedURL: attachement.url)
|
await quickLook.prepareFor(urls: attachements.map{ $0.url }, selectedURL: attachement.url)
|
||||||
|
|
Loading…
Reference in a new issue