1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-12 13:28:33 +00:00

Workshop - Add --alt-login-callback startup argument

UI - Rounded corners on profile icons
This commit is contained in:
Robert 2025-12-11 23:54:50 +01:00
parent 06c5294e88
commit 5609065974
7 changed files with 59 additions and 32 deletions

View File

@ -6,7 +6,6 @@ using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
@ -43,7 +42,7 @@ public partial class ProfileConfigurationIcon : UserControl, IDisposable
if (ConfigurationIcon.IconType == ProfileConfigurationIconType.MaterialIcon)
{
Content = Enum.TryParse(ConfigurationIcon.IconName, true, out MaterialIconKind parsedIcon)
? new MaterialIcon {Kind = parsedIcon!}
? new MaterialIcon {Kind = parsedIcon}
: new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
}
else if (ConfigurationIcon.IconBytes != null)
@ -65,19 +64,28 @@ public partial class ProfileConfigurationIcon : UserControl, IDisposable
return;
_stream = new MemoryStream(ConfigurationIcon.IconBytes);
if (!ConfigurationIcon.Fill)
Border border = new()
{
Content = new Image {Source = new Bitmap(_stream)};
return;
CornerRadius = CornerRadius,
ClipToBounds = true,
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch
};
if (ConfigurationIcon.Fill)
{
// Fill mode: use Foreground as Background and the bitmap as opacity mask
border.Background = TextElement.GetForeground(this);
border.OpacityMask = new ImageBrush(new Bitmap(_stream));
}
else
{
// Non-fill mode: place the image inside the rounded border
border.Child = new Image { Source = new Bitmap(_stream) };
}
Content = new Border
{
Background = TextElement.GetForeground(this),
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
OpacityMask = new ImageBrush(new Bitmap(_stream))
};
Content = border;
}
catch (Exception)
{

View File

@ -89,7 +89,7 @@
Background="{DynamicResource ControlFillColorDefaultBrush}"
IsVisible="{CompiledBinding ProfileConfiguration, Converter={x:Static ObjectConverters.IsNotNull}}">
<StackPanel Orientation="Horizontal" Margin="8">
<shared:ProfileConfigurationIcon ConfigurationIcon="{CompiledBinding ProfileConfiguration.Icon}" Width="18" Height="18" Margin="0 0 5 0" />
<shared:ProfileConfigurationIcon ConfigurationIcon="{CompiledBinding ProfileConfiguration.Icon}" Width="18" Height="18" CornerRadius="3" Margin="0 0 5 0" />
<TextBlock Text="{CompiledBinding ProfileConfiguration.Name}" />
</StackPanel>
</Border>

View File

@ -27,8 +27,9 @@ public partial class VisualEditorView : ReactiveUserControl<VisualEditorViewMode
this.WhenActivated(d =>
{
ViewModel!.AutoFitRequested += ViewModelOnAutoFitRequested;
Disposable.Create(() => ViewModel.AutoFitRequested -= ViewModelOnAutoFitRequested).DisposeWith(d);
VisualEditorViewModel? viewModel = ViewModel;
viewModel!.AutoFitRequested += ViewModelOnAutoFitRequested;
Disposable.Create(() => viewModel.AutoFitRequested -= ViewModelOnAutoFitRequested).DisposeWith(d);
});
this.WhenAnyValue(v => v.Bounds).Where(_ => !_movedByUser).Subscribe(_ => AutoFit(true));

View File

@ -72,15 +72,20 @@
Background="Transparent"
ContextFlyout="{StaticResource ProfileMenuFlyout}"
Classes.flyout-open="{CompiledBinding IsOpen, Source={StaticResource ProfileMenuFlyout}}">
<Border CornerRadius="4" ClipToBounds="True" Grid.Column="0" Width="22" Height="22" Margin="0 0 5 0" VerticalAlignment="Center">
<shared:ProfileConfigurationIcon x:Name="ProfileIcon" ConfigurationIcon="{CompiledBinding ProfileConfiguration.Icon}">
<shared:ProfileConfigurationIcon.Transitions>
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.2" />
</Transitions>
</shared:ProfileConfigurationIcon.Transitions>
</shared:ProfileConfigurationIcon>
</Border>
<shared:ProfileConfigurationIcon Grid.Column="0"
x:Name="ProfileIcon"
VerticalAlignment="Center"
ConfigurationIcon="{CompiledBinding ProfileConfiguration.Icon}"
Width="22"
Height="22"
CornerRadius="4"
Margin="0 0 5 0">
<shared:ProfileConfigurationIcon.Transitions>
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.2" />
</Transitions>
</shared:ProfileConfigurationIcon.Transitions>
</shared:ProfileConfigurationIcon>
<Panel Grid.Column="1" HorizontalAlignment="Left">
<TextBlock Classes="fadable"

View File

@ -80,7 +80,7 @@ public partial class DefaultEntryItemViewModel : ActivatableViewModelBase
await EnablePluginAndFeatures(result.Entry);
// If the entry is a profile, move it to the General profile category
else if (result.Entry?.EntryType == EntryType.Profile)
MoveProfileToGeneral(result.Entry);
PrepareProfile(result.Entry);
return result.IsSuccess;
}
@ -124,7 +124,7 @@ public partial class DefaultEntryItemViewModel : ActivatableViewModelBase
}
}
private void MoveProfileToGeneral(InstalledEntry entry)
private void PrepareProfile(InstalledEntry entry)
{
if (!entry.TryGetMetadata("ProfileId", out Guid profileId))
return;
@ -132,12 +132,18 @@ public partial class DefaultEntryItemViewModel : ActivatableViewModelBase
ProfileConfiguration? profile = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == profileId);
if (profile == null)
return;
ProfileCategory category = _profileService.ProfileCategories.FirstOrDefault(c => c.Name == "General") ?? _profileService.CreateProfileCategory("General", true);
if (category.ProfileConfigurations.Contains(profile))
return;
// Add the profile to the category
category.AddProfileConfiguration(profile, null);
// Suspend all but the first profile in the category
profile.IsSuspended = category.ProfileConfigurations.Count > 1;
_profileService.SaveProfileCategory(category);
}
}

View File

@ -38,6 +38,7 @@
Grid.Column="0"
ConfigurationIcon="{CompiledBinding Icon}"
VerticalAlignment="Center"
CornerRadius="4"
Width="22"
Height="22"
Margin="0 0 10 0" />

View File

@ -180,13 +180,15 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi
{
await _authLock.WaitAsync(cancellationToken);
// Start a HTTP listener, this port could be in use but chances are very slim
// IdentityServer only accepts these two redirect URLs
string redirectUri = Constants.StartupArguments.Contains("--alt-login-callback") ? "http://localhost:56789" : "http://localhost:57461";
try
{
if (_isLoggedInSubject.Value)
return;
// Start a HTTP listener, this port could be in use but chances are very slim
string redirectUri = "http://localhost:57461";
using HttpListener listener = new();
listener.Prefixes.Add(redirectUri + "/");
listener.Start();
@ -249,7 +251,11 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi
}
catch (HttpListenerException e)
{
throw new ArtemisWebClientException($"HTTP listener for login callback failed with error code {e.ErrorCode}", e);
// I've seen the Nvidia app do this after a login. What are the odds...
if (e.ErrorCode == 32)
throw new ArtemisWebClientException($"HTTP listener for login callback failed because another application is already listening on '{redirectUri}', please close that application and try again", e);
else
throw new ArtemisWebClientException($"HTTP listener for login callback failed with error code {e.ErrorCode}", e);
}
finally
{