fix: show processing status, fix when to not show popup buttons, update getFiles logic

This commit is contained in:
Prateek Sunal
2025-08-25 20:57:18 +05:30
parent 5869bec781
commit 707e8dbfcf
5 changed files with 117 additions and 23 deletions

View File

@@ -1687,26 +1687,36 @@ class FilesDB with SqlDbBase {
);
}
Future<List<EnteFile>> getAllFilesAfterDate({
required FileType fileType,
required DateTime beginDate,
Future<List<EnteFile>> getStreamingEligibleVideoFiles({
DateTime? beginDate,
required int userID,
bool onlyFilesWithLocalId = false,
}) async {
final db = await instance.sqliteAsyncDB;
final results = await db.getAll(
'''
String query = '''
SELECT * FROM $filesTable
WHERE $columnFileType = ?
AND $columnCreationTime > ?
AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID != -1)
AND $columnOwnerID = $userID
AND $columnLocalID IS NOT NULL
AND $columnOwnerID = ?
AND ($columnFileSize IS NOT NULL AND $columnFileSize <= 524288000)
AND ($columnDuration IS NOT NULL AND ($columnDuration <= 60 AND $columnDuration > 0))
ORDER BY $columnCreationTime DESC
''',
[getInt(fileType), beginDate.microsecondsSinceEpoch],
);
''';
final List<Object> queryArgs = [getInt(FileType.video), userID];
if (beginDate != null) {
query += ' AND $columnCreationTime > ?';
queryArgs.add(beginDate.microsecondsSinceEpoch);
}
if (onlyFilesWithLocalId) {
query += ' AND $columnLocalID IS NOT NULL';
}
query += ' ORDER BY $columnCreationTime DESC';
final results = await db.getAll(query, queryArgs);
return convertToFiles(results);
}

View File

@@ -1839,5 +1839,6 @@
"addedToStreamRecreationQueue": "Added to stream recreation queue",
"videoPreviewAlreadyExists": "Video preview already exists",
"videoAlreadyInQueue": "Video file already present in the queue",
"addedToQueue": "Added to queue"
"addedToQueue": "Added to queue",
"creatingStream": "Creating stream"
}

View File

@@ -158,6 +158,11 @@ class VideoPreviewService {
}
}
bool isCurrentlyProcessing(int? uploadedFileID) {
if (uploadedFileID == null) return false;
return uploadingFileId == uploadedFileID;
}
Future<bool> _isRecreateOperation(EnteFile file) async {
if (file.uploadedFileID == null) return false;
@@ -192,11 +197,14 @@ class VideoPreviewService {
}
}
Future<List<EnteFile>> _getFiles() async {
return await FilesDB.instance.getAllFilesAfterDate(
fileType: FileType.video,
beginDate: DateTime.now().subtract(const Duration(days: 60)),
Future<List<EnteFile>> _getFiles({
DateTime? beginDate,
bool onlyFilesWithLocalId = true,
}) async {
return await FilesDB.instance.getStreamingEligibleVideoFiles(
beginDate: beginDate,
userID: Configuration.instance.getUserID()!,
onlyFilesWithLocalId: onlyFilesWithLocalId,
);
}
@@ -204,7 +212,10 @@ class VideoPreviewService {
try {
// TODO: Should we consider all days we could have processed or last 60 days
await _ensurePreviewIdsInitialized();
final files = await _getFiles();
final files = await _getFiles(
beginDate: null,
onlyFilesWithLocalId: false,
);
final Set<int> totalProcessed = fileDataService.previewIds.keys.toSet();
final Set<int> total = {};
final Set<int> processed = {};
@@ -213,9 +224,7 @@ class VideoPreviewService {
for (final file in files) {
if (totalProcessed.contains(file.uploadedFileID)) {
processed.add(file.uploadedFileID!);
continue;
}
if (file.pubMagicMetadata?.sv == 1) {
} else if (file.pubMagicMetadata?.sv == 1) {
skipped++;
continue;
}
@@ -958,7 +967,10 @@ class VideoPreviewService {
manualQueueFiles = await UploadLocksDB.instance.getStreamQueue();
} catch (_) {}
final files = await _getFiles();
final files = await _getFiles(
beginDate: DateTime.now().subtract(const Duration(days: 60)),
onlyFilesWithLocalId: true,
);
final previewIds = fileDataService.previewIds;
_logger.info(

View File

@@ -481,17 +481,21 @@ class FileAppBarState extends State<FileAppBar> {
bool _shouldShowCreateStreamOption() {
// Show "Create Stream" option for uploaded video files without streams
// Skip if sv=1 (server indicates streaming not needed)
return widget.file.fileType == FileType.video &&
widget.file.isUploaded &&
widget.file.uploadedFileID != null &&
(widget.file.pubMagicMetadata?.sv ?? 0) != 1 &&
!fileDataService.previewIds.containsKey(widget.file.uploadedFileID!);
}
bool _shouldShowRecreateStreamOption() {
// Show "Recreate Stream" option for uploaded video files with existing streams
// Skip if sv=1 (server indicates streaming not needed)
return widget.file.fileType == FileType.video &&
widget.file.isUploaded &&
widget.file.uploadedFileID != null &&
(widget.file.pubMagicMetadata?.sv ?? 0) != 1 &&
fileDataService.previewIds.containsKey(widget.file.uploadedFileID!);
}

View File

@@ -2,6 +2,7 @@ import "package:flutter/material.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/models/file/file.dart";
import "package:photos/service_locator.dart";
import "package:photos/services/video_preview_service.dart";
import "package:photos/theme/colors.dart";
class VideoStreamChangeWidget extends StatefulWidget {
@@ -38,9 +39,75 @@ class _VideoStreamChangeWidgetState extends State<VideoStreamChangeWidget> {
Widget build(BuildContext context) {
final bool isPreviewAvailable = widget.file.uploadedFileID != null &&
(fileDataService.previewIds.containsKey(widget.file.uploadedFileID));
if (!isPreviewAvailable) {
// Check if this file is currently being processed for streaming
final bool isCurrentlyProcessing = VideoPreviewService.instance
.isCurrentlyProcessing(widget.file.uploadedFileID);
if (!isPreviewAvailable && !isCurrentlyProcessing) {
return const SizedBox();
}
// If currently processing, show "Creating Stream" with spinner (not clickable)
if (isCurrentlyProcessing) {
return Align(
alignment: Alignment.centerRight,
child: AnimatedOpacity(
duration: const Duration(
milliseconds: 200,
),
curve: Curves.easeInQuad,
opacity: widget._showControls ? 1 : 0,
child: Padding(
padding: const EdgeInsets.only(
right: 10,
bottom: 4,
),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: const BorderRadius.all(
Radius.circular(200),
),
border: Border.all(
color: strokeFaintDark,
width: 1,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
const SizedBox(width: 4),
Text(
AppLocalizations.of(context).creatingStream,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
],
),
),
),
),
);
}
// Default case - show stream toggle
return Align(
alignment: Alignment.centerRight,
child: AnimatedOpacity(