first version
This commit is contained in:
@@ -5,20 +5,20 @@
|
|||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="{x:Type controls:GroupButton}">
|
<ControlTemplate TargetType="{x:Type controls:GroupButton}">
|
||||||
<Grid x:Name="ButtonBorder" Height="70" Width="150" >
|
<Border x:Name="ButtonBorder" Height="70" Width="150" >
|
||||||
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="0.4*"/>
|
<RowDefinition Height="0.4*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Rectangle RadiusX="15" RadiusY="15" x:Name="Border" StrokeThickness="3" Stroke="Yellow" Stretch="Fill" Grid.RowSpan="2" Fill="#FF1F1E1E"/>
|
<Rectangle RadiusX="15" RadiusY="15" x:Name="Border" StrokeThickness="2" Stroke="Yellow" Stretch="Fill" Grid.RowSpan="2" Fill="#B0000000"/>
|
||||||
<TextBlock x:Name="groupName" Text="{TemplateBinding GroupName}" FontSize="15" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
<TextBlock x:Name="groupName" Text="{TemplateBinding GroupName}" FontSize="15" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
<TextBlock Grid.Row="1" FontSize="10" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" LineStackingStrategy="BlockLineHeight" LineHeight="10">
|
<TextBlock Grid.Row="1" FontSize="10" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" LineStackingStrategy="BlockLineHeight" LineHeight="10">
|
||||||
<Run Text="{TemplateBinding ProgramsCount}"/>
|
<Run Text="{TemplateBinding ProgramsCount}"/>
|
||||||
<Run>Programs</Run>
|
<Run>программ</Run>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Border>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
@@ -45,6 +45,54 @@ 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-
|
|||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="ButtonUp" TargetType="{x:Type Button}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
|
<Border Background="Yellow" Height="50" Width="50" CornerRadius="300">
|
||||||
|
<Viewbox Margin="0,6,5,5">
|
||||||
|
<Path VerticalAlignment="Center" HorizontalAlignment="Center" Fill="Gray" Data="M48.252,69.253c-2.271,0-4.405-0.884-6.011-2.489L17.736,42.258c-1.646-1.645-2.546-3.921-2.479-6.255
|
||||||
|
c-0.068-2.337,0.833-4.614,2.479-6.261L42.242,5.236c1.605-1.605,3.739-2.489,6.01-2.489c2.271,0,4.405,0.884,6.01,2.489
|
||||||
|
c3.314,3.314,3.314,8.707,0,12.021L35.519,36l18.743,18.742c3.314,3.314,3.314,8.707,0,12.021
|
||||||
|
C52.656,68.369,50.522,69.253,48.252,69.253z M48.252,6.747c-1.202,0-2.332,0.468-3.182,1.317L21.038,32.57
|
||||||
|
c-0.891,0.893-0.833,2.084-0.833,3.355c0,0.051,0,0.101,0,0.151c0,1.271-0.058,2.461,0.833,3.353l24.269,24.506
|
||||||
|
c0.85,0.85,1.862,1.317,3.063,1.317c1.203,0,2.273-0.468,3.123-1.317c1.755-1.755,1.725-4.61-0.03-6.365L31.292,37.414
|
||||||
|
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-6.365C50.587,7.215,49.454,6.747,48.252,6.747z" Stretch="Fill" Width="50">
|
||||||
|
<Path.LayoutTransform>
|
||||||
|
<RotateTransform Angle="90"></RotateTransform>
|
||||||
|
</Path.LayoutTransform>
|
||||||
|
</Path>
|
||||||
|
</Viewbox>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="ButtonDown" TargetType="{x:Type Button}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
|
<Border Background="Yellow" Height="50" Width="50" CornerRadius="300">
|
||||||
|
<Viewbox Margin="0,6,5,5">
|
||||||
|
<Path VerticalAlignment="Center" HorizontalAlignment="Center" Fill="Gray" Data="M48.252,69.253c-2.271,0-4.405-0.884-6.011-2.489L17.736,42.258c-1.646-1.645-2.546-3.921-2.479-6.255
|
||||||
|
c-0.068-2.337,0.833-4.614,2.479-6.261L42.242,5.236c1.605-1.605,3.739-2.489,6.01-2.489c2.271,0,4.405,0.884,6.01,2.489
|
||||||
|
c3.314,3.314,3.314,8.707,0,12.021L35.519,36l18.743,18.742c3.314,3.314,3.314,8.707,0,12.021
|
||||||
|
C52.656,68.369,50.522,69.253,48.252,69.253z M48.252,6.747c-1.202,0-2.332,0.468-3.182,1.317L21.038,32.57
|
||||||
|
c-0.891,0.893-0.833,2.084-0.833,3.355c0,0.051,0,0.101,0,0.151c0,1.271-0.058,2.461,0.833,3.353l24.269,24.506
|
||||||
|
c0.85,0.85,1.862,1.317,3.063,1.317c1.203,0,2.273-0.468,3.123-1.317c1.755-1.755,1.725-4.61-0.03-6.365L31.292,37.414
|
||||||
|
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-6.365C50.587,7.215,49.454,6.747,48.252,6.747z" Stretch="Fill" Width="50">
|
||||||
|
<Path.LayoutTransform>
|
||||||
|
<RotateTransform Angle="270"></RotateTransform>
|
||||||
|
</Path.LayoutTransform>
|
||||||
|
</Path>
|
||||||
|
</Viewbox>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
<Style x:Key="ButtonFullScreen" TargetType="{x:Type Button}">
|
<Style x:Key="ButtonFullScreen" TargetType="{x:Type Button}">
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
@@ -75,4 +123,77 @@ 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-
|
|||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style x:Key="ListBoxView" TargetType="ListView">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||||
|
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
|
||||||
|
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
|
||||||
|
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
|
||||||
|
<Setter Property="ScrollViewer.PanningMode" Value="VerticalOnly"/>
|
||||||
|
<Setter Property="VirtualizingPanel.IsVirtualizing" Value="True"/>
|
||||||
|
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
|
||||||
|
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling" />
|
||||||
|
<Setter Property="VirtualizingPanel.IsContainerVirtualizable" Value="True" />
|
||||||
|
<Style.Resources>
|
||||||
|
<Style x:Key="ScrollThumbs" TargetType="{x:Type Thumb}">
|
||||||
|
<Setter Property="Background" Value="#3E85C3" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||||
|
<Grid Name="Grid">
|
||||||
|
<Rectangle Name="Rectangle1"
|
||||||
|
Width="7" MinHeight="10"
|
||||||
|
Height="Auto"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Fill="{TemplateBinding Background}"
|
||||||
|
RadiusX="3"
|
||||||
|
RadiusY="3" />
|
||||||
|
</Grid>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsDragging" Value="True">
|
||||||
|
<Setter TargetName="Rectangle1" Property="Border.BorderThickness" Value="2"></Setter>
|
||||||
|
<Setter TargetName="Rectangle1" Property="Border.BorderBrush" Value="#003663"></Setter>
|
||||||
|
<Setter Property="Background" Value="#003663"></Setter>
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style TargetType="{x:Type ScrollBar}">
|
||||||
|
<Setter Property="Margin" Value="0"></Setter>
|
||||||
|
<Setter Property="Padding" Value="0"></Setter>
|
||||||
|
<Setter Property="Background" Value="#ecf0f6" />
|
||||||
|
<Setter Property="Width" Value="19" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type ScrollBar}">
|
||||||
|
<Grid x:Name="GridRoot"
|
||||||
|
AutomationProperties.AutomationId="HS000_AD_43"
|
||||||
|
Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidth}}"
|
||||||
|
Background="{TemplateBinding Background}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition MaxHeight="9" />
|
||||||
|
<RowDefinition Height="0.00001*" />
|
||||||
|
<RowDefinition MaxHeight="9" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Track x:Name="PART_Track"
|
||||||
|
Grid.Row="1"
|
||||||
|
Focusable="false"
|
||||||
|
IsDirectionReversed="true">
|
||||||
|
<Track.Thumb>
|
||||||
|
<Thumb x:Name="Thumb"
|
||||||
|
|
||||||
|
Style="{DynamicResource ScrollThumbs}" />
|
||||||
|
</Track.Thumb>
|
||||||
|
</Track>
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</Style.Resources>
|
||||||
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Grid Visibility="{Binding IsTopPanelVisible,Converter={StaticResource BooleanToVisibilityConverterKey}}" Height="70">
|
<Grid Visibility="{Binding IsTopPanelVisible,Converter={StaticResource BooleanToVisibilityConverterKey}}" Height="70">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="70"/>
|
<ColumnDefinition Width="70"/>
|
||||||
@@ -30,7 +29,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Button Height="50" Width="50" Margin="10,0,0,0" Style="{DynamicResource ButtonGear}" />
|
<Button Height="50" Width="50" Margin="10,0,0,0" Style="{DynamicResource ButtonGear}" />
|
||||||
<Button Grid.Column="1" Height="50" Width="50" Margin="10,0,0,0" Style="{DynamicResource ButtonBack}" Command="{Binding BackCommand}" />
|
<Button Grid.Column="1" Height="50" Width="50" Margin="10,0,0,0" Style="{DynamicResource ButtonBack}" Command="{Binding BackCommand}" />
|
||||||
<TextBlock Grid.Column="2" FontSize="20" Foreground="White" Text="{Binding TopPanelTitle}" HorizontalAlignment="Center"/>
|
<TextBlock Grid.Column="2" FontSize="30" Foreground="White" Text="{Binding TopPanelTitle}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
<Button Grid.Column="4" Height="50" Width="50" Margin="10,0,0,0" Style="{DynamicResource ButtonFullScreen}" Command="{Binding FullscreenCommand}" />
|
<Button Grid.Column="4" Height="50" Width="50" Margin="10,0,0,0" Style="{DynamicResource ButtonFullScreen}" Command="{Binding FullscreenCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<ContentControl Grid.Row="1" Name="ControlContainer" Content="{Binding Control}" />
|
<ContentControl Grid.Row="1" Name="ControlContainer" Content="{Binding Control}" />
|
||||||
|
|||||||
@@ -5,23 +5,26 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:tv_player="clr-namespace:TV_Player"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:tv_player="clr-namespace:TV_Player"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<Grid x:Name="groupsGrid">
|
|
||||||
<ScrollViewer>
|
<Grid x:Name="groupsGrid" VerticalAlignment="Center">
|
||||||
<ListBox ItemsSource="{Binding Programs}" Background="Transparent"
|
<ListView ItemsSource="{Binding Programs}" Background="Transparent"
|
||||||
SelectionMode="Single"
|
SelectionMode="Single" Style="{StaticResource ListBoxView}"
|
||||||
SelectedItem="{Binding SelectedItem}"
|
SelectedItem="{Binding SelectedItem}" BorderThickness="0"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||||
SelectionChanged="ListBox_SelectionChanged">
|
SelectionChanged="ListBox_SelectionChanged">
|
||||||
<ListBox.ItemsPanel>
|
<ListBox.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<UniformGrid Rows="4" />
|
<UniformGrid Rows="4" />
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</ListBox.ItemsPanel>
|
</ListBox.ItemsPanel>
|
||||||
<ListBox.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<tv_player:GroupButton Style="{DynamicResource GroupButton}" GroupName="{Binding Name}" ProgramsCount="{Binding Count}"/>
|
<Viewbox HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
</DataTemplate>
|
<tv_player:GroupButton Style="{DynamicResource GroupButton}" GroupName="{Binding Name}" ProgramsCount="{Binding Count}"/>
|
||||||
</ListBox.ItemTemplate>
|
</Viewbox>
|
||||||
</ListBox>
|
</DataTemplate>
|
||||||
</ScrollViewer>
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -5,26 +5,35 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<Grid x:Name="groupsGrid">
|
<Grid x:Name="programsGrid">
|
||||||
<ScrollViewer>
|
<ListView ItemsSource="{Binding Programs}" Background="Transparent" VerticalAlignment="Top" Margin="0,50,0,0"
|
||||||
<ListBox ItemsSource="{Binding Programs}" Background="Transparent"
|
SelectionMode="Single" Style="{StaticResource ListBoxView}"
|
||||||
SelectionMode="Single"
|
SelectedItem="{Binding SelectedItem}" BorderThickness="0"
|
||||||
SelectedItem="{Binding SelectedItem}"
|
|
||||||
SelectionChanged="ListBox_SelectionChanged">
|
SelectionChanged="ListBox_SelectionChanged">
|
||||||
<ListBox.ItemsPanel>
|
<ListView.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<UniformGrid Rows="4" />
|
<UniformGrid Columns="17" />
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</ListBox.ItemsPanel>
|
</ListView.ItemsPanel>
|
||||||
<ListBox.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel>
|
<Viewbox HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
<Image Source="{Binding Logo}" Width="50" Height="50" HorizontalAlignment="Center"/>
|
<Border Height="145" Width="106" HorizontalAlignment="Center" CornerRadius="5" BorderBrush="Yellow" BorderThickness="2">
|
||||||
<TextBlock Text="{Binding Name}" FontSize="15" Foreground="White" HorizontalAlignment="Center"/>
|
<Grid Margin="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="#B0000000">
|
||||||
</StackPanel>
|
<Grid.RowDefinitions>
|
||||||
</DataTemplate>
|
<RowDefinition Height="*"/>
|
||||||
</ListBox.ItemTemplate>
|
<RowDefinition Height=".4*"/>
|
||||||
</ListBox>
|
</Grid.RowDefinitions>
|
||||||
</ScrollViewer>
|
<Image Source="{Binding Logo}" MaxWidth="100" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,10"/>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Text="{Binding Name}" FontSize="15" TextAlignment="Center" Foreground="White" HorizontalAlignment="Center" TextWrapping="Wrap" Margin="1,0,1,2"/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Viewbox>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -22,20 +22,33 @@
|
|||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="70"/>
|
<ColumnDefinition Width="70"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="70"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Button Height="50" Width="50" Margin="10,0,0,0" Style="{DynamicResource ButtonBack}" Command="{Binding BackCommand}" />
|
<Button Height="50" Width="50" Margin="10,0,0,0" Style="{DynamicResource ButtonBack}" Command="{Binding BackCommand}" />
|
||||||
<TextBlock Grid.Column="1" FontSize="20" Foreground="White" Text="{Binding TopPanelTitle}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
<TextBlock Grid.Column="1" FontSize="20" Foreground="White" Text="{Binding TopPanelTitle}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
|
<Button Grid.Column="4" Height="50" Width="50" Margin="10,0,0,0" Style="{DynamicResource ButtonFullScreen}" Command="{Binding FullscreenCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid Grid.Row="2" Background="#70000000">
|
<Grid Grid.Row="2" Background="#70000000">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="180"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="70"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock FontSize="20" Foreground="White" Text="{Binding ProgramGuideText}" HorizontalAlignment="Center" />
|
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Grid.Row="1">
|
<StackPanel Grid.RowSpan="2" Orientation="Horizontal" >
|
||||||
<TextBlock FontSize="10" Foreground="White" Text="{Binding StartProgram}" HorizontalAlignment="Center" />
|
<Button Grid.RowSpan="2" Height="50" Width="50" Margin="10,0,10,0" Style="{DynamicResource ButtonDown}" Command="{Binding PreviousCommand}" />
|
||||||
|
<TextBlock FontSize="15" Foreground="White" Text="Ch" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
<Button Grid.RowSpan="2" Height="50" Width="50" Margin="10,0,10,0" Style="{DynamicResource ButtonUp}" Command="{Binding NextCommand}" />
|
||||||
|
</StackPanel>
|
||||||
|
<TextBlock Grid.Column="1" FontSize="20" Foreground="White" Text="{Binding ProgramGuideText}" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Grid.Column="1" Grid.Row="1">
|
||||||
|
<TextBlock FontSize="15" Foreground="White" Text="{Binding StartProgram}" HorizontalAlignment="Center" />
|
||||||
<ProgressBar Height="10" Foreground="Yellow" Name="progressBar" Value="{Binding DurationValue}" Maximum="100" VerticalAlignment="Center" HorizontalAlignment="Center" Width="400"/>
|
<ProgressBar Height="10" Foreground="Yellow" Name="progressBar" Value="{Binding DurationValue}" Maximum="100" VerticalAlignment="Center" HorizontalAlignment="Center" Width="400"/>
|
||||||
<TextBlock FontSize="10" Foreground="White" Text="{Binding EndProgram}" HorizontalAlignment="Center" />
|
<TextBlock FontSize="15" Foreground="White" Text="{Binding EndProgram}" HorizontalAlignment="Center" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -11,21 +11,11 @@ namespace TV_Player
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class VideoPlayer : UserControl
|
public partial class VideoPlayer : UserControl
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty SourceUrlProperty =
|
public string SourceUrl { get; set; }
|
||||||
DependencyProperty.Register(
|
|
||||||
"SourceUrl", // Name of the property
|
|
||||||
typeof(string), // Type of the property
|
|
||||||
typeof(VideoPlayer), // Type of the owner class
|
|
||||||
new PropertyMetadata(string.Empty) // Default value
|
|
||||||
);
|
|
||||||
public string SourceUrl
|
|
||||||
{
|
|
||||||
get { return (string)GetValue(SourceUrlProperty); }
|
|
||||||
set { SetValue(SourceUrlProperty, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private LibVLC _libVLC;
|
private LibVLC _libVLC;
|
||||||
private MediaPlayer _mediaPlayer;
|
private MediaPlayer _mediaPlayer;
|
||||||
|
private PlayerViewModel _viewModel;
|
||||||
|
|
||||||
public VideoPlayer()
|
public VideoPlayer()
|
||||||
{
|
{
|
||||||
@@ -33,6 +23,12 @@ namespace TV_Player
|
|||||||
|
|
||||||
_libVLC = new LibVLC(enableDebugLogs: true);
|
_libVLC = new LibVLC(enableDebugLogs: true);
|
||||||
_mediaPlayer = new MediaPlayer(_libVLC);
|
_mediaPlayer = new MediaPlayer(_libVLC);
|
||||||
|
this.DataContextChanged += (sender, e) =>
|
||||||
|
{
|
||||||
|
_viewModel = (PlayerViewModel)e.NewValue;
|
||||||
|
_viewModel.SourceUrlChangedEvent += _viewModel_SourceUrlChangedEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
VideoView.Loaded += (sender, e) =>
|
VideoView.Loaded += (sender, e) =>
|
||||||
{
|
{
|
||||||
@@ -43,7 +39,15 @@ namespace TV_Player
|
|||||||
AutoPlay();
|
AutoPlay();
|
||||||
};
|
};
|
||||||
Unloaded += VideoPlayer_Unloaded;
|
Unloaded += VideoPlayer_Unloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _viewModel_SourceUrlChangedEvent(string videoURL)
|
||||||
|
{
|
||||||
|
SourceUrl = videoURL;
|
||||||
|
VideoView.MediaPlayer.Stop();
|
||||||
|
VideoView.MediaPlayer.Media.Dispose();
|
||||||
|
|
||||||
|
AutoPlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VideoView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
private void VideoView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
@@ -55,8 +59,6 @@ namespace TV_Player
|
|||||||
{
|
{
|
||||||
VideoView.Dispose();
|
VideoView.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PauseButton_Click(object sender, RoutedEventArgs e)
|
void PauseButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (VideoView.MediaPlayer.IsPlaying)
|
if (VideoView.MediaPlayer.IsPlaying)
|
||||||
@@ -64,28 +66,22 @@ namespace TV_Player
|
|||||||
VideoView.MediaPlayer.Pause();
|
VideoView.MediaPlayer.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AutoPlay()
|
private void AutoPlay()
|
||||||
{
|
{
|
||||||
if (!VideoView.MediaPlayer.IsPlaying)
|
if (!VideoView.MediaPlayer.IsPlaying)
|
||||||
{
|
{
|
||||||
|
|
||||||
using (var media = new Media(_libVLC, new Uri(SourceUrl)))
|
using (var media = new Media(_libVLC, new Uri(SourceUrl)))
|
||||||
VideoView.MediaPlayer.Play(media);
|
VideoView.MediaPlayer.Play(media);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void MyUserControl_MouseDown(object sender, MouseButtonEventArgs e)
|
private void MyUserControl_MouseDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
ToggleOverlay();
|
ToggleOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MyUserControl_TouchDown(object sender, TouchEventArgs e)
|
private void MyUserControl_TouchDown(object sender, TouchEventArgs e)
|
||||||
{
|
{
|
||||||
ToggleOverlay();
|
ToggleOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleOverlay()
|
private void ToggleOverlay()
|
||||||
{
|
{
|
||||||
if (overlayPanel.Visibility == Visibility.Visible)
|
if (overlayPanel.Visibility == Visibility.Visible)
|
||||||
@@ -97,19 +93,17 @@ namespace TV_Player
|
|||||||
ShowOverlay();
|
ShowOverlay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowOverlay()
|
public void ShowOverlay()
|
||||||
{
|
{
|
||||||
overlayPanel.Visibility = Visibility.Visible;
|
overlayPanel.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HideOverlay()
|
public void HideOverlay()
|
||||||
{
|
{
|
||||||
overlayPanel.Visibility = Visibility.Collapsed;
|
overlayPanel.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
|
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
_viewModel.SourceUrlChangedEvent -= _viewModel_SourceUrlChangedEvent;
|
||||||
VideoView.MediaPlayer?.Dispose();
|
VideoView.MediaPlayer?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Channels;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
|
||||||
namespace TV_Player
|
namespace TV_Player
|
||||||
@@ -11,10 +12,10 @@ namespace TV_Player
|
|||||||
private int _durationValue;
|
private int _durationValue;
|
||||||
|
|
||||||
public string Title { get => _title; set => SetProperty(ref _title, value); }
|
public string Title { get => _title; set => SetProperty(ref _title, value); }
|
||||||
|
|
||||||
public DateTime StartTime { get; set; }
|
public DateTime StartTime { get; set; }
|
||||||
public DateTime StopTime { get; set; }
|
public DateTime StopTime { get; set; }
|
||||||
public int DurationValue { get => _durationValue; set => SetProperty(ref _durationValue , value); }
|
public int DurationValue { get => _durationValue; set => SetProperty(ref _durationValue, value); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,151 +50,174 @@ namespace TV_Player
|
|||||||
private static List<ProgramGuide> ParseEpg(string epgData)
|
private static List<ProgramGuide> ParseEpg(string epgData)
|
||||||
{
|
{
|
||||||
List<ProgramGuide> epgChannels = new List<ProgramGuide>();
|
List<ProgramGuide> epgChannels = new List<ProgramGuide>();
|
||||||
|
XmlReaderSettings settings = new XmlReaderSettings();
|
||||||
|
settings.IgnoreWhitespace = true;
|
||||||
|
settings.IgnoreComments = true;
|
||||||
|
|
||||||
using (XmlReader reader = XmlReader.Create(new System.IO.StringReader(epgData)))
|
using (XmlReader reader = XmlReader.Create(new System.IO.StringReader(epgData), settings))
|
||||||
{
|
{
|
||||||
ProgramGuide currentChannel = null;
|
try
|
||||||
XmlDocument doc = new XmlDocument();
|
|
||||||
doc.LoadXml(epgData);
|
|
||||||
|
|
||||||
XmlNodeList channelNodes = doc.SelectNodes("//channel");
|
|
||||||
|
|
||||||
foreach (XmlNode channelNode in channelNodes)
|
|
||||||
{
|
{
|
||||||
ProgramGuide channel = new ProgramGuide();
|
while (reader.Read())
|
||||||
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();
|
if (reader.NodeType == XmlNodeType.Element && reader.Name == "channel")
|
||||||
program.Title = programNode.SelectSingleNode("title").InnerText;
|
{
|
||||||
program.StartTime = DateTime.ParseExact(programNode.Attributes["start"].Value, "yyyyMMddHHmmss zzz", null);
|
ProgramGuide channel = new ProgramGuide();
|
||||||
program.StopTime = DateTime.ParseExact(programNode.Attributes["stop"].Value, "yyyyMMddHHmmss zzz", null);
|
channel.Id = reader.GetAttribute("id");
|
||||||
|
reader.Read();
|
||||||
|
channel.DisplayName = reader.ReadElementContentAsString();
|
||||||
|
|
||||||
channel.Programs.Add(program);
|
epgChannels.Add(channel);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.NodeType == XmlNodeType.Element && reader.Name == "programme")
|
||||||
|
{
|
||||||
|
ProgramInfo program = new ProgramInfo();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "channel")
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
epgChannels.Add(channel);
|
|
||||||
}
|
}
|
||||||
//while (reader.Read())
|
catch (Exception ex) {
|
||||||
//{
|
|
||||||
// if (reader.NodeType == XmlNodeType.Element)
|
|
||||||
// {
|
|
||||||
// if (reader.Name == "channel")
|
|
||||||
// {
|
|
||||||
// currentChannel = new ProgramGuide();
|
|
||||||
// currentChannel.Id = reader.GetAttribute("id");
|
|
||||||
// currentChannel.DisplayName = reader.ReadElementContentAsString();
|
|
||||||
// epgChannels.Add(currentChannel);
|
|
||||||
// }
|
|
||||||
// else if (reader.Name == "programme" && currentChannel != null)
|
|
||||||
// {
|
|
||||||
// ProgramInfo program = new ProgramInfo();
|
|
||||||
// program.Title = reader.ReadElementContentAsString();
|
|
||||||
// program.StartTime = DateTime.ParseExact(reader.GetAttribute("start"), "yyyyMMddHHmmss zzz", null);
|
|
||||||
// program.StopTime = DateTime.ParseExact(reader.GetAttribute("stop"), "yyyyMMddHHmmss zzz", null);
|
|
||||||
// currentChannel.Programs.Add(program);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
//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;
|
return epgChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static async Task<List<M3UInfo>> DownloadM3UFromWebAsync(string url)
|
public static async Task<List<M3UInfo>> DownloadM3UFromWebAsync(string url)
|
||||||
|
{
|
||||||
|
List<M3UInfo> playlistItems = new List<M3UInfo>();
|
||||||
|
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
using (var request = new HttpRequestMessage())
|
||||||
{
|
{
|
||||||
List<M3UInfo> playlistItems = new List<M3UInfo>();
|
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();
|
||||||
|
|
||||||
using (var client = new HttpClient())
|
// Parse M3U content
|
||||||
using (var request = new HttpRequestMessage())
|
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++)
|
||||||
{
|
{
|
||||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/text"));
|
parts[i] = separator + parts[i];
|
||||||
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)
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<M3UInfo> ParseM3UFromString(string content)
|
||||||
|
{
|
||||||
|
List<M3UInfo> playlistItems = new List<M3UInfo>();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
string[] parts = input.Split(separator);
|
var m3u = SplitStringBeforeSeparator(content, "#EXT");
|
||||||
|
|
||||||
// Reconstruct the string until the separator is reached
|
foreach (var line in m3u)
|
||||||
int separatorIndex = input.IndexOf(separator);
|
|
||||||
if (separatorIndex != -1)
|
|
||||||
{
|
{
|
||||||
parts[0] = input.Substring(0, separatorIndex + 1);
|
if (line.StartsWith("#EXTINF:"))
|
||||||
for (int i = 1; i < parts.Length; i++)
|
|
||||||
{
|
{
|
||||||
parts[i] = separator + parts[i];
|
if (TryParseM3ULine(line, out var m3uInfo))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<M3UInfo> ParseM3UFromString(string content)
|
|
||||||
{
|
|
||||||
List<M3UInfo> playlistItems = new List<M3UInfo>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var m3u = SplitStringBeforeSeparator(content, "#EXT");
|
|
||||||
|
|
||||||
foreach (var line in m3u)
|
|
||||||
{
|
|
||||||
if (line.StartsWith("#EXTINF:"))
|
|
||||||
{
|
{
|
||||||
if (TryParseM3ULine(line, out var m3uInfo))
|
playlistItems.Add(m3uInfo);
|
||||||
{
|
|
||||||
playlistItems.Add(m3uInfo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Error reading M3U file: " + ex.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return playlistItems;
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
|
||||||
static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
|
|
||||||
{
|
{
|
||||||
info = null;
|
Console.WriteLine("Error reading M3U file: " + ex.Message);
|
||||||
string pattern = @"#EXTINF:\d+ CUID=""(?<CUID>.*?)"" number=""(?<Number>.*?)"" tvg-id=""(?<TvgID>.*?)"" tvg-name=""(?<TvgName>.*?)"".*?tvg-logo=""(?<Logo>.*?)"" group-title=""(?<GroupTitle>.*?)""[^,]*,(?<Name>.*)[^\r](?<URL>.*)$";
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return playlistItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool TryParseM3ULine(string m3uLine, out M3UInfo? info)
|
||||||
|
{
|
||||||
|
info = null;
|
||||||
|
string pattern = @"#EXTINF:\d+ CUID=""(?<CUID>.*?)"" number=""(?<Number>.*?)"" tvg-id=""(?<TvgID>.*?)"" tvg-name=""(?<TvgName>.*?)"".*?tvg-logo=""(?<Logo>.*?)"" group-title=""(?<GroupTitle>.*?)""[^,]*,(?<Name>.*)[^\r](?<URL>.*)$";
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ namespace TV_Player
|
|||||||
{
|
{
|
||||||
public class MainViewModel : ObservableViewModelBase
|
public class MainViewModel : ObservableViewModelBase
|
||||||
{
|
{
|
||||||
private ContentControl _control;
|
private ContentControl? _control;
|
||||||
public ContentControl Control
|
public ContentControl? Control
|
||||||
{
|
{
|
||||||
get => _control;
|
get => _control;
|
||||||
set => SetProperty(ref _control, value);
|
set => SetProperty(ref _control, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool _isTopPanelVisible;
|
private bool _isTopPanelVisible;
|
||||||
public bool IsTopPanelVisible
|
public bool IsTopPanelVisible
|
||||||
@@ -56,7 +57,7 @@ namespace TV_Player
|
|||||||
CurrentWindowStyle = WindowStyle.SingleBorderWindow;
|
CurrentWindowStyle = WindowStyle.SingleBorderWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFullSctreenButtonClick()
|
public void OnFullSctreenButtonClick()
|
||||||
{
|
{
|
||||||
if (CurrentWindowStyle == WindowStyle.SingleBorderWindow)
|
if (CurrentWindowStyle == WindowStyle.SingleBorderWindow)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ namespace TV_Player
|
|||||||
|
|
||||||
public class PlayerViewModel : ObservableViewModelBase, IDisposable
|
public class PlayerViewModel : ObservableViewModelBase, IDisposable
|
||||||
{
|
{
|
||||||
private M3UInfo _currentProgram;
|
public delegate void SourceUrlChanged(string videoURL);
|
||||||
public M3UInfo SelectedProgram
|
public event SourceUrlChanged SourceUrlChangedEvent;
|
||||||
{
|
|
||||||
get => _currentProgram;
|
private M3UInfo _currentProgram;
|
||||||
set => SetProperty(ref _currentProgram, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string _topPaneTitle;
|
private string _topPaneTitle;
|
||||||
public string TopPanelTitle
|
public string TopPanelTitle
|
||||||
@@ -50,40 +48,81 @@ namespace TV_Player
|
|||||||
set => SetProperty(ref _endProgram, value);
|
set => SetProperty(ref _endProgram, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<M3UInfo> _programs;
|
||||||
public M3UInfo SelectedItem { get; set; }
|
|
||||||
public ICommand BackCommand { get; }
|
public ICommand BackCommand { get; }
|
||||||
|
public ICommand FullscreenCommand { get; }
|
||||||
|
public ICommand NextCommand { get; }
|
||||||
|
public ICommand PreviousCommand { get; }
|
||||||
|
|
||||||
private ProgramGuide _currentGuide;
|
private ProgramGuide _currentGuide;
|
||||||
private ProgramInfo _currentProgramInfo;
|
private ProgramInfo _currentProgramInfo;
|
||||||
|
|
||||||
private IDisposable _programGuideDisposable;
|
private IDisposable _programGuideDisposable;
|
||||||
private IDisposable _timer;
|
private IDisposable _timer;
|
||||||
|
private IDisposable _programSubscriber;
|
||||||
|
|
||||||
|
private int _currentProgramIndex = 0;
|
||||||
public PlayerViewModel(M3UInfo selectedProgram)
|
public PlayerViewModel(M3UInfo selectedProgram)
|
||||||
{
|
{
|
||||||
_currentProgram = selectedProgram;
|
_currentProgram = selectedProgram;
|
||||||
|
|
||||||
BackCommand = new RelayCommand(OnButtonBackClick);
|
BackCommand = new RelayCommand(OnButtonBackClick);
|
||||||
TVPlayerViewModel.Instance.TopPanelVisible(false, selectedProgram.Name);
|
NextCommand = new RelayCommand(NextProgram);
|
||||||
|
PreviousCommand = new RelayCommand(PreviousProgram);
|
||||||
TopPanelTitle = selectedProgram.Name;
|
FullscreenCommand = new RelayCommand(TVPlayerViewModel.Instance.FullScreenToggle);
|
||||||
|
|
||||||
_programGuideDisposable = ProgramsData.Instance.ProgramGuideInfo.Subscribe(x =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_currentGuide = x.FirstOrDefault(p => p.Id == selectedProgram.TvgID);
|
|
||||||
UpdateScreenInfo();
|
|
||||||
|
|
||||||
_timer = Observable.Interval(TimeSpan.FromMinutes(1)).Subscribe(x =>
|
|
||||||
{
|
|
||||||
UpdateScreenInfo();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
});
|
|
||||||
|
|
||||||
|
_programSubscriber = ProgramsData.Instance.AllPrograms.Subscribe(x =>
|
||||||
|
{
|
||||||
|
_programs = x.Where(p => p.GroupTitle == _currentProgram.GroupTitle).ToList();
|
||||||
|
_currentProgramIndex = _programs.Select((program, index) => new { program, index })
|
||||||
|
.Where(x => x.program.Name == _currentProgram.Name)
|
||||||
|
.Select(x => x.index)
|
||||||
|
.FirstOrDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
UpdateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateUI()
|
||||||
|
{
|
||||||
|
TVPlayerViewModel.Instance.TopPanelVisible(false, _currentProgram.Name);
|
||||||
|
TopPanelTitle = _currentProgram.Name;
|
||||||
|
SourceUrlChangedEvent?.Invoke(_currentProgram.Url);
|
||||||
|
|
||||||
|
_programGuideDisposable = ProgramsData.Instance.ProgramGuideInfo.Subscribe(x =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_currentGuide = x.FirstOrDefault(p => p.Id == _currentProgram.TvgID);
|
||||||
|
UpdateScreenInfo();
|
||||||
|
|
||||||
|
_timer = Observable.Interval(TimeSpan.FromMinutes(1)).Subscribe(x =>
|
||||||
|
{
|
||||||
|
UpdateScreenInfo();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PreviousProgram()
|
||||||
|
{
|
||||||
|
_currentProgramIndex -= 1;
|
||||||
|
if (_currentProgramIndex < 0)
|
||||||
|
_currentProgramIndex = _programs.Count - 1;
|
||||||
|
_currentProgram = _programs[_currentProgramIndex];
|
||||||
|
_programGuideDisposable?.Dispose();
|
||||||
|
UpdateUI();
|
||||||
|
}
|
||||||
|
private void NextProgram()
|
||||||
|
{
|
||||||
|
_currentProgramIndex += 1;
|
||||||
|
if (_currentProgramIndex > _programs.Count - 1)
|
||||||
|
_currentProgramIndex = 0;
|
||||||
|
_currentProgram = _programs[_currentProgramIndex];
|
||||||
|
_programGuideDisposable?.Dispose();
|
||||||
|
UpdateUI();
|
||||||
|
}
|
||||||
private void UpdateScreenInfo()
|
private void UpdateScreenInfo()
|
||||||
{
|
{
|
||||||
_currentProgramInfo = _currentGuide.Programs.FirstOrDefault(d => d.StartTime <= DateTime.Now && d.StopTime >= DateTime.Now);
|
_currentProgramInfo = _currentGuide.Programs.FirstOrDefault(d => d.StartTime <= DateTime.Now && d.StopTime >= DateTime.Now);
|
||||||
@@ -96,8 +135,6 @@ namespace TV_Player
|
|||||||
var programMinutes = (_currentProgramInfo.StopTime - _currentProgramInfo.StartTime).TotalMinutes;
|
var programMinutes = (_currentProgramInfo.StopTime - _currentProgramInfo.StartTime).TotalMinutes;
|
||||||
DurationValue = (int)((DateTime.Now - _currentProgramInfo.StartTime).TotalMinutes / programMinutes * 100);
|
DurationValue = (int)((DateTime.Now - _currentProgramInfo.StartTime).TotalMinutes / programMinutes * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnButtonBackClick()
|
private void OnButtonBackClick()
|
||||||
{
|
{
|
||||||
var groupInfo = new GroupInfo() { Name = _currentProgram.GroupTitle, Count = 0 };
|
var groupInfo = new GroupInfo() { Name = _currentProgram.GroupTitle, Count = 0 };
|
||||||
@@ -106,9 +143,9 @@ namespace TV_Player
|
|||||||
var conrtrol = new ProgramsList();
|
var conrtrol = new ProgramsList();
|
||||||
TVPlayerViewModel.Instance.SetPageContext(conrtrol, programListViewModel);
|
TVPlayerViewModel.Instance.SetPageContext(conrtrol, programListViewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_programSubscriber.Dispose();
|
||||||
_programGuideDisposable.Dispose();
|
_programGuideDisposable.Dispose();
|
||||||
_timer.Dispose();
|
_timer.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace TV_Player
|
|||||||
ItemSelectedCommand = new RelayCommand(OnItemSelected);
|
ItemSelectedCommand = new RelayCommand(OnItemSelected);
|
||||||
_groupInformationSubscriber = ProgramsData.Instance.GroupsInformation.Subscribe(x=>Programs = x);
|
_groupInformationSubscriber = ProgramsData.Instance.GroupsInformation.Subscribe(x=>Programs = x);
|
||||||
|
|
||||||
TVPlayerViewModel.Instance.TopPanelVisible(true, "Groups");
|
TVPlayerViewModel.Instance.TopPanelVisible(true, "Группы");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnItemSelected()
|
private void OnItemSelected()
|
||||||
|
|||||||
@@ -47,6 +47,11 @@ namespace TV_Player.ViewModels
|
|||||||
_mainViewModel.TopPanelTitle = title;
|
_mainViewModel.TopPanelTitle = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void FullScreenToggle()
|
||||||
|
{
|
||||||
|
_mainViewModel.OnFullSctreenButtonClick();
|
||||||
|
}
|
||||||
|
|
||||||
public void SetBackButtonAction(Action action)
|
public void SetBackButtonAction(Action action)
|
||||||
{
|
{
|
||||||
_mainViewModel.ButtonBackAction = action;
|
_mainViewModel.ButtonBackAction = action;
|
||||||
@@ -57,7 +62,9 @@ namespace TV_Player.ViewModels
|
|||||||
if (_mainViewModel.Control is IDisposable disposable)
|
if (_mainViewModel.Control is IDisposable disposable)
|
||||||
disposable.Dispose();
|
disposable.Dispose();
|
||||||
control.DataContext = viewModel;
|
control.DataContext = viewModel;
|
||||||
|
|
||||||
_mainViewModel.Control = control;
|
_mainViewModel.Control = control;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user