Rework the presentation of the media browser quick look view to use SwiftUI. (#3619)

* Embed the media preview quick look inside a full screen cover

With a zoom transition on iOS 18.

* Use a the representable coordinator properly.

* Fix a bug with the toolbar appearance.

* Format

* Try prevent the zoom transition being upside down.

* Fix the snapshot test configuration.
This commit is contained in:
Doug
2024-12-16 15:27:50 +00:00
committed by GitHub
parent 89ac38c91b
commit ee24764b08
23 changed files with 593 additions and 473 deletions

View File

@@ -11,6 +11,8 @@ import SwiftUI
struct MediaEventsTimelineScreen: View {
@ObservedObject var context: MediaEventsTimelineScreenViewModel.Context
@Namespace private var zoomTransition
var body: some View {
mainContent
.navigationBarTitleDisplayMode(.inline)
@@ -30,7 +32,6 @@ struct MediaEventsTimelineScreen: View {
.pickerStyle(.segmented)
}
}
.timelineMediaQuickLook(viewModel: $context.mediaPreviewViewModel)
.environmentObject(context.viewState.activeTimelineContextProvider())
.environment(\.timelineContext, context.viewState.activeTimelineContextProvider())
}
@@ -39,7 +40,7 @@ struct MediaEventsTimelineScreen: View {
// * flip the scrollView vertically to keep the items
// at the bottom and have pagination working properly
// * flip the grid vertically to counteract the scroll view
// but also horizontally to preserve the corect item order
// but also horizontally to preserve the correct item order
// * flip the items on both axes have them render correctly
@ViewBuilder
private var mainContent: some View {
@@ -73,7 +74,7 @@ struct MediaEventsTimelineScreen: View {
Section {
ForEach(group.items) { item in
Button {
context.send(viewAction: .tappedItem(item))
tappedItem(item)
} label: {
Color.clear // Let the image aspect fill in place
.aspectRatio(1, contentMode: .fill)
@@ -81,8 +82,9 @@ struct MediaEventsTimelineScreen: View {
viewForTimelineItem(item)
}
.clipped()
.scaleEffect(.init(width: -1, height: -1))
.scaleEffect(scale(for: item, isGridLayout: true))
}
.zoomTransitionSource(id: item.identifier, in: zoomTransition)
}
} footer: {
// Use a footer as the header because the scrollView is flipped
@@ -104,11 +106,12 @@ struct MediaEventsTimelineScreen: View {
Divider()
Button {
context.send(viewAction: .tappedItem(item))
tappedItem(item)
} label: {
viewForTimelineItem(item)
.scaleEffect(.init(width: 1, height: -1))
.scaleEffect(scale(for: item, isGridLayout: false))
}
.zoomTransitionSource(id: item.identifier, in: zoomTransition)
}
.padding(.horizontal, 16)
}
@@ -207,6 +210,19 @@ struct MediaEventsTimelineScreen: View {
.multilineTextAlignment(.center)
}
}
func tappedItem(_ item: RoomTimelineItemViewState) {
context.send(viewAction: .tappedItem(item: item, namespace: zoomTransition))
}
func scale(for item: RoomTimelineItemViewState, isGridLayout: Bool) -> CGSize {
guard item.identifier != context.viewState.currentPreviewItemID else {
// Remove the flip when presenting a preview so that the zoom transition is the right way up 🙃
return CGSize(width: 1, height: 1)
}
return CGSize(width: isGridLayout ? -1 : 1, height: -1)
}
}
// MARK: - Previews