Skip to content

Commit

Permalink
Use TimelineMediaQuickLook in the MediaEventsTimelineScreen. (#3598)
Browse files Browse the repository at this point in the history
  • Loading branch information
pixlwave authored Dec 10, 2024
1 parent ea0fa6b commit e59a705
Show file tree
Hide file tree
Showing 19 changed files with 109 additions and 37 deletions.
4 changes: 4 additions & 0 deletions ElementX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,7 @@
BE8E5985771DF9137C6CE89A /* ProcessInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077B01C13BBA2996272C5FB5 /* ProcessInfo.swift */; };
BEA646DF302711A753F0D420 /* MapTilerStyleBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 225EFCA26877E75CDFE7F48D /* MapTilerStyleBuilderProtocol.swift */; };
BEC6DFEA506085D3027E353C /* MediaEventsTimelineScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002399C6CB875C4EBB01CBC0 /* MediaEventsTimelineScreen.swift */; };
BFDDAF1A36FBC7CF63DCB7DD /* clear.png in Resources */ = {isa = PBXBuildFile; fileRef = 17F7A723A46DF5C95BE15EBF /* clear.png */; };
BFEB24336DFD5F196E6F3456 /* IntentionalMentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DF5CBAF69BDF5DF31C661E1 /* IntentionalMentions.swift */; };
C0090506A52A1991BAF4BA68 /* NotificationSettingsChatType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07579F9C29001E40715F3014 /* NotificationSettingsChatType.swift */; };
C022284E2774A5E1EF683B4D /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */; };
Expand Down Expand Up @@ -1408,6 +1409,7 @@
1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogAnalyticsClient.swift; sourceTree = "<group>"; };
1734A445A58ED855B977A0A8 /* TracingConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingConfigurationTests.swift; sourceTree = "<group>"; };
17A8AA0DFA06012A9DAB951E /* TimelineProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineProxyMock.swift; sourceTree = "<group>"; };
17F7A723A46DF5C95BE15EBF /* clear.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = clear.png; sourceTree = "<group>"; };
18486B87745B1811E7FBD3D2 /* AnalyticsPromptScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenModels.swift; sourceTree = "<group>"; };
184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecorationTimelineItemProtocol.swift; sourceTree = "<group>"; };
18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxy.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2958,6 +2960,7 @@
isa = PBXGroup;
children = (
01C4C7DB37597D7D8379511A /* Assets.xcassets */,
17F7A723A46DF5C95BE15EBF /* clear.png */,
A0C06C0F6A8621B22BFAEB56 /* Localizations */,
8AEA6A91159FA0D3EAFCCB0D /* Sounds */,
);
Expand Down Expand Up @@ -6204,6 +6207,7 @@
5FCD8AFA364206EE32B909A3 /* Settings.bundle in Resources */,
CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */,
2797C9D9BA642370F1C85D78 /* Untranslated.stringsdict in Resources */,
BFDDAF1A36FBC7CF63DCB7DD /* clear.png in Resources */,
147597951DB07123A87AA1D1 /* landscape_test_image.jpg in Resources */,
FDC67E8C0EDCB00ABC66C859 /* landscape_test_video.mov in Resources */,
E67418DACEDBC29E988E6ACD /* message.caf in Resources */,
Expand Down
Binary file added ElementX/Resources/clear.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ class MediaEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
mediaPlayerProvider: MediaPlayerProvider(),
voiceMessageMediaManager: userSession.voiceMessageMediaManager,
appMediator: appMediator,
emojiProvider: emojiProvider)
emojiProvider: emojiProvider,
userIndicatorController: userIndicatorController)

let coordinator = MediaEventsTimelineScreenCoordinator(parameters: parameters)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ class TimelineMediaPreviewController: QLPreviewController, QLPreviewControllerDa

headerHostingController = UIHostingController(rootView: HeaderView(context: viewModel.context))
headerHostingController.view.backgroundColor = .clear
headerHostingController.sizingOptions = .intrinsicContentSize
captionHostingController = UIHostingController(rootView: CaptionView(context: viewModel.context))
captionHostingController.view.backgroundColor = .clear
captionHostingController.sizingOptions = .intrinsicContentSize
detailsHostingController = UIHostingController(rootView: TimelineMediaPreviewDetailsView(context: viewModel.context))
detailsHostingController.view.backgroundColor = .compound.bgCanvasDefault

