diff --git a/TV Player WPF/Assets/GroupButtonStyle.xaml b/TV Player WPF/Assets/GroupButtonStyle.xaml
index 0972b13..1ab65f3 100644
--- a/TV Player WPF/Assets/GroupButtonStyle.xaml
+++ b/TV Player WPF/Assets/GroupButtonStyle.xaml
@@ -216,4 +216,82 @@ c-0.781-0.781-0.788-2.047-0.007-2.828L51.438,14.43c1.754-1.755,1.753-4.61-0.001-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TV Player WPF/MainWindow.xaml b/TV Player WPF/MainWindow.xaml
index d24af21..7e304e2 100644
--- a/TV Player WPF/MainWindow.xaml
+++ b/TV Player WPF/MainWindow.xaml
@@ -20,17 +20,17 @@
-
+
-
-
+
+
-
+
-
-
+
+
-
+
diff --git a/TV Player WPF/Settings.xaml b/TV Player WPF/Settings.xaml
new file mode 100644
index 0000000..e67a6e9
--- /dev/null
+++ b/TV Player WPF/Settings.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+ Откывать во весь экран
+ Запоминать последний выбор
+
+
+
+
+
+
diff --git a/TV Player WPF/Settings.xaml.cs b/TV Player WPF/Settings.xaml.cs
new file mode 100644
index 0000000..3c79318
--- /dev/null
+++ b/TV Player WPF/Settings.xaml.cs
@@ -0,0 +1,15 @@
+using System.Windows.Controls;
+
+namespace TV_Player
+{
+ ///
+ /// Interaction logic for ProgramsGroupGrid.xaml
+ ///
+ public partial class Settings : UserControl
+ {
+ public Settings()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/TV Player WPF/TV Player WPF.csproj b/TV Player WPF/TV Player WPF.csproj
index c23d128..4b0d236 100644
--- a/TV Player WPF/TV Player WPF.csproj
+++ b/TV Player WPF/TV Player WPF.csproj
@@ -19,6 +19,7 @@
true
+
@@ -30,6 +31,9 @@
+
+ Code
+
Code
diff --git a/TV Player WPF/VideoPlayer.xaml b/TV Player WPF/VideoPlayer.xaml
index 3ab4d27..4a92fcd 100644
--- a/TV Player WPF/VideoPlayer.xaml
+++ b/TV Player WPF/VideoPlayer.xaml
@@ -4,51 +4,56 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vlc="clr-namespace:LibVLCSharp.WPF;assembly=LibVLCSharp.WPF"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:local="clr-namespace:TV_Player"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Unloaded="UserControl_Unloaded">
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TV Player WPF/VideoPlayer.xaml.cs b/TV Player WPF/VideoPlayer.xaml.cs
index 20110c4..10998f1 100644
--- a/TV Player WPF/VideoPlayer.xaml.cs
+++ b/TV Player WPF/VideoPlayer.xaml.cs
@@ -3,6 +3,7 @@ using LibVLCSharp.WPF;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
+using System.Windows.Threading;
namespace TV_Player
{
@@ -16,11 +17,17 @@ namespace TV_Player
private LibVLC _libVLC;
private MediaPlayer _mediaPlayer;
private PlayerViewModel _viewModel;
-
+ private DispatcherTimer _overlayAutoHideTimer;
+
public VideoPlayer()
{
InitializeComponent();
+ _overlayAutoHideTimer = new DispatcherTimer();
+ _overlayAutoHideTimer.Interval = TimeSpan.FromSeconds(3);
+ _overlayAutoHideTimer.Tick += _overlayAutoHideTimer_Tick;
+ _overlayAutoHideTimer.Start();
+
_libVLC = new LibVLC(enableDebugLogs: true);
_mediaPlayer = new MediaPlayer(_libVLC);
this.DataContextChanged += (sender, e) =>
@@ -28,7 +35,6 @@ namespace TV_Player
_viewModel = (PlayerViewModel)e.NewValue;
_viewModel.SourceUrlChangedEvent += _viewModel_SourceUrlChangedEvent;
};
-
VideoView.Loaded += (sender, e) =>
{
@@ -39,7 +45,7 @@ namespace TV_Player
AutoPlay();
};
Unloaded += VideoPlayer_Unloaded;
- }
+ }
private void _viewModel_SourceUrlChangedEvent(string videoURL)
{
@@ -82,20 +88,28 @@ namespace TV_Player
private void ToggleOverlay()
{
if (overlayPanel.Visibility == Visibility.Visible)
- {
+ {
HideOverlay();
}
else
- {
+ {
ShowOverlay();
}
}
+
+ private void _overlayAutoHideTimer_Tick(object? sender, EventArgs e)
+ {
+ HideOverlay();
+ }
+
public void ShowOverlay()
{
+ _overlayAutoHideTimer.Start();
overlayPanel.Visibility = Visibility.Visible;
}
public void HideOverlay()
{
+ _overlayAutoHideTimer.Stop();
overlayPanel.Visibility = Visibility.Collapsed;
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
diff --git a/TV Player WPF/ViewModels/GroupInfo.cs b/TV Player WPF/ViewModels/GroupInfo.cs
index 634f0db..f8a3da8 100644
--- a/TV Player WPF/ViewModels/GroupInfo.cs
+++ b/TV Player WPF/ViewModels/GroupInfo.cs
@@ -1,5 +1,6 @@
namespace TV_Player
{
+ [Serializable]
public class GroupInfo
{
public string Name { get; set; }
diff --git a/TV Player WPF/ViewModels/M3UParser.cs b/TV Player WPF/ViewModels/M3UParser.cs
index b6613e6..6f33aac 100644
--- a/TV Player WPF/ViewModels/M3UParser.cs
+++ b/TV Player WPF/ViewModels/M3UParser.cs
@@ -1,7 +1,6 @@
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
-using System.Threading.Channels;
using System.Xml;
namespace TV_Player
@@ -28,7 +27,6 @@ namespace TV_Player
public static class M3UParser
{
-
public static async Task> DownloadGuideFromWebAsync(string url)
{
List epgChannels = new List(); ;
@@ -46,7 +44,6 @@ namespace TV_Player
return epgChannels;
}
-
private static List ParseEpg(string epgData)
{
List epgChannels = new List();
@@ -75,14 +72,14 @@ namespace TV_Player
{
ProgramInfo program = new ProgramInfo();
- var id=reader.GetAttribute("channel");
+ var id = reader.GetAttribute("channel");
var channel = epgChannels.FirstOrDefault(x => x.Id == id);
program.StartTime = DateTime.ParseExact(reader.GetAttribute("start"), "yyyyMMddHHmmss zzz", null);
program.StopTime = DateTime.ParseExact(reader.GetAttribute("stop"), "yyyyMMddHHmmss zzz", null);
reader.Read();
program.Title = reader.ReadElementContentAsString();
-
+
channel.Programs.Add(program);
}
@@ -92,132 +89,126 @@ namespace TV_Player
}
}
}
- catch (Exception ex) {
+ catch (Exception ex)
+ {
+ }
}
- }
- //using (XmlReader reader = XmlReader.Create(new System.IO.StringReader(epgData)))
- //{
- // ProgramGuide currentChannel = null;
- // XmlDocument doc = new XmlDocument();
- // doc.LoadXml(epgData);
-
- // XmlNodeList channelNodes = doc.SelectNodes("//channel");
-
- // foreach (XmlNode channelNode in channelNodes)
- // {
- // ProgramGuide channel = new ProgramGuide();
- // channel.Id = channelNode.Attributes["id"].Value;
- // channel.DisplayName = channelNode.SelectSingleNode("display-name").InnerText;
-
- // XmlNodeList programNodes = doc.SelectNodes($"//programme[@channel='{channel.Id}']");
- // foreach (XmlNode programNode in programNodes)
- // {
- // ProgramInfo program = new ProgramInfo();
- // program.Title = programNode.SelectSingleNode("title").InnerText;
- // program.StartTime = DateTime.ParseExact(programNode.Attributes["start"].Value, "yyyyMMddHHmmss zzz", null);
- // program.StopTime = DateTime.ParseExact(programNode.Attributes["stop"].Value, "yyyyMMddHHmmss zzz", null);
-
- // channel.Programs.Add(program);
- // }
-
- // epgChannels.Add(channel);
- // }
- //}
-
return epgChannels;
}
-
- public static async Task> DownloadM3UFromWebAsync(string url)
- {
- List playlistItems = new List();
-
- using (var client = new HttpClient())
- using (var request = new HttpRequestMessage())
+ private static async Task ReadFile(string url)
{
- client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/text"));
- request.Method = HttpMethod.Get;
- request.RequestUri = new Uri(url);
- var response = await client.GetAsync(url);
- response.EnsureSuccessStatusCode();
- string responseBody = await response.Content.ReadAsStringAsync();
-
- // Parse M3U content
- playlistItems = ParseM3UFromString(responseBody);
- }
- return playlistItems;
- }
-
- static string[] SplitStringBeforeSeparator(string input, string separator)
- {
- string[] parts = input.Split(separator);
-
- // Reconstruct the string until the separator is reached
- int separatorIndex = input.IndexOf(separator);
- if (separatorIndex != -1)
- {
- parts[0] = input.Substring(0, separatorIndex + 1);
- for (int i = 1; i < parts.Length; i++)
+ string responseBody;
+ using (var client = new HttpClient())
+ using (var request = new HttpRequestMessage())
{
- parts[i] = separator + parts[i];
+ client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/text"));
+ request.Method = HttpMethod.Get;
+ request.RequestUri = new Uri(url);
+ var response = await client.GetAsync(url);
+ response.EnsureSuccessStatusCode();
+ responseBody = await response.Content.ReadAsStringAsync();
}
+ return responseBody;
}
- return parts;
- }
-
- static List ParseM3UFromString(string content)
- {
- List playlistItems = new List();
-
- try
+ public static async Task<(List programList, string programGuide)> DownloadM3UFromWebAsync(string url)
{
- var m3u = SplitStringBeforeSeparator(content, "#EXT");
+ var fileData=await ReadFile(url);
+ // Parse M3U content
+ return ParseM3UFromString(fileData);
+ }
+ private static string[] SplitStringBeforeSeparator(string input, string separator)
+ {
+ string[] parts = input.Split(separator);
- foreach (var line in m3u)
+ // Reconstruct the string until the separator is reached
+ int separatorIndex = input.IndexOf(separator);
+ if (separatorIndex != -1)
{
- if (line.StartsWith("#EXTINF:"))
+ parts[0] = input.Substring(0, separatorIndex + 1);
+ for (int i = 1; i < parts.Length; i++)
{
- if (TryParseM3ULine(line, out var m3uInfo))
+ parts[i] = separator + parts[i];
+ }
+ }
+
+ return parts;
+ }
+
+ private static (List programList, string programGuide) ParseM3UFromString(string content)
+ {
+ List playlistItems = new List();
+ string programGuideLink = string.Empty;
+ try
+ {
+ var m3u = SplitStringBeforeSeparator(content, "#EXT");
+
+ foreach (var line in m3u)
+ {
+ if (line.StartsWith("#EXTINF:"))
{
- playlistItems.Add(m3uInfo);
+ if (TryParseM3ULine(line, out var m3uInfo))
+ {
+ playlistItems.Add(m3uInfo);
+ }
+ }
+ if (line.StartsWith("#EXTM3U"))
+ {
+ programGuideLink=ExtractXtvgUrl(line);
}
}
}
- }
- catch (Exception ex)
- {
- Console.WriteLine("Error reading M3U file: " + ex.Message);
- }
-
- return playlistItems;
- }
-
-
- static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
- {
- info = null;
- string pattern = @"#EXTINF:\d+ CUID=""(?.*?)"" number=""(?.*?)"" tvg-id=""(?.*?)"" tvg-name=""(?.*?)"".*?tvg-logo=""(?.*?)"" group-title=""(?.*?)""[^,]*,(?.*)[^\r](?.*)$";
- Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
-
- Match match = regex.Match(m3uLine);
- if (match.Success)
- {
- info = new M3UInfo
+ catch (Exception ex)
{
- CUID = match.Groups["CUID"].Value,
- Number = match.Groups["Number"].Value,
- TvgID = match.Groups["TvgID"].Value,
- TvgName = match.Groups["TvgName"].Value,
- GroupTitle = match.Groups["GroupTitle"].Value,
- Logo = match.Groups["Logo"].Value,
- Name = match.Groups["Name"].Value,
- Url = match.Groups["URL"].Value
- };
- return true;
+ Console.WriteLine("Error reading M3U file: " + ex.Message);
+ }
+
+ return (playlistItems,programGuideLink);
}
- return false;
+ private static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
+ {
+ info = null;
+ string pattern = @"#EXTINF:\d+ CUID=""(?.*?)"" number=""(?.*?)"" tvg-id=""(?.*?)"" tvg-name=""(?.*?)"".*?tvg-logo=""(?.*?)"" group-title=""(?.*?)""[^,]*,(?.*)[^\r](?.*)$";
+ Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
+
+ Match match = regex.Match(m3uLine);
+ if (match.Success)
+ {
+ info = new M3UInfo
+ {
+ CUID = match.Groups["CUID"].Value,
+ Number = match.Groups["Number"].Value,
+ TvgID = match.Groups["TvgID"].Value,
+ TvgName = match.Groups["TvgName"].Value,
+ GroupTitle = match.Groups["GroupTitle"].Value,
+ Logo = match.Groups["Logo"].Value,
+ Name = match.Groups["Name"].Value,
+ Url = match.Groups["URL"].Value
+ };
+ return true;
+ }
+
+ return false;
+ }
+
+ private static string ExtractXtvgUrl(string m3uEntry)
+ {
+ // Define a regular expression pattern to match x-tvg-url attribute
+ string pattern = @"x-tvg-url=""(.*?)""";
+
+ // Use Regex.Match to find the first match
+ Match match = Regex.Match(m3uEntry, pattern);
+
+ // Check if a match is found and get the value from the capturing group
+ if (match.Success && match.Groups.Count > 1)
+ {
+ return match.Groups[1].Value;
+ }
+
+ // Return null or an empty string if no match is found
+ return string.Empty;
+ }
}
}
-}
diff --git a/TV Player WPF/ViewModels/MainViewModel.cs b/TV Player WPF/ViewModels/MainViewModel.cs
index b212bb9..657a6e7 100644
--- a/TV Player WPF/ViewModels/MainViewModel.cs
+++ b/TV Player WPF/ViewModels/MainViewModel.cs
@@ -2,6 +2,7 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
+using TV_Player.ViewModels;
namespace TV_Player
{
@@ -48,11 +49,14 @@ namespace TV_Player
public Action ButtonBackAction { get; set; }
public ICommand BackCommand { get; }
+ public ICommand SettingsCommand{ get; }
+
public MainViewModel()
{
BackCommand = new RelayCommand(OnButtonBackClick);
FullscreenCommand = new RelayCommand(OnFullSctreenButtonClick);
+ SettingsCommand = new RelayCommand(OnSettingsButtonClick);
CurrentWindowStyle = WindowStyle.SingleBorderWindow;
}
@@ -76,5 +80,10 @@ namespace TV_Player
ButtonBackAction?.Invoke();
}
+
+ private void OnSettingsButtonClick()
+ {
+ TVPlayerViewModel.Instance.ShowSettingsScreen();
+ }
}
}
diff --git a/TV Player WPF/ViewModels/PlayerViewModel.cs b/TV Player WPF/ViewModels/PlayerViewModel.cs
index 9f3897a..59201a6 100644
--- a/TV Player WPF/ViewModels/PlayerViewModel.cs
+++ b/TV Player WPF/ViewModels/PlayerViewModel.cs
@@ -11,7 +11,14 @@ namespace TV_Player
public delegate void SourceUrlChanged(string videoURL);
public event SourceUrlChanged SourceUrlChangedEvent;
- private M3UInfo _currentProgram;
+ private M3UInfo _currentProgram;
+
+ private bool _isProgramInfoVisible;
+ public bool IsProgramInfoVisible
+ {
+ get => _isProgramInfoVisible;
+ set => SetProperty(ref _isProgramInfoVisible, value);
+ }
private string _topPaneTitle;
public string TopPanelTitle
@@ -71,7 +78,7 @@ namespace TV_Player
PreviousCommand = new RelayCommand(PreviousProgram);
FullscreenCommand = new RelayCommand(TVPlayerViewModel.Instance.FullScreenToggle);
- _programSubscriber = ProgramsData.Instance.AllPrograms.Subscribe(x =>
+ _programSubscriber = TVPlayerViewModel.Instance.PlaylistData.AllPrograms.Subscribe(x =>
{
_programs = x.Where(p => p.GroupTitle == _currentProgram.GroupTitle).ToList();
_currentProgramIndex = _programs.Select((program, index) => new { program, index })
@@ -79,7 +86,7 @@ namespace TV_Player
.Select(x => x.index)
.FirstOrDefault();
});
-
+
UpdateUI();
}
@@ -89,7 +96,7 @@ namespace TV_Player
TopPanelTitle = _currentProgram.Name;
SourceUrlChangedEvent?.Invoke(_currentProgram.Url);
- _programGuideDisposable = ProgramsData.Instance.ProgramGuideInfo.Subscribe(x =>
+ _programGuideDisposable = TVPlayerViewModel.Instance.PlaylistData.ProgramGuideInfo.Subscribe(x =>
{
try
{
@@ -125,23 +132,33 @@ namespace TV_Player
}
private void UpdateScreenInfo()
{
- _currentProgramInfo = _currentGuide.Programs.FirstOrDefault(d => d.StartTime <= DateTime.Now && d.StopTime >= DateTime.Now);
- if (_currentProgramInfo.Title != ProgramGuideText)
+ try
{
- ProgramGuideText = _currentProgramInfo.Title;
- StartProgram = _currentProgramInfo.StartTime.ToShortTimeString();
- EndProgram = _currentProgramInfo.StopTime.ToShortTimeString();
+ _currentProgramInfo = _currentGuide.Programs.FirstOrDefault(d => d.StartTime <= DateTime.Now && d.StopTime >= DateTime.Now);
+ if (_currentProgramInfo == null)
+ {
+ IsProgramInfoVisible = false;
+ }
+ else if (_currentProgramInfo.Title != ProgramGuideText)
+ {
+ IsProgramInfoVisible = true;
+ ProgramGuideText = _currentProgramInfo.Title;
+ StartProgram = _currentProgramInfo.StartTime.ToShortTimeString();
+ EndProgram = _currentProgramInfo.StopTime.ToShortTimeString();
+
+ var programMinutes = (_currentProgramInfo.StopTime - _currentProgramInfo.StartTime).TotalMinutes;
+ DurationValue = (int)((DateTime.Now - _currentProgramInfo.StartTime).TotalMinutes / programMinutes * 100);
+ }
+
}
- var programMinutes = (_currentProgramInfo.StopTime - _currentProgramInfo.StartTime).TotalMinutes;
- DurationValue = (int)((DateTime.Now - _currentProgramInfo.StartTime).TotalMinutes / programMinutes * 100);
+ catch
+ { }
}
private void OnButtonBackClick()
{
var groupInfo = new GroupInfo() { Name = _currentProgram.GroupTitle, Count = 0 };
- var programListViewModel = new ProgramsListViewModel(groupInfo);
- var conrtrol = new ProgramsList();
- TVPlayerViewModel.Instance.SetPageContext(conrtrol, programListViewModel);
+ TVPlayerViewModel.Instance.ShowProgramsListScreen(groupInfo);
}
public void Dispose()
{
diff --git a/TV Player WPF/ViewModels/ProgramsData.cs b/TV Player WPF/ViewModels/ProgramsData.cs
index 40fe7df..4f3225e 100644
--- a/TV Player WPF/ViewModels/ProgramsData.cs
+++ b/TV Player WPF/ViewModels/ProgramsData.cs
@@ -4,16 +4,6 @@ namespace TV_Player
{
public class ProgramsData
{
- private static ProgramsData _instance;
- public static ProgramsData Instance
- {
- get
- {
- _instance ??= new ProgramsData();
- return _instance;
- }
- }
-
private readonly ReplaySubject> programsSubject = new ReplaySubject>();
private readonly ReplaySubject> groupsSubject = new ReplaySubject>();
private readonly ReplaySubject> programGuideSubject = new ReplaySubject>();
@@ -21,29 +11,35 @@ namespace TV_Player
public IObservable> GroupsInformation => groupsSubject;
public IObservable> ProgramGuideInfo => programGuideSubject;
- private ProgramsData()
- {
- Task.Run(() => GetPrograms());
- Task.Run(() => GetProgramGuide());
+ public ProgramsData()
+ {
}
- private async Task GetPrograms()
+
+ private async Task GetPrograms(string m3uLink)
{
- string m3uLink = "http://pl.da-tv.vip/a71e77fa/835b3216/tv.m3u";
- var programs = await M3UParser.DownloadM3UFromWebAsync(m3uLink);
+ //string m3uLink = "http://pl.da-tv.vip/a71e77fa/835b3216/tv.m3u";
+ var result = await M3UParser.DownloadM3UFromWebAsync(m3uLink);
+
+ programsSubject.OnNext(result.programList);
- programsSubject.OnNext(programs);
-
- var groupping = programs.GroupBy(item => item.GroupTitle)
+ var groupping = result.programList.GroupBy(item => item.GroupTitle)
.Select(group => new GroupInfo() { Name = group.Key, Count = group.Count() })
.ToList();
groupsSubject.OnNext(groupping);
+
+ await Task.Run(() => GetProgramGuide(result.programGuide));
}
- private async Task GetProgramGuide()
+ private async Task GetProgramGuide(string guideLink)
{
- string guideLink = "http://epg.da-tv.vip/107-light.xml";
+ //string guideLink = "http://epg.da-tv.vip/107-light.xml";
var programGuide = await M3UParser.DownloadGuideFromWebAsync(guideLink);
programGuideSubject.OnNext(programGuide);
}
+
+ internal void GetData(string playlistURL)
+ {
+ Task.Run(() => GetPrograms(playlistURL));
+ }
}
}
diff --git a/TV Player WPF/ViewModels/ProgramsGroupViewModel.cs b/TV Player WPF/ViewModels/ProgramsGroupViewModel.cs
index 6643ccc..c9f20ad 100644
--- a/TV Player WPF/ViewModels/ProgramsGroupViewModel.cs
+++ b/TV Player WPF/ViewModels/ProgramsGroupViewModel.cs
@@ -20,16 +20,14 @@ namespace TV_Player
public ProgramsGroupViewModel()
{
ItemSelectedCommand = new RelayCommand(OnItemSelected);
- _groupInformationSubscriber = ProgramsData.Instance.GroupsInformation.Subscribe(x=>Programs = x);
+ _groupInformationSubscriber = TVPlayerViewModel.Instance.PlaylistData.GroupsInformation.Subscribe(x=>Programs = x);
TVPlayerViewModel.Instance.TopPanelVisible(true, "Группы");
}
private void OnItemSelected()
{
- var programListViewModel = new ProgramsListViewModel(SelectedItem);
- var conrtrol = new ProgramsList();
- TVPlayerViewModel.Instance.SetPageContext(conrtrol, programListViewModel);
+ TVPlayerViewModel.Instance.ShowProgramsListScreen(SelectedItem);
}
public void Dispose()
diff --git a/TV Player WPF/ViewModels/ProgramsListViewModel.cs b/TV Player WPF/ViewModels/ProgramsListViewModel.cs
index 6ce10b5..21cf630 100644
--- a/TV Player WPF/ViewModels/ProgramsListViewModel.cs
+++ b/TV Player WPF/ViewModels/ProgramsListViewModel.cs
@@ -16,26 +16,22 @@ namespace TV_Player
public M3UInfo SelectedItem { get; set; }
public ICommand ItemSelectedCommand { get; }
private IDisposable _programSubscriber;
+
public ProgramsListViewModel(GroupInfo groupInfo)
{
TVPlayerViewModel.Instance.TopPanelVisible(true, groupInfo.Name);
ItemSelectedCommand = new RelayCommand(OnItemSelected);
- _programSubscriber = ProgramsData.Instance.AllPrograms.Subscribe(x => Programs = x.Where(p => p.GroupTitle == groupInfo.Name).ToList());
+ _programSubscriber = TVPlayerViewModel.Instance.PlaylistData.AllPrograms.Subscribe(x => Programs = x.Where(p => p.GroupTitle == groupInfo.Name).ToList());
TVPlayerViewModel.Instance.SetBackButtonAction(new Action(() =>
{
- var programGroupViewModel = new ProgramsGroupViewModel();
- var conrtrol = new ProgramsGroupGrid();
- TVPlayerViewModel.Instance.SetPageContext(conrtrol, programGroupViewModel);
+ TVPlayerViewModel.Instance.ShowProgramsGroupScreen();
}));
}
private void OnItemSelected()
{
- var playerViewModel = new PlayerViewModel(SelectedItem);
- var conrtrol = new VideoPlayer();
- conrtrol.SourceUrl = SelectedItem.Url;
- TVPlayerViewModel.Instance.SetPageContext(conrtrol, playerViewModel);
+ TVPlayerViewModel.Instance.ShowPlayerScreen(SelectedItem);
}
public void Dispose()
diff --git a/TV Player WPF/ViewModels/RelayCommand.cs b/TV Player WPF/ViewModels/RelayCommand.cs
deleted file mode 100644
index 90ad717..0000000
--- a/TV Player WPF/ViewModels/RelayCommand.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Windows.Input;
-
-namespace TV_Player.ViewModels
-{
- //public class RelayCommand : ICommand
- //{
- // private readonly Action _execute;
- // private readonly Func _canExecute;
-
- // public event EventHandler CanExecuteChanged;
-
- // public RelayCommand(Action execute, Func canExecute = null)
- // {
- // _execute = execute ?? throw new ArgumentNullException(nameof(execute));
- // _canExecute = canExecute;
- // }
-
- // public bool CanExecute(object parameter)
- // {
- // return _canExecute == null || _canExecute();
- // }
-
- // public void Execute(object parameter)
- // {
- // _execute();
- // }
-
- // public void RaiseCanExecuteChanged()
- // {
- // CanExecuteChanged?.Invoke(this, EventArgs.Empty);
- // }
- //}
-}
diff --git a/TV Player WPF/ViewModels/SettingsModel.cs b/TV Player WPF/ViewModels/SettingsModel.cs
new file mode 100644
index 0000000..e6c7163
--- /dev/null
+++ b/TV Player WPF/ViewModels/SettingsModel.cs
@@ -0,0 +1,64 @@
+using Newtonsoft.Json;
+using System.IO;
+
+namespace TV_Player.ViewModels
+{
+ public static class SettingsModel
+ {
+ private const string _filePath = "settings.json";
+
+ public static string PlaylistURL { get; set; }
+ public static bool StartFullScreen { get; set; }
+ public static bool StartFromLastScreen { get; set; }
+ public static string LastScreen { get; set; }
+ public static GroupInfo Group { get; set; }
+ public static M3UInfo Program { get; set; }
+
+
+ public static void SaveSetttings()
+ {
+ // Create an anonymous object to hold the properties
+ var dataToSerialize = new
+ {
+ PlaylistURL,
+ StartFromLastScreen,
+ StartFullScreen,
+ LastScreen,
+ Group,
+ Program
+ };
+
+ // Serialize the object to JSON
+ string json = JsonConvert.SerializeObject(dataToSerialize, Formatting.Indented);
+
+ // Save the JSON to a file
+ File.WriteAllText(_filePath, json);
+ }
+
+ public static void LoadSettings()
+ {
+ var loadedData = new
+ {
+ PlaylistURL = default(string),
+ LastScreen = default(string),
+ Group = default(GroupInfo),
+ Program = default(M3UInfo),
+ StartFromLastScreen = default(bool),
+ StartFullScreen = default(bool)
+ };
+ if (File.Exists(_filePath))
+ {
+ // Read the JSON content from the file
+ string json = File.ReadAllText(_filePath);
+ loadedData = JsonConvert.DeserializeAnonymousType(json, loadedData);
+ }
+ // Assign the values to the properties
+ PlaylistURL = loadedData.PlaylistURL;
+ LastScreen = loadedData.LastScreen;
+ Group = loadedData.Group;
+ Program = loadedData.Program;
+ StartFromLastScreen = loadedData.StartFromLastScreen;
+ StartFullScreen = loadedData.StartFullScreen;
+ }
+ }
+}
diff --git a/TV Player WPF/ViewModels/SettingsViewModel.cs b/TV Player WPF/ViewModels/SettingsViewModel.cs
new file mode 100644
index 0000000..4e3ba47
--- /dev/null
+++ b/TV Player WPF/ViewModels/SettingsViewModel.cs
@@ -0,0 +1,59 @@
+using CommunityToolkit.Mvvm.Input;
+using System.Windows.Input;
+
+namespace TV_Player.ViewModels
+{
+ internal class SettingsViewModel : ObservableViewModelBase
+ {
+ private string _playlistURL;
+ public string PlaylistURL
+ {
+ get => _playlistURL;
+ set => SetProperty(ref _playlistURL, value);
+ }
+
+ private bool _startFullScreen;
+ public bool StartFullScreen
+ {
+ get => _startFullScreen;
+ set => SetProperty(ref _startFullScreen, value);
+ }
+
+ private bool _startLastScreen;
+ public bool StartLastScreen
+ {
+ get => _startLastScreen;
+ set => SetProperty(ref _startLastScreen, value);
+ }
+
+ public ICommand SaveCommand { get; }
+ public ICommand BackCommand { get; }
+
+ public SettingsViewModel()
+ {
+ TVPlayerViewModel.Instance.TopPanelVisible(false, "");
+
+ SaveCommand = new RelayCommand(OnSaveSettings);
+ BackCommand = new RelayCommand(OnBackCommand);
+
+ StartFullScreen = SettingsModel.StartFullScreen;
+ StartLastScreen = SettingsModel.StartFromLastScreen;
+ PlaylistURL = SettingsModel.PlaylistURL;
+ }
+
+ private void OnBackCommand()
+ {
+ TVPlayerViewModel.Instance.SelectScreen();
+ }
+
+ private void OnSaveSettings()
+ {
+ SettingsModel.StartFullScreen = StartFullScreen;
+ SettingsModel.StartFromLastScreen = StartLastScreen;
+ SettingsModel.PlaylistURL = PlaylistURL;
+
+ SettingsModel.SaveSetttings();
+ TVPlayerViewModel.Instance.InitializeTVWithData();
+ }
+ }
+}
\ No newline at end of file
diff --git a/TV Player WPF/ViewModels/TVPlayerViewModel.cs b/TV Player WPF/ViewModels/TVPlayerViewModel.cs
index 76bd9f7..e956588 100644
--- a/TV Player WPF/ViewModels/TVPlayerViewModel.cs
+++ b/TV Player WPF/ViewModels/TVPlayerViewModel.cs
@@ -5,6 +5,7 @@ namespace TV_Player.ViewModels
public class TVPlayerViewModel : IDisposable
{
private readonly MainViewModel _mainViewModel;
+ public ProgramsData PlaylistData { get; private set; }
public Action ButtonBackAction { get; set; }
@@ -21,6 +22,8 @@ namespace TV_Player.ViewModels
public TVPlayerViewModel()
{
+ PlaylistData = new ProgramsData();
+
_mainViewModel = new MainViewModel();
var mainWindow = new MainWindow();
mainWindow.DataContext = _mainViewModel;
@@ -28,19 +31,81 @@ namespace TV_Player.ViewModels
mainWindow.Show();
_instance = this;
- ShowInitialScreen();
+ SettingsModel.LoadSettings();
+ InitializeTVWithData();
}
- private void ShowInitialScreen()
+ public void InitializeTVWithData()
+ {
+ if (!string.IsNullOrEmpty(SettingsModel.PlaylistURL))
+ {
+ if (SettingsModel.StartFullScreen)
+ FullScreenToggle();
+ PlaylistData.GetData(SettingsModel.PlaylistURL);
+ if (SettingsModel.StartFromLastScreen)
+ SelectScreen();
+ else
+ ShowProgramsGroupScreen();
+ }
+ else
+ {
+ ShowSettingsScreen();
+ }
+ }
+
+ public void SelectScreen()
+ {
+ switch (SettingsModel.LastScreen)
+ {
+ case "ProgramsListViewModel":
+ ShowProgramsListScreen(SettingsModel.Group);
+ break;
+ case "PlayerViewModel":
+ ShowPlayerScreen(SettingsModel.Program);
+ break;
+ default:
+ ShowProgramsGroupScreen();
+ break;
+ }
+ }
+
+ public void ShowProgramsGroupScreen()
{
var vm = new ProgramsGroupViewModel();
var control = new ProgramsGroupGrid();
control.DataContext = vm;
+ SettingsModel.LastScreen = nameof(ProgramsGroupViewModel);
SetPageContext(control, vm);
}
+ public void ShowProgramsListScreen(GroupInfo group)
+ {
+ SettingsModel.Group = group;
+ var programListViewModel = new ProgramsListViewModel(group);
+ var conrtrol = new ProgramsList();
+ SettingsModel.LastScreen = nameof(ProgramsListViewModel);
+ SetPageContext(conrtrol, programListViewModel);
+ }
+
+ public void ShowPlayerScreen(M3UInfo program)
+ {
+ SettingsModel.Program = program;
+ var playerViewModel = new PlayerViewModel(program);
+ var conrtrol = new VideoPlayer();
+ conrtrol.SourceUrl = program.Url;
+ SettingsModel.LastScreen = nameof(PlayerViewModel);
+ SetPageContext(conrtrol, playerViewModel);
+ }
+
+ public void ShowSettingsScreen()
+ {
+ var playerViewModel = new SettingsViewModel();
+ var conrtrol = new Settings();
+ SetPageContext(conrtrol, playerViewModel);
+ }
+
public void TopPanelVisible(bool value, string title)
{
_mainViewModel.IsTopPanelVisible = value;
@@ -57,13 +122,15 @@ namespace TV_Player.ViewModels
_mainViewModel.ButtonBackAction = action;
}
- public void SetPageContext(ContentControl control, object viewModel)
+ private void SetPageContext(ContentControl control, object viewModel)
{
if (_mainViewModel.Control is IDisposable disposable)
disposable.Dispose();
control.DataContext = viewModel;
_mainViewModel.Control = control;
+
+ SettingsModel.SaveSetttings();
}
public void Dispose()