fix for a crash when trying to download a media

This commit is contained in:
Mauro Romito
2026-07-28 16:37:33 +02:00
committed by Mauro
parent 7ea9aeb174
commit 30bc4a06f2
2 changed files with 77 additions and 69 deletions
@@ -21,7 +21,8 @@ protocol PhotoLibraryManagerProtocol {
struct PhotoLibraryManager: PhotoLibraryManagerProtocol { struct PhotoLibraryManager: PhotoLibraryManagerProtocol {
func addResource(_ type: PHAssetResourceType, at url: URL) async -> Result<Void, PhotoLibraryManagerError> { func addResource(_ type: PHAssetResourceType, at url: URL) async -> Result<Void, PhotoLibraryManagerError> {
do { do {
try await PHPhotoLibrary.shared().performChanges { // @Sendable as PhotoKit runs the block on its own queue, so it must not inherit MainActor isolation.
try await PHPhotoLibrary.shared().performChanges { @Sendable in
let request = PHAssetCreationRequest.forAsset() let request = PHAssetCreationRequest.forAsset()
let options = PHAssetResourceCreationOptions() let options = PHAssetResourceCreationOptions()
request.addResource(with: type, fileURL: url, options: options) request.addResource(with: type, fileURL: url, options: options)
@@ -216,13 +216,6 @@ enum TimelineMediaPreviewItem: Equatable {
} }
} }
var galleryItem: GalleryItem? {
switch content {
case .timelineItem: nil
case .galleryItem(_, let item): item
}
}
var fileHandle: MediaFileHandleProxy? { var fileHandle: MediaFileHandleProxy? {
didSet { updatePreviewItemValues() } didSet { updatePreviewItemValues() }
} }
@@ -299,55 +292,63 @@ enum TimelineMediaPreviewItem: Equatable {
enum Kind { case image, video, file } enum Kind { case image, video, file }
var kind: Kind { var kind: Kind {
if let galleryItem { switch content {
switch galleryItem { case .galleryItem(_, let item):
case .image: return .image switch item {
case .video: return .video case .image: .image
case .audio, .file, .other: return .file case .video: .video
case .audio, .file, .other: .file
}
case .timelineItem(let timelineItem):
switch timelineItem {
case is ImageRoomTimelineItem: .image
case is VideoRoomTimelineItem: .video
default: .file
} }
}
return switch timelineItem {
case is ImageRoomTimelineItem: .image
case is VideoRoomTimelineItem: .video
default: .file
} }
} }
var mediaSource: MediaSourceProxy? { var mediaSource: MediaSourceProxy? {
if let galleryItem { switch content {
return galleryItem.mediaSource case .galleryItem(_, let item):
} item.mediaSource
return switch timelineItem { case .timelineItem(let timelineItem):
case let audioItem as AudioRoomTimelineItem: audioItem.content.source switch timelineItem {
case let fileItem as FileRoomTimelineItem: fileItem.content.source case let audioItem as AudioRoomTimelineItem: audioItem.content.source
case let imageItem as ImageRoomTimelineItem: imageItem.content.imageInfo.source case let fileItem as FileRoomTimelineItem: fileItem.content.source
case let videoItem as VideoRoomTimelineItem: videoItem.content.videoInfo.source case let imageItem as ImageRoomTimelineItem: imageItem.content.imageInfo.source
default: nil case let videoItem as VideoRoomTimelineItem: videoItem.content.videoInfo.source
default: nil
}
} }
} }
var thumbnailMediaSource: MediaSourceProxy? { var thumbnailMediaSource: MediaSourceProxy? {
if let galleryItem { switch content {
return galleryItem.thumbnailSource case .galleryItem(_, let item):
} item.thumbnailSource
return switch timelineItem { case .timelineItem(let timelineItem):
case let fileItem as FileRoomTimelineItem: fileItem.content.thumbnailSource switch timelineItem {
case let imageItem as ImageRoomTimelineItem: imageItem.content.thumbnailInfo?.source case let fileItem as FileRoomTimelineItem: fileItem.content.thumbnailSource
case let videoItem as VideoRoomTimelineItem: videoItem.content.thumbnailInfo?.source case let imageItem as ImageRoomTimelineItem: imageItem.content.thumbnailInfo?.source
default: nil case let videoItem as VideoRoomTimelineItem: videoItem.content.thumbnailInfo?.source
default: nil
}
} }
} }
var filename: String? { var filename: String? {
if let galleryItem { switch content {
return galleryItem.filename case .galleryItem(_, let item):
} item.filename
return switch timelineItem { case .timelineItem(let timelineItem):
case let audioItem as AudioRoomTimelineItem: audioItem.content.filename switch timelineItem {
case let fileItem as FileRoomTimelineItem: fileItem.content.filename case let audioItem as AudioRoomTimelineItem: audioItem.content.filename
case let imageItem as ImageRoomTimelineItem: imageItem.content.filename case let fileItem as FileRoomTimelineItem: fileItem.content.filename
case let videoItem as VideoRoomTimelineItem: videoItem.content.filename case let imageItem as ImageRoomTimelineItem: imageItem.content.filename
default: nil case let videoItem as VideoRoomTimelineItem: videoItem.content.filename
default: nil
}
} }
} }
@@ -356,15 +357,17 @@ enum TimelineMediaPreviewItem: Equatable {
} }
private var expectedFileSize: UInt? { private var expectedFileSize: UInt? {
if let galleryItem { switch content {
return galleryItem.fileSize case .galleryItem(_, let item):
} item.fileSize
return switch timelineItem { case .timelineItem(let timelineItem):
case let audioItem as AudioRoomTimelineItem: audioItem.content.fileSize switch timelineItem {
case let fileItem as FileRoomTimelineItem: fileItem.content.fileSize case let audioItem as AudioRoomTimelineItem: audioItem.content.fileSize
case let imageItem as ImageRoomTimelineItem: imageItem.content.imageInfo.fileSize case let fileItem as FileRoomTimelineItem: fileItem.content.fileSize
case let videoItem as VideoRoomTimelineItem: videoItem.content.videoInfo.fileSize case let imageItem as ImageRoomTimelineItem: imageItem.content.imageInfo.fileSize
default: nil case let videoItem as VideoRoomTimelineItem: videoItem.content.videoInfo.fileSize
default: nil
}
} }
} }
@@ -382,26 +385,30 @@ enum TimelineMediaPreviewItem: Equatable {
} }
var contentType: String? { var contentType: String? {
if let galleryItem { switch content {
return galleryItem.contentType?.localizedDescription case .galleryItem(_, let item):
} item.contentType?.localizedDescription
return switch timelineItem { case .timelineItem(let timelineItem):
case let audioItem as AudioRoomTimelineItem: audioItem.content.contentType?.localizedDescription switch timelineItem {
case let fileItem as FileRoomTimelineItem: fileItem.content.contentType?.localizedDescription case let audioItem as AudioRoomTimelineItem: audioItem.content.contentType?.localizedDescription
case let imageItem as ImageRoomTimelineItem: imageItem.content.contentType?.localizedDescription case let fileItem as FileRoomTimelineItem: fileItem.content.contentType?.localizedDescription
case let videoItem as VideoRoomTimelineItem: videoItem.content.contentType?.localizedDescription case let imageItem as ImageRoomTimelineItem: imageItem.content.contentType?.localizedDescription
default: nil case let videoItem as VideoRoomTimelineItem: videoItem.content.contentType?.localizedDescription
default: nil
}
} }
} }
var blurhash: String? { var blurhash: String? {
if let galleryItem { switch content {
return galleryItem.blurhash case .galleryItem(_, let item):
} item.blurhash
return switch timelineItem { case .timelineItem(let timelineItem):
case let imageItem as ImageRoomTimelineItem: imageItem.content.blurhash switch timelineItem {
case let videoItem as VideoRoomTimelineItem: videoItem.content.blurhash case let imageItem as ImageRoomTimelineItem: imageItem.content.blurhash
default: nil case let videoItem as VideoRoomTimelineItem: videoItem.content.blurhash
default: nil
}
} }
} }
} }