diff --git a/Pixeval.sln b/Pixeval.sln index 350ca5fe..c33031ef 100644 --- a/Pixeval.sln +++ b/Pixeval.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31515.178 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31808.319 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pixeval", "src\Pixeval\Pixeval.csproj", "{97004D5A-21BE-4137-A529-A9E150AEB3CE}" EndProject diff --git a/src/Pixeval/Activation/ActivationRegistrar.cs b/src/Pixeval/Activation/ActivationRegistrar.cs new file mode 100644 index 00000000..7d0b58aa --- /dev/null +++ b/src/Pixeval/Activation/ActivationRegistrar.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Windows.ApplicationModel.Activation; +using Microsoft.Windows.AppLifecycle; + +namespace Pixeval.Activation +{ + public static class ActivationRegistrar + { + static ActivationRegistrar() + { + FeatureHandlers[IllustrationActivationFragment] = new IllustrationAppActivationHandler(); + } + + public static readonly Dictionary FeatureHandlers = new(); + + public const string IllustrationActivationFragment = "illust"; + + public static void Dispatch(AppActivationArguments args) + { + if (args.Kind == ExtendedActivationKind.Protocol && args.Data is IProtocolActivatedEventArgs { Uri: var activationUri } && FeatureHandlers.TryGetValue(activationUri.Host, out var handler)) + { + handler.Execute(activationUri.PathAndQuery[1..]); + } + } + } +} \ No newline at end of file diff --git a/src/Pixeval/Activation/IAppActivationHandler.cs b/src/Pixeval/Activation/IAppActivationHandler.cs new file mode 100644 index 00000000..f38694cd --- /dev/null +++ b/src/Pixeval/Activation/IAppActivationHandler.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Pixeval.Activation +{ + public interface IAppActivationHandler + { + Task Execute(string id); + } +} \ No newline at end of file diff --git a/src/Pixeval/Activation/IllustrationAppActivationHandler.cs b/src/Pixeval/Activation/IllustrationAppActivationHandler.cs new file mode 100644 index 00000000..63300046 --- /dev/null +++ b/src/Pixeval/Activation/IllustrationAppActivationHandler.cs @@ -0,0 +1,46 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Toolkit.Mvvm.Messaging; +using Microsoft.UI.Xaml.Media.Animation; +using Pixeval.Messages; +using Pixeval.Pages.IllustrationViewer; +using Pixeval.Util.UI; +using Pixeval.Utilities; +using Pixeval.ViewModel; + +namespace Pixeval.Activation +{ + public class IllustrationAppActivationHandler : IAppActivationHandler + { + public Task Execute(string id) + { + WeakReferenceMessenger.Default.Send(new MainPageFrameSetConnectedAnimationTargetMessage(App.AppViewModel.AppWindowRootFrame)); + + return App.AppViewModel.DispatchTaskAsync(async () => + { + App.AppViewModel.PrepareForActivation(); + + try + { + var viewModels = new IllustrationViewModel(await App.AppViewModel.MakoClient.GetIllustrationFromIdAsync(id)) + .GetMangaIllustrationViewModels() + .ToArray(); + + ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("ForwardConnectedAnimation", App.AppViewModel.AppWindowRootFrame); + App.AppViewModel.RootFrameNavigate(typeof(IllustrationViewerPage), new IllustrationViewerPageViewModel(viewModels), new SuppressNavigationTransitionInfo()); + } + catch (Exception e) + { + UIHelper.ShowTextToastNotification( + ActivationsResources.IllustrationActivationFailedTitle, + ActivationsResources.IllustrationActivationFailedContentFormatted.Format(e.Message)); + } + finally + { + App.AppViewModel.ActivationProcessed(); + } + }); + } + } +} \ No newline at end of file diff --git a/src/Pixeval/App.xaml.cs b/src/Pixeval/App.xaml.cs index 18297144..af3bb65f 100644 --- a/src/Pixeval/App.xaml.cs +++ b/src/Pixeval/App.xaml.cs @@ -1,8 +1,13 @@ -using Microsoft.UI.Xaml; +using System; +using System.Linq; +using Windows.ApplicationModel.Activation; using Microsoft.UI.Xaml.Media; +using Microsoft.Windows.AppLifecycle; +using Pixeval.Activation; using Pixeval.Util.UI; using Pixeval.ViewModel; using ApplicationTheme = Pixeval.Options.ApplicationTheme; +using LaunchActivatedEventArgs = Microsoft.UI.Xaml.LaunchActivatedEventArgs; namespace Pixeval { @@ -11,7 +16,7 @@ namespace Pixeval private const string ApplicationWideFontKey = "ContentControlThemeFontFamily"; public static AppViewModel AppViewModel { get; private set; } = null!; - + public App() { // The theme can only be changed in ctor @@ -22,13 +27,24 @@ namespace Pixeval ApplicationTheme.Light => Microsoft.UI.Xaml.ApplicationTheme.Light, _ => RequestedTheme }; + AppInstance.GetCurrent().Activated += (_, arguments) => ActivationRegistrar.Dispatch(arguments); InitializeComponent(); } + + protected override async void OnLaunched(LaunchActivatedEventArgs args) { + var isProtocolActivated = AppInstance.GetCurrent().GetActivatedEventArgs() is { Kind: ExtendedActivationKind.Protocol }; + if (isProtocolActivated && AppInstance.GetInstances().Count > 1) + { + var notCurrent = AppInstance.GetInstances().First(ins => !ins.IsCurrent); + await notCurrent.RedirectActivationToAsync(AppInstance.GetCurrent().GetActivatedEventArgs()); + return; + } + Current.Resources[ApplicationWideFontKey] = new FontFamily(AppViewModel.AppSetting.AppFontFamilyName); - await AppViewModel.InitializeAsync(); + await AppViewModel.InitializeAsync(isProtocolActivated); } /// diff --git a/src/Pixeval/MainWindow.xaml b/src/Pixeval/MainWindow.xaml index 3ff11b26..cee1a448 100644 --- a/src/Pixeval/MainWindow.xaml +++ b/src/Pixeval/MainWindow.xaml @@ -5,15 +5,31 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Closed="MainWindow_OnClosed" mc:Ignorable="d"> - - - - - - - + + + + + + + + + + + + + diff --git a/src/Pixeval/MainWindow.xaml.cs b/src/Pixeval/MainWindow.xaml.cs index 9d20b025..86fbe180 100644 --- a/src/Pixeval/MainWindow.xaml.cs +++ b/src/Pixeval/MainWindow.xaml.cs @@ -46,5 +46,15 @@ namespace Pixeval { NavigationMode = e.NavigationMode; } + + public void ShowActivationProgressRing() + { + ProcessingActivation.Visibility = Visibility.Visible; + } + + public void HideActivationProgressRing() + { + ProcessingActivation.Visibility = Visibility.Collapsed; + } } } diff --git a/src/Pixeval/Messages/NavigatingBackToMainPageMessage.cs b/src/Pixeval/Messages/NavigatingBackToMainPageMessage.cs index 81d11eb0..be548dd3 100644 --- a/src/Pixeval/Messages/NavigatingBackToMainPageMessage.cs +++ b/src/Pixeval/Messages/NavigatingBackToMainPageMessage.cs @@ -9,5 +9,5 @@ namespace Pixeval.Messages /// , the parameter contains the item that the /// is currently browsing /// - public record NavigatingBackToMainPageMessage(IllustrationViewModel IllustrationViewModel); + public record NavigatingBackToMainPageMessage(IllustrationViewModel? IllustrationViewModel); } \ No newline at end of file diff --git a/src/Pixeval/Package.appxmanifest b/src/Pixeval/Package.appxmanifest index bb9bb449..be901b8b 100644 --- a/src/Pixeval/Package.appxmanifest +++ b/src/Pixeval/Package.appxmanifest @@ -49,6 +49,13 @@ + + + + Pixeval App Protocol + + + diff --git a/src/Pixeval/Pages/IllustrationViewer/IllustrationViewerPage.xaml.cs b/src/Pixeval/Pages/IllustrationViewer/IllustrationViewerPage.xaml.cs index 1f8c234a..22cb05cd 100644 --- a/src/Pixeval/Pages/IllustrationViewer/IllustrationViewerPage.xaml.cs +++ b/src/Pixeval/Pages/IllustrationViewer/IllustrationViewerPage.xaml.cs @@ -61,7 +61,7 @@ namespace Pixeval.Pages.IllustrationViewer IllustrationImageShowcaseFrame.Navigate(typeof(ImageViewerPage), _viewModel.Current); - WeakReferenceMessenger.Default.Send(new MainPageFrameSetConnectedAnimationTargetMessage(_viewModel.IllustrationGrid.GetItemContainer(_viewModel.IllustrationViewModelInTheGridView))); + WeakReferenceMessenger.Default.Send(new MainPageFrameSetConnectedAnimationTargetMessage(_viewModel.IllustrationGrid?.GetItemContainer(_viewModel.IllustrationViewModelInTheGridView!) ?? App.AppViewModel.AppWindowRootFrame)); WeakReferenceMessenger.Default.Register(this, CommentRepliesHyperlinkButtonTapped); } @@ -133,13 +133,13 @@ namespace Pixeval.Pages.IllustrationViewer Effect = SlideNavigationTransitionEffect.FromLeft }); } - + private void NextIllustration() { - var illustrationViewModel = (IllustrationViewModel) _viewModel.ContainerGridViewModel.IllustrationsView[_viewModel.IllustrationIndex + 1]; + var illustrationViewModel = (IllustrationViewModel) _viewModel.ContainerGridViewModel!.IllustrationsView[_viewModel.IllustrationIndex!.Value + 1]; var viewModel = illustrationViewModel.GetMangaIllustrationViewModels().ToArray(); - App.AppViewModel.RootFrameNavigate(typeof(IllustrationViewerPage), new IllustrationViewerPageViewModel(_viewModel.IllustrationGrid, viewModel), new SlideNavigationTransitionInfo + App.AppViewModel.RootFrameNavigate(typeof(IllustrationViewerPage), new IllustrationViewerPageViewModel(_viewModel.IllustrationGrid!, viewModel), new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromRight }); @@ -147,10 +147,10 @@ namespace Pixeval.Pages.IllustrationViewer private void PrevIllustration() { - var illustrationViewModel = (IllustrationViewModel)_viewModel.ContainerGridViewModel.IllustrationsView[_viewModel.IllustrationIndex - 1]; + var illustrationViewModel = (IllustrationViewModel) _viewModel.ContainerGridViewModel!.IllustrationsView[_viewModel.IllustrationIndex!.Value - 1]; var viewModel = illustrationViewModel.GetMangaIllustrationViewModels().ToArray(); - App.AppViewModel.RootFrameNavigate(typeof(IllustrationViewerPage), new IllustrationViewerPageViewModel(_viewModel.IllustrationGrid, viewModel), new SlideNavigationTransitionInfo + App.AppViewModel.RootFrameNavigate(typeof(IllustrationViewerPage), new IllustrationViewerPageViewModel(_viewModel.IllustrationGrid!, viewModel), new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromLeft }); diff --git a/src/Pixeval/Pages/MainPage.xaml b/src/Pixeval/Pages/MainPage.xaml index 7a178d8e..621f9b4c 100644 --- a/src/Pixeval/Pages/MainPage.xaml +++ b/src/Pixeval/Pages/MainPage.xaml @@ -83,9 +83,11 @@ Icon="{ui:FontIcon Glyph=SearchAndAppsE773}" /> + Icon="{ui:FontIcon Glyph=HistoryE81C}" + Tag="{x:Bind _histories}" /> + Icon="{ui:FontIcon Glyph=CheckListE9D5}" + Tag="{x:Bind _downloads}" /> (this, (_, message) => _connectedAnimationTarget = message.Sender); WeakReferenceMessenger.Default.Register(this, (_, message) => _illustrationViewerContent = message.IllustrationViewModel); WeakReferenceMessenger.Default.Register(this, (_, message) => PerformSearch(message.Tag)); diff --git a/src/Pixeval/Pages/Misc/BrowsingHistoryPage.xaml b/src/Pixeval/Pages/Misc/BrowsingHistoryPage.xaml new file mode 100644 index 00000000..3625af5a --- /dev/null +++ b/src/Pixeval/Pages/Misc/BrowsingHistoryPage.xaml @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/Pixeval/Pages/Misc/BrowsingHistoryPage.xaml.cs b/src/Pixeval/Pages/Misc/BrowsingHistoryPage.xaml.cs new file mode 100644 index 00000000..2492e237 --- /dev/null +++ b/src/Pixeval/Pages/Misc/BrowsingHistoryPage.xaml.cs @@ -0,0 +1,31 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace Pixeval.Pages.Misc +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class BrowsingHistoryPage : Page + { + public BrowsingHistoryPage() + { + this.InitializeComponent(); + } + } +} diff --git a/src/Pixeval/Pages/Misc/DownloadAndHistoryListPage.xaml b/src/Pixeval/Pages/Misc/DownloadAndHistoryListPage.xaml deleted file mode 100644 index 8dbfedca..00000000 --- a/src/Pixeval/Pages/Misc/DownloadAndHistoryListPage.xaml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - diff --git a/src/Pixeval/Pages/Misc/DownloadListPage.xaml b/src/Pixeval/Pages/Misc/DownloadListPage.xaml new file mode 100644 index 00000000..fdabdff0 --- /dev/null +++ b/src/Pixeval/Pages/Misc/DownloadListPage.xaml @@ -0,0 +1,7 @@ + diff --git a/src/Pixeval/Pages/Misc/DownloadAndHistoryListPage.xaml.cs b/src/Pixeval/Pages/Misc/DownloadListPage.xaml.cs similarity index 51% rename from src/Pixeval/Pages/Misc/DownloadAndHistoryListPage.xaml.cs rename to src/Pixeval/Pages/Misc/DownloadListPage.xaml.cs index 601e0283..d9da8400 100644 --- a/src/Pixeval/Pages/Misc/DownloadAndHistoryListPage.xaml.cs +++ b/src/Pixeval/Pages/Misc/DownloadListPage.xaml.cs @@ -1,8 +1,8 @@ namespace Pixeval.Pages.Misc { - public sealed partial class DownloadAndHistoryListPage + public sealed partial class DownloadListPage { - public DownloadAndHistoryListPage() + public DownloadListPage() { this.InitializeComponent(); } diff --git a/src/Pixeval/Pixeval.csproj b/src/Pixeval/Pixeval.csproj index 14c398a0..cf93b6da 100644 --- a/src/Pixeval/Pixeval.csproj +++ b/src/Pixeval/Pixeval.csproj @@ -44,7 +44,6 @@ - @@ -80,12 +79,14 @@ + + - + @@ -98,7 +99,6 @@ - @@ -186,7 +186,7 @@ - + MSBuild:Compile @@ -232,10 +232,11 @@ + - + @@ -280,6 +281,9 @@ MSBuild:Compile + + MSBuild:Compile + MSBuild:Compile diff --git a/src/Pixeval/Properties/launchSettings.json b/src/Pixeval/Properties/launchSettings.json index 011c203a..ae08b693 100644 --- a/src/Pixeval/Properties/launchSettings.json +++ b/src/Pixeval/Properties/launchSettings.json @@ -2,7 +2,6 @@ "profiles": { "Pixeval": { "commandName": "MsixPackage", - "commandLineArgs": "", "alwaysReinstallApp": "false", "remoteDebugEnabled": false, "allowLocalNetworkLoopbackProperty": true, diff --git a/src/Pixeval/Strings/zh-CN/DownloadAndHistoryListPage.resw b/src/Pixeval/Strings/zh-CN/Activations.resw similarity index 95% rename from src/Pixeval/Strings/zh-CN/DownloadAndHistoryListPage.resw rename to src/Pixeval/Strings/zh-CN/Activations.resw index 242e977e..31144879 100644 --- a/src/Pixeval/Strings/zh-CN/DownloadAndHistoryListPage.resw +++ b/src/Pixeval/Strings/zh-CN/Activations.resw @@ -117,13 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 历史记录 + + 错误详情: {0} - - 已下载 - - - 下载中 + + 启动失败 \ No newline at end of file diff --git a/src/Pixeval/Strings/zh-CN/DownloadListPage.resw b/src/Pixeval/Strings/zh-CN/DownloadListPage.resw new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/src/Pixeval/Strings/zh-CN/DownloadListPage.resw @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Pixeval/UserControls/IllustrationGrid.xaml.cs b/src/Pixeval/UserControls/IllustrationGrid.xaml.cs index eea7b4f3..e794e36b 100644 --- a/src/Pixeval/UserControls/IllustrationGrid.xaml.cs +++ b/src/Pixeval/UserControls/IllustrationGrid.xaml.cs @@ -68,12 +68,12 @@ namespace Pixeval.UserControls e.Handled = true; WeakReferenceMessenger.Default.Send(new MainPageFrameSetConnectedAnimationTargetMessage(sender as UIElement)); - var viewModel = sender.GetDataContext() + var viewModels = sender.GetDataContext() .GetMangaIllustrationViewModels() .ToArray(); ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("ForwardConnectedAnimation", (UIElement) sender); - App.AppViewModel.RootFrameNavigate(typeof(IllustrationViewerPage), new IllustrationViewerPageViewModel(this, viewModel), new SuppressNavigationTransitionInfo()); + App.AppViewModel.RootFrameNavigate(typeof(IllustrationViewerPage), new IllustrationViewerPageViewModel(this, viewModels), new SuppressNavigationTransitionInfo()); } private void IllustrationThumbnailContainerItem_OnTapped(object sender, TappedRoutedEventArgs e) diff --git a/src/Pixeval/ViewModel/AppViewModel.cs b/src/Pixeval/ViewModel/AppViewModel.cs index 94393567..c4f8a39b 100644 --- a/src/Pixeval/ViewModel/AppViewModel.cs +++ b/src/Pixeval/ViewModel/AppViewModel.cs @@ -5,6 +5,7 @@ using Windows.Foundation; using Windows.Graphics; using Microsoft.Toolkit.Mvvm.Messaging; using Microsoft.UI; +using Microsoft.UI.Dispatching; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -30,6 +31,8 @@ namespace Pixeval.ViewModel App = app; } + private bool _activatedByProtocol; + public App App { get; } public MainWindow Window = null!; @@ -116,21 +119,31 @@ namespace Pixeval.ViewModel }; #if DEBUG + // ReSharper disable once UnusedParameter.Local static Task UncaughtExceptionHandler(Exception e) { Debugger.Break(); return Task.CompletedTask; } #elif RELEASE - static async Task UncaughtExceptionHandler(Exception e) + async Task UncaughtExceptionHandler(Exception e) { await MessageDialogBuilder.CreateAcknowledgement(Window, MiscResources.ExceptionEncountered, e.ToString()).ShowAsync(); ExitWithPushedNotification(); - } #endif } + public void DispatchTask(DispatcherQueueHandler action) + { + Window.DispatcherQueue.TryEnqueue(action); + } + + public Task DispatchTaskAsync(Func action) + { + return Window.DispatcherQueue.EnqueueAsync(action); + } + /// /// Exit the notification after pushing an @@ -143,12 +156,13 @@ namespace Pixeval.ViewModel Application.Current.Exit(); } - public async Task InitializeAsync() + public async Task InitializeAsync(bool activatedByProtocol) { + _activatedByProtocol = activatedByProtocol; RegisterUnhandledExceptionHandler(); await AppContext.WriteLogoIcoIfNotExist(); - Window = new MainWindow(); + Window = new MainWindow(); AppWindow = AppWindow.GetFromWindowId(Win32Interop.GetWindowIdFromWindow(GetMainWindowHandle())); AppWindow.Title = AppContext.AppIdentifier; AppWindow.Resize(new SizeInt32(AppSetting.WindowWidth, AppSetting.WindowHeight)); @@ -188,5 +202,26 @@ namespace Pixeval.ViewModel { AppContext.SaveContext(); } + + public void PrepareForActivation() + { + Window.ShowActivationProgressRing(); + } + + public void ActivationProcessed() + { + Window.HideActivationProgressRing(); + } + + /// + /// Gets and resets the field, used for one-time activation process + /// during the app start + /// + public bool ConsumeProtocolActivation() + { + var original = _activatedByProtocol; + _activatedByProtocol = false; + return original; + } } } \ No newline at end of file diff --git a/src/Pixeval/ViewModel/IllustrationViewerPageViewModel.cs b/src/Pixeval/ViewModel/IllustrationViewerPageViewModel.cs index b0549be6..603c278c 100644 --- a/src/Pixeval/ViewModel/IllustrationViewerPageViewModel.cs +++ b/src/Pixeval/ViewModel/IllustrationViewerPageViewModel.cs @@ -25,12 +25,23 @@ namespace Pixeval.ViewModel /// /// The view model of the GridView that the comes from /// - public IllustrationGridViewModel ContainerGridViewModel { get; } + public IllustrationGridViewModel? ContainerGridViewModel { get; } /// /// The that owns /// - public IllustrationGrid IllustrationGrid { get; } + public IllustrationGrid? IllustrationGrid { get; } + + /// + /// The in that corresponds to current + /// + /// + public IllustrationViewModel? IllustrationViewModelInTheGridView { get; } + + /// + /// The index of current illustration in + /// + public int? IllustrationIndex => ContainerGridViewModel?.IllustrationsView.IndexOf(IllustrationViewModelInTheGridView); private ImageSource? _qrCodeSource; @@ -158,6 +169,14 @@ namespace Pixeval.ViewModel _ = LoadUserProfileImage(); } + public IllustrationViewerPageViewModel(params IllustrationViewModel[] illustrations) + { + ImageViewerPageViewModels = illustrations.Select(i => new ImageViewerPageViewModel(this, i)).ToArray(); + Current = ImageViewerPageViewModels[CurrentIndex]; + InitializeCommands(); + _ = LoadUserProfileImage(); + } + public void UpdateCommandCanExecute() { PlayGifCommand.NotifyCanExecuteChanged(); @@ -379,17 +398,6 @@ namespace Pixeval.ViewModel private ImageSource? _userProfileImageSource; - /// - /// The in that corresponds to current - /// - /// - public IllustrationViewModel IllustrationViewModelInTheGridView { get; } - - /// - /// The index of current illustration in - /// - public int IllustrationIndex => ContainerGridViewModel.IllustrationsView.IndexOf(IllustrationViewModelInTheGridView); - // Remarks: // The reason why we don't put UserProfileImageSource into IllustrationViewModel // is because the whole array of Illustrations is just representing the same @@ -450,13 +458,21 @@ namespace Pixeval.ViewModel { // changes the IsBookmarked property of the item that of in the thumbnail list // so the thumbnail item will also receives state update - IllustrationViewModelInTheGridView.IsBookmarked = true; + if (IllustrationViewModelInTheGridView is not null) + { + IllustrationViewModelInTheGridView.IsBookmarked = true; + } + return FirstIllustrationViewModel.PostPublicBookmarkAsync(); } public Task RemoveBookmarkAsync() { - IllustrationViewModelInTheGridView.IsBookmarked = false; + if (IllustrationViewModelInTheGridView is not null) + { + IllustrationViewModelInTheGridView.IsBookmarked = false; + } + return FirstIllustrationViewModel.RemoveBookmarkAsync(); } @@ -482,16 +498,28 @@ namespace Pixeval.ViewModel #region Helper Functions public Visibility CalculateNextImageButtonVisibility(int index) { + if (IllustrationGrid is null) + { + return Visibility.Collapsed; + } return index < ImageViewerPageViewModels.Length - 1 ? Visibility.Visible : Visibility.Collapsed; } public Visibility CalculatePrevImageButtonVisibility(int index) { + if (IllustrationGrid is null) + { + return Visibility.Collapsed; + } return index > 0 ? Visibility.Visible : Visibility.Collapsed; } public Visibility CalculateNextIllustrationButtonVisibility(int index) { + if (ContainerGridViewModel is null) + { + return Visibility.Collapsed; + } return ContainerGridViewModel.IllustrationsView.Count > IllustrationIndex + 1 ? CalculateNextImageButtonVisibility(index).Inverse() : Visibility.Collapsed; @@ -499,6 +527,10 @@ namespace Pixeval.ViewModel public Visibility CalculatePrevIllustrationButtonVisibility(int index) { + if (ContainerGridViewModel is null) + { + return Visibility.Collapsed; + } return IllustrationIndex > 0 ? CalculatePrevImageButtonVisibility(index).Inverse() : Visibility.Collapsed;