Skip to content

Commit 4bb47e1

Browse files
authored
feat(llc)!: add standalone file/image upload/remove methods (#2396)
1 parent 5a02491 commit 4bb47e1

File tree

7 files changed

+437
-2
lines changed

7 files changed

+437
-2
lines changed

migrations/v10-migration.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This guide includes breaking changes grouped by release phase:
1010

1111
### 🚧 v10.0.0-beta.7
1212

13+
- [AttachmentFileUploader](#-attachmentfileuploader)
1314
- [MessageState](#-messagestate)
1415

1516
### 🚧 v10.0.0-beta.4
@@ -34,6 +35,111 @@ This guide includes breaking changes grouped by release phase:
3435

3536
## 🧪 Migration for v10.0.0-beta.7
3637

38+
### 🛠 AttachmentFileUploader
39+
40+
#### Key Changes:
41+
42+
- `AttachmentFileUploader` interface now includes four new abstract methods: `uploadImage`, `uploadFile`, `removeImage`, and `removeFile`.
43+
- Custom implementations must implement these new standalone upload/removal methods.
44+
45+
#### Migration Steps:
46+
47+
**Before:**
48+
```dart
49+
class CustomAttachmentFileUploader implements AttachmentFileUploader {
50+
// Only needed to implement sendImage, sendFile, deleteImage, deleteFile
51+
52+
@override
53+
Future<SendImageResponse> sendImage(/* ... */) async {
54+
// Implementation
55+
}
56+
57+
@override
58+
Future<SendFileResponse> sendFile(/* ... */) async {
59+
// Implementation
60+
}
61+
62+
@override
63+
Future<EmptyResponse> deleteImage(/* ... */) async {
64+
// Implementation
65+
}
66+
67+
@override
68+
Future<EmptyResponse> deleteFile(/* ... */) async {
69+
// Implementation
70+
}
71+
}
72+
```
73+
74+
**After:**
75+
```dart
76+
class CustomAttachmentFileUploader implements AttachmentFileUploader {
77+
// Must now implement all 8 methods including the new standalone ones
78+
79+
@override
80+
Future<SendImageResponse> sendImage(/* ... */) async {
81+
// Implementation
82+
}
83+
84+
@override
85+
Future<SendFileResponse> sendFile(/* ... */) async {
86+
// Implementation
87+
}
88+
89+
@override
90+
Future<EmptyResponse> deleteImage(/* ... */) async {
91+
// Implementation
92+
}
93+
94+
@override
95+
Future<EmptyResponse> deleteFile(/* ... */) async {
96+
// Implementation
97+
}
98+
99+
// New required methods
100+
@override
101+
Future<UploadImageResponse> uploadImage(
102+
AttachmentFile image, {
103+
ProgressCallback? onSendProgress,
104+
CancelToken? cancelToken,
105+
}) async {
106+
// Implementation for standalone image upload
107+
}
108+
109+
@override
110+
Future<UploadFileResponse> uploadFile(
111+
AttachmentFile file, {
112+
ProgressCallback? onSendProgress,
113+
CancelToken? cancelToken,
114+
}) async {
115+
// Implementation for standalone file upload
116+
}
117+
118+
@override
119+
Future<EmptyResponse> removeImage(
120+
String url, {
121+
CancelToken? cancelToken,
122+
}) async {
123+
// Implementation for standalone image removal
124+
}
125+
126+
@override
127+
Future<EmptyResponse> removeFile(
128+
String url, {
129+
CancelToken? cancelToken,
130+
}) async {
131+
// Implementation for standalone file removal
132+
}
133+
}
134+
```
135+
136+
> ⚠️ **Important:**
137+
> - Custom `AttachmentFileUploader` implementations must now implement four additional methods
138+
> - The new methods support standalone uploads/removals without requiring channel context
139+
> - `UploadImageResponse` and `UploadFileResponse` are aliases for `SendAttachmentResponse`
140+
141+
---
142+
37143
### 🛠 MessageState
38144

39145
#### Key Changes:
@@ -505,6 +611,7 @@ StreamMessageWidget(
505611
## 🎉 You're Ready to Migrate!
506612

507613
### For v10.0.0-beta.7:
614+
- ✅ Update custom `AttachmentFileUploader` implementations to include the four new abstract methods: `uploadImage`, `uploadFile`, `removeImage`, and `removeFile`
508615
- ✅ Update `MessageState` factory constructors to use `MessageDeleteScope` parameter
509616
- ✅ Update pattern matching callbacks to handle `MessageDeleteScope` instead of `bool hard`
510617
- ✅ Leverage new delete-for-me functionality with `deleteMessageForMe` methods

packages/stream_chat/CHANGELOG.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
- **Changed `MessageState` factory constructors**: The `deleting`, `deleted`, and `deletingFailed`
66
factory constructors now accept a `MessageDeleteScope` parameter instead of `bool hard`.
77
Pattern matching callbacks also receive `MessageDeleteScope scope` instead of `bool hard`.
8+
- **Added new abstract methods to `AttachmentFileUploader`**: The `AttachmentFileUploader` interface
9+
now includes four new abstract methods (`uploadImage`, `uploadFile`, `removeImage`, `removeFile`).
10+
Custom implementations must implement these methods.
11+
12+
For more details, please refer to the [migration guide](../../migrations/v10-migration.md).
813

914
✅ Added
1015

@@ -14,8 +19,11 @@
1419
- `MessageDeleteScope` - New sealed class to represent deletion scope
1520
- `MessageState.deletingForMe`, `MessageState.deletedForMe`, `MessageState.deletingForMeFailed` states
1621
- `Message.deletedOnlyForMe`, `Event.deletedForMe`, `Member.deletedMessages` model fields
17-
18-
For more details, please refer to the [migration guide](../../migrations/v10-migration.md).
22+
- Added standalone file and image upload/removal methods for CDN operations:
23+
- `StreamChatClient.uploadImage()` - Upload an image to the Stream CDN
24+
- `StreamChatClient.uploadFile()` - Upload a file to the Stream CDN
25+
- `StreamChatClient.removeImage()` - Remove an image from the Stream CDN
26+
- `StreamChatClient.removeFile()` - Remove a file from the Stream CDN
1927

2028
## 10.0.0-beta.6
2129

packages/stream_chat/lib/src/client/client.dart

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,68 @@ class StreamChatClient {
921921
extraData: extraData,
922922
);
923923

924+
/// Upload an image to the Stream CDN
925+
///
926+
/// Upload progress can be tracked using [onProgress], and the operation can
927+
/// be cancelled using [cancelToken].
928+
///
929+
/// Returns a [UploadImageResponse] once uploaded successfully.
930+
Future<UploadImageResponse> uploadImage(
931+
AttachmentFile image, {
932+
ProgressCallback? onUploadProgress,
933+
CancelToken? cancelToken,
934+
}) =>
935+
_chatApi.fileUploader.uploadImage(
936+
image,
937+
onSendProgress: onUploadProgress,
938+
cancelToken: cancelToken,
939+
);
940+
941+
/// Upload a file to the Stream CDN
942+
///
943+
/// Upload progress can be tracked using [onProgress], and the operation can
944+
/// be cancelled using [cancelToken].
945+
///
946+
/// Returns a [UploadFileResponse] once uploaded successfully.
947+
Future<UploadFileResponse> uploadFile(
948+
AttachmentFile file, {
949+
ProgressCallback? onUploadProgress,
950+
CancelToken? cancelToken,
951+
}) =>
952+
_chatApi.fileUploader.uploadFile(
953+
file,
954+
onSendProgress: onUploadProgress,
955+
cancelToken: cancelToken,
956+
);
957+
958+
/// Remove an image from the Stream CDN using its [url].
959+
///
960+
/// The operation can be cancelled using [cancelToken] if needed.
961+
///
962+
/// Returns an [EmptyResponse] once removed successfully.
963+
Future<EmptyResponse> removeImage(
964+
String url, {
965+
CancelToken? cancelToken,
966+
}) =>
967+
_chatApi.fileUploader.removeImage(
968+
url,
969+
cancelToken: cancelToken,
970+
);
971+
972+
/// Remove a file from the Stream CDN using its [url].
973+
///
974+
/// The operation can be cancelled using [cancelToken] if needed.
975+
///
976+
/// Returns an [EmptyResponse] once removed successfully.
977+
Future<EmptyResponse> removeFile(
978+
String url, {
979+
CancelToken? cancelToken,
980+
}) =>
981+
_chatApi.fileUploader.removeFile(
982+
url,
983+
cancelToken: cancelToken,
984+
);
985+
924986
/// Replaces the [channelId] of type [ChannelType] data with [data].
925987
///
926988
/// Use [updateChannelPartial] for a partial update.

packages/stream_chat/lib/src/core/api/attachment_file_uploader.dart

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,54 @@ abstract class AttachmentFileUploader {
6161
CancelToken? cancelToken,
6262
Map<String, Object?>? extraData,
6363
});
64+
65+
// region Standalone upload methods
66+
67+
/// Uploads an image file to the CDN.
68+
///
69+
/// Upload progress can be tracked using [onProgress], and the operation can
70+
/// be cancelled using [cancelToken].
71+
///
72+
/// Returns a [UploadImageResponse] once uploaded successfully.
73+
Future<UploadImageResponse> uploadImage(
74+
AttachmentFile image, {
75+
ProgressCallback? onSendProgress,
76+
CancelToken? cancelToken,
77+
});
78+
79+
/// Uploads a file to the CDN.
80+
///
81+
/// Upload progress can be tracked using [onProgress], and the operation can
82+
/// be cancelled using [cancelToken].
83+
///
84+
/// Returns a [UploadFileResponse] once uploaded successfully.
85+
Future<UploadFileResponse> uploadFile(
86+
AttachmentFile file, {
87+
ProgressCallback? onSendProgress,
88+
CancelToken? cancelToken,
89+
});
90+
91+
/// Removes an image from the CDN using its [url].
92+
///
93+
/// The operation can be cancelled using [cancelToken] if needed.
94+
///
95+
/// Returns a [EmptyResponse] once removed successfully.
96+
Future<EmptyResponse> removeImage(
97+
String url, {
98+
CancelToken? cancelToken,
99+
});
100+
101+
/// Removes a file from the CDN using its [url].
102+
///
103+
/// The operation can be cancelled using [cancelToken] if needed.
104+
///
105+
/// Returns a [EmptyResponse] once removed successfully.
106+
Future<EmptyResponse> removeFile(
107+
String url, {
108+
CancelToken? cancelToken,
109+
});
110+
111+
// endregion
64112
}
65113

66114
/// Stream's default implementation of [AttachmentFileUploader]
@@ -139,4 +187,62 @@ class StreamAttachmentFileUploader implements AttachmentFileUploader {
139187
);
140188
return EmptyResponse.fromJson(response.data);
141189
}
190+
191+
@override
192+
Future<UploadImageResponse> uploadImage(
193+
AttachmentFile image, {
194+
ProgressCallback? onSendProgress,
195+
CancelToken? cancelToken,
196+
}) async {
197+
final multiPartFile = await image.toMultipartFile();
198+
final response = await _client.postFile(
199+
'/uploads/image',
200+
multiPartFile,
201+
onSendProgress: onSendProgress,
202+
cancelToken: cancelToken,
203+
);
204+
return UploadImageResponse.fromJson(response.data);
205+
}
206+
207+
@override
208+
Future<UploadFileResponse> uploadFile(
209+
AttachmentFile file, {
210+
ProgressCallback? onSendProgress,
211+
CancelToken? cancelToken,
212+
}) async {
213+
final multiPartFile = await file.toMultipartFile();
214+
final response = await _client.postFile(
215+
'/uploads/file',
216+
multiPartFile,
217+
onSendProgress: onSendProgress,
218+
cancelToken: cancelToken,
219+
);
220+
return UploadFileResponse.fromJson(response.data);
221+
}
222+
223+
@override
224+
Future<EmptyResponse> removeImage(
225+
String url, {
226+
CancelToken? cancelToken,
227+
}) async {
228+
final response = await _client.delete(
229+
'/uploads/image',
230+
queryParameters: {'url': url},
231+
cancelToken: cancelToken,
232+
);
233+
return EmptyResponse.fromJson(response.data);
234+
}
235+
236+
@override
237+
Future<EmptyResponse> removeFile(
238+
String url, {
239+
CancelToken? cancelToken,
240+
}) async {
241+
final response = await _client.delete(
242+
'/uploads/file',
243+
queryParameters: {'url': url},
244+
cancelToken: cancelToken,
245+
);
246+
return EmptyResponse.fromJson(response.data);
247+
}
142248
}

packages/stream_chat/lib/src/core/api/responses.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,12 @@ class SendFileResponse extends SendAttachmentResponse {
201201
/// Model response for [Channel.sendImage] api call
202202
typedef SendImageResponse = SendAttachmentResponse;
203203

204+
/// Model response for [StreamChatClient.uploadImage] api call
205+
typedef UploadImageResponse = SendAttachmentResponse;
206+
207+
/// Model response for [StreamChatClient.uploadFile] api call
208+
typedef UploadFileResponse = SendAttachmentResponse;
209+
204210
/// Model response for [Channel.sendReaction] api call
205211
@JsonSerializable(createToJson: false)
206212
class SendReactionResponse extends MessageResponse {

0 commit comments

Comments
 (0)