Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

评论支持添加表情 #255

Merged
merged 1 commit into from
Jan 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/App/App.csproj
Original file line number Diff line number Diff line change
@@ -87,6 +87,7 @@
<None Remove="Controls\Modules\AnimeNavListModule.xaml" />
<None Remove="Controls\Modules\ArticleNavListModule.xaml" />
<None Remove="Controls\Modules\DynamicUpListModule.xaml" />
<None Remove="Controls\Modules\EmotePanel.xaml" />
<None Remove="Controls\Modules\FavoritesNavListModule.xaml" />
<None Remove="Controls\Modules\FilmNavListModule.xaml" />
<None Remove="Controls\Modules\FixModule.xaml" />
@@ -281,6 +282,9 @@
<Content Update="Assets\AppCenterSecret.txt">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Content>
<Page Update="Controls\Modules\EmotePanel.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Update="Controls\Modules\WebDavInformationView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
Original file line number Diff line number Diff line change
@@ -134,7 +134,7 @@ private void HideTempMessage()

private void HandleTransportAutoHide()
{
if (_transportStayTime > 1.2)
if (_transportStayTime > 1.2 && ViewModel.Player != null)
{
_transportStayTime = 0;
var isManual = SettingsToolkit.ReadLocalSetting(SettingNames.IsPlayerControlModeManual, false);
@@ -163,6 +163,7 @@ private void HandleCursorAutoHide()
&& !ViewModel.IsShowMediaTransport
&& IsPointerStay
&& !_rootSplitView.IsPaneOpen
&& ViewModel.Player != null
&& ViewModel.Player.Status == PlayerStatus.Playing)
{
ProtectedCursor.Dispose();
54 changes: 36 additions & 18 deletions src/App/Controls/Comment/CommentBox.xaml
Original file line number Diff line number Diff line change
@@ -8,11 +8,12 @@
xmlns:ext="using:Bili.Copilot.App.Extensions"
xmlns:local="using:Bili.Copilot.App.Controls.Comment"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:modules="using:Bili.Copilot.App.Controls.Modules"
mc:Ignorable="d">

<Grid
Grid.Row="2"
Padding="12,8"
Padding="4"
Background="{ThemeResource CardBackgroundFillColorDefault}"
ColumnSpacing="12"
CornerRadius="{StaticResource ControlCornerRadius}">
@@ -51,34 +52,51 @@
<base:FluentIcon FontSize="10" Symbol="Dismiss" />
</Button>
</Grid>
<TextBox
<AutoSuggestBox
x:Name="ReplyBox"
Grid.Row="1"
MaxHeight="80"
Padding="12,10,8,8"
Grid.ColumnSpan="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AcceptsReturn="True"
AllowFocusOnInteraction="True"
Background="Transparent"
BorderThickness="0"
PlaceholderText="{ext:Locale Name=ReplyPlaceholderText}"
Text="{x:Bind Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />

QuerySubmitted="OnReplySubmitted"
Text="{x:Bind Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<AutoSuggestBox.TextBoxStyle>
<Style BasedOn="{StaticResource AutoSuggestBoxTextBoxStyle}" TargetType="TextBox">
<Setter Property="Padding" Value="40,8,12,8" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="AcceptsReturn" Value="True" />
<Setter Property="MaxHeight" Value="80" />
</Style>
</AutoSuggestBox.TextBoxStyle>
<AutoSuggestBox.QueryIcon>
<base:FluentIcon Symbol="Send" />
</AutoSuggestBox.QueryIcon>
</AutoSuggestBox>
<Button
x:Name="SendReplyButton"
Grid.Row="1"
Grid.Column="1"
Width="40"
Height="40"
Margin="4,2,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Command="{x:Bind SendCommand, Mode=OneWay}">
<base:FluentIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
Symbol="Send" />
Style="{StaticResource SmallIconButtonStyle}"
ToolTipService.ToolTip="{ext:Locale Name=Emote}">
<base:FluentIcon FontSize="14" Symbol="Emoji" />
<Button.Flyout>
<Flyout Closed="OnFlyoutClosed" ShouldConstrainToRootBounds="False">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource DefaultFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="Padding" Value="4,8" />
</Style>
</Flyout.FlyoutPresenterStyle>
<modules:EmotePanel
Width="320"
Height="420"
ItemClick="OnItemClick" />
</Flyout>
</Button.Flyout>
</Button>
</Grid>
</UserControl>
18 changes: 18 additions & 0 deletions src/App/Controls/Comment/CommentBox.xaml.cs
Original file line number Diff line number Diff line change
@@ -73,4 +73,22 @@ public ICommand ResetSelectedCommand
get => (ICommand)GetValue(ResetSelectedCommandProperty);
set => SetValue(ResetSelectedCommandProperty, value);
}

private void OnReplySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
if (string.IsNullOrEmpty(Text))
{
return;
}

SendCommand?.Execute(Text);
}

