From bde4e861c2705a377767bf80b2328d90f98faecb Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 11 Jun 2023 18:52:17 +0200 Subject: [PATCH 01/13] Initial workshop commit --- src/Artemis.UI/Artemis.UI.csproj | 1 + src/Artemis.UI/ArtemisBootstrapper.cs | 2 + .../Screens/Workshop/WorkshopView.axaml | 70 ++--- .../Screens/Workshop/WorkshopViewModel.cs | 78 +++--- src/Artemis.WebClient.Updating/.graphqlconfig | 15 -- .../Artemis.WebClient.Updating.csproj | 4 + .../graphql.config.yml | 8 + .../schema.extensions.graphql | 13 - src/Artemis.WebClient.Updating/schema.graphql | 29 ++- .../.config/dotnet-tools.json | 12 + .../.graphqlrc.json | 22 ++ .../Artemis.WebClient.Workshop.csproj | 20 ++ .../DryIoc/ContainerExtensions.cs | 26 ++ .../Queries/GetEntries.graphql | 9 + .../Queries/GetEntryById.graphql | 7 + .../graphql.config.yml | 8 + src/Artemis.WebClient.Workshop/schema.graphql | 244 ++++++++++++++++++ src/Artemis.sln | 6 + 18 files changed, 441 insertions(+), 133 deletions(-) delete mode 100644 src/Artemis.WebClient.Updating/.graphqlconfig create mode 100644 src/Artemis.WebClient.Updating/graphql.config.yml delete mode 100644 src/Artemis.WebClient.Updating/schema.extensions.graphql create mode 100644 src/Artemis.WebClient.Workshop/.config/dotnet-tools.json create mode 100644 src/Artemis.WebClient.Workshop/.graphqlrc.json create mode 100644 src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj create mode 100644 src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs create mode 100644 src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql create mode 100644 src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql create mode 100644 src/Artemis.WebClient.Workshop/graphql.config.yml create mode 100644 src/Artemis.WebClient.Workshop/schema.graphql diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index ce2eaaf18..f30f7879f 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Artemis.UI/ArtemisBootstrapper.cs b/src/Artemis.UI/ArtemisBootstrapper.cs index 52cab9df9..dbed7a0f4 100644 --- a/src/Artemis.UI/ArtemisBootstrapper.cs +++ b/src/Artemis.UI/ArtemisBootstrapper.cs @@ -12,6 +12,7 @@ using Artemis.UI.Shared.DryIoc; using Artemis.UI.Shared.Services; using Artemis.VisualScripting.DryIoc; using Artemis.WebClient.Updating.DryIoc; +using Artemis.WebClient.Workshop.DryIoc; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; @@ -45,6 +46,7 @@ public static class ArtemisBootstrapper _container.RegisterUI(); _container.RegisterSharedUI(); _container.RegisterUpdatingClient(); + _container.RegisterWorkshopClient(); _container.RegisterNoStringEvaluating(); configureServices?.Invoke(_container); diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml index 4cd4ef63f..485e308ca 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml +++ b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml @@ -10,62 +10,26 @@ xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared" xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker;assembly=Artemis.UI.Shared" xmlns:materialIconPicker="clr-namespace:Artemis.UI.Shared.MaterialIconPicker;assembly=Artemis.UI.Shared" + xmlns:workshop1="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop" mc:Ignorable="d" d:DesignWidth="800" x:Class="Artemis.UI.Screens.Workshop.WorkshopView" x:DataType="workshop:WorkshopViewModel"> - - - - - Notification tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs index 32df9585c..44fbb4226 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs @@ -1,70 +1,52 @@ -using System.Reactive; +using System; +using System.Collections.ObjectModel; +using System.Reactive; using System.Reactive.Linq; +using System.Threading.Tasks; using Artemis.Core; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; +using Artemis.WebClient.Workshop; using Avalonia.Input; using ReactiveUI; using SkiaSharp; +using StrawberryShake; namespace Artemis.UI.Screens.Workshop; public class WorkshopViewModel : MainScreenViewModel { - private readonly ObservableAsPropertyHelper _cursor; - private readonly INotificationService _notificationService; + private readonly IWorkshopClient _workshopClient; - private ColorGradient _colorGradient = new() + public WorkshopViewModel(IScreen hostScreen, IWorkshopClient workshopClient) : base(hostScreen, "workshop") { - new ColorGradientStop(new SKColor(0xFFFF6D00), 0f), - new ColorGradientStop(new SKColor(0xFFFE6806), 0.2f), - new ColorGradientStop(new SKColor(0xFFEF1788), 0.4f), - new ColorGradientStop(new SKColor(0xFFEF1788), 0.6f), - new ColorGradientStop(new SKColor(0xFF00FCCC), 0.8f), - new ColorGradientStop(new SKColor(0xFF00FCCC), 1f) - }; - - private StandardCursorType _selectedCursor; - private double _testValue; - - public WorkshopViewModel(IScreen hostScreen, INotificationService notificationService) : base(hostScreen, "workshop") - { - _notificationService = notificationService; - _cursor = this.WhenAnyValue(vm => vm.SelectedCursor).Select(c => new Cursor(c)).ToProperty(this, vm => vm.Cursor); - + _workshopClient = workshopClient; DisplayName = "Workshop"; - ShowNotification = ReactiveCommand.Create(ExecuteShowNotification); + + Task.Run(() => GetEntries()); } - public ReactiveCommand ShowNotification { get; set; } + public ObservableCollection Test { get; set; } = new(); - public StandardCursorType SelectedCursor + private async Task GetEntries() { - get => _selectedCursor; - set => RaiseAndSetIfChanged(ref _selectedCursor, value); - } - public Cursor Cursor => _cursor.Value; - - public ColorGradient ColorGradient - { - get => _colorGradient; - set => RaiseAndSetIfChanged(ref _colorGradient, value); - } - - public double TestValue - { - get => _testValue; - set => RaiseAndSetIfChanged(ref _testValue, value); - } - - public void CreateRandomGradient() - { - ColorGradient = ColorGradient.GetRandom(6); - } - - private void ExecuteShowNotification(NotificationSeverity severity) - { - _notificationService.CreateNotification().WithTitle("Test title").WithMessage("Test message").WithSeverity(severity).Show(); + try + { + IOperationResult entries = await _workshopClient.GetEntries.ExecuteAsync(); + if (entries.Data?.Entries?.Nodes == null) + return; + + foreach (IGetEntries_Entries_Nodes getEntriesEntriesNodes in entries.Data.Entries.Nodes) + { + Console.WriteLine(getEntriesEntriesNodes); + Test.Add(getEntriesEntriesNodes); + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } } } \ No newline at end of file diff --git a/src/Artemis.WebClient.Updating/.graphqlconfig b/src/Artemis.WebClient.Updating/.graphqlconfig deleted file mode 100644 index 727ec86a0..000000000 --- a/src/Artemis.WebClient.Updating/.graphqlconfig +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "Untitled GraphQL Schema", - "schemaPath": "schema.graphql", - "extensions": { - "endpoints": { - "Default GraphQL Endpoint": { - "url": "https://updating.artemis-rgb.com/graphql", - "headers": { - "user-agent": "JS GraphQL" - }, - "introspect": true - } - } - } -} \ No newline at end of file diff --git a/src/Artemis.WebClient.Updating/Artemis.WebClient.Updating.csproj b/src/Artemis.WebClient.Updating/Artemis.WebClient.Updating.csproj index c31da3c25..0b6943ddc 100644 --- a/src/Artemis.WebClient.Updating/Artemis.WebClient.Updating.csproj +++ b/src/Artemis.WebClient.Updating/Artemis.WebClient.Updating.csproj @@ -13,4 +13,8 @@ + + + + diff --git a/src/Artemis.WebClient.Updating/graphql.config.yml b/src/Artemis.WebClient.Updating/graphql.config.yml new file mode 100644 index 000000000..784e49e2e --- /dev/null +++ b/src/Artemis.WebClient.Updating/graphql.config.yml @@ -0,0 +1,8 @@ +schema: schema.graphql +extensions: + endpoints: + Default GraphQL Endpoint: + url: https://updating.artemis-rgb.com/graphql + headers: + user-agent: JS GraphQL + introspect: true diff --git a/src/Artemis.WebClient.Updating/schema.extensions.graphql b/src/Artemis.WebClient.Updating/schema.extensions.graphql deleted file mode 100644 index 0b5fbd98b..000000000 --- a/src/Artemis.WebClient.Updating/schema.extensions.graphql +++ /dev/null @@ -1,13 +0,0 @@ -scalar _KeyFieldSet - -directive @key(fields: _KeyFieldSet!) on SCHEMA | OBJECT - -directive @serializationType(name: String!) on SCALAR - -directive @runtimeType(name: String!) on SCALAR - -directive @enumValue(value: String!) on ENUM_VALUE - -directive @rename(name: String!) on INPUT_FIELD_DEFINITION | INPUT_OBJECT | ENUM | ENUM_VALUE - -extend schema @key(fields: "id") \ No newline at end of file diff --git a/src/Artemis.WebClient.Updating/schema.graphql b/src/Artemis.WebClient.Updating/schema.graphql index fe855cb6c..c0973062b 100644 --- a/src/Artemis.WebClient.Updating/schema.graphql +++ b/src/Artemis.WebClient.Updating/schema.graphql @@ -1,4 +1,4 @@ -# This file was generated based on ".graphqlconfig". Do not edit manually. +# This file was generated. Do not edit manually. schema { query: Query @@ -107,10 +107,11 @@ type Release { type ReleaseStatistic { count: Int! + date: Date! lastReportedUsage: DateTime! linuxCount: Int! osxCount: Int! - releaseId: UUID! + release: Release windowsCount: Int! } @@ -144,6 +145,9 @@ enum SortEnumType { DESC } +"The `Date` scalar represents an ISO-8601 compliant date type." +scalar Date + "The `DateTime` scalar represents an ISO-8601 compliant date time type." scalar DateTime @@ -176,6 +180,21 @@ input BooleanOperationFilterInput { neq: Boolean } +input DateOperationFilterInput { + eq: Date + gt: Date + gte: Date + in: [Date] + lt: Date + lte: Date + neq: Date + ngt: Date + ngte: Date + nin: [Date] + nlt: Date + nlte: Date +} + input DateTimeOperationFilterInput { eq: DateTime gt: DateTime @@ -265,20 +284,22 @@ input ReleaseSortInput { input ReleaseStatisticFilterInput { and: [ReleaseStatisticFilterInput!] count: IntOperationFilterInput + date: DateOperationFilterInput lastReportedUsage: DateTimeOperationFilterInput linuxCount: IntOperationFilterInput or: [ReleaseStatisticFilterInput!] osxCount: IntOperationFilterInput - releaseId: UuidOperationFilterInput + release: ReleaseFilterInput windowsCount: IntOperationFilterInput } input ReleaseStatisticSortInput { count: SortEnumType + date: SortEnumType lastReportedUsage: SortEnumType linuxCount: SortEnumType osxCount: SortEnumType - releaseId: SortEnumType + release: ReleaseSortInput windowsCount: SortEnumType } diff --git a/src/Artemis.WebClient.Workshop/.config/dotnet-tools.json b/src/Artemis.WebClient.Workshop/.config/dotnet-tools.json new file mode 100644 index 000000000..7d8626c03 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "strawberryshake.tools": { + "version": "13.0.0-rc.4", + "commands": [ + "dotnet-graphql" + ] + } + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/.graphqlrc.json b/src/Artemis.WebClient.Workshop/.graphqlrc.json new file mode 100644 index 000000000..24fb39de3 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/.graphqlrc.json @@ -0,0 +1,22 @@ +{ + "schema": "schema.graphql", + "documents": "**/*.graphql", + "extensions": { + "strawberryShake": { + "name": "WorkshopClient", + "namespace": "Artemis.WebClient.Workshop", + "url": "https://localhost:7281/graphql/", + "emitGeneratedCode": false, + "records": { + "inputs": false, + "entities": false + }, + "transportProfiles": [ + { + "default": "Http", + "subscription": "WebSocket" + } + ] + } + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj new file mode 100644 index 000000000..0b6943ddc --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj @@ -0,0 +1,20 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + + + diff --git a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs new file mode 100644 index 000000000..aed1df5a7 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs @@ -0,0 +1,26 @@ +using DryIoc; +using DryIoc.Microsoft.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; + +namespace Artemis.WebClient.Workshop.DryIoc; + +/// +/// Provides an extension method to register services onto a DryIoc . +/// +public static class ContainerExtensions +{ + /// + /// Registers the updating client into the container. + /// + /// The builder building the current container + public static void RegisterWorkshopClient(this IContainer container) + { + ServiceCollection serviceCollection = new(); + serviceCollection + .AddHttpClient() + .AddWorkshopClient() + .ConfigureHttpClient(client => client.BaseAddress = new Uri("https://localhost:7281/graphql")); + + container.WithDependencyInjectionAdapter(serviceCollection); + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql new file mode 100644 index 000000000..9d9457e62 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql @@ -0,0 +1,9 @@ +query GetEntries { + entries { + nodes { + author + name + entryType + } + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql new file mode 100644 index 000000000..e5ba4a96d --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql @@ -0,0 +1,7 @@ +query GetEntryById($id: UUID!) { + entry(id: $id) { + author + name + entryType + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/graphql.config.yml b/src/Artemis.WebClient.Workshop/graphql.config.yml new file mode 100644 index 000000000..a8ba99703 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/graphql.config.yml @@ -0,0 +1,8 @@ +schema: schema.graphql +extensions: + endpoints: + Default GraphQL Endpoint: + url: https://localhost:7281/graphql + headers: + user-agent: JS GraphQL + introspect: true diff --git a/src/Artemis.WebClient.Workshop/schema.graphql b/src/Artemis.WebClient.Workshop/schema.graphql new file mode 100644 index 000000000..daa53bde8 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/schema.graphql @@ -0,0 +1,244 @@ +# This file was generated. Do not edit manually. + +schema { + query: Query + mutation: Mutation +} + +"A connection to a list of items." +type EntriesConnection { + "A list of edges." + edges: [EntriesEdge!] + "A flattened list of the nodes." + nodes: [Entry!] + "Information to aid in pagination." + pageInfo: PageInfo! + "Identifies the total count of items in the connection." + totalCount: Int! +} + +"An edge in a connection." +type EntriesEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: Entry! +} + +type Entry { + author: UUID! + description: String! + entryType: EntryType! + icon: Image + id: UUID! + images: [Image!]! + name: String! + releases: [Release!]! + tags: [String!]! +} + +type Image { + id: UUID! + mimeType: String! +} + +type Mutation { + addEntry(input: EntryInput!): Entry +} + +"Information about pagination in a connection." +type PageInfo { + "When paginating forwards, the cursor to continue." + endCursor: String + "Indicates whether more edges exist following the set defined by the clients arguments." + hasNextPage: Boolean! + "Indicates whether more edges exist prior the set defined by the clients arguments." + hasPreviousPage: Boolean! + "When paginating backwards, the cursor to continue." + startCursor: String +} + +type Query { + entries( + "Returns the elements in the list that come after the specified cursor." + after: String, + "Returns the elements in the list that come before the specified cursor." + before: String, + "Returns the first _n_ elements from the list." + first: Int, + "Returns the last _n_ elements from the list." + last: Int, + order: [EntrySortInput!], + where: EntryFilterInput + ): EntriesConnection + entry(id: UUID!): Entry +} + +type Release { + createdAt: DateTime! + downloadSize: Long! + downloads: Long! + id: UUID! + md5Hash: String + version: String! +} + +enum EntryType { + LAYOUT + PLUGIN + PROFILE +} + +enum SortEnumType { + ASC + DESC +} + +"The `DateTime` scalar represents an ISO-8601 compliant date time type." +scalar DateTime + +"The `Long` scalar type represents non-fractional signed whole 64-bit numeric values. Long can represent values between -(2^63) and 2^63 - 1." +scalar Long + +scalar UUID + +input DateTimeOperationFilterInput { + eq: DateTime + gt: DateTime + gte: DateTime + in: [DateTime] + lt: DateTime + lte: DateTime + neq: DateTime + ngt: DateTime + ngte: DateTime + nin: [DateTime] + nlt: DateTime + nlte: DateTime +} + +input EntryFilterInput { + and: [EntryFilterInput!] + author: UuidOperationFilterInput + description: StringOperationFilterInput + entryType: EntryTypeOperationFilterInput + icon: ImageFilterInput + id: UuidOperationFilterInput + images: ListFilterInputTypeOfImageFilterInput + name: StringOperationFilterInput + or: [EntryFilterInput!] + releases: ListFilterInputTypeOfReleaseFilterInput + tags: ListStringOperationFilterInput +} + +input EntryInput { + description: String! + entryType: EntryType! + name: String! + tags: [String!]! +} + +input EntrySortInput { + author: SortEnumType + description: SortEnumType + entryType: SortEnumType + icon: ImageSortInput + id: SortEnumType + name: SortEnumType +} + +input EntryTypeOperationFilterInput { + eq: EntryType + in: [EntryType!] + neq: EntryType + nin: [EntryType!] +} + +input ImageFilterInput { + and: [ImageFilterInput!] + id: UuidOperationFilterInput + mimeType: StringOperationFilterInput + or: [ImageFilterInput!] +} + +input ImageSortInput { + id: SortEnumType + mimeType: SortEnumType +} + +input ListFilterInputTypeOfImageFilterInput { + all: ImageFilterInput + any: Boolean + none: ImageFilterInput + some: ImageFilterInput +} + +input ListFilterInputTypeOfReleaseFilterInput { + all: ReleaseFilterInput + any: Boolean + none: ReleaseFilterInput + some: ReleaseFilterInput +} + +input ListStringOperationFilterInput { + all: StringOperationFilterInput + any: Boolean + none: StringOperationFilterInput + some: StringOperationFilterInput +} + +input LongOperationFilterInput { + eq: Long + gt: Long + gte: Long + in: [Long] + lt: Long + lte: Long + neq: Long + ngt: Long + ngte: Long + nin: [Long] + nlt: Long + nlte: Long +} + +input ReleaseFilterInput { + and: [ReleaseFilterInput!] + createdAt: DateTimeOperationFilterInput + downloadSize: LongOperationFilterInput + downloads: LongOperationFilterInput + id: UuidOperationFilterInput + md5Hash: StringOperationFilterInput + or: [ReleaseFilterInput!] + version: StringOperationFilterInput +} + +input StringOperationFilterInput { + and: [StringOperationFilterInput!] + contains: String + endsWith: String + eq: String + in: [String] + ncontains: String + nendsWith: String + neq: String + nin: [String] + nstartsWith: String + or: [StringOperationFilterInput!] + startsWith: String +} + +input UuidOperationFilterInput { + eq: UUID + gt: UUID + gte: UUID + in: [UUID] + lt: UUID + lte: UUID + neq: UUID + ngt: UUID + ngte: UUID + nin: [UUID] + nlt: UUID + nlte: UUID +} diff --git a/src/Artemis.sln b/src/Artemis.sln index 2e53b5d9a..8c5b6ee51 100644 --- a/src/Artemis.sln +++ b/src/Artemis.sln @@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.VisualScripting", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.WebClient.Updating", "Artemis.WebClient.Updating\Artemis.WebClient.Updating.csproj", "{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.WebClient.Workshop", "Artemis.WebClient.Workshop\Artemis.WebClient.Workshop.csproj", "{2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -63,6 +65,10 @@ Global {7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Debug|x64.Build.0 = Debug|Any CPU {7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Release|x64.ActiveCfg = Release|Any CPU {7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Release|x64.Build.0 = Release|Any CPU + {2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}.Debug|x64.ActiveCfg = Debug|Any CPU + {2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}.Debug|x64.Build.0 = Debug|Any CPU + {2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}.Release|x64.ActiveCfg = Release|Any CPU + {2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 4224875fb07fe994baddcadb4c6c6126b8e85f9b Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 22 Jun 2023 22:56:24 +0200 Subject: [PATCH 02/13] Added basic login --- .../Assets/Images/avatar-placeholder.png | Bin 0 -> 216568 bytes .../Screens/Settings/Tabs/AboutTabView.axaml | 4 +- .../CurrentUser/CurrentUserView.axaml | 59 +++++ .../CurrentUser/CurrentUserView.axaml.cs | 21 ++ .../CurrentUser/CurrentUserViewModel.cs | 104 ++++++++ .../Screens/Workshop/WorkshopView.axaml | 1 + .../Screens/Workshop/WorkshopViewModel.cs | 7 +- .../Artemis.WebClient.Workshop.csproj | 5 + .../DryIoc/ContainerExtensions.cs | 14 +- .../Entities/RefreshTokenEntity.cs | 7 + .../Exceptions/ArtemisWebClientException.cs | 24 ++ .../Repositories/AuthenticationRepository.cs | 36 +++ .../Services/AccessToken.cs | 25 ++ .../Services/IAuthenticationService.cs | 222 ++++++++++++++++++ 14 files changed, 524 insertions(+), 5 deletions(-) create mode 100644 src/Artemis.UI/Assets/Images/avatar-placeholder.png create mode 100644 src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs create mode 100644 src/Artemis.WebClient.Workshop/Entities/RefreshTokenEntity.cs create mode 100644 src/Artemis.WebClient.Workshop/Exceptions/ArtemisWebClientException.cs create mode 100644 src/Artemis.WebClient.Workshop/Repositories/AuthenticationRepository.cs create mode 100644 src/Artemis.WebClient.Workshop/Services/AccessToken.cs create mode 100644 src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs diff --git a/src/Artemis.UI/Assets/Images/avatar-placeholder.png b/src/Artemis.UI/Assets/Images/avatar-placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..e7bdbefd2fb2b16ba52802312f822a1b69d587f4 GIT binary patch literal 216568 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 M07*qoM6N<$g6k=5NdN!< literal 0 HcmV?d00001 diff --git a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml index 6d21dc30e..5f7a0ebfe 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml @@ -56,8 +56,8 @@ Grid.Column="0" Grid.RowSpan="3" VerticalAlignment="Top" - Height="75" - Width="75" + Height="40" + Width="40" Margin="0 0 15 0" IsVisible="{CompiledBinding RobertProfileImage, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" RenderOptions.BitmapInterpolationMode="HighQuality"> diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml new file mode 100644 index 000000000..57a245c81 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sign out + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml.cs b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml.cs new file mode 100644 index 000000000..b690eb8dc --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml.cs @@ -0,0 +1,21 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.CurrentUser; + +public partial class CurrentUserView : ReactiveUserControl +{ + public CurrentUserView() + { + InitializeComponent(); + } + + private void Button_OnClick(object? sender, RoutedEventArgs e) + { + UserMenu.ContextFlyout?.Hide(); + ViewModel?.Logout(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs new file mode 100644 index 000000000..3d0121043 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs @@ -0,0 +1,104 @@ +using System; +using System.Linq; +using System.Reactive; +using System.Reactive.Disposables; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Shared; +using Artemis.WebClient.Workshop.Services; +using Avalonia.Media.Imaging; +using Flurl.Http; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.CurrentUser; + +public class CurrentUserViewModel : ActivatableViewModelBase +{ + private readonly IAuthenticationService _authenticationService; + private ObservableAsPropertyHelper? _isLoggedIn; + + private string? _userId; + private string? _name; + private string? _email; + private Bitmap? _avatar; + + public CurrentUserViewModel(IAuthenticationService authenticationService) + { + _authenticationService = authenticationService; + Login = ReactiveCommand.CreateFromTask(ExecuteLogin); + + this.WhenActivated(d => _isLoggedIn = _authenticationService.WhenAnyValue(s => s.IsLoggedIn).ToProperty(this, vm => vm.IsLoggedIn).DisposeWith(d)); + this.WhenActivated(d => + { + Task.Run(async () => + { + await _authenticationService.AutoLogin(); + await LoadCurrentUser(); + }).DisposeWith(d); + }); + } + + public void Logout() + { + _authenticationService.Logout(); + } + + public string? UserId + { + get => _userId; + set => RaiseAndSetIfChanged(ref _userId, value); + } + + public string? Name + { + get => _name; + set => RaiseAndSetIfChanged(ref _name, value); + } + + public string? Email + { + get => _email; + set => RaiseAndSetIfChanged(ref _email, value); + } + + public Bitmap? Avatar + { + get => _avatar; + set => RaiseAndSetIfChanged(ref _avatar, value); + } + + public ReactiveCommand Login { get; } + public bool IsLoggedIn => _isLoggedIn?.Value ?? false; + + private async Task ExecuteLogin(CancellationToken cancellationToken) + { + await _authenticationService.Login(); + await LoadCurrentUser(); + Console.WriteLine(_authenticationService.Claims); + } + + private async Task LoadCurrentUser() + { + if (!IsLoggedIn) + return; + + UserId = _authenticationService.Claims.FirstOrDefault(c => c.Type == "sub")?.Value; + Name = _authenticationService.Claims.FirstOrDefault(c => c.Type == "name")?.Value; + Email = _authenticationService.Claims.FirstOrDefault(c => c.Type == "email")?.Value; + + if (UserId != null) + await LoadAvatar(UserId); + } + + private async Task LoadAvatar(string userId) + { + try + { + Avatar = new Bitmap(await $"{IAuthenticationService.AUTHORITY}/user/avatar/{userId}".GetStreamAsync()); + } + catch (Exception) + { + // ignored + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml index 485e308ca..e303305de 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml +++ b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml @@ -30,6 +30,7 @@ + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs index 44fbb4226..06be34781 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs @@ -4,6 +4,7 @@ using System.Reactive; using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; +using Artemis.UI.Screens.Workshop.CurrentUser; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Artemis.WebClient.Workshop; @@ -18,8 +19,9 @@ public class WorkshopViewModel : MainScreenViewModel { private readonly IWorkshopClient _workshopClient; - public WorkshopViewModel(IScreen hostScreen, IWorkshopClient workshopClient) : base(hostScreen, "workshop") + public WorkshopViewModel(IScreen hostScreen, IWorkshopClient workshopClient, CurrentUserViewModel currentUserViewModel) : base(hostScreen, "workshop") { + CurrentUserViewModel = currentUserViewModel; _workshopClient = workshopClient; DisplayName = "Workshop"; @@ -27,7 +29,8 @@ public class WorkshopViewModel : MainScreenViewModel } public ObservableCollection Test { get; set; } = new(); - + public CurrentUserViewModel CurrentUserViewModel { get; set; } + private async Task GetEntries() { diff --git a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj index 0b6943ddc..ecacce222 100644 --- a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj +++ b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj @@ -9,6 +9,7 @@ + @@ -17,4 +18,8 @@ + + + + diff --git a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs index aed1df5a7..1988fa300 100644 --- a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs @@ -1,5 +1,8 @@ +using Artemis.WebClient.Workshop.Repositories; +using Artemis.WebClient.Workshop.Services; using DryIoc; using DryIoc.Microsoft.DependencyInjection; +using IdentityModel.Client; using Microsoft.Extensions.DependencyInjection; namespace Artemis.WebClient.Workshop.DryIoc; @@ -20,7 +23,16 @@ public static class ContainerExtensions .AddHttpClient() .AddWorkshopClient() .ConfigureHttpClient(client => client.BaseAddress = new Uri("https://localhost:7281/graphql")); - + + serviceCollection.AddSingleton(r => + { + IHttpClientFactory factory = r.GetRequiredService(); + return new DiscoveryCache(IAuthenticationService.AUTHORITY, () => factory.CreateClient()); + }); + container.WithDependencyInjectionAdapter(serviceCollection); + + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); } } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Entities/RefreshTokenEntity.cs b/src/Artemis.WebClient.Workshop/Entities/RefreshTokenEntity.cs new file mode 100644 index 000000000..1abbdfe22 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Entities/RefreshTokenEntity.cs @@ -0,0 +1,7 @@ +namespace Artemis.WebClient.Workshop.Entities; + +public class RefreshTokenEntity +{ + public string RefreshToken { get; set; } + +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWebClientException.cs b/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWebClientException.cs new file mode 100644 index 000000000..1bd2af386 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Exceptions/ArtemisWebClientException.cs @@ -0,0 +1,24 @@ +using System; + +namespace Artemis.Core; + +///