Expand Down Expand Up @@ -87,9 +89,7 @@ class TimelineMediaPreviewController: QLPreviewController, QLPreviewControllerDa

navigationBar?.topItem?.titleView = headerHostingController.view

if navigationBar?.topItem?.rightBarButtonItems?.count == 1 {
navigationBar?.topItem?.rightBarButtonItems?.append(UIBarButtonItem(image: UIImage(systemSymbol: .infoCircle), style: .plain, target: self, action: #selector(presentMediaDetails)))
}
updateBarButtons()
}

// MARK: QLPreviewControllerDataSource
Expand All @@ -111,6 +111,21 @@ class TimelineMediaPreviewController: QLPreviewController, QLPreviewControllerDa

present(detailsHostingController, animated: true)
}

private var detailsButtonIcon: UIImage {
guard let bundle = Bundle(url: Bundle.main.bundleURL.appending(path: "CompoundDesignTokens_CompoundDesignTokens.bundle")) else {
return UIImage(systemSymbol: .infoCircle)
}

return UIImage(named: "info", in: bundle, compatibleWith: nil) ?? UIImage(systemSymbol: .infoCircle)
}

private func updateBarButtons() {
if navigationBar?.topItem?.rightBarButtonItems?.count == 1 {
let button = UIBarButtonItem(image: detailsButtonIcon, style: .plain, target: self, action: #selector(presentMediaDetails))
navigationBar?.topItem?.rightBarButtonItems?.append(button)
}
}
}

// MARK: - Subviews
Expand Down Expand Up @@ -143,7 +158,21 @@ private struct CaptionView: View {
.frame(maxWidth: .infinity, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
.padding(16)
.background(.ultraThinMaterial)
.background {
BlurView(style: .systemChromeMaterial) // Darkest material available, matches the bottom bar when content is beneath.
}
}
}
}

