mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Detect the timeline start/end when swiping through media files. (#3714)
This commit is contained in:
@@ -35,8 +35,11 @@ class TimelineMediaPreviewViewModel: TimelineMediaPreviewViewModelType {
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.appMediator = appMediator
|
||||
|
||||
super.init(initialViewState: TimelineMediaPreviewViewState(dataSource: .init(itemViewStates: timelineViewModel.context.viewState.timelineState.itemViewStates,
|
||||
initialItem: context.item),
|
||||
let timelineState = timelineViewModel.context.viewState.timelineState
|
||||
|
||||
super.init(initialViewState: TimelineMediaPreviewViewState(dataSource: .init(itemViewStates: timelineState.itemViewStates,
|
||||
initialItem: context.item,
|
||||
paginationState: timelineState.paginationState),
|
||||
transitionNamespace: context.namespace),
|
||||
mediaProvider: mediaProvider)
|
||||
|
||||
@@ -57,14 +60,19 @@ class TimelineMediaPreviewViewModel: TimelineMediaPreviewViewModelType {
|
||||
self?.state.dataSource.updatePreviewItems(itemViewStates: itemViewStates)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
timelineViewModel.context.$viewState.map(\.timelineState.paginationState)
|
||||
.removeDuplicates()
|
||||
.weakAssign(to: \.state.dataSource.paginationState, on: self)
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
override func process(viewAction: TimelineMediaPreviewViewAction) {
|
||||
switch viewAction {
|
||||
case .updateCurrentItem(let item):
|
||||
Task { await updateCurrentItem(item) }
|
||||
case .showCurrentItemDetails:
|
||||
state.bindings.mediaDetailsItem = state.currentItem
|
||||
case .showItemDetails(let mediaItem):
|
||||
state.bindings.mediaDetailsItem = mediaItem
|
||||
case .menuAction(let action, let item):
|
||||
switch action {
|
||||
case .viewInRoomTimeline:
|
||||
@@ -78,28 +86,32 @@ class TimelineMediaPreviewViewModel: TimelineMediaPreviewViewModelType {
|
||||
}
|
||||
case .redactConfirmation(let item):
|
||||
redactItem(item)
|
||||
case .timelineEndReached:
|
||||
showTimelineEndIndicator()
|
||||
case .dismiss:
|
||||
actionsSubject.send(.dismiss)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateCurrentItem(_ previewItem: TimelineMediaPreviewItem?) async {
|
||||
previewItem?.downloadError = nil // Clear any existing error.
|
||||
private func updateCurrentItem(_ previewItem: TimelineMediaPreviewItem) async {
|
||||
if case let .media(item) = previewItem {
|
||||
item.downloadError = nil // Clear any existing error.
|
||||
}
|
||||
state.dataSource.updateCurrentItem(previewItem)
|
||||
rebuildCurrentItemActions()
|
||||
|
||||
if let previewItem {
|
||||
currentItemIDHandler?(previewItem.id)
|
||||
if case let .media(mediaItem) = previewItem {
|
||||
currentItemIDHandler?(mediaItem.id)
|
||||
|
||||
if previewItem.fileHandle == nil, let source = previewItem.mediaSource {
|
||||
switch await mediaProvider.loadFileFromSource(source, filename: previewItem.filename) {
|
||||
if mediaItem.fileHandle == nil, let source = mediaItem.mediaSource {
|
||||
switch await mediaProvider.loadFileFromSource(source, filename: mediaItem.filename) {
|
||||
case .success(let handle):
|
||||
previewItem.fileHandle = handle
|
||||
state.fileLoadedPublisher.send(previewItem.id)
|
||||
mediaItem.fileHandle = handle
|
||||
state.fileLoadedPublisher.send(mediaItem.id)
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed loading media: \(error)")
|
||||
context.objectWillChange.send() // Manually trigger the SwiftUI view update.
|
||||
previewItem.downloadError = error
|
||||
mediaItem.downloadError = error
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,8 +119,9 @@ class TimelineMediaPreviewViewModel: TimelineMediaPreviewViewModelType {
|
||||
|
||||
private func rebuildCurrentItemActions() {
|
||||
let timelineContext = timelineViewModel.context
|
||||
state.currentItemActions = if let currentItem = state.currentItem {
|
||||
TimelineItemMenuActionProvider(timelineItem: currentItem.timelineItem,
|
||||
state.currentItemActions = switch state.currentItem {
|
||||
case .media(let mediaItem):
|
||||
TimelineItemMenuActionProvider(timelineItem: mediaItem.timelineItem,
|
||||
canCurrentUserRedactSelf: timelineContext.viewState.canCurrentUserRedactSelf,
|
||||
canCurrentUserRedactOthers: timelineContext.viewState.canCurrentUserRedactOthers,
|
||||
canCurrentUserPin: timelineContext.viewState.canCurrentUserPin,
|
||||
@@ -118,13 +131,13 @@ class TimelineMediaPreviewViewModel: TimelineMediaPreviewViewModelType {
|
||||
timelineKind: timelineContext.viewState.timelineKind,
|
||||
emojiProvider: timelineContext.viewState.emojiProvider)
|
||||
.makeActions()
|
||||
} else {
|
||||
case .loading:
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
private func saveCurrentItem() async {
|
||||
guard let currentItem = state.currentItem, let fileURL = currentItem.fileHandle?.url else {
|
||||
guard case let .media(mediaItem) = state.currentItem, let fileURL = mediaItem.fileHandle?.url else {
|
||||
MXLog.error("Unable to save an item without a URL, the button shouldn't be visible.")
|
||||
return
|
||||
}
|
||||
@@ -133,7 +146,7 @@ class TimelineMediaPreviewViewModel: TimelineMediaPreviewViewModelType {
|
||||
state.bindings.mediaDetailsItem = nil
|
||||
|
||||
do {
|
||||
switch currentItem.timelineItem {
|
||||
switch mediaItem.timelineItem {
|
||||
case is AudioRoomTimelineItem, is FileRoomTimelineItem:
|
||||
state.bindings.fileToExport = .init(url: fileURL)
|
||||
return // Don't show the indicator.
|
||||
@@ -158,7 +171,7 @@ class TimelineMediaPreviewViewModel: TimelineMediaPreviewViewModelType {
|
||||
}
|
||||
}
|
||||
|
||||
private func redactItem(_ item: TimelineMediaPreviewItem) {
|
||||
private func redactItem(_ item: TimelineMediaPreviewItem.Media) {
|
||||
timelineViewModel.context.send(viewAction: .handleTimelineItemMenuAction(itemID: item.id, action: .redact))
|
||||
state.bindings.redactConfirmationItem = nil
|
||||
state.bindings.mediaDetailsItem = nil
|
||||
@@ -189,5 +202,11 @@ class TimelineMediaPreviewViewModel: TimelineMediaPreviewViewModelType {
|
||||
iconName: "xmark"))
|
||||
}
|
||||
|
||||
private func showTimelineEndIndicator() {
|
||||
userIndicatorController.submitIndicator(UserIndicator(id: statusIndicatorID,
|
||||
type: .toast,
|
||||
title: L10n.screenMediaDetailsNoMoreMediaToShow))
|
||||
}
|
||||
|
||||
private var statusIndicatorID: String { "\(Self.self)-Status" }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user