+/// An exception thrown when a web client related error occurs +/// +public class ArtemisWebClientException : Exception +{ + /// + public ArtemisWebClientException() + { + } + + /// + public ArtemisWebClientException(string? message) : base(message) + { + } + + /// + public ArtemisWebClientException(string? message, Exception? innerException) : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Repositories/AuthenticationRepository.cs b/src/Artemis.WebClient.Workshop/Repositories/AuthenticationRepository.cs new file mode 100644 index 000000000..9a3021c1f --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Repositories/AuthenticationRepository.cs @@ -0,0 +1,36 @@ +using Artemis.WebClient.Workshop.Entities; +using LiteDB; + +namespace Artemis.WebClient.Workshop.Repositories; + +internal class AuthenticationRepository : IAuthenticationRepository +{ + private readonly LiteRepository _repository; + + public AuthenticationRepository(LiteRepository repository) + { + _repository = repository; + _repository.Database.GetCollection().EnsureIndex(s => s.RefreshToken); + } + + /// + public void SetRefreshToken(string? refreshToken) + { + _repository.Database.GetCollection().DeleteAll(); + + if (refreshToken != null) + _repository.Insert(new RefreshTokenEntity {RefreshToken = refreshToken}); + } + + /// + public string? GetRefreshToken() + { + return _repository.Query().FirstOrDefault()?.RefreshToken; + } +} + +internal interface IAuthenticationRepository +{ + void SetRefreshToken(string? refreshToken); + string? GetRefreshToken(); +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/AccessToken.cs b/src/Artemis.WebClient.Workshop/Services/AccessToken.cs new file mode 100644 index 000000000..f67dd9395 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/AccessToken.cs @@ -0,0 +1,25 @@ +using Artemis.Core; +using IdentityModel.Client; + +namespace Artemis.WebClient.Workshop.Services; + +internal class AuthenticationToken +{ + public AuthenticationToken(TokenResponse tokenResponse) + { + if (tokenResponse.AccessToken == null) + throw new ArtemisWebClientException("Token response contains no access token"); + if (tokenResponse.RefreshToken == null) + throw new ArtemisWebClientException("Token response contains no refresh token"); + + AccessToken = tokenResponse.AccessToken; + RefreshToken = tokenResponse.RefreshToken; + ExpiresAt = DateTimeOffset.UtcNow.AddSeconds(tokenResponse.ExpiresIn); + } + + public DateTimeOffset ExpiresAt { get; private set; } + public bool Expired => DateTimeOffset.UtcNow.AddSeconds(5) >= ExpiresAt; + + public string AccessToken { get; private set; } + public string RefreshToken { get; private set; } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs b/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs new file mode 100644 index 000000000..c3c112451 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs @@ -0,0 +1,222 @@ +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Security.Claims; +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.WebClient.Workshop.Repositories; +using IdentityModel; +using IdentityModel.Client; + +namespace Artemis.WebClient.Workshop.Services; + +public interface IAuthenticationService : IProtectedArtemisService +{ + public const string AUTHORITY = "https://localhost:5001"; + + bool IsLoggedIn { get; } + string? UserCode { get; } + ReadOnlyObservableCollection Claims { get; } + + Task GetBearer(); + Task AutoLogin(); + Task Login(); + void Logout(); +} + +internal class AuthenticationService : CorePropertyChanged, IAuthenticationService +{ + internal const string CLIENT_ID = "artemis.desktop"; + + private readonly IDiscoveryCache _discoveryCache; + private readonly IAuthenticationRepository _authenticationRepository; + private readonly IHttpClientFactory _httpClientFactory; + private readonly ObservableCollection _claims = new(); + private readonly SemaphoreSlim _bearerLock = new(1); + + private AuthenticationToken? _token; + private string? _userCode; + private bool _isLoggedIn; + + public AuthenticationService(IHttpClientFactory httpClientFactory, IDiscoveryCache discoveryCache, IAuthenticationRepository authenticationRepository) + { + _httpClientFactory = httpClientFactory; + _discoveryCache = discoveryCache; + _authenticationRepository = authenticationRepository; + + Claims = new ReadOnlyObservableCollection(_claims); + } + + /// + public bool IsLoggedIn + { + get => _isLoggedIn; + private set => SetAndNotify(ref _isLoggedIn, value); + } + + /// + public string? UserCode + { + get => _userCode; + private set => SetAndNotify(ref _userCode, value); + } + + /// + public ReadOnlyObservableCollection Claims { get; } + + public async Task GetBearer() + { + await _bearerLock.WaitAsync(); + + try + { + // If not logged in, attempt to auto login first + if (!IsLoggedIn) + await AutoLogin(); + + if (_token == null) + return null; + + // If the token is expiring, refresh it + if (_token.Expired && !await UseRefreshToken(_token.RefreshToken)) + return null; + + return _token.AccessToken; + } + finally + { + _bearerLock.Release(); + } + } + + /// + public async Task AutoLogin() + { + if (IsLoggedIn) + return true; + + string? refreshToken = _authenticationRepository.GetRefreshToken(); + if (refreshToken == null) + return false; + + return await UseRefreshToken(refreshToken); + } + + /// + public async Task Login() + { + DiscoveryDocumentResponse disco = await GetDiscovery(); + HttpClient client = _httpClientFactory.CreateClient(); + DeviceAuthorizationResponse response = await client.RequestDeviceAuthorizationAsync(new DeviceAuthorizationRequest + { + Address = disco.DeviceAuthorizationEndpoint, + ClientId = CLIENT_ID + }); + if (response.IsError) + throw new ArtemisWebClientException("Failed to request device authorization: " + response.Error); + if (response.DeviceCode == null) + throw new ArtemisWebClientException("Failed to request device authorization: Got no device code"); + + DateTimeOffset timeout = DateTimeOffset.UtcNow.AddSeconds(response.ExpiresIn ?? 1800); + + Process.Start(new ProcessStartInfo {FileName = response.VerificationUriComplete, UseShellExecute = true}); + await Task.Delay(TimeSpan.FromSeconds(response.Interval)); + while (DateTimeOffset.UtcNow < timeout) + { + bool success = await AttemptRequestDeviceToken(client, response.DeviceCode); + if (success) + return true; + await Task.Delay(TimeSpan.FromSeconds(response.Interval)); + } + + return false; + } + + /// + public void Logout() + { + _token = null; + _claims.Clear(); + _authenticationRepository.SetRefreshToken(null); + + IsLoggedIn = false; + } + + private async Task GetDiscovery() + { + DiscoveryDocumentResponse disco = await _discoveryCache.GetAsync(); + if (disco.IsError) + throw new ArtemisWebClientException("Failed to retrieve discovery document: " + disco.Error); + + return disco; + } + + private async Task AttemptRequestDeviceToken(HttpClient client, string deviceCode) + { + DiscoveryDocumentResponse disco = await GetDiscovery(); + TokenResponse response = await client.RequestDeviceTokenAsync(new DeviceTokenRequest + { + Address = disco.TokenEndpoint, + ClientId = CLIENT_ID, + DeviceCode = deviceCode + }); + + if (response.IsError) + { + if (response.Error == OidcConstants.TokenErrors.AuthorizationPending || response.Error == OidcConstants.TokenErrors.SlowDown) + return false; + + throw new ArtemisWebClientException("Failed to request device token: " + response.Error); + } + + await SetCurrentUser(client, response); + return true; + } + + private async Task SetCurrentUser(HttpClient client, TokenResponse response) + { + _token = new AuthenticationToken(response); + _authenticationRepository.SetRefreshToken(_token.RefreshToken); + + await GetUserInfo(client, _token.AccessToken); + IsLoggedIn = true; + } + + private async Task GetUserInfo(HttpClient client, string accessToken) + { + DiscoveryDocumentResponse disco = await GetDiscovery(); + UserInfoResponse response = await client.GetUserInfoAsync(new UserInfoRequest() + { + Address = disco.UserInfoEndpoint, + Token = accessToken + }); + if (response.IsError) + throw new ArtemisWebClientException("Failed to retrieve user info: " + response.Error); + + _claims.Clear(); + foreach (Claim responseClaim in response.Claims) + _claims.Add(responseClaim); + } + + private async Task UseRefreshToken(string refreshToken) + { + DiscoveryDocumentResponse disco = await GetDiscovery(); + HttpClient client = _httpClientFactory.CreateClient(); + TokenResponse response = await client.RequestRefreshTokenAsync(new RefreshTokenRequest() + { + Address = disco.TokenEndpoint, + ClientId = CLIENT_ID, + RefreshToken = refreshToken + }); + + if (response.IsError) + { + if (response.Error == OidcConstants.TokenErrors.ExpiredToken) + return false; + + throw new ArtemisWebClientException("Failed to request refresh token: " + response.Error); + } + + await SetCurrentUser(client, response); + return false; + } +} \ No newline at end of file From 99a365be0b867c348d59141f7a539fccf0bc733b Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 7 Jul 2023 22:55:02 +0200 Subject: [PATCH 03/13] Sidebar - Added subitems support --- .../Routable/RoutableScreenOfTScreen.cs | 10 +- .../ParameterParsers/IntParameterParser.cs | 17 +++ .../Routing/Route/RouteResolution.cs | 1 - .../Routing/Route/RouteSegment.cs | 9 +- src/Artemis.UI.Shared/Styles/Sidebar.axaml | 12 +- src/Artemis.UI/Artemis.UI.csproj | 12 ++ src/Artemis.UI/DryIoc/Factories/IVMFactory.cs | 5 +- src/Artemis.UI/Routing/Routes.cs | 11 +- .../Screens/Sidebar/SidebarCategoryView.axaml | 1 - .../SidebarProfileConfigurationView.axaml | 4 +- .../Screens/Sidebar/SidebarScreenView.axaml | 10 +- .../Sidebar/SidebarScreenView.axaml.cs | 14 +- .../Screens/Sidebar/SidebarScreenViewModel.cs | 52 +++++++- .../Screens/Sidebar/SidebarView.axaml | 104 ++++++++------- .../Screens/Sidebar/SidebarViewModel.cs | 45 ++++--- .../Workshop/Layout/LayoutDetailsView.axaml | 21 +++ .../Layout/LayoutDetailsView.axaml.cs | 17 +++ .../Workshop/Layout/LayoutDetailsViewModel.cs | 8 ++ .../Workshop/Layout/LayoutListView.axaml | 22 ++++ .../Workshop/Layout/LayoutListView.axaml.cs | 17 +++ .../Workshop/Layout/LayoutListViewModel.cs | 26 ++++ .../Workshop/Profile/ProfileDetailsView.axaml | 8 ++ .../Profile/ProfileDetailsView.axaml.cs | 17 +++ .../Profile/ProfileDetailsViewModel.cs | 8 ++ .../Workshop/Profile/ProfileListView.axaml | 22 ++++ .../Workshop/Profile/ProfileListView.axaml.cs | 17 +++ .../Workshop/Profile/ProfileListViewModel.cs | 26 ++++ .../Workshop/WorkshopListParameters.cs | 6 + .../Screens/Workshop/WorkshopView.axaml | 28 +--- .../Screens/Workshop/WorkshopView.axaml.cs | 2 - .../Screens/Workshop/WorkshopViewModel.cs | 52 +------- src/Artemis.UI/Styles/Artemis.axaml | 8 ++ src/Artemis.UI/Styles/TreeView.axaml | 122 ++++++++++++++++++ 33 files changed, 572 insertions(+), 162 deletions(-) create mode 100644 src/Artemis.UI.Shared/Routing/Route/ParameterParsers/IntParameterParser.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs create mode 100644 src/Artemis.UI/Screens/Workshop/WorkshopListParameters.cs create mode 100644 src/Artemis.UI/Styles/TreeView.axaml diff --git a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreen.cs b/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreen.cs index 00c48b111..b4f60ca47 100644 --- a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreen.cs +++ b/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreen.cs @@ -62,7 +62,15 @@ public abstract class RoutableScreen : ActivatableViewModelBase, IRouta void IRoutableScreen.InternalChangeScreen(object? screen) { - Screen = screen as TScreen; + if (screen == null) + { + Screen = null; + return; + } + + if (screen is not TScreen typedScreen) + throw new ArtemisRoutingException($"Screen cannot be hosted, {screen.GetType().Name} is not assignable to {typeof(TScreen).Name}."); + Screen = typedScreen; } async Task IRoutableScreen.InternalOnNavigating(NavigationArguments args, CancellationToken cancellationToken) diff --git a/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/IntParameterParser.cs b/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/IntParameterParser.cs new file mode 100644 index 000000000..38a3a9c46 --- /dev/null +++ b/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/IntParameterParser.cs @@ -0,0 +1,17 @@ + +namespace Artemis.UI.Shared.Routing.ParameterParsers; + +internal class IntParameterParser : IRouteParameterParser +{ + /// + public bool IsMatch(RouteSegment segment, string source) + { + return int.TryParse(source, out _); + } + + /// + public object GetValue(RouteSegment segment, string source) + { + return int.Parse(source); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Route/RouteResolution.cs b/src/Artemis.UI.Shared/Routing/Route/RouteResolution.cs index 545d85fa6..32d285ccd 100644 --- a/src/Artemis.UI.Shared/Routing/Route/RouteResolution.cs +++ b/src/Artemis.UI.Shared/Routing/Route/RouteResolution.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using DryIoc; namespace Artemis.UI.Shared.Routing; diff --git a/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs b/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs index 5668c6fb4..77025b389 100644 --- a/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs +++ b/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs @@ -48,11 +48,14 @@ public partial class RouteSegment private IRouteParameterParser GetParameterParser(string parameterType) { - if (parameterType == "guid") - return new GuidParameterParser(); + return parameterType switch + { + "guid" => new GuidParameterParser(), + "int" => new IntParameterParser(), + _ => new StringParameterParser() + }; // Default to a string parser which just returns the segment as is - return new StringParameterParser(); } [GeneratedRegex(@"\{(\w+):(\w+)\}")] diff --git a/src/Artemis.UI.Shared/Styles/Sidebar.axaml b/src/Artemis.UI.Shared/Styles/Sidebar.axaml index 95359910d..605ba8e40 100644 --- a/src/Artemis.UI.Shared/Styles/Sidebar.axaml +++ b/src/Artemis.UI.Shared/Styles/Sidebar.axaml @@ -13,9 +13,15 @@ - --> + + \ No newline at end of file diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 0dd2f9d09..ecd1c4c9f 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -43,4 +43,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs b/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs index e9c315f05..98fb7ea4e 100644 --- a/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs +++ b/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Reactive; using Artemis.Core; @@ -30,6 +31,8 @@ using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Updating; using DryIoc; +using DynamicData; +using Material.Icons; using ReactiveUI; namespace Artemis.UI.DryIoc.Factories; @@ -137,7 +140,7 @@ public class SidebarVmFactory : ISidebarVmFactory { _container = container; } - + public SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory) { return _container.Resolve(new object[] { profileCategory }); diff --git a/src/Artemis.UI/Routing/Routes.cs b/src/Artemis.UI/Routing/Routes.cs index af90f3b25..5aec9d1ec 100644 --- a/src/Artemis.UI/Routing/Routes.cs +++ b/src/Artemis.UI/Routing/Routes.cs @@ -5,6 +5,8 @@ using Artemis.UI.Screens.Settings; using Artemis.UI.Screens.Settings.Updating; using Artemis.UI.Screens.SurfaceEditor; using Artemis.UI.Screens.Workshop; +using Artemis.UI.Screens.Workshop.Layout; +using Artemis.UI.Screens.Workshop.Profile; using Artemis.UI.Shared.Routing; namespace Artemis.UI.Routing; @@ -14,8 +16,15 @@ public static class Routes public static List ArtemisRoutes = new() { new RouteRegistration("home"), + new RouteRegistration("workshop"), + new RouteRegistration("workshop/profiles/{page:int}"), + new RouteRegistration("workshop/profiles/{entryId:guid}"), + new RouteRegistration("workshop/layouts/{page:int}"), + new RouteRegistration("workshop/layouts/{entryId:guid}"), + new RouteRegistration("surface-editor"), + new RouteRegistration("settings") { Children = new List @@ -25,7 +34,7 @@ public static class Routes new RouteRegistration("devices"), new RouteRegistration("releases") { - Children = new List() + Children = new List { new RouteRegistration("{releaseId:guid}") } diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml index 25f43bbf2..b71403e6c 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml +++ b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml @@ -99,7 +99,6 @@ + + + + + + + + @@ -41,51 +53,51 @@ - + - - + + - - + + - - + + - - + + - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs index 17c0e0590..3e666815b 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive; @@ -23,34 +24,38 @@ namespace Artemis.UI.Screens.Sidebar; public class SidebarViewModel : ActivatableViewModelBase { + public const string ROOT_SCREEN = "root"; + private readonly IRouter _router; private readonly IWindowService _windowService; - private SidebarScreenViewModel? _selectedSidebarScreen; private ReadOnlyObservableCollection _sidebarCategories = new(new ObservableCollection()); + private SidebarScreenViewModel? _selectedScreen; public SidebarViewModel(IRouter router, IProfileService profileService, IWindowService windowService, ISidebarVmFactory sidebarVmFactory) { _router = router; _windowService = windowService; - SidebarScreens = new ObservableCollection + SidebarScreen = new SidebarScreenViewModel(MaterialIconKind.Abacus, ROOT_SCREEN, "", null, new ObservableCollection() { - new(MaterialIconKind.Home, "Home", "home"), -#if DEBUG - new(MaterialIconKind.TestTube, "Workshop", "workshop"), -#endif + new(MaterialIconKind.HomeOutline, "Home", "home"), + new(MaterialIconKind.TestTube, "Workshop", "workshop", null, new ObservableCollection + { + new(MaterialIconKind.FolderVideo, "Profiles", "workshop/profiles/1", "workshop/profiles"), + new(MaterialIconKind.KeyboardVariant, "Layouts", "workshop/layouts/1", "workshop/layouts"), + }), new(MaterialIconKind.Devices, "Surface Editor", "surface-editor"), - new(MaterialIconKind.Cog, "Settings", "settings") - }; + new(MaterialIconKind.SettingsOutline, "Settings", "settings") + }); AddCategory = ReactiveCommand.CreateFromTask(ExecuteAddCategory); + this.WhenAnyValue(vm => vm.SelectedScreen).WhereNotNull().Subscribe(NavigateToScreen); + this.WhenAnyValue(vm => vm.SelectedScreen).WhereNotNull().Subscribe(s => SidebarScreen.ExpandIfRequired(s)); SourceList profileCategories = new(); - - this.WhenAnyValue(vm => vm.SelectedSidebarScreen).WhereNotNull().Subscribe(NavigateToScreen); this.WhenActivated(d => { - _router.CurrentPath.WhereNotNull().Subscribe(r => SelectedSidebarScreen = SidebarScreens.FirstOrDefault(s => s.Matches(r))).DisposeWith(d); + _router.CurrentPath.WhereNotNull().Subscribe(r => SelectedScreen = SidebarScreen.GetMatch(r)).DisposeWith(d); Observable.FromEventPattern(x => profileService.ProfileCategoryAdded += x, x => profileService.ProfileCategoryAdded -= x) .Subscribe(e => profileCategories.Add(e.EventArgs.ProfileCategory)) @@ -75,11 +80,17 @@ public class SidebarViewModel : ActivatableViewModelBase .DisposeWith(d); SidebarCategories = categoryViewModels; - SelectedSidebarScreen = SidebarScreens.First(); }); + SelectedScreen = SidebarScreen.Screens.First(); } - public ObservableCollection SidebarScreens { get; } + public SidebarScreenViewModel SidebarScreen { get; } + + public SidebarScreenViewModel? SelectedScreen + { + get => _selectedScreen; + set => RaiseAndSetIfChanged(ref _selectedScreen, value); + } public ReadOnlyObservableCollection SidebarCategories { @@ -87,12 +98,6 @@ public class SidebarViewModel : ActivatableViewModelBase set => RaiseAndSetIfChanged(ref _sidebarCategories, value); } - public SidebarScreenViewModel? SelectedSidebarScreen - { - get => _selectedSidebarScreen; - set => RaiseAndSetIfChanged(ref _selectedSidebarScreen, value); - } - public ReactiveCommand AddCategory { get; } private async Task ExecuteAddCategory() @@ -112,7 +117,7 @@ public class SidebarViewModel : ActivatableViewModelBase { try { - await _router.Navigate(sidebarScreenViewModel.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true}); + await _router.Navigate(sidebarScreenViewModel.Path); } catch (Exception e) { diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml new file mode 100644 index 000000000..90e0f2b0f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml @@ -0,0 +1,21 @@ + + + + + Side panel + + + + Main panel + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml.cs new file mode 100644 index 000000000..3a529743e --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Layout; + +public partial class LayoutDetailsView : ReactiveUserControl +{ + public LayoutDetailsView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs new file mode 100644 index 000000000..00e9d9d1d --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs @@ -0,0 +1,8 @@ +using Artemis.UI.Shared; + +namespace Artemis.UI.Screens.Workshop.Layout; + +public class LayoutDetailsViewModel : ActivatableViewModelBase +{ + +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml new file mode 100644 index 000000000..ebbdfd31c --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml @@ -0,0 +1,22 @@ + + + + + Side panel + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml.cs new file mode 100644 index 000000000..9d604f4f6 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Layout; + +public partial class LayoutListView : ReactiveUserControl +{ + public LayoutListView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs new file mode 100644 index 000000000..54134176f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs @@ -0,0 +1,26 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; + +namespace Artemis.UI.Screens.Workshop.Layout; + +public class LayoutListViewModel : RoutableScreen, IMainScreenViewModel +{ + private int _page; + + public int Page + { + get => _page; + set => RaiseAndSetIfChanged(ref _page, value); + } + + public override Task OnNavigating(WorkshopListParameters parameters, NavigationArguments args, CancellationToken cancellationToken) + { + Page = Math.Max(1, parameters.Page); + return Task.CompletedTask; + } + + public ViewModelBase? TitleBarViewModel => null; +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml new file mode 100644 index 000000000..6b9f1f2df --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml @@ -0,0 +1,8 @@ + + Welcome to Avalonia! + diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml.cs new file mode 100644 index 000000000..25ca88e9f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Profile; + +public partial class ProfileDetailsView : ReactiveUserControl +{ + public ProfileDetailsView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs new file mode 100644 index 000000000..e32bb2dab --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs @@ -0,0 +1,8 @@ +using Artemis.UI.Shared; + +namespace Artemis.UI.Screens.Workshop.Profile; + +public class ProfileDetailsViewModel : ActivatableViewModelBase +{ + +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml new file mode 100644 index 000000000..d103a3288 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml @@ -0,0 +1,22 @@ + + + + + Side panel + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml.cs new file mode 100644 index 000000000..fb6c372c7 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Profile; + +public partial class ProfileListView : ReactiveUserControl +{ + public ProfileListView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs new file mode 100644 index 000000000..8ece60ec1 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs @@ -0,0 +1,26 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; + +namespace Artemis.UI.Screens.Workshop.Profile; + +public class ProfileListViewModel : RoutableScreen, IMainScreenViewModel +{ + private int _page; + + public int Page + { + get => _page; + set => RaiseAndSetIfChanged(ref _page, value); + } + + public override Task OnNavigating(WorkshopListParameters parameters, NavigationArguments args, CancellationToken cancellationToken) + { + Page = Math.Max(1, parameters.Page); + return Task.CompletedTask; + } + + public ViewModelBase? TitleBarViewModel => null; +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopListParameters.cs b/src/Artemis.UI/Screens/Workshop/WorkshopListParameters.cs new file mode 100644 index 000000000..1e223659b --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/WorkshopListParameters.cs @@ -0,0 +1,6 @@ +namespace Artemis.UI.Screens.Workshop; + +public class WorkshopListParameters +{ + public int Page { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml index e303305de..cb672cb99 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml +++ b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml @@ -2,35 +2,13 @@ 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:builders="clr-namespace:Artemis.UI.Shared.Services.Builders;assembly=Artemis.UI.Shared" - xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:attachedProperties="clr-namespace:Artemis.UI.Shared.AttachedProperties;assembly=Artemis.UI.Shared" xmlns:workshop="clr-namespace:Artemis.UI.Screens.Workshop" - xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared" - xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared" - xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker;assembly=Artemis.UI.Shared" - xmlns:materialIconPicker="clr-namespace:Artemis.UI.Shared.MaterialIconPicker;assembly=Artemis.UI.Shared" - xmlns:workshop1="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop" + xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" + xmlns:ui="clr-namespace:Artemis.UI" mc:Ignorable="d" d:DesignWidth="800" x:Class="Artemis.UI.Screens.Workshop.WorkshopView" x:DataType="workshop:WorkshopViewModel"> - - - - - - - - - - - - - - - - - + Workshop overview \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml.cs b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml.cs index c875bd294..76fcc9e13 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml.cs @@ -1,4 +1,3 @@ -using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; namespace Artemis.UI.Screens.Workshop; @@ -9,5 +8,4 @@ public partial class WorkshopView : ReactiveUserControl { InitializeComponent(); } - } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs index 951b7c8e0..86d0c6bdc 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs @@ -1,55 +1,13 @@ -using System; -using System.Collections.ObjectModel; -using System.Reactive; -using System.Reactive.Linq; -using System.Threading.Tasks; -using Artemis.Core; -using Artemis.UI.Screens.Workshop.CurrentUser; -using Artemis.UI.Shared.Services; -using Artemis.UI.Shared.Services.Builders; -using Artemis.WebClient.Workshop; -using Avalonia.Input; -using ReactiveUI; -using SkiaSharp; -using StrawberryShake; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; namespace Artemis.UI.Screens.Workshop; -public class WorkshopViewModel : ActivatableViewModelBase, IMainScreenViewModel +public class WorkshopViewModel : RoutableScreen, IMainScreenViewModel { - private readonly IWorkshopClient _workshopClient; - - public WorkshopViewModel(IScreen hostScreen, IWorkshopClient workshopClient, CurrentUserViewModel currentUserViewModel) : base(hostScreen, "workshop") + public WorkshopViewModel() { - CurrentUserViewModel = currentUserViewModel; - _workshopClient = workshopClient; - DisplayName = "Workshop"; - - Task.Run(() => GetEntries()); } - public ObservableCollection Test { get; set; } = new(); - public CurrentUserViewModel CurrentUserViewModel { get; set; } - - private async Task GetEntries() - { - - try - { - IOperationResult entries = await _workshopClient.GetEntries.ExecuteAsync(); - if (entries.Data?.Entries?.Nodes == null) - return; - - foreach (IGetEntries_Entries_Nodes getEntriesEntriesNodes in entries.Data.Entries.Nodes) - { - Console.WriteLine(getEntriesEntriesNodes); - Test.Add(getEntriesEntriesNodes); - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } + public ViewModelBase? TitleBarViewModel => null; } \ No newline at end of file diff --git a/src/Artemis.UI/Styles/Artemis.axaml b/src/Artemis.UI/Styles/Artemis.axaml index 242bef032..a121ec71b 100644 --- a/src/Artemis.UI/Styles/Artemis.axaml +++ b/src/Artemis.UI/Styles/Artemis.axaml @@ -8,4 +8,12 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Styles/TreeView.axaml b/src/Artemis.UI/Styles/TreeView.axaml new file mode 100644 index 000000000..754755713 --- /dev/null +++ b/src/Artemis.UI/Styles/TreeView.axaml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 31 + 12 + 12, 0, 12, 0 + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 65f81ab768b332a3c3a495aa9a36a460865b6419 Mon Sep 17 00:00:00 2001 From: Robert Date: Sat, 8 Jul 2023 21:44:39 +0200 Subject: [PATCH 04/13] Added workshop home, changed VM routing structure --- .../Routable/RoutableScreenOfTScreenTParam.cs | 11 ++- .../Routing/Router/Navigation.cs | 24 +++++- .../Assets/Images/workshop-banner.jpg | Bin 0 -> 87578 bytes src/Artemis.UI/MainWindow.axaml | 2 +- src/Artemis.UI/Routing/Routes.cs | 18 ++-- src/Artemis.UI/Screens/Home/HomeView.axaml | 23 +++-- .../Screens/Sidebar/SidebarScreenView.axaml | 2 +- .../Sidebar/SidebarScreenView.axaml.cs | 12 ++- .../Screens/Sidebar/SidebarScreenViewModel.cs | 13 +-- .../Workshop/Categories/CategoriesView.axaml | 8 ++ .../Categories/CategoriesView.axaml.cs | 19 +++++ .../Categories/CategoriesViewModel.cs | 14 +++ .../Workshop/Home/WorkshopHomeView.axaml | 58 +++++++++++++ .../Workshop/Home/WorkshopHomeView.axaml.cs | 19 +++++ .../Workshop/Home/WorkshopHomeViewModel.cs | 20 +++++ .../Workshop/Layout/LayoutDetailsView.axaml | 20 +++-- .../Workshop/Layout/LayoutDetailsViewModel.cs | 39 ++++++++- .../Workshop/Layout/LayoutListViewModel.cs | 12 ++- .../Parameters/WorkshopDetailParameters.cs | 8 ++ .../WorkshopListParameters.cs | 2 +- .../Workshop/Profile/ProfileDetailsView.axaml | 23 ++++- .../Profile/ProfileDetailsViewModel.cs | 39 ++++++++- .../Workshop/Profile/ProfileListViewModel.cs | 15 +++- .../Screens/Workshop/Search/SearchView.axaml | 55 ++++++++++++ .../Workshop/Search/SearchView.axaml.cs | 18 ++++ .../Workshop/Search/SearchViewModel.cs | 80 ++++++++++++++++++ .../Workshop/Search/SearchViewStyles.axaml | 28 ++++++ .../Screens/Workshop/WorkshopView.axaml | 8 +- .../Screens/Workshop/WorkshopView.axaml.cs | 5 ++ .../Screens/Workshop/WorkshopViewModel.cs | 33 +++++++- .../Artemis.WebClient.Workshop.csproj | 9 ++ .../Queries/GetCategories.graphql | 7 ++ .../Queries/SearchEntries.graphql | 18 ++++ src/Artemis.WebClient.Workshop/schema.graphql | 80 ++++++++++++++++-- 34 files changed, 667 insertions(+), 75 deletions(-) create mode 100644 src/Artemis.UI/Assets/Images/workshop-banner.jpg create mode 100644 src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeViewModel.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Parameters/WorkshopDetailParameters.cs rename src/Artemis.UI/Screens/Workshop/{ => Parameters}/WorkshopListParameters.cs (59%) create mode 100644 src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Search/SearchViewStyles.axaml create mode 100644 src/Artemis.WebClient.Workshop/Queries/GetCategories.graphql create mode 100644 src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql diff --git a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreenTParam.cs b/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreenTParam.cs index 38afcd3d7..ac62129dc 100644 --- a/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreenTParam.cs +++ b/src/Artemis.UI.Shared/Routing/Routable/RoutableScreenOfTScreenTParam.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; +using Avalonia.Platform; namespace Artemis.UI.Shared.Routing; @@ -72,7 +73,15 @@ public abstract class RoutableScreen : ActivatableViewModelBase void IRoutableScreen.InternalChangeScreen(object? screen) { - Screen = screen as TScreen; + if (screen == null) + { + Screen = null; + return; + } + + if (screen is not TScreen typedScreen) + throw new ArtemisRoutingException($"Provided screen is not assignable to {typeof(TScreen).FullName}"); + Screen = typedScreen; } async Task IRoutableScreen.InternalOnNavigating(NavigationArguments args, CancellationToken cancellationToken) diff --git a/src/Artemis.UI.Shared/Routing/Router/Navigation.cs b/src/Artemis.UI.Shared/Routing/Router/Navigation.cs index 69d3ed15b..ac171100f 100644 --- a/src/Artemis.UI.Shared/Routing/Router/Navigation.cs +++ b/src/Artemis.UI.Shared/Routing/Router/Navigation.cs @@ -70,7 +70,17 @@ internal class Navigation // Only change the screen if it wasn't reused if (!ReferenceEquals(host.InternalScreen, screen)) - host.InternalChangeScreen(screen); + { + try + { + host.InternalChangeScreen(screen); + } + catch (Exception e) + { + Cancel(); + _logger.Error(e, "Failed to navigate to {Path}", resolution.Path); + } + } if (CancelIfRequested(args, "ChangeScreen", screen)) return; @@ -93,8 +103,16 @@ internal class Navigation return; } - if (resolution.Child != null && screen is IRoutableScreen childScreen) - await NavigateResolution(resolution.Child, args, childScreen); + if (screen is IRoutableScreen childScreen) + { + // Navigate the child too + if (resolution.Child != null) + await NavigateResolution(resolution.Child, args, childScreen); + // Make sure there is no child + else if (childScreen.InternalScreen != null) + childScreen.InternalChangeScreen(null); + } + Completed = true; } diff --git a/src/Artemis.UI/Assets/Images/workshop-banner.jpg b/src/Artemis.UI/Assets/Images/workshop-banner.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da259f5f5191250295dfe15fa013426ed72a7bb0 GIT binary patch literal 87578 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