private void OnItemClick(object sender, string e)
=> Text += e;

private void OnFlyoutClosed(object sender, object e)
{
ReplyBox.Focus(FocusState.Programmatic);
}
}
118 changes: 118 additions & 0 deletions src/App/Controls/Modules/EmotePanel.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="utf-8" ?>
<local:EmotePanelBase
x:Class="Bili.Copilot.App.Controls.Modules.EmotePanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:appearance="using:Bili.Copilot.Models.Data.Appearance"
xmlns:base="using:Bili.Copilot.App.Controls.Base"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ext="using:Bili.Copilot.App.Extensions"
xmlns:items="using:Bili.Copilot.ViewModels.Items"
xmlns:labs="using:CommunityToolkit.Labs.WinUI"
xmlns:local="using:Bili.Copilot.App.Controls.Modules"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid>
<base:LoadingOverlapper IsOpen="{x:Bind ViewModel.IsLoading, Mode=OneWay}" Text="{ext:Locale Name=LoadingAndWait}" />
<Grid Visibility="{x:Bind ViewModel.IsLoading, Mode=OneWay, Converter={StaticResource BoolToVisibilityReverseConverter}}">
<base:EmptyHolder
Title="{ext:Locale Name=RequestEmoteFailed}"
Description="{ext:Locale Name=RequestEmoteFailedDescription}"
Emoji="&#x1F975;"
Visibility="{x:Bind ViewModel.IsError, Mode=OneWay}">
<base:EmptyHolder.ActionElement>
<HyperlinkButton Command="{x:Bind ViewModel.InitializeCommand}" Content="{ext:Locale Name=Refresh}" />
</base:EmptyHolder.ActionElement>
</base:EmptyHolder>
<Grid Visibility="{x:Bind ViewModel.IsError, Mode=OneWay, Converter={StaticResource BoolToVisibilityReverseConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ScrollViewer
HorizontalScrollMode="Disabled"
VerticalScrollBarVisibility="Hidden"
VerticalScrollMode="Enabled">
<ItemsRepeater ItemsSource="{x:Bind ViewModel.Packages, Mode=OneWay}">
<ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="items:EmotePackageViewModel">
<base:CardPanel
Width="40"
Height="40"
Background="Transparent"
BorderBrush="Transparent"
Click="OnPackageClick"
DataContext="{x:Bind}"
IsChecked="{x:Bind IsSelected, Mode=OneWay}"
ToolTipService.ToolTip="{x:Bind Data.Name}">
<base:ImageEx
Width="28"
Background="Transparent"
DecodePixelWidth="80"
Source="{x:Bind Data.Icon.Uri}" />
</base:CardPanel>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
<ItemsRepeater.Layout>
<StackLayout Spacing="4" />
</ItemsRepeater.Layout>
</ItemsRepeater>
</ScrollViewer>
<Rectangle
Grid.Column="1"
Width="1"
Margin="8,0,0,0"
VerticalAlignment="Stretch"
Fill="{ThemeResource DividerStrokeColorDefaultBrush}" />
<ScrollViewer
Grid.Column="2"
Padding="8,0"
Style="{StaticResource PageScrollViewerStyle}">
<ItemsRepeater ItemsSource="{x:Bind ViewModel.Current.Data.Images, Mode=OneWay}">
<ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="appearance:Emote">
<Button
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Background="Transparent"
BorderThickness="0"
Click="OnItemClick"
Tag="{x:Bind Key}"
ToolTipService.ToolTip="{x:Bind Key}">
<Grid>
<base:ImageEx
Width="32"
Height="32"
Background="Transparent"
DecodePixelWidth="80"
Source="{x:Bind Image.Uri}"
Stretch="Uniform"
Visibility="{x:Bind Image, Converter={StaticResource ObjectToVisibilityConverter}}" />
<TextBlock
FontSize="12"
Text="{x:Bind Key}"
Visibility="{x:Bind Image, Converter={StaticResource ObjectToVisibilityReverseConverter}}" />
</Grid>
</Button>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
<ItemsRepeater.Layout>
<UniformGridLayout
ItemsStretch="Fill"
MinColumnSpacing="8"
MinItemHeight="40"
MinItemWidth="40"
MinRowSpacing="8" />
</ItemsRepeater.Layout>
</ItemsRepeater>
</ScrollViewer>
</Grid>
</Grid>
</Grid>

