Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add file property to the ImageAttachmentPayload #3548

Merged
merged 5 commits into from
Jan 6, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,11 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## StreamChat
### ✅ Added
- Add `FilterKey.disabled` and `ChatChannel.isDisabled` [#3546](https://github.com/GetStream/stream-chat-swift/pull/3546)
- Add `ImageAttachmentPayload.file` for setting `file_size` and `mime_type` for image attachments [#3548](https://github.com/GetStream/stream-chat-swift/pull/3548)
### 🐞 Fixed
- Remove the main thread requirement from the `DataStore` [#3541](https://github.com/GetStream/stream-chat-swift/pull/3541)
### ⚡ Performance
- Improve performance of accessing database model properties [#3534](https://github.com/GetStream/stream-chat-swift/pull/3534)
- Improve performance of model conversions with large extra data [#3534](https://github.com/GetStream/stream-chat-swift/pull/3534)
### 🔄 Changed
- Deprecate `ImageAttachmentPayload.init(title:imageRemoteURL:originalWidth:originalHeight:extraData:)` in favor of `ImageAttachmentPayload.init(title:imageRemoteURL:file:originalWidth:originalHeight:extraData:)` [#3548](https://github.com/GetStream/stream-chat-swift/pull/3548)

# [4.69.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.69.0)
_December 18, 2024_
22 changes: 11 additions & 11 deletions DemoShare/DemoShareViewModel.swift
Original file line number Diff line number Diff line change
@@ -68,32 +68,32 @@ class DemoShareViewModel: ObservableObject, ChatChannelControllerDelegate {
channelController.delegate = self
loading = true
try await channelController.synchronize()
let remoteUrls = await withThrowingTaskGroup(of: URL.self) { taskGroup in
let attachmentPayloads = await withThrowingTaskGroup(of: AnyAttachmentPayload.self) { taskGroup in
for url in imageURLs {
taskGroup.addTask {
let file = try AttachmentFile(url: url)
let uploaded = try await channelController.uploadAttachment(
localFileURL: url,
type: .image
)
return uploaded.remoteURL
let attachment = ImageAttachmentPayload(
title: nil,
imageRemoteURL: uploaded.remoteURL,
file: file
)
return AnyAttachmentPayload(payload: attachment)
}
}

var results = [URL]()
var results = [AnyAttachmentPayload]()
while let result = await taskGroup.nextResult() {
if let url = try? result.get() {
results.append(url)
if let attachment = try? result.get() {
results.append(attachment)
}
}
return results
}

var attachmentPayloads = [AnyAttachmentPayload]()
for remoteUrl in remoteUrls {
let attachment = ImageAttachmentPayload(title: nil, imageRemoteURL: remoteUrl)
attachmentPayloads.append(AnyAttachmentPayload(payload: attachment))
}

messageId = try await channelController.createNewMessage(
text: text,
attachments: attachmentPayloads
Original file line number Diff line number Diff line change
@@ -117,6 +117,7 @@ public extension AnyAttachmentPayload {
payload = ImageAttachmentPayload(
title: localFileURL.lastPathComponent,
imageRemoteURL: localFileURL,
file: file,
originalWidth: localMetadata?.originalResolution?.width,
originalHeight: localMetadata?.originalResolution?.height,
extraData: extraData
Original file line number Diff line number Diff line change
@@ -24,6 +24,8 @@ public struct ImageAttachmentPayload: AttachmentPayload {
public var originalWidth: Double?
/// The original height of the image in pixels.
public var originalHeight: Double?
/// The image file size information.
public var file: AttachmentFile
/// An extra data.
public var extraData: [String: RawJSON]?

@@ -35,10 +37,38 @@ public struct ImageAttachmentPayload: AttachmentPayload {
.flatMap { try? JSONEncoder.stream.encode($0) }
.flatMap { try? JSONDecoder.stream.decode(T.self, from: $0) }
}

/// Creates `ImageAttachmentPayload` instance.
///
/// Use this initializer if the attachment is already uploaded and you have the remote URLs. Create the ``AttachmentFile`` type using the local file URL.
///
/// - Parameters:
/// - title: A title, usually the name of the image.
/// - imageRemoteURL: A link to the image.
/// - file: The image file size information.
/// - originalWidth: The original width of the image in pixels.
/// - originalHeight: The original height of the image in pixels.
/// - extraData: Custom data associated with the attachment.
public init(
title: String?,
imageRemoteURL: URL,
file: AttachmentFile,
originalWidth: Double? = nil,
originalHeight: Double? = nil,
extraData: [String: RawJSON]? = nil
) {
self.title = title
imageURL = imageRemoteURL
self.file = file
self.originalWidth = originalWidth
self.originalHeight = originalHeight
self.extraData = extraData
}

/// Creates `ImageAttachmentPayload` instance.
///
/// Use this initializer if the attachment is already uploaded and you have the remote URLs.
@available(*, deprecated, renamed: "init(title:imageRemoteURL:file:originalWidth:originalHeight:extraData:)")
public init(
title: String?,
imageRemoteURL: URL,
@@ -48,6 +78,8 @@ public struct ImageAttachmentPayload: AttachmentPayload {
) {
self.title = title
imageURL = imageRemoteURL
let fileType = AttachmentFileType(ext: imageRemoteURL.pathExtension)
file = AttachmentFile(type: fileType, size: 0, mimeType: nil)
self.originalWidth = originalWidth
self.originalHeight = originalHeight
self.extraData = extraData
@@ -78,6 +110,8 @@ public struct ImageAttachmentPayload: AttachmentPayload {
imageURL = imageRemoteURL
self.originalWidth = originalWidth
self.originalHeight = originalHeight
let fileType = AttachmentFileType(ext: imageRemoteURL.pathExtension)
file = AttachmentFile(type: fileType, size: 0, mimeType: nil)
self.extraData = extraData
}
}
@@ -108,6 +142,11 @@ extension ImageAttachmentPayload: Encodable {
values[AttachmentCodingKeys.originalWidth.rawValue] = .double(originalWidth)
values[AttachmentCodingKeys.originalHeight.rawValue] = .double(originalHeight)
}

if file.size > 0 {
values[AttachmentFile.CodingKeys.size.rawValue] = .number(Double(Int(file.size)))
values[AttachmentFile.CodingKeys.mimeType.rawValue] = file.mimeType.map { .string($0) }
}

try values.encode(to: encoder)
}
@@ -134,12 +173,14 @@ extension ImageAttachmentPayload: Decodable {
return try container.decodeIfPresent(String.self, forKey: .name)
}()

let file = try AttachmentFile(from: decoder)
let originalWidth = try container.decodeIfPresent(Double.self, forKey: .originalWidth)
let originalHeight = try container.decodeIfPresent(Double.self, forKey: .originalHeight)

self.init(
title: title?.trimmingCharacters(in: .whitespacesAndNewlines),
imageRemoteURL: imageURL,
file: file,
originalWidth: originalWidth,
originalHeight: originalHeight,
extraData: try Self.decodeExtraData(from: decoder)
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ extension ChatMessageImageAttachment {
payload: .init(
title: title,
imageRemoteURL: imageURL,
file: try! AttachmentFile(url: imageURL),
extraData: extraData
),
downloadingState: localDownloadState.map {
Original file line number Diff line number Diff line change
@@ -14,11 +14,13 @@ final class ImageAttachmentPayload_Tests: XCTestCase {
let thumbURL: URL = .unique()
let originalWidth: Double = 3200
let originalHeight: Double = 2600
let fileSize: Int64 = 1024

// Create JSON with the given values.
let json = """
{
"title": "\(title)",
"file_size": \(fileSize),
"image_url": "\(imageURL.absoluteString)",
"thumb_url": "\(thumbURL.absoluteString)",
"original_width": \(originalWidth),
@@ -32,6 +34,40 @@ final class ImageAttachmentPayload_Tests: XCTestCase {
// Assert values are decoded correctly.
XCTAssertEqual(payload.title, title)
XCTAssertEqual(payload.imageURL, imageURL)
XCTAssertEqual(payload.file.size, fileSize)
XCTAssertEqual(payload.file.mimeType, nil)
XCTAssertEqual(payload.originalWidth, originalWidth)
XCTAssertEqual(payload.originalHeight, originalHeight)
XCTAssertNil(payload.extraData)
}

func test_decodingDefaultValues_withoutFileSize() throws {
// Create attachment field values.
let title: String = .unique
let imageURL: URL = .unique()
let thumbURL: URL = .unique()
let originalWidth: Double = 3200
let originalHeight: Double = 2600

// Create JSON with the given values.
let json = """
{
"title": "\(title)",
"image_url": "\(imageURL.absoluteString)",
"thumb_url": "\(thumbURL.absoluteString)",
"original_width": \(originalWidth),
"original_height": \(originalHeight)
}
""".data(using: .utf8)!

// Decode attachment from JSON.
let payload = try JSONDecoder.stream.decode(ImageAttachmentPayload.self, from: json)

// Assert values are decoded correctly.
XCTAssertEqual(payload.title, title)
XCTAssertEqual(payload.imageURL, imageURL)
XCTAssertEqual(payload.file.size, 0)
XCTAssertEqual(payload.file.mimeType, nil)
XCTAssertEqual(payload.originalWidth, originalWidth)
XCTAssertEqual(payload.originalHeight, originalHeight)
XCTAssertNil(payload.extraData)
@@ -74,6 +110,7 @@ final class ImageAttachmentPayload_Tests: XCTestCase {
let payload = ImageAttachmentPayload(
title: "Image1.png",
imageRemoteURL: URL(string: "dummyURL")!,
file: AttachmentFile(type: .png, size: 75, mimeType: "image/png"),
originalWidth: 100,
originalHeight: 50,
extraData: ["isVerified": true]
@@ -83,6 +120,8 @@ final class ImageAttachmentPayload_Tests: XCTestCase {
let expectedJsonObject: [String: Any] = [
"title": "Image1.png",
"image_url": "dummyURL",
"file_size": 75,
"mime_type": "image/png",
"original_width": 100,
"original_height": 50,
"isVerified": true
4 changes: 2 additions & 2 deletions Tests/StreamChatTests/Workers/MessageUpdater_Tests.swift
Original file line number Diff line number Diff line change
@@ -1962,15 +1962,15 @@ final class MessageUpdater_Tests: XCTestCase {
let attachment = try setUpAttachment(
attachment: ChatMessageImageAttachment.mock(
id: .unique,
imageURL: URL(string: "http://asset.url/image.jpg")!,
imageURL: .localYodaImage,
localState: nil
)
)
apiClient.downloadFile_completion_result = .success(())
let result = try waitFor { messageUpdater.downloadAttachment(attachment, completion: $0) }
let value = try XCTUnwrap(result.value)
XCTAssertEqual("yoda.jpg", apiClient.downloadFile_localURL?.lastPathComponent)
XCTAssertEqual("http://asset.url/image.jpg", apiClient.downloadFile_remoteURL?.absoluteString)
XCTAssertEqual(URL.localYodaImage, apiClient.downloadFile_remoteURL)
XCTAssertEqual(attachment.id, value.id)
XCTAssertEqual(LocalAttachmentDownloadState.downloaded, value.downloadingState?.state)
XCTAssertEqual(URL.streamAttachmentLocalStorageURL(forRelativePath: value.relativeStoragePath), value.downloadingState?.localFileURL)