feat: загрузки

This commit is contained in:
Jganenokk
2026-07-27 18:11:38 +07:00
parent 92c0a90367
commit 1a043f033d
18 changed files with 1566 additions and 102 deletions
@@ -7,9 +7,11 @@ import 'package:komet/main.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:ogg_opus_player/ogg_opus_player.dart';
import '../../../backend/modules/messages.dart' show CachedMessage, ContactCache;
import '../../../backend/modules/messages.dart'
show CachedMessage, ContactCache;
import '../../../backend/modules/shared_content.dart';
import '../../../core/cache/info_cache.dart';
import '../../../core/utils/download_history.dart';
import '../../../core/utils/download_progress.dart';
import '../../../core/utils/file_download.dart';
import '../../../core/utils/format.dart';
@@ -103,9 +105,7 @@ Widget _emptyState(ColorScheme cs, String label, IconData icon) {
Widget _loadingState(ColorScheme cs) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 56),
child: Center(
child: SmallSpinner(size: 26, color: cs.primary),
),
child: Center(child: SmallSpinner(size: 26, color: cs.primary)),
);
}
@@ -231,6 +231,7 @@ void _notifySave(BuildContext context, MediaSaveResult result) {
Future<void> _downloadAttachment(
BuildContext context,
SharedMediaItem item,
String sourceName,
) async {
final att = item.attachment;
final now = DateTime.now().millisecondsSinceEpoch;
@@ -243,6 +244,16 @@ Future<void> _downloadAttachment(
resolveUrl: () async => url,
saveName: 'IMG_$now.jpg',
kind: SaveMediaKind.image,
download: DownloadMetadata(
cacheName: 'photo_${att.photoId ?? url.hashCode}.jpg',
kind: DownloadKind.photo,
sourceName: sourceName,
thumbnailUrl: url,
expectedSize: att.size ?? 0,
chatId: item.chatId,
messageId: item.messageId,
messageTime: item.time,
),
);
if (context.mounted) _notifySave(context, result);
return;
@@ -262,6 +273,16 @@ Future<void> _downloadAttachment(
},
saveName: 'VID_$now.mp4',
kind: SaveMediaKind.video,
download: DownloadMetadata(
cacheName: 'video_${att.videoId ?? item.messageId}.mp4',
kind: DownloadKind.video,
sourceName: sourceName,
thumbnailUrl: att.thumbnail ?? att.baseUrl ?? att.previewData,
expectedSize: att.size ?? 0,
chatId: item.chatId,
messageId: item.messageId,
messageTime: item.time,
),
);
if (context.mounted) _notifySave(context, result);
return;
@@ -271,6 +292,7 @@ Future<void> _downloadAttachment(
final fileId = att.fileId;
if (fileId == null) return;
final name = att.name ?? 'file_$now';
final downloadKind = downloadKindForName(name);
final result = await saveMediaFile(
cacheName: '${fileId}_$name',
resolveUrl: () => messagesModule.getFileUrl(
@@ -280,6 +302,18 @@ Future<void> _downloadAttachment(
),
saveName: name,
kind: SaveMediaKind.file,
download: DownloadMetadata(
cacheName: '${fileId}_$name',
name: downloadKind == DownloadKind.file ? name : '',
kind: downloadKind,
sourceName: sourceName,
thumbnailUrl:
att.preview?.baseUrl ?? att.preview?.previewData ?? att.previewData,
expectedSize: att.size ?? 0,
chatId: item.chatId,
messageId: item.messageId,
messageTime: item.time,
),
);
if (context.mounted) _notifySave(context, result);
return;
@@ -293,6 +327,15 @@ Future<void> _downloadAttachment(
resolveUrl: () async => url,
saveName: 'AUD_$now.ogg',
kind: SaveMediaKind.file,
download: DownloadMetadata(
cacheName: '${att.audioId ?? item.messageId}.ogg',
kind: DownloadKind.audio,
sourceName: sourceName,
expectedSize: att.size ?? 0,
chatId: item.chatId,
messageId: item.messageId,
messageTime: item.time,
),
);
if (context.mounted) _notifySave(context, result);
}
@@ -593,7 +636,13 @@ class _SharedMediaTabState extends State<SharedMediaTab>
children.add(_mediaGrid(cs, group.items));
case SharedContentKind.files:
children.addAll(
group.items.map((i) => _FileRow(item: i, onGoTo: () => _goTo(i))),
group.items.map(
(i) => _FileRow(
item: i,
sourceName: widget.sourceName,
onGoTo: () => _goTo(i),
),
),
);
case SharedContentKind.voice:
children.addAll(
@@ -601,6 +650,7 @@ class _SharedMediaTabState extends State<SharedMediaTab>
(i) => _ProfileVoiceTile(
item: i,
senderName: _resolveName(i.senderId),
sourceName: widget.sourceName,
onGoTo: () => _goTo(i),
),
),
@@ -645,13 +695,12 @@ class _SharedMediaTabState extends State<SharedMediaTab>
crossAxisSpacing: 3,
),
itemCount: items.length,
itemBuilder: (context, index) =>
_MediaTile(
item: items[index],
onGoTo: () => _goTo(items[index]),
onGoToMessage: widget.onGoToMessage,
sourceName: widget.sourceName,
),
itemBuilder: (context, index) => _MediaTile(
item: items[index],
onGoTo: () => _goTo(items[index]),
onGoToMessage: widget.onGoToMessage,
sourceName: widget.sourceName,
),
);
}
}
@@ -676,7 +725,7 @@ class _MediaTile extends StatelessWidget {
onGoTo();
}),
_MenuAction(Symbols.download, l10n.sharedDownload, () async {
await _downloadAttachment(context, item);
await _downloadAttachment(context, item, sourceName);
}),
]);
}
@@ -810,9 +859,14 @@ class _MediaTile extends StatelessWidget {
class _FileRow extends StatelessWidget {
final SharedMediaItem item;
final String sourceName;
final VoidCallback onGoTo;
const _FileRow({required this.item, required this.onGoTo});
const _FileRow({
required this.item,
required this.sourceName,
required this.onGoTo,
});
void _menu(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
@@ -821,7 +875,7 @@ class _FileRow extends StatelessWidget {
onGoTo();
}),
_MenuAction(Symbols.download, l10n.sharedDownload, () async {
await _downloadAttachment(context, item);
await _downloadAttachment(context, item, sourceName);
}),
]);
}
@@ -946,6 +1000,20 @@ class _FileRow extends StatelessWidget {
),
onProgress: (p) => MediaDownloadProgress.set(cacheName, p),
onReady: () => MediaDownloadProgress.set(cacheName, null),
download: DownloadMetadata(
cacheName: cacheName,
name: downloadKindForName(att.name ?? '') == DownloadKind.file
? att.name ?? ''
: '',
kind: downloadKindForName(att.name ?? ''),
sourceName: sourceName,
thumbnailUrl:
att.preview?.baseUrl ?? att.preview?.previewData ?? att.previewData,
expectedSize: att.size ?? 0,
chatId: item.chatId,
messageId: item.messageId,
messageTime: item.time,
),
);
if (!context.mounted) return;
@@ -1083,11 +1151,13 @@ class _LinkRow extends StatelessWidget {
class _ProfileVoiceTile extends StatefulWidget {
final SharedMediaItem item;
final String senderName;
final String sourceName;
final VoidCallback onGoTo;
const _ProfileVoiceTile({
required this.item,
required this.senderName,
required this.sourceName,
required this.onGoTo,
});
@@ -1262,7 +1332,7 @@ class _ProfileVoiceTileState extends State<_ProfileVoiceTile> {
widget.onGoTo();
}),
_MenuAction(Symbols.download, l10n.sharedDownload, () async {
await _downloadAttachment(context, widget.item);
await _downloadAttachment(context, widget.item, widget.sourceName);
}),
]);
}