Elias pc->laptop
This commit is contained in:
@@ -123,9 +123,9 @@
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Bottom" Background="#222" KeyboardNavigation.DirectionalNavigation="None">
|
||||
<TextBlock Name="title" Text="Titel" Foreground="White" FontSize="16" Margin="10"/>
|
||||
<Button Content="⏮" Width="40" Margin="10" TabIndex="10" Focusable="True" Click="OnItemPriorButtonClick"/>
|
||||
<Button Name="prior" Content="⏮" Width="40" Margin="10" TabIndex="10" Focusable="True" Click="OnItemPriorButtonClick"/>
|
||||
<Button Content="▶" Width="40" Margin="10" TabIndex="11" Focusable="True" Click="OnItemPauseBtn_Click"/>
|
||||
<Button Content="⏭" Width="40" Margin="10" TabIndex="12" Focusable="True" Click="OnItemNextButtonClick"/>
|
||||
<Button Name="next" Content="⏭" Width="40" Margin="10" TabIndex="12" Focusable="True" Click="OnItemNextButtonClick"/>
|
||||
<TextBlock Text="🔊" Foreground="White" VerticalAlignment="Center" Margin="10,0"/>
|
||||
<Slider Name="vol" Width="100" Minimum="0" Maximum="100" Value="50" Margin="10"
|
||||
TabIndex="13" Focusable="True" ValueChanged="RangeBase_OnValueChanged"/>
|
||||
|
@@ -59,7 +59,7 @@ public partial class MainWindow : Window
|
||||
List<string> dirs = new List<string>();
|
||||
private int option = 2;
|
||||
int specificOption = 0;
|
||||
string rootPath = "G:/";
|
||||
string rootPath = "M:/Media";
|
||||
|
||||
FileScanner fileScanner;
|
||||
|
||||
@@ -123,7 +123,7 @@ public partial class MainWindow : Window
|
||||
#endregion
|
||||
|
||||
#region BlutuethLogic
|
||||
InitBluetoothServer();
|
||||
//InitBluetoothServer();
|
||||
#endregion
|
||||
|
||||
#region only exdend. no remuving of code
|
||||
@@ -255,7 +255,8 @@ public partial class MainWindow : Window
|
||||
VideoView.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private async void scanButton_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
private async void scanButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -299,68 +300,142 @@ public partial class MainWindow : Window
|
||||
log.Log($"photoFiles count: {photoFiles.Count}");
|
||||
log.Log($"series count: {series.Count}");
|
||||
log.Log($"movies count: {movies.Count}");
|
||||
|
||||
progressScann = new ProgressBar("ImageGen",musicFiles.Count + videoFiles.Count + photoFiles.Count);
|
||||
|
||||
progressScann = new ProgressBar("ImageGen", musicFiles.Count + videoFiles.Count + photoFiles.Count);
|
||||
progressScann.Show();
|
||||
videoFiles = null;
|
||||
|
||||
log.Log("files sorted");
|
||||
|
||||
// Prepare JSON lists
|
||||
List<locJason> muviesJS = new List<locJason>();
|
||||
List<locJason> seriesJS = new List<locJason>();
|
||||
List<locJason> photosJS = new List<locJason>();
|
||||
List<locJason> mucicJS = new List<locJason>();
|
||||
List<locJason> musicJS = new List<locJason>();
|
||||
|
||||
JasonToString jasonToString = new JasonToString();
|
||||
|
||||
// Use async ItemCreaterAsync
|
||||
var movieItems = await ItemCreater(movies, "Muvie", false);
|
||||
foreach (var VARIABLE in movieItems)
|
||||
foreach (var item in movieItems)
|
||||
{
|
||||
Muvie.addItem(VARIABLE);
|
||||
muviesJS.Add(new locJason
|
||||
BitmapImage bitmapImage = item.getImage();
|
||||
if (bitmapImage != null)
|
||||
{
|
||||
path = VARIABLE.getLink(),
|
||||
imageData = jasonToString.BitmapToBase64String(BitmapConversions.BitmapImageToBitmap(VARIABLE.getImage())),
|
||||
type = VARIABLE.getType()
|
||||
});
|
||||
try
|
||||
{
|
||||
string base64Image = jasonToString.BitmapToBase64String(
|
||||
BitmapConversions.BitmapImageToBitmap(bitmapImage));
|
||||
Muvie.addItem(item);
|
||||
muviesJS.Add(new locJason
|
||||
{
|
||||
path = item.getLink(),
|
||||
imageData = base64Image,
|
||||
type = item.getType()
|
||||
});
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Console.WriteLine($"Error processing movie item {item.getLink()}: {exception.Message}");
|
||||
log.Error($"Error processing movie item {item.getLink()}: {exception}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Warning: Movie item {item.getLink()} has no image data.");
|
||||
log.Log($"Warning: Movie item {item.getLink()} has no image data.");
|
||||
}
|
||||
}
|
||||
|
||||
var seriesItems = await ItemCreater(series, "Serie", false);
|
||||
foreach (var VARIABLE in seriesItems)
|
||||
foreach (var item in seriesItems)
|
||||
{
|
||||
Serie.addItem(VARIABLE);
|
||||
seriesJS.Add(new locJason
|
||||
BitmapImage bitmapImage = item.getImage();
|
||||
if (bitmapImage != null)
|
||||
{
|
||||
path = VARIABLE.getLink(),
|
||||
imageData = jasonToString.BitmapToBase64String(BitmapConversions.BitmapImageToBitmap(VARIABLE.getImage())),
|
||||
type = VARIABLE.getType()
|
||||
});
|
||||
try
|
||||
{
|
||||
string base64Image = jasonToString.BitmapToBase64String(
|
||||
BitmapConversions.BitmapImageToBitmap(bitmapImage));
|
||||
Serie.addItem(item);
|
||||
seriesJS.Add(new locJason
|
||||
{
|
||||
path = item.getLink(),
|
||||
imageData = base64Image,
|
||||
type = item.getType()
|
||||
});
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Console.WriteLine($"Error processing series item {item.getLink()}: {exception.Message}");
|
||||
log.Error($"Error processing series item {item.getLink()}: {exception}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Warning: Series item {item.getLink()} has no image data.");
|
||||
log.Log($"Warning: Series item {item.getLink()} has no image data.");
|
||||
}
|
||||
}
|
||||
|
||||
var photoItems = await ItemCreater(photoFiles, "Photo", true);
|
||||
foreach (var VARIABLE in photoItems)
|
||||
foreach (var item in photoItems)
|
||||
{
|
||||
Photo.addItem(VARIABLE);
|
||||
photosJS.Add(new locJason
|
||||
BitmapImage bitmapImage = item.getImage();
|
||||
if (bitmapImage != null)
|
||||
{
|
||||
path = VARIABLE.getLink(),
|
||||
imageData = jasonToString.BitmapToBase64String(BitmapConversions.BitmapImageToBitmap(VARIABLE.getImage())),
|
||||
type = VARIABLE.getType()
|
||||
});
|
||||
try
|
||||
{
|
||||
string base64Image = jasonToString.BitmapToBase64String(
|
||||
BitmapConversions.BitmapImageToBitmap(bitmapImage));
|
||||
Photo.addItem(item);
|
||||
photosJS.Add(new locJason
|
||||
{
|
||||
path = item.getLink(),
|
||||
imageData = base64Image,
|
||||
type = item.getType()
|
||||
});
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Console.WriteLine($"Error processing photo item {item.getLink()}: {exception.Message}");
|
||||
log.Error($"Error processing photo item {item.getLink()}: {exception}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Warning: Photo item {item.getLink()} has no image data.");
|
||||
log.Log($"Warning: Photo item {item.getLink()} has no image data.");
|
||||
}
|
||||
}
|
||||
|
||||
var musicItems = await ItemCreater(musicFiles, "Music", false, true);
|
||||
foreach (var VARIABLE in musicItems)
|
||||
var musicItems = await ItemCreater(musicFiles, "Music", false);
|
||||
foreach (var item in musicItems)
|
||||
{
|
||||
Music.addItem(VARIABLE);
|
||||
mucicJS.Add(new locJason
|
||||
BitmapImage bitmapImage = item.getImage();
|
||||
if (bitmapImage != null)
|
||||
{
|
||||
path = VARIABLE.getLink(),
|
||||
imageData = jasonToString.BitmapToBase64String(BitmapConversions.BitmapImageToBitmap(VARIABLE.getImage())),
|
||||
type = VARIABLE.getType()
|
||||
});
|
||||
try
|
||||
{
|
||||
string base64Image = jasonToString.BitmapToBase64String(
|
||||
BitmapConversions.BitmapImageToBitmap(bitmapImage));
|
||||
Music.addItem(item);
|
||||
musicJS.Add(new locJason
|
||||
{
|
||||
path = item.getLink(),
|
||||
imageData = base64Image,
|
||||
type = item.getType()
|
||||
});
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Console.WriteLine($"Error processing music item {item.getLink()}: {exception.Message}");
|
||||
log.Error($"Error processing music item {item.getLink()}: {exception}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Info: Music item {item.getLink()} has no image data.");
|
||||
log.Log($"Info: Music item {item.getLink()} has no image data.");
|
||||
}
|
||||
}
|
||||
|
||||
log.Log("scan finished");
|
||||
@@ -371,13 +446,12 @@ public partial class MainWindow : Window
|
||||
jason_Writer.SaveList("Muvies", muviesJS),
|
||||
jason_Writer.SaveList("Series", seriesJS),
|
||||
jason_Writer.SaveList("Photos", photosJS),
|
||||
jason_Writer.SaveList("Music", mucicJS)
|
||||
jason_Writer.SaveList("Music", musicJS)
|
||||
};
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
// Clear lists to free memory
|
||||
mucicJS = null;
|
||||
musicJS = null;
|
||||
seriesJS = null;
|
||||
photosJS = null;
|
||||
|
||||
@@ -387,7 +461,7 @@ public partial class MainWindow : Window
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"An error occurred during scanning:\n\n{ex}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
MessageBox.Show($"An error occurred during scanning:\n\n{ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
log.Error($"An error occurred during scanning:\n\n{ex}");
|
||||
}
|
||||
}
|
||||
@@ -428,6 +502,7 @@ public partial class MainWindow : Window
|
||||
ScrollContentCat.Visibility = Visibility.Collapsed;
|
||||
ScrollContentHome.Visibility = Visibility.Visible;
|
||||
MenueItems();
|
||||
SetInitialFocusForCurrentView();
|
||||
}
|
||||
private void Musik_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -439,6 +514,7 @@ public partial class MainWindow : Window
|
||||
ScrollContentCat.Visibility = Visibility.Visible;
|
||||
Name_of_Catagory1.Visibility = Visibility.Collapsed;
|
||||
MenueItems(ref Music);
|
||||
SetInitialFocusForCurrentView();
|
||||
}
|
||||
private void Photo_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -450,6 +526,7 @@ public partial class MainWindow : Window
|
||||
ScrollContentCat.Visibility = Visibility.Visible;
|
||||
Name_of_Catagory1.Visibility = Visibility.Collapsed;
|
||||
MenueItems(ref Photo);
|
||||
SetInitialFocusForCurrentView();
|
||||
}
|
||||
private void Video_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -460,6 +537,7 @@ public partial class MainWindow : Window
|
||||
ScrollContentCat.Visibility = Visibility.Visible;
|
||||
Name_of_Catagory1.Visibility = Visibility.Visible;
|
||||
MenueItems(ref Muvie,ref Serie);
|
||||
SetInitialFocusForCurrentView();
|
||||
}
|
||||
private void PlayListButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -471,6 +549,8 @@ public partial class MainWindow : Window
|
||||
Name_of_Catagory1.Visibility = Visibility.Collapsed;
|
||||
|
||||
PopulateAllCategoriesFromPlaylists(); // <-- This needs to set ScrollContentPlaylist visible
|
||||
|
||||
SetInitialFocusForCurrentView();
|
||||
}
|
||||
|
||||
|
||||
@@ -480,51 +560,18 @@ public partial class MainWindow : Window
|
||||
|
||||
#region itemCreation
|
||||
|
||||
async Task<List<Item>> ItemCreater(List<string> paths, string type, bool isFoto)
|
||||
{
|
||||
var semaphore = new SemaphoreSlim(Math.Max(1, Environment.ProcessorCount / 2));
|
||||
var tasks = paths.Select(async path =>
|
||||
{
|
||||
await semaphore.WaitAsync();
|
||||
try
|
||||
{
|
||||
BitmapImage frame200 = null;
|
||||
|
||||
if (!isFoto)
|
||||
{
|
||||
frame200 = await Task.Run(() => VideoFrameExtractor.GetFrame200(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
frame200 = new BitmapImage(new Uri(path, UriKind.Absolute));
|
||||
frame200.DecodePixelWidth = 150;
|
||||
frame200.DecodePixelHeight = 100;
|
||||
});
|
||||
}
|
||||
Application.Current.Dispatcher.Invoke(() => progressScann.UpdateProgress(1));
|
||||
return new Item(path, type, frame200, isFoto, OnItemPlayButtonClick);
|
||||
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release();
|
||||
}
|
||||
}).ToList();
|
||||
|
||||
return (await Task.WhenAll(tasks)).ToList();
|
||||
}
|
||||
public async Task<List<Item>> ItemCreater(List<string> paths, string type, bool isFoto, bool isMusic = false)
|
||||
public async Task<List<Item>> ItemCreater(List<string> paths, string type, bool isFoto)
|
||||
{
|
||||
var itemsBag = new ConcurrentBag<Item>();
|
||||
var workQueue = new ConcurrentQueue<string>(paths);
|
||||
int maxWorkers = Math.Max(1, Environment.ProcessorCount / 2);
|
||||
var workers = new List<Task>();
|
||||
// Determine if it's music based on 'type' string
|
||||
bool isMusic = (type == "Music");
|
||||
|
||||
// Prepare default image for music if needed
|
||||
BitmapImage defaultImage = null;
|
||||
// Semaphore for concurrency control
|
||||
var semaphore = new SemaphoreSlim(Math.Max(1, Environment.ProcessorCount / 2));
|
||||
// ConcurrentBag for thread-safe collection of items
|
||||
var itemsBag = new ConcurrentBag<Item>();
|
||||
|
||||
// Pre-load default music image once, if applicable
|
||||
BitmapImage defaultMusicImage = null;
|
||||
if (isMusic)
|
||||
{
|
||||
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
@@ -532,85 +579,147 @@ public partial class MainWindow : Window
|
||||
|
||||
if (System.IO.File.Exists(imagePath))
|
||||
{
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
try
|
||||
{
|
||||
defaultImage = new BitmapImage(new Uri(imagePath));
|
||||
defaultImage.DecodePixelWidth = 150;
|
||||
defaultImage.DecodePixelHeight = 100;
|
||||
defaultImage.Freeze();
|
||||
});
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
defaultMusicImage = new BitmapImage(new Uri(imagePath));
|
||||
defaultMusicImage.DecodePixelWidth = 150;
|
||||
defaultMusicImage.DecodePixelHeight = 100;
|
||||
defaultMusicImage.Freeze(); // Crucial for cross-thread access
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log error if default image itself cannot be loaded
|
||||
Console.WriteLine($"Error loading default music image {imagePath}: {ex.Message}");
|
||||
// Consider adding to your specific logger here: log.Error(...)
|
||||
defaultMusicImage = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show($"Default image not found at: {imagePath}");
|
||||
// Inform the user if the default image is missing
|
||||
MessageBox.Show($"Default music image not found at: {imagePath}");
|
||||
// Consider adding to your specific logger here: log.Error(...)
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxWorkers; i++)
|
||||
// Create a list of tasks, one for each path
|
||||
var tasks = paths.Select(async path =>
|
||||
{
|
||||
workers.Add(Task.Run(async () =>
|
||||
{
|
||||
while (workQueue.TryDequeue(out var filePath))
|
||||
{
|
||||
BitmapImage bitmapImage = null;
|
||||
await semaphore.WaitAsync(); // Acquire a slot from the semaphore
|
||||
BitmapImage bitmapImage = null; // To hold the image for the current item
|
||||
Item newItem = null; // The Item object to be created
|
||||
|
||||
try
|
||||
{
|
||||
if (isMusic) // Logic for Music files: extract album art or use default
|
||||
{
|
||||
bitmapImage = defaultMusicImage; // Start with the default image
|
||||
|
||||
TagLib.File file = null; // TagLib.File object for disposing
|
||||
try
|
||||
{
|
||||
if (isMusic)
|
||||
file = TagLib.File.Create(path); // Create TagLib file instance
|
||||
if (file.Tag.Pictures.Length > 0) // Check if album art exists
|
||||
{
|
||||
bitmapImage = defaultImage;
|
||||
var pic = file.Tag.Pictures[0];
|
||||
var ms = new System.IO.MemoryStream(pic.Data.Data); // Get image data as MemoryStream
|
||||
|
||||
try
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
var file = TagLib.File.Create(filePath);
|
||||
if (file.Tag.Pictures.Length > 0)
|
||||
{
|
||||
var pic = file.Tag.Pictures[0];
|
||||
var ms = new System.IO.MemoryStream(pic.Data.Data);
|
||||
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
var img = new BitmapImage();
|
||||
img.BeginInit();
|
||||
img.CacheOption = BitmapCacheOption.OnLoad;
|
||||
ms.Position = 0;
|
||||
img.StreamSource = ms;
|
||||
img.EndInit();
|
||||
img.Freeze();
|
||||
img.DecodePixelWidth = 150;
|
||||
img.DecodePixelHeight = 100;
|
||||
bitmapImage = img;
|
||||
});
|
||||
|
||||
ms.Dispose();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// keep defaultImage on failure
|
||||
}
|
||||
var img = new BitmapImage();
|
||||
img.BeginInit();
|
||||
img.CacheOption = BitmapCacheOption.OnLoad; // Load full image data
|
||||
ms.Position = 0; // Reset stream position
|
||||
img.StreamSource = ms; // Set image source from stream
|
||||
img.EndInit();
|
||||
img.Freeze(); // Make immutable for performance
|
||||
img.DecodePixelWidth = 150;
|
||||
img.DecodePixelHeight = 100;
|
||||
bitmapImage = img; // Overwrite default with extracted cover
|
||||
});
|
||||
ms.Dispose(); // Dispose MemoryStream
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception tagLibEx)
|
||||
{
|
||||
// fallback: bitmapImage stays null or default
|
||||
// Catch errors during TagLib processing (e.g., corrupted file, unsupported format)
|
||||
Console.WriteLine($"Error extracting album art for {path}: {tagLibEx.Message}");
|
||||
// Consider adding to your specific logger here: log.Error(...)
|
||||
// bitmapImage remains defaultMusicImage or null if default also failed
|
||||
}
|
||||
|
||||
// Create Item on UI thread because it creates UI controls internally
|
||||
Item newItem = null;
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
finally
|
||||
{
|
||||
newItem = new Item(filePath, type, bitmapImage, isFoto, OnItemPlayButtonClick);
|
||||
});
|
||||
|
||||
itemsBag.Add(newItem);
|
||||
Application.Current.Dispatcher.Invoke(() => progressScann.UpdateProgress(1));
|
||||
file?.Dispose(); // Ensure TagLib.File is disposed to release file locks
|
||||
}
|
||||
}
|
||||
else if (isFoto) // Logic for Photo files: direct image loading
|
||||
{
|
||||
try
|
||||
{
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
bitmapImage = new BitmapImage();
|
||||
bitmapImage.BeginInit();
|
||||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad; // Load full image data
|
||||
bitmapImage.UriSource = new Uri(path, UriKind.Absolute); // Set URI source
|
||||
bitmapImage.DecodePixelWidth = 150;
|
||||
bitmapImage.DecodePixelHeight = 100;
|
||||
bitmapImage.EndInit();
|
||||
bitmapImage.Freeze(); // Make immutable
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Catch errors during photo image loading
|
||||
Console.WriteLine($"Error loading photo image {path}: {ex.Message}");
|
||||
// Consider adding to your specific logger here: log.Error(...)
|
||||
bitmapImage = null; // Set image to null on failure
|
||||
}
|
||||
}
|
||||
else // Logic for Video files: using VideoFrameExtractor
|
||||
{
|
||||
// VideoFrameExtractor.GetFrame200 should return null on failure (as previously discussed)
|
||||
bitmapImage = await Task.Run(() => VideoFrameExtractor.GetFrame200(path));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
await Task.WhenAll(workers);
|
||||
// Create the Item object on the UI thread
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
// newItem will have the extracted image, default image, or null if all failed
|
||||
newItem = new Item(path, type, bitmapImage, isFoto, OnItemPlayButtonClick);
|
||||
});
|
||||
|
||||
itemsBag.Add(newItem); // Add the created item to the thread-safe bag
|
||||
Application.Current.Dispatcher.Invoke(() => progressScann.UpdateProgress(1)); // Update progress on UI thread
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Catch any unexpected exceptions during the processing of a single item
|
||||
Console.WriteLine($"Unexpected error processing item {path}: {ex.Message}");
|
||||
// Consider adding to your specific logger here: log.Error(...)
|
||||
|
||||
// Create a fallback Item with a null image to ensure the task completes
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
newItem = new Item(path, type, null, isFoto, OnItemPlayButtonClick);
|
||||
});
|
||||
itemsBag.Add(newItem); // Add this fallback item
|
||||
Application.Current.Dispatcher.Invoke(() => progressScann.UpdateProgress(1)); // Still update progress
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release(); // Release the semaphore slot regardless of success or failure
|
||||
}
|
||||
return newItem; // Return the processed item (can have null image)
|
||||
}).ToList(); // Convert the collection of tasks to a List<Task<Item>>
|
||||
|
||||
// Wait for all individual item processing tasks to complete
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
// Convert the ConcurrentBag to a List and return
|
||||
return itemsBag.ToList();
|
||||
}
|
||||
|
||||
@@ -874,21 +983,134 @@ public partial class MainWindow : Window
|
||||
MessageBox.Show($"📨 Message: {msg.Trim()}");
|
||||
switch (msg.Trim())
|
||||
{
|
||||
//arrow up
|
||||
case "\u2191": MessageBox.Show("case 1"); break;
|
||||
//arrow down
|
||||
case "\u2193": MessageBox.Show("case 2"); break;
|
||||
//arrow left
|
||||
//arrow right
|
||||
//double left
|
||||
//double right
|
||||
//enter
|
||||
//home
|
||||
//vol +
|
||||
//vol -
|
||||
//mute
|
||||
//time stamp
|
||||
}
|
||||
// Arrow Up
|
||||
case "↑": // \u2191
|
||||
var keyEventArgs = new KeyEventArgs(
|
||||
Keyboard.PrimaryDevice,
|
||||
PresentationSource.FromVisual(this),
|
||||
0,
|
||||
Key.Up) // simulate pressing the "A" key
|
||||
{
|
||||
RoutedEvent = Keyboard.PreviewKeyDownEvent
|
||||
};
|
||||
|
||||
this.RaiseEvent(keyEventArgs);
|
||||
break;
|
||||
|
||||
// Arrow Down
|
||||
case "↓": // \u2193
|
||||
var keyEventArgs2 = new KeyEventArgs(
|
||||
Keyboard.PrimaryDevice,
|
||||
PresentationSource.FromVisual(this),
|
||||
0,
|
||||
Key.Down) // simulate pressing the "A" key
|
||||
{
|
||||
RoutedEvent = Keyboard.PreviewKeyDownEvent
|
||||
};
|
||||
|
||||
this.RaiseEvent(keyEventArgs2);
|
||||
break;
|
||||
|
||||
// Arrow Left
|
||||
case "←": // \u2190
|
||||
var keyEventArgs3 = new KeyEventArgs(
|
||||
Keyboard.PrimaryDevice,
|
||||
PresentationSource.FromVisual(this),
|
||||
0,
|
||||
Key.Left) // simulate pressing the "A" key
|
||||
{
|
||||
RoutedEvent = Keyboard.PreviewKeyDownEvent
|
||||
};
|
||||
|
||||
this.RaiseEvent(keyEventArgs3);
|
||||
break;
|
||||
|
||||
// Arrow Right
|
||||
case "→": // \u2192
|
||||
var keyEventArgs4 = new KeyEventArgs(
|
||||
Keyboard.PrimaryDevice,
|
||||
PresentationSource.FromVisual(this),
|
||||
0,
|
||||
Key.Right) // simulate pressing the "A" key
|
||||
{
|
||||
RoutedEvent = Keyboard.PreviewKeyDownEvent
|
||||
};
|
||||
|
||||
this.RaiseEvent(keyEventArgs4);
|
||||
break;
|
||||
|
||||
// Double Left
|
||||
case "⇚": // \u21DA
|
||||
var clickEventArgs1 = new RoutedEventArgs(Button.ClickEvent);
|
||||
prior.RaiseEvent(clickEventArgs1);
|
||||
break;
|
||||
|
||||
// Double Right
|
||||
case "⇛": // \u21DB
|
||||
var clickEventArgs2 = new RoutedEventArgs(Button.ClickEvent);
|
||||
next.RaiseEvent(clickEventArgs2);
|
||||
|
||||
break;
|
||||
|
||||
// Center button (Dot)
|
||||
case "●": // \u25CF
|
||||
if (_mediaPlayer.IsPlaying)
|
||||
{
|
||||
var keyEventArgs5 = new KeyEventArgs(
|
||||
Keyboard.PrimaryDevice,
|
||||
PresentationSource.FromVisual(this),
|
||||
0,
|
||||
Key.Space) // simulate pressing the "A" key
|
||||
{
|
||||
RoutedEvent = Keyboard.PreviewKeyDownEvent
|
||||
};
|
||||
|
||||
this.RaiseEvent(keyEventArgs5);
|
||||
}
|
||||
else
|
||||
{
|
||||
var keyEventArgs5 = new KeyEventArgs(
|
||||
Keyboard.PrimaryDevice,
|
||||
PresentationSource.FromVisual(this),
|
||||
0,
|
||||
Key.Enter) // simulate pressing the "A" key
|
||||
{
|
||||
RoutedEvent = Keyboard.PreviewKeyDownEvent
|
||||
};
|
||||
|
||||
this.RaiseEvent(keyEventArgs5);
|
||||
}
|
||||
break;
|
||||
case "Vol -":
|
||||
if(_mediaPlayer.Volume>10)
|
||||
_mediaPlayer.Volume = _mediaPlayer.Volume - 10;
|
||||
else
|
||||
_mediaPlayer.Volume = 10;
|
||||
vol.Value = _mediaPlayer.Volume;
|
||||
break;
|
||||
case "Vol +":
|
||||
if(_mediaPlayer.Volume<90)
|
||||
_mediaPlayer.Volume = _mediaPlayer.Volume + 10;
|
||||
else
|
||||
_mediaPlayer.Volume = 100;
|
||||
vol.Value = _mediaPlayer.Volume;
|
||||
break;
|
||||
case string s when s.StartsWith("Time:"):
|
||||
string valuePart = s.Substring("Time:".Length);
|
||||
if (double.TryParse(valuePart, out double timeValue))
|
||||
{
|
||||
_mediaPlayer.Time= Convert.ToInt32(valuePart);;
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Invalid time format.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MessageBox.Show($"Unrecognized input: '{msg}'");
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -1317,7 +1539,8 @@ public partial class MainWindow : Window
|
||||
{
|
||||
itemProgress.Value = timeStap/1000;
|
||||
itemProgressVisual.Value = itemProgress.Value;
|
||||
Server1.SendMessage("Progress="+itemProgress.Value);
|
||||
if(Server1!=null)
|
||||
Server1.SendMessage("Progress="+itemProgress.Value);
|
||||
}
|
||||
private void ProgressBarValueChange()
|
||||
{
|
||||
@@ -1413,13 +1636,14 @@ public partial class MainWindow : Window
|
||||
|
||||
#endregion
|
||||
|
||||
#region arrow nav
|
||||
#region arrow nav
|
||||
private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (Keyboard.FocusedElement is not DependencyObject focusedElement)
|
||||
return;
|
||||
|
||||
var wrapPanel = FindAncestor<WrapPanel>(focusedElement);
|
||||
var stackPanel = FindAncestor<StackPanel>(focusedElement);
|
||||
|
||||
if (wrapPanel != null && wrapPanel.Children.Count > 0)
|
||||
{
|
||||
@@ -1450,81 +1674,121 @@ private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
|
||||
case Key.Up:
|
||||
e.Handled = true;
|
||||
if (focusedIndex < columns)
|
||||
{
|
||||
if (stackPanel != null)
|
||||
{
|
||||
int currentWrapPanelIndex = stackPanel.Children.IndexOf(wrapPanel);
|
||||
if (currentWrapPanelIndex > 0)
|
||||
{
|
||||
for (int i = currentWrapPanelIndex - 1; i >= 0; i--)
|
||||
{
|
||||
if (stackPanel.Children[i] is WrapPanel prevWrapPanel && prevWrapPanel.Children.Count > 0)
|
||||
{
|
||||
int targetIndexInPrev = Math.Min(prevWrapPanel.Children.Count - 1, focusedIndex + ((prevWrapPanel.Children.Count / columns) * columns));
|
||||
MoveFocusInWrapPanel(prevWrapPanel, targetIndexInPrev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MoveFocusInWrapPanel(wrapPanel, focusedIndex - columns);
|
||||
break;
|
||||
|
||||
case Key.Down:
|
||||
e.Handled = true;
|
||||
if (focusedIndex >= wrapPanel.Children.Count - columns)
|
||||
{
|
||||
if (stackPanel != null)
|
||||
{
|
||||
int currentWrapPanelIndex = stackPanel.Children.IndexOf(wrapPanel);
|
||||
if (currentWrapPanelIndex != -1 && currentWrapPanelIndex < stackPanel.Children.Count - 1)
|
||||
{
|
||||
for (int i = currentWrapPanelIndex + 1; i < stackPanel.Children.Count; i++)
|
||||
{
|
||||
if (stackPanel.Children[i] is WrapPanel nextWrapPanel && nextWrapPanel.Children.Count > 0)
|
||||
{
|
||||
int targetIndexInNext = Math.Min(columns - 1, nextWrapPanel.Children.Count - 1);
|
||||
MoveFocusInWrapPanel(nextWrapPanel, targetIndexInNext);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MoveFocusInWrapPanel(wrapPanel, focusedIndex + columns);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (FirstCat.IsFocused && e.Key == Key.Right)
|
||||
{
|
||||
// Find the first visible WrapPanel child in your current visible ScrollViewer
|
||||
e.Handled = true; // Always handle the key if we are trying to move from FirstCat
|
||||
var firstFocusable = FindFirstFocusableInVisibleWrapPanel();
|
||||
if (firstFocusable != null)
|
||||
{
|
||||
firstFocusable.Focus();
|
||||
e.Handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: Wenn kein spezifisches fokussierbares Element gefunden wurde, versuchen Sie, den ScrollViewer selbst zu fokussieren
|
||||
if (ScrollContentHome.Visibility == Visibility.Visible) ScrollContentHome.Focus();
|
||||
else if (ScrollContentCat.Visibility == Visibility.Visible) ScrollContentCat.Focus();
|
||||
else if (ScrollContentPlaylist.Visibility == Visibility.Visible) ScrollContentPlaylist.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finds the first focusable control in the first visible WrapPanel child of your main ScrollViewer content
|
||||
private Control FindFirstFocusableInVisibleWrapPanel()
|
||||
private Control FindFirstFocusableInVisibleWrapPanel()
|
||||
{
|
||||
ScrollViewer currentScrollViewer = null;
|
||||
|
||||
if (ScrollContentHome.Visibility == Visibility.Visible)
|
||||
{
|
||||
ScrollViewer currentScrollViewer = null;
|
||||
|
||||
if (ScrollContentHome.Visibility == Visibility.Visible)
|
||||
{
|
||||
currentScrollViewer = ScrollContentHome;
|
||||
}
|
||||
else if (ScrollContentCat.Visibility == Visibility.Visible)
|
||||
{
|
||||
currentScrollViewer = ScrollContentCat;
|
||||
}
|
||||
else if (ScrollContentPlaylist.Visibility == Visibility.Visible)
|
||||
{
|
||||
currentScrollViewer = ScrollContentPlaylist;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("No visible ScrollViewer found");
|
||||
return null;
|
||||
}
|
||||
|
||||
Panel mainPanel = currentScrollViewer.Content as Panel;
|
||||
if (mainPanel != null)
|
||||
{
|
||||
for (int i = 0; i < mainPanel.Children.Count; i++)
|
||||
{
|
||||
var child = mainPanel.Children[i];
|
||||
WrapPanel wp = child as WrapPanel;
|
||||
if (wp != null && wp.Visibility == Visibility.Visible && wp.Children.Count > 0)
|
||||
{
|
||||
Control firstFocusable = FindFirstFocusableChild(wp);
|
||||
if (firstFocusable != null)
|
||||
{
|
||||
return firstFocusable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("ScrollViewer content is not a Panel");
|
||||
}
|
||||
|
||||
Control fallback = FindFirstFocusableChild(currentScrollViewer.Content as DependencyObject);
|
||||
if (fallback != null)
|
||||
return fallback;
|
||||
|
||||
currentScrollViewer = ScrollContentHome;
|
||||
}
|
||||
else if (ScrollContentCat.Visibility == Visibility.Visible)
|
||||
{
|
||||
currentScrollViewer = ScrollContentCat;
|
||||
}
|
||||
else if (ScrollContentPlaylist.Visibility == Visibility.Visible)
|
||||
{
|
||||
currentScrollViewer = ScrollContentPlaylist;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("No visible ScrollViewer found");
|
||||
return null;
|
||||
}
|
||||
|
||||
Panel mainPanel = currentScrollViewer.Content as Panel;
|
||||
if (mainPanel != null)
|
||||
{
|
||||
for (int i = 0; i < mainPanel.Children.Count; i++)
|
||||
{
|
||||
var child = mainPanel.Children[i];
|
||||
WrapPanel wp = child as WrapPanel;
|
||||
if (wp != null && wp.Visibility == Visibility.Visible && wp.Children.Count > 0)
|
||||
{
|
||||
Control firstFocusable = FindFirstFocusableChild(wp);
|
||||
if (firstFocusable != null)
|
||||
{
|
||||
return firstFocusable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("ScrollViewer content is not a Panel");
|
||||
}
|
||||
|
||||
// ... rest of your helpers remain unchanged ...
|
||||
Control fallback = FindFirstFocusableChild(currentScrollViewer.Content as DependencyObject);
|
||||
if (fallback != null)
|
||||
return fallback;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int CalculateColumns(WrapPanel panel)
|
||||
{
|
||||
@@ -1534,7 +1798,7 @@ private int CalculateColumns(WrapPanel panel)
|
||||
if (firstChild == null) return 1;
|
||||
|
||||
double itemWidth = firstChild.ActualWidth + firstChild.Margin.Left + firstChild.Margin.Right;
|
||||
if (itemWidth <= 1) itemWidth = 150; // fallback
|
||||
if (itemWidth <= 1) itemWidth = 150;
|
||||
|
||||
double panelWidth = panel.ActualWidth;
|
||||
int columns = Math.Max(1, (int)(panelWidth / itemWidth));
|
||||
@@ -1545,14 +1809,22 @@ private bool IsLeftmostInRow(int index, int columns) => (index % columns) == 0;
|
||||
|
||||
private void MoveFocusInWrapPanel(WrapPanel panel, int index)
|
||||
{
|
||||
if (index < 0 || index >= panel.Children.Count) return;
|
||||
if (index < 0) index = 0;
|
||||
if (index >= panel.Children.Count) index = panel.Children.Count - 1;
|
||||
|
||||
if (panel.Children[index] is Control ctrl && ctrl.Focusable)
|
||||
{
|
||||
ctrl.Focus();
|
||||
ctrl.BringIntoView();
|
||||
}
|
||||
else if (panel.Children[index] is Panel container)
|
||||
{
|
||||
var focusable = FindFirstFocusableChild(container);
|
||||
focusable?.Focus();
|
||||
if (focusable != null)
|
||||
{
|
||||
focusable.Focus();
|
||||
focusable.BringIntoView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1606,6 +1878,26 @@ private static T FindAncestor<T>(DependencyObject child) where T : DependencyObj
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SetInitialFocusForCurrentView()
|
||||
{
|
||||
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input, new Action(() =>
|
||||
{
|
||||
Control firstFocusable = FindFirstFocusableInVisibleWrapPanel();
|
||||
if (firstFocusable != null)
|
||||
{
|
||||
firstFocusable.Focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ScrollContentHome.Visibility == Visibility.Visible) ScrollContentHome.Focus();
|
||||
else if (ScrollContentCat.Visibility == Visibility.Visible) ScrollContentCat.Focus();
|
||||
else if (ScrollContentPlaylist.Visibility == Visibility.Visible) ScrollContentPlaylist.Focus();
|
||||
}
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user