private struct BlurView: UIViewRepresentable {
var style: UIBlurEffect.Style

func makeUIView(context: Context) -> UIVisualEffectView {
UIVisualEffectView(effect: UIBlurEffect(style: style))
}

func updateUIView(_ uiView: UIVisualEffectView, context: Context) {
uiView.effect = UIBlurEffect(style: style)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ class TimelineMediaPreviewItem: NSObject, QLPreviewItem {
// MARK: QLPreviewItem

var previewItemURL: URL? {
fileHandle?.url
// Falling back to a clear image allows the presentation animation to work when
// the item is in the event cache and just needs to be loaded from the store.
fileHandle?.url ?? Bundle.main.url(forResource: "clear", withExtension: "png")
}

var previewItemTitle: String? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct MediaEventsTimelineScreenCoordinatorParameters {
let voiceMessageMediaManager: VoiceMessageMediaManagerProtocol
let appMediator: AppMediatorProtocol
let emojiProvider: EmojiProviderProtocol
let userIndicatorController: UserIndicatorControllerProtocol
}

enum MediaEventsTimelineScreenCoordinatorAction { }
Expand Down Expand Up @@ -59,7 +60,8 @@ final class MediaEventsTimelineScreenCoordinator: CoordinatorProtocol {

viewModel = MediaEventsTimelineScreenViewModel(mediaTimelineViewModel: mediaTimelineViewModel,
filesTimelineViewModel: filesTimelineViewModel,
mediaProvider: parameters.mediaProvider)
mediaProvider: parameters.mediaProvider,
userIndicatorController: parameters.userIndicatorController)
}

func toPresentable() -> AnyView {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ struct MediaEventsTimelineScreenViewState: BindableState {

struct MediaEventsTimelineScreenViewStateBindings {
var screenMode: MediaEventsTimelineScreenMode
var mediaPreviewViewModel: TimelineMediaPreviewViewModel?
}

enum MediaEventsTimelineScreenViewAction {
case changedScreenMode
case oldestItemDidAppear
case oldestItemDidDisappear
case tappedItem(RoomTimelineItemViewState)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ typealias MediaEventsTimelineScreenViewModelType = StateStoreViewModel<MediaEven
class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType, MediaEventsTimelineScreenViewModelProtocol {
private let mediaTimelineViewModel: TimelineViewModelProtocol
private let filesTimelineViewModel: TimelineViewModelProtocol
private let userIndicatorController: UserIndicatorControllerProtocol

private var isOldestItemVisible = false

Expand All @@ -33,9 +34,11 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
init(mediaTimelineViewModel: TimelineViewModelProtocol,
filesTimelineViewModel: TimelineViewModelProtocol,
mediaProvider: MediaProviderProtocol,
screenMode: MediaEventsTimelineScreenMode = .media) {
screenMode: MediaEventsTimelineScreenMode = .media,
userIndicatorController: UserIndicatorControllerProtocol) {
self.mediaTimelineViewModel = mediaTimelineViewModel
self.filesTimelineViewModel = filesTimelineViewModel
self.userIndicatorController = userIndicatorController

super.init(initialViewState: .init(bindings: .init(screenMode: screenMode)), mediaProvider: mediaProvider)

Expand Down Expand Up @@ -73,6 +76,8 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
backPaginateIfNecessary(paginationStatus: activeTimelineViewModel.context.viewState.timelineState.paginationState.backward)
case .oldestItemDidDisappear:
isOldestItemVisible = false
case .tappedItem(let item):
handleItemTapped(item)
}
}

Expand All @@ -99,4 +104,24 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
activeTimelineViewModel.context.send(viewAction: .paginateBackwards)
}
}

private func handleItemTapped(_ item: RoomTimelineItemViewState) {
let item: EventBasedMessageTimelineItemProtocol? = switch item.type {
case .audio(let audioItem): audioItem
case .file(let fileItem): fileItem
case .image(let imageItem): imageItem
case .video(let videoItem): videoItem
default: nil
}

guard let item, let mediaProvider = context.mediaProvider else {
MXLog.error("Unexpected item type (or the media provider is missing).")
return
}

let viewModel = TimelineMediaPreviewViewModel(previewItems: [item],
mediaProvider: mediaProvider,
userIndicatorController: userIndicatorController)
state.bindings.mediaPreviewViewModel = viewModel
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct MediaEventsTimelineScreen: View {
.pickerStyle(.segmented)
}
}
.timelineMediaQuickLook(viewModel: $context.mediaPreviewViewModel)
}

@ViewBuilder
Expand All @@ -39,13 +40,17 @@ struct MediaEventsTimelineScreen: View {
let columns = [GridItem(.adaptive(minimum: 80, maximum: 150), spacing: 1)]
LazyVGrid(columns: columns, alignment: .center, spacing: 1) {
ForEach(context.viewState.items) { item in
Color.clear // Let the image aspect fill in place
.aspectRatio(1, contentMode: .fill)
.overlay {
viewForTimelineItem(item)
}
.clipped()
.scaleEffect(.init(width: 1, height: -1))
Button {
context.send(viewAction: .tappedItem(item))
} label: {
Color.clear // Let the image aspect fill in place
.aspectRatio(1, contentMode: .fill)
.overlay {
viewForTimelineItem(item)
}
.clipped()
.scaleEffect(.init(width: 1, height: -1))
}
}
}

Expand Down Expand Up @@ -152,12 +157,14 @@ struct MediaEventsTimelineScreen_Previews: PreviewProvider, TestablePreview {
static let mediaViewModel = MediaEventsTimelineScreenViewModel(mediaTimelineViewModel: timelineViewModel,
filesTimelineViewModel: timelineViewModel,
mediaProvider: MediaProviderMock(configuration: .init()),
screenMode: .media)
screenMode: .media,
userIndicatorController: UserIndicatorControllerMock())

static let filesViewModel = MediaEventsTimelineScreenViewModel(mediaTimelineViewModel: timelineViewModel,
filesTimelineViewModel: timelineViewModel,
mediaProvider: MediaProviderMock(configuration: .init()),
screenMode: .files)
screenMode: .files,
userIndicatorController: UserIndicatorControllerMock())

static var previews: some View {
NavigationStack {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit e59a705

Please sign in to comment.