Refine UX, fix auth crash, and revert to .NET 8.0

- Reverted target framework to .NET 8.0 for stability.
- Added autofocus to all dialog input fields (e.g. password dialogs).
- Fixed crash when relogging into accounts without Steam Guard and added proper error message.
- Unified and improved “Confirm Action” dialog design and text clarity.
- Added setting to disable ripple effect animations for better performance.
- Reduced minimum auto-confirmation timer interval from 10s to 5s.
- App now auto-selects the most appropriate language on first launch.
- Added trimming to proxy parse input
- Fixed incorrect hint about maFile binding when using login-based mode.
- Added ESC key behavior to remove focus from account search
- Minor UI polish and cleanup across dialogs.
This commit is contained in:
achiez
2025-10-08 18:08:38 +03:00
parent a56757302e
commit d319fc19f9
29 changed files with 258 additions and 111 deletions
+2
View File
@@ -361,3 +361,5 @@ MigrationBackup/
# Fody - auto-generated XML schema # Fody - auto-generated XML schema
FodyWeavers.xsd FodyWeavers.xsd
todo/
@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
+8 -3
View File
@@ -18,7 +18,8 @@
FontFamily="{md:MaterialDesignFont}" FontFamily="{md:MaterialDesignFont}"
TextElement.Foreground="{DynamicResource BaseContentBrush}" TextElement.Foreground="{DynamicResource BaseContentBrush}"
mc:Ignorable="d" mc:Ignorable="d"
d:DataContext="{d:DesignInstance viewModel:MainVM}"> d:DataContext="{d:DesignInstance viewModel:MainVM}"
md:RippleAssist.IsDisabled="{Binding Settings.RippleDisabled}">
<b:Interaction.Behaviors> <b:Interaction.Behaviors>
<windowStyle:WindowChromeRenderedBehavior /> <windowStyle:WindowChromeRenderedBehavior />
</b:Interaction.Behaviors> </b:Interaction.Behaviors>
@@ -63,6 +64,7 @@
<TextBlock FontWeight="Bold" Foreground="#9a65b8" Text="{Tr MainWindow.Global.DragNDropHint}" /> <TextBlock FontWeight="Bold" Foreground="#9a65b8" Text="{Tr MainWindow.Global.DragNDropHint}" />
<md:PackIcon Foreground="#9a65b8" HorizontalAlignment="Center" Width="36" Height="36" <md:PackIcon Foreground="#9a65b8" HorizontalAlignment="Center" Width="36" Height="36"
Kind="FileReplaceOutline" /> Kind="FileReplaceOutline" />
</StackPanel> </StackPanel>
<ToolBarTray> <ToolBarTray>
<ToolBar ClipToBounds="True" HorizontalContentAlignment="Stretch" <ToolBar ClipToBounds="True" HorizontalContentAlignment="Stretch"
@@ -146,6 +148,7 @@
<KeyBinding Key="Delete" Command="{Binding RemoveProxyCommand}" /> <KeyBinding Key="Delete" Command="{Binding RemoveProxyCommand}" />
</UIElement.InputBindings> </UIElement.InputBindings>
</ComboBox> </ComboBox>
<md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center" <md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="{DynamicResource ErrorBrush}" Margin="3" Foreground="{DynamicResource ErrorBrush}" Margin="3"
ToolTipService.InitialShowDelay="300"> ToolTipService.InitialShowDelay="300">
@@ -173,6 +176,7 @@
ToolTip="{Tr MainWindow.AppBar.Proxy.ProxyAlert.DefaultInUse}" ToolTip="{Tr MainWindow.AppBar.Proxy.ProxyAlert.DefaultInUse}"
ToolTipService.InitialShowDelay="300" ToolTipService.InitialShowDelay="300"
Visibility="{Binding IsDefaultProxy, Converter={StaticResource BooleanToVisibilityConverter}}" /> Visibility="{Binding IsDefaultProxy, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Separator />
<ToggleButton ToolTip="{Tr MainWindow.AppBar.MarketTimerHint}" <ToggleButton ToolTip="{Tr MainWindow.AppBar.MarketTimerHint}"
IsEnabled="{Binding IsMafileSelected}" Margin="2" IsEnabled="{Binding IsMafileSelected}" Margin="2"
Style="{StaticResource MaterialDesignFlatToggleButton}" Style="{StaticResource MaterialDesignFlatToggleButton}"
@@ -346,7 +350,9 @@
md:TextFieldAssist.HasClearButton="True" w:FontScaleWindow.Scale="0.7" md:TextFieldAssist.HasClearButton="True" w:FontScaleWindow.Scale="0.7"
w:FontScaleWindow.ResizeFont="True" Grid.Row="1" Margin="10,5,10,10" w:FontScaleWindow.ResizeFont="True" Grid.Row="1" Margin="10,5,10,10"
md:HintAssist.Hint="{Tr MainWindow.LeftPart.SearchBoxHint}" md:HintAssist.Hint="{Tr MainWindow.LeftPart.SearchBoxHint}"
Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
x:Name="SearchField"
KeyDown="SearchField_OnKeyDown" />
</Grid> </Grid>
</Border> </Border>
@@ -382,7 +388,6 @@
Grid.Row="1" Height="4" Style="{StaticResource MaterialDesignLinearProgressBar}" Grid.Row="1" Height="4" Style="{StaticResource MaterialDesignLinearProgressBar}"
MaxTime="30" TimeRemaining="{Binding CodeProgress, Mode=OneWay}" /> MaxTime="30" TimeRemaining="{Binding CodeProgress, Mode=OneWay}" />
</Grid> </Grid>
<Button IsEnabled="{Binding IsMafileSelected}" w:FontScaleWindow.Scale="0.7" <Button IsEnabled="{Binding IsMafileSelected}" w:FontScaleWindow.Scale="0.7"
w:FontScaleWindow.ResizeFont="True" Grid.Row="1" w:FontScaleWindow.ResizeFont="True" Grid.Row="1"
Style="{StaticResource MaterialDesignOutlinedButton}" Margin="0,10,0,10" Style="{StaticResource MaterialDesignOutlinedButton}" Margin="0,10,0,10"
+6
View File
@@ -51,6 +51,12 @@ public partial class MainWindow
} }
} }
private void SearchField_OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key != Key.Escape || !SearchField.IsFocused) return;
Keyboard.ClearFocus();
}
#region Dran'n'Drop #region Dran'n'Drop
private void UIElement_OnPreviewTextInput(object sender, TextCompositionEventArgs e) private void UIElement_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
+4
View File
@@ -5,6 +5,7 @@ using System.IO;
using System.Windows.Media; using System.Windows.Media;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using NebulaAuth.Core; using NebulaAuth.Core;
using NebulaAuth.Utility;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace NebulaAuth.Model; namespace NebulaAuth.Model;
@@ -28,6 +29,7 @@ public partial class Settings : ObservableObject
{ {
Instance = new Settings(); Instance = new Settings();
Instance.PropertyChanged += SettingsOnPropertyChanged; Instance.PropertyChanged += SettingsOnPropertyChanged;
Instance.Language = LanguageUtility.DetectPreferredLanguage();
return; return;
} }
@@ -70,6 +72,7 @@ public partial class Settings : ObservableObject
Instance.LeftOpacity = 0.4; Instance.LeftOpacity = 0.4;
Instance.RightOpacity = 0.8; Instance.RightOpacity = 0.8;
Instance.ApplyBlurBackground = true; Instance.ApplyBlurBackground = true;
Instance.RippleDisabled = false;
Save(); Save();
} }
@@ -99,6 +102,7 @@ public partial class Settings : ObservableObject
[ObservableProperty] private double _backgroundGamma; [ObservableProperty] private double _backgroundGamma;
[ObservableProperty] private bool _applyBlurBackground = true; [ObservableProperty] private bool _applyBlurBackground = true;
[ObservableProperty] private ThemeType _themeType = ThemeType.Default; [ObservableProperty] private ThemeType _themeType = ThemeType.Default;
[ObservableProperty] private bool _rippleDisabled;
#endregion #endregion
} }
+1 -1
View File
@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net9.0-windows7.0</TargetFramework> <TargetFramework>net8.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
-11
View File
@@ -1,11 +0,0 @@
• Сейчас, при наличии новой версии, отображается стандартное окно обновлений из библиотеки. Планируется сделать кастомный дизайн, для соответствия общему стилю.
• В приложении реализованы "совмещённые" подтверждения для торговой площадки. Т.е. при наличии более одного предмета, ожидающего подтверждение, можно либо отменить, либо подтвердить все. В планах добавить расширенный функционал, с возможностью точечного управления.
• Добавить кнопку "открыть мафайл" в меню "Файл" по аналогии с открытием папки
• Добавить полное шифрование мафайлов по аналогии с SDA
• Сделать автоматический билд и загрузку обновления на Github при изменении в мастер ветке
• Антик-окно как в MarketApp, возможность сразу открыть браузер напр. на CefSharp с залогиненым аккаунтом
• Стабильность авто-подтверждений, возможность задать пользователю порог времени когда льются ошибки и только тогда выключать авто-подтверждение
• Безопасное сохранение мафайлов через .tmp / .bak
• Создание механизма накопления ошибок, чтобы исправить Patch Tuesday, условно аккаунт может игнорировать ошибки 1-2 часа (настриавемо)
• Исправить "Перенос гуарда". Иногда не хочет принимать код / подтверждение
@@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using NebulaAuth.Core; using NebulaAuth.Core;
@@ -6,6 +7,7 @@ using NebulaAuth.Model;
using SteamLib.Exceptions; using SteamLib.Exceptions;
using SteamLib.Exceptions.Authorization; using SteamLib.Exceptions.Authorization;
using SteamLib.Exceptions.General; using SteamLib.Exceptions.General;
using SteamLib.ProtoCore.Enums;
using SteamLibForked.Exceptions.Authorization; using SteamLibForked.Exceptions.Authorization;
namespace NebulaAuth.Utility; namespace NebulaAuth.Utility;
@@ -94,6 +96,18 @@ public static class ExceptionHandler
return "LoginException".GetCodeBehindLocalization() + ": " + return "LoginException".GetCodeBehindLocalization() + ": " +
ErrorTranslatorHelper.TranslateLoginError(e.Error); ErrorTranslatorHelper.TranslateLoginError(e.Error);
} }
case UnsupportedAuthTypeException e:
{
var requestedType = e.AllowedGuardTypes.First();
var msgType = requestedType switch
{
EAuthSessionGuardType.DeviceCode or EAuthSessionGuardType.DeviceConfirmation => "Guard",
EAuthSessionGuardType.EmailCode => "Mail",
_ => "Unknown"
};
return GetCodeBehindLocalization("UnsupportedAuthTypeException", msgType);
}
case not null when handleAllExceptions: case not null when handleAllExceptions:
{ {
return "UnknownException".GetCodeBehindLocalization() + exception.Message; return "UnknownException".GetCodeBehindLocalization() + exception.Message;
@@ -112,4 +126,11 @@ public static class ExceptionHandler
{ {
return LocManager.GetCodeBehindOrDefault(key, EXCEPTION_HANDLER_LOC_PATH, key); return LocManager.GetCodeBehindOrDefault(key, EXCEPTION_HANDLER_LOC_PATH, key);
} }
private static string GetCodeBehindLocalization(params string[] path)
{
var def = path.Length == 0 ? "" : path.Last();
var newArr = path.Prepend(EXCEPTION_HANDLER_LOC_PATH).ToArray();
return LocManager.GetCodeBehindOrDefault(def, newArr);
}
} }
+36
View File
@@ -0,0 +1,36 @@
using System;
using System.Globalization;
using System.Linq;
using NebulaAuth.Core;
namespace NebulaAuth.Utility;
public static class LanguageUtility
{
public static LocalizationLanguage DetectPreferredLanguage()
{
var userCulture = CultureInfo.CurrentUICulture;
var userLang = userCulture.TwoLetterISOLanguageName;
var userRegion = userCulture.Name;
switch (userLang)
{
case "ru": return LocalizationLanguage.Russian;
case "uk": return LocalizationLanguage.Ukrainian;
case "en": return LocalizationLanguage.English;
}
if (userRegion.EndsWith("UA", StringComparison.OrdinalIgnoreCase))
return LocalizationLanguage.Ukrainian;
string[] cisRegions =
[
"RU", "BY", "KZ", "KG", "TJ", "TM", "UZ", "AM", "AZ", "GE", "MD"
];
if (cisRegions.Any(r => userRegion.EndsWith(r, StringComparison.OrdinalIgnoreCase)))
return LocalizationLanguage.Russian;
return LocalizationLanguage.English;
}
}
@@ -4,42 +4,88 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:theme="clr-namespace:NebulaAuth.Theme"
mc:Ignorable="d" mc:Ignorable="d"
Height="Auto" Width="Auto" MaxWidth="500" Height="Auto" Width="Auto" MaxWidth="500"
Background="{DynamicResource WindowBackground}"> Background="{DynamicResource WindowBackground}">
<Grid Margin="15"> <Grid MinHeight="140" MinWidth="350">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<!--<materialDesign:PackIcon Kind="WarningCircleOutline" Width="20" Height="20" Margin="0,0,5,0"
VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}" />-->
<TextBlock FontStyle="Normal" Foreground="{DynamicResource BaseContentBrush}"
HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr ConfirmCancelDialog.Title}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" CommandParameter="{StaticResource False}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Opacity="0.7" />
<Grid Grid.Row="2" Margin="12">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock theme:FontScaleWindow.Scale="0.8" <Border Visibility="{Binding Tip, Converter={StaticResource NullableToVisibilityConverter}}"
theme:FontScaleWindow.ResizeFont="True" Margin="10"
HorizontalAlignment="Center" Margin="10,10,10,15" Padding="5"
Text="Подтвердите действие" BorderThickness="1"
x:Name="ConfirmTextBlock" CornerRadius="12">
TextWrapping="WrapWithOverflow" /> <Border.BorderBrush>
<SolidColorBrush Color="{DynamicResource BaseShadowColor}" Opacity="0.5" />
</Border.BorderBrush>
<Border.Background>
<SolidColorBrush Color="{DynamicResource Base300Color}" Opacity="0.2" />
</Border.Background>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="QuestionMarkCircleOutline" Foreground="{DynamicResource InfoBrush}"
Height="22"
Width="22" VerticalAlignment="Center" Margin="5,0,0,0" />
<TextBlock x:Name="ConfirmTextBlock" VerticalAlignment="Center"
MaxWidth="420" FontSize="14"
TextWrapping="WrapWithOverflow"
Margin="10,10,10,10" Text="Confirm?" />
</StackPanel>
</Border>
<Grid Grid.Row="1" Margin="10,0,10,5"> <Grid Grid.Row="1" Margin="10,0,10,5">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition /> <ColumnDefinition />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Button DockPanel.Dock="Left" <Button
Width="130"
HorizontalAlignment="Left"
Margin="2,0,4,0"
Style="{StaticResource MaterialDesignRaisedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource True}" CommandParameter="{StaticResource True}">
FontSize="{Binding ElementName=ConfirmTextBlock, Path=FontSize,
Converter={StaticResource CoefficientConverter},
ConverterParameter=0.85}">
ОК ОК
</Button> </Button>
<Button Grid.Column="1" DockPanel.Dock="Right" <Button Grid.Column="1"
HorizontalAlignment="Right"
Width="130"
Margin="0,0,2,0"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource False}" CommandParameter="{StaticResource False}">
FontSize="{Binding ElementName=ConfirmTextBlock, Path=FontSize,
Converter={StaticResource CoefficientConverter},
ConverterParameter=0.85}">
Отмена Отмена
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
</Grid>
</UserControl> </UserControl>
@@ -45,7 +45,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBox Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" <TextBox TabIndex="0" Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
materialDesign:TextFieldAssist.HasClearButton="True" materialDesign:TextFieldAssist.HasClearButton="True"
Padding="10" Padding="10"
@@ -49,7 +49,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBox Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" <TextBox TabIndex="0" Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
materialDesign:TextFieldAssist.HasClearButton="True" materialDesign:TextFieldAssist.HasClearButton="True"
Padding="10" Padding="10"
@@ -42,7 +42,7 @@
<TextBlock Grid.Row="2" IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal" <TextBlock Grid.Row="2" IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal"
Text="{Tr SetEncryptedPasswordDialog.DialogText}" theme:FontScaleWindow.Scale="0.8" Text="{Tr SetEncryptedPasswordDialog.DialogText}" theme:FontScaleWindow.Scale="0.8"
theme:FontScaleWindow.ResizeFont="True" Margin="10" HorizontalAlignment="Left" /> theme:FontScaleWindow.ResizeFont="True" Margin="10" HorizontalAlignment="Left" />
<PasswordBox FontSize="16" <PasswordBox TabIndex="0" FontSize="16" x:Name="PasswordBox"
materialDesign:PasswordBoxAssist.Password="{Binding Password, UpdateSourceTrigger=PropertyChanged}" materialDesign:PasswordBoxAssist.Password="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
Margin="10" Grid.Row="3" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}" Margin="10" Grid.Row="3" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
materialDesign:HintAssist.Hint="{Tr SetEncryptedPasswordDialog.Password}" /> materialDesign:HintAssist.Hint="{Tr SetEncryptedPasswordDialog.Password}" />
@@ -28,7 +28,8 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Image x:Name="CaptchaImage" Stretch="Uniform" /> <Image x:Name="CaptchaImage" Stretch="Uniform" />
<TextBox Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintTextBox}" x:Name="CaptchaTB" /> <TextBox TabIndex="0" Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintTextBox}"
x:Name="CaptchaTB" />
<Grid Grid.Row="2"> <Grid Grid.Row="2">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition /> <ColumnDefinition />
@@ -11,6 +11,7 @@
<TextBlock Margin="5,0,0,0" Text="{Tr LinkerDialog.Authorization}" /> <TextBlock Margin="5,0,0,0" Text="{Tr LinkerDialog.Authorization}" />
</StackPanel> </StackPanel>
<TextBox <TextBox
TabIndex="0"
Padding="8" Padding="8"
FontSize="14" FontSize="14"
Style="{StaticResource MaterialDesignOutlinedTextBox}" Style="{StaticResource MaterialDesignOutlinedTextBox}"
@@ -13,6 +13,7 @@
</StackPanel> </StackPanel>
<TextBox <TextBox
TabIndex="0"
Padding="8" Padding="8"
FontSize="14" FontSize="14"
Style="{StaticResource MaterialDesignOutlinedTextBox}" Style="{StaticResource MaterialDesignOutlinedTextBox}"
@@ -11,6 +11,7 @@
MinHeight="500" MinHeight="500"
MinWidth="400" MinWidth="400"
MaxHeight="550" MaxHeight="550"
MaxWidth="500"
d:DataContext="{d:DesignInstance other:ProxyManagerVM}" d:DataContext="{d:DesignInstance other:ProxyManagerVM}"
Background="Transparent"> Background="Transparent">
<Grid> <Grid>
+17 -15
View File
@@ -8,7 +8,8 @@
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="650" d:DesignHeight="650"
FontFamily="{materialDesign:MaterialDesignFont}" FontFamily="{materialDesign:MaterialDesignFont}"
MinHeight="600" MinHeight="400"
MaxHeight="600"
MinWidth="400" MinWidth="400"
MaxWidth="400" MaxWidth="400"
d:DataContext="{d:DesignInstance other:SettingsVM}" d:DataContext="{d:DesignInstance other:SettingsVM}"
@@ -46,7 +47,7 @@
<TabControl materialDesign:ColorZoneAssist.Background="{DynamicResource Base100Brush}" <TabControl materialDesign:ColorZoneAssist.Background="{DynamicResource Base100Brush}"
Style="{StaticResource MaterialDesignUniformTabControl}" Grid.Row="2"> Style="{StaticResource MaterialDesignUniformTabControl}" Grid.Row="2">
<TabItem Header="{Tr SettingsDialog.MainSettings}"> <TabItem Header="{Tr SettingsDialog.MainSettings}">
<StackPanel Width="340" Margin="10,30,10,10" Orientation="Vertical" HorizontalAlignment="Center"> <StackPanel Width="340" Margin="10,20,10,40" Orientation="Vertical" HorizontalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignFloatingHintComboBox}" Margin="0,15,0,0" <ComboBox Style="{StaticResource MaterialDesignFloatingHintComboBox}" Margin="0,15,0,0"
FontSize="16" FontSize="16"
ItemsSource="{Binding Languages}" DisplayMemberPath="Value" SelectedValuePath="Key" ItemsSource="{Binding Languages}" DisplayMemberPath="Value" SelectedValuePath="Key"
@@ -92,7 +93,15 @@
</TabItem> </TabItem>
<TabItem IsEnabled="True" Header="{Tr SettingsDialog.ThemeSettings}"> <TabItem IsEnabled="True" Header="{Tr SettingsDialog.ThemeSettings}">
<StackPanel Width="340" Margin="10,30,10,10" Orientation="Vertical" HorizontalAlignment="Center"> <StackPanel Width="340" Margin="10,20,10,10" Orientation="Vertical" HorizontalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignOutlinedComboBox}"
Padding="8"
Margin="0,15,0,0"
FontSize="16"
ItemsSource="{Binding ThemeTypes}" DisplayMemberPath="Value" SelectedValuePath="Key"
SelectedValue="{Binding ThemeType}"
materialDesign:HintAssist.Hint="{Tr SettingsDialog.Theme.CurrentTheme}" />
<ComboBox Style="{StaticResource MaterialDesignOutlinedComboBox}" <ComboBox Style="{StaticResource MaterialDesignOutlinedComboBox}"
Padding="8" Padding="8"
Margin="0,15,0,0" Margin="0,15,0,0"
@@ -102,15 +111,6 @@
SelectedValue="{Binding BackgroundMode}" SelectedValue="{Binding BackgroundMode}"
materialDesign:HintAssist.Hint="{Tr SettingsDialog.BackgroundHint}" /> materialDesign:HintAssist.Hint="{Tr SettingsDialog.BackgroundHint}" />
<!-- Theme input -->
<ComboBox Style="{StaticResource MaterialDesignOutlinedComboBox}"
Padding="8"
Margin="0,15,0,0"
FontSize="16"
ItemsSource="{Binding ThemeTypes}" DisplayMemberPath="Value" SelectedValuePath="Key"
SelectedValue="{Binding ThemeType}"
materialDesign:HintAssist.Hint="{Tr SettingsDialog.Theme.CurrentTheme}" />
<TextBlock Text="{Tr SettingsDialog.Theme.BackgroundBlur}" Margin="0,15,0,0" /> <TextBlock Text="{Tr SettingsDialog.Theme.BackgroundBlur}" Margin="0,15,0,0" />
<Slider materialDesign:SliderAssist.HideActiveTrack="True" <Slider materialDesign:SliderAssist.HideActiveTrack="True"
TickFrequency="5" TickFrequency="5"
@@ -156,14 +156,16 @@
<CheckBox Margin="0,15,0,0" Content="{Tr SettingsDialog.Theme.DialogBlur}" <CheckBox Margin="0,15,0,0" Content="{Tr SettingsDialog.Theme.DialogBlur}"
IsChecked="{Binding ApplyBlurBackground}" /> IsChecked="{Binding ApplyBlurBackground}"
FontSize="15" />
<CheckBox Margin="0,15,0,0" Content="{Tr SettingsDialog.Theme.RippleDisabled}"
FontSize="15"
IsChecked="{Binding RippleDisabled}" />
<Button Margin="0,15,0,0" Command="{Binding ResetThemeDefaultsCommand}" <Button Margin="0,15,0,0" Command="{Binding ResetThemeDefaultsCommand}"
Content="{Tr SettingsDialog.Theme.Reset}" /> Content="{Tr SettingsDialog.Theme.Reset}" />
</StackPanel> </StackPanel>
</TabItem> </TabItem>
</TabControl> </TabControl>
</Grid> </Grid>
</Grid> </Grid>
</UserControl> </UserControl>
@@ -227,7 +227,7 @@ public partial class LinkAccountVM : ObservableObject, ISmsCodeProvider, IPhoneN
Storage.SaveMafile(mafile); Storage.SaveMafile(mafile);
File.Delete(Path.Combine("mafiles_backup", mafile.AccountName + ".mafile")); File.Delete(Path.Combine("mafiles_backup", mafile.AccountName + ".mafile"));
await Done(mafile.RevocationCode ?? string.Empty, mafile.SteamId.Steam64.ToString()); await Done(mafile.RevocationCode ?? string.Empty, mafile.SteamId.Steam64.ToString(), login);
} }
#region Step 3: Phone Number #region Step 3: Phone Number
@@ -280,9 +280,10 @@ public partial class LinkAccountVM : ObservableObject, ISmsCodeProvider, IPhoneN
#region Step 7: Done #region Step 7: Done
public async Task Done(string rCode, string steamId) public async Task Done(string rCode, string steamId, string login)
{ {
var step = new LinkAccountDoneStepVM(rCode, steamId); var filename = Settings.Instance.UseAccountNameAsMafileName ? login : steamId;
var step = new LinkAccountDoneStepVM(rCode, filename);
SetCurrentStep(step); SetCurrentStep(step);
await step.GetResultAsync(); await step.GetResultAsync();
} }
@@ -1,9 +1,7 @@
using System; using System.Threading.Tasks;
using System.Threading.Tasks;
using System.Windows;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Core; using NebulaAuth.Core;
using NebulaAuth.Model; using NebulaAuth.Utility;
namespace NebulaAuth.ViewModel.Linker; namespace NebulaAuth.ViewModel.Linker;
@@ -13,10 +11,10 @@ public partial class LinkAccountDoneStepVM : LinkAccountStepVM
private readonly TaskCompletionSource _doneTcs = new(); private readonly TaskCompletionSource _doneTcs = new();
private readonly string _rCode; private readonly string _rCode;
public LinkAccountDoneStepVM(string rCode, string steamId) public LinkAccountDoneStepVM(string rCode, string fileName)
{ {
var tipStr = LocManager.GetCodeBehindOrDefault("MafileLinked", LinkAccountVM.LOCALIZATION_KEY, "MafileLinked"); var tipStr = LocManager.GetCodeBehindOrDefault("MafileLinked", LinkAccountVM.LOCALIZATION_KEY, "MafileLinked");
InnerTip = string.Format(tipStr, rCode, steamId); InnerTip = string.Format(tipStr, rCode, fileName);
_rCode = rCode; _rCode = rCode;
} }
@@ -44,13 +42,6 @@ public partial class LinkAccountDoneStepVM : LinkAccountStepVM
[RelayCommand] [RelayCommand]
private void CopyCode() private void CopyCode()
{ {
try ClipboardHelper.Set(_rCode);
{
Clipboard.SetText(_rCode);
}
catch (Exception ex)
{
Shell.Logger.Error(ex, "Error whily copying RCode");
}
} }
} }
-1
View File
@@ -55,7 +55,6 @@ public partial class MainVM : ObservableObject
[RelayCommand] [RelayCommand]
public async Task Debug() public async Task Debug()
{ {
Shell.Logger.Info("test");
} }
+3 -3
View File
@@ -86,12 +86,12 @@ public partial class MainVM //MAAC
{ {
var timerCheckSeconds = Settings.TimerSeconds; var timerCheckSeconds = Settings.TimerSeconds;
if (timerCheckSeconds == value) return; if (timerCheckSeconds == value) return;
if (timerCheckSeconds < 10) if (timerCheckSeconds < 5)
{ {
timerCheckSeconds = 10; //Guard timerCheckSeconds = 5; //Guard
} }
if (value < 10) if (value < 5)
{ {
value = timerCheckSeconds; value = timerCheckSeconds;
SnackbarController.SendSnackbar(GetLocalization("TimerTooFast")); SnackbarController.SendSnackbar(GetLocalization("TimerTooFast"));
@@ -42,6 +42,7 @@ public partial class ProxyManagerVM : ObservableObject
var split = input var split = input
.Split(Environment.NewLine) .Split(Environment.NewLine)
.Where(s => string.IsNullOrWhiteSpace(s) == false) .Where(s => string.IsNullOrWhiteSpace(s) == false)
.Select(x => x.Trim())
.ToArray(); .ToArray();
if (split.Length == 0) return; if (split.Length == 0) return;
@@ -169,5 +169,11 @@ public partial class SettingsVM : ObservableObject
set => Settings.ThemeType = value; set => Settings.ThemeType = value;
} }
public bool RippleDisabled
{
get => Settings.RippleDisabled;
set => Settings.RippleDisabled = value;
}
#endregion #endregion
} }
+48 -14
View File
@@ -166,8 +166,8 @@
}, },
"MafileProxyInUse": { "MafileProxyInUse": {
"en": "Mafile proxy is in use", "en": "Mafile proxy is in use",
"ru": "Используется прокси из mafile", "ru": "Используется прокси из мафайла",
"ua": "Використовується проксі з mafile" "ua": "Використовується проксі з мафайла"
} }
} }
}, },
@@ -366,6 +366,11 @@
"ru": "Размытие при открытии диалог. окна", "ru": "Размытие при открытии диалог. окна",
"ua": "Розмиття при відкритті діалог. вікна" "ua": "Розмиття при відкритті діалог. вікна"
}, },
"RippleDisabled": {
"en": "Disable ripple animations",
"ru": "Отключить анимации «ripple»",
"ua": "Вимкнути анімації «ripple»"
},
"Reset": { "Reset": {
"en": "Reset", "en": "Reset",
"ru": "Сбросить", "ru": "Сбросить",
@@ -680,6 +685,13 @@
"ua": "Steam Guard перенесено" "ua": "Steam Guard перенесено"
} }
}, },
"ConfirmCancelDialog": {
"Title": {
"ru": "Подтвердите действие",
"en": "Confirm action",
"ua": "Підтвердіть дію"
}
},
"CodeBehind": { "CodeBehind": {
"MainVM": { "MainVM": {
"SuccessfulLogin": { "SuccessfulLogin": {
@@ -698,9 +710,13 @@
"ua": "Відсутній RCode" "ua": "Відсутній RCode"
}, },
"ConfirmRemovingAuthenticator": { "ConfirmRemovingAuthenticator": {
"ru": "Вы точно уверены что хотите удалить аутентификатор?", "ru":
"en": "Are you sure you want to remove authenticator?", "Вы точно уверены, что хотите удалить аутентификатор?\r\nПосле этого вы не сможете обмениваться, использовать торговую площадку 15 дней. Мафайл будет удалён навсегда",
"ua": "Ви точно впевнені що хочете видалити аутентифікатор?" "en":
"Are you sure you want to remove the authenticator?\r\nAfter that, you will not be able to trade or use the marketplace for 15 days. Mafile will be deleted permanently",
"ua":
"Ви точно впевнені, що хочете видалити автентифікатор?\r\nПісля цього ви не зможете обмінюватися, використовувати торгову площадку 15 днів. Мафайл буде видалено назавжди"
}, },
"AuthenticatorRemoved": { "AuthenticatorRemoved": {
"ru": "Аутентификатор удален", "ru": "Аутентификатор удален",
@@ -733,12 +749,12 @@
"ua": "Помилка підтвердження" "ua": "Помилка підтвердження"
}, },
"ConfirmMafileOverwrite": { "ConfirmMafileOverwrite": {
"ru": "Внимание, мафайл уже присутствует в папке mafiles.\r\nПерезаписать мафайлы, которые конфликтуют?", "ru": "Внимание, мафайл(-ы) уже присутствует в папке mafiles.\r\nПерезаписать мафайлы, которые конфликтуют?",
"en": "Attention, mafile already exists in mafiles folder.\r\nOverwrite conflicting mafiles?", "en": "Attention, mafile(-s) already exists in mafiles folder.\r\nOverwrite conflicting mafiles?",
"ua": "Увага, мафайл вже присутній у папці mafiles.\r\nПерезаписати мафайли, які конфліктують?" "ua": "Увага, мафайл(-и) вже присутній у папці mafiles.\r\nПерезаписати мафайли, які конфліктують?"
}, },
"MafileImportError": { "MafileImportError": {
"ru": "Ошибка импорта мафайла", "ru": "Ошибка при импорте мафайла",
"en": "Mafile import error", "en": "Mafile import error",
"ua": "Помилка імпорту мафайла" "ua": "Помилка імпорту мафайла"
}, },
@@ -769,16 +785,16 @@
}, },
"RemoveMafileConfirmation": { "RemoveMafileConfirmation": {
"ru": "ru":
"Удалить мафайл? Мафайл будет перемещен в папку 'mafiles_removed' (Это действие не удаляет Steam Guard с аккаунта)", "Удалить mafile?\r\nМафайл будет перемещен в папку 'mafiles_removed'\r\nЭто действие НЕ удаляет Steam Guard с аккаунта",
"en": "en":
"Remove mafile? Mafile will be moved to 'mafiles_removed' directory (This action does not remove the Steam Guard from the account)", "Remove mafile?\r\nMafile will be moved to 'mafiles_removed' directory\r\nThis action will NOT remove the Steam Guard from the account",
"ua": "ua":
"Видалити мафайл? Мафайл буде переміщено у каталог 'mafiles_removed' (Ця дія не видаляє автентифікатор з облікового запису)" "Видалити mafile?\r\nМафайл буде переміщено у каталог 'mafiles_removed'\r\nЦя дія НЕ видаляє автентифікатор з облікового запису"
}, },
"CantRemoveAlreadyExist": { "CantRemoveAlreadyExist": {
"ru": "Не удалось переместить мафайл, возможно в папке уже существует мафайл с таким именем.", "ru": "Не удалось переместить mafile, возможно в папке уже существует мафайл с таким именем.",
"en": "Can't move mafile, maybe mafile with same name already exists in mafiles_removed folder.", "en": "Can't move mafile, maybe mafile with same name already exists in mafiles_removed folder.",
"ua": "Не вдалося перемістити мафайл, можливо в папці вже існує мафайл з таким іменем." "ua": "Не вдалося перемістити mafile, можливо в папці вже існує мафайл з таким іменем."
}, },
"CantRemoveMafile": { "CantRemoveMafile": {
"ru": "Не удалось удалить (переместить) мафайл:", "ru": "Не удалось удалить (переместить) мафайл:",
@@ -1132,6 +1148,24 @@
"en": "Login error: ", "en": "Login error: ",
"ua": "Помилка входу: " "ua": "Помилка входу: "
}, },
"UnsupportedAuthTypeException": {
"Mail": {
"ru": "Ошибка: Был запрошен код с почты. Steam Guard не активирован",
"en": "Error: Email code was requested. Steam Guard is not activated",
"ua": "Помилка: Був запрошений код з пошти. Steam Guard не активовано"
},
"Guard": {
"ru": "Ошибка: Был запрошен вход с помощью Steam Guard. На аккаунте уже активирован мобильный аутентификатор",
"en": "Error: Login with Steam Guard was requested. Mobile authenticator is already activated on the account",
"ua":
"Помилка: Був запрошений вхід за допомогою Steam Guard. На акаунті вже активовано мобільний автентифікатор"
},
"Unknown": {
"ru": "Ошибка: Неизвестный тип аутентификации",
"en": "Error: Unknown authentication type",
"ua": "Помилка: Невідомий тип автентифікації"
}
},
"UnknownException": { "UnknownException": {
"ru": "Неизвестная ошибка: ", "ru": "Неизвестная ошибка: ",
"en": "Unknown error: ", "en": "Unknown error: ",
+4 -4
View File
@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AchiesUtilities.Newtonsoft.JSON" Version="1.3.3" /> <PackageReference Include="AchiesUtilities.Newtonsoft.JSON" Version="1.3.8" />
<PackageReference Include="AchiesUtilities.Web" Version="1.3.2" /> <PackageReference Include="AchiesUtilities.Web" Version="1.3.8" />
<PackageReference Include="HtmlAgilityPack" Version="1.12.1" /> <PackageReference Include="HtmlAgilityPack" Version="1.12.1" />
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" /> <PackageReference Include="JetBrains.Annotations" Version="2025.2.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.6" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.6" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="protobuf-net" Version="3.2.52" /> <PackageReference Include="protobuf-net" Version="3.2.52" />
+8 -8
View File
@@ -6,13 +6,13 @@ namespace SteamLib.Utility;
public static partial class SteamIdParser public static partial class SteamIdParser
{ {
[GeneratedRegex("^7656119([0-9]{10})$", RegexOptions.Compiled)] [GeneratedRegex("^7656119([0-9]{10})$", RegexOptions.Compiled)]
public static partial Regex Steam64Regex { get; } public static partial Regex Steam64Regex();
[GeneratedRegex(@"STEAM_(?<universe>[0-9]):(?<lowestBit>[0-9]):(?<highestBits>[0-9]{1,10})", RegexOptions.Compiled)] [GeneratedRegex(@"STEAM_(?<universe>[0-9]):(?<lowestBit>[0-9]):(?<highestBits>[0-9]{1,10})", RegexOptions.Compiled)]
public static partial Regex Steam2Regex { get; } public static partial Regex Steam2Regex();
[GeneratedRegex(@"^\[?(?<type>[a-zA-Z]):1:(?<id>[0-9]{1,10})\]$", RegexOptions.Compiled)] [GeneratedRegex(@"^\[?(?<type>[a-zA-Z]):1:(?<id>[0-9]{1,10})\]$", RegexOptions.Compiled)]
public static partial Regex Steam3Regex { get; } public static partial Regex Steam3Regex();
#region TryParse #region TryParse
@@ -46,7 +46,7 @@ public static partial class SteamIdParser
{ {
result = default; result = default;
if (input == null) return false; if (input == null) return false;
var match64 = Steam64Regex.Match(input); var match64 = Steam64Regex().Match(input);
if (match64.Success) if (match64.Success)
{ {
return TryParse64(long.Parse(match64.Value), out result); return TryParse64(long.Parse(match64.Value), out result);
@@ -69,7 +69,7 @@ public static partial class SteamIdParser
public static bool TryParse2(string input, out SteamId2 result) public static bool TryParse2(string input, out SteamId2 result)
{ {
var match2 = Steam2Regex.Match(input); var match2 = Steam2Regex().Match(input);
if (match2.Success) if (match2.Success)
{ {
var universe = byte.Parse(match2.Groups["universe"].Value); var universe = byte.Parse(match2.Groups["universe"].Value);
@@ -85,7 +85,7 @@ public static partial class SteamIdParser
public static bool TryParse3(string input, out SteamId3 result) public static bool TryParse3(string input, out SteamId3 result)
{ {
var match3 = Steam3Regex.Match(input); var match3 = Steam3Regex().Match(input);
if (match3.Success) if (match3.Success)
{ {
var type = match3.Groups["type"].Value[0]; var type = match3.Groups["type"].Value[0];
@@ -137,7 +137,7 @@ public static partial class SteamIdParser
public static SteamId2 Parse2(string input) public static SteamId2 Parse2(string input)
{ {
var match2 = Steam2Regex.Match(input); var match2 = Steam2Regex().Match(input);
if (match2.Success) if (match2.Success)
{ {
var universe = byte.Parse(match2.Groups["universe"].Value); var universe = byte.Parse(match2.Groups["universe"].Value);
@@ -151,7 +151,7 @@ public static partial class SteamIdParser
public static SteamId3 Parse3(string input) public static SteamId3 Parse3(string input)
{ {
var match3 = Steam3Regex.Match(input); var match3 = Steam3Regex().Match(input);
if (match3.Success) if (match3.Success)
{ {
var type = match3.Groups["type"].Value[0]; var type = match3.Groups["type"].Value[0];