</local:EmotePanelBase>
55 changes: 55 additions & 0 deletions src/App/Controls/Modules/EmotePanel.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) Bili Copilot. All rights reserved.

using Bili.Copilot.App.Controls.Base;
using Bili.Copilot.ViewModels.Components;
using Bili.Copilot.ViewModels.Items;

namespace Bili.Copilot.App.Controls.Modules;

/// <summary>
/// 表情模块.
/// </summary>
public sealed partial class EmotePanel : EmotePanelBase
{
/// <summary>
/// Initializes a new instance of the <see cref="EmotePanel"/> class.
/// </summary>
public EmotePanel()
{
InitializeComponent();
ViewModel = EmoteModuleViewModel.Instance;
Loaded += OnLoaded;
}

/// <summary>
/// 点击表情.
/// </summary>
public event EventHandler<string> ItemClick;

private void OnLoaded(object sender, RoutedEventArgs e)
{
ViewModel.InitializeCommand.Execute(default);
}

private void OnItemClick(object sender, RoutedEventArgs e)
{
var key = (sender as FrameworkElement).Tag as string;
ItemClick?.Invoke(this, key);
}

private void OnPackageClick(object sender, RoutedEventArgs e)
{
var data = (sender as FrameworkElement).DataContext as EmotePackageViewModel;
if (data != ViewModel.Current)
{
ViewModel.SelectPackageCommand.Execute(data);
}
}
}

