mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
fix minor issue
This commit is contained in:
@@ -10,7 +10,7 @@ using Snap.Hutao.UI.Xaml.Data;
|
||||
namespace Snap.Hutao.Core.Database;
|
||||
|
||||
// The scope of the view follows the scope of the service provider.
|
||||
internal sealed class AdvancedDbCollectionView<TEntity> : AdvancedCollectionView<TEntity>
|
||||
internal sealed class AdvancedDbCollectionView<TEntity> : AdvancedCollectionView<TEntity>, IAdvancedDbCollectionView<TEntity>
|
||||
where TEntity : class, IAdvancedCollectionViewItem, ISelectable
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
@@ -57,7 +57,7 @@ internal sealed class AdvancedDbCollectionView<TEntity> : AdvancedCollectionView
|
||||
|
||||
// The scope of the view follows the scope of the service provider.
|
||||
[SuppressMessage("", "SA1402")]
|
||||
internal sealed class AdvancedDbCollectionView<TEntityAccess, TEntity> : AdvancedCollectionView<TEntityAccess>
|
||||
internal sealed class AdvancedDbCollectionView<TEntityAccess, TEntity> : AdvancedCollectionView<TEntityAccess>, IAdvancedDbCollectionView<TEntityAccess>
|
||||
where TEntityAccess : class, IEntityAccess<TEntity>, IAdvancedCollectionViewItem
|
||||
where TEntity : class, ISelectable
|
||||
{
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.UI.Xaml.Data;
|
||||
|
||||
namespace Snap.Hutao.Core.Database;
|
||||
|
||||
internal interface IAdvancedDbCollectionView<TEntity> : IAdvancedCollectionView<TEntity>
|
||||
where TEntity : class
|
||||
{
|
||||
void Detach();
|
||||
}
|
||||
@@ -51,13 +51,6 @@ internal sealed class HutaoException : Exception
|
||||
throw new HutaoException(SH.FormatServiceGachaStatisticsFactoryItemIdInvalid(id), innerException);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static HutaoException UserdataCorrupted(string message, Exception? innerException = default)
|
||||
{
|
||||
throw new HutaoException(message, innerException);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static InvalidCastException InvalidCast<TFrom, TTo>(string name, Exception? innerException = default)
|
||||
|
||||
@@ -28,7 +28,7 @@ internal sealed partial class AchievementDbService : IAchievementDbService
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
throw HutaoException.UserdataCorrupted(SH.ServiceAchievementUserdataCorruptedAchievementIdNotUnique, ex);
|
||||
throw HutaoException.Throw(SH.ServiceAchievementUserdataCorruptedAchievementIdNotUnique, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ internal sealed partial class AchievementDbService : IAchievementDbService
|
||||
|
||||
public void RemoveAchievementArchive(AchievementArchive archive)
|
||||
{
|
||||
// It will cascade delete the achievements.
|
||||
// Cascade delete the achievements.
|
||||
this.Delete(archive);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@ using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.InterChange.Achievement;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using Snap.Hutao.UI.Xaml.Data;
|
||||
using Snap.Hutao.ViewModel.Achievement;
|
||||
using System.Collections.ObjectModel;
|
||||
using EntityAchievement = Snap.Hutao.Model.Entity.Achievement;
|
||||
|
||||
namespace Snap.Hutao.Service.Achievement;
|
||||
@@ -23,11 +25,19 @@ internal sealed partial class AchievementService : IAchievementService
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
private AdvancedDbCollectionView<AchievementArchive>? archivesView;
|
||||
private AdvancedDbCollectionView<AchievementArchive>? archives;
|
||||
|
||||
public AdvancedDbCollectionView<AchievementArchive> Archives
|
||||
public async ValueTask<IAdvancedDbCollectionView<AchievementArchive>> GetArchivesAsync(CancellationToken token = default)
|
||||
{
|
||||
get => archivesView ??= new(achievementDbService.GetAchievementArchiveCollection(), serviceProvider);
|
||||
if (archives is null)
|
||||
{
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
ObservableCollection<AchievementArchive> source = achievementDbService.GetAchievementArchiveCollection();
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
archives = new(source, serviceProvider);
|
||||
}
|
||||
|
||||
return archives;
|
||||
}
|
||||
|
||||
public List<AchievementView> GetAchievementViewList(AchievementArchive archive, AchievementServiceMetadataContext context)
|
||||
@@ -53,27 +63,27 @@ internal sealed partial class AchievementService : IAchievementService
|
||||
return ArchiveAddResultKind.InvalidName;
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(archivesView);
|
||||
ArgumentNullException.ThrowIfNull(archives);
|
||||
|
||||
if (archivesView.SourceCollection.Any(a => a.Name == newArchive.Name))
|
||||
if (archives.SourceCollection.Any(a => a.Name == newArchive.Name))
|
||||
{
|
||||
return ArchiveAddResultKind.AlreadyExists;
|
||||
}
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
archivesView.Add(newArchive);
|
||||
archivesView.MoveCurrentTo(newArchive);
|
||||
archives.Add(newArchive);
|
||||
archives.MoveCurrentTo(newArchive);
|
||||
|
||||
return ArchiveAddResultKind.Added;
|
||||
}
|
||||
|
||||
public async ValueTask RemoveArchiveAsync(AchievementArchive archive)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(archivesView);
|
||||
ArgumentNullException.ThrowIfNull(archives);
|
||||
|
||||
// Sync cache
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
archivesView.Remove(archive);
|
||||
archives.Remove(archive);
|
||||
|
||||
// Sync database
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
|
||||
@@ -10,9 +10,9 @@ namespace Snap.Hutao.Service.Achievement;
|
||||
|
||||
internal interface IAchievementService
|
||||
{
|
||||
AdvancedDbCollectionView<EntityArchive> Archives { get; }
|
||||
ValueTask<IAdvancedDbCollectionView<EntityArchive>> GetArchivesAsync(CancellationToken token = default);
|
||||
|
||||
ValueTask<UIAF> ExportToUIAFAsync(EntityArchive selectedArchive);
|
||||
ValueTask<UIAF> ExportToUIAFAsync(EntityArchive archive);
|
||||
|
||||
List<AchievementView> GetAchievementViewList(EntityArchive archive, AchievementServiceMetadataContext context);
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@ using ModelItem = Snap.Hutao.Model.Item;
|
||||
|
||||
namespace Snap.Hutao.Service.Cultivation;
|
||||
|
||||
/// <summary>
|
||||
/// 养成计算服务
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Singleton, typeof(ICultivationService))]
|
||||
internal sealed partial class CultivationService : ICultivationService
|
||||
@@ -126,19 +122,17 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
return true;
|
||||
}
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
if (Projects.CurrentItem is null)
|
||||
{
|
||||
Projects.MoveCurrentTo(Projects.SourceCollection.SelectedOrDefault());
|
||||
if (Projects.CurrentItem is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
|
||||
if (Projects?.CurrentItem is null)
|
||||
{
|
||||
// Initialize
|
||||
_ = Projects;
|
||||
}
|
||||
|
||||
if (Projects?.CurrentItem is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CultivateEntry? entry = cultivationDbService.GetCultivateEntryByProjectIdAndItemId(Projects.CurrentItem.InnerId, itemId);
|
||||
|
||||
if (entry is null)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
<Visibility x:Key="VisibilityVisible">Visible</Visibility>
|
||||
<Visibility x:Key="VisibilityCollapsed">Collapsed</Visibility>
|
||||
<Duration x:Key="StandardViewOpacityAnimationDuration">0:0:0.5</Duration>
|
||||
<CubicEase x:Key="CubicEaseFunction"/>
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultStandardViewStyle}" TargetType="shuxc:StandardView"/>
|
||||
@@ -34,7 +35,7 @@
|
||||
Storyboard.TargetName="PartEmptyContent"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0"
|
||||
Duration="0:0:0.3"/>
|
||||
Duration="{StaticResource StandardViewOpacityAnimationDuration}"/>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PartEmptyContent" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource VisibilityCollapsed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
@@ -46,7 +47,7 @@
|
||||
Storyboard.TargetName="PartContent"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1"
|
||||
Duration="0:0:0.3"/>
|
||||
Duration="{StaticResource StandardViewOpacityAnimationDuration}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
@@ -57,7 +58,7 @@
|
||||
Storyboard.TargetName="PartContent"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0"
|
||||
Duration="0:0:0.3"/>
|
||||
Duration="{StaticResource StandardViewOpacityAnimationDuration}"/>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PartContent" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource VisibilityCollapsed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
@@ -69,7 +70,7 @@
|
||||
Storyboard.TargetName="PartEmptyContent"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1"
|
||||
Duration="0:0:0.3"/>
|
||||
Duration="{StaticResource StandardViewOpacityAnimationDuration}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
@@ -80,7 +81,7 @@
|
||||
Storyboard.TargetName="PartContent"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0"
|
||||
Duration="0:0:0.3"/>
|
||||
Duration="{StaticResource StandardViewOpacityAnimationDuration}"/>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PartContent" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource VisibilityCollapsed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
@@ -90,7 +91,7 @@
|
||||
Storyboard.TargetName="PartEmptyContent"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0"
|
||||
Duration="0:0:0.3"/>
|
||||
Duration="{StaticResource StandardViewOpacityAnimationDuration}"/>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PartEmptyContent" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource VisibilityCollapsed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
|
||||
@@ -107,7 +107,11 @@ internal class AdvancedCollectionView<T> : IAdvancedCollectionView<T>, INotifyPr
|
||||
set => MoveCurrentTo(value);
|
||||
}
|
||||
|
||||
public int CurrentPosition { get; private set; }
|
||||
public int CurrentPosition
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool HasMoreItems
|
||||
{
|
||||
@@ -633,6 +637,7 @@ internal class AdvancedCollectionView<T> : IAdvancedCollectionView<T>, INotifyPr
|
||||
if (itemIndex <= CurrentPosition)
|
||||
{
|
||||
CurrentPosition--;
|
||||
OnPropertyChanged(nameof(CurrentItem));
|
||||
}
|
||||
|
||||
OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemRemoved, itemIndex, item));
|
||||
@@ -650,13 +655,14 @@ internal class AdvancedCollectionView<T> : IAdvancedCollectionView<T>, INotifyPr
|
||||
|
||||
private bool MoveCurrentToIndex(int i)
|
||||
{
|
||||
if (i < -1 || i >= view.Count)
|
||||
if (i == CurrentPosition)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i == CurrentPosition)
|
||||
if (i < -1 || i >= view.Count)
|
||||
{
|
||||
OnPropertyChanged(nameof(CurrentItem));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
<shuxb:InvokeCommandOnLoadedBehavior Command="{Binding LoadCommand}"/>
|
||||
</mxi:Interaction.Behaviors>
|
||||
|
||||
<shuxc:StandardView HideCondition="{Binding IsInitialized, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" ShowCondition="{Binding Achievements, Converter={StaticResource EmptyObjectToBoolConverter}, Mode=OneWay}">
|
||||
<shuxc:StandardView HideCondition="{Binding IsInitialized, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" ShowCondition="{Binding Archives.CurrentItem, Converter={StaticResource EmptyObjectToBoolConverter}, Mode=OneWay}">
|
||||
<shuxc:StandardView.EmptyContent>
|
||||
<Border
|
||||
HorizontalAlignment="Center"
|
||||
|
||||
@@ -419,7 +419,7 @@
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{shuxm:ResourceString Name=ViewPageLaunchGameSelectGamePath}"/>
|
||||
<Border Style="{ThemeResource BorderCardStyle}">
|
||||
<Border Style="{ThemeResource BorderCardStyle}" Visibility="{Binding GamePathEntries.Count, Converter={StaticResource Int32ToVisibilityConverter}}">
|
||||
<ListView
|
||||
ItemTemplate="{StaticResource GamePathEntryListTemplate}"
|
||||
ItemsSource="{Binding GamePathEntries}"
|
||||
|
||||
@@ -21,7 +21,7 @@ internal sealed partial class AchievementImporter
|
||||
|
||||
public async ValueTask<bool> FromClipboardAsync(AchievementViewModelScopeContext context)
|
||||
{
|
||||
if (context.AchievementService.Archives.CurrentItem is not { } archive)
|
||||
if (await context.AchievementService.GetArchivesAsync().ConfigureAwait(false) is not { CurrentItem: { } archive })
|
||||
{
|
||||
scopeContext.InfoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage2);
|
||||
return false;
|
||||
@@ -38,7 +38,7 @@ internal sealed partial class AchievementImporter
|
||||
|
||||
public async ValueTask<bool> FromFileAsync(AchievementViewModelScopeContext context)
|
||||
{
|
||||
if (context.AchievementService.Archives.CurrentItem is not { } archive)
|
||||
if (await context.AchievementService.GetArchivesAsync().ConfigureAwait(false) is not { CurrentItem: { } archive })
|
||||
{
|
||||
scopeContext.InfoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage2);
|
||||
return false;
|
||||
|
||||
@@ -16,7 +16,7 @@ using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.UI.Xaml.Data;
|
||||
using Snap.Hutao.UI.Xaml.View.Dialog;
|
||||
using System.Text.RegularExpressions;
|
||||
using EntityAchievementArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
||||
using EntityArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
||||
using MetadataAchievementGoal = Snap.Hutao.Model.Metadata.Achievement.AchievementGoal;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Achievement;
|
||||
@@ -36,13 +36,13 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
|
||||
private AdvancedCollectionView<AchievementView>? achievements;
|
||||
private AdvancedCollectionView<AchievementGoalView>? achievementGoals;
|
||||
private AdvancedDbCollectionView<EntityAchievementArchive>? archives;
|
||||
private IAdvancedDbCollectionView<EntityArchive>? archives;
|
||||
|
||||
private bool isUncompletedItemsFirst = true;
|
||||
private string searchText = string.Empty;
|
||||
private string? finishDescription;
|
||||
|
||||
public AdvancedDbCollectionView<EntityAchievementArchive>? Archives
|
||||
public IAdvancedDbCollectionView<EntityArchive>? Archives
|
||||
{
|
||||
get => archives;
|
||||
set
|
||||
@@ -137,10 +137,11 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
sortedGoals = goals.SortBy(goal => goal.Order).SelectList(AchievementGoalView.From);
|
||||
}
|
||||
|
||||
IAdvancedDbCollectionView<EntityArchive> archives = await scopeContext.AchievementService.GetArchivesAsync(CancellationToken).ConfigureAwait(false);
|
||||
await scopeContext.TaskContext.SwitchToMainThreadAsync();
|
||||
|
||||
AchievementGoals = new(sortedGoals, true);
|
||||
Archives = scopeContext.AchievementService.Archives;
|
||||
Archives = archives;
|
||||
Archives.MoveCurrentTo(Archives.SourceCollection.SelectedOrDefault());
|
||||
return true;
|
||||
}
|
||||
@@ -183,7 +184,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
return;
|
||||
}
|
||||
|
||||
switch (await scopeContext.AchievementService.AddArchiveAsync(EntityAchievementArchive.From(name)).ConfigureAwait(false))
|
||||
switch (await scopeContext.AchievementService.AddArchiveAsync(EntityArchive.From(name)).ConfigureAwait(false))
|
||||
{
|
||||
case ArchiveAddResultKind.Added:
|
||||
await scopeContext.TaskContext.SwitchToMainThreadAsync();
|
||||
@@ -225,9 +226,6 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
{
|
||||
await scopeContext.AchievementService.RemoveArchiveAsync(current).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await scopeContext.TaskContext.SwitchToMainThreadAsync();
|
||||
Archives.MoveCurrentToFirstOrDefault();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -281,7 +279,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask UpdateAchievementsAsync(EntityAchievementArchive? archive)
|
||||
private async ValueTask UpdateAchievementsAsync(EntityArchive? archive)
|
||||
{
|
||||
// TODO: immediately clear values
|
||||
if (archive is null)
|
||||
@@ -305,7 +303,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
UpdateAchievementsSort();
|
||||
}
|
||||
|
||||
private bool TryGetAchievements(EntityAchievementArchive archive, AchievementServiceMetadataContext context, [NotNullWhen(true)] out List<AchievementView>? combined)
|
||||
private bool TryGetAchievements(EntityArchive archive, AchievementServiceMetadataContext context, [NotNullWhen(true)] out List<AchievementView>? combined)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -73,7 +73,7 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Projects = cultivationService.Projects;
|
||||
Projects.CurrentItem = Projects.SourceCollection.SelectedOrDefault();
|
||||
Projects.MoveCurrentTo(Projects.SourceCollection.SelectedOrDefault());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user