未验证 提交 82926ab0 编写于 作者: R Richasy 提交者: GitHub

支持点赞/投币/收藏/追番 (#27)

* 添加点赞和投币

* 添加收藏操作

* 添加追番/取消追番功能
上级 3cee3f48
......@@ -8,6 +8,8 @@
xmlns:loc="using:Richasy.Bili.Locator.Uwp"
xmlns:local="using:Richasy.Bili.App.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:uwp="using:Richasy.Bili.ViewModels.Uwp"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
......@@ -19,6 +21,102 @@
</Style>
<converter:PgcFollowTextConverter x:Key="FollowTextConverter" />
<Flyout x:Name="CoinFlyout">
<Grid RowSpacing="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{loc:LocaleLocator Name=ChooseCoinNumber}" />
<StackPanel
Grid.Row="1"
Orientation="Horizontal"
Spacing="12">
<Button
Width="40"
Height="40"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Click="OnGiveCoinButtonClickAsync"
Content="1"
FontWeight="Bold"
Tag="1" />
<Button
Width="40"
Height="40"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Click="OnGiveCoinButtonClickAsync"
Content="2"
FontWeight="Bold"
Tag="2" />
</StackPanel>
<CheckBox
x:Name="AlsoLikeCheckBox"
Grid.Row="2"
MinWidth="0"
Content="{loc:LocaleLocator Name=AlsoLike}" />
</Grid>
</Flyout>
<Flyout x:Name="FavoriteFlyout">
<Grid>
<Grid Visibility="{x:Bind ViewModel.IsRequestFavoritesError, Mode=OneWay, Converter={StaticResource BoolToVisibilityReverseConverter}}">
<StackPanel Spacing="8" Visibility="{x:Bind ViewModel.IsRequestingFavorites, Mode=OneWay, Converter={StaticResource BoolToVisibilityReverseConverter}}">
<TextBlock
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{loc:LocaleLocator Name=ChooseFavorite}" />
<muxc:ItemsRepeater ItemsSource="{x:Bind ViewModel.FavoriteMetaCollection}">
<muxc:ItemsRepeater.Layout>
<muxc:StackLayout Spacing="4" />
</muxc:ItemsRepeater.Layout>
<muxc:ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="uwp:FavoriteMetaViewModel">
<local:CardPanel
IsChecked="{x:Bind IsSelected, Mode=TwoWay}"
IsEnableCheck="True"
IsEnableHoverAnimation="False"
IsEnableShadow="False">
<Grid
Width="240"
Height="40"
Padding="12,8">
<TextBlock
Style="{StaticResource CaptionTextBlockStyle}"
VerticalAlignment="Center"
FontWeight="Bold"
Text="{x:Bind Data.Title}"
TextTrimming="CharacterEllipsis" />
</Grid>
</local:CardPanel>
</DataTemplate>
</muxc:ItemsRepeater.ItemTemplate>
</muxc:ItemsRepeater>
<Button
x:Name="RequestFavoriteButton"
Style="{StaticResource AccentButtonStyle}"
HorizontalAlignment="Stretch"
Click="OnRequestFavoriteButtonClickAsync"
Content="{loc:LocaleLocator Name=Confirm}" />
</StackPanel>
<muxc:ProgressRing
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsActive="{x:Bind ViewModel.IsRequestingFavorites, Mode=OneWay}" />
</Grid>
<local:ErrorPanel
ActionButtonClick="OnRefreshFavoriteButtonClickAsync"
ActionContent="{loc:LocaleLocator Name=Refresh}"
Text="{loc:LocaleLocator Name=RequestFavoriteError}"
Visibility="{x:Bind ViewModel.IsRequestFavoritesError}" />
</Grid>
</Flyout>
</local:PlayerComponent.Resources>
<Grid RowSpacing="20">
......@@ -29,6 +127,7 @@
<StackPanel Orientation="Horizontal" Visibility="{x:Bind ViewModel.IsLive, Mode=OneWay, Converter={StaticResource BoolToVisibilityReverseConverter}}">
<local:ProgressButton
x:Name="LikeButton"
Click="OnLikeButtonClickAsync"
Description="{x:Bind ViewModel.LikeCount, Mode=OneWay}"
HoldingCompleted="OnLikeButtonHoldingCompletedAsync"
IsChecked="{x:Bind ViewModel.IsLikeChecked, Mode=OneWay}"
......@@ -39,6 +138,7 @@
<local:ProgressButton
x:Name="CoinButton"
Margin="12,0"
Click="OnCoinButtonClick"
Description="{x:Bind ViewModel.CoinCount, Mode=OneWay}"
IsChecked="{x:Bind ViewModel.IsCoinChecked, Mode=OneWay}"
IsHoldingEnabled="False"
......@@ -47,6 +147,7 @@
</local:ProgressButton>
<local:ProgressButton
x:Name="FavoriteButton"
Click="OnFavoriteButtonClickAsync"
Description="{x:Bind ViewModel.FavoriteCount, Mode=OneWay}"
IsChecked="{x:Bind ViewModel.IsFavoriteChecked, Mode=OneWay}"
IsHoldingEnabled="False"
......@@ -56,6 +157,7 @@
<local:ProgressButton
x:Name="FollowButton"
Margin="12,0,0,0"
Click="OnFollowButtonClickAsync"
Description="{x:Bind ViewModel.IsFollow, Mode=OneWay, Converter={StaticResource FollowTextConverter}}"
IsChecked="{x:Bind ViewModel.IsFollow, Mode=OneWay}"
IsHoldingEnabled="False"
......
// Copyright (c) Richasy. All rights reserved.
using System;
using Windows.UI.Xaml;
namespace Richasy.Bili.App.Controls
......@@ -32,8 +33,55 @@ namespace Richasy.Bili.App.Controls
{
}
private void OnFollowButtonClickAsync(object sender, RoutedEventArgs e)
private async void OnFollowButtonClickAsync(object sender, RoutedEventArgs e)
{
ViewModel.IsFollow = !ViewModel.IsFollow;
ViewModel.IsFollow = !ViewModel.IsFollow;
await ViewModel.ToggleFollowAsync();
}
private async void OnLikeButtonClickAsync(object sender, RoutedEventArgs e)
{
ViewModel.IsLikeChecked = !ViewModel.IsLikeChecked;
ViewModel.IsLikeChecked = !ViewModel.IsLikeChecked;
await ViewModel.LikeAsync();
}
private async void OnGiveCoinButtonClickAsync(object sender, RoutedEventArgs e)
{
var coinNumber = Convert.ToInt32((sender as FrameworkElement).Tag);
CoinFlyout.Hide();
await ViewModel.CoinAsync(coinNumber, AlsoLikeCheckBox.IsChecked.Value);
}
private void OnCoinButtonClick(object sender, RoutedEventArgs e)
{
ViewModel.IsCoinChecked = !ViewModel.IsCoinChecked;
ViewModel.IsCoinChecked = !ViewModel.IsCoinChecked;
AlsoLikeCheckBox.IsChecked = true;
CoinFlyout.ShowAt(CoinButton);
}
private async void OnRefreshFavoriteButtonClickAsync(object sender, RoutedEventArgs e)
{
await ViewModel.LoadFavoritesAsync();
}
private async void OnRequestFavoriteButtonClickAsync(object sender, RoutedEventArgs e)
{
FavoriteFlyout.Hide();
await ViewModel.FavoriteAsync();
}
private async void OnFavoriteButtonClickAsync(object sender, RoutedEventArgs e)
{
ViewModel.IsFavoriteChecked = !ViewModel.IsFavoriteChecked;
ViewModel.IsFavoriteChecked = !ViewModel.IsFavoriteChecked;
FavoriteFlyout.ShowAt(FavoriteButton);
await ViewModel.LoadFavoritesAsync();
}
}
}
......@@ -81,6 +81,13 @@ namespace Richasy.Bili.App.Controls
Nav.SelectedItem = SectionItem;
}
}
else if (e.PropertyName == nameof(ViewModel.IsDetailCanLoaded))
{
if (ViewModel.IsDetailCanLoaded)
{
InitializeLayout();
}
}
}
private void OnNavSelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args)
......@@ -90,37 +97,37 @@ namespace Richasy.Bili.App.Controls
private void InitializeLayout()
{
if (ViewModel.IsShowRelatedVideos)
if (ViewModel.IsShowRelatedVideos && RelatedVideoView != null)
{
RelatedVideoView.Visibility = Nav.SelectedItem == RelatedViedeosItem ?
Visibility.Visible : Visibility.Collapsed;
}
if (ViewModel.IsShowParts)
if (ViewModel.IsShowParts && VideoPartView != null)
{
VideoPartView.Visibility = Nav.SelectedItem == PartsItem ?
Visibility.Visible : Visibility.Collapsed;
}
if (ViewModel.IsShowEpisode)
if (ViewModel.IsShowEpisode && EpisodeView != null)
{
EpisodeView.Visibility = Nav.SelectedItem == EpisodeItem ?
Visibility.Visible : Visibility.Collapsed;
}
if (ViewModel.IsShowSeason)
if (ViewModel.IsShowSeason && SeasonView != null)
{
SeasonView.Visibility = Nav.SelectedItem == SeasonItem ?
Visibility.Visible : Visibility.Collapsed;
}
if (ViewModel.IsShowSection)
if (ViewModel.IsShowSection && SectionView != null)
{
SectionView.Visibility = Nav.SelectedItem == SectionItem ?
Visibility.Visible : Visibility.Collapsed;
}
if (ViewModel.IsShowChat)
if (ViewModel.IsShowChat && ChatView != null)
{
ChatView.Visibility = Nav.SelectedItem == ChatItem ?
Visibility.Visible : Visibility.Collapsed;
......
......@@ -66,6 +66,7 @@
<Grid
x:Name="ContentGrid"
Margin="{StaticResource DefaultContainerWithBottomPadding}"
x:Load="{x:Bind ViewModel.IsDetailCanLoaded, Mode=OneWay}"
ColumnSpacing="48"
Visibility="{x:Bind ViewModel.IsDetailError, Mode=OneWay, Converter={StaticResource BoolToVisibilityReverseConverter}}">
<Grid.RowDefinitions>
......
......@@ -120,6 +120,9 @@
<data name="AddToViewLater" xml:space="preserve">
<value>添加到稍后再看</value>
</data>
<data name="AlsoLike" xml:space="preserve">
<value>同时点赞</value>
</data>
<data name="AppDescription" xml:space="preserve">
<value>哔哩是云之幻练手做的项目,旨在构建BiliBili的桌面客户端,满足个人需求</value>
</data>
......@@ -168,6 +171,12 @@
<data name="Chat" xml:space="preserve">
<value>聊天互动</value>
</data>
<data name="ChooseCoinNumber" xml:space="preserve">
<value>打算投几个币?</value>
</data>
<data name="ChooseFavorite" xml:space="preserve">
<value>选择收藏夹</value>
</data>
<data name="Clean" xml:space="preserve">
<value>清除</value>
</data>
......@@ -567,6 +576,9 @@
<data name="RequestArticleListFailed" xml:space="preserve">
<value>文章列表请求失败</value>
</data>
<data name="RequestFavoriteError" xml:space="preserve">
<value>请求收藏夹失败</value>
</data>
<data name="RequestFeedDetailFailed" xml:space="preserve">
<value>数据源详情请求失败</value>
</data>
......
......@@ -311,5 +311,19 @@ namespace Richasy.Bili.Controller.Uwp
return false;
}
}
/// <summary>
/// 获取收藏夹列表.
/// </summary>
/// <param name="userId">用户Id.</param>
/// <param name="videoId">视频Id.</param>
/// <returns>收藏夹列表.</returns>
public async Task<List<FavoriteMeta>> GetFavoriteListAsync(int userId, int videoId)
{
ThrowWhenNetworkUnavaliable();
var list = await _accountProvider.GetFavoriteListAsync(userId, videoId);
return list.List;
}
}
}
......@@ -160,5 +160,35 @@ namespace Richasy.Bili.Controller.Uwp
return await _pgcProvider.GetDisplayInformationAsync(episodeId, seasonId);
}
/// <summary>
/// 获取PGC分集的交互信息.
/// </summary>
/// <param name="episodeId">分集Id.</param>
/// <returns>分集交互信息.</returns>
public async Task<EpisodeInteraction> GetPgcEpisodeInteractionAsync(int episodeId)
{
return await _pgcProvider.GetEpisodeInteractionAsync(episodeId);
}
/// <summary>
/// 追番/取消追番.
/// </summary>
/// <param name="seasonId">番剧/影视Id.</param>
/// <param name="isFollow">是否关注.</param>
/// <returns>关注结果.</returns>
public async Task<bool> FollowPgcSeasonAsync(int seasonId, bool isFollow)
{
ThrowWhenNetworkUnavaliable();
try
{
var result = await _pgcProvider.FollowAsync(seasonId, isFollow);
return result;
}
catch (Exception)
{
return false;
}
}
}
}
......@@ -166,7 +166,7 @@ namespace Richasy.Bili.Controller.Uwp
/// <param name="addFavoriteListIds">要添加到的收藏夹Id列表.</param>
/// <param name="deleteFavoriteListIds">要移除的收藏夹Id列表.</param>
/// <returns>结果.</returns>
public async Task<FavoriteResult> FavoriteVideoAsync(long videoId, List<string> addFavoriteListIds, List<string> deleteFavoriteListIds)
public async Task<FavoriteResult> FavoriteVideoAsync(long videoId, List<int> addFavoriteListIds, List<int> deleteFavoriteListIds)
{
if (await _authorizeProvider.IsTokenValidAsync())
{
......
......@@ -122,5 +122,13 @@ namespace Richasy.Bili.Lib.Interfaces
/// <param name="videoIds">需要移除的视频Id列表.</param>
/// <returns>移除结果.</returns>
Task<bool> RemoveVideoFromViewLaterAsync(params int[] videoIds);
/// <summary>
/// 获取用户的收藏夹列表.
/// </summary>
/// <param name="userId">用户Id.</param>
/// <param name="videoId">待查询的视频Id.</param>
/// <returns><see cref="FavoriteListResponse"/>.</returns>
Task<FavoriteListResponse> GetFavoriteListAsync(int userId, int videoId = 0);
}
}
......@@ -49,5 +49,20 @@ namespace Richasy.Bili.Lib.Interfaces
/// <param name="seasonId">(可选项) 剧集/系列Id.</param>
/// <returns>PGC内容详情.</returns>
Task<PgcDisplayInformation> GetDisplayInformationAsync(int episodeId = 0, int seasonId = 0);
/// <summary>
/// 获取分集的交互信息,包括用户的投币/点赞/收藏.
/// </summary>
/// <param name="episodeId">分集Id.</param>
/// <returns>交互信息.</returns>
Task<EpisodeInteraction> GetEpisodeInteractionAsync(int episodeId);
/// <summary>
/// 追番/追剧.
/// </summary>
/// <param name="seasonId">剧Id.</param>
/// <param name="isFollow">是否关注.</param>
/// <returns>关注结果.</returns>
Task<bool> FollowAsync(int seasonId, bool isFollow);
}
}
......@@ -104,7 +104,7 @@ namespace Richasy.Bili.Lib.Interfaces
/// <param name="needAddFavoriteList">需要添加的收藏夹列表.</param>
/// <param name="needRemoveFavoriteList">需要移除的收藏夹列表.</param>
/// <returns>收藏结果.</returns>
Task<FavoriteResult> FavoriteAsync(long videoId, IList<string> needAddFavoriteList, IList<string> needRemoveFavoriteList);
Task<FavoriteResult> FavoriteAsync(long videoId, IList<int> needAddFavoriteList, IList<int> needRemoveFavoriteList);
/// <summary>
/// 一键三连.
......
......@@ -229,5 +229,21 @@ namespace Richasy.Bili.Lib.Uwp
var result = await _httpProvider.ParseAsync<ServerResponse>(response);
return result.IsSuccess();
}
/// <inheritdoc/>
public async Task<FavoriteListResponse> GetFavoriteListAsync(int userId, int videoId = 0)
{
var queryParameters = new Dictionary<string, string>
{
{ Query.UpId, userId.ToString() },
{ Query.Type, "2" },
{ Query.PartitionId, videoId.ToString() },
};
var request = await _httpProvider.GetRequestMessageAsync(HttpMethod.Get, Account.FavoriteList, queryParameters, needToken: true);
var response = await _httpProvider.SendAsync(request);
var result = await _httpProvider.ParseAsync<ServerResponse<FavoriteListResponse>>(response);
return result.Data;
}
}
}
......@@ -125,5 +125,25 @@ namespace Richasy.Bili.Lib.Uwp
return queryParameters;
}
private Dictionary<string, string> GetEpisodeInteractionQueryParameters(int episodeId)
{
var queryParameters = new Dictionary<string, string>
{
{ Query.EpisodeId, episodeId.ToString() },
};
return queryParameters;
}
private Dictionary<string, string> GetFollowQueryParameters(int seasonId)
{
var queryParameters = new Dictionary<string, string>
{
{ Query.SeasonId, seasonId.ToString() },
};
return queryParameters;
}
}
}
......@@ -66,5 +66,26 @@ namespace Richasy.Bili.Lib.Uwp
var data = await _httpProvider.ParseAsync<ServerResponse<PgcDisplayInformation>>(response);
return data.Data;
}
/// <inheritdoc/>
public async Task<EpisodeInteraction> GetEpisodeInteractionAsync(int episodeId)
{
var queryParameters = GetEpisodeInteractionQueryParameters(episodeId);
var request = await _httpProvider.GetRequestMessageAsync(HttpMethod.Get, Pgc.EpisodeInteraction, queryParameters, RequestClientType.IOS);
var response = await _httpProvider.SendAsync(request);
var data = await _httpProvider.ParseAsync<ServerResponse<EpisodeInteraction>>(response);
return data.Data;
}
/// <inheritdoc/>
public async Task<bool> FollowAsync(int seasonId, bool isFollow)
{
var queryParameters = GetFollowQueryParameters(seasonId);
var url = isFollow ? Pgc.Follow : Pgc.Unfollow;
var request = await _httpProvider.GetRequestMessageAsync(HttpMethod.Post, url, queryParameters, RequestClientType.IOS, true);
var response = await _httpProvider.SendAsync(request);
var data = await _httpProvider.ParseAsync<ServerResponse>(response);
return data.IsSuccess();
}
}
}
......@@ -170,6 +170,7 @@ namespace Richasy.Bili.Lib.Uwp
{
{ Query.Aid, videoId.ToString() },
{ Query.Multiply, number.ToString() },
{ Query.AlsoLike, alsoLike ? "1" : "0" },
};
var request = await _httpProvider.GetRequestMessageAsync(HttpMethod.Post, Video.Coin, queryParameters, needToken: true);
......@@ -179,7 +180,7 @@ namespace Richasy.Bili.Lib.Uwp
}
/// <inheritdoc/>
public async Task<FavoriteResult> FavoriteAsync(long videoId, IList<string> needAddFavoriteList, IList<string> needRemoveFavoriteList)
public async Task<FavoriteResult> FavoriteAsync(long videoId, IList<int> needAddFavoriteList, IList<int> needRemoveFavoriteList)
{
var queryParameters = new Dictionary<string, string>
{
......
......@@ -131,6 +131,11 @@ namespace Richasy.Bili.Models.App.Constants
/// 清空稍后再看的视频.
/// </summary>
public const string ViewLaterClear = _apiBase + "/x/v2/history/toview/clear";
/// <summary>
/// 获取全部收藏夹列表.
/// </summary>
public const string FavoriteList = _apiBase + "/x/v3/fav/folder/created/list-all";
}
public static class Partition
......@@ -261,6 +266,21 @@ namespace Richasy.Bili.Models.App.Constants
/// 剧集播放信息.
/// </summary>
public const string PlayInformation = _apiBase + "/pgc/player/web/playurl";
/// <summary>
/// 分集交互信息.
/// </summary>
public const string EpisodeInteraction = _apiBase + "/pgc/season/episode/community";
/// <summary>
/// 追番/追剧.
/// </summary>
public const string Follow = _apiBase + "/pgc/app/follow/add";
/// <summary>
/// 取消追番/追剧.
/// </summary>
public const string Unfollow = _apiBase + "/pgc/app/follow/del";
}
public static class Video
......
......@@ -135,6 +135,7 @@ namespace Richasy.Bili.Models.App.Constants
public const string FontSize = "fontsize";
public const string PlayTime = "playTime";
public const string TagId = "tagid";
public const string UpId = "up_mid";
}
public static class Sort
......
// Copyright (c) Richasy. All rights reserved.
using Newtonsoft.Json;
namespace Richasy.Bili.Models.BiliBili
{
/// <summary>
/// 分集交互信息(包括用户投币,点赞,收藏等信息).
/// </summary>
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class EpisodeInteraction
{
/// <summary>
/// 投币数.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "coin_number", Required = Required.Default)]
public int CoinNumber { get; set; }
/// <summary>
/// 是否收藏.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "favorite", Required = Required.Default)]
public int IsFavorite { get; set; }
/// <summary>
/// 是否点赞.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "like", Required = Required.Default)]
public int IsLike { get; set; }
}
}
// Copyright (c) Richasy. All rights reserved.
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Richasy.Bili.Models.BiliBili
{
/// <summary>
/// 收藏夹列表响应.
/// </summary>
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class FavoriteListResponse
{
/// <summary>
/// 收藏夹总数.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "count", Required = Required.Default)]
public int Count { get; set; }
/// <summary>
/// 收藏夹列表.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "list", Required = Required.Default)]
public List<FavoriteMeta> List { get; set; }
}
/// <summary>
/// 收藏夹元数据.
/// </summary>
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class FavoriteMeta
{
/// <summary>
/// 收藏夹完整Id.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "id", Required = Required.Default)]
public int Id { get; set; }
/// <summary>
/// 收藏夹原始Id.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "fid", Required = Required.Default)]
public int FolderId { get; set; }
/// <summary>
/// 用户Id.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "mid", Required = Required.Default)]
public int UserId { get; set; }
/// <summary>
/// 收藏夹标题.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "title", Required = Required.Default)]
public string Title { get; set; }
/// <summary>
/// 查询的视频是否在该收藏夹内,0-存在,1-不存在.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "fav_state", Required = Required.Default)]
public int FavoriteState { get; set; }
/// <summary>
/// 媒体数目.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "media_count", Required = Required.Default)]
public int MediaCount { get; set; }
}
}
......@@ -236,6 +236,10 @@ namespace Richasy.Bili.Models.Enums
PlayCount,
DanmakuCount,
ReplyCount,
ChooseCoinNumber,
AlsoLike,
ChooseFavorite,
RequestFavoriteError,
#pragma warning restore SA1602 // Enumeration items should be documented
}
}
// Copyright (c) Richasy. All rights reserved.
using Richasy.Bili.Models.BiliBili;
namespace Richasy.Bili.ViewModels.Uwp
{
/// <summary>
/// 收藏夹元数据视图模型.
/// </summary>
public class FavoriteMetaViewModel : SelectableViewModelBase<FavoriteMeta>
{
/// <summary>
/// Initializes a new instance of the <see cref="FavoriteMetaViewModel"/> class.
/// </summary>
/// <param name="data">数据.</param>
/// <param name="isSelected">是否选中.</param>
public FavoriteMetaViewModel(FavoriteMeta data, bool isSelected)
: base(data, isSelected)
{
}
}
}
// Copyright (c) Richasy. All rights reserved.
using System;
using System.Linq;
using System.Threading.Tasks;
using Richasy.Bili.Models.BiliBili;
using Richasy.Bili.Models.Enums;
namespace Richasy.Bili.ViewModels.Uwp
......@@ -79,22 +79,99 @@ namespace Richasy.Bili.ViewModels.Uwp
/// <returns><see cref="Task"/>.</returns>
public async Task TripleAsync()
{
TripleResult result = null;
if (_videoId > 0)
var aid = GetAid();
var result = await Controller.TripleAsync(aid);
if (result != null)
{
result = await Controller.TripleAsync(_videoId);
IsLikeChecked = result.IsLike;
IsCoinChecked = result.IsCoin;
IsFavoriteChecked = result.IsFavorite;
}
else if (IsPgc)
}
/// <summary>
/// 点赞视频.
/// </summary>
/// <returns><see cref="Task"/>.</returns>
public async Task LikeAsync()
{
var isLike = !IsLikeChecked;
var aid = GetAid();
var isSuccess = await Controller.LikeVideoAsync(aid, isLike);
if (isSuccess)
{
result = await Controller.TripleAsync(CurrentPgcEpisode.Aid);
IsLikeChecked = isLike;
}
}
/// <summary>
/// 投币.
/// </summary>
/// <param name="number">投币个数.</param>
/// <param name="isAlsoLike">是否同时点赞.</param>
/// <returns><see cref="Task"/>.</returns>
public async Task CoinAsync(int number, bool isAlsoLike)
{
var aid = GetAid();
var result = await Controller.CoinVideoAsync(aid, number, isAlsoLike);
if (result != null)
{
IsLikeChecked = result.IsLike;
IsCoinChecked = result.IsCoin;
IsFavoriteChecked = result.IsFavorite;
IsCoinChecked = true;
if (result.IsAlsoLike)
{
IsLikeChecked = true;
}
}
}
/// <summary>
/// 收藏视频.
/// </summary>
/// <param name="selectedIds">选中的收藏夹Id.</param>
/// <param name="deselectedIds">取消选中的收藏夹Id.</param>
/// <returns><see cref="Task"/>.</returns>
public async Task FavoriteAsync()
{
var aid = GetAid();
var selectedIds = FavoriteMetaCollection.Where(p => p.IsSelected).Select(p => p.Data.Id).ToList();
var deselectedIds = FavoriteMetaCollection.Where(p => !p.IsSelected).Select(p => p.Data.Id).ToList();
var result = await Controller.FavoriteVideoAsync(aid, selectedIds, deselectedIds);
switch (result)
{
case Models.Enums.Bili.FavoriteResult.Success:
case Models.Enums.Bili.FavoriteResult.InsufficientAccess:
IsFavoriteChecked = selectedIds.Count > 0;
break;
default:
break;
}
}
/// <summary>
/// 追番/取消追番.
/// </summary>
/// <returns><see cref="Task"/>.</returns>
public async Task ToggleFollowAsync()
{
if (!IsPgc)
{
return;
}
var seasonId = Convert.ToInt32(SeasonId);
var isSuccess = await Controller.FollowPgcSeasonAsync(seasonId, !IsFollow);
if (isSuccess)
{
IsFollow = !IsFollow;
}
}
private long GetAid()
{
return IsPgc ? CurrentPgcEpisode.Aid : _videoId;
}
}
}
......@@ -57,6 +57,7 @@ namespace Richasy.Bili.ViewModels.Uwp
LiveQualityCollection.Clear();
LivePlayLineCollection.Clear();
LiveDanmakuCollection.Clear();
FavoriteMetaCollection.Clear();
var preferPlayerMode = _settingsToolkit.ReadLocalSetting(SettingNames.DefaultPlayerDisplayMode, PlayerDisplayMode.Default);
PlayerDisplayMode = preferPlayerMode;
......@@ -282,12 +283,9 @@ namespace Richasy.Bili.ViewModels.Uwp
var episodeModule = _pgcDetail.Modules.Where(p => p.Style == ServiceConstants.Positive).FirstOrDefault();
IsShowEpisode = episodeModule != null && episodeModule.Data.Episodes.Count > 1;
if (IsShowEpisode)
foreach (var item in episodeModule.Data.Episodes)
{
foreach (var item in episodeModule.Data.Episodes)
{
EpisodeCollection.Add(new PgcEpisodeViewModel(item, false));
}
EpisodeCollection.Add(new PgcEpisodeViewModel(item, false));
}
var partModuleList = _pgcDetail.Modules.Where(p => p.Style == ServiceConstants.Section).ToList();
......
......@@ -86,6 +86,12 @@ namespace Richasy.Bili.ViewModels.Uwp
/// </summary>
public CoreDispatcher Dispatcher { get; set; }
/// <summary>
/// 详情是否可以加载(用于优化页面跳转的加载时间).
/// </summary>
[Reactive]
public bool IsDetailCanLoaded { get; set; }
/// <summary>
/// 标题.
/// </summary>
......@@ -254,6 +260,12 @@ namespace Richasy.Bili.ViewModels.Uwp
[Reactive]
public ObservableCollection<LiveDanmakuMessage> LiveDanmakuCollection { get; set; }
/// <summary>
/// 收藏夹集合.
/// </summary>
[Reactive]
public ObservableCollection<FavoriteMetaViewModel> FavoriteMetaCollection { get; set; }
/// <summary>
/// 当前分P.
/// </summary>
......@@ -446,6 +458,18 @@ namespace Richasy.Bili.ViewModels.Uwp
[Reactive]
public bool IsShowHistory { get; set; }
/// <summary>
/// 请求收藏夹出错.
/// </summary>
[Reactive]
public bool IsRequestFavoritesError { get; set; }
/// <summary>
/// 是否正在请求收藏夹列表.
/// </summary>
[Reactive]
public bool IsRequestingFavorites { get; set; }
private BiliController Controller { get; } = BiliController.Instance;
}
}
......@@ -36,6 +36,7 @@ namespace Richasy.Bili.ViewModels.Uwp
LivePlayLineCollection = new ObservableCollection<LivePlayLineViewModel>();
LiveQualityCollection = new ObservableCollection<LiveQualityViewModel>();
LiveDanmakuCollection = new ObservableCollection<LiveDanmakuMessage>();
FavoriteMetaCollection = new ObservableCollection<FavoriteMetaViewModel>();
_audioList = new List<DashItem>();
_videoList = new List<DashItem>();
_lastReportProgress = TimeSpan.Zero;
......@@ -105,6 +106,8 @@ namespace Richasy.Bili.ViewModels.Uwp
_videoType = VideoType.Pgc;
}
IsDetailCanLoaded = true;
switch (_videoType)
{
case VideoType.Video:
......@@ -212,14 +215,6 @@ namespace Richasy.Bili.ViewModels.Uwp
return;
}
try
{
ViewerCount = await Controller.GetOnlineViewerCountAsync(CurrentPgcEpisode.Aid, CurrentPgcEpisode.PartId);
}
catch (Exception)
{
}
EpisodeId = CurrentPgcEpisode?.Id.ToString() ?? string.Empty;
CheckEpisodeSelection();
......@@ -246,6 +241,18 @@ namespace Richasy.Bili.ViewModels.Uwp
await InitializeVideoPlayInformationAsync(_dashInformation);
await DanmakuViewModel.Instance.LoadAsync(CurrentPgcEpisode.Aid, CurrentPgcEpisode.PartId);
}
try
{
ViewerCount = await Controller.GetOnlineViewerCountAsync(CurrentPgcEpisode.Aid, CurrentPgcEpisode.PartId);
var interaction = await Controller.GetPgcEpisodeInteractionAsync(CurrentPgcEpisode.Id);
IsLikeChecked = interaction.IsLike != 0;
IsCoinChecked = interaction.CoinNumber > 0;
IsFavoriteChecked = interaction.IsFavorite != 0;
}
catch (Exception)
{
}
}
/// <summary>
......@@ -312,7 +319,10 @@ namespace Richasy.Bili.ViewModels.Uwp
/// </summary>
public void ClearPlayer()
{
BiliPlayer.SetMediaPlayer(null);
if (BiliPlayer != null)
{
BiliPlayer.SetMediaPlayer(null);
}
if (_currentVideoPlayer != null)
{
......@@ -373,6 +383,37 @@ namespace Richasy.Bili.ViewModels.Uwp
}
}
/// <summary>
/// 加载收藏夹列表.
/// </summary>
/// <returns><see cref="Task"/>.</returns>
public async Task LoadFavoritesAsync()
{
var accVM = AccountViewModel.Instance;
if (accVM.Status != AccountViewModelStatus.Login || IsRequestingFavorites)
{
return;
}
try
{
IsRequestFavoritesError = false;
FavoriteMetaCollection.Clear();
IsRequestingFavorites = true;
var favorites = await Controller.GetFavoriteListAsync(AccountViewModel.Instance.Mid.Value, Convert.ToInt32(GetAid()));
if (favorites.Count > 0)
{
favorites.ForEach(p => FavoriteMetaCollection.Add(new FavoriteMetaViewModel(p, p.FavoriteState == 1)));
}
}
catch (Exception)
{
IsRequestFavoritesError = true;
}
IsRequestingFavorites = false;
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
switch (args.PropertyName)
......
......@@ -13,6 +13,7 @@
<Compile Include="Common\DanmakuViewModel\DanmakuViewModel.cs" />
<Compile Include="Common\DanmakuViewModel\DanmakuViewModel.Methods.cs" />
<Compile Include="Common\DanmakuViewModel\DanmakuViewModel.Properties.cs" />
<Compile Include="Common\FavoriteMetaViewModel.cs" />
<Compile Include="Common\LivePlayLineViewModel.cs" />
<Compile Include="Common\LiveQualityViewModel.cs" />
<Compile Include="Common\PgcEpisodeViewModel.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册