Add overall progress, notifications, and UI polish
- Unify audio/subtitle selection: single-select, auto-default, cross-file propagation by exact name - Show file size in queue, group divider and reordered columns in track table, drop accent highlight on row selection - Add cumulative progress bar (files finished, MB copied) to the stripping window - Add Windows toast notifications on stripping completion/cancel/error - Restart the app after settings are changed; Cancel no longer clears the queue, only closes the window - Add ConfigureAwait(false) throughout MkvService so concurrent strips don't starve the UI thread - Hardcode scan/strip concurrency (10/5) instead of exposing it in Settings
This commit is contained in:
@@ -14,6 +14,12 @@ public class JobProgressItem : INotifyPropertyChanged
|
||||
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the source file in bytes, used as this job's weight when
|
||||
/// computing overall cumulative progress across all queued files.
|
||||
/// </summary>
|
||||
public long FileSizeBytes { get; set; }
|
||||
|
||||
public int Percent
|
||||
{
|
||||
get => _percent;
|
||||
|
||||
@@ -32,6 +32,7 @@ public class QueuedFileItem : INotifyPropertyChanged
|
||||
|
||||
public string FilePath { get; }
|
||||
public string FileName => Path.GetFileName(FilePath);
|
||||
public string FileSizeDisplay { get; }
|
||||
public ObservableCollection<TrackItem> Tracks { get; } = new();
|
||||
|
||||
public string Status
|
||||
@@ -76,9 +77,33 @@ public class QueuedFileItem : INotifyPropertyChanged
|
||||
public QueuedFileItem(string filePath)
|
||||
{
|
||||
FilePath = filePath;
|
||||
FileSizeDisplay = FormatFileSize(filePath);
|
||||
Tracks.CollectionChanged += OnTracksChanged;
|
||||
}
|
||||
|
||||
private static string FormatFileSize(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
long bytes = new FileInfo(filePath).Length;
|
||||
string[] units = { "B", "KB", "MB", "GB", "TB" };
|
||||
double size = bytes;
|
||||
int unitIndex = 0;
|
||||
while (size >= 1024 && unitIndex < units.Length - 1)
|
||||
{
|
||||
size /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
return unitIndex == 0
|
||||
? $"{size:0} {units[unitIndex]}"
|
||||
: $"{size:0.#} {units[unitIndex]}";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTracksChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.NewItems != null)
|
||||
|
||||
+18
-11
@@ -19,12 +19,21 @@ public class TrackItem : INotifyPropertyChanged
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public bool ForcedDisplay { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// True for the first track of each type group (video/audio/subtitles/
|
||||
/// chapters) in the track table, computed once when the list is built.
|
||||
/// Used to draw a divider line above the row in the UI.
|
||||
/// </summary>
|
||||
public bool IsGroupStart { get; set; }
|
||||
|
||||
|
||||
private bool _defaultTrack;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this track should be flagged as the default track of its type
|
||||
/// when stripped. For subtitles this is kept in sync with <see cref="Copy"/>
|
||||
/// (selecting a subtitle also makes it the default one).
|
||||
/// when stripped. For audio and subtitles this is kept in sync with
|
||||
/// <see cref="Copy"/> (selecting a track also makes it the default one
|
||||
/// of its type).
|
||||
/// </summary>
|
||||
public bool DefaultTrack
|
||||
{
|
||||
@@ -38,11 +47,9 @@ public class TrackItem : INotifyPropertyChanged
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text shown in the track table's Name column. Subtitle tracks are shown
|
||||
/// as "Codec/Name" so tracks that share a display name but use a different
|
||||
/// codec are easy to tell apart.
|
||||
/// Text shown in the track table's Name column.
|
||||
/// </summary>
|
||||
public string DisplayName => Type == "subtitles" ? $"{Codec}/{Name}" : Name;
|
||||
public string DisplayName => Name;
|
||||
|
||||
/// <summary>
|
||||
/// Video is always kept, and chapters (a synthetic pseudo-track, not a
|
||||
@@ -70,12 +77,12 @@ public class TrackItem : INotifyPropertyChanged
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Key used to match subtitle tracks with the same identity across different
|
||||
/// queued files when propagating a subtitle selection. Subtitles are matched
|
||||
/// on "Codec/Name" so tracks with the same name but a different codec are
|
||||
/// treated as distinct.
|
||||
/// Key used to match a track's identity across different queued files
|
||||
/// when propagating an audio/subtitle selection. Matched on "Codec/Name"
|
||||
/// so tracks with the same name but a different codec are treated as
|
||||
/// distinct, even though only the name is shown in the table.
|
||||
/// </summary>
|
||||
public string PropagationKey => DisplayName;
|
||||
public string PropagationKey => $"{Codec}/{Name}";
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user