/// <summary>
/// <see cref="EmotePanel"/> 的基类.
/// </summary>
public abstract class EmotePanelBase : ReactiveUserControl<EmoteModuleViewModel>
{
}
9 changes: 9 additions & 0 deletions src/App/Resources/zh-Hans/Resources.resw
Original file line number Diff line number Diff line change
@@ -2223,4 +2223,13 @@ UGC优先级:分P &gt; 播放列表 &gt; 合集视频 &gt; 关联视频 (如
<data name="PlayerControlModeDescription" xml:space="preserve">
<value>自动=控制器自行显示/隐藏,手动=用户控制显示/隐藏</value>
</data>
<data name="Emote" xml:space="preserve">
<value>表情</value>
</data>
<data name="RequestEmoteFailed" xml:space="preserve">
<value>请求表情失败</value>
</data>
<data name="RequestEmoteFailedDescription" xml:space="preserve">
<value>无法获取表情包,请稍后再试</value>
</data>
</root>
9 changes: 9 additions & 0 deletions src/App/Resources/zh-Hant/Resources.resw
Original file line number Diff line number Diff line change
@@ -2217,4 +2217,13 @@ UGC優先級:分P &gt; 播放列表 &gt; 合集視頻 &gt; 關聯視頻 (如
<data name="PlayerControlModeDescription" xml:space="preserve">
<value>自動=控制器自行顯示/隱藏,手動=使用者控制顯示/隱藏</value>
</data>
<data name="Emote" xml:space="preserve">
<value>表情</value>
</data>
<data name="RequestEmoteFailed" xml:space="preserve">
<value>請求表情失敗</value>
</data>
<data name="RequestEmoteFailedDescription" xml:space="preserve">
<value>無法獲取表情包,請稍後再試</value>
</data>
</root>
28 changes: 28 additions & 0 deletions src/Libs/Libs.Adapter/CommunityAdapter.cs
Original file line number Diff line number Diff line change
@@ -5,8 +5,10 @@
using System.Linq;
using Bili.Copilot.Libs.Toolkit;
using Bili.Copilot.Models.BiliBili;
using Bili.Copilot.Models.BiliBili.Others;
using Bili.Copilot.Models.Constants.App;
using Bili.Copilot.Models.Constants.Community;
using Bili.Copilot.Models.Data.Appearance;
using Bili.Copilot.Models.Data.Community;
using Bilibili.App.Archive.V1;
using Bilibili.App.Card.V1;
@@ -763,4 +765,30 @@ public static TripleInformation ConvertToTripleInformation(TripleResult result,
/// <returns><see cref="EpisodeInteractionInformation"/>.</returns>
public static EpisodeInteractionInformation ConvertToEpisodeInteractionInformation(EpisodeInteraction interaction)
=> new(interaction.IsLike == 1, interaction.CoinNumber > 0, interaction.IsFavorite == 1);

/// <summary>
/// 将 <see cref="BiliEmotePackage"/> 转换成 <see cref="EmotePackage"/>.
/// </summary>
/// <param name="package">表情包.</param>
/// <returns><see cref="EmotePackage"/>.</returns>
public static EmotePackage ConvertToEmotePackage(BiliEmotePackage package)
{
var p = new EmotePackage();
p.Name = package.Text;
p.Icon = ImageAdapter.ConvertToImage(package.Url);
p.Images = new List<Emote>();
foreach (var item in package.Emotes)
{
var e = new Emote();
e.Key = item.Text;
if (item.Url.StartsWith("http"))
{
e.Image = ImageAdapter.ConvertToImage(item.Url);
}

p.Images.Add(e);
}

return p;
}
}
19 changes: 19 additions & 0 deletions src/Libs/Libs.Provider/CommunityProvider/CommunityProvider.cs
Original file line number Diff line number Diff line change
@@ -2,12 +2,15 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Bili.Copilot.Libs.Adapter;
using Bili.Copilot.Models.BiliBili;
using Bili.Copilot.Models.BiliBili.Others;
using Bili.Copilot.Models.Constants.Authorize;
using Bili.Copilot.Models.Constants.Bili;
using Bili.Copilot.Models.Data.Appearance;
using Bili.Copilot.Models.Data.Community;
using Bili.Copilot.Models.Data.Dynamic;
using Bilibili.App.Dynamic.V2;
@@ -157,6 +160,22 @@ public static async Task MarkUserDynamicReadAsync(string userId, string offset,
response.EnsureSuccessStatusCode();
}

/// <summary>
/// 获取表情包列表.
/// </summary>
/// <returns>表情包列表.</returns>
public static async Task<List<EmotePackage>> GetEmotePackagesAsync()
{
var queryParameters = new Dictionary<string, string>
{
{ "business", "reply" },
};
var request = await HttpProvider.GetRequestMessageAsync(HttpMethod.Get, Community.Emotes, queryParameters);
var response = await HttpProvider.Instance.SendAsync(request);
var data = await HttpProvider.ParseAsync<ServerResponse<EmoteResponse>>(response);
return data.Data.Packages.Select(CommunityAdapter.ConvertToEmotePackage).ToList();
}

/// <summary>
/// 获取单层评论详情列表.
/// </summary>
5 changes: 5 additions & 0 deletions src/Models/Models.App/Constants/ApiConstants.cs
Original file line number Diff line number Diff line change
@@ -649,6 +649,11 @@ public static class Community
/// 点赞/取消点赞动态.
/// </summary>
public const string LikeDynamic = _grpcBase + "/bilibili.main.dynamic.feed.v1.Feed/DynamicThumb";

/// <summary>
/// 表情包.
/// </summary>
public const string Emotes = _apiBase + "/x/emote/user/panel/web";
}
}
#pragma warning restore SA1600 // Elements should be documented
76 changes: 76 additions & 0 deletions src/Models/Models.BiliBili/Others/EmoteResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Bili Copilot. All rights reserved.

namespace Bili.Copilot.Models.BiliBili.Others;

/// <summary>
/// 表情包响应.
/// </summary>
public class EmoteResponse
{
/// <summary>
/// 表情包集合.
/// </summary>
[JsonPropertyName("packages")]
public List<BiliEmotePackage> Packages { get; set; }
}

/// <summary>
/// 表情包.
/// </summary>
public class BiliEmotePackage
{
/// <summary>
/// 标识符.
/// </summary>
[JsonPropertyName("id")]
public int Id { get; set; }

/// <summary>
/// 对应文本.
/// </summary>
[JsonPropertyName("text")]
public string Text { get; set; }

/// <summary>
/// 图标地址.
/// </summary>
[JsonPropertyName("url")]
public string Url { get; set; }

/// <summary>
/// 表情集合.
/// </summary>
[JsonPropertyName("emote")]
public List<BiliEmote> Emotes { get; set; }
}

/// <summary>
/// 表情.
/// </summary>
public class BiliEmote
{
/// <summary>
/// 标识符.
/// </summary>
[JsonPropertyName("id")]
public int Id { get; set; }

/// <summary>
/// 表情包标识符.
/// </summary>
[JsonPropertyName("package_id")]
public int PackageId { get; set; }

/// <summary>
/// 文本.
/// </summary>
[JsonPropertyName("text")]
public string Text { get; set; }

/// <summary>
/// 图标地址.
/// </summary>
[JsonPropertyName("url")]
public string Url { get; set; }
}

