提交 7f3c0a2e 编写于 作者: A Anran Zhang

调整视频视图的逻辑结构,替换横幅图片控件

上级 9368baef
...@@ -5,7 +5,6 @@ using Windows.System; ...@@ -5,7 +5,6 @@ using Windows.System;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
namespace Richasy.Bili.App.Controls namespace Richasy.Bili.App.Controls
{ {
...@@ -18,7 +17,7 @@ namespace Richasy.Bili.App.Controls ...@@ -18,7 +17,7 @@ namespace Richasy.Bili.App.Controls
/// <see cref="Source"/>的依赖属性. /// <see cref="Source"/>的依赖属性.
/// </summary> /// </summary>
public static readonly DependencyProperty SourceProperty = public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register(nameof(Source), typeof(ImageSource), typeof(BannerItem), new PropertyMetadata(null)); DependencyProperty.Register(nameof(Source), typeof(object), typeof(BannerItem), new PropertyMetadata(null));
/// <summary> /// <summary>
/// <see cref="Uri"/>的依赖属性. /// <see cref="Uri"/>的依赖属性.
...@@ -43,9 +42,9 @@ namespace Richasy.Bili.App.Controls ...@@ -43,9 +42,9 @@ namespace Richasy.Bili.App.Controls
/// <summary> /// <summary>
/// 图片源. /// 图片源.
/// </summary> /// </summary>
public ImageSource Source public object Source
{ {
get { return (ImageSource)GetValue(SourceProperty); } get { return GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); } set { SetValue(SourceProperty, value); }
} }
...@@ -85,6 +84,23 @@ namespace Richasy.Bili.App.Controls ...@@ -85,6 +84,23 @@ namespace Richasy.Bili.App.Controls
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnPointerReleased(PointerRoutedEventArgs e) protected override void OnPointerReleased(PointerRoutedEventArgs e)
{
BackToNormal(e);
}
/// <inheritdoc/>
protected override void OnPointerCanceled(PointerRoutedEventArgs e)
{
BackToNormal(e);
}
/// <inheritdoc/>
protected override void OnPointerCaptureLost(PointerRoutedEventArgs e)
{
BackToNormal(e);
}
private void BackToNormal(PointerRoutedEventArgs e)
{ {
VisualStateManager.GoToState(this, "NormalState", true); VisualStateManager.GoToState(this, "NormalState", true);
this.ReleasePointerCapture(e.Pointer); this.ReleasePointerCapture(e.Pointer);
......
...@@ -50,6 +50,12 @@ namespace Richasy.Bili.App.Controls ...@@ -50,6 +50,12 @@ namespace Richasy.Bili.App.Controls
public static readonly DependencyProperty AdditionalContentProperty = public static readonly DependencyProperty AdditionalContentProperty =
DependencyProperty.Register(nameof(AdditionalContent), typeof(object), typeof(VideoView), new PropertyMetadata(null)); DependencyProperty.Register(nameof(AdditionalContent), typeof(object), typeof(VideoView), new PropertyMetadata(null));
/// <summary>
/// <see cref="IsAutoFillEnable"/>的依赖属性.
/// </summary>
public static readonly DependencyProperty IsAutoFillEnableProperty =
DependencyProperty.Register(nameof(IsAutoFillEnable), typeof(bool), typeof(VideoView), new PropertyMetadata(true));
private ScrollViewer _parentScrollViewer; private ScrollViewer _parentScrollViewer;
/// <summary> /// <summary>
...@@ -67,12 +73,6 @@ namespace Richasy.Bili.App.Controls ...@@ -67,12 +73,6 @@ namespace Richasy.Bili.App.Controls
/// </summary> /// </summary>
public event EventHandler RequestLoadMore; public event EventHandler RequestLoadMore;
/// <summary>
/// 当有新的条目添加并准备好与用户交互时发生.
/// 会返回新条目的索引值与其实际高度的乘积,用以估算列表总高度.
/// </summary>
public event EventHandler<Microsoft.UI.Xaml.Controls.ItemsRepeaterElementPreparedEventArgs> NewItemAdded;
/// <summary> /// <summary>
/// 条目模板. /// 条目模板.
/// </summary> /// </summary>
...@@ -127,6 +127,15 @@ namespace Richasy.Bili.App.Controls ...@@ -127,6 +127,15 @@ namespace Richasy.Bili.App.Controls
set { SetValue(AdditionalContentProperty, value); } set { SetValue(AdditionalContentProperty, value); }
} }
/// <summary>
/// 是否允许根据容器剩余空间自行计算视频条目容量,并主动发起请求填满整个容器.
/// </summary>
public bool IsAutoFillEnable
{
get { return (bool)GetValue(IsAutoFillEnableProperty); }
set { SetValue(IsAutoFillEnableProperty, value); }
}
private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ {
var instance = d as VideoView; var instance = d as VideoView;
...@@ -208,7 +217,28 @@ namespace Richasy.Bili.App.Controls ...@@ -208,7 +217,28 @@ namespace Richasy.Bili.App.Controls
if (args.Element != null && args.Element is VideoItem item) if (args.Element != null && args.Element is VideoItem item)
{ {
item.Orientation = ItemOrientation; item.Orientation = ItemOrientation;
NewItemAdded?.Invoke(this, args); if (IsAutoFillEnable &&
ItemsSource is ObservableCollection<VideoViewModel> collectionSource &&
_parentScrollViewer != null &&
args.Index >= collectionSource.Count - 1)
{
var size = item.GetHolderSize();
var isNeedLoadMore = false;
if (double.IsInfinity(size.Width))
{
isNeedLoadMore = (args.Index + 1) * size.Height <= _parentScrollViewer.ViewportHeight;
}
else
{
var rowCount = args.Index / (_parentScrollViewer.ViewportWidth / size.Width);
isNeedLoadMore = rowCount * size.Height <= _parentScrollViewer.ViewportHeight;
}
if (isNeedLoadMore)
{
RequestLoadMore?.Invoke(this, EventArgs.Empty);
}
}
} }
} }
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
xmlns:controls="using:Richasy.Bili.App.Controls" xmlns:controls="using:Richasy.Bili.App.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:enums="using:Richasy.Bili.Models.Enums" xmlns:enums="using:Richasy.Bili.Models.Enums"
xmlns:icons="using:Fluent.Icons"
xmlns:loc="using:Richasy.Bili.Locator.Uwp" xmlns:loc="using:Richasy.Bili.Locator.Uwp"
xmlns:local="using:Richasy.Bili.App.Pages.Overlay" xmlns:local="using:Richasy.Bili.App.Pages.Overlay"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
...@@ -91,7 +92,8 @@ ...@@ -91,7 +92,8 @@
x:Name="BannerView" x:Name="BannerView"
Margin="0,0,0,12" Margin="0,0,0,12"
VerticalAlignment="Top" VerticalAlignment="Top"
ItemsSource="{x:Bind ViewModel.CurrentSelectedSubPartition.BannerCollection, Mode=OneWay}" /> ItemsSource="{x:Bind ViewModel.CurrentSelectedSubPartition.BannerCollection, Mode=OneWay}"
Visibility="{x:Bind ViewModel.CurrentSelectedSubPartition.IsShowBanner, Mode=OneWay}" />
<controls:VideoView <controls:VideoView
x:Name="VideoView" x:Name="VideoView"
...@@ -101,19 +103,30 @@ ...@@ -101,19 +103,30 @@
ItemsSource="{x:Bind ViewModel.CurrentSelectedSubPartition.VideoCollection, Mode=OneWay}" ItemsSource="{x:Bind ViewModel.CurrentSelectedSubPartition.VideoCollection, Mode=OneWay}"
RequestLoadMore="OnVideoViewRequestLoadMoreAsync"> RequestLoadMore="OnVideoViewRequestLoadMoreAsync">
<controls:VideoView.AdditionalContent> <controls:VideoView.AdditionalContent>
<ComboBox <Grid>
x:Name="VideoSortComboBox" <Button
Style="{StaticResource DefaultComboBoxStyle}" x:Name="RefreshButton"
ItemsSource="{x:Bind ViewModel.CurrentSelectedSubPartition.SortTypeCollection, Mode=OneWay}" VerticalAlignment="Center"
PlaceholderText="{loc:LocaleLocator Name=SelectSortType}" Click="OnRefreshButtonClickAsync">
SelectionChanged="OnVideoSortComboBoxSlectionChanged" <StackPanel Orientation="Horizontal" Spacing="8">
Visibility="Collapsed"> <icons:FluentIconElement VerticalAlignment="Center" Symbol="ArrowSyncCircle16" />
<ComboBox.ItemTemplate> <TextBlock Text="{loc:LocaleLocator Name=Refresh}" />
<DataTemplate x:DataType="enums:VideoSortType"> </StackPanel>
<TextBlock Text="{x:Bind Converter={StaticResource SortTypeTextConverter}}" /> </Button>
</DataTemplate> <ComboBox
</ComboBox.ItemTemplate> x:Name="VideoSortComboBox"
</ComboBox> Style="{StaticResource DefaultComboBoxStyle}"
ItemsSource="{x:Bind ViewModel.CurrentSelectedSubPartition.SortTypeCollection, Mode=OneWay}"
PlaceholderText="{loc:LocaleLocator Name=SelectSortType}"
SelectionChanged="OnVideoSortComboBoxSlectionChanged"
Visibility="Collapsed">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="enums:VideoSortType">
<TextBlock Text="{x:Bind Converter={StaticResource SortTypeTextConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</controls:VideoView.AdditionalContent> </controls:VideoView.AdditionalContent>
<controls:VideoView.ItemTemplate> <controls:VideoView.ItemTemplate>
<DataTemplate x:DataType="uwp:VideoViewModel"> <DataTemplate x:DataType="uwp:VideoViewModel">
......
// Copyright (c) Richasy. All rights reserved. // Copyright (c) Richasy. All rights reserved.
using System.ComponentModel; using System.ComponentModel;
using Richasy.Bili.App.Controls;
using Richasy.Bili.Models.Enums; using Richasy.Bili.Models.Enums;
using Richasy.Bili.ViewModels.Uwp; using Richasy.Bili.ViewModels.Uwp;
using Windows.UI.Xaml; using Windows.UI.Xaml;
...@@ -68,13 +67,11 @@ namespace Richasy.Bili.App.Pages.Overlay ...@@ -68,13 +67,11 @@ namespace Richasy.Bili.App.Pages.Overlay
private void OnUnloaded(object sender, RoutedEventArgs e) private void OnUnloaded(object sender, RoutedEventArgs e)
{ {
ViewModel.PropertyChanged -= OnViewModelPropertyChanged; ViewModel.PropertyChanged -= OnViewModelPropertyChanged;
VideoView.NewItemAdded -= OnVideoViewNewItemAddedAsync;
} }
private void OnLoaded(object sender, RoutedEventArgs e) private void OnLoaded(object sender, RoutedEventArgs e)
{ {
ViewModel.PropertyChanged += OnViewModelPropertyChanged; ViewModel.PropertyChanged += OnViewModelPropertyChanged;
VideoView.NewItemAdded += OnVideoViewNewItemAddedAsync;
CheckCurrentSubPartition(); CheckCurrentSubPartition();
} }
...@@ -97,15 +94,16 @@ namespace Richasy.Bili.App.Pages.Overlay ...@@ -97,15 +94,16 @@ namespace Richasy.Bili.App.Pages.Overlay
var vm = ViewModel.CurrentSelectedSubPartition; var vm = ViewModel.CurrentSelectedSubPartition;
if (vm != null) if (vm != null)
{ {
BannerView.Visibility = vm.BannerCollection != null && vm.BannerCollection.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
var isShowSort = vm.SortTypeCollection != null && vm.SortTypeCollection.Count > 0; var isShowSort = vm.SortTypeCollection != null && vm.SortTypeCollection.Count > 0;
if (isShowSort) if (isShowSort)
{ {
VideoSortComboBox.Visibility = Visibility.Visible; VideoSortComboBox.Visibility = Visibility.Visible;
RefreshButton.Visibility = Visibility.Collapsed;
VideoSortComboBox.SelectedItem = vm.CurrentSortType; VideoSortComboBox.SelectedItem = vm.CurrentSortType;
} }
else else
{ {
RefreshButton.Visibility = Visibility.Visible;
VideoSortComboBox.Visibility = Visibility.Collapsed; VideoSortComboBox.Visibility = Visibility.Collapsed;
} }
...@@ -118,41 +116,12 @@ namespace Richasy.Bili.App.Pages.Overlay ...@@ -118,41 +116,12 @@ namespace Richasy.Bili.App.Pages.Overlay
private async void OnVideoViewRequestLoadMoreAsync(object sender, System.EventArgs e) private async void OnVideoViewRequestLoadMoreAsync(object sender, System.EventArgs e)
{ {
var currentSubPartition = ViewModel.CurrentSelectedSubPartition;
if (currentSubPartition != null && !currentSubPartition.IsDeltaLoading && !currentSubPartition.IsInitializeLoading)
{
await currentSubPartition.RequestDataAsync();
}
}
private async void OnVideoViewNewItemAddedAsync(object sender, Microsoft.UI.Xaml.Controls.ItemsRepeaterElementPreparedEventArgs e)
{
// 当视频条目列表加载完成之后计算这些视频条目是否足以填满整个显示区域,
// 如果不足,则再次请求,直到填满显示区域.
// 此法是滚动加载设计的前置条件,即先让显示区域能够滚动.
var currentSubPartition = ViewModel.CurrentSelectedSubPartition; var currentSubPartition = ViewModel.CurrentSelectedSubPartition;
if (currentSubPartition != null && if (currentSubPartition != null &&
!currentSubPartition.IsDeltaLoading && !currentSubPartition.IsDeltaLoading &&
!currentSubPartition.IsInitializeLoading && !currentSubPartition.IsInitializeLoading)
e.Index >= currentSubPartition.VideoCollection.Count - 1)
{ {
var videoItem = e.Element as VideoItem; await currentSubPartition.RequestDataAsync();
var size = videoItem.GetHolderSize();
var isNeedLoadMore = false;
if (double.IsInfinity(size.Width))
{
isNeedLoadMore = (e.Index + 1) * size.Height <= ContentScrollView.ViewportHeight;
}
else
{
var rowCount = e.Index / (ContentScrollView.ViewportWidth / size.Width);
isNeedLoadMore = rowCount * size.Height <= ContentScrollView.ViewportHeight;
}
if (isNeedLoadMore)
{
await ViewModel.CurrentSelectedSubPartition.RequestDataAsync();
}
} }
} }
...@@ -164,5 +133,15 @@ namespace Richasy.Bili.App.Pages.Overlay ...@@ -164,5 +133,15 @@ namespace Richasy.Bili.App.Pages.Overlay
ViewModel.CurrentSelectedSubPartition.CurrentSortType = item; ViewModel.CurrentSelectedSubPartition.CurrentSortType = item;
} }
} }
private async void OnRefreshButtonClickAsync(object sender, RoutedEventArgs e)
{
if (ViewModel.CurrentSelectedSubPartition != null &&
!ViewModel.CurrentSelectedSubPartition.IsInitializeLoading &&
!ViewModel.CurrentSelectedSubPartition.IsDeltaLoading)
{
await ViewModel.CurrentSelectedSubPartition.InitializeRequestAsync();
}
}
} }
} }
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Richasy.Bili.App.Controls" xmlns:controls="using:Richasy.Bili.App.Controls"
xmlns:local="using:Richasy.Bili.App"> xmlns:hn="using:HN.Controls"
xmlns:icons="using:Fluent.Icons"
xmlns:local="using:Richasy.Bili.App"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls">
<Style TargetType="controls:BannerItem"> <Style TargetType="controls:BannerItem">
<Setter Property="Template"> <Setter Property="Template">
...@@ -28,13 +31,40 @@ ...@@ -28,13 +31,40 @@
</VisualState> </VisualState>
</VisualStateGroup> </VisualStateGroup>
</VisualStateManager.VisualStateGroups> </VisualStateManager.VisualStateGroups>
<Image <hn:ImageEx
x:Name="BannerImage" x:Name="BannerImage"
AutomationProperties.Name="{TemplateBinding Title}" AutomationProperties.Name="{TemplateBinding Title}"
MinWidth="300"
MinHeight="100"
MaxHeight="114" MaxHeight="114"
LazyLoadingEnabled="True"
RetryCount="2"
RetryDelay="0:0:5"
Source="{TemplateBinding Source}" Source="{TemplateBinding Source}"
Stretch="Uniform" Stretch="Uniform"
ToolTipService.ToolTip="{TemplateBinding Title}" /> ToolTipService.ToolTip="{TemplateBinding Title}">
<hn:ImageEx.LoadingTemplate>
<DataTemplate>
<Grid>
<muxc:ProgressRing
Style="{StaticResource PageProgressRingStyle}"
Width="28"
Height="28" />
</Grid>
</DataTemplate>
</hn:ImageEx.LoadingTemplate>
<hn:ImageEx.FailedTemplate>
<DataTemplate>
<Grid Background="{ThemeResource SystemControlForegroundBaseMediumBrush}" Opacity="0.5">
<icons:FluentIconElement
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
Symbol="Image28Filled" />
</Grid>
</DataTemplate>
</hn:ImageEx.FailedTemplate>
</hn:ImageEx>
</Grid> </Grid>
</ControlTemplate> </ControlTemplate>
</Setter.Value> </Setter.Value>
......
...@@ -34,6 +34,18 @@ namespace Richasy.Bili.ViewModels.Uwp ...@@ -34,6 +34,18 @@ namespace Richasy.Bili.ViewModels.Uwp
/// </summary> /// </summary>
public bool IsRequested => _offsetId != 0 || _pageNumber > 1; public bool IsRequested => _offsetId != 0 || _pageNumber > 1;
/// <summary>
/// 是否显示横幅.
/// </summary>
[Reactive]
public bool IsShowBanner { get; set; }
/// <summary>
/// 是否显示顶部标签组.
/// </summary>
[Reactive]
public bool IsShowTags { get; set; }
/// <summary> /// <summary>
/// 子分区名称. /// 子分区名称.
/// </summary> /// </summary>
......
...@@ -88,13 +88,14 @@ namespace Richasy.Bili.ViewModels.Uwp ...@@ -88,13 +88,14 @@ namespace Richasy.Bili.ViewModels.Uwp
/// 执行初始请求. /// 执行初始请求.
/// </summary> /// </summary>
/// <returns><see cref="Task"/>.</returns> /// <returns><see cref="Task"/>.</returns>
internal async Task InitializeRequestAsync() public async Task InitializeRequestAsync()
{ {
if (!IsInitializeLoading && !IsDeltaLoading) if (!IsInitializeLoading && !IsDeltaLoading)
{ {
IsInitializeLoading = true; IsInitializeLoading = true;
VideoCollection.Clear(); VideoCollection.Clear();
_offsetId = 0; _offsetId = 0;
_pageNumber = 1;
_lastRequestTime = DateTimeOffset.MinValue; _lastRequestTime = DateTimeOffset.MinValue;
await _controller.RequestSubPartitionDataAsync(SubPartitionId, _isRecommendPartition, 0, CurrentSortType, _pageNumber); await _controller.RequestSubPartitionDataAsync(SubPartitionId, _isRecommendPartition, 0, CurrentSortType, _pageNumber);
IsInitializeLoading = false; IsInitializeLoading = false;
...@@ -140,13 +141,15 @@ namespace Richasy.Bili.ViewModels.Uwp ...@@ -140,13 +141,15 @@ namespace Richasy.Bili.ViewModels.Uwp
{ {
if (e.SubPartitionId == SubPartitionId) if (e.SubPartitionId == SubPartitionId)
{ {
if (e.BannerList?.Any() ?? false) IsShowBanner = e.BannerList?.Any() ?? false;
IsShowTags = e.TagList?.Any() ?? false;
if (IsShowBanner)
{ {
BannerCollection.Clear(); BannerCollection.Clear();
e.BannerList.ToList().ForEach(p => BannerCollection.Add(p)); e.BannerList.ToList().ForEach(p => BannerCollection.Add(p));
} }
if (e.TagList?.Any() ?? false) if (IsShowTags)
{ {
TagCollection.Clear(); TagCollection.Clear();
e.TagList.ToList().ForEach(p => TagCollection.Add(p)); e.TagList.ToList().ForEach(p => TagCollection.Add(p));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册