7=j`K~M0RXW~&6z4L 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 literal 0 HcmV?d00001 diff --git a/src/Artemis.UI/MainWindow.axaml b/src/Artemis.UI/MainWindow.axaml index d735ae109..bff2c07c9 100644 --- a/src/Artemis.UI/MainWindow.axaml +++ b/src/Artemis.UI/MainWindow.axaml @@ -15,7 +15,7 @@ + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml index cb672cb99..39cd6ca6c 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml +++ b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml @@ -8,7 +8,9 @@ mc:Ignorable="d" d:DesignWidth="800" x:Class="Artemis.UI.Screens.Workshop.WorkshopView" x:DataType="workshop:WorkshopViewModel"> - - Workshop overview - + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml.cs b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml.cs index 76fcc9e13..c013afa8e 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml.cs @@ -1,4 +1,8 @@ +using System; +using System.Reactive.Disposables; using Avalonia.ReactiveUI; +using Avalonia.Threading; +using ReactiveUI; namespace Artemis.UI.Screens.Workshop; @@ -7,5 +11,6 @@ public partial class WorkshopView : ReactiveUserControl public WorkshopView() { InitializeComponent(); + this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen).Subscribe(vm => WorkshopFrame.NavigateFromObject(vm ?? ViewModel?.HomeViewModel)).DisposeWith(d)); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs index 86d0c6bdc..f6b53a013 100644 --- a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs @@ -1,13 +1,38 @@ -using Artemis.UI.Shared; +using System; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Screens.Workshop.Home; +using Artemis.UI.Screens.Workshop.Search; +using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; +using Artemis.WebClient.Workshop; namespace Artemis.UI.Screens.Workshop; -public class WorkshopViewModel : RoutableScreen, IMainScreenViewModel +public class WorkshopViewModel : RoutableScreen, IMainScreenViewModel { - public WorkshopViewModel() + private readonly SearchViewModel _searchViewModel; + + public WorkshopViewModel(SearchViewModel searchViewModel, WorkshopHomeViewModel homeViewModel) { + _searchViewModel = searchViewModel; + + TitleBarViewModel = searchViewModel; + HomeViewModel = homeViewModel; } - public ViewModelBase? TitleBarViewModel => null; + public ViewModelBase TitleBarViewModel { get; } + public WorkshopHomeViewModel HomeViewModel { get; } + + /// + public override Task OnNavigating(NavigationArguments args, CancellationToken cancellationToken) + { + _searchViewModel.EntryType = Screen?.EntryType; + return Task.CompletedTask; + } +} + +public interface IWorkshopViewModel +{ + public EntryType? EntryType { get; } } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj index ecacce222..09befbe14 100644 --- a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj +++ b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj @@ -22,4 +22,13 @@ + + + + MSBuild:GenerateGraphQLCode + + + MSBuild:GenerateGraphQLCode + + diff --git a/src/Artemis.WebClient.Workshop/Queries/GetCategories.graphql b/src/Artemis.WebClient.Workshop/Queries/GetCategories.graphql new file mode 100644 index 000000000..d39be92f2 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/GetCategories.graphql @@ -0,0 +1,7 @@ +query GetCategories { + categories { + id + name + icon + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql new file mode 100644 index 000000000..b2a03cf3f --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql @@ -0,0 +1,18 @@ +query SearchEntries($filter: EntryFilterInput) { + entries( + first: 10 + where: $filter + ) { + nodes { + id + name + summary + entryType + categories { + id + name + icon + } + } + } +} diff --git a/src/Artemis.WebClient.Workshop/schema.graphql b/src/Artemis.WebClient.Workshop/schema.graphql index daa53bde8..93e31079c 100644 --- a/src/Artemis.WebClient.Workshop/schema.graphql +++ b/src/Artemis.WebClient.Workshop/schema.graphql @@ -5,6 +5,12 @@ schema { mutation: Mutation } +type Category { + icon: String! + id: Int! + name: String! +} + "A connection to a list of items." type EntriesConnection { "A list of edges." @@ -27,14 +33,18 @@ type EntriesEdge { type Entry { author: UUID! + categories: [Category!]! + createdAt: DateTime! description: String! + downloads: Long! entryType: EntryType! icon: Image id: UUID! images: [Image!]! name: String! releases: [Release!]! - tags: [String!]! + summary: String! + tags: [Tag!]! } type Image { @@ -59,6 +69,7 @@ type PageInfo { } type Query { + categories(order: [CategorySortInput!], where: CategoryFilterInput): [Category!]! entries( "Returns the elements in the list that come after the specified cursor." after: String, @@ -78,11 +89,17 @@ type Release { createdAt: DateTime! downloadSize: Long! downloads: Long! + entry: Entry! id: UUID! md5Hash: String version: String! } +type Tag { + id: Int! + name: String! +} + enum EntryType { LAYOUT PLUGIN @@ -102,6 +119,20 @@ scalar Long scalar UUID +input CategoryFilterInput { + and: [CategoryFilterInput!] + icon: StringOperationFilterInput + id: IntOperationFilterInput + name: StringOperationFilterInput + or: [CategoryFilterInput!] +} + +input CategorySortInput { + icon: SortEnumType + id: SortEnumType + name: SortEnumType +} + input DateTimeOperationFilterInput { eq: DateTime gt: DateTime @@ -120,7 +151,10 @@ input DateTimeOperationFilterInput { input EntryFilterInput { and: [EntryFilterInput!] author: UuidOperationFilterInput + categories: ListFilterInputTypeOfCategoryFilterInput + createdAt: DateTimeOperationFilterInput description: StringOperationFilterInput + downloads: LongOperationFilterInput entryType: EntryTypeOperationFilterInput icon: ImageFilterInput id: UuidOperationFilterInput @@ -128,7 +162,8 @@ input EntryFilterInput { name: StringOperationFilterInput or: [EntryFilterInput!] releases: ListFilterInputTypeOfReleaseFilterInput - tags: ListStringOperationFilterInput + summary: StringOperationFilterInput + tags: ListFilterInputTypeOfTagFilterInput } input EntryInput { @@ -140,11 +175,14 @@ input EntryInput { input EntrySortInput { author: SortEnumType + createdAt: SortEnumType description: SortEnumType + downloads: SortEnumType entryType: SortEnumType icon: ImageSortInput id: SortEnumType name: SortEnumType + summary: SortEnumType } input EntryTypeOperationFilterInput { @@ -166,6 +204,28 @@ input ImageSortInput { mimeType: SortEnumType } +input IntOperationFilterInput { + eq: Int + gt: Int + gte: Int + in: [Int] + lt: Int + lte: Int + neq: Int + ngt: Int + ngte: Int + nin: [Int] + nlt: Int + nlte: Int +} + +input ListFilterInputTypeOfCategoryFilterInput { + all: CategoryFilterInput + any: Boolean + none: CategoryFilterInput + some: CategoryFilterInput +} + input ListFilterInputTypeOfImageFilterInput { all: ImageFilterInput any: Boolean @@ -180,11 +240,11 @@ input ListFilterInputTypeOfReleaseFilterInput { some: ReleaseFilterInput } -input ListStringOperationFilterInput { - all: StringOperationFilterInput +input ListFilterInputTypeOfTagFilterInput { + all: TagFilterInput any: Boolean - none: StringOperationFilterInput - some: StringOperationFilterInput + none: TagFilterInput + some: TagFilterInput } input LongOperationFilterInput { @@ -207,6 +267,7 @@ input ReleaseFilterInput { createdAt: DateTimeOperationFilterInput downloadSize: LongOperationFilterInput downloads: LongOperationFilterInput + entry: EntryFilterInput id: UuidOperationFilterInput md5Hash: StringOperationFilterInput or: [ReleaseFilterInput!] @@ -228,6 +289,13 @@ input StringOperationFilterInput { startsWith: String } +input TagFilterInput { + and: [TagFilterInput!] + id: IntOperationFilterInput + name: StringOperationFilterInput + or: [TagFilterInput!] +} + input UuidOperationFilterInput { eq: UUID gt: UUID From 428bbd73e3c090e322ecac9236ad24f57d0700ef Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 9 Jul 2023 12:54:07 +0200 Subject: [PATCH 05/13] Added basic profile list --- .../Workshop/Categories/CategoriesView.axaml | 19 ++++++-- .../Categories/CategoriesView.axaml.cs | 8 +++- .../Categories/CategoriesViewModel.cs | 38 ++++++++++++++- .../Workshop/Categories/CategoryViewModel.cs | 29 +++++++++++ .../Workshop/Layout/LayoutListView.axaml | 5 +- .../Workshop/Layout/LayoutListViewModel.cs | 8 ++-- .../Profile/ProfileListEntryView.axaml | 39 +++++++++++++++ .../Profile/ProfileListEntryView.axaml.cs | 18 +++++++ .../Profile/ProfileListEntryViewModel.cs | 14 ++++++ .../Workshop/Profile/ProfileListView.axaml | 18 +++++-- .../Workshop/Profile/ProfileListViewModel.cs | 48 ++++++++++++++++--- .../Queries/GetEntries.graphql | 9 +++- 12 files changed, 231 insertions(+), 22 deletions(-) create mode 100644 src/Artemis.UI/Screens/Workshop/Categories/CategoryViewModel.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryViewModel.cs diff --git a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml index a9072633d..d629cc7d3 100644 --- a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml @@ -2,7 +2,20 @@ 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:categories="clr-namespace:Artemis.UI.Screens.Workshop.Categories" + xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Artemis.UI.Screens.Workshop.Categories.CategoriesView"> - Welcome to Avalonia! - + x:Class="Artemis.UI.Screens.Workshop.Categories.CategoriesView" + x:DataType="categories:CategoriesViewModel"> + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml.cs index 0864378dd..15ac17ab5 100644 --- a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesView.axaml.cs @@ -1,5 +1,5 @@ using Avalonia; -using Avalonia.Controls; +using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; @@ -16,4 +16,10 @@ public partial class CategoriesView : ReactiveUserControl { AvaloniaXamlLoader.Load(this); } + + private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e) + { + if (e.InitialPressMouseButton == MouseButton.Left && sender is IDataContextProvider p && p.DataContext is CategoryViewModel categoryViewModel) + categoryViewModel.IsSelected = !categoryViewModel.IsSelected; + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs index 4306a9fbf..f131958ae 100644 --- a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs @@ -1,14 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Disposables; +using System.Threading; +using System.Threading.Tasks; using Artemis.UI.Shared; using Artemis.WebClient.Workshop; +using ReactiveUI; +using Serilog; +using StrawberryShake; namespace Artemis.UI.Screens.Workshop.Categories; public class CategoriesViewModel : ActivatableViewModelBase { private readonly IWorkshopClient _client; + private readonly ILogger _logger; + private IReadOnlyList _categories; - public CategoriesViewModel(IWorkshopClient client) + public CategoriesViewModel(ILogger logger, IWorkshopClient client) { + _logger = logger; _client = client; + + this.WhenActivated(d => ReactiveCommand.CreateFromTask(GetCategories).Execute().Subscribe().DisposeWith(d)); + } + + public IReadOnlyList Categories + { + get => _categories; + set => RaiseAndSetIfChanged(ref _categories, value); + } + + private async Task GetCategories(CancellationToken cancellationToken) + { + try + { + IOperationResult result = await _client.GetCategories.ExecuteAsync(cancellationToken); + if (result.IsErrorResult()) + _logger.Warning("Failed to retrieve categories {Error}", result.Errors); + + Categories = result.Data?.Categories.Select(c => new CategoryViewModel(c)).ToList() ?? new List(); + } + catch (Exception e) + { + _logger.Warning(e, "Failed to retrieve categories"); + } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Categories/CategoryViewModel.cs b/src/Artemis.UI/Screens/Workshop/Categories/CategoryViewModel.cs new file mode 100644 index 000000000..08d991009 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Categories/CategoryViewModel.cs @@ -0,0 +1,29 @@ +using System; +using Artemis.UI.Shared; +using Artemis.WebClient.Workshop; +using Material.Icons; + +namespace Artemis.UI.Screens.Workshop.Categories; + +public class CategoryViewModel : ViewModelBase +{ + private bool _isSelected; + + public CategoryViewModel(IGetCategories_Categories category) + { + Id = category.Id; + Name = category.Name; + if (Enum.TryParse(typeof(MaterialIconKind), category.Icon, out object? icon)) + Icon = icon as MaterialIconKind? ?? MaterialIconKind.QuestionMarkCircle; + } + + public int Id { get; } + public string Name { get; } + public MaterialIconKind Icon { get; } + + public bool IsSelected + { + get => _isSelected; + set => RaiseAndSetIfChanged(ref _isSelected, value); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml index ebbdfd31c..151ec2089 100644 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListView.axaml @@ -9,7 +9,10 @@ - Side panel + + Categories + + diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs index b86bf8ecc..17ac0ca9e 100644 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutListViewModel.cs @@ -1,8 +1,8 @@ using System; using System.Threading; using System.Threading.Tasks; +using Artemis.UI.Screens.Workshop.Categories; using Artemis.UI.Screens.Workshop.Parameters; -using Artemis.UI.Screens.Workshop.Search; using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; @@ -13,11 +13,13 @@ public class LayoutListViewModel : RoutableScreen - public LayoutListViewModel() + public LayoutListViewModel(CategoriesViewModel categoriesViewModel) { + CategoriesViewModel = categoriesViewModel; } + public CategoriesViewModel CategoriesViewModel { get; } + public int Page { get => _page; diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml new file mode 100644 index 000000000..13395d7b7 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Downloads + Last updated + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml.cs new file mode 100644 index 000000000..288da66ae --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Artemis.UI.Screens.Workshop.Profile; + +public partial class ProfileListEntryView : UserControl +{ + public ProfileListEntryView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryViewModel.cs new file mode 100644 index 000000000..67786214d --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryViewModel.cs @@ -0,0 +1,14 @@ +using Artemis.UI.Shared; +using Artemis.WebClient.Workshop; + +namespace Artemis.UI.Screens.Workshop.Profile; + +public class ProfileListEntryViewModel : ViewModelBase +{ + public ProfileListEntryViewModel(IGetEntries_Entries_Nodes entry) + { + Entry = entry; + } + + public IGetEntries_Entries_Nodes Entry { get; } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml index d103a3288..38380c8e7 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml @@ -8,14 +8,22 @@ x:DataType="profile:ProfileListViewModel"> - - Side panel + + + Categories + + + - - - + + + + + + + diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs index d478b5229..76f1fa762 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs @@ -1,34 +1,70 @@ using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Disposables; using System.Threading; using System.Threading.Tasks; +using Artemis.UI.Screens.Workshop.Categories; using Artemis.UI.Screens.Workshop.Parameters; -using Artemis.UI.Screens.Workshop.Search; using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; +using DynamicData; +using ReactiveUI; +using StrawberryShake; namespace Artemis.UI.Screens.Workshop.Profile; public class ProfileListViewModel : RoutableScreen, IWorkshopViewModel { + private readonly SourceList _entries; + private readonly IWorkshopClient _workshopClient; private int _page; - /// - public ProfileListViewModel() + public ProfileListViewModel(IWorkshopClient workshopClient, CategoriesViewModel categoriesViewModel) { - + _workshopClient = workshopClient; + CategoriesViewModel = categoriesViewModel; + + _entries = new SourceList(); + _entries.Connect() + .Transform(e => new ProfileListEntryViewModel(e)) + .Bind(out ReadOnlyObservableCollection observableEntries) + .Subscribe(); + Entries = observableEntries; } + public CategoriesViewModel CategoriesViewModel { get; } + public ReadOnlyObservableCollection Entries { get; set; } + public int Page { get => _page; set => RaiseAndSetIfChanged(ref _page, value); } - public override Task OnNavigating(WorkshopListParameters parameters, NavigationArguments args, CancellationToken cancellationToken) + public override async Task OnNavigating(WorkshopListParameters parameters, NavigationArguments args, CancellationToken cancellationToken) { Page = Math.Max(1, parameters.Page); - return Task.CompletedTask; + await GetEntries(cancellationToken); + } + + private async Task GetEntries(CancellationToken cancellationToken) + { + IOperationResult result = await _workshopClient.GetEntries.ExecuteAsync(CreateFilter(), cancellationToken); + if (result.IsErrorResult() || result.Data?.Entries?.Nodes == null) + return; + + _entries.Edit(e => + { + e.Clear(); + e.AddRange(result.Data.Entries.Nodes); + }); + } + + private EntryFilterInput CreateFilter() + { + return new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = WebClient.Workshop.EntryType.Profile}}; } public EntryType? EntryType => null; diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql index 9d9457e62..dae8242c6 100644 --- a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql +++ b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql @@ -1,9 +1,14 @@ -query GetEntries { - entries { +query GetEntries($filter: EntryFilterInput) { + entries(where: $filter) { nodes { author name + summary entryType + categories { + name + icon + } } } } \ No newline at end of file From 1c07bef3cf8a5b7d55470633e9549d222dc8150e Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 14 Jul 2023 09:21:09 +0200 Subject: [PATCH 06/13] Use real backend --- .../CurrentUser/CurrentUserViewModel.cs | 3 +- .../.graphqlrc.json | 2 +- .../Artemis.WebClient.Workshop.csproj | 1 + .../DryIoc/ContainerExtensions.cs | 4 +- .../Services/IAuthenticationService.cs | 38 ++++++++----------- .../WorkshopConstants.cs | 7 ++++ .../graphql.config.yml | 2 +- src/Artemis.WebClient.Workshop/schema.graphql | 16 +++++++- 8 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 src/Artemis.WebClient.Workshop/WorkshopConstants.cs diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs index 3d0121043..7df2e3150 100644 --- a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs @@ -5,6 +5,7 @@ using System.Reactive.Disposables; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Shared; +using Artemis.WebClient.Workshop; using Artemis.WebClient.Workshop.Services; using Avalonia.Media.Imaging; using Flurl.Http; @@ -94,7 +95,7 @@ public class CurrentUserViewModel : ActivatableViewModelBase { try { - Avatar = new Bitmap(await $"{IAuthenticationService.AUTHORITY}/user/avatar/{userId}".GetStreamAsync()); + Avatar = new Bitmap(await $"{WorkshopConstants.AUTHORITY_URL}/user/avatar/{userId}".GetStreamAsync()); } catch (Exception) { diff --git a/src/Artemis.WebClient.Workshop/.graphqlrc.json b/src/Artemis.WebClient.Workshop/.graphqlrc.json index 24fb39de3..3cd18817b 100644 --- a/src/Artemis.WebClient.Workshop/.graphqlrc.json +++ b/src/Artemis.WebClient.Workshop/.graphqlrc.json @@ -5,7 +5,7 @@ "strawberryShake": { "name": "WorkshopClient", "namespace": "Artemis.WebClient.Workshop", - "url": "https://localhost:7281/graphql/", + "url": "https://workshop.artemis-rgb.com/graphql/", "emitGeneratedCode": false, "records": { "inputs": false, diff --git a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj index 09befbe14..653d780a8 100644 --- a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj +++ b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj @@ -13,6 +13,7 @@ + diff --git a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs index 1988fa300..bdcdbede6 100644 --- a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs @@ -22,12 +22,12 @@ public static class ContainerExtensions serviceCollection .AddHttpClient() .AddWorkshopClient() - .ConfigureHttpClient(client => client.BaseAddress = new Uri("https://localhost:7281/graphql")); + .ConfigureHttpClient(client => client.BaseAddress = new Uri(WorkshopConstants.WORKSHOP_URL + "/graphql")); serviceCollection.AddSingleton(r => { IHttpClientFactory factory = r.GetRequiredService(); - return new DiscoveryCache(IAuthenticationService.AUTHORITY, () => factory.CreateClient()); + return new DiscoveryCache(WorkshopConstants.AUTHORITY_URL, () => factory.CreateClient()); }); container.WithDependencyInjectionAdapter(serviceCollection); diff --git a/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs b/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs index c3c112451..eed47ecff 100644 --- a/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs +++ b/src/Artemis.WebClient.Workshop/Services/IAuthenticationService.cs @@ -1,5 +1,6 @@ using System.Collections.ObjectModel; using System.Diagnostics; +using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using Artemis.Core; using Artemis.Core.Services; @@ -11,8 +12,6 @@ namespace Artemis.WebClient.Workshop.Services; public interface IAuthenticationService : IProtectedArtemisService { - public const string AUTHORITY = "https://localhost:5001"; - bool IsLoggedIn { get; } string? UserCode { get; } ReadOnlyObservableCollection Claims { get; } @@ -25,7 +24,7 @@ public interface IAuthenticationService : IProtectedArtemisService internal class AuthenticationService : CorePropertyChanged, IAuthenticationService { - internal const string CLIENT_ID = "artemis.desktop"; + private const string CLIENT_ID = "artemis.desktop"; private readonly IDiscoveryCache _discoveryCache; private readonly IAuthenticationRepository _authenticationRepository; @@ -109,7 +108,8 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi DeviceAuthorizationResponse response = await client.RequestDeviceAuthorizationAsync(new DeviceAuthorizationRequest { Address = disco.DeviceAuthorizationEndpoint, - ClientId = CLIENT_ID + ClientId = CLIENT_ID, + Scope = "openid profile email offline_access api" }); if (response.IsError) throw new ArtemisWebClientException("Failed to request device authorization: " + response.Error); @@ -168,33 +168,25 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi throw new ArtemisWebClientException("Failed to request device token: " + response.Error); } - await SetCurrentUser(client, response); + SetCurrentUser(response); return true; } - private async Task SetCurrentUser(HttpClient client, TokenResponse response) + private void SetCurrentUser(TokenResponse response) { _token = new AuthenticationToken(response); _authenticationRepository.SetRefreshToken(_token.RefreshToken); - - await GetUserInfo(client, _token.AccessToken); - IsLoggedIn = true; - } - - private async Task GetUserInfo(HttpClient client, string accessToken) - { - DiscoveryDocumentResponse disco = await GetDiscovery(); - UserInfoResponse response = await client.GetUserInfoAsync(new UserInfoRequest() - { - Address = disco.UserInfoEndpoint, - Token = accessToken - }); - if (response.IsError) - throw new ArtemisWebClientException("Failed to retrieve user info: " + response.Error); + + JwtSecurityTokenHandler handler = new(); + JwtSecurityToken? token = handler.ReadJwtToken(response.IdentityToken); + if (token == null) + throw new ArtemisWebClientException("Failed to read JWT token"); _claims.Clear(); - foreach (Claim responseClaim in response.Claims) + foreach (Claim responseClaim in token.Claims) _claims.Add(responseClaim); + + IsLoggedIn = true; } private async Task UseRefreshToken(string refreshToken) @@ -216,7 +208,7 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi throw new ArtemisWebClientException("Failed to request refresh token: " + response.Error); } - await SetCurrentUser(client, response); + SetCurrentUser(response); return false; } } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/WorkshopConstants.cs b/src/Artemis.WebClient.Workshop/WorkshopConstants.cs new file mode 100644 index 000000000..b514ae862 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/WorkshopConstants.cs @@ -0,0 +1,7 @@ +namespace Artemis.WebClient.Workshop; + +public static class WorkshopConstants +{ + public const string AUTHORITY_URL = "https://identity.artemis-rgb.com"; + public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com"; +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/graphql.config.yml b/src/Artemis.WebClient.Workshop/graphql.config.yml index a8ba99703..9662a514f 100644 --- a/src/Artemis.WebClient.Workshop/graphql.config.yml +++ b/src/Artemis.WebClient.Workshop/graphql.config.yml @@ -2,7 +2,7 @@ schema: schema.graphql extensions: endpoints: Default GraphQL Endpoint: - url: https://localhost:7281/graphql + url: https://workshop.artemis-rgb.com/graphql headers: user-agent: JS GraphQL introspect: true diff --git a/src/Artemis.WebClient.Workshop/schema.graphql b/src/Artemis.WebClient.Workshop/schema.graphql index 93e31079c..c41fd39ba 100644 --- a/src/Artemis.WebClient.Workshop/schema.graphql +++ b/src/Artemis.WebClient.Workshop/schema.graphql @@ -32,7 +32,8 @@ type EntriesEdge { } type Entry { - author: UUID! + author: String! + authorId: UUID! categories: [Category!]! createdAt: DateTime! description: String! @@ -83,6 +84,7 @@ type Query { where: EntryFilterInput ): EntriesConnection entry(id: UUID!): Entry + searchEntries(input: String!, order: [EntrySortInput!], type: EntryType, where: EntryFilterInput): [Entry!]! } type Release { @@ -90,6 +92,7 @@ type Release { downloadSize: Long! downloads: Long! entry: Entry! + entryId: UUID! id: UUID! md5Hash: String version: String! @@ -100,6 +103,12 @@ type Tag { name: String! } +enum ApplyPolicy { + AFTER_RESOLVER + BEFORE_RESOLVER + VALIDATION +} + enum EntryType { LAYOUT PLUGIN @@ -150,7 +159,8 @@ input DateTimeOperationFilterInput { input EntryFilterInput { and: [EntryFilterInput!] - author: UuidOperationFilterInput + author: StringOperationFilterInput + authorId: UuidOperationFilterInput categories: ListFilterInputTypeOfCategoryFilterInput createdAt: DateTimeOperationFilterInput description: StringOperationFilterInput @@ -175,6 +185,7 @@ input EntryInput { input EntrySortInput { author: SortEnumType + authorId: SortEnumType createdAt: SortEnumType description: SortEnumType downloads: SortEnumType @@ -268,6 +279,7 @@ input ReleaseFilterInput { downloadSize: LongOperationFilterInput downloads: LongOperationFilterInput entry: EntryFilterInput + entryId: UuidOperationFilterInput id: UuidOperationFilterInput md5Hash: StringOperationFilterInput or: [ReleaseFilterInput!] From 07d4539add289572b73bad68657c9da90e47b7d4 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 14 Jul 2023 23:05:44 +0200 Subject: [PATCH 07/13] Workshop list progress --- src/Artemis.UI.Shared/Styles/Sidebar.axaml | 2 +- src/Artemis.UI.Shared/Styles/TextBlock.axaml | 31 ++++++++++ src/Artemis.UI/Artemis.UI.csproj | 7 +++ .../Categories/CategoriesViewModel.cs | 24 +++++--- .../CurrentUser/CurrentUserView.axaml | 6 +- .../CurrentUser/CurrentUserViewModel.cs | 55 +++++++++++------ .../Workshop/Entries/EntryListView.axaml | 61 +++++++++++++++++++ .../Workshop/Entries/EntryListView.axaml.cs | 24 ++++++++ .../Workshop/Entries/EntryListViewModel.cs | 37 +++++++++++ .../Profile/ProfileListEntryView.axaml | 39 ------------ .../Profile/ProfileListEntryView.axaml.cs | 18 ------ .../Profile/ProfileListEntryViewModel.cs | 14 ----- .../Workshop/Profile/ProfileListViewModel.cs | 29 +++++++-- .../Screens/Workshop/Search/SearchView.axaml | 4 +- .../Workshop/Search/SearchViewModel.cs | 25 ++------ src/Artemis.UI/Styles/TreeView.axaml | 3 +- .../Queries/GetEntries.graphql | 3 + .../Queries/SearchEntries.graphql | 21 +++---- 18 files changed, 258 insertions(+), 145 deletions(-) create mode 100644 src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/Entries/EntryListViewModel.cs delete mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml delete mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml.cs delete mode 100644 src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryViewModel.cs diff --git a/src/Artemis.UI.Shared/Styles/Sidebar.axaml b/src/Artemis.UI.Shared/Styles/Sidebar.axaml index 605ba8e40..5fbfb48d5 100644 --- a/src/Artemis.UI.Shared/Styles/Sidebar.axaml +++ b/src/Artemis.UI.Shared/Styles/Sidebar.axaml @@ -22,6 +22,6 @@ \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Styles/TextBlock.axaml b/src/Artemis.UI.Shared/Styles/TextBlock.axaml index 9d3cf6ab4..8a5099cde 100644 --- a/src/Artemis.UI.Shared/Styles/TextBlock.axaml +++ b/src/Artemis.UI.Shared/Styles/TextBlock.axaml @@ -10,6 +10,15 @@ This is heading 5 This is heading 6 This is a subtitle + + This is heading 1 + This is heading 2 + This is heading 3 + This is heading 4 + This is heading 5 + This is heading 6 + This is a subtitle + @@ -50,4 +59,26 @@ + + + + + + + + diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 4e71ac252..5da497f13 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -55,4 +55,11 @@ + + + + ProfileListEntryView.axaml + Code + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs index f131958ae..e3b1e0464 100644 --- a/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Categories/CategoriesViewModel.cs @@ -1,11 +1,12 @@ using System; -using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Reactive.Disposables; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Shared; using Artemis.WebClient.Workshop; +using DynamicData; using ReactiveUI; using Serilog; using StrawberryShake; @@ -16,21 +17,21 @@ public class CategoriesViewModel : ActivatableViewModelBase { private readonly IWorkshopClient _client; private readonly ILogger _logger; - private IReadOnlyList _categories; + public readonly SourceList _categories; public CategoriesViewModel(ILogger logger, IWorkshopClient client) { _logger = logger; _client = client; - + _categories = new SourceList(); + _categories.Connect().Bind(out ReadOnlyObservableCollection categoryViewModels).Subscribe(); + + Categories = categoryViewModels; this.WhenActivated(d => ReactiveCommand.CreateFromTask(GetCategories).Execute().Subscribe().DisposeWith(d)); } - public IReadOnlyList Categories - { - get => _categories; - set => RaiseAndSetIfChanged(ref _categories, value); - } + public ReadOnlyObservableCollection Categories { get; } + private async Task GetCategories(CancellationToken cancellationToken) { @@ -40,7 +41,12 @@ public class CategoriesViewModel : ActivatableViewModelBase if (result.IsErrorResult()) _logger.Warning("Failed to retrieve categories {Error}", result.Errors); - Categories = result.Data?.Categories.Select(c => new CategoryViewModel(c)).ToList() ?? new List(); + _categories.Edit(l => + { + l.Clear(); + if (result.Data?.Categories != null) + l.AddRange(result.Data.Categories.Select(c => new CategoryViewModel(c))); + }); } catch (Exception e) { diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml index 57a245c81..9487ac4eb 100644 --- a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml @@ -9,9 +9,9 @@ x:Class="Artemis.UI.Screens.Workshop.CurrentUser.CurrentUserView" x:DataType="currentUser:CurrentUserViewModel"> - + - + @@ -27,7 +27,7 @@ - + diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs index 7df2e3150..c204c3165 100644 --- a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserViewModel.cs @@ -10,38 +10,33 @@ using Artemis.WebClient.Workshop.Services; using Avalonia.Media.Imaging; using Flurl.Http; using ReactiveUI; +using Serilog; namespace Artemis.UI.Screens.Workshop.CurrentUser; public class CurrentUserViewModel : ActivatableViewModelBase { + private readonly ILogger _logger; private readonly IAuthenticationService _authenticationService; - private ObservableAsPropertyHelper? _isLoggedIn; - - private string? _userId; - private string? _name; - private string? _email; + private bool _loading = true; private Bitmap? _avatar; + private string? _email; + private string? _name; + private string? _userId; - public CurrentUserViewModel(IAuthenticationService authenticationService) + public CurrentUserViewModel(ILogger logger, IAuthenticationService authenticationService) { + _logger = logger; _authenticationService = authenticationService; Login = ReactiveCommand.CreateFromTask(ExecuteLogin); - this.WhenActivated(d => _isLoggedIn = _authenticationService.WhenAnyValue(s => s.IsLoggedIn).ToProperty(this, vm => vm.IsLoggedIn).DisposeWith(d)); - this.WhenActivated(d => - { - Task.Run(async () => - { - await _authenticationService.AutoLogin(); - await LoadCurrentUser(); - }).DisposeWith(d); - }); + this.WhenActivated(d => ReactiveCommand.CreateFromTask(ExecuteAutoLogin).Execute().Subscribe().DisposeWith(d)); } - public void Logout() + public bool Loading { - _authenticationService.Logout(); + get => _loading; + set => RaiseAndSetIfChanged(ref _loading, value); } public string? UserId @@ -69,18 +64,38 @@ public class CurrentUserViewModel : ActivatableViewModelBase } public ReactiveCommand Login { get; } - public bool IsLoggedIn => _isLoggedIn?.Value ?? false; + + public void Logout() + { + _authenticationService.Logout(); + } private async Task ExecuteLogin(CancellationToken cancellationToken) { await _authenticationService.Login(); await LoadCurrentUser(); - Console.WriteLine(_authenticationService.Claims); + } + + private async Task ExecuteAutoLogin(CancellationToken cancellationToken) + { + try + { + await _authenticationService.AutoLogin(); + await LoadCurrentUser(); + } + catch (Exception e) + { + _logger.Warning(e, "Failed to load the current user"); + } + finally + { + Loading = false; + } } private async Task LoadCurrentUser() { - if (!IsLoggedIn) + if (!_authenticationService.IsLoggedIn) return; UserId = _authenticationService.Claims.FirstOrDefault(c => c.Type == "sub")?.Value; diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml b/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml new file mode 100644 index 000000000..e7450f685 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + by + + + + + + + + + + + + + + + + + + + + + + + + + + downloads + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml.cs new file mode 100644 index 000000000..42a7b86ad --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml.cs @@ -0,0 +1,24 @@ +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Entries; + +public partial class EntryListView : ReactiveUserControl +{ + public EntryListView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private async void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e) + { + await ViewModel.NavigateToEntry(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntryListViewModel.cs new file mode 100644 index 000000000..7a318fc27 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryListViewModel.cs @@ -0,0 +1,37 @@ +using System; +using System.Threading.Tasks; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; +using Artemis.WebClient.Workshop; + +namespace Artemis.UI.Screens.Workshop.Entries; + +public class EntryListViewModel : ViewModelBase +{ + private readonly IRouter _router; + + public EntryListViewModel(IGetEntries_Entries_Nodes entry, IRouter router) + { + _router = router; + Entry = entry; + } + + public IGetEntries_Entries_Nodes Entry { get; } + + public async Task NavigateToEntry() + { + switch (Entry.EntryType) + { + case EntryType.Layout: + await _router.Navigate($"workshop/layouts/{Entry.Id}"); + break; + case EntryType.Profile: + await _router.Navigate($"workshop/profiles/{Entry.Id}"); + break; + case EntryType.Plugin: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml deleted file mode 100644 index 13395d7b7..000000000 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - Downloads - Last updated - - - - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml.cs deleted file mode 100644 index 288da66ae..000000000 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryView.axaml.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace Artemis.UI.Screens.Workshop.Profile; - -public partial class ProfileListEntryView : UserControl -{ - public ProfileListEntryView() - { - InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryViewModel.cs deleted file mode 100644 index 67786214d..000000000 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListEntryViewModel.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Artemis.UI.Shared; -using Artemis.WebClient.Workshop; - -namespace Artemis.UI.Screens.Workshop.Profile; - -public class ProfileListEntryViewModel : ViewModelBase -{ - public ProfileListEntryViewModel(IGetEntries_Entries_Nodes entry) - { - Entry = entry; - } - - public IGetEntries_Entries_Nodes Entry { get; } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs index 76f1fa762..ecbdb28ff 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListViewModel.cs @@ -1,15 +1,18 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive.Disposables; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Screens.Workshop.Categories; +using Artemis.UI.Screens.Workshop.Entries; using Artemis.UI.Screens.Workshop.Parameters; using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; using DynamicData; +using DynamicData.Alias; using ReactiveUI; using StrawberryShake; @@ -21,21 +24,31 @@ public class ProfileListViewModel : RoutableScreen(); _entries.Connect() - .Transform(e => new ProfileListEntryViewModel(e)) - .Bind(out ReadOnlyObservableCollection observableEntries) + .Transform(e => new EntryListViewModel(e, router)) + .Bind(out ReadOnlyObservableCollection observableEntries) .Subscribe(); + + this.WhenActivated(d => + { + CategoriesViewModel._categories.Connect() + .AutoRefresh(c => c.IsSelected) + .Filter(e => e.IsSelected) + .Select(e => e.Id) + .Subscribe(_ => ReactiveCommand.CreateFromTask(GetEntries).Execute().Subscribe()) + .DisposeWith(d); + }); Entries = observableEntries; } public CategoriesViewModel CategoriesViewModel { get; } - public ReadOnlyObservableCollection Entries { get; set; } + public ReadOnlyObservableCollection Entries { get; set; } public int Page { @@ -64,7 +77,13 @@ public class ProfileListViewModel : RoutableScreen categories = CategoriesViewModel.Categories.Where(c => c.IsSelected).Select(c => (int?) c.Id).ToList(); + if (categories.Any()) + filter.Categories = new ListFilterInputTypeOfCategoryFilterInput {All = new CategoryFilterInput {Id = new IntOperationFilterInput {In = categories}}}; + + return filter; } public EntryType? EntryType => null; diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml index c4b5f5063..e46ea18ac 100644 --- a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml @@ -16,13 +16,13 @@ MaxWidth="500" Watermark="Search" Margin="0 5" - ValueMemberBinding="{CompiledBinding Name, DataType=workshop:ISearchEntries_Entries_Nodes}" + ValueMemberBinding="{CompiledBinding Name, DataType=workshop:ISearchEntries_SearchEntries}" AsyncPopulator="{CompiledBinding SearchAsync}" SelectedItem="{CompiledBinding SelectedEntry}" FilterMode="None" windowing:AppWindow.AllowInteractionInTitleBar="True"> - + diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs b/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs index 9d66eb0ba..b3370ee8b 100644 --- a/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchViewModel.cs @@ -18,7 +18,7 @@ public class SearchViewModel : ViewModelBase private readonly IRouter _router; private readonly IWorkshopClient _workshopClient; private EntryType? _entryType; - private ISearchEntries_Entries_Nodes? _selectedEntry; + private ISearchEntries_SearchEntries? _selectedEntry; public SearchViewModel(IWorkshopClient workshopClient, IRouter router, CurrentUserViewModel currentUserViewModel) { @@ -32,7 +32,7 @@ public class SearchViewModel : ViewModelBase public Func>> SearchAsync { get; } - public ISearchEntries_Entries_Nodes? SelectedEntry + public ISearchEntries_SearchEntries? SelectedEntry { get => _selectedEntry; set => RaiseAndSetIfChanged(ref _selectedEntry, value); @@ -44,7 +44,7 @@ public class SearchViewModel : ViewModelBase set => RaiseAndSetIfChanged(ref _entryType, value); } - private void NavigateToEntry(ISearchEntries_Entries_Nodes entry) + private void NavigateToEntry(ISearchEntries_SearchEntries entry) { string? url = null; if (entry.EntryType == WebClient.Workshop.EntryType.Profile) @@ -60,21 +60,8 @@ public class SearchViewModel : ViewModelBase { if (string.IsNullOrWhiteSpace(input)) return new List(); - - EntryFilterInput filter; - if (EntryType != null) - filter = new EntryFilterInput - { - And = new[] - { - new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = EntryType}}, - new EntryFilterInput {Name = new StringOperationFilterInput {Contains = input}} - } - }; - else - filter = new EntryFilterInput {Name = new StringOperationFilterInput {Contains = input}}; - - IOperationResult results = await _workshopClient.SearchEntries.ExecuteAsync(filter, cancellationToken); - return results.Data?.Entries?.Nodes?.Cast() ?? new List(); + + IOperationResult results = await _workshopClient.SearchEntries.ExecuteAsync(input, EntryType, cancellationToken); + return results.Data?.SearchEntries.Cast() ?? new List(); } } \ No newline at end of file diff --git a/src/Artemis.UI/Styles/TreeView.axaml b/src/Artemis.UI/Styles/TreeView.axaml index 754755713..0041e20fb 100644 --- a/src/Artemis.UI/Styles/TreeView.axaml +++ b/src/Artemis.UI/Styles/TreeView.axaml @@ -1,7 +1,6 @@  @@ -77,7 +76,7 @@ BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" MinHeight="{DynamicResource NavigationViewItemOnLeftMinHeight}" - CornerRadius="{DynamicResource OverlayCornerRadius}" + CornerRadius="{DynamicResource ControlCornerRadius}" TemplatedControl.IsTemplateFocusTarget="True" Margin="2"> diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql index dae8242c6..3ae3fc34b 100644 --- a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql +++ b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql @@ -1,10 +1,13 @@ query GetEntries($filter: EntryFilterInput) { entries(where: $filter) { nodes { + id author name summary entryType + downloads + createdAt categories { name icon diff --git a/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql index b2a03cf3f..620aeb70d 100644 --- a/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql +++ b/src/Artemis.WebClient.Workshop/Queries/SearchEntries.graphql @@ -1,18 +1,13 @@ -query SearchEntries($filter: EntryFilterInput) { - entries( - first: 10 - where: $filter - ) { - nodes { +query SearchEntries($input: String! $type: EntryType) { + searchEntries(input: $input type: $type) { + id + name + summary + entryType + categories { id name - summary - entryType - categories { - id - name - icon - } + icon } } } From cfb39b986d2758878e10e3d92ce664206fd2b61c Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 21 Jul 2023 22:11:35 +0200 Subject: [PATCH 08/13] Added pagination --- .../Controls/Pagination/Pagination.cs | 172 ++++++++++++++++++ .../Pagination/Pagination.properties.cs | 38 ++++ .../Controls/Pagination/PaginationEllipsis.cs | 10 + .../Controls/Pagination/PaginationPage.cs | 39 ++++ .../Pagination/PaginationStyles.axaml | 80 ++++++++ src/Artemis.UI.Shared/Styles/Artemis.axaml | 27 ++- 6 files changed, 356 insertions(+), 10 deletions(-) create mode 100644 src/Artemis.UI.Shared/Controls/Pagination/Pagination.cs create mode 100644 src/Artemis.UI.Shared/Controls/Pagination/Pagination.properties.cs create mode 100644 src/Artemis.UI.Shared/Controls/Pagination/PaginationEllipsis.cs create mode 100644 src/Artemis.UI.Shared/Controls/Pagination/PaginationPage.cs create mode 100644 src/Artemis.UI.Shared/Controls/Pagination/PaginationStyles.axaml diff --git a/src/Artemis.UI.Shared/Controls/Pagination/Pagination.cs b/src/Artemis.UI.Shared/Controls/Pagination/Pagination.cs new file mode 100644 index 000000000..26352ee17 --- /dev/null +++ b/src/Artemis.UI.Shared/Controls/Pagination/Pagination.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Metadata; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using Avalonia.Interactivity; +using ReactiveUI; + +namespace Artemis.UI.Shared.Pagination; + +/// +/// Represents a pagination control that can be used to switch between pages. +/// +[TemplatePart("PART_PreviousButton", typeof(Button))] +[TemplatePart("PART_NextButton", typeof(Button))] +[TemplatePart("PART_PagesView", typeof(StackPanel))] +public partial class Pagination : TemplatedControl +{ + /// + public Pagination() + { + PropertyChanged += OnPropertyChanged; + } + + public Button? PreviousButton { get; set; } + public Button? NextButton { get; set; } + public StackPanel? PagesView { get; set; } + + /// + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + if (PreviousButton != null) + PreviousButton.Click -= PreviousButtonOnClick; + if (NextButton != null) + NextButton.Click -= NextButtonOnClick; + + PreviousButton = e.NameScope.Find + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml.cs index 42a7b86ad..4ce9dc9dd 100644 --- a/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryListView.axaml.cs @@ -16,9 +16,4 @@ public partial class EntryListView : ReactiveUserControl { AvaloniaXamlLoader.Load(this); } - - private async void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e) - { - await ViewModel.NavigateToEntry(); - } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntryListViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntryListViewModel.cs index dc393b80c..0691c5b53 100644 --- a/src/Artemis.UI/Screens/Workshop/Entries/EntryListViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Entries/EntryListViewModel.cs @@ -1,8 +1,10 @@ using System; +using System.Reactive; using System.Threading.Tasks; using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; +using ReactiveUI; namespace Artemis.UI.Screens.Workshop.Entries; @@ -14,11 +16,13 @@ public class EntryListViewModel : ViewModelBase { _router = router; Entry = entry; + NavigateToEntry = ReactiveCommand.CreateFromTask(ExecuteNavigateToEntry); } public IGetEntries_Entries_Items Entry { get; } + public ReactiveCommand NavigateToEntry { get; } - public async Task NavigateToEntry() + private async Task ExecuteNavigateToEntry() { switch (Entry.EntryType) { diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml index a22fc4448..b94899712 100644 --- a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml @@ -4,55 +4,78 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:home="clr-namespace:Artemis.UI.Screens.Workshop.Home" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + xmlns:controls="clr-namespace:Artemis.UI.Controls" + xmlns:acrylicBlur="clr-namespace:Artemis.UI.Controls.AcrylicBlur" + mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800" x:Class="Artemis.UI.Screens.Workshop.Home.WorkshopHomeView" x:DataType="home:WorkshopHomeViewModel"> - - + - - - - - - - - - + Source="/Assets/Images/workshop-banner.jpg" + Height="200" + Stretch="UniformToFill" + RenderOptions.BitmapInterpolationMode="HighQuality"> + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Test + + + - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml index 586bcdd75..3ae086124 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileListView.axaml @@ -16,20 +16,10 @@ - - - Filters - - - - - - - - - - + + + @@ -41,6 +31,7 @@ , IWorkshopViewModel { private readonly IRouter _router; + private readonly INotificationService _notificationService; private readonly IWorkshopClient _workshopClient; private readonly ObservableAsPropertyHelper _showPagination; + private readonly ObservableAsPropertyHelper _isLoading; private List? _entries; private int _page; + private int _loadedPage = -1; private int _totalPages = 1; - private int _entriesPerPage = 5; + private int _entriesPerPage = 10; - public ProfileListViewModel(IWorkshopClient workshopClient, IRouter router, CategoriesViewModel categoriesViewModel) + public ProfileListViewModel(IWorkshopClient workshopClient, IRouter router, CategoriesViewModel categoriesViewModel, INotificationService notificationService) { _workshopClient = workshopClient; _router = router; + _notificationService = notificationService; _showPagination = this.WhenAnyValue(vm => vm.TotalPages).Select(t => t > 1).ToProperty(this, vm => vm.ShowPagination); - + _isLoading = this.WhenAnyValue(vm => vm.Page, vm => vm.LoadedPage, (p, c) => p != c).ToProperty(this, vm => vm.IsLoading); + CategoriesViewModel = categoriesViewModel; // Respond to page changes @@ -49,6 +56,8 @@ public class ProfileListViewModel : RoutableScreen _showPagination.Value; + public bool IsLoading => _isLoading.Value; + public CategoriesViewModel CategoriesViewModel { get; } public List? Entries @@ -63,6 +72,12 @@ public class ProfileListViewModel : RoutableScreen RaiseAndSetIfChanged(ref _page, value); } + public int LoadedPage + { + get => _loadedPage; + set => RaiseAndSetIfChanged(ref _loadedPage, value); + } + public int TotalPages { get => _totalPages; @@ -78,25 +93,42 @@ public class ProfileListViewModel : RoutableScreen entries = await _workshopClient.GetEntries.ExecuteAsync(filter, EntriesPerPage * (Page - 1), EntriesPerPage, cancellationToken); - if (!entries.IsErrorResult() && entries.Data?.Entries?.Items != null) + try { - Entries = entries.Data.Entries.Items.Select(n => new EntryListViewModel(n, _router)).ToList(); - TotalPages = (int) Math.Ceiling(entries.Data.Entries.TotalCount / (double) EntriesPerPage); + EntryFilterInput filter = GetFilter(); + IOperationResult entries = await _workshopClient.GetEntries.ExecuteAsync(filter, EntriesPerPage * (Page - 1), EntriesPerPage, cancellationToken); + entries.EnsureNoErrors(); + + if (entries.Data?.Entries?.Items != null) + { + Entries = entries.Data.Entries.Items.Select(n => new EntryListViewModel(n, _router)).ToList(); + TotalPages = (int) Math.Ceiling(entries.Data.Entries.TotalCount / (double) EntriesPerPage); + } + else + TotalPages = 1; + } + catch (Exception e) + { + _notificationService.CreateNotification() + .WithTitle("Failed to load entries") + .WithMessage(e.Message) + .WithSeverity(NotificationSeverity.Error) + .Show(); + } + finally + { + LoadedPage = Page; } - else - TotalPages = 1; } private EntryFilterInput GetFilter() diff --git a/src/Artemis.UI/Styles/Artemis.axaml b/src/Artemis.UI/Styles/Artemis.axaml index a121ec71b..8e62c47f2 100644 --- a/src/Artemis.UI/Styles/Artemis.axaml +++ b/src/Artemis.UI/Styles/Artemis.axaml @@ -13,6 +13,7 @@ + From ee6d295fd840f3f07719982062407183f703122f Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 26 Jul 2023 22:13:40 +0200 Subject: [PATCH 11/13] Upgrade Avalonia --- src/Artemis.UI.Linux/App.axaml.cs | 11 +- src/Artemis.UI.Shared/ReactiveAppWindow.cs | 59 +++----- src/Artemis.UI.Shared/Utilities.cs | 38 +++-- src/Artemis.UI.Windows/App.axaml.cs | 9 +- src/Artemis.UI/Artemis.UI.csproj | 5 + .../Controls/AcrylicBlur/AcrylicBlur.axaml | 22 --- .../Controls/AcrylicBlur/AcrylicBlur.cs | 45 ------ .../AcrylicBlur/AcrylicBlurRenderOperation.cs | 138 ------------------ src/Artemis.UI/MainWindow.axaml | 2 +- src/Artemis.UI/Screens/Root/RootViewModel.cs | 9 +- .../Settings/Tabs/GeneralTabView.axaml | 13 ++ .../Settings/Tabs/GeneralTabViewModel.cs | 10 +- .../CurrentUser/CurrentUserView.axaml | 6 +- .../Workshop/Home/WorkshopHomeView.axaml | 71 +++++---- .../Workshop/Home/WorkshopHomeViewModel.cs | 19 ++- .../Screens/Workshop/Search/SearchView.axaml | 2 + .../Steps/WelcomeStepView.axaml | 11 ++ .../Steps/WelcomeStepView.axaml.cs | 17 +++ .../Steps/WelcomeStepViewModel.cs | 22 +++ .../SubmissionWizardView.axaml | 56 +++++++ .../SubmissionWizardView.axaml.cs | 33 +++++ .../SubmissionWizardViewModel.cs | 47 ++++++ src/Artemis.UI/Styles/Artemis.axaml | 1 - src/Artemis.props | 2 +- 24 files changed, 337 insertions(+), 311 deletions(-) delete mode 100644 src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlur.axaml delete mode 100644 src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlur.cs delete mode 100644 src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlurRenderOperation.cs create mode 100644 src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepViewModel.cs create mode 100644 src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs diff --git a/src/Artemis.UI.Linux/App.axaml.cs b/src/Artemis.UI.Linux/App.axaml.cs index 52f729727..88f0f8179 100644 --- a/src/Artemis.UI.Linux/App.axaml.cs +++ b/src/Artemis.UI.Linux/App.axaml.cs @@ -1,3 +1,4 @@ +using System; using Artemis.Core.Services; using Artemis.UI.Linux.DryIoc; using Artemis.UI.Linux.Providers.Input; @@ -26,15 +27,11 @@ public class App : Application public override void OnFrameworkInitializationCompleted() { - if (Design.IsDesignMode) + if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || Design.IsDesignMode) return; - - if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) - return; - - ArtemisBootstrapper.Initialize(); - _applicationStateManager = new ApplicationStateManager(_container!, desktop.Args); + _applicationStateManager = new ApplicationStateManager(_container!, desktop.Args ?? Array.Empty()); + ArtemisBootstrapper.Initialize(); RegisterProviders(); } diff --git a/src/Artemis.UI.Shared/ReactiveAppWindow.cs b/src/Artemis.UI.Shared/ReactiveAppWindow.cs index a751f4ee6..c943cbbfe 100644 --- a/src/Artemis.UI.Shared/ReactiveAppWindow.cs +++ b/src/Artemis.UI.Shared/ReactiveAppWindow.cs @@ -1,4 +1,5 @@ using System; +using System.Reactive.Disposables; using System.Runtime.InteropServices; using Avalonia; using Avalonia.Controls; @@ -26,6 +27,8 @@ public class ReactiveAppWindow : AppWindow, IViewFor whe public static readonly StyledProperty ViewModelProperty = AvaloniaProperty .Register, TViewModel?>(nameof(ViewModel)); + private bool _micaEnabled; + /// /// Initializes a new instance of the class. /// @@ -33,23 +36,33 @@ public class ReactiveAppWindow : AppWindow, IViewFor whe { // This WhenActivated block calls ViewModel's WhenActivated // block if the ViewModel implements IActivatableViewModel. - this.WhenActivated(disposables => { }); + this.WhenActivated(disposables => UI.MicaEnabled.Subscribe(ToggleMica).DisposeWith(disposables)); this.GetObservable(DataContextProperty).Subscribe(OnDataContextChanged); this.GetObservable(ViewModelProperty).Subscribe(OnViewModelChanged); } - /// - protected override void OnOpened(EventArgs e) + private void ToggleMica(bool enable) { - // TODO: Move to a style and remove opacity on focus loss - base.OnOpened(e); - - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || !IsWindows11) + if (enable == _micaEnabled) return; - TransparencyBackgroundFallback = Brushes.Transparent; - TransparencyLevelHint = new[] {WindowTransparencyLevel.Mica}; - TryEnableMicaEffect(); + if (enable) + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || !IsWindows11) + return; + + // TransparencyBackgroundFallback = Brushes.Transparent; + TransparencyLevelHint = new[] {WindowTransparencyLevel.Mica}; + Background = new SolidColorBrush(new Color(80, 0,0,0)); + + } + else + { + ClearValue(TransparencyLevelHintProperty); + ClearValue(BackgroundProperty); + } + + _micaEnabled = enable; } private void OnDataContextChanged(object? value) @@ -67,32 +80,6 @@ public class ReactiveAppWindow : AppWindow, IViewFor whe else if (DataContext != value) DataContext = value; } - private void TryEnableMicaEffect() - { - // The background colors for the Mica brush are still based around SolidBackgroundFillColorBase resource - // BUT since we can't control the actual Mica brush color, we have to use the window background to create - // the same effect. However, we can't use SolidBackgroundFillColorBase directly since its opaque, and if - // we set the opacity the color become lighter than we want. So we take the normal color, darken it and - // apply the opacity until we get the roughly the correct color - // NOTE that the effect still doesn't look right, but it suffices. Ideally we need access to the Mica - // CompositionBrush to properly change the color but I don't know if we can do that or not - if (ActualThemeVariant == ThemeVariant.Dark) - { - Color2 color = this.TryFindResource("SolidBackgroundFillColorBase", ThemeVariant.Dark, out object? value) ? (Color) value : new Color2(32, 32, 32); - color = color.LightenPercent(-0.5f); - - Background = new ImmutableSolidColorBrush(color, 0.78); - } - else if (ActualThemeVariant == ThemeVariant.Light) - { - // Similar effect here - Color2 color = this.TryFindResource("SolidBackgroundFillColorBase", ThemeVariant.Light, out object? value) ? (Color) value : new Color2(243, 243, 243); - color = color.LightenPercent(0.5f); - - Background = new ImmutableSolidColorBrush(color, 0.9); - } - } - /// /// The ViewModel. /// diff --git a/src/Artemis.UI.Shared/Utilities.cs b/src/Artemis.UI.Shared/Utilities.cs index 344aa4834..3b1c58495 100644 --- a/src/Artemis.UI.Shared/Utilities.cs +++ b/src/Artemis.UI.Shared/Utilities.cs @@ -1,29 +1,29 @@ using System; using System.Reactive.Concurrency; using System.Reactive.Linq; +using System.Reactive.Subjects; using System.Threading; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Input.Platform; -using IContainer = DryIoc.IContainer; +using Avalonia.Threading; +using DryIoc; namespace Artemis.UI.Shared; /// -/// Static UI helpers. +/// Static UI helpers. /// public static class UI { + private static readonly BehaviorSubject MicaEnabledSubject = new(false); + + public static EventLoopScheduler BackgroundScheduler = new(ts => new Thread(ts)); + static UI() { KeyBindingsEnabled = InputElement.GotFocusEvent.Raised.Select(e => e.Item2.Source is not TextBox).StartWith(true); - } - - public static EventLoopScheduler BackgroundScheduler = new EventLoopScheduler(ts => new Thread(ts)); - - internal static void ClearCache() - { - DeviceVisualizer.BitmapCache.Clear(); + MicaEnabled = MicaEnabledSubject.AsObservable(); } /// @@ -40,4 +40,24 @@ public static class UI /// Gets a boolean indicating whether hotkeys are to be disabled. /// public static IObservable KeyBindingsEnabled { get; } + + /// + /// Gets a boolean indicating whether the Mica effect should be enabled. + /// + public static IObservable MicaEnabled { get; } + + /// + /// Changes whether Mica should be enabled. + /// + /// + public static void SetMicaEnabled(bool enabled) + { + if (MicaEnabledSubject.Value != enabled) + Dispatcher.UIThread.Invoke(() => MicaEnabledSubject.OnNext(enabled)); + } + + internal static void ClearCache() + { + DeviceVisualizer.BitmapCache.Clear(); + } } \ No newline at end of file diff --git a/src/Artemis.UI.Windows/App.axaml.cs b/src/Artemis.UI.Windows/App.axaml.cs index 617858fb9..9854a1ca5 100644 --- a/src/Artemis.UI.Windows/App.axaml.cs +++ b/src/Artemis.UI.Windows/App.axaml.cs @@ -43,8 +43,8 @@ public class App : Application { if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || Design.IsDesignMode || _shutDown) return; - - _applicationStateManager = new ApplicationStateManager(_container!, desktop.Args); + + _applicationStateManager = new ApplicationStateManager(_container!, desktop.Args ?? Array.Empty()); ArtemisBootstrapper.Initialize(); RegisterProviders(_container!); } @@ -52,11 +52,14 @@ public class App : Application private void RegisterProviders(IContainer container) { IInputService inputService = container.Resolve(); - inputService.AddInputProvider(container.Resolve(serviceKey: WindowsInputProvider.Id)); + inputService.AddInputProvider(container.Resolve(WindowsInputProvider.Id)); } private bool FocusExistingInstance() { + if (Design.IsDesignMode) + return false; + _artemisMutex = new Mutex(true, "Artemis-3c24b502-64e6-4587-84bf-9072970e535f", out bool createdNew); return !createdNew && RemoteFocus(); } diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 5da497f13..be43581c5 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -54,6 +54,7 @@ + @@ -61,5 +62,9 @@ ProfileListEntryView.axaml Code + + StartupWizardView.axaml + Code + \ No newline at end of file diff --git a/src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlur.axaml b/src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlur.axaml deleted file mode 100644 index ee706785b..000000000 --- a/src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlur.axaml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlur.cs b/src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlur.cs deleted file mode 100644 index 721ce1ebf..000000000 --- a/src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlur.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Media; - -namespace Artemis.UI.Controls.AcrylicBlur; - -public class AcrylicBlur : ContentControl -{ - private static readonly ImmutableExperimentalAcrylicMaterial DefaultAcrylicMaterial = (ImmutableExperimentalAcrylicMaterial) new ExperimentalAcrylicMaterial() - { - MaterialOpacity = 0.1, - TintColor = new Color(255, 7, 7, 7), - TintOpacity = 1, - PlatformTransparencyCompensationLevel = 0 - }.ToImmutable(); - - public static readonly StyledProperty MaterialProperty = - AvaloniaProperty.Register(nameof(Material)); - - public ExperimentalAcrylicMaterial? Material - { - get => GetValue(MaterialProperty); - set => SetValue(MaterialProperty, value); - } - - public static readonly StyledProperty BlurProperty = AvaloniaProperty.Register(nameof(Blur)); - - public int Blur - { - get => GetValue(BlurProperty); - set => SetValue(BlurProperty, value); - } - - static AcrylicBlur() - { - AffectsRender(MaterialProperty); - AffectsRender(BlurProperty); - } - - public override void Render(DrawingContext context) - { - ImmutableExperimentalAcrylicMaterial mat = Material != null ? (ImmutableExperimentalAcrylicMaterial) Material.ToImmutable() : DefaultAcrylicMaterial; - context.Custom(new AcrylicBlurRenderOperation(this, mat, Blur, new Rect(default, Bounds.Size))); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlurRenderOperation.cs b/src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlurRenderOperation.cs deleted file mode 100644 index 326c9aefa..000000000 --- a/src/Artemis.UI/Controls/AcrylicBlur/AcrylicBlurRenderOperation.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.IO; -using Avalonia; -using Avalonia.Media; -using Avalonia.Platform; -using Avalonia.Rendering.SceneGraph; -using Avalonia.Skia; -using Avalonia.Threading; -using SkiaSharp; - -namespace Artemis.UI.Controls.AcrylicBlur; - -public class AcrylicBlurRenderOperation : ICustomDrawOperation -{ - private static SKShader? _acrylicNoiseShader; - - private readonly AcrylicBlur _acrylicBlur; - private readonly ImmutableExperimentalAcrylicMaterial _material; - private readonly int _blur; - private readonly Rect _bounds; - private SKImage? _backgroundSnapshot; - private bool _disposed; - - public AcrylicBlurRenderOperation(AcrylicBlur acrylicBlur, ImmutableExperimentalAcrylicMaterial material, int blur, Rect bounds) - { - _acrylicBlur = acrylicBlur; - _material = material; - _blur = blur; - _bounds = bounds; - } - - public void Dispose() - { - if (_disposed) - return; - - _backgroundSnapshot?.Dispose(); - _disposed = true; - } - - public bool HitTest(Point p) => _bounds.Contains(p); - - static SKColorFilter CreateAlphaColorFilter(double opacity) - { - if (opacity > 1) - opacity = 1; - byte[] c = new byte[256]; - byte[] a = new byte[256]; - for (int i = 0; i < 256; i++) - { - c[i] = (byte) i; - a[i] = (byte) (i * opacity); - } - - return SKColorFilter.CreateTable(a, c, c, c); - } - - public void Render(ImmediateDrawingContext context) - { - if (_disposed) - throw new ObjectDisposedException(nameof(AcrylicBlurRenderOperation)); - - ISkiaSharpApiLeaseFeature? leaseFeature = context.PlatformImpl.GetFeature(); - if (leaseFeature == null) - return; - using ISkiaSharpApiLease lease = leaseFeature.Lease(); - - if (!lease.SkCanvas.TotalMatrix.TryInvert(out SKMatrix currentInvertedTransform) || lease.SkSurface == null) - return; - - if (lease.SkCanvas.GetLocalClipBounds(out SKRect bounds) && !bounds.Contains(SKRect.Create(bounds.Left, bounds.Top, (float) _acrylicBlur.Bounds.Width, (float) _acrylicBlur.Bounds.Height))) - { - Dispatcher.UIThread.Invoke(() => _acrylicBlur.InvalidateVisual()); - } - else - { - _backgroundSnapshot?.Dispose(); - _backgroundSnapshot = lease.SkSurface.Snapshot(); - } - - _backgroundSnapshot ??= lease.SkSurface.Snapshot(); - using SKShader? backdropShader = SKShader.CreateImage(_backgroundSnapshot, SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, currentInvertedTransform); - using SKSurface? blurred = SKSurface.Create( - lease.GrContext, - false, - new SKImageInfo((int) Math.Ceiling(_bounds.Width), (int) Math.Ceiling(_bounds.Height), SKImageInfo.PlatformColorType, SKAlphaType.Premul) - ); - using (SKImageFilter? filter = SKImageFilter.CreateBlur(_blur, _blur, SKShaderTileMode.Clamp)) - using (SKPaint blurPaint = new SKPaint {Shader = backdropShader, ImageFilter = filter}) - { - blurred.Canvas.DrawRect(0, 0, (float) _bounds.Width, (float) _bounds.Height, blurPaint); - - using (SKImage? blurSnap = blurred.Snapshot()) - using (SKShader? blurSnapShader = SKShader.CreateImage(blurSnap)) - using (SKPaint blurSnapPaint = new SKPaint {Shader = blurSnapShader, IsAntialias = true}) - { - // Rendering twice to reduce opacity - lease.SkCanvas.DrawRect(0, 0, (float) _bounds.Width, (float) _bounds.Height, blurSnapPaint); - lease.SkCanvas.DrawRect(0, 0, (float) _bounds.Width, (float) _bounds.Height, blurSnapPaint); - } - - //return; - using SKPaint acrylliPaint = new SKPaint(); - acrylliPaint.IsAntialias = true; - - double opacity = 1; - - const double noiseOpacity = 0.0225; - - Color tintColor = _material.TintColor; - SKColor tint = new SKColor(tintColor.R, tintColor.G, tintColor.B, tintColor.A); - - if (_acrylicNoiseShader == null) - { - using Stream? stream = typeof(SkiaPlatform).Assembly.GetManifestResourceStream("Avalonia.Skia.Assets.NoiseAsset_256X256_PNG.png"); - using SKBitmap? bitmap = SKBitmap.Decode(stream); - _acrylicNoiseShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat).WithColorFilter(CreateAlphaColorFilter(noiseOpacity)); - } - - using (SKShader? backdrop = SKShader.CreateColor(new SKColor(_material.MaterialColor.R, _material.MaterialColor.G, _material.MaterialColor.B, _material.MaterialColor.A))) - using (SKShader? tintShader = SKShader.CreateColor(tint)) - using (SKShader? effectiveTint = SKShader.CreateCompose(backdrop, tintShader)) - using (SKShader? compose = SKShader.CreateCompose(effectiveTint, _acrylicNoiseShader)) - { - acrylliPaint.Shader = compose; - acrylliPaint.IsAntialias = true; - lease.SkCanvas.DrawRect(0, 0, (float) _bounds.Width, (float) _bounds.Height, acrylliPaint); - } - } - } - - public Rect Bounds => _bounds.Inflate(4); - - public bool Equals(ICustomDrawOperation? other) - { - return other is AcrylicBlurRenderOperation op && op._bounds == _bounds && op._material.Equals(_material); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/MainWindow.axaml b/src/Artemis.UI/MainWindow.axaml index bff2c07c9..f91d7815a 100644 --- a/src/Artemis.UI/MainWindow.axaml +++ b/src/Artemis.UI/MainWindow.axaml @@ -10,7 +10,7 @@ Icon="/Assets/Images/Logo/application.ico" Title="Artemis 2.0" MinWidth="600" - MinHeight="400" + MinHeight="400" PointerReleased="InputElement_OnPointerReleased"> diff --git a/src/Artemis.UI/Screens/Root/RootViewModel.cs b/src/Artemis.UI/Screens/Root/RootViewModel.cs index ebc64a565..828b080ae 100644 --- a/src/Artemis.UI/Screens/Root/RootViewModel.cs +++ b/src/Artemis.UI/Screens/Root/RootViewModel.cs @@ -20,11 +20,11 @@ namespace Artemis.UI.Screens.Root; public class RootViewModel : RoutableScreen, IMainWindowProvider { - private readonly IRouter _router; private readonly ICoreService _coreService; private readonly IDebugService _debugService; private readonly DefaultTitleBarViewModel _defaultTitleBarViewModel; private readonly IClassicDesktopStyleApplicationLifetime _lifeTime; + private readonly IRouter _router; private readonly ISettingsService _settingsService; private readonly IUpdateService _updateService; private readonly IWindowService _windowService; @@ -41,6 +41,7 @@ public class RootViewModel : RoutableScreen, IMainWindowPr SidebarViewModel sidebarViewModel, DefaultTitleBarViewModel defaultTitleBarViewModel) { + Shared.UI.SetMicaEnabled(settingsService.GetSetting("UI.EnableMica", true).Value); WindowSizeSetting = settingsService.GetSetting("WindowSize"); SidebarViewModel = sidebarViewModel; @@ -61,7 +62,7 @@ public class RootViewModel : RoutableScreen, IMainWindowPr OpenDebugger = ReactiveCommand.CreateFromTask(ExecuteOpenDebugger); Exit = ReactiveCommand.CreateFromTask(ExecuteExit); this.WhenAnyValue(vm => vm.Screen).Subscribe(UpdateTitleBarViewModel); - + Task.Run(() => { if (_updateService.Initialize()) @@ -85,6 +86,8 @@ public class RootViewModel : RoutableScreen, IMainWindowPr set => RaiseAndSetIfChanged(ref _titleBarViewModel, value); } + public static PluginSetting? WindowSizeSetting { get; private set; } + public void GoBack() { _router.GoBack(); @@ -95,8 +98,6 @@ public class RootViewModel : RoutableScreen, IMainWindowPr _router.GoForward(); } - public static PluginSetting? WindowSizeSetting { get; private set; } - private void UpdateTitleBarViewModel(IMainScreenViewModel? viewModel) { if (viewModel?.TitleBarViewModel != null) diff --git a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml index 9d2fd980c..c2c394214 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml @@ -44,6 +44,19 @@ + + + + Enable Mica effect + + The Mica effect is the semi-transparent effect used by the application window, the colors are based on your wallpaper. + + + + + + + diff --git a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs index 5121af0f5..ca707b9e3 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs @@ -30,9 +30,9 @@ public class GeneralTabViewModel : ActivatableViewModelBase private readonly IAutoRunProvider? _autoRunProvider; private readonly IDebugService _debugService; private readonly PluginSetting _defaultLayerBrushDescriptor; + private readonly INotificationService _notificationService; private readonly ISettingsService _settingsService; private readonly IUpdateService _updateService; - private readonly INotificationService _notificationService; private readonly IWindowService _windowService; private bool _startupWizardOpen; @@ -74,12 +74,14 @@ public class GeneralTabViewModel : ActivatableViewModelBase { UIAutoRun.SettingChanged += UIAutoRunOnSettingChanged; UIAutoRunDelay.SettingChanged += UIAutoRunDelayOnSettingChanged; + EnableMica.SettingChanged += EnableMicaOnSettingChanged; Dispatcher.UIThread.InvokeAsync(ApplyAutoRun); Disposable.Create(() => { UIAutoRun.SettingChanged -= UIAutoRunOnSettingChanged; UIAutoRunDelay.SettingChanged -= UIAutoRunDelayOnSettingChanged; + EnableMica.SettingChanged -= EnableMicaOnSettingChanged; _settingsService.SaveAllSettings(); }).DisposeWith(d); @@ -146,6 +148,7 @@ public class GeneralTabViewModel : ActivatableViewModelBase public PluginSetting UIAutoRun => _settingsService.GetSetting("UI.AutoRun", false); public PluginSetting UIAutoRunDelay => _settingsService.GetSetting("UI.AutoRunDelay", 15); public PluginSetting UIShowOnStartup => _settingsService.GetSetting("UI.ShowOnStartup", true); + public PluginSetting EnableMica => _settingsService.GetSetting("UI.EnableMica", true); public PluginSetting UICheckForUpdates => _settingsService.GetSetting("UI.Updating.AutoCheck", true); public PluginSetting UIAutoUpdate => _settingsService.GetSetting("UI.Updating.AutoInstall", true); public PluginSetting ProfileEditorShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); @@ -238,4 +241,9 @@ public class GeneralTabViewModel : ActivatableViewModelBase _windowService.ShowExceptionDialog("Failed to apply auto-run", exception); } } + + private void EnableMicaOnSettingChanged(object? sender, EventArgs e) + { + Shared.UI.SetMicaEnabled(EnableMica.Value); + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml index 9487ac4eb..2b28230f7 100644 --- a/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml +++ b/src/Artemis.UI/Screens/Workshop/CurrentUser/CurrentUserView.axaml @@ -9,9 +9,9 @@ x:Class="Artemis.UI.Screens.Workshop.CurrentUser.CurrentUserView" x:DataType="currentUser:CurrentUserViewModel"> - + - + @@ -27,7 +27,7 @@ - + diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml index b94899712..d0717860f 100644 --- a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeView.axaml @@ -4,8 +4,6 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:home="clr-namespace:Artemis.UI.Screens.Workshop.Home" - xmlns:controls="clr-namespace:Artemis.UI.Controls" - xmlns:acrylicBlur="clr-namespace:Artemis.UI.Controls.AcrylicBlur" mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800" x:Class="Artemis.UI.Screens.Workshop.Home.WorkshopHomeView" x:DataType="home:WorkshopHomeViewModel"> @@ -39,43 +37,42 @@ - - - - - - + + + + + - - - - - + + + + + + Featured submissions + Not yet implemented, here we'll show submissions we think are worth some extra attention. + + Recently updated + Not yet implemented, here we'll a few of the most recent uploads/updates to the workshop. - - - - - - - - - - Test - - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeViewModel.cs b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeViewModel.cs index 863df049a..67391c0bd 100644 --- a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeViewModel.cs @@ -1,6 +1,10 @@ using System.Reactive; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Screens.Workshop.SubmissionWizard; using Artemis.UI.Shared; using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Services; using Artemis.WebClient.Workshop; using ReactiveUI; @@ -8,13 +12,22 @@ namespace Artemis.UI.Screens.Workshop.Home; public class WorkshopHomeViewModel : ActivatableViewModelBase, IWorkshopViewModel { - public WorkshopHomeViewModel(IRouter router) + private readonly IWindowService _windowService; + + public WorkshopHomeViewModel(IRouter router, IWindowService windowService) { + _windowService = windowService; + AddSubmission = ReactiveCommand.CreateFromTask(ExecuteAddSubmission); Navigate = ReactiveCommand.CreateFromTask(async r => await router.Navigate(r)); } - public ReactiveCommand Navigate { get; set; } + public ReactiveCommand AddSubmission { get; } + public ReactiveCommand Navigate { get; } + + private async Task ExecuteAddSubmission(CancellationToken arg) + { + await _windowService.ShowDialogAsync(); + } public EntryType? EntryType => null; - } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml index e46ea18ac..171d4c400 100644 --- a/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Search/SearchView.axaml @@ -48,6 +48,8 @@ diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml new file mode 100644 index 000000000..7341a2307 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml @@ -0,0 +1,11 @@ + + + Welcome to the Workshop Submission Wizard 🧙 + Here we'll take you, step by step, through the process of uploading your submission to the workshop. + + diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml.cs new file mode 100644 index 000000000..9de30c623 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public partial class WelcomeStepView : ReactiveUserControl +{ + public WelcomeStepView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepViewModel.cs new file mode 100644 index 000000000..cf70f6410 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/WelcomeStepViewModel.cs @@ -0,0 +1,22 @@ +using System.Reactive; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; + +public class WelcomeStepViewModel : SubmissionViewModel +{ + #region Overrides of SubmissionViewModel + + /// + public override ReactiveCommand Continue { get; } + + /// + public override ReactiveCommand GoBack { get; } = null!; + + public WelcomeStepViewModel() + { + ShowGoBack = false; + } + + #endregion +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml new file mode 100644 index 000000000..18315e3fc --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs new file mode 100644 index 000000000..58dade5ef --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs @@ -0,0 +1,33 @@ +using System; +using System.Reactive.Disposables; +using Artemis.UI.Shared; +using Avalonia; +using Avalonia.Threading; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard; + +public partial class SubmissionWizardView : ReactiveAppWindow +{ + public SubmissionWizardView() + { + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + + this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen).Subscribe(Navigate).DisposeWith(d)); + } + + private void Navigate(SubmissionViewModel viewModel) + { + try + { + Dispatcher.UIThread.Invoke(() => Frame.NavigateFromObject(viewModel)); + } + catch (Exception) + { + // ignored + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs new file mode 100644 index 000000000..fed2c3241 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs @@ -0,0 +1,47 @@ +using System.Reactive; +using Artemis.UI.Screens.Workshop.CurrentUser; +using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps; +using Artemis.UI.Shared; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.SubmissionWizard; + +public class SubmissionWizardViewModel : DialogViewModelBase +{ + private SubmissionViewModel _screen; + + public SubmissionWizardViewModel(CurrentUserViewModel currentUserViewModel) + { + _screen = new WelcomeStepViewModel(); + CurrentUserViewModel = currentUserViewModel; + } + + public CurrentUserViewModel CurrentUserViewModel { get; } + + public SubmissionViewModel Screen + { + get => _screen; + set => RaiseAndSetIfChanged(ref _screen, value); + } +} + +public abstract class SubmissionViewModel : ActivatableViewModelBase +{ + private bool _showFinish; + private bool _showGoBack = true; + + public abstract ReactiveCommand Continue { get; } + public abstract ReactiveCommand GoBack { get; } + + public bool ShowGoBack + { + get => _showGoBack; + set => RaiseAndSetIfChanged(ref _showGoBack, value); + } + + public bool ShowFinish + { + get => _showFinish; + set => RaiseAndSetIfChanged(ref _showFinish, value); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Styles/Artemis.axaml b/src/Artemis.UI/Styles/Artemis.axaml index 8e62c47f2..a121ec71b 100644 --- a/src/Artemis.UI/Styles/Artemis.axaml +++ b/src/Artemis.UI/Styles/Artemis.axaml @@ -13,7 +13,6 @@ - diff --git a/src/Artemis.props b/src/Artemis.props index 121967a89..8bbeacbcb 100644 --- a/src/Artemis.props +++ b/src/Artemis.props @@ -1,6 +1,6 @@ - 11.0.0 + 11.0.1 2.0.0 2.0.0-prerelease.83 2.88.3 From 66f263ff2ad7d835c8148c18b1f0cd31b341fae6 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 27 Jul 2023 20:15:52 +0200 Subject: [PATCH 12/13] Gradient picker - Fixed selecting stops in the top part of the picker --- src/Artemis.UI.Shared/Styles/Controls/GradientPicker.axaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Artemis.UI.Shared/Styles/Controls/GradientPicker.axaml b/src/Artemis.UI.Shared/Styles/Controls/GradientPicker.axaml index ce985c2c6..a4744f59a 100644 --- a/src/Artemis.UI.Shared/Styles/Controls/GradientPicker.axaml +++ b/src/Artemis.UI.Shared/Styles/Controls/GradientPicker.axaml @@ -106,7 +106,7 @@ + GradientPicker="{CompiledBinding $parent[gradientPicker:GradientPicker]}"> @@ -207,7 +207,7 @@ From 02798b6d6e223aad30eddb207cae2a82aff5909b Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 27 Jul 2023 20:16:02 +0200 Subject: [PATCH 13/13] Routing - Added missing XAML comments to public types --- .../Routing/Route/IRouterRegistration.cs | 25 +++++++++++++++ .../ParameterParsers/IRouteParameterParser.cs | 16 ++++++++++ src/Artemis.UI.Shared/Routing/Route/Route.cs | 14 ++++++++ .../Routing/Route/RouteRegistration.cs | 21 ++++++------ .../Routing/Route/RouteSegment.cs | 32 +++++++++++++++++++ 5 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 src/Artemis.UI.Shared/Routing/Route/IRouterRegistration.cs diff --git a/src/Artemis.UI.Shared/Routing/Route/IRouterRegistration.cs b/src/Artemis.UI.Shared/Routing/Route/IRouterRegistration.cs new file mode 100644 index 000000000..941bb43e3 --- /dev/null +++ b/src/Artemis.UI.Shared/Routing/Route/IRouterRegistration.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; + +namespace Artemis.UI.Shared.Routing; + +/// +/// Represents a registration for a route. +/// +public interface IRouterRegistration +{ + /// + /// Gets the route associated with this registration. + /// + Route Route { get; } + + /// + /// Gets the type of the view model associated with the route. + /// + Type ViewModel { get; } + + /// + /// Gets or sets the child registrations of this route. + /// + List Children { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/IRouteParameterParser.cs b/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/IRouteParameterParser.cs index 5851418e8..02ed8f21b 100644 --- a/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/IRouteParameterParser.cs +++ b/src/Artemis.UI.Shared/Routing/Route/ParameterParsers/IRouteParameterParser.cs @@ -1,7 +1,23 @@ namespace Artemis.UI.Shared.Routing.ParameterParsers; +/// +/// Represents a contract for parsing route parameters. +/// public interface IRouteParameterParser { + /// + /// Checks if the given segment matches the provided source. + /// + /// The route segment to match. + /// The source value to match against the route segment. + /// if the segment matches the source; otherwise, . bool IsMatch(RouteSegment segment, string source); + + /// + /// Gets the parameter value from the provided source value. + /// + /// The route segment containing the parameter information. + /// The source value from which to extract the parameter value. + /// The extracted parameter value. object GetValue(RouteSegment segment, string source); } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Route/Route.cs b/src/Artemis.UI.Shared/Routing/Route/Route.cs index ad95bddd3..12ea6d4b4 100644 --- a/src/Artemis.UI.Shared/Routing/Route/Route.cs +++ b/src/Artemis.UI.Shared/Routing/Route/Route.cs @@ -3,15 +3,29 @@ using System.Linq; namespace Artemis.UI.Shared.Routing; +/// +/// Represents a route at a certain path. +/// public class Route { + /// + /// Initializes a new instance of the class. + /// + /// The path of the route. public Route(string path) { Path = path; Segments = path.Split('/').Select(s => new RouteSegment(s)).ToList(); } + /// + /// Gets the path of the route. + /// public string Path { get; } + + /// + /// Gets the list of segments that makes up the path. + /// public List Segments { get; } /// diff --git a/src/Artemis.UI.Shared/Routing/Route/RouteRegistration.cs b/src/Artemis.UI.Shared/Routing/Route/RouteRegistration.cs index dabb5dadb..2d9f8508f 100644 --- a/src/Artemis.UI.Shared/Routing/Route/RouteRegistration.cs +++ b/src/Artemis.UI.Shared/Routing/Route/RouteRegistration.cs @@ -1,12 +1,18 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Artemis.UI.Shared.Routing; +/// +/// Represents a registration for a route and its associated view model. +/// +/// The type of the view model associated with the route. public class RouteRegistration : IRouterRegistration where TViewModel : ViewModelBase { + /// + /// Initializes a new instance of the class. + /// + /// The path of the route. public RouteRegistration(string path) { Route = new Route(path); @@ -18,6 +24,9 @@ public class RouteRegistration : IRouterRegistration where TViewMode return $"{nameof(Route)}: {Route}, {nameof(ViewModel)}: {ViewModel}"; } + /// + /// Gets the route associated with this registration. + /// public Route Route { get; } /// @@ -25,12 +34,4 @@ public class RouteRegistration : IRouterRegistration where TViewMode /// public List Children { get; set; } = new(); -} - -public interface IRouterRegistration -{ - Route Route { get; } - Type ViewModel { get; } - List Children { get; set; } - } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs b/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs index 77025b389..1f25b67da 100644 --- a/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs +++ b/src/Artemis.UI.Shared/Routing/Route/RouteSegment.cs @@ -4,10 +4,17 @@ using Artemis.UI.Shared.Routing.ParameterParsers; namespace Artemis.UI.Shared.Routing; +/// +/// Represents a segment of a route. +/// public partial class RouteSegment { private readonly IRouteParameterParser? _parameterParser; + /// + /// Initializes a new instance of the class. + /// + /// The segment value. public RouteSegment(string segment) { Segment = segment; @@ -21,10 +28,26 @@ public partial class RouteSegment } } + /// + /// Gets the segment value. + /// public string Segment { get; } + + /// + /// Gets the parameter name if the segment is a parameterized segment; otherwise . + /// public string? Parameter { get; } + + /// + /// Gets the type of the parameter if the segment is a parameterized segment; otherwise . + /// public string? ParameterType { get; } + /// + /// Checks if the segment matches the provided value. + /// + /// The value to compare with the segment. + /// if the segment matches the value; otherwise, . public bool IsMatch(string value) { if (_parameterParser == null) @@ -32,6 +55,11 @@ public partial class RouteSegment return _parameterParser.IsMatch(this, value); } + /// + /// Gets the parameter value from the provided value. + /// + /// The value from which to extract the parameter value. + /// The extracted parameter value. public object? GetParameter(string value) { if (_parameterParser == null) @@ -58,6 +86,10 @@ public partial class RouteSegment // Default to a string parser which just returns the segment as is } + /// + /// Gets the regular expression used to identify parameterized segments in the route. + /// + /// The regular expression pattern. [GeneratedRegex(@"\{(\w+):(\w+)\}")] private static partial Regex ParameterRegex(); } \ No newline at end of file