25 changes: 25 additions & 0 deletions src/Models/Models.Data/Appearance/Emote.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Bili Copilot. All rights reserved.

namespace Bili.Copilot.Models.Data.Appearance;

/// <summary>
/// 表情.
/// </summary>
public sealed class Emote
{
/// <summary>
/// 替代文本.
/// </summary>
public string Key { get; set; }

/// <summary>
/// 图片信息.
/// </summary>
public Image Image { get; set; }

/// <inheritdoc/>
public override bool Equals(object obj) => obj is Emote emote && Key == emote.Key;

/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(Key);
}
24 changes: 24 additions & 0 deletions src/Models/Models.Data/Appearance/EmotePackage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Bili Copilot. All rights reserved.

namespace Bili.Copilot.Models.Data.Appearance;

/// <summary>
/// 表情包.
/// </summary>
public sealed class EmotePackage
{
/// <summary>
/// 名称.
/// </summary>
public string Name { get; set; }

/// <summary>
/// 图标.
/// </summary>
public Image Icon { get; set; }

/// <summary>
/// 表情列表.
/// </summary>
public List<Emote> Images { get; set; }
}
79 changes: 79 additions & 0 deletions src/ViewModels/Components/EmoteModuleViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) Bili Copilot. All rights reserved.

using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Bili.Copilot.Libs.Provider;
using Bili.Copilot.ViewModels.Items;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace Bili.Copilot.ViewModels.Components;

/// <summary>
/// 表情模块视图模型.
/// </summary>
public sealed partial class EmoteModuleViewModel : ViewModelBase
{
[ObservableProperty]
private bool _isLoading;

[ObservableProperty]
private EmotePackageViewModel _current;

[ObservableProperty]
private bool _isError;

private EmoteModuleViewModel()
{
Packages = new ObservableCollection<EmotePackageViewModel>();

AttachIsRunningToAsyncCommand(p => IsLoading = p, InitializeCommand);
AttachExceptionHandlerToAsyncCommand(
ex =>
{
LogException(ex);
IsError = true;
},
InitializeCommand);
}

/// <summary>
/// 实例.
/// </summary>
public static EmoteModuleViewModel Instance { get; } = new EmoteModuleViewModel();

/// <summary>
/// 表情包集合.
/// </summary>
public ObservableCollection<EmotePackageViewModel> Packages { get; }

[RelayCommand]
private async Task InitializeAsync()
{
if (Packages.Count > 0)
{
return;
}

IsError = false;
var packages = await CommunityProvider.GetEmotePackagesAsync();
foreach (var item in packages)
{
Packages.Add(new EmotePackageViewModel(item));
}

SelectPackageCommand.Execute(Packages.First());
}

[RelayCommand]
private void SelectPackage(EmotePackageViewModel vm)
{
foreach (var item in Packages)
{
item.IsSelected = vm.Equals(item);
}

Current = vm;
}
}
19 changes: 19 additions & 0 deletions src/ViewModels/Items/EmotePackageViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Bili Copilot. All rights reserved.

using Bili.Copilot.Models.Data.Appearance;

namespace Bili.Copilot.ViewModels.Items;

/// <summary>
/// 表情包视图模型.
/// </summary>
public sealed partial class EmotePackageViewModel : SelectableViewModel<EmotePackage>
{
/// <summary>
/// Initializes a new instance of the <see cref="EmotePackageViewModel"/> class.
/// </summary>
public EmotePackageViewModel(EmotePackage data)
: base(data)
{
}
}
Original file line number Diff line number Diff line change
@@ -33,7 +33,6 @@ private MessageDetailViewModel()
};

InitializeMessageCount();
SelectTypeCommand.Execute(MessageTypes.FirstOrDefault(p => p.Count > 0) ?? MessageTypes.First());
AccountViewModel.Instance.PropertyChanged += OnAccountViewModelPropertyChanged;
}

@@ -54,15 +53,14 @@ protected override void BeforeReload()
/// <inheritdoc/>
protected override async Task GetDataAsync()
{
if (_caches.Count == 0)
if (_isEnd)
{
CurrentType = MessageTypes.First();
CurrentType.IsSelected = true;
return;
}

if (_isEnd)
if (CurrentType == default)
{
return;
SelectTypeCommand.Execute(MessageTypes.First());
}

var view = await AccountProvider.Instance.GetMyMessagesAsync(CurrentType.Type);