mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 13:28:33 +00:00
Workshop - Improves default entry handling in workshop
Core - Modifies the Artemis data folder path based on the build configuration. Plugins - Adds a confirmation dialog to prompt the user to restart if a plugin requires admin rights. Startup wizard - Updates the installation progress bar in the startup wizard. Workshop - Changes category retrieval to be based on EntryType. Workshop - Adds the ability to include default entries when searching the workshop.
This commit is contained in:
parent
f0cbc3e561
commit
565647f1ed
@ -40,7 +40,11 @@ public static class Constants
|
||||
/// <summary>
|
||||
/// The full path to the Artemis data folder
|
||||
/// </summary>
|
||||
#if DEBUG
|
||||
public static readonly string DataFolder = Path.Combine(BaseFolder, "Artemis-dev");
|
||||
#else
|
||||
public static readonly string DataFolder = Path.Combine(BaseFolder, "Artemis");
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The full path to the Artemis logs folder
|
||||
|
||||
@ -119,7 +119,7 @@ public partial class PluginViewModel : ActivatableViewModelBase
|
||||
Enabling = true;
|
||||
if (Plugin.Info.RequiresAdmin && !_coreService.IsElevated)
|
||||
{
|
||||
bool confirmed = await _windowService.ShowConfirmContentDialog("Enable plugin", "This plugin requires admin rights, are you sure you want to enable it?");
|
||||
bool confirmed = await _windowService.ShowConfirmContentDialog("Enable plugin", "This plugin requires admin rights, are you sure you want to enable it? Artemis will need to restart.", "Confirm and restart");
|
||||
if (!confirmed)
|
||||
return;
|
||||
}
|
||||
|
||||
@ -62,7 +62,6 @@
|
||||
<ProgressBar Minimum="0"
|
||||
Maximum="{CompiledBinding TotalEntries}"
|
||||
Value="{CompiledBinding CurrentEntry.InstallProgress, FallbackValue=0}"
|
||||
IsIndeterminate="{CompiledBinding CurrentEntry.Enabling, FallbackValue=true}"
|
||||
Margin="0 0 0 5" />
|
||||
<TextBlock>
|
||||
<Run>Currently installing: </Run>
|
||||
|
||||
@ -41,7 +41,7 @@ public partial class DefaultEntriesStepViewModel : WizardStepViewModel
|
||||
_client = client;
|
||||
_getDefaultEntryItemViewModel = getDefaultEntryItemViewModel;
|
||||
_remainingEntries = this.WhenAnyValue(vm => vm.InstalledEntries, vm => vm.TotalEntries)
|
||||
.Select(t => t.Item2 - t.Item1)
|
||||
.Select(t => t.Item2 - t.Item1 + 1)
|
||||
.ToProperty(this, vm => vm.RemainingEntries);
|
||||
|
||||
ContinueText = "Install selected entries";
|
||||
|
||||
@ -31,7 +31,6 @@ public partial class DefaultEntryItemViewModel : ActivatableViewModelBase
|
||||
|
||||
[Notify] private bool _isInstalled;
|
||||
[Notify] private bool _shouldInstall;
|
||||
[Notify] private bool _enabling;
|
||||
[Notify] private float _installProgress;
|
||||
|
||||
public DefaultEntryItemViewModel(ILogger logger, IEntrySummary entry, IWorkshopService workshopService, IWindowService windowService, IPluginManagementService pluginManagementService,
|
||||
@ -70,9 +69,7 @@ public partial class DefaultEntryItemViewModel : ActivatableViewModelBase
|
||||
// If the entry is a plugin, enable the plugin and all features
|
||||
else if (result.Entry?.EntryType == EntryType.Plugin)
|
||||
{
|
||||
Enabling = true;
|
||||
await EnablePluginAndFeatures(result.Entry);
|
||||
Enabling = false;
|
||||
}
|
||||
|
||||
return result.IsSuccess;
|
||||
|
||||
@ -18,10 +18,10 @@ public class CategoriesViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private ObservableAsPropertyHelper<IReadOnlyList<EntryFilterInput>?>? _categoryFilters;
|
||||
|
||||
public CategoriesViewModel(IWorkshopClient client)
|
||||
public CategoriesViewModel(EntryType entryType, IWorkshopClient client)
|
||||
{
|
||||
client.GetCategories
|
||||
.Watch(ExecutionStrategy.CacheFirst)
|
||||
.Watch(entryType, ExecutionStrategy.CacheFirst)
|
||||
.SelectOperationResult(c => c.Categories)
|
||||
.ToObservableChangeSet(c => c.Id)
|
||||
.Transform(c => new CategoryViewModel(c))
|
||||
|
||||
@ -88,6 +88,7 @@ public partial class EntrySpecificationsViewModel : ValidatableViewModelBase
|
||||
public bool IsAdministrator { get; }
|
||||
|
||||
public List<long> PreselectedCategories { get; set; } = new();
|
||||
public EntryType EntryType { get; set; }
|
||||
|
||||
private async Task ExecuteSelectIcon()
|
||||
{
|
||||
@ -114,7 +115,7 @@ public partial class EntrySpecificationsViewModel : ValidatableViewModelBase
|
||||
|
||||
private async Task PopulateCategories()
|
||||
{
|
||||
IOperationResult<IGetCategoriesResult> categories = await _workshopClient.GetCategories.ExecuteAsync();
|
||||
IOperationResult<IGetCategoriesResult> categories = await _workshopClient.GetCategories.ExecuteAsync(EntryType);
|
||||
Categories.Clear();
|
||||
if (categories.Data != null)
|
||||
Categories.AddRange(categories.Data.Categories.Select(c => new CategoryViewModel(c) {IsSelected = PreselectedCategories.Contains(c.Id)}));
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Grid.RowSpan="3"
|
||||
Spacing="10"
|
||||
Margin="0 0 10 0"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Right"
|
||||
@ -32,20 +33,16 @@
|
||||
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">Categories</TextBlock>
|
||||
<Border Classes="card-separator" />
|
||||
<ContentControl Content="{CompiledBinding CategoriesViewModel}"></ContentControl>
|
||||
<CheckBox IsChecked="{CompiledBinding IncludeDefaultEntries}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="2">
|
||||
<Image Source="/Assets/Images/Logo/bow.png" RenderOptions.BitmapInterpolationMode="HighQuality" Width="18" Height="18"/>
|
||||
<TextBlock>Default entries</TextBlock>
|
||||
</StackPanel>
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Classes="card" VerticalAlignment="Stretch">
|
||||
<StackPanel>
|
||||
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">Categories</TextBlock>
|
||||
<Border Classes="card-separator" />
|
||||
<ContentControl Content="{CompiledBinding CategoriesViewModel}"></ContentControl>
|
||||
<CheckBox IsChecked="{CompiledBinding IncludeDefaultEntries}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="2">
|
||||
<TextBlock>Include default entries</TextBlock>
|
||||
</StackPanel>
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
@ -25,7 +25,7 @@ public partial class EntryListViewModel : RoutableScreen
|
||||
private readonly SourceList<IEntrySummary> _entries = new();
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly IWorkshopClient _workshopClient;
|
||||
private IGetEntriesv2_EntriesV2_PageInfo? _currentPageInfo;
|
||||
private IGetEntries_EntriesV2_PageInfo? _currentPageInfo;
|
||||
|
||||
[Notify] private bool _initializing = true;
|
||||
[Notify] private bool _fetchingMore;
|
||||
@ -33,18 +33,20 @@ public partial class EntryListViewModel : RoutableScreen
|
||||
[Notify] private bool _includeDefaultEntries;
|
||||
[Notify] private Vector _scrollOffset;
|
||||
|
||||
protected EntryListViewModel(IWorkshopClient workshopClient,
|
||||
CategoriesViewModel categoriesViewModel,
|
||||
protected EntryListViewModel(EntryType entryType,
|
||||
IWorkshopClient workshopClient,
|
||||
EntryListInputViewModel entryListInputViewModel,
|
||||
INotificationService notificationService,
|
||||
Func<EntryType, CategoriesViewModel> getCategoriesViewModel,
|
||||
Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
||||
{
|
||||
_workshopClient = workshopClient;
|
||||
_notificationService = notificationService;
|
||||
|
||||
CategoriesViewModel = categoriesViewModel;
|
||||
CategoriesViewModel = getCategoriesViewModel(entryType);
|
||||
InputViewModel = entryListInputViewModel;
|
||||
|
||||
EntryType = entryType;
|
||||
|
||||
_entries.Connect()
|
||||
.Transform(getEntryListViewModel)
|
||||
.Bind(out ReadOnlyObservableCollection<EntryListItemViewModel> entries)
|
||||
@ -75,7 +77,7 @@ public partial class EntryListViewModel : RoutableScreen
|
||||
public CategoriesViewModel CategoriesViewModel { get; }
|
||||
public EntryListInputViewModel InputViewModel { get; }
|
||||
public bool ShowCategoryFilter { get; set; } = true;
|
||||
public EntryType? EntryType { get; set; }
|
||||
public EntryType EntryType { get; }
|
||||
|
||||
public ReadOnlyObservableCollection<EntryListItemViewModel> Entries { get; }
|
||||
|
||||
@ -93,7 +95,7 @@ public partial class EntryListViewModel : RoutableScreen
|
||||
|
||||
try
|
||||
{
|
||||
IOperationResult<IGetEntriesv2Result> entries = await _workshopClient.GetEntriesv2.ExecuteAsync(search, filter, sort, entriesPerFetch, _currentPageInfo?.EndCursor, cancellationToken);
|
||||
IOperationResult<IGetEntriesResult> entries = await _workshopClient.GetEntries.ExecuteAsync(search, IncludeDefaultEntries, filter, sort, entriesPerFetch, _currentPageInfo?.EndCursor, cancellationToken);
|
||||
entries.EnsureNoErrors();
|
||||
|
||||
_currentPageInfo = entries.Data?.EntriesV2?.PageInfo;
|
||||
@ -124,7 +126,6 @@ public partial class EntryListViewModel : RoutableScreen
|
||||
And =
|
||||
[
|
||||
new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = EntryType}},
|
||||
new EntryFilterInput {DefaultEntryInfo = IncludeDefaultEntries ? new DefaultEntryInfoFilterInput {EntryId = new LongOperationFilterInput {Ngt = 0}} : null},
|
||||
..CategoriesViewModel.CategoryFilters ?? []
|
||||
]
|
||||
};
|
||||
|
||||
@ -51,7 +51,7 @@ public partial class WorkshopHomeViewModel : RoutableScreen
|
||||
p.AddRange(popularResult.Data.PopularEntries.Take(8));
|
||||
});
|
||||
|
||||
IOperationResult<IGetEntriesv2Result> latestResult = await client.GetEntriesv2.ExecuteAsync(null, null, [new EntrySortInput {CreatedAt = SortEnumType.Desc}], 8, null);
|
||||
IOperationResult<IGetEntriesResult> latestResult = await client.GetEntries.ExecuteAsync(null, null, null, [new EntrySortInput {CreatedAt = SortEnumType.Desc}], 8, null);
|
||||
latest.Edit(l =>
|
||||
{
|
||||
l.Clear();
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Artemis.UI.Screens.Workshop.Entries.List;
|
||||
using Artemis.UI.Screens.Workshop.LayoutFinder;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
@ -7,11 +8,10 @@ namespace Artemis.UI.Screens.Workshop.Layout;
|
||||
|
||||
public class LayoutListDefaultViewModel : RoutableScreen
|
||||
{
|
||||
public LayoutListDefaultViewModel(LayoutFinderViewModel layoutFinderViewModel, EntryListViewModel entryListViewModel)
|
||||
public LayoutListDefaultViewModel(LayoutFinderViewModel layoutFinderViewModel, Func<EntryType, EntryListViewModel> getEntryListViewModel)
|
||||
{
|
||||
LayoutFinderViewModel = layoutFinderViewModel;
|
||||
EntryListViewModel = entryListViewModel;
|
||||
EntryListViewModel.EntryType = EntryType.Layout;
|
||||
EntryListViewModel = getEntryListViewModel(EntryType.Layout);
|
||||
EntryListViewModel.ShowCategoryFilter = false;
|
||||
}
|
||||
|
||||
|
||||
@ -109,6 +109,7 @@ public partial class SubmissionDetailsViewModel : RoutableScreen
|
||||
specificationsViewModel.IsEssential = Entry.DefaultEntryInfo?.IsEssential ?? false;
|
||||
specificationsViewModel.IsDeviceProvider = Entry.DefaultEntryInfo?.IsDeviceProvider ?? false;
|
||||
specificationsViewModel.PreselectedCategories = Entry.Categories.Select(c => c.Id).ToList();
|
||||
specificationsViewModel.EntryType = Entry.EntryType;
|
||||
|
||||
specificationsViewModel.Tags.Clear();
|
||||
foreach (string tag in Entry.Tags.Select(c => c.Name))
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Artemis.UI.Screens.Workshop.Entries.List;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
using Artemis.WebClient.Workshop;
|
||||
@ -9,9 +10,8 @@ public class PluginListViewModel : RoutableHostScreen<RoutableScreen>
|
||||
private readonly EntryListViewModel _entryListViewModel;
|
||||
public override RoutableScreen DefaultScreen => _entryListViewModel;
|
||||
|
||||
public PluginListViewModel(EntryListViewModel entryListViewModel)
|
||||
public PluginListViewModel(Func<EntryType, EntryListViewModel> getEntryListViewModel)
|
||||
{
|
||||
_entryListViewModel = entryListViewModel;
|
||||
_entryListViewModel.EntryType = EntryType.Plugin;
|
||||
_entryListViewModel = getEntryListViewModel(EntryType.Plugin);
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Artemis.UI.Screens.Workshop.Entries.List;
|
||||
using Artemis.UI.Shared.Routing;
|
||||
using Artemis.WebClient.Workshop;
|
||||
@ -9,9 +10,8 @@ public class ProfileListViewModel : RoutableHostScreen<RoutableScreen>
|
||||
private readonly EntryListViewModel _entryListViewModel;
|
||||
public override RoutableScreen DefaultScreen => _entryListViewModel;
|
||||
|
||||
public ProfileListViewModel(EntryListViewModel entryListViewModel)
|
||||
public ProfileListViewModel(Func<EntryType, EntryListViewModel> getEntryListViewModel)
|
||||
{
|
||||
_entryListViewModel = entryListViewModel;
|
||||
_entryListViewModel.EntryType = EntryType.Profile;
|
||||
_entryListViewModel = getEntryListViewModel(EntryType.Profile);
|
||||
}
|
||||
}
|
||||
@ -75,6 +75,7 @@ public partial class SpecificationsStepViewModel : SubmissionViewModel
|
||||
|
||||
// Categories
|
||||
viewModel.PreselectedCategories = State.Categories;
|
||||
viewModel.EntryType = State.EntryType;
|
||||
|
||||
// Icon
|
||||
if (State.Icon != null)
|
||||
|
||||
@ -38,7 +38,7 @@ public partial class SubmitStepViewModel : SubmissionViewModel
|
||||
IconBitmap.DisposeWith(d);
|
||||
}
|
||||
|
||||
Observable.FromAsync(workshopClient.GetCategories.ExecuteAsync).Subscribe(PopulateCategories).DisposeWith(d);
|
||||
Observable.FromAsync(() => workshopClient.GetCategories.ExecuteAsync(State.EntryType)).Subscribe(PopulateCategories).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
query GetCategories {
|
||||
categories(order: {name: ASC}) {
|
||||
query GetCategories($entryType: EntryType) {
|
||||
categories(where: {entryType: {in: [$entryType, null]}} order: {name: ASC}) {
|
||||
id
|
||||
name
|
||||
icon
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
query GetEntriesv2($search: String $filter: EntryFilterInput $order: [EntrySortInput!] $first: Int $after: String) {
|
||||
entriesV2(search: $search where: $filter order: $order first: $first after: $after) {
|
||||
query GetEntries($search: String $includeDefaults: Boolean $filter: EntryFilterInput $order: [EntrySortInput!] $first: Int $after: String) {
|
||||
entriesV2(search: $search includeDefaults: $includeDefaults where: $filter order: $order first: $first after: $after) {
|
||||
totalCount
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
@ -22,6 +22,7 @@ query GetPopularEntries {
|
||||
|
||||
query GetDefaultEntries($first: Int, $after: String) {
|
||||
entriesV2(
|
||||
includeDefaults: true
|
||||
where: { defaultEntryInfo: { entryId: { gt: 0 } } }
|
||||
first: $first
|
||||
after: $after
|
||||
|
||||
@ -7,6 +7,7 @@ type Category {
|
||||
id: Long!
|
||||
name: String!
|
||||
icon: String!
|
||||
entryType: EntryType
|
||||
}
|
||||
|
||||
"Information about the offset pagination."
|
||||
@ -166,7 +167,7 @@ type Query {
|
||||
skip: Int
|
||||
take: Int
|
||||
search: String
|
||||
popular: Boolean
|
||||
includeDefaults: Boolean
|
||||
order: [EntrySortInput!] @cost(weight: "10")
|
||||
where: EntryFilterInput @cost(weight: "10")
|
||||
): EntriesCollectionSegment
|
||||
@ -180,7 +181,7 @@ type Query {
|
||||
@cost(weight: "10")
|
||||
entriesV2(
|
||||
search: String
|
||||
popular: Boolean
|
||||
includeDefaults: Boolean
|
||||
"Returns the first _n_ elements from the list."
|
||||
first: Int
|
||||
"Returns the elements in the list that come after the specified cursor."
|
||||
@ -273,12 +274,14 @@ input CategoryFilterInput {
|
||||
id: LongOperationFilterInput
|
||||
name: StringOperationFilterInput
|
||||
icon: StringOperationFilterInput
|
||||
entryType: NullableOfEntryTypeOperationFilterInput
|
||||
}
|
||||
|
||||
input CategorySortInput {
|
||||
id: SortEnumType @cost(weight: "10")
|
||||
name: SortEnumType @cost(weight: "10")
|
||||
icon: SortEnumType @cost(weight: "10")
|
||||
entryType: SortEnumType @cost(weight: "10")
|
||||
}
|
||||
|
||||
input CreateEntryInput {
|
||||
@ -509,6 +512,13 @@ input LongOperationFilterInput {
|
||||
nlte: Long @cost(weight: "10")
|
||||
}
|
||||
|
||||
input NullableOfEntryTypeOperationFilterInput {
|
||||
eq: EntryType @cost(weight: "10")
|
||||
neq: EntryType @cost(weight: "10")
|
||||
in: [EntryType] @cost(weight: "10")
|
||||
nin: [EntryType] @cost(weight: "10")
|
||||
}
|
||||
|
||||
input NullableOfKeyboardLayoutTypeOperationFilterInput {
|
||||
eq: KeyboardLayoutType @cost(weight: "10")
|
||||
neq: KeyboardLayoutType @cost(weight: "10")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user