Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into thumbnails-in-pages
Browse files Browse the repository at this point in the history
  • Loading branch information
Sewer56 committed Jan 8, 2025
2 parents 8b5856c + b8beabe commit 591746a
Show file tree
Hide file tree
Showing 39 changed files with 527 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ public static Uri CreateUri(string baseUrl, string? campaign = null, string? med

public static Uri CreateCollectionsUri(GameDomain gameDomain, CollectionSlug collectionSlug) => CreateUri($"https://next.nexusmods.com/{gameDomain}/collections/{collectionSlug}", campaign: "collections");

public static Uri LearAboutPremiumUri => CreateUri("https://next.nexusmods.com/premium");

public static Uri UpgradeToPremiumUri => CreateUri("https://users.nexusmods.com/account/billing/premium");

/// <summary>
/// Creates a new URI pointing to a mod on Nexus Mods. This should only be used
/// by diagnostics.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using JetBrains.Annotations;
using NexusMods.App.UI.Controls;
using NexusMods.App.UI.Controls.Navigation;

namespace NexusMods.App.UI.LeftMenu.Items;
namespace NexusMods.App.UI.Controls.Navigation;

/// <summary>
/// A standard left menu button with active and selected states, as well as workspace navigation capabilities.
Expand Down
1 change: 1 addition & 0 deletions src/NexusMods.App.UI/LeftMenu/ILeftMenuViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.ObjectModel;
using NexusMods.Abstractions.UI;
using NexusMods.App.UI.LeftMenu.Items;
using NexusMods.App.UI.WorkspaceSystem;

namespace NexusMods.App.UI.LeftMenu;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System.Reactive;
using NexusMods.Abstractions.Jobs;
using NexusMods.Abstractions.Loadouts;
using NexusMods.Abstractions.UI;
using ReactiveUI;

namespace NexusMods.App.UI.LeftMenu.Items;

public interface ILaunchButtonViewModel : ILeftMenuItemViewModel
public interface ILaunchButtonViewModel : IViewModelInterface
{
/// <summary>
/// The currently selected loadout.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using NexusMods.Abstractions.UI;

namespace NexusMods.App.UI.LeftMenu;
namespace NexusMods.App.UI.LeftMenu.Items;

public interface ILeftMenuItemViewModel : IViewModelInterface
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using NexusMods.Abstractions.Loadouts;
using NexusMods.App.UI.LeftMenu.Items;

namespace NexusMods.App.UI.LeftMenu.Loadout;
namespace NexusMods.App.UI.LeftMenu.Items;

public class LeftMenuCollectionViewModel : IconViewModel
public class LeftMenuCollectionItemViewModel : IconViewModel
{
/// <summary>
/// The group id of the collection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public LoadoutLeftMenuViewModel(

private ILeftMenuItemViewModel MakeLoadoutItemGroupViewModel(IWorkspaceController workspaceController, CollectionGroup.ReadOnly itm, IServiceProvider serviceProvider)
{
var vm = new LeftMenuCollectionViewModel
var vm = new LeftMenuCollectionItemViewModel
{
CollectionGroupId = itm.CollectionGroupId,
Name = itm.AsLoadoutItemGroup().AsLoadoutItem().Name,
Expand Down Expand Up @@ -239,7 +239,7 @@ public int Compare(ILeftMenuItemViewModel? x, ILeftMenuItemViewModel? y)

return (x, y) switch
{
(LeftMenuCollectionViewModel a, LeftMenuCollectionViewModel b) => a.CollectionGroupId.Value.CompareTo(b.CollectionGroupId.Value),
(LeftMenuCollectionItemViewModel a, LeftMenuCollectionItemViewModel b) => a.CollectionGroupId.Value.CompareTo(b.CollectionGroupId.Value),
(IconViewModel a, IconViewModel b) => a.RelativeOrder.CompareTo(b.RelativeOrder),
_ => 0,
};
Expand Down
29 changes: 17 additions & 12 deletions src/NexusMods.App.UI/NexusMods.App.UI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -391,21 +391,12 @@
<Compile Update="LeftMenu\Loadout\LoadoutLeftMenuDesignViewModel.cs">
<DependentUpon>ILoadoutLeftMenuViewModel.cs</DependentUpon>
</Compile>
<Compile Update="LeftMenu\Items\LaunchButtonDesignViewModel.cs">
<DependentUpon>ILaunchButtonViewModel.cs</DependentUpon>
</Compile>
<Compile Update="LeftMenu\Items\LaunchButtonViewModel.cs">
<DependentUpon>ILaunchButtonViewModel.cs</DependentUpon>
</Compile>
<Compile Update="LeftMenu\Items\IconViewModel.cs">
<DependentUpon>IIconViewModel.cs</DependentUpon>
</Compile>
<Compile Update="LeftMenu\Items\IApplyControlDesignViewModel.cs">
<DependentUpon>IApplyControlViewModel.cs</DependentUpon>
</Compile>
<Compile Update="LeftMenu\Items\ApplyControlViewModel.cs">
<DependentUpon>IApplyControlViewModel.cs</DependentUpon>
</Compile>
<Compile Update="Controls\ModInfo\Dummy\ViewModFilesView.axaml.cs">
<DependentUpon>ViewModFilesView.axaml</DependentUpon>
<SubType>Code</SubType>
Expand Down Expand Up @@ -451,9 +442,6 @@
<Compile Update="Controls\Trees\ModFileTreeViewModel.cs">
<DependentUpon>IFileTreeViewModel.cs</DependentUpon>
</Compile>
<Compile Update="LeftMenu\Items\ApplyControlDesignViewModel.cs">
<DependentUpon>IApplyControlViewModel.cs</DependentUpon>
</Compile>
<Compile Update="Pages\MyGames\MyGamesDesignViewModel.cs">
<DependentUpon>IMyGamesViewModel.cs</DependentUpon>
</Compile>
Expand Down Expand Up @@ -708,6 +696,23 @@
<Compile Update="Pages\LibraryPage\ILibraryItemWithThumbnailAndName.cs">
<DependentUpon>ILibraryItemModel.cs</DependentUpon>
</Compile>
<Compile Update="LeftMenu\Items\IconDesignViewModel.cs">
<DependentUpon>IIconViewModel.cs</DependentUpon>
</Compile>
<Compile Update="LeftMenu\Items\ApplyControl\ApplyControlView.axaml.cs">
<DependentUpon>ApplyControlView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="LeftMenu\Items\ApplyControl\LaunchButtonView.axaml.cs">
<DependentUpon>LaunchButtonView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="LeftMenu\Items\LeftMenuCollectionItemViewModel.cs">
<DependentUpon>IconViewModel.cs</DependentUpon>
</Compile>
<Compile Update="LeftMenu\Items\IIconViewModel.cs">
<DependentUpon>ILeftMenuItemViewModel.cs</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/NexusMods.App.UI/NexusMods.App.UI.csproj.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=controls_005Csettings_005Csettingentries_005Csettinginteractioncontrols_005Ctoggle/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=controls_005Ctreedatagrid/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=filters/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=leftmenu_005Citems_005Capplycontrol/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=overlays_005Clogin_005Cstartupmessagebox/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=overlays_005Cupgradetopremium/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pages_005Cdiagnostics_005Cdetails/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pages_005Cdiagnostics_005Clist/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pages_005Cmodlibrary_005Cdownloadslibrary/@EntryIndexedValue">True</s:Boolean>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<reactive:ReactiveUserControl
x:TypeArguments="local:IUpgradeToPremiumViewModel"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactive="http://reactiveui.net"
xmlns:local="clr-namespace:NexusMods.App.UI.Overlays"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:base="clr-namespace:NexusMods.App.UI.Overlays.Generic.MessageBox.Base"
x:Class="NexusMods.App.UI.Overlays.UpgradeToPremiumView">

<base:MessageBoxBackground>
<base:MessageBoxBackground.TopContent>
<StackPanel Orientation="Vertical" Margin="16, 24, 24, 24" Classes="Spacing-3_5">
<reactive:ViewModelViewHost x:Name="ViewModelViewHostMarkdownRenderer"/>
</StackPanel>
</base:MessageBoxBackground.TopContent>

<base:MessageBoxBackground.BottomContent>
<StackPanel Orientation="Horizontal" Margin="24" HorizontalAlignment="Right" Classes="Spacing-2">
<Button x:Name="ButtonCancel" Classes="Standard Tertiary" HorizontalAlignment="Stretch">
<TextBlock Text="Cancel"/>
</Button>
<Button x:Name="ButtonUpgrade" Classes="Standard Primary" HorizontalAlignment="Stretch">
<TextBlock Text="Upgrade to Premium"/>
</Button>
</StackPanel>
</base:MessageBoxBackground.BottomContent>
</base:MessageBoxBackground>

</reactive:ReactiveUserControl>

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Reactive.Disposables;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using ReactiveUI;

namespace NexusMods.App.UI.Overlays;

public partial class UpgradeToPremiumView : ReactiveUserControl<IUpgradeToPremiumViewModel>
{
public UpgradeToPremiumView()
{
InitializeComponent();

this.WhenActivated(disposables =>
{
this.BindCommand(ViewModel, vm => vm.CommandCancel, view => view.ButtonCancel)
.DisposeWith(disposables);

this.BindCommand(ViewModel, vm => vm.CommandUpgrade, view => view.ButtonUpgrade)
.DisposeWith(disposables);

this.OneWayBind(ViewModel, vm => vm.MarkdownRendererViewModel, view => view.ViewModelViewHostMarkdownRenderer.ViewModel)
.DisposeWith(disposables);
});
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using NexusMods.Abstractions.Telemetry;
using NexusMods.Abstractions.UI;
using NexusMods.App.UI.Controls.MarkdownRenderer;
using NexusMods.CrossPlatform.Process;
using R3;

namespace NexusMods.App.UI.Overlays;

public interface IUpgradeToPremiumViewModel : IOverlayViewModel
{
public IMarkdownRendererViewModel MarkdownRendererViewModel { get; }

public ReactiveCommand<Unit> CommandCancel { get; }

public ReactiveCommand<Unit> CommandUpgrade { get; }
}

public class UpgradeToPremiumViewModel : AOverlayViewModel<IUpgradeToPremiumViewModel>, IUpgradeToPremiumViewModel
{
public UpgradeToPremiumViewModel(
IOSInterop osInterop,
IMarkdownRendererViewModel markdownRendererViewModel)
{
MarkdownRendererViewModel = markdownRendererViewModel;
MarkdownRendererViewModel.Contents = $"""
### Upgrade to Premium to unlock 1 click downloads
Download all mods in a collection at full speed with 1 click and without leaving the app.
No more visiting every mod page in the browser.
Premium users also get:
* **Uncapped downloads** - Download all mods without any speed limits.
* **No Ads - For Life!** - Never see ads again on the website, even if you cancel!
* **Support authors** - Premium memberships allow Nexus Mods to reward mod authors.
[Learn more about Premium]({ NexusModsUrlBuilder.LearAboutPremiumUri })
""";

CommandCancel = new ReactiveCommand(_ => base.Close());
CommandUpgrade = new ReactiveCommand(
executeAsync: async (_, cancellationToken) => await osInterop.OpenUrl(NexusModsUrlBuilder.UpgradeToPremiumUri, cancellationToken: cancellationToken),
awaitOperation: AwaitOperation.Parallel,
configureAwait: false
);
}

public IMarkdownRendererViewModel MarkdownRendererViewModel { get; }
public ReactiveCommand<Unit> CommandCancel { get; }
public ReactiveCommand<Unit> CommandUpgrade { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public CollectionDownloadDesignViewModel() : base(new DesignWindowManager()) { }

public int CountDownloadedOptionalItems { get; } = 0;
public int CountDownloadedRequiredItems { get; } = 1;
public bool CanDownloadAutomatically { get; } = false;
public ReactiveCommand<Unit> CommandDownloadOptionalItems { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandDownloadRequiredItems { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandInstallOptionalItems { get; } = new ReactiveCommand();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Avalonia.ReactiveUI;
using NexusMods.App.UI.Controls;
using NexusMods.App.UI.Pages.LibraryPage;
using NexusMods.Icons;
using NexusMods.MnemonicDB.Abstractions;
using R3;
using ReactiveUI;
Expand Down Expand Up @@ -152,6 +153,13 @@ public CollectionDownloadView()
})
.Subscribe(className => OverallRatingPanel.Classes.Add(className))
.DisposeWith(d);

this.WhenAnyValue(view => view.ViewModel!.CanDownloadAutomatically)
.Subscribe(canDownloadAutomatically =>
{
ButtonDownloadRequiredItems.LeftIcon = canDownloadAutomatically ? null : IconValues.Lock;
ButtonDownloadOptionalItems.LeftIcon = canDownloadAutomatically ? null : IconValues.Lock;
}).DisposeWith(d);
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using NexusMods.Abstractions.UI.Extensions;
using NexusMods.App.UI.Controls;
using NexusMods.App.UI.Extensions;
using NexusMods.App.UI.Overlays;
using NexusMods.App.UI.Pages.LibraryPage;
using NexusMods.App.UI.Pages.LibraryPage.Collections;
using NexusMods.App.UI.Pages.TextEdit;
Expand Down Expand Up @@ -59,6 +60,7 @@ public CollectionDownloadViewModel(
var nexusModsLibrary = serviceProvider.GetRequiredService<NexusModsLibrary>();
var collectionDownloader = new CollectionDownloader(serviceProvider);
var loginManager = serviceProvider.GetRequiredService<ILoginManager>();
var overlayController = serviceProvider.GetRequiredService<IOverlayController>();

var tileImagePipeline = ImagePipelines.GetCollectionTileImagePipeline(serviceProvider);
var backgroundImagePipeline = ImagePipelines.GetCollectionBackgroundImagePipeline(serviceProvider);
Expand All @@ -81,13 +83,21 @@ public CollectionDownloadViewModel(
OptionalDownloadsCount = collectionDownloader.CountItems(_revision, CollectionDownloader.ItemType.Optional);

CommandDownloadRequiredItems = _canDownloadRequiredItems.ToReactiveCommand<Unit>(
executeAsync: (_, cancellationToken) => collectionDownloader.DownloadItems(_revision, itemType: CollectionDownloader.ItemType.Required, db: connection.Db, cancellationToken: cancellationToken),
executeAsync: async (_, cancellationToken) =>
{
if (loginManager.IsPremium) await collectionDownloader.DownloadItems(_revision, itemType: CollectionDownloader.ItemType.Required, db: connection.Db, cancellationToken: cancellationToken);
else overlayController.Enqueue(serviceProvider.GetRequiredService<IUpgradeToPremiumViewModel>());
},
awaitOperation: AwaitOperation.Drop,
configureAwait: false
);

CommandDownloadOptionalItems = _canDownloadOptionalItems.ToReactiveCommand<Unit>(
executeAsync: (_, cancellationToken) => collectionDownloader.DownloadItems(_revision, itemType: CollectionDownloader.ItemType.Optional, db: connection.Db, cancellationToken: cancellationToken),
executeAsync: async (_, cancellationToken) =>
{
if (loginManager.IsPremium) await collectionDownloader.DownloadItems(_revision, itemType: CollectionDownloader.ItemType.Optional, db: connection.Db, cancellationToken: cancellationToken);
else overlayController.Enqueue(serviceProvider.GetRequiredService<IUpgradeToPremiumViewModel>());
},
awaitOperation: AwaitOperation.Drop,
configureAwait: false
);
Expand Down Expand Up @@ -184,19 +194,24 @@ public CollectionDownloadViewModel(
.OffUi()
.SelectMany(revision => collectionDownloader.DownloadedItemCountObservable(revision, itemType: CollectionDownloader.ItemType.Optional));

var isPremiumObservable = loginManager.IsPremiumObservable.Prepend(false);
loginManager.IsPremiumObservable
.Prepend(false)
.OnUI()
.Subscribe(isPremium => CanDownloadAutomatically = isPremium)
.AddTo(disposables);

var isCollectionInstalledObservable = collectionDownloader.IsCollectionInstalled(_revision).Prepend(false);

numDownloadedRequiredItemsObservable.CombineLatest(isPremiumObservable, isCollectionInstalledObservable)
numDownloadedRequiredItemsObservable.CombineLatest(isCollectionInstalledObservable)
.OnUI()
.Subscribe(tuple =>
{
var (numDownloadedRequiredItems, isPremium, isCollectionInstalled) = tuple;
var (numDownloadedRequiredItems, isCollectionInstalled) = tuple;
var hasDownloadedAllRequiredItems = numDownloadedRequiredItems == RequiredDownloadsCount;

CountDownloadedRequiredItems = numDownloadedRequiredItems;
_canInstallRequiredItems.OnNext(!isCollectionInstalled && hasDownloadedAllRequiredItems);
_canDownloadRequiredItems.OnNext(!hasDownloadedAllRequiredItems && isPremium);
_canDownloadRequiredItems.OnNext(!hasDownloadedAllRequiredItems);

if (hasDownloadedAllRequiredItems)
{
Expand All @@ -208,16 +223,15 @@ public CollectionDownloadViewModel(
}
}).AddTo(disposables);

numDownloadedOptionalItemsObservable.CombineLatest(isPremiumObservable)
numDownloadedOptionalItemsObservable
.OnUI()
.Subscribe(tuple =>
.Subscribe(numDownloadedOptionalItems =>
{
var (numDownloadedOptionalItems, isPremium) = tuple;
var hasDownloadedAllOptionalItems = numDownloadedOptionalItems == OptionalDownloadsCount;

CountDownloadedOptionalItems = numDownloadedOptionalItems;
_canInstallOptionalItems.OnNext(numDownloadedOptionalItems > 0);
_canDownloadOptionalItems.OnNext(!hasDownloadedAllOptionalItems && isPremium);
_canDownloadOptionalItems.OnNext(!hasDownloadedAllOptionalItems);
}).AddTo(disposables);

ImagePipelines.CreateObservable(_collection.Id, tileImagePipeline)
Expand Down Expand Up @@ -294,6 +308,8 @@ private async ValueTask InstallItem(NexusMods.Abstractions.NexusModsLibrary.Mode
[Reactive] public Bitmap? AuthorAvatar { get; private set; }
[Reactive] public string CollectionStatusText { get; private set; } = "";

[Reactive] public bool CanDownloadAutomatically { get; private set; } = false;

public ReactiveCommand<Unit> CommandDownloadRequiredItems { get; }
public ReactiveCommand<Unit> CommandInstallRequiredItems { get; }
public ReactiveCommand<Unit> CommandDownloadOptionalItems { get; }
Expand Down
Loading

0 comments on commit 591746a

Please sign in to comment.