♻️ Refactored file uploading
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- Alamofire (5.10.2)
|
- Alamofire (5.10.2)
|
||||||
- app_links (6.4.1):
|
|
||||||
- Flutter
|
|
||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- croppy (0.0.1):
|
- croppy (0.0.1):
|
||||||
@@ -52,18 +50,18 @@ PODS:
|
|||||||
- Firebase/Messaging (12.4.0):
|
- Firebase/Messaging (12.4.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseMessaging (~> 12.4.0)
|
- FirebaseMessaging (~> 12.4.0)
|
||||||
- firebase_analytics (12.0.3):
|
- firebase_analytics (12.0.4):
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- FirebaseAnalytics (= 12.4.0)
|
- FirebaseAnalytics (= 12.4.0)
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_core (4.2.0):
|
- firebase_core (4.2.1):
|
||||||
- Firebase/CoreOnly (= 12.4.0)
|
- Firebase/CoreOnly (= 12.4.0)
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_crashlytics (5.0.3):
|
- firebase_crashlytics (5.0.4):
|
||||||
- Firebase/Crashlytics (= 12.4.0)
|
- Firebase/Crashlytics (= 12.4.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_messaging (16.0.3):
|
- firebase_messaging (16.0.4):
|
||||||
- Firebase/Messaging (= 12.4.0)
|
- Firebase/Messaging (= 12.4.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
@@ -265,6 +263,8 @@ PODS:
|
|||||||
- PromisesObjC (2.4.0)
|
- PromisesObjC (2.4.0)
|
||||||
- PromisesSwift (2.4.0):
|
- PromisesSwift (2.4.0):
|
||||||
- PromisesObjC (= 2.4.0)
|
- PromisesObjC (= 2.4.0)
|
||||||
|
- protocol_handler_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
- receive_sharing_intent (1.8.1):
|
- receive_sharing_intent (1.8.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- record_ios (1.1.0):
|
- record_ios (1.1.0):
|
||||||
@@ -323,7 +323,6 @@ PODS:
|
|||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- Alamofire
|
- Alamofire
|
||||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
|
||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||||
- croppy (from `.symlinks/plugins/croppy/ios`)
|
- croppy (from `.symlinks/plugins/croppy/ios`)
|
||||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
@@ -358,6 +357,7 @@ DEPENDENCIES:
|
|||||||
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
|
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
|
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
|
||||||
|
- protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`)
|
||||||
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
|
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
|
||||||
- record_ios (from `.symlinks/plugins/record_ios/ios`)
|
- record_ios (from `.symlinks/plugins/record_ios/ios`)
|
||||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
@@ -404,8 +404,6 @@ SPEC REPOS:
|
|||||||
- WebRTC-SDK
|
- WebRTC-SDK
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
app_links:
|
|
||||||
:path: ".symlinks/plugins/app_links/ios"
|
|
||||||
connectivity_plus:
|
connectivity_plus:
|
||||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||||
croppy:
|
croppy:
|
||||||
@@ -470,6 +468,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
pointer_interceptor_ios:
|
pointer_interceptor_ios:
|
||||||
:path: ".symlinks/plugins/pointer_interceptor_ios/ios"
|
:path: ".symlinks/plugins/pointer_interceptor_ios/ios"
|
||||||
|
protocol_handler_ios:
|
||||||
|
:path: ".symlinks/plugins/protocol_handler_ios/ios"
|
||||||
receive_sharing_intent:
|
receive_sharing_intent:
|
||||||
:path: ".symlinks/plugins/receive_sharing_intent/ios"
|
:path: ".symlinks/plugins/receive_sharing_intent/ios"
|
||||||
record_ios:
|
record_ios:
|
||||||
@@ -497,7 +497,6 @@ EXTERNAL SOURCES:
|
|||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
|
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
|
||||||
app_links: 3dbc685f76b1693c66a6d9dd1e9ab6f73d97dc0a
|
|
||||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||||
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
||||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||||
@@ -506,10 +505,10 @@ SPEC CHECKSUMS:
|
|||||||
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||||
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
||||||
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
|
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
|
||||||
firebase_analytics: 1d024068b1d4707d5ba7a42a12976ddf3316d835
|
firebase_analytics: 67fbdd9f3c04e55048024f3da21cfc36f05e56cf
|
||||||
firebase_core: 744984dbbed8b3036abf34f0b98d80f130a7e464
|
firebase_core: f1aafb21c14f497e5498f7ffc4dc63cbb52b2594
|
||||||
firebase_crashlytics: f3a9a4338ab99b67042f64e9e22e1bf349cb44ed
|
firebase_crashlytics: 83c7467d7534975a4d779af43bd226d0a4616464
|
||||||
firebase_messaging: 82c70650c426a0a14873e1acdb9ec2b443c4e8b4
|
firebase_messaging: c17a29984eafce4b2997fe078bb0a9e0b06f5dde
|
||||||
FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f
|
FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f
|
||||||
FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3
|
FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3
|
||||||
FirebaseCoreExtension: 7e1f7118ee970e001a8013719fb90950ee5e0018
|
FirebaseCoreExtension: 7e1f7118ee970e001a8013719fb90950ee5e0018
|
||||||
@@ -553,6 +552,7 @@ SPEC CHECKSUMS:
|
|||||||
pointer_interceptor_ios: da06a662d5bfd329602b45b2ab41bc0fb5fdb0f0
|
pointer_interceptor_ios: da06a662d5bfd329602b45b2ab41bc0fb5fdb0f0
|
||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
||||||
|
protocol_handler_ios: 59f23ee71f3ec602d67902ca7f669a80957888d5
|
||||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||||
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
||||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import "dart:async";
|
|||||||
import "dart:math" as math;
|
import "dart:math" as math;
|
||||||
import "package:easy_localization/easy_localization.dart";
|
import "package:easy_localization/easy_localization.dart";
|
||||||
import "package:file_picker/file_picker.dart";
|
import "package:file_picker/file_picker.dart";
|
||||||
|
import "package:image_picker/image_picker.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:go_router/go_router.dart";
|
import "package:go_router/go_router.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
@@ -181,16 +182,13 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
}, [scrollController]);
|
}, [scrollController]);
|
||||||
|
|
||||||
Future<void> pickPhotoMedia() async {
|
Future<void> pickPhotoMedia() async {
|
||||||
final result = await FilePicker.platform.pickFiles(
|
final ImagePicker picker = ImagePicker();
|
||||||
type: FileType.image,
|
final List<XFile> results = await picker.pickMultiImage();
|
||||||
allowMultiple: true,
|
if (results.isEmpty) return;
|
||||||
allowCompression: false,
|
|
||||||
);
|
|
||||||
if (result == null || result.count == 0) return;
|
|
||||||
attachments.value = [
|
attachments.value = [
|
||||||
...attachments.value,
|
...attachments.value,
|
||||||
...result.files.map(
|
...results.map(
|
||||||
(e) => UniversalFile(data: e.xFile, type: UniversalFileType.image),
|
(xfile) => UniversalFile(data: xfile, type: UniversalFileType.image),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:convert/convert.dart';
|
||||||
import 'package:cross_file/cross_file.dart';
|
import 'package:cross_file/cross_file.dart';
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
@@ -21,9 +22,51 @@ class FileUploader {
|
|||||||
return digest.toString();
|
return digest.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the MD5 hash from a stream.
|
||||||
|
Future<String> _calculateFileHashFromStream(Stream<List<int>> stream) async {
|
||||||
|
final accumulator = AccumulatorSink<Digest>();
|
||||||
|
final converter = md5.startChunkedConversion(accumulator);
|
||||||
|
await for (final chunk in stream) {
|
||||||
|
converter.add(chunk);
|
||||||
|
}
|
||||||
|
converter.close();
|
||||||
|
final digest = accumulator.events.single;
|
||||||
|
return digest.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the next chunk from a stream subscription.
|
||||||
|
Future<Uint8List> _readNextChunk(
|
||||||
|
StreamSubscription<List<int>> subscription,
|
||||||
|
int size,
|
||||||
|
) async {
|
||||||
|
final completer = Completer<Uint8List>();
|
||||||
|
final buffer = <int>[];
|
||||||
|
int remaining = size;
|
||||||
|
|
||||||
|
void onData(List<int> data) {
|
||||||
|
buffer.addAll(data);
|
||||||
|
remaining -= data.length;
|
||||||
|
if (remaining <= 0) {
|
||||||
|
subscription.pause();
|
||||||
|
completer.complete(Uint8List.fromList(buffer.sublist(0, size)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDone() {
|
||||||
|
if (!completer.isCompleted) {
|
||||||
|
completer.complete(Uint8List.fromList(buffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription.onData(onData);
|
||||||
|
subscription.onDone(onDone);
|
||||||
|
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an upload task for the given file.
|
/// Creates an upload task for the given file.
|
||||||
Future<Map<String, dynamic>> createUploadTask({
|
Future<Map<String, dynamic>> createUploadTask({
|
||||||
required Uint8List bytes,
|
required dynamic fileData,
|
||||||
required String fileName,
|
required String fileName,
|
||||||
required String contentType,
|
required String contentType,
|
||||||
String? poolId,
|
String? poolId,
|
||||||
@@ -32,8 +75,17 @@ class FileUploader {
|
|||||||
String? expiredAt,
|
String? expiredAt,
|
||||||
int? chunkSize,
|
int? chunkSize,
|
||||||
}) async {
|
}) async {
|
||||||
final hash = _calculateFileHash(bytes);
|
String hash;
|
||||||
final fileSize = bytes.length;
|
int fileSize;
|
||||||
|
if (fileData is XFile) {
|
||||||
|
fileSize = await fileData.length();
|
||||||
|
hash = await _calculateFileHashFromStream(fileData.openRead());
|
||||||
|
} else if (fileData is Uint8List) {
|
||||||
|
hash = _calculateFileHash(fileData);
|
||||||
|
fileSize = fileData.length;
|
||||||
|
} else {
|
||||||
|
throw ArgumentError('Invalid fileData type');
|
||||||
|
}
|
||||||
|
|
||||||
final response = await _client.post(
|
final response = await _client.post(
|
||||||
'/drive/files/upload/create',
|
'/drive/files/upload/create',
|
||||||
@@ -81,7 +133,7 @@ class FileUploader {
|
|||||||
|
|
||||||
/// Uploads a file in chunks using the multi-part API.
|
/// Uploads a file in chunks using the multi-part API.
|
||||||
Future<SnCloudFile> uploadFile({
|
Future<SnCloudFile> uploadFile({
|
||||||
required Uint8List bytes,
|
required dynamic fileData,
|
||||||
required String fileName,
|
required String fileName,
|
||||||
required String contentType,
|
required String contentType,
|
||||||
String? poolId,
|
String? poolId,
|
||||||
@@ -92,7 +144,7 @@ class FileUploader {
|
|||||||
}) async {
|
}) async {
|
||||||
// Step 1: Create upload task
|
// Step 1: Create upload task
|
||||||
final createResponse = await createUploadTask(
|
final createResponse = await createUploadTask(
|
||||||
bytes: bytes,
|
fileData: fileData,
|
||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
poolId: poolId,
|
poolId: poolId,
|
||||||
@@ -112,23 +164,32 @@ class FileUploader {
|
|||||||
final chunksCount = createResponse['chunks_count'] as int;
|
final chunksCount = createResponse['chunks_count'] as int;
|
||||||
|
|
||||||
// Step 2: Upload chunks
|
// Step 2: Upload chunks
|
||||||
final chunks = <Uint8List>[];
|
if (fileData is XFile) {
|
||||||
for (int i = 0; i < bytes.length; i += chunkSize) {
|
// Use stream for XFile
|
||||||
final end = i + chunkSize > bytes.length ? bytes.length : i + chunkSize;
|
final subscription = fileData.openRead().listen(null);
|
||||||
chunks.add(Uint8List.fromList(bytes.sublist(i, end)));
|
subscription.pause();
|
||||||
|
for (int i = 0; i < chunksCount; i++) {
|
||||||
|
subscription.resume();
|
||||||
|
final chunkData = await _readNextChunk(subscription, chunkSize);
|
||||||
|
await uploadChunk(taskId: taskId, chunkIndex: i, chunkData: chunkData);
|
||||||
}
|
}
|
||||||
|
subscription.cancel();
|
||||||
// Ensure we have the correct number of chunks
|
} else if (fileData is Uint8List) {
|
||||||
if (chunks.length != chunksCount) {
|
// Use old way for Uint8List
|
||||||
throw Exception(
|
final chunks = <Uint8List>[];
|
||||||
'Chunk count mismatch: expected $chunksCount, got ${chunks.length}',
|
for (int i = 0; i < fileData.length; i += chunkSize) {
|
||||||
);
|
final end =
|
||||||
|
i + chunkSize > fileData.length ? fileData.length : i + chunkSize;
|
||||||
|
chunks.add(Uint8List.fromList(fileData.sublist(i, end)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload each chunk
|
// Upload each chunk
|
||||||
for (int i = 0; i < chunks.length; i++) {
|
for (int i = 0; i < chunks.length; i++) {
|
||||||
await uploadChunk(taskId: taskId, chunkIndex: i, chunkData: chunks[i]);
|
await uploadChunk(taskId: taskId, chunkIndex: i, chunkData: chunks[i]);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw ArgumentError('Invalid fileData type');
|
||||||
|
}
|
||||||
|
|
||||||
// Step 3: Complete upload
|
// Step 3: Complete upload
|
||||||
return await completeUpload(taskId);
|
return await completeUpload(taskId);
|
||||||
@@ -216,12 +277,8 @@ class FileUploader {
|
|||||||
final data = fileData.data;
|
final data = fileData.data;
|
||||||
|
|
||||||
if (data is XFile) {
|
if (data is XFile) {
|
||||||
// Read bytes from XFile
|
|
||||||
data
|
|
||||||
.readAsBytes()
|
|
||||||
.then((readBytes) {
|
|
||||||
_performUpload(
|
_performUpload(
|
||||||
bytes: readBytes,
|
fileData: data,
|
||||||
fileName: fileData.displayName ?? data.name,
|
fileName: fileData.displayName ?? data.name,
|
||||||
contentType: actualMimetype,
|
contentType: actualMimetype,
|
||||||
client: client,
|
client: client,
|
||||||
@@ -229,10 +286,6 @@ class FileUploader {
|
|||||||
onProgress: onProgress,
|
onProgress: onProgress,
|
||||||
completer: completer,
|
completer: completer,
|
||||||
);
|
);
|
||||||
})
|
|
||||||
.catchError((e) {
|
|
||||||
completer.completeError(e);
|
|
||||||
});
|
|
||||||
return completer;
|
return completer;
|
||||||
} else if (data is List<int> || data is Uint8List) {
|
} else if (data is List<int> || data is Uint8List) {
|
||||||
bytes = data is List<int> ? Uint8List.fromList(data) : data;
|
bytes = data is List<int> ? Uint8List.fromList(data) : data;
|
||||||
@@ -252,7 +305,7 @@ class FileUploader {
|
|||||||
|
|
||||||
if (bytes != null) {
|
if (bytes != null) {
|
||||||
_performUpload(
|
_performUpload(
|
||||||
bytes: bytes,
|
fileData: bytes,
|
||||||
fileName: actualFilename,
|
fileName: actualFilename,
|
||||||
contentType: actualMimetype,
|
contentType: actualMimetype,
|
||||||
client: client,
|
client: client,
|
||||||
@@ -267,7 +320,7 @@ class FileUploader {
|
|||||||
|
|
||||||
// Helper method to perform the actual upload
|
// Helper method to perform the actual upload
|
||||||
static void _performUpload({
|
static void _performUpload({
|
||||||
required Uint8List bytes,
|
required dynamic fileData,
|
||||||
required String fileName,
|
required String fileName,
|
||||||
required String contentType,
|
required String contentType,
|
||||||
required Dio client,
|
required Dio client,
|
||||||
@@ -281,7 +334,7 @@ class FileUploader {
|
|||||||
onProgress?.call(0.0, Duration.zero);
|
onProgress?.call(0.0, Duration.zero);
|
||||||
uploader
|
uploader
|
||||||
.uploadFile(
|
.uploadFile(
|
||||||
bytes: bytes,
|
fileData: fileData,
|
||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
poolId: poolId,
|
poolId: poolId,
|
||||||
|
|||||||
@@ -112,23 +112,28 @@ class CloudFilePicker extends HookConsumerWidget {
|
|||||||
|
|
||||||
void pickImage() async {
|
void pickImage() async {
|
||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final result = await FilePicker.platform.pickFiles(
|
final ImagePicker picker = ImagePicker();
|
||||||
allowMultiple: allowMultiple,
|
List<XFile> results;
|
||||||
type: FileType.image,
|
if (allowMultiple) {
|
||||||
|
results = await picker.pickMultiImage();
|
||||||
|
} else {
|
||||||
|
final XFile? result = await picker.pickImage(
|
||||||
|
source: ImageSource.gallery,
|
||||||
);
|
);
|
||||||
if (result == null || result.files.isEmpty) {
|
results = result != null ? [result] : [];
|
||||||
|
}
|
||||||
|
if (results.isEmpty) {
|
||||||
if (context.mounted) hideLoadingModal(context);
|
if (context.mounted) hideLoadingModal(context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final newFiles =
|
final newFiles =
|
||||||
result.files.map((e) {
|
results
|
||||||
final xfile =
|
.map(
|
||||||
e.bytes != null
|
(xfile) =>
|
||||||
? XFile.fromData(e.bytes!, name: e.name)
|
UniversalFile(data: xfile, type: UniversalFileType.image),
|
||||||
: XFile(e.path!);
|
)
|
||||||
return UniversalFile(data: xfile, type: UniversalFileType.image);
|
.toList();
|
||||||
}).toList();
|
|
||||||
|
|
||||||
if (!allowMultiple) {
|
if (!allowMultiple) {
|
||||||
files.value = newFiles;
|
files.value = newFiles;
|
||||||
|
|||||||
@@ -402,16 +402,13 @@ class ComposeLogic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> pickPhotoMedia(WidgetRef ref, ComposeState state) async {
|
static Future<void> pickPhotoMedia(WidgetRef ref, ComposeState state) async {
|
||||||
final result = await FilePicker.platform.pickFiles(
|
final ImagePicker picker = ImagePicker();
|
||||||
type: FileType.image,
|
final List<XFile> results = await picker.pickMultiImage();
|
||||||
allowMultiple: true,
|
if (results.isEmpty) return;
|
||||||
allowCompression: false,
|
|
||||||
);
|
|
||||||
if (result == null || result.count == 0) return;
|
|
||||||
state.attachments.value = [
|
state.attachments.value = [
|
||||||
...state.attachments.value,
|
...state.attachments.value,
|
||||||
...result.files.map(
|
...results.map(
|
||||||
(e) => UniversalFile(data: e.xFile, type: UniversalFileType.image),
|
(xfile) => UniversalFile(data: xfile, type: UniversalFileType.image),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,19 +19,19 @@ PODS:
|
|||||||
- Firebase/Messaging (12.4.0):
|
- Firebase/Messaging (12.4.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseMessaging (~> 12.4.0)
|
- FirebaseMessaging (~> 12.4.0)
|
||||||
- firebase_analytics (12.0.3):
|
- firebase_analytics (12.0.4):
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- FirebaseAnalytics (= 12.4.0)
|
- FirebaseAnalytics (= 12.4.0)
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- firebase_core (4.2.0):
|
- firebase_core (4.2.1):
|
||||||
- Firebase/CoreOnly (~> 12.4.0)
|
- Firebase/CoreOnly (~> 12.4.0)
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- firebase_crashlytics (5.0.3):
|
- firebase_crashlytics (5.0.4):
|
||||||
- Firebase/CoreOnly (~> 12.4.0)
|
- Firebase/CoreOnly (~> 12.4.0)
|
||||||
- Firebase/Crashlytics (~> 12.4.0)
|
- Firebase/Crashlytics (~> 12.4.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- firebase_messaging (16.0.3):
|
- firebase_messaging (16.0.4):
|
||||||
- Firebase/CoreOnly (~> 12.4.0)
|
- Firebase/CoreOnly (~> 12.4.0)
|
||||||
- Firebase/Messaging (~> 12.4.0)
|
- Firebase/Messaging (~> 12.4.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
@@ -416,10 +416,10 @@ SPEC CHECKSUMS:
|
|||||||
file_saver: e35bd97de451dde55ff8c38862ed7ad0f3418d0f
|
file_saver: e35bd97de451dde55ff8c38862ed7ad0f3418d0f
|
||||||
file_selector_macos: 9e9e068e90ebee155097d00e89ae91edb2374db7
|
file_selector_macos: 9e9e068e90ebee155097d00e89ae91edb2374db7
|
||||||
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
|
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
|
||||||
firebase_analytics: d876586269c1d8d2b3dcac085bc2d97c62abc9df
|
firebase_analytics: 09241c4796c1c42a02349ef8bf30025f5b640f0e
|
||||||
firebase_core: d81d1a44df95699ce074ae63d8cb43e9df21e142
|
firebase_core: e054894ab56033ef9bcbe2d9eac9395e5306e2fc
|
||||||
firebase_crashlytics: 723622cc39a9fa7320585424f5864c5699893ce1
|
firebase_crashlytics: c2438b5f5bdcacf59d0eaee5852c6b0ab09dab77
|
||||||
firebase_messaging: 31f412ae5a54e02d1c46d467969f7ad92c4b81ec
|
firebase_messaging: 373ac3a56e5aa37bb9aff4127f700aa5973c1168
|
||||||
FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f
|
FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f
|
||||||
FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3
|
FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3
|
||||||
FirebaseCoreExtension: 7e1f7118ee970e001a8013719fb90950ee5e0018
|
FirebaseCoreExtension: 7e1f7118ee970e001a8013719fb90950ee5e0018
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.1.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: convert
|
name: convert
|
||||||
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||||
@@ -1185,10 +1185,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: d8f590a69729f719177ea68eb1e598295e8dbc41bbc247fed78b2c8a25660d7c
|
sha256: c92d18e1fe994cb06d48aa786c46b142a5633067e8297cff6b5a3ac742620104
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "16.3.0"
|
version: "17.0.0"
|
||||||
google_fonts:
|
google_fonts:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ dependencies:
|
|||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
flutter_hooks: ^0.21.3+1
|
flutter_hooks: ^0.21.3+1
|
||||||
hooks_riverpod: ^2.6.1
|
hooks_riverpod: ^2.6.1
|
||||||
go_router: ^16.3.0
|
go_router: ^17.0.0
|
||||||
styled_widget: ^0.4.1
|
styled_widget: ^0.4.1
|
||||||
shared_preferences: ^2.5.3
|
shared_preferences: ^2.5.3
|
||||||
flutter_riverpod: ^2.6.1
|
flutter_riverpod: ^2.6.1
|
||||||
@@ -165,6 +165,7 @@ dependencies:
|
|||||||
dio_smart_retry: ^7.0.1
|
dio_smart_retry: ^7.0.1
|
||||||
flutter_expandable_fab: ^2.5.2
|
flutter_expandable_fab: ^2.5.2
|
||||||
event_bus: ^2.0.1
|
event_bus: ^2.0.1
|
||||||
|
convert: ^3.1.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user