fix: add backup status item tap action, sorting fix, color space fix

This commit is contained in:
Prateek Sunal
2025-02-08 03:51:04 +05:30
parent 38ae9e2b19
commit f4b7ef19ce
3 changed files with 199 additions and 171 deletions

View File

@@ -1741,7 +1741,7 @@ class FilesDB {
WHERE $columnFileType = ?
AND $columnCreationTime > ?
AND $columnUploadedFileID != -1
SORT BY $columnCreationTime DESC
ORDER BY $columnCreationTime DESC
''',
[getInt(fileType), beginDate.microsecondsSinceEpoch],
);

View File

@@ -202,7 +202,10 @@ class PreviewVideoStore {
);
FFmpegSession? session;
final colorSpace = videoData["color_space"]?.toString().toLowerCase();
final isColorGood = colorSpace == "bt709";
final codecIsH264 = codec?.contains("h264") ?? false;
if (bitrate != null && bitrate <= 4000 * 1000 && codecIsH264) {
// create playlist without compression, as is
session = await FFmpegKit.execute(
@@ -233,6 +236,18 @@ class PreviewVideoStore {
);
}
if (codecIsH264 && (colorSpace == null || isColorGood)) {
session ??= await FFmpegKit.execute(
'-i "${file.path}" '
'-metadata:s:v:0 rotate=0 '
'-vf "scale=-2:720,fps=30" '
'-c:v libx264 -b:v 2000k -preset medium '
'-c:a aac -b:a 128k -f hls -hls_time 10 -hls_flags single_file '
'-hls_list_size 0 -hls_key_info_file ${keyinfo.path} '
'$prefix/output.m3u8',
);
}
session ??= await FFmpegKit.execute(
'-i "${file.path}" '
'-metadata:s:v:0 rotate=0 '

View File

@@ -7,9 +7,11 @@ import "package:photos/models/preview/preview_item.dart";
import "package:photos/models/preview/preview_item_status.dart";
import "package:photos/services/preview_video_store.dart";
import 'package:photos/theme/ente_theme.dart';
import "package:photos/ui/viewer/file/file_widget.dart";
import "package:photos/ui/viewer/file/thumbnail_widget.dart";
import "package:photos/utils/dialog_util.dart";
import "package:photos/utils/file_uploader.dart";
import "package:photos/utils/navigation_util.dart";
class BackupItemCard extends StatefulWidget {
const BackupItemCard({
@@ -55,199 +57,210 @@ class _BackupItemCardState extends State<BackupItemCard> {
final hasError = widget.item.error != null ||
widget.preview?.status == PreviewItemStatus.failed;
return Container(
height: 60,
margin: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: colorScheme.fillFaint.withOpacity(0.08),
width: 1,
return GestureDetector(
onTap: () {
routeToPage(
context,
FileWidget(
widget.item.file,
),
forceCustomPageRoute: true,
);
},
child: Container(
height: 60,
margin: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: colorScheme.fillFaint.withOpacity(0.08),
width: 1,
),
),
),
child: Row(
children: [
SizedBox(
width: 60,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.circular(4),
child: showThumbnail
? ThumbnailWidget(
widget.item.file,
shouldShowSyncStatus: false,
)
: Container(
color: colorScheme.fillFaint, // Placeholder color
child: Row(
children: [
SizedBox(
width: 60,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.circular(4),
child: showThumbnail
? ThumbnailWidget(
widget.item.file,
shouldShowSyncStatus: false,
)
: Container(
color: colorScheme.fillFaint, // Placeholder color
),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.item.file.displayName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 16,
height: 20 / 16,
color: Theme.of(context).brightness == Brightness.light
? const Color(0xFF000000)
: const Color(0xFFFFFFFF),
),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.item.file.displayName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 16,
height: 20 / 16,
color: Theme.of(context).brightness == Brightness.light
? const Color(0xFF000000)
: const Color(0xFFFFFFFF),
),
),
const SizedBox(height: 4),
Text(
folderName ?? "",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14,
height: 17 / 14,
color: Theme.of(context).brightness == Brightness.light
? const Color.fromRGBO(0, 0, 0, 0.7)
: const Color.fromRGBO(255, 255, 255, 0.7),
const SizedBox(height: 4),
Text(
folderName ?? "",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14,
height: 17 / 14,
color: Theme.of(context).brightness == Brightness.light
? const Color.fromRGBO(0, 0, 0, 0.7)
: const Color.fromRGBO(255, 255, 255, 0.7),
),
),
),
],
],
),
),
),
if (hasError) const SizedBox(width: 12),
if (hasError)
if (hasError) const SizedBox(width: 12),
if (hasError)
SizedBox(
height: 48,
width: 48,
child: IconButton(
icon: Icon(
Icons.error_outline,
color: getEnteColorScheme(context).fillBase,
),
onPressed: () {
String errorMessage = "";
if (widget.item.error is Exception) {
final Exception ex = widget.item.error as Exception;
errorMessage = "Error: " +
ex.runtimeType.toString() +
" - " +
ex.toString();
} else if (widget.item.error != null) {
errorMessage = widget.item.error.toString();
} else if (widget.preview?.error != null) {
errorMessage = widget.preview!.error!.toString();
}
showErrorDialog(
context,
'Upload failed',
errorMessage,
);
},
),
),
if (hasError) const SizedBox(width: 12),
SizedBox(
height: 48,
width: 48,
child: IconButton(
icon: Icon(
Icons.error_outline,
color: getEnteColorScheme(context).fillBase,
),
onPressed: () {
String errorMessage = "";
if (widget.item.error is Exception) {
final Exception ex = widget.item.error as Exception;
errorMessage = "Error: " +
ex.runtimeType.toString() +
" - " +
ex.toString();
} else if (widget.item.error != null) {
errorMessage = widget.item.error.toString();
} else if (widget.preview?.error != null) {
errorMessage = widget.preview!.error!.toString();
}
showErrorDialog(
context,
'Upload failed',
errorMessage,
);
},
),
),
if (hasError) const SizedBox(width: 12),
SizedBox(
height: 48,
width: 48,
child: Center(
child: switch (widget.item.status) {
BackupItemStatus.uploading => SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2.0,
color: colorScheme.primary700,
child: Center(
child: switch (widget.item.status) {
BackupItemStatus.uploading => SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2.0,
color: colorScheme.primary700,
),
),
),
BackupItemStatus.uploaded => widget.preview != null
? switch (widget.preview!.status) {
PreviewItemStatus.uploading ||
PreviewItemStatus.compressing =>
SizedBox(
width: 24,
height: 24,
child: Image.asset(
"assets/processing-video.png",
),
),
PreviewItemStatus.failed => GestureDetector(
onTap: () =>
PreviewVideoStore.instance.chunkAndUploadVideo(
context,
widget.item.file,
true,
),
child: SizedBox(
BackupItemStatus.uploaded => widget.preview != null
? switch (widget.preview!.status) {
PreviewItemStatus.uploading ||
PreviewItemStatus.compressing =>
SizedBox(
width: 24,
height: 24,
child: Image.asset(
"assets/processing-video-failed.png",
"assets/processing-video.png",
),
),
),
PreviewItemStatus.retry ||
PreviewItemStatus.inQueue =>
SizedBox(
width: 24,
height: 24,
child: Image.asset(
"assets/video-processing-queued.png",
PreviewItemStatus.failed => GestureDetector(
onTap: () => PreviewVideoStore.instance
.chunkAndUploadVideo(
context,
widget.item.file,
true,
),
child: SizedBox(
width: 24,
height: 24,
child: Image.asset(
"assets/processing-video-failed.png",
),
),
),
),
PreviewItemStatus.uploaded => SizedBox(
width: 24,
height: 24,
child: Image.asset(
"assets/processing-video-success.png",
PreviewItemStatus.retry ||
PreviewItemStatus.inQueue =>
SizedBox(
width: 24,
height: 24,
child: Image.asset(
"assets/video-processing-queued.png",
),
),
PreviewItemStatus.uploaded => SizedBox(
width: 24,
height: 24,
child: Image.asset(
"assets/processing-video-success.png",
),
),
}
: const SizedBox(
width: 24,
height: 24,
child: Icon(
Icons.check,
color: Color(0xFF00B33C),
),
}
: const SizedBox(
width: 24,
height: 24,
child: Icon(
Icons.check,
color: Color(0xFF00B33C),
),
BackupItemStatus.inQueue => SizedBox(
width: 24,
height: 24,
child: Icon(
Icons.history,
color: Theme.of(context).brightness == Brightness.light
? const Color.fromRGBO(0, 0, 0, .6)
: const Color.fromRGBO(255, 255, 255, .6),
),
BackupItemStatus.inQueue => SizedBox(
width: 24,
height: 24,
child: Icon(
Icons.history,
color: Theme.of(context).brightness == Brightness.light
? const Color.fromRGBO(0, 0, 0, .6)
: const Color.fromRGBO(255, 255, 255, .6),
),
),
BackupItemStatus.retry => IconButton(
icon: const Icon(
Icons.sync,
color: Color(0xFFFDB816),
BackupItemStatus.retry => IconButton(
icon: const Icon(
Icons.sync,
color: Color(0xFFFDB816),
),
onPressed: () async {
await FileUploader.instance.upload(
widget.item.file,
widget.item.collectionID,
);
},
),
onPressed: () async {
await FileUploader.instance.upload(
widget.item.file,
widget.item.collectionID,
);
},
),
BackupItemStatus.inBackground => SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2.0,
color: Theme.of(context).brightness == Brightness.light
? const Color.fromRGBO(0, 0, 0, .6)
: const Color.fromRGBO(255, 255, 255, .6),
BackupItemStatus.inBackground => SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2.0,
color: Theme.of(context).brightness == Brightness.light
? const Color.fromRGBO(0, 0, 0, .6)
: const Color.fromRGBO(255, 255, 255, .6),
),
),
),
},
},
),
),
),
],
],
),
),
);
}