👽 Fix attachment uploading
This commit is contained in:
parent
91c85e8a58
commit
cf0df91d8c
@ -21,7 +21,7 @@ class SnAttachmentProvider {
|
||||
|
||||
void putCache(Iterable<SnAttachment> items, {bool noCheck = false}) {
|
||||
for (final item in items) {
|
||||
if ((item.isAnalyzed && item.isUploaded) || noCheck) {
|
||||
if (item.isAnalyzed || noCheck) {
|
||||
_cache[item.rid] = item;
|
||||
}
|
||||
}
|
||||
@ -34,7 +34,7 @@ class SnAttachmentProvider {
|
||||
|
||||
final resp = await _sn.client.get('/cgi/uc/attachments/$rid/meta');
|
||||
final out = SnAttachment.fromJson(resp.data);
|
||||
if (out.isAnalyzed && out.isUploaded) {
|
||||
if (out.isAnalyzed) {
|
||||
_cache[rid] = out;
|
||||
}
|
||||
|
||||
@ -62,11 +62,12 @@ class SnAttachmentProvider {
|
||||
'id': pendingFetch.join(','),
|
||||
},
|
||||
);
|
||||
final out = resp.data['data'].map((e) => e['id'] == 0 ? null : SnAttachment.fromJson(e)).toList();
|
||||
final List<SnAttachment?> out =
|
||||
resp.data['data'].map((e) => e['id'] == 0 ? null : SnAttachment.fromJson(e)).cast<SnAttachment?>().toList();
|
||||
|
||||
for (final item in out) {
|
||||
if (item == null) continue;
|
||||
if (item.isAnalyzed && item.isUploaded) {
|
||||
if (item.isAnalyzed) {
|
||||
_cache[item.rid] = item;
|
||||
}
|
||||
result[randomMapping[item.rid]!] = item;
|
||||
@ -117,7 +118,7 @@ class SnAttachmentProvider {
|
||||
return SnAttachment.fromJson(resp.data);
|
||||
}
|
||||
|
||||
Future<(SnAttachment, int)> chunkedUploadInitialize(
|
||||
Future<(SnAttachmentFragment, int)> chunkedUploadInitialize(
|
||||
int size,
|
||||
String filename,
|
||||
String pool,
|
||||
@ -134,7 +135,7 @@ class SnAttachmentProvider {
|
||||
mimetypeOverride = mimetype;
|
||||
}
|
||||
|
||||
final resp = await _sn.client.post('/cgi/uc/attachments/multipart', data: {
|
||||
final resp = await _sn.client.post('/cgi/uc/fragments', data: {
|
||||
'alt': fileAlt,
|
||||
'name': filename,
|
||||
'pool': pool,
|
||||
@ -143,17 +144,17 @@ class SnAttachmentProvider {
|
||||
if (mimetypeOverride != null) 'mimetype': mimetypeOverride,
|
||||
});
|
||||
|
||||
return (SnAttachment.fromJson(resp.data['meta']), resp.data['chunk_size'] as int);
|
||||
return (SnAttachmentFragment.fromJson(resp.data['meta']), resp.data['chunk_size'] as int);
|
||||
}
|
||||
|
||||
Future<SnAttachment> _chunkedUploadOnePart(
|
||||
Future<dynamic> _chunkedUploadOnePart(
|
||||
Uint8List data,
|
||||
String rid,
|
||||
String cid, {
|
||||
Function(double progress)? onProgress,
|
||||
}) async {
|
||||
final resp = await _sn.client.post(
|
||||
'/cgi/uc/attachments/multipart/$rid/$cid',
|
||||
'/cgi/uc/fragments/$rid/$cid',
|
||||
data: data,
|
||||
options: Options(headers: {'Content-Type': 'application/octet-stream'}),
|
||||
onSendProgress: (count, total) {
|
||||
@ -163,21 +164,27 @@ class SnAttachmentProvider {
|
||||
},
|
||||
);
|
||||
|
||||
return SnAttachment.fromJson(resp.data);
|
||||
if (resp.data['attachment'] != null) {
|
||||
return SnAttachment.fromJson(resp.data['attachment']);
|
||||
} else {
|
||||
return SnAttachmentFragment.fromJson(resp.data['fragment']);
|
||||
}
|
||||
}
|
||||
|
||||
Future<SnAttachment> chunkedUploadParts(
|
||||
XFile file,
|
||||
SnAttachment place,
|
||||
SnAttachmentFragment place,
|
||||
int chunkSize, {
|
||||
Function(double progress)? onProgress,
|
||||
}) async {
|
||||
final Map<String, dynamic> chunks = place.fileChunks ?? {};
|
||||
final Map<String, dynamic> chunks = place.fileChunks;
|
||||
var currentTask = 0;
|
||||
|
||||
final queue = Queue<Future<void>>();
|
||||
final activeTasks = <Future<void>>[];
|
||||
|
||||
late SnAttachment out;
|
||||
|
||||
for (final entry in chunks.entries) {
|
||||
queue.add(() async {
|
||||
final beginCursor = entry.value * chunkSize;
|
||||
@ -187,7 +194,7 @@ class SnAttachmentProvider {
|
||||
);
|
||||
final data = Uint8List.fromList(await file.openRead(beginCursor, endCursor).expand((chunk) => chunk).toList());
|
||||
|
||||
place = await _chunkedUploadOnePart(
|
||||
final result = await _chunkedUploadOnePart(
|
||||
data,
|
||||
place.rid,
|
||||
entry.key,
|
||||
@ -197,6 +204,12 @@ class SnAttachmentProvider {
|
||||
onProgress?.call(overallProgress);
|
||||
|
||||
currentTask++;
|
||||
|
||||
if (result is SnAttachmentFragment) {
|
||||
place = result;
|
||||
} else {
|
||||
out = result as SnAttachment;
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
@ -213,7 +226,7 @@ class SnAttachmentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
return place;
|
||||
return out;
|
||||
}
|
||||
|
||||
Future<SnAttachment> updateOne(
|
||||
|
@ -19,7 +19,7 @@ class SnAttachment with _$SnAttachment {
|
||||
required int id,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required dynamic deletedAt,
|
||||
required DateTime? deletedAt,
|
||||
required String rid,
|
||||
required String uuid,
|
||||
required int size,
|
||||
@ -31,19 +31,20 @@ class SnAttachment with _$SnAttachment {
|
||||
required int refCount,
|
||||
@Default(0) int contentRating,
|
||||
@Default(0) int qualityRating,
|
||||
required dynamic fileChunks,
|
||||
required dynamic cleanedAt,
|
||||
required DateTime? cleanedAt,
|
||||
required bool isAnalyzed,
|
||||
required bool isUploaded,
|
||||
required bool isSelfRef,
|
||||
required dynamic ref,
|
||||
required dynamic refId,
|
||||
required SnAttachment? ref,
|
||||
required int? refId,
|
||||
required SnAttachmentPool? pool,
|
||||
required int poolId,
|
||||
required int accountId,
|
||||
int? thumbnailId,
|
||||
SnAttachment? thumbnail,
|
||||
int? compressedId,
|
||||
SnAttachment? compressed,
|
||||
@Default({}) Map<String, dynamic> usermeta,
|
||||
@Default({}) Map<String, dynamic> metadata,
|
||||
String? thumbnail,
|
||||
}) = _SnAttachment;
|
||||
|
||||
factory SnAttachment.fromJson(Map<String, Object?> json) => _$SnAttachmentFromJson(json);
|
||||
@ -61,6 +62,37 @@ class SnAttachment with _$SnAttachment {
|
||||
};
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SnAttachmentFragment with _$SnAttachmentFragment {
|
||||
const SnAttachmentFragment._();
|
||||
|
||||
const factory SnAttachmentFragment({
|
||||
required int id,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
required String rid,
|
||||
required String uuid,
|
||||
required int size,
|
||||
required String name,
|
||||
required String alt,
|
||||
required String mimetype,
|
||||
required String hash,
|
||||
String? fingerprint,
|
||||
@Default({}) Map<String, int> fileChunks,
|
||||
@Default([]) List<String> fileChunksMissing,
|
||||
}) = _SnAttachmentFragment;
|
||||
|
||||
factory SnAttachmentFragment.fromJson(Map<String, Object?> json) => _$SnAttachmentFragmentFromJson(json);
|
||||
|
||||
SnMediaType get mediaType => switch (mimetype.split('/').firstOrNull) {
|
||||
'image' => SnMediaType.image,
|
||||
'video' => SnMediaType.video,
|
||||
'audio' => SnMediaType.audio,
|
||||
_ => SnMediaType.file,
|
||||
};
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SnAttachmentPool with _$SnAttachmentPool {
|
||||
const factory SnAttachmentPool({
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,9 @@ _$SnAttachmentImpl _$$SnAttachmentImplFromJson(Map<String, dynamic> json) =>
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'],
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
rid: json['rid'] as String,
|
||||
uuid: json['uuid'] as String,
|
||||
size: (json['size'] as num).toInt(),
|
||||
@ -23,21 +25,30 @@ _$SnAttachmentImpl _$$SnAttachmentImplFromJson(Map<String, dynamic> json) =>
|
||||
refCount: (json['ref_count'] as num).toInt(),
|
||||
contentRating: (json['content_rating'] as num?)?.toInt() ?? 0,
|
||||
qualityRating: (json['quality_rating'] as num?)?.toInt() ?? 0,
|
||||
fileChunks: json['file_chunks'],
|
||||
cleanedAt: json['cleaned_at'],
|
||||
cleanedAt: json['cleaned_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['cleaned_at'] as String),
|
||||
isAnalyzed: json['is_analyzed'] as bool,
|
||||
isUploaded: json['is_uploaded'] as bool,
|
||||
isSelfRef: json['is_self_ref'] as bool,
|
||||
ref: json['ref'],
|
||||
refId: json['ref_id'],
|
||||
ref: json['ref'] == null
|
||||
? null
|
||||
: SnAttachment.fromJson(json['ref'] as Map<String, dynamic>),
|
||||
refId: (json['ref_id'] as num?)?.toInt(),
|
||||
pool: json['pool'] == null
|
||||
? null
|
||||
: SnAttachmentPool.fromJson(json['pool'] as Map<String, dynamic>),
|
||||
poolId: (json['pool_id'] as num).toInt(),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
thumbnailId: (json['thumbnail_id'] as num?)?.toInt(),
|
||||
thumbnail: json['thumbnail'] == null
|
||||
? null
|
||||
: SnAttachment.fromJson(json['thumbnail'] as Map<String, dynamic>),
|
||||
compressedId: (json['compressed_id'] as num?)?.toInt(),
|
||||
compressed: json['compressed'] == null
|
||||
? null
|
||||
: SnAttachment.fromJson(json['compressed'] as Map<String, dynamic>),
|
||||
usermeta: json['usermeta'] as Map<String, dynamic>? ?? const {},
|
||||
metadata: json['metadata'] as Map<String, dynamic>? ?? const {},
|
||||
thumbnail: json['thumbnail'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SnAttachmentImplToJson(_$SnAttachmentImpl instance) =>
|
||||
@ -45,7 +56,7 @@ Map<String, dynamic> _$$SnAttachmentImplToJson(_$SnAttachmentImpl instance) =>
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt,
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'rid': instance.rid,
|
||||
'uuid': instance.uuid,
|
||||
'size': instance.size,
|
||||
@ -57,19 +68,66 @@ Map<String, dynamic> _$$SnAttachmentImplToJson(_$SnAttachmentImpl instance) =>
|
||||
'ref_count': instance.refCount,
|
||||
'content_rating': instance.contentRating,
|
||||
'quality_rating': instance.qualityRating,
|
||||
'file_chunks': instance.fileChunks,
|
||||
'cleaned_at': instance.cleanedAt,
|
||||
'cleaned_at': instance.cleanedAt?.toIso8601String(),
|
||||
'is_analyzed': instance.isAnalyzed,
|
||||
'is_uploaded': instance.isUploaded,
|
||||
'is_self_ref': instance.isSelfRef,
|
||||
'ref': instance.ref,
|
||||
'ref': instance.ref?.toJson(),
|
||||
'ref_id': instance.refId,
|
||||
'pool': instance.pool?.toJson(),
|
||||
'pool_id': instance.poolId,
|
||||
'account_id': instance.accountId,
|
||||
'thumbnail_id': instance.thumbnailId,
|
||||
'thumbnail': instance.thumbnail?.toJson(),
|
||||
'compressed_id': instance.compressedId,
|
||||
'compressed': instance.compressed?.toJson(),
|
||||
'usermeta': instance.usermeta,
|
||||
'metadata': instance.metadata,
|
||||
'thumbnail': instance.thumbnail,
|
||||
};
|
||||
|
||||
_$SnAttachmentFragmentImpl _$$SnAttachmentFragmentImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$SnAttachmentFragmentImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
rid: json['rid'] as String,
|
||||
uuid: json['uuid'] as String,
|
||||
size: (json['size'] as num).toInt(),
|
||||
name: json['name'] as String,
|
||||
alt: json['alt'] as String,
|
||||
mimetype: json['mimetype'] as String,
|
||||
hash: json['hash'] as String,
|
||||
fingerprint: json['fingerprint'] as String?,
|
||||
fileChunks: (json['file_chunks'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, (e as num).toInt()),
|
||||
) ??
|
||||
const {},
|
||||
fileChunksMissing: (json['file_chunks_missing'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList() ??
|
||||
const [],
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SnAttachmentFragmentImplToJson(
|
||||
_$SnAttachmentFragmentImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'rid': instance.rid,
|
||||
'uuid': instance.uuid,
|
||||
'size': instance.size,
|
||||
'name': instance.name,
|
||||
'alt': instance.alt,
|
||||
'mimetype': instance.mimetype,
|
||||
'hash': instance.hash,
|
||||
'fingerprint': instance.fingerprint,
|
||||
'file_chunks': instance.fileChunks,
|
||||
'file_chunks_missing': instance.fileChunksMissing,
|
||||
};
|
||||
|
||||
_$SnAttachmentPoolImpl _$$SnAttachmentPoolImplFromJson(
|
||||
|
@ -215,9 +215,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Stack(
|
||||
children: [
|
||||
if (widget.data.thumbnail?.isNotEmpty ?? false)
|
||||
if (widget.data.thumbnail != null)
|
||||
AutoResizeUniversalImage(
|
||||
sn.getAttachmentUrl(widget.data.thumbnail!),
|
||||
sn.getAttachmentUrl(widget.data.thumbnail!.rid),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
else
|
||||
|
@ -315,7 +315,7 @@ class _PostMediaPendingItem extends StatelessWidget {
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
if (media.attachment?.thumbnail != null)
|
||||
AutoResizeUniversalImage(sn.getAttachmentUrl(media.attachment!.thumbnail!)),
|
||||
AutoResizeUniversalImage(sn.getAttachmentUrl(media.attachment!.thumbnail!.rid)),
|
||||
const Icon(Symbols.videocam, color: Colors.white, shadows: [
|
||||
Shadow(
|
||||
offset: Offset(1, 1),
|
||||
@ -332,7 +332,7 @@ class _PostMediaPendingItem extends StatelessWidget {
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
if (media.attachment?.thumbnail != null)
|
||||
AutoResizeUniversalImage(sn.getAttachmentUrl(media.attachment!.thumbnail!)),
|
||||
AutoResizeUniversalImage(sn.getAttachmentUrl(media.attachment!.thumbnail!.rid)),
|
||||
const Icon(Symbols.audio_file, color: Colors.white, shadows: [
|
||||
Shadow(
|
||||
offset: Offset(1, 1),
|
||||
|
Loading…
Reference in New Issue
Block a user