1611 lines
52 KiB
C#
1611 lines
52 KiB
C#
using file_finder__test;
|
|
using LibVLCSharp.Shared;
|
|
using ModuleManager.Modules;
|
|
using NotVPR_SideProjecktForVpr_FreeTime;
|
|
using ShadowStream;
|
|
using ShadowStream.LogHelper;
|
|
using ShadowStream.Modules;
|
|
using ShadowStream.Obejeckte;
|
|
using ShadowStream.ObjecktForJason;
|
|
using ShadowStream.Views;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.ObjectModel;
|
|
using System.Net.Mime;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Input;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using System.Windows.Threading;
|
|
using Brushes = System.Windows.Media.Brushes;
|
|
using Color = System.Windows.Media.Color;
|
|
using File = System.IO.File;
|
|
using Path = System.IO.Path;
|
|
using Point = System.Windows.Point;
|
|
|
|
|
|
namespace ModuleManager;
|
|
|
|
/// <summary>
|
|
/// Interaction logic for MainWindow.xaml
|
|
/// </summary>
|
|
//Quinn and Reda and Yazan
|
|
public partial class MainWindow : Window
|
|
{ //quinn
|
|
#region no dont cahnge
|
|
|
|
//adding base components used threw out the code
|
|
LogWindow logWin = new LogWindow(log.GetEntries());
|
|
static LogHelper log = new LogHelper();
|
|
|
|
PlaylistEditor popupWindow;
|
|
|
|
ObjListBP _playlists = new ObjListBP();
|
|
|
|
private Catagory Muvie = new Catagory("Muvie");
|
|
private Catagory Serie = new Catagory("Serie");
|
|
private Catagory Music = new Catagory("Music");
|
|
private Catagory Photo = new Catagory("Photos");
|
|
|
|
private Catagory Favorites;
|
|
|
|
List<string> suportedVidioFiles = new List<string>();
|
|
List<string> suportedMusicFiles = new List<string>();
|
|
List<string> suportedPhotoFiles = new List<string>();
|
|
|
|
//root directory
|
|
List<string> dirs = new List<string>();
|
|
private int option = 2;
|
|
int specificOption = 0;
|
|
string rootPath = "G:/";
|
|
|
|
FileScanner fileScanner;
|
|
|
|
|
|
//video player variables
|
|
public string _path ;
|
|
public string _category;
|
|
|
|
StringConversions stringConversions = new StringConversions();
|
|
|
|
private DispatcherTimer _progressTimer;
|
|
|
|
#endregion
|
|
|
|
//Quinn
|
|
#region vlc logic
|
|
|
|
private LibVLC _libVLC;
|
|
private LibVLCSharp.Shared.MediaPlayer _mediaPlayer;
|
|
|
|
#endregion
|
|
//code start
|
|
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
|
{
|
|
FirstCat?.Focus();
|
|
}
|
|
|
|
public MainWindow()
|
|
{
|
|
#region Init wpf
|
|
InitializeComponent();
|
|
//Initialise but Hide
|
|
//logWin.Show();
|
|
//logWin.Hide();
|
|
//this.Hide();
|
|
//Begin Login Process
|
|
var login = new LogIn();
|
|
login.Show();
|
|
//login.Owner = this;
|
|
Favorites = new Catagory("Favorites",Favorites_Home);
|
|
|
|
#endregion
|
|
//Quinn Dont change or remuve!!!
|
|
#region vlc init
|
|
|
|
Core.Initialize(); // Important: load native libvlc binaries
|
|
|
|
_libVLC = new LibVLC();
|
|
_mediaPlayer = new LibVLCSharp.Shared.MediaPlayer(_libVLC);
|
|
|
|
VideoView.MediaPlayer = _mediaPlayer;
|
|
|
|
_mediaPlayer.Volume = Convert.ToInt32(vol.Value);
|
|
|
|
_progressTimer = new DispatcherTimer
|
|
{
|
|
Interval = TimeSpan.FromSeconds(1)
|
|
};
|
|
_progressTimer.Tick += ProgressTimer_Tick;
|
|
|
|
#endregion
|
|
|
|
#region BlutuethLogic
|
|
InitBluetoothServer();
|
|
#endregion
|
|
|
|
#region only exdend. no remuving of code
|
|
|
|
//adding all extensions... example values added
|
|
suportedVidioFiles.Add(".mp4");
|
|
suportedVidioFiles.Add(".mkv");
|
|
suportedMusicFiles.Add(".wav");
|
|
suportedMusicFiles.Add(".mp3");
|
|
suportedPhotoFiles.Add(".jpg");
|
|
Createscan();
|
|
//dirs.Add("C:/");
|
|
|
|
//execute and wait for task completion
|
|
var tmp = fileScanner.ScanAllDrivesAsync();
|
|
|
|
//load json parallel to finding drives
|
|
//add code laiter
|
|
|
|
tmp.Wait();
|
|
foreach (var VARIABLE in tmp.Result)
|
|
{
|
|
dirs.Add(VARIABLE);
|
|
}
|
|
|
|
#endregion
|
|
|
|
LoadSavedData();
|
|
|
|
}
|
|
//Quinn
|
|
#region dont change
|
|
//reminder to self. if issue acures. check if anyone changed folder names/or if paths are being refrenced wrongly
|
|
|
|
#region ScannLogic
|
|
|
|
void Createscan()
|
|
{
|
|
//adding all string arrays to one temp array to do the initial scan of the designated drive
|
|
int count = 0;
|
|
string[] tmp = new string[suportedMusicFiles.Count + suportedVidioFiles.Count + suportedPhotoFiles.Count];
|
|
foreach (var suportedVidioFile in suportedVidioFiles)
|
|
{
|
|
tmp[count] = suportedVidioFile;
|
|
count++;
|
|
}
|
|
|
|
foreach (var suportedMusicFile in suportedMusicFiles)
|
|
{
|
|
tmp[count] = suportedMusicFile;
|
|
count++;
|
|
}
|
|
|
|
foreach (var suportedPhotoFile in suportedPhotoFiles)
|
|
{
|
|
tmp[count] = suportedPhotoFile;
|
|
count++;
|
|
}
|
|
//initialise the file scanner with all files endings wanted
|
|
fileScanner = new FileScanner(tmp);
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region Click Methods
|
|
//-_- warum klapt es nicht
|
|
private ProgressBar progressScann;
|
|
private void OnItemPlayButtonClick(object sender, RoutedEventArgs e)
|
|
{
|
|
|
|
if (sender is Button btn && btn.Tag is string filePath)
|
|
{
|
|
string[] parts = filePath.Split("||");
|
|
string left = parts[0];
|
|
PlayVideo(left);
|
|
}
|
|
}
|
|
private void OnItemNextButtonClick(object sender, RoutedEventArgs e)
|
|
{
|
|
setStrings();
|
|
switch (_category.ToLower())
|
|
{
|
|
case "muvie":
|
|
videoArrows(ref Muvie,true); break;
|
|
case "serie":
|
|
videoArrows(ref Serie,true);break;
|
|
case "music":
|
|
videoArrows(ref Music,true); break;
|
|
case "photos":
|
|
videoArrows(ref Photo,true); break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
private void OnItemPriorButtonClick(object sender, RoutedEventArgs e)
|
|
{
|
|
setStrings();
|
|
switch (_category.ToLower())
|
|
{
|
|
case "muvie":
|
|
videoArrows(ref Muvie,false); break;
|
|
case "serie":
|
|
videoArrows(ref Serie,false);break;
|
|
case "music":
|
|
videoArrows(ref Music,false); break;
|
|
case "photos":
|
|
videoArrows(ref Photo,false); break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void OnItemPauseBtn_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_mediaPlayer.IsPlaying)
|
|
{
|
|
_mediaPlayer.Pause(); // Pauses the video
|
|
}
|
|
else
|
|
{
|
|
_mediaPlayer.SetPause(false); // Unpauses the video
|
|
}
|
|
}
|
|
|
|
private void Close_Player(object sender, RoutedEventArgs e)
|
|
{
|
|
_mediaPlayer.Stop();
|
|
VideoView.Visibility = Visibility.Collapsed;
|
|
}
|
|
|
|
private async void scanButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
Muvie.clear();
|
|
Serie.clear();
|
|
Music.clear();
|
|
Photo.clear();
|
|
log.Log("Scanning files...");
|
|
|
|
List<string> tmp = new List<string>();
|
|
|
|
switch (option)
|
|
{
|
|
case 0:
|
|
foreach (var VARIABLE in dirs)
|
|
{
|
|
var scanResult = await fileScanner.ScanDriveParallel(VARIABLE);
|
|
tmp.AddRange(scanResult);
|
|
}
|
|
break;
|
|
case 1:
|
|
var scanResult1 = await fileScanner.ScanDriveParallel(dirs[specificOption]);
|
|
tmp.AddRange(scanResult1);
|
|
break;
|
|
case 2:
|
|
var scanResult2 = await fileScanner.ScanDriveParallel(rootPath);
|
|
tmp.AddRange(scanResult2);
|
|
break;
|
|
}
|
|
|
|
log.Log($"Total scanned files: {tmp.Count}");
|
|
|
|
var classifier = new FileClassifier();
|
|
var (musicFiles, videoFiles, photoFiles) = await classifier.ClassifyFilesAsync(tmp, suportedMusicFiles, suportedVidioFiles, suportedPhotoFiles);
|
|
|
|
var separator = new VideoSeparator();
|
|
var (series, movies) = await separator.SeparateVideosAsync(videoFiles);
|
|
|
|
log.Log($"musicFiles count: {musicFiles.Count}");
|
|
log.Log($"videoFiles count: {videoFiles.Count}");
|
|
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.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>();
|
|
|
|
JasonToString jasonToString = new JasonToString();
|
|
|
|
// Use async ItemCreaterAsync
|
|
var movieItems = await ItemCreater(movies, "Muvie", false);
|
|
foreach (var VARIABLE in movieItems)
|
|
{
|
|
Muvie.addItem(VARIABLE);
|
|
muviesJS.Add(new locJason
|
|
{
|
|
path = VARIABLE.getLink(),
|
|
imageData = jasonToString.BitmapToBase64String(BitmapConversions.BitmapImageToBitmap(VARIABLE.getImage())),
|
|
type = VARIABLE.getType()
|
|
});
|
|
}
|
|
|
|
var seriesItems = await ItemCreater(series, "Serie", false);
|
|
foreach (var VARIABLE in seriesItems)
|
|
{
|
|
Serie.addItem(VARIABLE);
|
|
seriesJS.Add(new locJason
|
|
{
|
|
path = VARIABLE.getLink(),
|
|
imageData = jasonToString.BitmapToBase64String(BitmapConversions.BitmapImageToBitmap(VARIABLE.getImage())),
|
|
type = VARIABLE.getType()
|
|
});
|
|
}
|
|
|
|
var photoItems = await ItemCreater(photoFiles, "Photo", true);
|
|
foreach (var VARIABLE in photoItems)
|
|
{
|
|
Photo.addItem(VARIABLE);
|
|
photosJS.Add(new locJason
|
|
{
|
|
path = VARIABLE.getLink(),
|
|
imageData = jasonToString.BitmapToBase64String(BitmapConversions.BitmapImageToBitmap(VARIABLE.getImage())),
|
|
type = VARIABLE.getType()
|
|
});
|
|
}
|
|
|
|
var musicItems = await ItemCreater(musicFiles, "Music", false, true);
|
|
foreach (var VARIABLE in musicItems)
|
|
{
|
|
Music.addItem(VARIABLE);
|
|
mucicJS.Add(new locJason
|
|
{
|
|
path = VARIABLE.getLink(),
|
|
imageData = jasonToString.BitmapToBase64String(BitmapConversions.BitmapImageToBitmap(VARIABLE.getImage())),
|
|
type = VARIABLE.getType()
|
|
});
|
|
}
|
|
|
|
log.Log("scan finished");
|
|
|
|
Jason_Writer jason_Writer = new Jason_Writer();
|
|
List<Task> tasks = new List<Task>
|
|
{
|
|
jason_Writer.SaveList("Muvies", muviesJS),
|
|
jason_Writer.SaveList("Series", seriesJS),
|
|
jason_Writer.SaveList("Photos", photosJS),
|
|
jason_Writer.SaveList("Music", mucicJS)
|
|
};
|
|
|
|
await Task.WhenAll(tasks);
|
|
|
|
// Clear lists to free memory
|
|
mucicJS = null;
|
|
seriesJS = null;
|
|
photosJS = null;
|
|
|
|
MenueItems();
|
|
progressScann.Hide();
|
|
MessageBox.Show("Scan finished");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"An error occurred during scanning:\n\n{ex}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
log.Error($"An error occurred during scanning:\n\n{ex}");
|
|
}
|
|
}
|
|
|
|
private void PlayListButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
ObservableCollection<Catagory> tmpBP= new ObservableCollection<Catagory>();
|
|
tmpBP.Add(Muvie);
|
|
tmpBP.Add(Serie);
|
|
tmpBP.Add(Photo);
|
|
tmpBP.Add(Music);
|
|
popupWindow = new PlaylistEditor(tmpBP,false,false);
|
|
popupWindow.Owner = this;
|
|
popupWindow.ShowInTaskbar = false;
|
|
popupWindow.Show();
|
|
}
|
|
|
|
private void EdditFav_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
ObservableCollection<Catagory> tmpBP= new ObservableCollection<Catagory>();
|
|
tmpBP.Add(Muvie);
|
|
tmpBP.Add(Serie);
|
|
tmpBP.Add(Photo);
|
|
tmpBP.Add(Music);
|
|
popupWindow = new PlaylistEditor(tmpBP,true,true,Favorites);
|
|
popupWindow.Owner = this;
|
|
popupWindow.ShowInTaskbar = false;
|
|
popupWindow.Show();
|
|
}
|
|
|
|
|
|
|
|
#region Catagory btns
|
|
private void Home_OnClick(object sender, RoutedEventArgs e)
|
|
{
|
|
Close_Player();
|
|
ScrollContentPlaylist.Visibility = Visibility.Collapsed;
|
|
ScrollContentCat.Visibility = Visibility.Collapsed;
|
|
ScrollContentHome.Visibility = Visibility.Visible;
|
|
MenueItems();
|
|
}
|
|
private void Musik_OnClick(object sender, RoutedEventArgs e)
|
|
{
|
|
Close_Player();
|
|
Name_of_Catagory_Text1.Visibility = Visibility.Collapsed;
|
|
ScrollContentPlaylist.Visibility = Visibility.Collapsed;
|
|
|
|
ScrollContentHome.Visibility = Visibility.Collapsed;
|
|
ScrollContentCat.Visibility = Visibility.Visible;
|
|
Name_of_Catagory1.Visibility = Visibility.Collapsed;
|
|
MenueItems(ref Music);
|
|
}
|
|
private void Photo_OnClick(object sender, RoutedEventArgs e)
|
|
{
|
|
Close_Player();
|
|
Name_of_Catagory_Text1.Visibility = Visibility.Collapsed;
|
|
ScrollContentPlaylist.Visibility = Visibility.Collapsed;
|
|
|
|
ScrollContentHome.Visibility = Visibility.Collapsed;
|
|
ScrollContentCat.Visibility = Visibility.Visible;
|
|
Name_of_Catagory1.Visibility = Visibility.Collapsed;
|
|
MenueItems(ref Photo);
|
|
}
|
|
private void Video_OnClick(object sender, RoutedEventArgs e)
|
|
{
|
|
Close_Player();
|
|
Name_of_Catagory_Text1.Visibility = Visibility.Visible;
|
|
ScrollContentPlaylist.Visibility = Visibility.Collapsed;
|
|
ScrollContentHome.Visibility = Visibility.Collapsed;
|
|
ScrollContentCat.Visibility = Visibility.Visible;
|
|
Name_of_Catagory1.Visibility = Visibility.Visible;
|
|
MenueItems(ref Muvie,ref Serie);
|
|
}
|
|
private void PlayListButton_OnClick(object sender, RoutedEventArgs e)
|
|
{
|
|
Close_Player();
|
|
Name_of_Catagory_Text1.Visibility = Visibility.Collapsed;
|
|
|
|
ScrollContentHome.Visibility = Visibility.Collapsed;
|
|
ScrollContentCat.Visibility = Visibility.Collapsed;
|
|
Name_of_Catagory1.Visibility = Visibility.Collapsed;
|
|
|
|
PopulateAllCategoriesFromPlaylists(); // <-- This needs to set ScrollContentPlaylist visible
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#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)
|
|
{
|
|
var itemsBag = new ConcurrentBag<Item>();
|
|
var workQueue = new ConcurrentQueue<string>(paths);
|
|
int maxWorkers = Math.Max(1, Environment.ProcessorCount / 2);
|
|
var workers = new List<Task>();
|
|
|
|
// Prepare default image for music if needed
|
|
BitmapImage defaultImage = null;
|
|
if (isMusic)
|
|
{
|
|
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
|
string imagePath = System.IO.Path.Combine(baseDir, "Resources", "Pics", "MusicD.jpeg");
|
|
|
|
if (System.IO.File.Exists(imagePath))
|
|
{
|
|
await Application.Current.Dispatcher.InvokeAsync(() =>
|
|
{
|
|
defaultImage = new BitmapImage(new Uri(imagePath));
|
|
defaultImage.DecodePixelWidth = 150;
|
|
defaultImage.DecodePixelHeight = 100;
|
|
defaultImage.Freeze();
|
|
});
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show($"Default image not found at: {imagePath}");
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < maxWorkers; i++)
|
|
{
|
|
workers.Add(Task.Run(async () =>
|
|
{
|
|
while (workQueue.TryDequeue(out var filePath))
|
|
{
|
|
BitmapImage bitmapImage = null;
|
|
|
|
try
|
|
{
|
|
if (isMusic)
|
|
{
|
|
bitmapImage = defaultImage;
|
|
|
|
try
|
|
{
|
|
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
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// fallback: bitmapImage stays null or default
|
|
}
|
|
|
|
// Create Item on UI thread because it creates UI controls internally
|
|
Item newItem = null;
|
|
await Application.Current.Dispatcher.InvokeAsync(() =>
|
|
{
|
|
newItem = new Item(filePath, type, bitmapImage, isFoto, OnItemPlayButtonClick);
|
|
});
|
|
|
|
itemsBag.Add(newItem);
|
|
Application.Current.Dispatcher.Invoke(() => progressScann.UpdateProgress(1));
|
|
}
|
|
}));
|
|
}
|
|
|
|
await Task.WhenAll(workers);
|
|
|
|
return itemsBag.ToList();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Comunication
|
|
public void ReciveErrorLog(string logMessage)
|
|
{
|
|
log.Error(logMessage);
|
|
}
|
|
public void PlayVideo(string filePath)
|
|
{
|
|
if(suportedVidioFiles.Contains(Path.GetExtension(filePath))||suportedPhotoFiles.Contains(Path.GetExtension(filePath)))
|
|
VideoView.Visibility = Visibility.Visible;
|
|
var media = new Media(_libVLC, filePath, FromType.FromPath);
|
|
Console.WriteLine(filePath);
|
|
media.ParsedChanged += (sender, args) =>
|
|
{
|
|
if (args.ParsedStatus == MediaParsedStatus.Done)
|
|
{
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
var duration = media.Duration;
|
|
Console.WriteLine(duration);
|
|
videoSliderInit(duration / 1000);
|
|
title.Text=Path.GetFileNameWithoutExtension(filePath);
|
|
});
|
|
}
|
|
};
|
|
media.Parse(MediaParseOptions.ParseLocal);
|
|
_mediaPlayer.Play(media);
|
|
}
|
|
public void setStrings()
|
|
{
|
|
#region type?
|
|
var currentMedia = _mediaPlayer?.Media;
|
|
|
|
if (currentMedia != null)
|
|
{
|
|
var mrl = currentMedia.Mrl; // This is the media resource locator
|
|
_path = new Uri(mrl).LocalPath;;
|
|
_path = stringConversions.ReplaceFirst(_path, '/', '\\');
|
|
|
|
Console.WriteLine("Now Playing Path: " + _path);
|
|
}
|
|
if (_mediaPlayer.IsPlaying)
|
|
{
|
|
_mediaPlayer.Stop();
|
|
}
|
|
|
|
|
|
|
|
if (suportedMusicFiles.Any(keyword => _path.Contains(keyword, StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
_category = "music";
|
|
}
|
|
else if (suportedPhotoFiles.Any(keyword => _path.Contains(keyword, StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
_category = "photos";
|
|
}
|
|
else
|
|
{
|
|
|
|
if (Regex.IsMatch(_path, @"\b(E|EP|Ep|e|ep)\d+\b", RegexOptions.IgnoreCase))
|
|
{
|
|
_category = "serie";
|
|
}
|
|
else
|
|
{
|
|
_category = "muvie";
|
|
}
|
|
}
|
|
|
|
log.Log($"replacing: {_path} from {_category}");
|
|
#endregion
|
|
}
|
|
public void videoArrows(ref Catagory catagory, bool next)
|
|
{
|
|
catagory = catagory as Catagory;
|
|
var items = catagory?.getAllItems();
|
|
|
|
if (catagory == null || items == null)
|
|
{
|
|
MessageBox.Show("Category or items are null");
|
|
return;
|
|
}
|
|
|
|
int tmp = catagory.contains(_path);
|
|
if (tmp == -1 || tmp >= items.Count)
|
|
{
|
|
MessageBox.Show("Current item not found in category");
|
|
return;
|
|
}
|
|
|
|
Media media = null;
|
|
int newIndex =0;
|
|
|
|
if (next)
|
|
{
|
|
if (tmp + 1 < items.Count)
|
|
{
|
|
var link = items[tmp + 1]?.getLink();
|
|
if (!string.IsNullOrEmpty(link))
|
|
media = new Media(_libVLC, link, FromType.FromPath);
|
|
}
|
|
}
|
|
if (!next)
|
|
{
|
|
newIndex = (tmp - 1 >= 0) ? tmp - 1 : items.Count - 1; // wrap around
|
|
var link = items[newIndex]?.getLink();
|
|
Console.WriteLine(link);
|
|
if (!string.IsNullOrEmpty(link))
|
|
media = new Media(_libVLC, link, FromType.FromPath);
|
|
}
|
|
|
|
|
|
if (media != null)
|
|
{
|
|
_mediaPlayer.Play(media);
|
|
title.Text = items[newIndex].Name.ToString();
|
|
}
|
|
else
|
|
MessageBox.Show("Could not load media. Media or link is null.");
|
|
}
|
|
private void Close_Player()
|
|
{
|
|
_mediaPlayer.Stop();
|
|
VideoView.Visibility = Visibility.Collapsed;
|
|
}
|
|
|
|
public void RecivePlaylist(Catagory items)
|
|
{
|
|
_playlists.SharedRefs.Add(items);
|
|
RecivePlaylist();
|
|
var writer = new Jason_Writer();
|
|
var tmp = new List<locJasonPlaylist>();
|
|
int index = 0;
|
|
foreach (var VARIABLE in items.getAllItems())
|
|
{
|
|
tmp.Add(new locJasonPlaylist());
|
|
tmp[index].name = VARIABLE.Name;
|
|
tmp[index].path = VARIABLE.Path;
|
|
tmp[index].type = VARIABLE.Type;
|
|
index++;
|
|
}
|
|
writer.SavePlaylistListAsync(items.name,tmp);
|
|
Console.WriteLine("wrote"+items.name);
|
|
}
|
|
public void RecivePlaylist(Catagory items,bool favorite)
|
|
{
|
|
if (favorite)
|
|
{
|
|
Favorites.clear();
|
|
foreach (var VARIABLE in items.getAllItems())
|
|
{
|
|
Favorites.addItem(VARIABLE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (var VARIABLE in _playlists.SharedRefs)
|
|
{
|
|
if (VARIABLE.name == items.name)
|
|
{
|
|
|
|
VARIABLE.clear();
|
|
foreach (var var2 in items.getAllItems())
|
|
{
|
|
VARIABLE.addItem(var2);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
RecivePlaylist();
|
|
var writer = new Jason_Writer();
|
|
var tmp = new List<locJasonPlaylist>();
|
|
int index = 0;
|
|
foreach (var VARIABLE in items.getAllItems())
|
|
{
|
|
tmp.Add(new locJasonPlaylist());
|
|
tmp[index].name = VARIABLE.Name;
|
|
tmp[index].path = VARIABLE.Path;
|
|
tmp[index].type = VARIABLE.Type;
|
|
index++;
|
|
}
|
|
writer.SavePlaylistListAsync(items.name,tmp);
|
|
Console.WriteLine("faf updated");
|
|
if (favorite)
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
MenueItems(); // safely update UI
|
|
});
|
|
|
|
|
|
foreach (var VARIABLE in items.getAllItems())
|
|
{
|
|
Console.WriteLine(VARIABLE.Name);
|
|
}
|
|
}
|
|
public void RecivePlaylist()
|
|
{
|
|
popupWindow.Close();
|
|
}
|
|
|
|
private void PopulateAllCategoriesFromPlaylists()
|
|
{
|
|
PlaylistContentPanel.Children.Clear(); // Optional: clear previous entries
|
|
|
|
foreach (Catagory category in _playlists.SharedRefs)
|
|
{
|
|
// Create TextBlock for category name
|
|
var textBlock = new TextBlock
|
|
{
|
|
Text = category.name,
|
|
FontSize = 18,
|
|
Foreground = Brushes.White,
|
|
Margin = new Thickness(0, 10, 0, 5)
|
|
};
|
|
|
|
// Create WrapPanel for items
|
|
var wrapPanel = new WrapPanel
|
|
{
|
|
Margin = new Thickness(0, 0, 0, 10)
|
|
};
|
|
|
|
// Fill WrapPanel with items
|
|
PopulatePanelWithItems(category.getAllItems(), wrapPanel);
|
|
|
|
// Add both to the ScrollViewer's inner panel
|
|
PlaylistContentPanel.Children.Add(textBlock);
|
|
PlaylistContentPanel.Children.Add(wrapPanel);
|
|
}
|
|
|
|
// Make the ScrollViewer visible
|
|
ScrollContentPlaylist.Visibility = Visibility.Visible;
|
|
|
|
PopulatePlaylistsWithButtons();
|
|
}
|
|
|
|
#region tvRemote
|
|
BluetoothServer Server1;
|
|
private void InitBluetoothServer()
|
|
{
|
|
Server1 = new BluetoothServer();
|
|
|
|
Server1.ClientConnected += () =>
|
|
{
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
MessageBox.Show("🔗 Client connected!");
|
|
|
|
});
|
|
};
|
|
|
|
Server1.MessageReceived += (msg) =>
|
|
{
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
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
|
|
}
|
|
});
|
|
|
|
|
|
// Optional: echo back the message
|
|
Server1.SendMessage("Echo: " + msg.Trim());
|
|
};
|
|
|
|
Server1.ErrorOccurred += (err) =>
|
|
{
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
MessageBox.Show($"⚠️ Error: {err}");
|
|
});
|
|
};
|
|
|
|
// Start server in background
|
|
new Thread(() => Server1.Init())
|
|
{
|
|
IsBackground = true
|
|
}.Start();
|
|
}
|
|
|
|
|
|
#endregion
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Menue
|
|
|
|
|
|
void MenueItems(ref Catagory catagory)
|
|
{
|
|
PopulatePanelWithItemsCatagorised(Name_of_Catagory,ref catagory);
|
|
}
|
|
void MenueItems(ref Catagory catagory,ref Catagory catagory1)
|
|
{
|
|
PopulatePanelWithItemsCatagorised(Name_of_Catagory,ref catagory);
|
|
PopulatePanelWithItemsCatagorised(Name_of_Catagory1,ref catagory1);
|
|
}
|
|
void MenueItems()
|
|
{
|
|
PopulatePanelWithItems(Favorites.getAllItems(), Favorites_Home);
|
|
PopulatePanelWithItems(Muvie.getAllItems(), Muvies_Home);
|
|
PopulatePanelWithItems(Serie.getAllItems(), Series_Home);
|
|
PopulatePanelWithItems(Photo.getAllItems(), Photos_Home);
|
|
PopulatePanelWithItems(Music.getAllItems(), Music_Home);
|
|
}
|
|
#endregion
|
|
|
|
#region PanelPop
|
|
|
|
private void PopulatePanelWithItemsCatagorised(Panel targetPanel,ref Catagory catagory)
|
|
{
|
|
if (catagory.name == "Serie")
|
|
{
|
|
Name_of_Catagory_Text1.Text = catagory.name;
|
|
}
|
|
else
|
|
{
|
|
Name_of_Catagory_Text.Text = catagory.name;
|
|
}
|
|
PopulatePanelWithItems(catagory.getAllItems(),targetPanel);
|
|
}
|
|
private void PopulatePanelWithItems(List<Item> items, Panel targetPanel)
|
|
{
|
|
targetPanel.Children.Clear();
|
|
byte tmp = 0;
|
|
foreach (var item in items)
|
|
{
|
|
if(tmp >= 10)
|
|
break;
|
|
if (ScrollContentHome.Visibility == Visibility.Visible)
|
|
tmp++;
|
|
if (tmp < 10)
|
|
{
|
|
var name = item.getName();
|
|
var image = item.getImage();
|
|
var isFoto = item.getType() == "Photo";
|
|
var path = item.getLink();
|
|
var buttonText = isFoto ? "Show" : "Play";
|
|
|
|
if (image == null)
|
|
continue; // Skip if image is not available
|
|
|
|
// Container for stacking label, image, and button
|
|
var container = new Grid
|
|
{
|
|
Width = 150,
|
|
Height = 120,
|
|
Margin = new Thickness(5)
|
|
};
|
|
|
|
// Define rows for layout
|
|
container.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); // Image
|
|
container.RowDefinitions.Add(new RowDefinition { Height = new GridLength(30) }); // Button
|
|
|
|
// Image
|
|
var imgControl = new System.Windows.Controls.Image
|
|
{
|
|
Source = image,
|
|
Width = 150,
|
|
Height = 90,
|
|
Stretch = Stretch.UniformToFill
|
|
};
|
|
|
|
Grid.SetRow(imgControl, 0);
|
|
container.Children.Add(imgControl);
|
|
|
|
// Label (overlays top-left, optional)
|
|
var label = new Label
|
|
{
|
|
Content = name,
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
VerticalAlignment = VerticalAlignment.Top,
|
|
Background = new SolidColorBrush(Color.FromArgb(180, 0, 0, 0)),
|
|
Foreground = Brushes.White,
|
|
Padding = new Thickness(4),
|
|
FontSize = 12
|
|
};
|
|
Grid.SetRow(label, 0);
|
|
container.Children.Add(label);
|
|
|
|
// Button
|
|
var btn = new Button
|
|
{
|
|
Content = buttonText,
|
|
Height = 25,
|
|
Width = 140,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
Margin = new Thickness(0, 0, 0, 5)
|
|
};
|
|
btn.Click += (s, e) => PlayVideo(path);
|
|
Grid.SetRow(btn, 1);
|
|
container.Children.Add(btn);
|
|
|
|
// Add to target UI panel
|
|
targetPanel.Children.Add(container);
|
|
}
|
|
|
|
}
|
|
}
|
|
private void PopulatePlaylistsWithButtons()
|
|
{
|
|
// Make sure the playlist ScrollViewer is visible
|
|
ScrollContentHome.Visibility = Visibility.Collapsed;
|
|
ScrollContentCat.Visibility = Visibility.Collapsed;
|
|
ScrollContentPlaylist.Visibility = Visibility.Visible;
|
|
|
|
// Clear previous content
|
|
PlaylistContentPanel.Children.Clear();
|
|
|
|
// Add "New Playlist" button
|
|
var newPlaylistBtn = new Button
|
|
{
|
|
Content = "New Playlist",
|
|
Background = Brushes.Black,
|
|
Foreground = Brushes.White,
|
|
Margin = new Thickness(5)
|
|
};
|
|
newPlaylistBtn.Click += PlayListButton_Click;
|
|
PlaylistContentPanel.Children.Add(newPlaylistBtn);
|
|
|
|
// Guard: If there are no playlists, show a message
|
|
if (_playlists?.SharedRefs == null || !_playlists.SharedRefs.Any())
|
|
{
|
|
PlaylistContentPanel.Children.Add(new TextBlock
|
|
{
|
|
Text = "No playlists available.",
|
|
Foreground = Brushes.White,
|
|
Margin = new Thickness(10)
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Add playlist sections
|
|
foreach (var playlistCategory in _playlists.SharedRefs)
|
|
{
|
|
var container = new StackPanel
|
|
{
|
|
Margin = new Thickness(10),
|
|
Orientation = Orientation.Vertical,
|
|
HorizontalAlignment = HorizontalAlignment.Stretch
|
|
};
|
|
|
|
// Header row with playlist name and ">>" button
|
|
var headerRow = new DockPanel
|
|
{
|
|
LastChildFill = true, // Let the title take remaining space
|
|
HorizontalAlignment = HorizontalAlignment.Stretch
|
|
};
|
|
|
|
// Button (goes first, docked right)
|
|
var btn = new Button
|
|
{
|
|
Content = ">>",
|
|
Width = 30,
|
|
Height = 25,
|
|
Margin = new Thickness(10, 0, 0, 0),
|
|
VerticalAlignment = VerticalAlignment.Center
|
|
};
|
|
DockPanel.SetDock(btn, Dock.Right);
|
|
btn.Click += (s, e) => ShowFullCategoryView(playlistCategory);
|
|
headerRow.Children.Add(btn);
|
|
|
|
// Playlist name
|
|
var title = new TextBlock
|
|
{
|
|
Text = playlistCategory.name,
|
|
FontSize = 18,
|
|
FontWeight = FontWeights.Bold,
|
|
Foreground = Brushes.White,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
Margin = new Thickness(5)
|
|
};
|
|
headerRow.Children.Add(title);
|
|
|
|
container.Children.Add(headerRow);
|
|
|
|
// Preview items in WrapPanel
|
|
var wrap = new WrapPanel();
|
|
PopulatePanelWithItems(playlistCategory.getAllItems().Take(9).ToList(), wrap);
|
|
container.Children.Add(wrap);
|
|
|
|
PlaylistContentPanel.Children.Add(container);
|
|
}
|
|
}
|
|
|
|
|
|
private void ShowFullCategoryView(Catagory category)
|
|
{
|
|
ScrollContentHome.Visibility = Visibility.Collapsed;
|
|
ScrollContentPlaylist.Visibility = Visibility.Collapsed;
|
|
|
|
ScrollContentCat.Visibility = Visibility.Visible;
|
|
|
|
Name_of_Catagory_Text.Text = category.name;
|
|
Name_of_Catagory1.Visibility = Visibility.Collapsed;
|
|
|
|
PopulatePanelWithItems(category.getAllItems(), Name_of_Catagory);
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region load saved data
|
|
|
|
private async void LoadSavedData()
|
|
{
|
|
try
|
|
{
|
|
Jason_Writer jason_Writer = new Jason_Writer(); // Uses default "Temp Data" folder
|
|
|
|
// Load main media lists
|
|
var muvies = await jason_Writer.LoadListAsync("Muvies");
|
|
var series = await jason_Writer.LoadListAsync("Series");
|
|
var photos = await jason_Writer.LoadListAsync("Photos");
|
|
var music = await jason_Writer.LoadListAsync("Music");
|
|
var favorites = await jason_Writer.LoadListAsync("Favorit");
|
|
|
|
// Initialize progress bar with total count
|
|
progressScann = new ProgressBar("Reading saved data",
|
|
muvies.Count + series.Count + photos.Count + music.Count + favorites.Count);
|
|
progressScann.Show();
|
|
|
|
// Create Item lists from JSON
|
|
List<Item> MuvieItems = CreateItemsFromJson(muvies);
|
|
List<Item> SerieItems = CreateItemsFromJson(series);
|
|
List<Item> PhotoItems = CreateItemsFromJson(photos, isPhoto: true);
|
|
List<Item> MusicItems = CreateItemsFromJson(music, isPhoto: false, isMusic: true);
|
|
|
|
Muvie.addItems(MuvieItems);
|
|
Serie.addItems(SerieItems);
|
|
Photo.addItems(PhotoItems);
|
|
Music.addItems(MusicItems);
|
|
|
|
// Combine all media items for playlist/favorite matching
|
|
var allLocs = muvies.Concat(series).Concat(photos).Concat(music).ToList();
|
|
|
|
// Enrich favorite items by matching them with main list entries
|
|
var enrichedFavorites = new List<locJason>();
|
|
foreach (var fav in favorites)
|
|
{
|
|
var match = allLocs.FirstOrDefault(item =>
|
|
string.Equals(item.path, fav.path, StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (match != null)
|
|
{
|
|
enrichedFavorites.Add(match);
|
|
}
|
|
else
|
|
{
|
|
enrichedFavorites.Add(fav); // fallback if not found
|
|
Console.WriteLine($"[Warning] Favorite not found in main lists: {fav.path}");
|
|
}
|
|
}
|
|
|
|
List<Item> FavoriteItems = CreateItemsFromJson(enrichedFavorites);
|
|
Favorites.addItems(FavoriteItems);
|
|
|
|
// Load playlists
|
|
var playlistNames = await jason_Writer.GetSavedPlaylistNamesAsync();
|
|
|
|
foreach (var playlistName in playlistNames)
|
|
{
|
|
var playlistEntries = await jason_Writer.LoadPlaylistListAsync(playlistName);
|
|
|
|
var matchedLocs = new List<locJason>();
|
|
foreach (var entry in playlistEntries)
|
|
{
|
|
var match = allLocs.FirstOrDefault(item =>
|
|
string.Equals(item.path, entry.path, StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (match != null)
|
|
{
|
|
matchedLocs.Add(match);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"[Warning] Playlist '{playlistName}' contains unknown path: {entry.path}");
|
|
}
|
|
}
|
|
|
|
List<Item> PlaylistItems = CreateItemsFromJson(matchedLocs);
|
|
var playlistCategory = new Catagory(playlistName);
|
|
playlistCategory.addItems(PlaylistItems);
|
|
_playlists.SharedRefs.Add(playlistCategory);
|
|
}
|
|
|
|
MenueItems(); // Refresh the UI
|
|
progressScann.Hide();
|
|
log.Log("Loaded saved data from JSON.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Failed to load saved data:\n{ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
log.Error($"LoadSavedData error: {ex}");
|
|
}
|
|
}
|
|
|
|
private List<Item> CreateItemsFromJson(List<locJason> jsonItems)
|
|
{
|
|
return CreateItemsFromJson(jsonItems, isPhoto: false, isMusic: false);
|
|
}
|
|
|
|
private List<Item> CreateItemsFromJson(List<locJason> jsonItems, bool isPhoto)
|
|
{
|
|
return CreateItemsFromJson(jsonItems, isPhoto, isMusic: false);
|
|
}
|
|
|
|
private List<Item> CreateItemsFromJson(List<locJason> jsonItems, bool isPhoto, bool isMusic)
|
|
{
|
|
List<Item> items = new List<Item>();
|
|
JasonToString jasonToString = new JasonToString();
|
|
|
|
foreach (var loc in jsonItems)
|
|
{
|
|
BitmapImage bitmapImage = null;
|
|
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(loc.imageData))
|
|
{
|
|
bitmapImage = BitmapConversions.BitmapToBitmapImage(
|
|
jasonToString.Base64StringToBitmap(loc.imageData)
|
|
);
|
|
}
|
|
else if (isMusic)
|
|
{
|
|
string defaultImagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Pics", "MusicD.jpeg");
|
|
if (File.Exists(defaultImagePath))
|
|
{
|
|
bitmapImage = new BitmapImage(new Uri(defaultImagePath));
|
|
bitmapImage.Freeze();
|
|
}
|
|
}
|
|
else if (isPhoto && File.Exists(loc.path))
|
|
{
|
|
bitmapImage = new BitmapImage(new Uri(loc.path));
|
|
bitmapImage.Freeze();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Handle any corrupt or missing image cases
|
|
}
|
|
|
|
items.Add(new Item(loc.path, loc.type, bitmapImage, isPhoto, OnItemPlayButtonClick));
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
progressScann.UpdateProgress(1);
|
|
});
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region sliders
|
|
|
|
private void RangeBase_OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
|
{
|
|
if (sender is Slider&&_mediaPlayer != null)
|
|
{
|
|
Slider slider = sender as Slider;
|
|
int value = Convert.ToInt32(slider.Value);
|
|
_mediaPlayer.Volume = value;
|
|
Server1.SendMessage("Vol=" + value);
|
|
log.Log("VolumeChanged");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region progress slider
|
|
private void ItemProgress_OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
|
{
|
|
if (itemProgress.IsMouseOver&&(itemProgress.Value>_mediaPlayer.Time/1000+2||itemProgress.Value<_mediaPlayer.Time/1000-2))
|
|
{
|
|
ProgressBarValueChange();
|
|
}
|
|
}
|
|
private void ItemProgress_OnValueChangedMil(long timeStap)
|
|
{
|
|
itemProgress.Value = timeStap/1000;
|
|
itemProgressVisual.Value = itemProgress.Value;
|
|
Server1.SendMessage("Progress="+itemProgress.Value);
|
|
}
|
|
private void ProgressBarValueChange()
|
|
{
|
|
itemProgressVisual.Value = itemProgress.Value;
|
|
if(itemProgress.IsMouseOver)
|
|
_mediaPlayer.Time = Convert.ToInt64(itemProgress.Value) * 1000; // convert to milliseconds
|
|
}
|
|
private void videoSliderInit(long timeStap)
|
|
{
|
|
itemProgress.Maximum = timeStap;
|
|
itemProgressVisual.Maximum = timeStap;
|
|
itemProgress.Minimum = 0;
|
|
itemProgressVisual.Minimum = 0;
|
|
StartProgressTimer();
|
|
Console.WriteLine(timeStap);
|
|
}
|
|
private void ItemProgress_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
|
|
{
|
|
var slider = sender as Slider;
|
|
if (slider == null) return;
|
|
Point position = e.GetPosition(slider);
|
|
double relativePosition = position.X / slider.ActualWidth;
|
|
relativePosition = Math.Max(0, Math.Min(1, relativePosition));
|
|
double newValue = slider.Minimum + (relativePosition * (slider.Maximum - slider.Minimum));
|
|
slider.Value = newValue;
|
|
|
|
ProgressBarValueChange();
|
|
|
|
}
|
|
private void ProgressTimer_Tick(object sender, EventArgs e)
|
|
{
|
|
if (!_mediaPlayer.IsPlaying)
|
|
{
|
|
StopProgressTimer();
|
|
}
|
|
// Get current timestamp from media player in seconds
|
|
long currentTimeInSeconds = _mediaPlayer.Time;
|
|
|
|
// Update progress bar value
|
|
ItemProgress_OnValueChangedMil(currentTimeInSeconds);
|
|
}
|
|
private void StartProgressTimer()
|
|
{
|
|
if (!_progressTimer.IsEnabled)
|
|
_progressTimer.Start();
|
|
}
|
|
private void StopProgressTimer()
|
|
{
|
|
if (_progressTimer.IsEnabled)
|
|
_progressTimer.Stop();
|
|
}
|
|
|
|
private void Key_Up(object sender, KeyEventArgs e)
|
|
{
|
|
switch (e.Key)
|
|
{
|
|
case Key.Escape:
|
|
var result = MessageBox.Show(
|
|
"Do you want to quit?",
|
|
"Exit",
|
|
MessageBoxButton.YesNo,
|
|
MessageBoxImage.Question
|
|
);
|
|
|
|
if (result == MessageBoxResult.Yes)
|
|
{
|
|
Application.Current.Shutdown();
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
if (VideoView.IsVisible)
|
|
{
|
|
switch (e.Key)
|
|
{
|
|
case Key.Left:_mediaPlayer.Time=_mediaPlayer.Time-10000;break;
|
|
case Key.Right:_mediaPlayer.Time=_mediaPlayer.Time+10000;break;
|
|
case Key.Space:
|
|
if (_mediaPlayer.IsPlaying)
|
|
_mediaPlayer.Pause();
|
|
else
|
|
_mediaPlayer.Play();
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region arrow nav
|
|
private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (Keyboard.FocusedElement is not DependencyObject focusedElement)
|
|
return;
|
|
|
|
var wrapPanel = FindAncestor<WrapPanel>(focusedElement);
|
|
|
|
if (wrapPanel != null && wrapPanel.Children.Count > 0)
|
|
{
|
|
int focusedIndex = FindFocusedIndexInWrapPanel(wrapPanel, focusedElement);
|
|
if (focusedIndex == -1)
|
|
return;
|
|
|
|
int columns = CalculateColumns(wrapPanel);
|
|
|
|
switch (e.Key)
|
|
{
|
|
case Key.Left:
|
|
e.Handled = true;
|
|
if (IsLeftmostInRow(focusedIndex, columns))
|
|
{
|
|
FirstCat?.Focus();
|
|
}
|
|
else
|
|
{
|
|
MoveFocusInWrapPanel(wrapPanel, focusedIndex - 1);
|
|
}
|
|
break;
|
|
|
|
case Key.Right:
|
|
e.Handled = true;
|
|
MoveFocusInWrapPanel(wrapPanel, focusedIndex + 1);
|
|
break;
|
|
|
|
case Key.Up:
|
|
e.Handled = true;
|
|
MoveFocusInWrapPanel(wrapPanel, focusedIndex - columns);
|
|
break;
|
|
|
|
case Key.Down:
|
|
e.Handled = true;
|
|
MoveFocusInWrapPanel(wrapPanel, focusedIndex + columns);
|
|
break;
|
|
}
|
|
}
|
|
else if (FirstCat.IsFocused && e.Key == Key.Right)
|
|
{
|
|
// Find the first visible WrapPanel child in your current visible ScrollViewer
|
|
var firstFocusable = FindFirstFocusableInVisibleWrapPanel();
|
|
if (firstFocusable != null)
|
|
{
|
|
firstFocusable.Focus();
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Finds the first focusable control in the first visible WrapPanel child of your main ScrollViewer content
|
|
private Control FindFirstFocusableInVisibleWrapPanel()
|
|
{
|
|
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;
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
// ... rest of your helpers remain unchanged ...
|
|
|
|
private int CalculateColumns(WrapPanel panel)
|
|
{
|
|
if (panel.Children.Count == 0) return 1;
|
|
|
|
var firstChild = panel.Children[0] as FrameworkElement;
|
|
if (firstChild == null) return 1;
|
|
|
|
double itemWidth = firstChild.ActualWidth + firstChild.Margin.Left + firstChild.Margin.Right;
|
|
if (itemWidth <= 1) itemWidth = 150; // fallback
|
|
|
|
double panelWidth = panel.ActualWidth;
|
|
int columns = Math.Max(1, (int)(panelWidth / itemWidth));
|
|
return columns;
|
|
}
|
|
|
|
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 (panel.Children[index] is Control ctrl && ctrl.Focusable)
|
|
ctrl.Focus();
|
|
else if (panel.Children[index] is Panel container)
|
|
{
|
|
var focusable = FindFirstFocusableChild(container);
|
|
focusable?.Focus();
|
|
}
|
|
}
|
|
|
|
private int FindFocusedIndexInWrapPanel(WrapPanel panel, DependencyObject focusedElement)
|
|
{
|
|
for (int i = 0; i < panel.Children.Count; i++)
|
|
{
|
|
var container = panel.Children[i];
|
|
if (IsOrContains(container, focusedElement))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
private bool IsOrContains(DependencyObject parent, DependencyObject child)
|
|
{
|
|
if (parent == child) return true;
|
|
|
|
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
|
|
{
|
|
var sub = VisualTreeHelper.GetChild(parent, i);
|
|
if (IsOrContains(sub, child))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private Control FindFirstFocusableChild(DependencyObject parent)
|
|
{
|
|
if (parent is Control c && c.Focusable)
|
|
return c;
|
|
|
|
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
|
|
{
|
|
var found = FindFirstFocusableChild(VisualTreeHelper.GetChild(parent, i));
|
|
if (found != null)
|
|
return found;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static T FindAncestor<T>(DependencyObject child) where T : DependencyObject
|
|
{
|
|
DependencyObject current = child;
|
|
while (current != null)
|
|
{
|
|
if (current is T match)
|
|
return match;
|
|
current = VisualTreeHelper.GetParent(current);
|
|
}
|
|
return null;
|
|
}
|
|
#endregion
|
|
|
|
} |