Skip to content

Commit

Permalink
Progress indication when opening VLC
Browse files Browse the repository at this point in the history
  • Loading branch information
electroly committed Nov 25, 2024
1 parent 8671855 commit 1f18e68
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/J.App/AddTagToMoviesForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private void Ok()

try
{
SimpleProgressForm.Do(
ProgressForm.Do(
this,
"Adding tags...",
async (updateProgress, cancel) =>
Expand Down
11 changes: 5 additions & 6 deletions src/J.App/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ private async void OptionsButton_Click(object? sender, EventArgs e)
{
_client.Restart();
_m3U8FolderSync.InvalidateAll();
SimpleProgressForm.Do(
ProgressForm.Do(
this,
"Synchronizing network sharing folder...",
(updateProgress, cancel) =>
Expand Down Expand Up @@ -1146,7 +1146,6 @@ private void MovieContextPropertiesButton_Click(object? sender, EventArgs e)
private void ShowTagContextMenu(IEnumerable<TagId> tagIds)
{
//TODO
throw new NotImplementedException();
}

private void OpenMovie(MovieId movieId)
Expand Down Expand Up @@ -1208,8 +1207,8 @@ private void OpenMovie(MovieId movieId)
return;
#endif

using var p = Process.Start(psi)!;
ApplicationSubProcesses.Add(p);
using VlcLaunchProgressForm f = new(psi);
f.ShowDialog(this);

static bool IsVlcInstalled()
{
Expand Down Expand Up @@ -1265,7 +1264,7 @@ private void DeleteMovies(List<MovieId> movieIds)

try
{
using SimpleProgressForm f =
using ProgressForm f =
new(
(updateProgress, updateMessage, cancel) =>
{
Expand Down Expand Up @@ -1349,7 +1348,7 @@ private void MovieContextExportButton_Click(object? sender, EventArgs e)

var movies = _libraryProvider.GetMovies().ToDictionary(x => x.Id);

using SimpleProgressForm f =
using ProgressForm f =
new(
(updateProgress, updateMessage, cancel) =>
{
Expand Down
2 changes: 1 addition & 1 deletion src/J.App/MoviePropertiesForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ private void OkButton_Click(object? sender, EventArgs e)
foreach (DataRow row in _tagsTable.Rows)
tagIds.Add((TagId)row["tag_id"]);

SimpleProgressForm.Do(
ProgressForm.Do(
this,
"Saving changes...",
async (updateProgress, cancel) =>
Expand Down
2 changes: 1 addition & 1 deletion src/J.App/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private void ShowConnectForm()
Try(
() =>
{
SimpleProgressForm f =
ProgressForm f =
new(
(updateProgress, updateMessage, cancel) =>
{
Expand Down
6 changes: 3 additions & 3 deletions src/J.App/SimpleProgressForm.cs → src/J.App/ProgressForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace J.App;

public sealed class SimpleProgressForm : Form
public sealed class ProgressForm : Form
{
private readonly CancellationTokenSource _cts = new();
private readonly TableLayoutPanel _table;
Expand All @@ -29,7 +29,7 @@ public static void Do(IWin32Window owner, string text, Func<Action<double>, Canc

public static void Do(IWin32Window owner, string text, Action<Action<double>, CancellationToken> action)
{
using SimpleProgressForm f =
using ProgressForm f =
new(
(updateProgress, updateMessage, cancel) =>
{
Expand All @@ -44,7 +44,7 @@ public static void Do(IWin32Window owner, string text, Action<Action<double>, Ca
f.Exception!.Throw();
}

public SimpleProgressForm(WorkDelegate action)
public ProgressForm(WorkDelegate action)
{
Ui ui = new(this);

Expand Down
2 changes: 1 addition & 1 deletion src/J.App/TagForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ private void SaveButton_Click(object? sender, EventArgs e)
if (string.IsNullOrWhiteSpace(_nameTextBox.Text))
throw new Exception("Please enter a name.");

SimpleProgressForm.Do(
ProgressForm.Do(
this,
"Saving tag...",
async (updateProgress, cancel) =>
Expand Down
4 changes: 2 additions & 2 deletions src/J.App/TagTypeForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private void OkButton_Click(object? sender, EventArgs e)
{
var tagType = new TagType(new(), 0, singular, plural);

SimpleProgressForm.Do(
ProgressForm.Do(
this,
"Creating tag group...",
async (updateProgress, cancel) =>
Expand All @@ -110,7 +110,7 @@ private void OkButton_Click(object? sender, EventArgs e)
{
var newTagType = _tagType.Value with { SingularName = singular, PluralName = plural };

SimpleProgressForm.Do(
ProgressForm.Do(
this,
"Renaming tag group...",
async (updateProgress, cancel) =>
Expand Down
6 changes: 3 additions & 3 deletions src/J.App/TagsControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ private void MoveTagType(int direction)
tagTypes[i] = tagTypes[i] with { SortIndex = i };
}

SimpleProgressForm.Do(
ProgressForm.Do(
FindForm()!,
"Moving tag group...",
async (updateProgress, cancel) =>
Expand All @@ -408,7 +408,7 @@ private void LeftDeleteGroupButton_Click(object? sender, EventArgs e)
if (response != DialogResult.OK)
return;

SimpleProgressForm.Do(
ProgressForm.Do(
FindForm()!,
"Deleting tag group...",
async (updateProgress, cancel) =>
Expand Down Expand Up @@ -472,7 +472,7 @@ private void RightDeleteTagButton_Click(object? sender, EventArgs e)

try
{
SimpleProgressForm.Do(
ProgressForm.Do(
FindForm()!,
"Deleting...",
async (updateProgress, cancel) =>
Expand Down
150 changes: 150 additions & 0 deletions src/J.App/VlcLaunchProgressForm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using J.Base;

namespace J.App;

public sealed partial class VlcLaunchProgressForm : Form
{
private readonly FlowLayoutPanel _flow;
private readonly Label _label;
private readonly ProgressBar _progressBar;
private readonly ProcessStartInfo _psi;

public VlcLaunchProgressForm(ProcessStartInfo psi)
{
_psi = psi;
Ui ui = new(this);

Controls.Add(_flow = ui.NewFlowColumn());
{
_flow.Padding = ui.DefaultPadding;

_flow.Controls.Add(_label = ui.NewLabel("Opening movie..."));
{
_label.Margin += ui.BottomSpacingBig;
}

_flow.Controls.Add(_progressBar = ui.NewProgressBar(300));
{
_progressBar.Style = ProgressBarStyle.Marquee;
_progressBar.MarqueeAnimationSpeed = 10;
}
}

Text = "VLC";
StartPosition = FormStartPosition.CenterScreen;
AutoSize = true;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
FormBorderStyle = FormBorderStyle.Fixed3D;
ControlBox = false;
MinimizeBox = false;
MaximizeBox = false;
ShowIcon = false;
ShowInTaskbar = false;
}

protected override async void OnShown(EventArgs e)
{
base.OnShown(e);

try
{
await Task.Run(() =>
{
using var p = Process.Start(_psi)!;
ApplicationSubProcesses.Add(p);
WaitForWindow(p, TimeSpan.FromSeconds(10));
})
.ConfigureAwait(true);

Close();
}
catch (Exception ex)
{
MessageBox.Show(
"Unable to launch VLC.\n\n" + ex.Message,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
Close();
}
}

private static void WaitForWindow(Process process, TimeSpan timeout)
{
ArgumentNullException.ThrowIfNull(process);

if (process.HasExited)
return;

var sw = Stopwatch.StartNew();

while (sw.Elapsed < timeout)
{
if (HasVisibleWindow(process))
return;

Thread.Sleep(100);
}
}

private static bool HasVisibleWindow(Process process)
{
try
{
// Refresh the process info to get the current threads
process.Refresh();

// Check each thread in the process
foreach (ProcessThread thread in process.Threads)
{
bool found = false;

// Enumerate windows for this thread
NativeMethods.EnumThreadWindows(
(uint)thread.Id,
(hWnd, lParam) =>
{
if (NativeMethods.IsWindowVisible(hWnd))
{
found = true;
return false; // Stop enumeration
}
return true; // Continue enumeration
},
IntPtr.Zero
);

if (found)
return true;
}
}
catch (InvalidOperationException)
{
// Process has exited or access was denied
return false;
}
catch (Exception)
{
// Handle any other unexpected errors gracefully
return false;
}

return false;
}

private static partial class NativeMethods
{
public delegate bool EnumThreadWindowsProc(IntPtr hWnd, IntPtr lParam);

[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool EnumThreadWindows(uint threadId, EnumThreadWindowsProc enumFunc, IntPtr lParam);

[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool IsWindowVisible(IntPtr hWnd);
}
}

0 comments on commit 1f18e68

Please sign in to comment.