1.5.6 Bug fixes and code clean-ups

- Update: Added "Copy Password" to Mafile context menu (if available)
- Update: "Save Password" now pre-fills the current password in the "Login Again" dialog when encryption is enabled
- Fix: Prevented overlapping confirmation cycles in AutoConfirmer
- Fix: Added a Snackbar notification when a confirmation cycle is skipped due to a too frequent timer interval
- Fix: Fixed a rare bug where the previous proxy was used instead of the current one during session refresh
- Fix: Corrected "Session Permanently Expired" message showing on unrelated errors (e.g. network issues)
- UI-Fix: Fixed visual glitch where proxy input appeared non-empty when switching to a mafile-specific proxy
- Cleanup: Refactored and cleaned up codebase, improved styling and formatting via ReSharper
This commit is contained in:
achiez
2025-05-02 23:29:24 +03:00
parent 5102e25266
commit 8ff960189e
191 changed files with 3743 additions and 2767 deletions
+24 -21
View File
@@ -11,38 +11,41 @@
<SolidColorBrush x:Key="MaterialDesignPaper">#1E2025</SolidColorBrush>
<FontFamily x:Key="Roboto">pack://application:,,,/Fonts/Roboto/#Roboto</FontFamily>
<FontFamily x:Key="RobotoSymbols">pack://application:,,,/Fonts/Roboto/#Roboto Symbols</FontFamily>
<converters:CoefficientConverter x:Key="CoefficientConverter"/>
<converters:ReverseBooleanConverter x:Key="ReverseBooleanConverter"/>
<converters:ProxyTextConverter x:Key="ProxyTextConverter"/>
<converters:ProxyDataTextConverter x:Key="ProxyDataTextConverter"/>
<converters:MultiCommandParameterConverter x:Key="MultiCommandParameterConverter"/>
<converters:ColorToBrushConverter x:Key="ColorToBrushConverter"/>
<converters:AnyMafilesToVisibilityConverter x:Key="AnyMafilesToVisibilityConverter"/>
<converters:PortableMaClientStatusToColorConverter x:Key="PortableMaClientStatusToColorConverter"/>
<converters:CoefficientConverter x:Key="CoefficientConverter" />
<converters:ReverseBooleanConverter x:Key="ReverseBooleanConverter" />
<converters:ProxyTextConverter x:Key="ProxyTextConverter" />
<converters:ProxyDataTextConverter x:Key="ProxyDataTextConverter" />
<converters:MultiCommandParameterConverter x:Key="MultiCommandParameterConverter" />
<converters:ColorToBrushConverter x:Key="ColorToBrushConverter" />
<converters:AnyMafilesToVisibilityConverter x:Key="AnyMafilesToVisibilityConverter" />
<converters:PortableMaClientStatusToColorConverter x:Key="PortableMaClientStatusToColorConverter" />
<!-- Background converters-->
<background:BackgroundImageVisibleConverter x:Key="BackgroundImageVisibleConverter"/>
<background:BackgroundSourceConverter x:Key="BackgroundSourceConverter"/>
<background:BackgroundImageVisibleConverter x:Key="BackgroundImageVisibleConverter" />
<background:BackgroundSourceConverter x:Key="BackgroundSourceConverter" />
<system:Boolean x:Key="True">True</system:Boolean>
<system:Boolean x:Key="False">False</system:Boolean>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Dark" PrimaryColor="LightGreen" SecondaryColor="Purple" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.snackbar.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.Dark.xaml" />
<materialDesign:BundledTheme BaseTheme="Dark" PrimaryColor="LightGreen" SecondaryColor="Purple" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.snackbar.xaml" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.Dark.xaml" />
<!-- Theme-->
<ResourceDictionary Source="Theme/Brushes.xaml"/>
<ResourceDictionary Source="Theme/WindowStyle/WindowStyle.xaml"/>
<ResourceDictionary Source="Theme/Brushes.xaml" />
<ResourceDictionary Source="Theme/WindowStyle/WindowStyle.xaml" />
<!--Controls-->
<ResourceDictionary Source="View/ConfirmationTemplates.xaml"/>
<ResourceDictionary Source="View/ConfirmationTemplates.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
</Application>
+6 -7
View File
@@ -1,12 +1,11 @@
using NebulaAuth.Core;
using System;
using System.Windows;
using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.Model.Exceptions;
using System;
using System.Windows;
namespace NebulaAuth;
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
@@ -27,9 +26,9 @@ public partial class App
msg = LocManager.Get("CantAlignTimeError");
}
MessageBox.Show(msg, "Error", MessageBoxButton.OK, MessageBoxImage.Stop, MessageBoxResult.OK, MessageBoxOptions.DefaultDesktopOnly);
MessageBox.Show(msg, "Error", MessageBoxButton.OK, MessageBoxImage.Stop, MessageBoxResult.OK,
MessageBoxOptions.DefaultDesktopOnly);
throw;
}
}
}
}
+5 -5
View File
@@ -2,9 +2,9 @@ using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
@@ -8,12 +8,14 @@ namespace NebulaAuth.Converters;
public class AnyMafilesToVisibilityConverter : IValueConverter
{
private static bool _everAnyMafiles;
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (_everAnyMafiles)
{
return Visibility.Collapsed;
}
if (value is 0)
{
return Visibility.Visible;
@@ -1,8 +1,8 @@
using NebulaAuth.Model;
using System;
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using NebulaAuth.Model;
namespace NebulaAuth.Converters.Background;
@@ -13,10 +13,10 @@ public class BackgroundSourceConverter : IValueConverter
{
if (value is BackgroundMode.Custom)
{
if(File.Exists("Background.png"))
if (File.Exists("Background.png"))
return new BitmapImage(new Uri(Path.GetFullPath("Background.png")));
}
return new BitmapImage(new Uri("pack://application:,,,/Theme/Background.jpg"));
}
@@ -1,7 +1,7 @@
using System.Globalization;
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
using System;
namespace NebulaAuth.Converters;
@@ -16,6 +16,7 @@ public class ColorToBrushConverter : IValueConverter
rv.Freeze();
return rv;
}
return Binding.DoNothing;
}
@@ -25,6 +26,7 @@ public class ColorToBrushConverter : IValueConverter
{
return brush.Color;
}
return default(Color);
}
}
@@ -1,7 +1,7 @@
using System.Globalization;
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
using System;
namespace NebulaAuth.Converters;
@@ -13,8 +13,8 @@ public class PortableMaClientStatusToColorConverter : IValueConverter
{
return new SolidColorBrush(Color.FromRgb(187, 224, 139));
}
return new SolidColorBrush(Color.FromRgb(224, 139, 139));
return new SolidColorBrush(Color.FromRgb(224, 139, 139));
}
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
@@ -25,4 +25,4 @@ public class ReverseBooleanConverter : IValueConverter
throw new ArgumentException("Value must be of type bool", nameof(value));
}
}
}
+5 -3
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
@@ -9,12 +10,13 @@ public class ValueConverterGroup : List<IValueConverter>, IValueConverter
{
#region IValueConverter Members
public object? Convert(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture)
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return this.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, culture));
return this.Aggregate(value,
(current, converter) => converter.Convert(current, targetType, parameter, culture));
}
public object ConvertBack(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture)
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
+13 -10
View File
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using MaterialDesignThemes.Wpf;
using NebulaAuth.Model;
using NebulaAuth.Model.Entities;
using NebulaAuth.View;
using NebulaAuth.View.Dialogs;
@@ -10,12 +11,10 @@ namespace NebulaAuth.Core;
public static class DialogsController
{
#region CommonDialogs
public static async Task<bool> ShowConfirmCancelDialog(string? msg = null)
{
var content = msg == null ? new ConfirmCancelDialog() : new ConfirmCancelDialog(msg);
var result = await DialogHost.Show(content);
@@ -31,11 +30,13 @@ public static class DialogsController
#endregion
public static async Task<LoginAgainVM?> ShowLoginAgainDialog(string username)
public static async Task<LoginAgainVM?> ShowLoginAgainDialog(string username, string? currentPassword = null)
{
var vm = new LoginAgainVM
{
UserName = username
UserName = username,
Password = currentPassword ?? string.Empty,
SavePassword = PHandler.IsPasswordSet
};
var content = new LoginAgainDialog
{
@@ -50,10 +51,11 @@ public static class DialogsController
return null;
}
public static async Task<LoginAgainOnImportVM?> ShowLoginAgainOnImportDialog(Mafile mafile, IEnumerable<MaProxy> proxies)
public static async Task<LoginAgainOnImportVM?> ShowLoginAgainOnImportDialog(Mafile mafile,
IEnumerable<MaProxy> proxies)
{
var vm = new LoginAgainOnImportVM(mafile, proxies);
var content = new LoginAgainOnImportDialog()
var content = new LoginAgainOnImportDialog
{
DataContext = vm
};
@@ -66,7 +68,7 @@ public static class DialogsController
return null;
}
public static async Task ShowProxyManager(MaProxy? currentProxy)
public static async Task<bool> ShowProxyManager()
{
var vm = new ProxyManagerVM();
var view = new ProxyManagerView
@@ -74,20 +76,21 @@ public static class DialogsController
DataContext = vm
};
await DialogHost.Show(view);
return vm.AnyChanges;
}
public static void CloseDialog()
{
DialogHost.Close(null);
}
public static async Task ShowLinkerDialog()
{
var vm = new LinkAccountVM();
var view = new LinkerView()
var view = new LinkerView
{
DataContext = vm
};
await DialogHost.Show(view);
}
}
+11 -9
View File
@@ -1,9 +1,9 @@
using CodingSeb.Localization;
using CodingSeb.Localization.Loaders;
using System;
using System;
using System.IO;
using System.Reflection;
using System.Text;
using CodingSeb.Localization;
using CodingSeb.Localization.Loaders;
namespace NebulaAuth.Core;
@@ -11,6 +11,7 @@ public static class LocManager
{
public const string CODE_BEHIND_PATH_PART = "CodeBehind";
public const string COMMON_PATH_PART = "Common";
public static void SetApplicationLocalization(LocalizationLanguage language)
{
Loc.Instance.CurrentLanguage = GetLanguageCode(language);
@@ -35,7 +36,6 @@ public static class LocManager
}
public static void Init()
{
Loc.LogOutMissingTranslations = true;
@@ -47,7 +47,8 @@ public static class LocManager
public static void ReloadFiles()
{
string exampleFileFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "localization.loc.json");
var exampleFileFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!,
"localization.loc.json");
LocalizationLoader.Instance.ClearAllTranslations();
LocalizationLoader.Instance.AddFile(exampleFileFileName);
}
@@ -64,14 +65,14 @@ public static class LocManager
public static string? GetCommon(params string[] path)
{
return GetConcat(COMMON_PATH_PART, path);
return GetConcat(COMMON_PATH_PART, path);
}
public static string GetCommonOrDefault(string def, params string[] path)
{
return GetCommon(path) ?? def;
return GetCommon(path) ?? def;
}
public static string? Get(params string[] path)
{
@@ -92,9 +93,10 @@ public static class LocManager
{
return Get(path) ?? def;
}
private static string? GetConcat(string first, string[] path)
{
string[] newArray = new string[path.Length + 1];
var newArray = new string[path.Length + 1];
newArray[0] = first;
Array.Copy(path, 0, newArray, 1, path.Length);
return Get(newArray);
+6 -8
View File
@@ -5,12 +5,11 @@ namespace NebulaAuth.Core;
public class SnackbarController
{
public static SnackbarMessageQueue MessageQueue { get; } = new() { DiscardDuplicates = true};
private const int MIN_SNACKBAR_TIME = 1200;
public static SnackbarMessageQueue MessageQueue { get; } = new() {DiscardDuplicates = true};
/// <summary>
///
/// </summary>
/// <param name="text"></param>
/// <param name="duration">Default duration is 1 second</param>
@@ -21,13 +20,13 @@ public class SnackbarController
}
/// <summary>
///
/// </summary>
/// <param name="text"></param>
/// <param name="action"></param>
/// <param name="duration">Default duration is 1 second</param>
/// <param name="actionText">Default: 'OK'</param>
public static void SendSnackbarWithButton(string text, string actionText = "OK", Action? action = null, TimeSpan? duration = null)
public static void SendSnackbarWithButton(string text, string actionText = "OK", Action? action = null,
TimeSpan? duration = null)
{
duration ??= GetSnackbarTime(text);
Action<object?> argAction;
@@ -48,10 +47,9 @@ public class SnackbarController
var duration = str.Length / 0.03;
if (duration < MIN_SNACKBAR_TIME)
{
duration = MIN_SNACKBAR_TIME;
duration = MIN_SNACKBAR_TIME;
}
return TimeSpan.FromMilliseconds(duration);
}
}
+7 -5
View File
@@ -1,11 +1,13 @@
using NebulaAuth.Model;
using System;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shell;
using NebulaAuth.Model;
using Color = System.Drawing.Color;
namespace NebulaAuth.Core;
@@ -14,6 +16,7 @@ public static class ThemeManager
{
public static System.Windows.Media.Color DefaultBackgroundColor = System.Windows.Media.Color.FromRgb(30, 32, 37);
private static readonly Window MainWindow = Application.Current.MainWindow!;
static ThemeManager()
{
Settings.Instance.PropertyChanged += SettingsOnPropertyChanged;
@@ -44,13 +47,13 @@ public static class ThemeManager
var diameter = 14;
var bitmap = new Bitmap(diameter, diameter);
var graphics = Graphics.FromImage(bitmap);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
var brush = new SolidBrush(Color.FromArgb(c.A, c.R, c.G, c.B));
graphics.FillEllipse(brush, 0, 0, diameter, diameter);
var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
MainWindow.TaskbarItemInfo = new();
MainWindow.TaskbarItemInfo = new TaskbarItemInfo();
MainWindow.TaskbarItemInfo.Overlay = bitmapSource;
}
}
@@ -59,7 +62,6 @@ public static class ThemeManager
{
var color = Settings.Instance.BackgroundColor ?? DefaultBackgroundColor;
Application.Current.Resources["WindowBackground"] = new SolidColorBrush(color);
}
public static void InitializeTheme()
+3 -3
View File
@@ -1,9 +1,9 @@
using NebulaAuth.Model;
using System;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Windows;
using System.Windows.Forms;
using NebulaAuth.Model;
using Application = System.Windows.Application;
namespace NebulaAuth.Core;
@@ -29,7 +29,7 @@ public static class TrayManager
var contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("Выйти", null!, onClick: OnExitClick);
contextMenu.Items.Add("Выйти", null!, OnExitClick);
_notifyIcon.ContextMenuStrip = contextMenu;
+7 -8
View File
@@ -1,24 +1,23 @@
using AutoUpdaterDotNET;
using NebulaAuth.Model;
using System;
using System;
using System.IO;
using AutoUpdaterDotNET;
using NebulaAuth.Model;
namespace NebulaAuth.Core;
public static class UpdateManager
{
private const string UPDATE_URL = "https://raw.githubusercontent.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/master/NebulaAuth/update.xml";
private const string UPDATE_URL =
"https://raw.githubusercontent.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/master/NebulaAuth/update.xml";
public static void CheckForUpdates()
{
string jsonPath = Path.Combine(Environment.CurrentDirectory, "update-settings.json");
var jsonPath = Path.Combine(Environment.CurrentDirectory, "update-settings.json");
AutoUpdater.PersistenceProvider = new JsonFilePersistenceProvider(jsonPath);
AutoUpdater.ShowSkipButton = false;
if (Settings.Instance.AllowAutoUpdate)
AutoUpdater.UpdateMode = Mode.ForcedDownload;
AutoUpdater.Start(UPDATE_URL);
}
+1 -1
View File
@@ -1,3 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<CodingSebLocalization />
<CodingSebLocalization />
</Weavers>
+196 -87
View File
@@ -15,21 +15,19 @@
RenderOptions.BitmapScalingMode="HighQuality" Foreground="#FFF5F5F5"
FontFamily="{md:MaterialDesignFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance viewModel:MainVM}"
>
mc:Ignorable="d"
d:DataContext="{d:DesignInstance viewModel:MainVM}">
<b:Interaction.Behaviors>
<windowStyle:WindowChromeRenderedBehavior />
</b:Interaction.Behaviors>
<Window.InputBindings>
<KeyBinding Command="{Binding Path=PasteMafilesFromClipboardCommand}"
Key="V"
Modifiers="Control"/>
<KeyBinding Command="{Binding Path=PasteMafilesFromClipboardCommand}"
Key="V"
Modifiers="Control" />
</Window.InputBindings>
<Border Name="DragNDropBorder" Panel.ZIndex="3" Opacity="1" AllowDrop="True" DragDrop.DragEnter="Rectangle_DragEnter" DragLeave="Rectangle_DragLeave" Drop="Rectangle_Drop">
<Border Name="DragNDropBorder" Panel.ZIndex="3" Opacity="1" AllowDrop="True"
DragDrop.DragEnter="Rectangle_DragEnter" DragLeave="Rectangle_DragLeave" Drop="Rectangle_Drop">
<md:DialogHost DialogOpened="DialogHost_DialogOpened" DialogClosed="DialogHost_DialogClosed">
<Grid ZIndex="0">
<Grid.RowDefinitions>
@@ -37,39 +35,61 @@
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Grid.RowSpan="2" Opacity="0.6" Stretch="UniformToFill" RenderOptions.BitmapScalingMode="LowQuality" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding Settings.BackgroundMode, Converter={StaticResource BackgroundImageVisibleConverter}}" Source="{Binding Settings.BackgroundMode, Mode=OneWay, Converter={StaticResource BackgroundSourceConverter}}" />
<Rectangle Grid.Row="0" Grid.RowSpan="2" Opacity="0.5" Fill="#FF1F1D1D" Visibility="{Binding Settings.BackgroundMode, Converter={StaticResource BackgroundImageVisibleConverter}}" />
<Rectangle Name="DragNDropOverlay" Grid.Row="0" Grid.RowSpan="3" Panel.ZIndex="1" Fill="#242123" Opacity="0.9" Visibility="Hidden" />
<StackPanel Name="DragNDropPanel" Grid.Row="0" ZIndex="2" w:FontScaleWindow.Scale="1" w:FontScaleWindow.ResizeFont="True" Grid.RowSpan="3" Visibility="Hidden" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock FontWeight="Bold" Foreground="#9a65b8" Text="{Tr MainWindow.Global.DragNDropHint}"/>
<md:PackIcon Foreground="#9a65b8" HorizontalAlignment="Center" Width="36" Height="36" Kind="FileReplaceOutline" />
<Image Grid.RowSpan="2" Opacity="0.6" Stretch="UniformToFill"
RenderOptions.BitmapScalingMode="LowQuality" HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding Settings.BackgroundMode, Converter={StaticResource BackgroundImageVisibleConverter}}"
Source="{Binding Settings.BackgroundMode, Mode=OneWay, Converter={StaticResource BackgroundSourceConverter}}" />
<Rectangle Grid.Row="0" Grid.RowSpan="2" Opacity="0.5" Fill="#FF1F1D1D"
Visibility="{Binding Settings.BackgroundMode, Converter={StaticResource BackgroundImageVisibleConverter}}" />
<Rectangle Name="DragNDropOverlay" Grid.Row="0" Grid.RowSpan="3" Panel.ZIndex="1" Fill="#242123"
Opacity="0.9" Visibility="Hidden" />
<StackPanel Name="DragNDropPanel" Grid.Row="0" ZIndex="2" w:FontScaleWindow.Scale="1"
w:FontScaleWindow.ResizeFont="True" Grid.RowSpan="3" Visibility="Hidden"
VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock FontWeight="Bold" Foreground="#9a65b8" Text="{Tr MainWindow.Global.DragNDropHint}" />
<md:PackIcon Foreground="#9a65b8" HorizontalAlignment="Center" Width="36" Height="36"
Kind="FileReplaceOutline" />
</StackPanel>
<ToolBarTray IsLocked="True" Grid.Row="0" >
<ToolBarTray IsLocked="True" Grid.Row="0">
<ToolBarTray.Background>
<SolidColorBrush Opacity="0.6" Color="#FF1A1C25" />
</ToolBarTray.Background>
<ToolBar Background="#00FFFFFF" ClipToBounds="False" Style="{StaticResource MaterialDesignToolBar}" w:FontScaleWindow.Scale="0.68" w:FontScaleWindow.ResizeFont="True">
<ToolBar Background="#00FFFFFF" ClipToBounds="False" Style="{StaticResource MaterialDesignToolBar}"
w:FontScaleWindow.Scale="0.68" w:FontScaleWindow.ResizeFont="True">
<Menu w:FontScaleWindow.Scale="0.68" w:FontScaleWindow.ResizeFont="True">
<MenuItem Header="{Tr MainWindow.Menu.File.Caption}">
<MenuItem Header="{Tr MainWindow.Menu.File.Import}" Command="{Binding AddMafileCommand}" />
<MenuItem IsEnabled="{Binding IsMafileSelected}" Header="{Tr MainWindow.Menu.File.Remove}" Command="{Binding RemoveMafileCommand}" />
<MenuItem Header="{Tr MainWindow.Menu.File.OpenFolder}" Command="{Binding OpenMafileFolderCommand}" />
<MenuItem Header="{Tr MainWindow.Menu.File.Import}"
Command="{Binding AddMafileCommand}" />
<MenuItem IsEnabled="{Binding IsMafileSelected}"
Header="{Tr MainWindow.Menu.File.Remove}"
Command="{Binding RemoveMafileCommand}" />
<MenuItem Header="{Tr MainWindow.Menu.File.OpenFolder}"
Command="{Binding OpenMafileFolderCommand}" />
<MenuItem IsEnabled="False" Header="⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯" Height="15" />
<MenuItem Header="{Tr MainWindow.Menu.File.Settings}" Command="{Binding OpenSettingsDialogCommand}" />
<MenuItem Header="{Tr MainWindow.Menu.File.Settings}"
Command="{Binding OpenSettingsDialogCommand}" />
</MenuItem>
</Menu>
<Menu w:FontScaleWindow.Scale="0.68" w:FontScaleWindow.ResizeFont="True">
<MenuItem Header="{Tr MainWindow.Menu.Account.Caption}">
<MenuItem Header="{Tr MainWindow.Menu.Account.Link}" Command="{Binding LinkAccountCommand}" />
<MenuItem Header="{Tr MainWindow.Menu.Account.Unlink}" Command="{Binding RemoveAuthenticatorCommand}"/>
<MenuItem Header="{Tr MainWindow.Menu.Account.Link}"
Command="{Binding LinkAccountCommand}" />
<MenuItem Header="{Tr MainWindow.Menu.Account.Unlink}"
Command="{Binding RemoveAuthenticatorCommand}" />
<MenuItem IsEnabled="False" Header="⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯" Height="15" />
<MenuItem IsEnabled="{Binding IsMafileSelected}" Header="{Tr MainWindow.Menu.Account.RefreshSession}" Command="{Binding RefreshSessionCommand}" />
<MenuItem IsEnabled="{Binding IsMafileSelected}" Header="{Tr MainWindow.Menu.Account.LoginAgain}" Command="{Binding LoginAgainCommand}" />
<MenuItem IsEnabled="{Binding IsMafileSelected}"
Header="{Tr MainWindow.Menu.Account.RefreshSession}"
Command="{Binding RefreshSessionCommand}" />
<MenuItem IsEnabled="{Binding IsMafileSelected}"
Header="{Tr MainWindow.Menu.Account.LoginAgain}"
Command="{Binding LoginAgainCommand}" />
</MenuItem>
</Menu>
<Separator />
<ComboBox ToolTip="{Tr MainWindow.AppBar.GroupToolTip}" md:HintAssist.Hint="{Tr MainWindow.AppBar.GroupsHint}"
MinWidth="100" Margin="8,0,8,0" VerticalAlignment="Center" IsEditable="True"
<ComboBox ToolTip="{Tr MainWindow.AppBar.GroupToolTip}"
md:HintAssist.Hint="{Tr MainWindow.AppBar.GroupsHint}"
MinWidth="100" Margin="8,0,8,0" VerticalAlignment="Center" IsEditable="True"
ItemsSource="{Binding Groups}"
SelectedValue="{Binding SelectedGroup}">
@@ -82,37 +102,43 @@
</ResourceDictionary>
</FrameworkElement.Resources>
<UIElement.InputBindings>
<KeyBinding Key="Enter" Command="{Binding AddGroupCommand}" CommandParameter="{Binding Path=Text, RelativeSource={RelativeSource AncestorType=ComboBox}}" />
<KeyBinding Key="Enter" Command="{Binding AddGroupCommand}"
CommandParameter="{Binding Path=Text, RelativeSource={RelativeSource AncestorType=ComboBox}}" />
</UIElement.InputBindings>
</ComboBox>
<ComboBox ToolTip="{Tr MainWindow.AppBar.Proxy.ProxyManipulateToolTip}"
MinWidth="80"
Margin="8,0,8,0"
Margin="8,0,8,0"
VerticalAlignment="Center"
md:HintAssist.Hint="{Tr MainWindow.AppBar.Proxy.ProxyHint}"
md:ComboBoxAssist.ShowSelectedItem="False"
SelectedItem="{Binding SelectedProxy}"
md:ComboBoxAssist.ShowSelectedItem="False"
SelectedValue="{Binding SelectedProxy}"
ItemsSource="{Binding Proxies}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type entities:MaProxy}">
<TextBlock Text="{Binding Converter={StaticResource ProxyTextConverter}, Mode=OneWay}" />
<TextBlock
Text="{Binding Converter={StaticResource ProxyTextConverter}, Mode=OneWay}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<FrameworkElement.ContextMenu>
<ContextMenu>
<MenuItem Header="{Tr MainWindow.AppBar.Proxy.ProxyOpenManagerHint}" Command="{Binding OpenProxyManagerCommand}" />
<MenuItem Header="{Tr MainWindow.AppBar.Proxy.ProxyOpenManagerHint}"
Command="{Binding OpenProxyManagerCommand}" />
</ContextMenu>
</FrameworkElement.ContextMenu>
<UIElement.InputBindings>
<KeyBinding Key="Delete" Command="{Binding RemoveProxyCommand}" />
</UIElement.InputBindings>
</ComboBox>
<md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="#FFFF0000" Margin="3" ToolTipService.InitialShowDelay="300">
<md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="#FFFF0000" Margin="3" ToolTipService.InitialShowDelay="300">
<md:PackIcon.ToolTip>
<TextBlock>
<Run Text="{Tr MainWindow.AppBar.Proxy.ProxyAlert.MafileProxyInUse, IsDynamic=False}"/>
<Run Text="&#10;"/><Run Text="{Binding SelectedMafile.Proxy.Data, FallbackValue='', Mode=OneWay}"/>
<Run
Text="{Tr MainWindow.AppBar.Proxy.ProxyAlert.MafileProxyInUse, IsDynamic=False}" />
<Run Text="&#10;" />
<Run Text="{Binding SelectedMafile.Proxy.Data, FallbackValue='', Mode=OneWay}" />
</TextBlock>
</md:PackIcon.ToolTip>
<UIElement.Visibility>
@@ -126,27 +152,53 @@
</Binding>
</UIElement.Visibility>
</md:PackIcon>
<md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="#FFFFA500" Margin="3" ToolTip="{Tr MainWindow.AppBar.Proxy.ProxyAlert.DefaultInUse}" ToolTipService.InitialShowDelay="300" Visibility="{Binding IsDefaultProxy, Converter={StaticResource BooleanToVisibilityConverter}}" />
<ToggleButton ToolTip="{Tr MainWindow.AppBar.MarketTimerHint}" Foreground="{DynamicResource PrimaryHueDarkForegroundBrush}" IsEnabled="{Binding IsMafileSelected}" Margin="2" Style="{StaticResource MaterialDesignFlatToggleButton}" IsChecked="{Binding MarketTimerEnabled}" >
<md:PackIcon Kind="ShoppingCart"/>
<md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="#FFFFA500" Margin="3"
ToolTip="{Tr MainWindow.AppBar.Proxy.ProxyAlert.DefaultInUse}"
ToolTipService.InitialShowDelay="300"
Visibility="{Binding IsDefaultProxy, Converter={StaticResource BooleanToVisibilityConverter}}" />
<ToggleButton ToolTip="{Tr MainWindow.AppBar.MarketTimerHint}"
Foreground="{DynamicResource PrimaryHueDarkForegroundBrush}"
IsEnabled="{Binding IsMafileSelected}" Margin="2"
Style="{StaticResource MaterialDesignFlatToggleButton}"
IsChecked="{Binding MarketTimerEnabled}">
<md:PackIcon Kind="ShoppingCart" />
<FrameworkElement.ContextMenu>
<ContextMenu>
<MenuItem Header="{Tr MainWindow.AppBar.TimersContextMenu.SwitchMAACGroup}" Command="{Binding Path=SwitchMAACOnGroupCommand}" CommandParameter="{StaticResource True}"/>
<MenuItem Header="{Tr MainWindow.AppBar.TimersContextMenu.SwitchMAACAll}" Command="{Binding Path=SwitchMAACOnAllCommand}" CommandParameter="{StaticResource True}"/>
<MenuItem Header="{Tr MainWindow.AppBar.TimersContextMenu.SwitchMAACGroup}"
Command="{Binding Path=SwitchMAACOnGroupCommand}"
CommandParameter="{StaticResource True}" />
<MenuItem Header="{Tr MainWindow.AppBar.TimersContextMenu.SwitchMAACAll}"
Command="{Binding Path=SwitchMAACOnAllCommand}"
CommandParameter="{StaticResource True}" />
</ContextMenu>
</FrameworkElement.ContextMenu>
</ToggleButton>
<ToggleButton ToolTip="{Tr MainWindow.AppBar.TradeTimerHint}" Foreground="{DynamicResource PrimaryHueDarkForegroundBrush}" IsEnabled="{Binding IsMafileSelected}" Margin="2" Style="{StaticResource MaterialDesignFlatToggleButton}" IsChecked="{Binding TradeTimerEnabled}" >
<ToggleButton ToolTip="{Tr MainWindow.AppBar.TradeTimerHint}"
Foreground="{DynamicResource PrimaryHueDarkForegroundBrush}"
IsEnabled="{Binding IsMafileSelected}" Margin="2"
Style="{StaticResource MaterialDesignFlatToggleButton}"
IsChecked="{Binding TradeTimerEnabled}">
<md:PackIcon Kind="AccountArrowRight" />
<FrameworkElement.ContextMenu>
<ContextMenu>
<MenuItem Header="{Tr MainWindow.AppBar.TimersContextMenu.SwitchMAACGroup}" Command="{Binding Path=SwitchMAACOnGroupCommand}" CommandParameter="{StaticResource False}"/>
<MenuItem Header="{Tr MainWindow.AppBar.TimersContextMenu.SwitchMAACAll}" Command="{Binding Path=SwitchMAACOnAllCommand}" CommandParameter="{StaticResource False}"/>
<MenuItem Header="{Tr MainWindow.AppBar.TimersContextMenu.SwitchMAACGroup}"
Command="{Binding Path=SwitchMAACOnGroupCommand}"
CommandParameter="{StaticResource False}" />
<MenuItem Header="{Tr MainWindow.AppBar.TimersContextMenu.SwitchMAACAll}"
Command="{Binding Path=SwitchMAACOnAllCommand}"
CommandParameter="{StaticResource False}" />
</ContextMenu>
</FrameworkElement.ContextMenu>
</ToggleButton>
<TextBox md:HintAssist.Hint="{Tr Common.Abbreviations.Time.Seconds}" Margin="10,0,0,0" MinWidth="30" Style="{StaticResource MaterialDesignFloatingHintTextBox}" Text="{Binding TimerCheckSeconds, UpdateSourceTrigger=PropertyChanged, Delay=700}" PreviewTextInput="UIElement_OnPreviewTextInput" />
<ToggleButton ToolTip="{Tr MainWindow.AppBar.ShowAutoConfirmAccountsHint}" HorizontalAlignment="Right" IsChecked="{Binding MaacDisplay}" Foreground="WhiteSmoke" VerticalAlignment="Center" Style="{StaticResource MaterialDesignFlatPrimaryToggleButton}" Margin="4">
<TextBox md:HintAssist.Hint="{Tr Common.Abbreviations.Time.Seconds}" Margin="10,0,0,0"
MinWidth="30" Style="{StaticResource MaterialDesignFloatingHintTextBox}"
Text="{Binding TimerCheckSeconds, UpdateSourceTrigger=PropertyChanged, Delay=700}"
PreviewTextInput="UIElement_OnPreviewTextInput" />
<ToggleButton ToolTip="{Tr MainWindow.AppBar.ShowAutoConfirmAccountsHint}"
HorizontalAlignment="Right" IsChecked="{Binding MaacDisplay}"
Foreground="WhiteSmoke" VerticalAlignment="Center"
Style="{StaticResource MaterialDesignFlatPrimaryToggleButton}" Margin="4">
<md:PackIcon Kind="Accounts" />
</ToggleButton>
</ToolBar>
@@ -162,74 +214,107 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox w:FontScaleWindow.Scale="0.8" w:FontScaleWindow.ResizeFont="True" Grid.Row="0" Margin="10,15,0,0" ItemsSource="{Binding MaFiles}" SelectedValue="{Binding SelectedMafile}">
<ListBox w:FontScaleWindow.Scale="0.8" w:FontScaleWindow.ResizeFont="True" Grid.Row="0"
Margin="10,15,0,0" ItemsSource="{Binding MaFiles}"
SelectedValue="{Binding SelectedMafile}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource MaterialDesignListBoxItem}">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate >
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Stretch" Text="{Binding AccountName}">
<TextBlock HorizontalAlignment="Stretch" Text="{Binding AccountName}">
<TextBlock.Foreground>
<Binding Mode="OneWay" Path="LinkedClient.IsError" Converter="{StaticResource PortableMaClientStatusToColorConverter}">
<Binding Mode="OneWay" Path="LinkedClient.IsError"
Converter="{StaticResource PortableMaClientStatusToColorConverter}">
<Binding.FallbackValue>
<SolidColorBrush Color="WhiteSmoke"/>
<SolidColorBrush Color="WhiteSmoke" />
</Binding.FallbackValue>
</Binding>
</TextBlock.Foreground>
</TextBlock>
<StackPanel Visibility="{Binding LinkedClient, Converter={StaticResource NullableToVisibilityConverter}}" Grid.Column="1" Orientation="Horizontal">
<md:PackIcon Kind="ShoppingCart" Visibility="{Binding LinkedClient.AutoConfirmMarket, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}"/>
<md:PackIcon Kind="AccountArrowRight" Visibility="{Binding LinkedClient.AutoConfirmTrades, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}"/>
<StackPanel
Visibility="{Binding LinkedClient, Converter={StaticResource NullableToVisibilityConverter}}"
Grid.Column="1" Orientation="Horizontal">
<md:PackIcon Kind="ShoppingCart"
Visibility="{Binding LinkedClient.AutoConfirmMarket, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}" />
<md:PackIcon Kind="AccountArrowRight"
Visibility="{Binding LinkedClient.AutoConfirmTrades, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.InputBindings>
<KeyBinding Key="C" Modifiers="Control" Command="{Binding DataContext.CopyLoginCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}"/>
<KeyBinding Key="X" Modifiers="Control" Command="{Binding DataContext.CopyMafileCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}"/>
<KeyBinding Key="C" Modifiers="Control"
Command="{Binding DataContext.CopyLoginCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" />
<KeyBinding Key="X" Modifiers="Control"
Command="{Binding DataContext.CopyMafileCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" />
</ListBox.InputBindings>
<FrameworkElement.ContextMenu>
<ContextMenu>
<MenuItem InputGestureText="Ctrl+C" Header="{Tr MainWindow.ContextMenus.Mafile.CopyLogin}" Command="{Binding CopyLoginCommand}" CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.CopySteamId}" Command="{Binding CopySteamIdCommand}" CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem InputGestureText="Ctrl+X" Header="{Tr MainWindow.ContextMenus.Mafile.CopyMafile}" Command="{Binding CopyMafileCommand}" CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.AddToGroup}" ItemsSource="{Binding Groups}">
<MenuItem InputGestureText="Ctrl+C"
Header="{Tr MainWindow.ContextMenus.Mafile.CopyLogin}"
Command="{Binding CopyLoginCommand}"
CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.CopySteamId}"
Command="{Binding CopySteamIdCommand}"
CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem InputGestureText="Ctrl+X"
Header="{Tr MainWindow.ContextMenus.Mafile.CopyMafile}"
Command="{Binding CopyMafileCommand}"
CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.AddToGroup}"
ItemsSource="{Binding Groups}">
<ItemsControl.ItemContainerStyle>
<Style BasedOn="{StaticResource MaterialDesignMenuItem}" TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding DataContext.AddToGroupCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<Style BasedOn="{StaticResource MaterialDesignMenuItem}"
TargetType="{x:Type MenuItem}">
<Setter Property="Command"
Value="{Binding DataContext.AddToGroupCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<Setter Property="CommandParameter">
<Setter.Value>
<MultiBinding Converter="{StaticResource MultiCommandParameterConverter}">
<MultiBinding
Converter="{StaticResource MultiCommandParameterConverter}">
<Binding />
<Binding Path="PlacementTarget.SelectedValue" RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
<Binding Path="PlacementTarget.SelectedValue"
RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
</MenuItem>
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.RemoveFromGroup}" Command="{Binding Path=RemoveGroupCommand}" CommandParameter="{Binding Path=PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.RemoveFromGroup}"
Command="{Binding Path=RemoveGroupCommand}"
CommandParameter="{Binding Path=PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.CopyPassword}"
Command="{Binding Path=CopyPasswordCommand}"
CommandParameter="{Binding Path=PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
</ContextMenu>
</FrameworkElement.ContextMenu>
</ListBox>
<Border Grid.Row="0" Margin="10" Padding="5" Visibility="{Binding MaFiles.Count, Converter={StaticResource AnyMafilesToVisibilityConverter}, Mode=OneWay}">
<Border Grid.Row="0" Margin="10" Padding="5"
Visibility="{Binding MaFiles.Count, Converter={StaticResource AnyMafilesToVisibilityConverter}, Mode=OneWay}">
<Border.Background>
<SolidColorBrush Color="DarkGray" Opacity="0.5"/>
<SolidColorBrush Color="DarkGray" Opacity="0.5" />
</Border.Background>
<TextBlock TextWrapping="WrapWithOverflow" FontSize="16" Text="{Tr MainWindow.Global.StartTip}"/>
<TextBlock TextWrapping="WrapWithOverflow" FontSize="16"
Text="{Tr MainWindow.Global.StartTip}" />
</Border>
<TextBox Style="{StaticResource MaterialDesignFloatingHintTextBox}" md:TextFieldAssist.HasClearButton="True" w:FontScaleWindow.Scale="0.7" w:FontScaleWindow.ResizeFont="True" Grid.Row="1" Margin="10,5,10,10" md:HintAssist.Hint="{Tr MainWindow.LeftPart.SearchBoxHint}" Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Style="{StaticResource MaterialDesignFloatingHintTextBox}"
md:TextFieldAssist.HasClearButton="True" w:FontScaleWindow.Scale="0.7"
w:FontScaleWindow.ResizeFont="True" Grid.Row="1" Margin="10,5,10,10"
md:HintAssist.Hint="{Tr MainWindow.LeftPart.SearchBoxHint}"
Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
<md:Card Grid.Column="1" Margin="10,10,15,10" UniformCornerRadius="15">
<Control.Background>
@@ -247,7 +332,10 @@
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox w:FontScaleWindow.Scale="1.1" w:FontScaleWindow.ResizeFont="True" IsReadOnly="True" HorizontalContentAlignment="Center" Background="#00FFFFFF" Style="{StaticResource MaterialDesignFilledTextBox}" Text="{Binding Code, FallbackValue=Code}">
<TextBox w:FontScaleWindow.Scale="1.1" w:FontScaleWindow.ResizeFont="True"
IsReadOnly="True" HorizontalContentAlignment="Center" Background="#00FFFFFF"
Style="{StaticResource MaterialDesignFilledTextBox}"
Text="{Binding Code, FallbackValue=Code}">
<TextBox.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding CopyCodeCommand}" />
</TextBox.InputBindings>
@@ -257,14 +345,27 @@
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ProgressBar Margin="5" Foreground="#FF9932CC" Height="15" md:TransitionAssist.DisableTransitions="True" Value="{Binding CodeProgress}" />
<ProgressBar Margin="5" Foreground="#FF9932CC" Height="15"
md:TransitionAssist.DisableTransitions="True"
Value="{Binding CodeProgress}" />
</Grid>
</Grid>
<Button IsEnabled="{Binding IsMafileSelected}" w:FontScaleWindow.Scale="0.7" w:FontScaleWindow.ResizeFont="True" Grid.Row="1" Style="{StaticResource MaterialDesignOutlinedButton}" Margin="10" Command="{Binding GetConfirmationsCommand}" Width="{Binding Path=ActualWidth, Converter={StaticResource CoefficientConverter}, ConverterParameter=0.6, RelativeSource={RelativeSource AncestorType=md:Card}}">
<TextBlock TextWrapping="Wrap" TextTrimming="WordEllipsis" Text="{Tr MainWindow.RightPart.LoadConfirmations}"/>
<Button IsEnabled="{Binding IsMafileSelected}" w:FontScaleWindow.Scale="0.7"
w:FontScaleWindow.ResizeFont="True" Grid.Row="1"
Style="{StaticResource MaterialDesignOutlinedButton}" Margin="10"
Command="{Binding GetConfirmationsCommand}"
Width="{Binding Path=ActualWidth, Converter={StaticResource CoefficientConverter}, ConverterParameter=0.6, RelativeSource={RelativeSource AncestorType=md:Card}}">
<TextBlock TextWrapping="Wrap" TextTrimming="WordEllipsis"
Text="{Tr MainWindow.RightPart.LoadConfirmations}" />
</Button>
<ItemsControl md:RippleAssist.IsDisabled="True" Focusable="False" Grid.Row="2" w:FontScaleWindow.Scale="0.72" w:FontScaleWindow.ResizeFont="True" Margin="10" Visibility="{Binding ConfirmationsVisible, Converter={StaticResource BooleanToVisibilityConverter}}" ItemsSource="{Binding Confirmations}"/>
<Button Grid.Row="3" Margin="1,0,1,3" w:FontScaleWindow.Scale="0.8" w:FontScaleWindow.ResizeFont="True" Command="{Binding ConfirmLoginCommand}" Content="{Tr MainWindow.RightPart.ConfirmLogin}"/>
<ItemsControl md:RippleAssist.IsDisabled="True" Focusable="False" Grid.Row="2"
w:FontScaleWindow.Scale="0.72" w:FontScaleWindow.ResizeFont="True"
Margin="10"
Visibility="{Binding ConfirmationsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
ItemsSource="{Binding Confirmations}" />
<Button Grid.Row="3" Margin="1,0,1,3" w:FontScaleWindow.Scale="0.8"
w:FontScaleWindow.ResizeFont="True" Command="{Binding ConfirmLoginCommand}"
Content="{Tr MainWindow.RightPart.ConfirmLogin}" />
</Grid>
</md:Card>
</Grid>
@@ -273,15 +374,23 @@
<SolidColorBrush Opacity="0.5" Color="DimGray" />
</Border.Background>
<Grid>
<ToolBarPanel Orientation="Horizontal" Margin="5" w:FontScaleWindow.Scale="0.73" w:FontScaleWindow.ResizeFont="True">
<ToolBarPanel Orientation="Horizontal" Margin="5" w:FontScaleWindow.Scale="0.73"
w:FontScaleWindow.ResizeFont="True">
<TextBlock FontWeight="Bold" Text="{Tr MainWindow.Footer.Account}" />
<TextBlock Text="{Binding SelectedMafile.AccountName}" />
<TextBlock Text="|" Margin="10,0,10,0" />
<TextBlock FontWeight="Bold" Text="{Tr MainWindow.Footer.Group}" />
<TextBlock FontWeight="Normal" Text="{Binding SelectedMafile.Group, TargetNullValue=' ', FallbackValue=' ', Mode=OneWay}" />
<TextBlock FontWeight="Normal"
Text="{Binding SelectedMafile.Group, TargetNullValue=' ', FallbackValue=' ', Mode=OneWay}" />
</ToolBarPanel>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" w:FontScaleWindow.Scale="0.7" w:FontScaleWindow.ResizeFont="True" Margin="0,0,10,0">
<Hyperlink NavigateUri="https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies" Foreground="{DynamicResource PrimaryHueMidBrush}" RequestNavigate="Hyperlink_OnRequestNavigate">by achies</Hyperlink>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" w:FontScaleWindow.Scale="0.7"
w:FontScaleWindow.ResizeFont="True" Margin="0,0,10,0">
<Hyperlink
NavigateUri="https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies"
Foreground="{DynamicResource PrimaryHueMidBrush}"
RequestNavigate="Hyperlink_OnRequestNavigate">
by achies
</Hyperlink>
</TextBlock>
</Grid>
</Border>
+20 -20
View File
@@ -1,10 +1,4 @@
using MaterialDesignThemes.Wpf;
using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.View.Dialogs;
using NebulaAuth.ViewModel;
using NebulaAuth.ViewModel.Other;
using System;
using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
@@ -12,6 +6,12 @@ using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Threading;
using MaterialDesignThemes.Wpf;
using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.View.Dialogs;
using NebulaAuth.ViewModel;
using NebulaAuth.ViewModel.Other;
namespace NebulaAuth;
@@ -37,7 +37,7 @@ public partial class MainWindow
private async Task ShowSetPasswordDialog()
{
var vm = new SetEncryptPasswordVM();
var dialog = new SetCryptPasswordDialog()
var dialog = new SetCryptPasswordDialog
{
DataContext = vm
};
@@ -49,12 +49,20 @@ public partial class MainWindow
}
}
private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.ToString())
{
UseShellExecute = true
});
}
#region Dran'n'Drop
private void UIElement_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
if (int.TryParse(e.Text, out _) == false) e.Handled = true;
}
private void Rectangle_DragEnter(object sender, DragEventArgs e)
@@ -72,12 +80,13 @@ public partial class MainWindow
private async void Rectangle_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop) == false) return;
string[] filePaths = (string[])e.Data.GetData(DataFormats.FileDrop)!;
var filePaths = (string[]) e.Data.GetData(DataFormats.FileDrop)!;
if (filePaths.Length == 0) return;
if (DataContext is MainVM mainVm)
{
await mainVm.AddMafile(filePaths);
}
DragNDropPanel.Visibility = Visibility.Hidden;
DragNDropOverlay.Visibility = Visibility.Hidden;
}
@@ -98,15 +107,6 @@ public partial class MainWindow
{
DragNDropBorder.AllowDrop = true;
}
#endregion
private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.ToString())
{
UseShellExecute = true
});
}
}
@@ -6,14 +6,12 @@ public class LoginConfirmationResult
{
[MemberNotNullWhen(false, nameof(Error))]
public bool Success { get; set; }
public string IP { get; set; } = null!;
public string Country { get; set; } = null!;
public LoginConfirmationError? Error { get; set; }
}
public enum LoginConfirmationError
{
NoRequests,
+1 -1
View File
@@ -5,7 +5,7 @@ using NebulaAuth.Model.Comparers;
namespace NebulaAuth.Model.Entities;
public class MaProxy
{
{
public int Id { get; }
public ProxyData Data { get; }
+4 -3
View File
@@ -20,8 +20,7 @@ public partial class Mafile : MobileDataExtended
set => SetProperty(ref _linkedClient, value);
}
[JsonIgnore]
private PortableMaClient? _linkedClient;
[JsonIgnore] private PortableMaClient? _linkedClient;
public void SetSessionData(MobileSessionData? sessionData)
@@ -48,7 +47,9 @@ public partial class Mafile : MobileDataExtended
SteamId = data.SteamId
};
}
public static Mafile FromMobileDataExtended(MobileDataExtended data, MaProxy? proxy, string? group, string? password)
public static Mafile FromMobileDataExtended(MobileDataExtended data, MaProxy? proxy, string? group,
string? password)
{
var result = FromMobileDataExtended(data);
result.Proxy = proxy;
@@ -8,9 +8,11 @@ namespace NebulaAuth.Model.Entities;
public class MarketMultiConfirmation : Confirmation
{
public ObservableCollection<MarketConfirmation> Confirmations { get; }
public MarketMultiConfirmation(IEnumerable<MarketConfirmation> confirmations) : base(0, 0, 0, 0, ConfirmationType.Unknown, "")
public MarketMultiConfirmation(IEnumerable<MarketConfirmation> confirmations) : base(0, 0, 0, 0,
ConfirmationType.Unknown, "")
{
Confirmations = new(confirmations);
Confirmations = new ObservableCollection<MarketConfirmation>(confirmations);
Time = Confirmations.FirstOrDefault()?.Time ?? default;
}
}
@@ -1,6 +1,5 @@
using System;
using NebulaAuth.Model.Entities;
using SteamLib;
namespace NebulaAuth.Model.Exceptions;
@@ -1,22 +1,23 @@
using AchiesUtilities.Extensions;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
using System;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AchiesUtilities.Extensions;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
using NLog;
namespace NebulaAuth.Model.MAAC;
public static class MultiAccountAutoConfirmer
{
private const string LOC_PATH = "MAAC";
private static readonly ReaderWriterLockSlim Lock = new();
public static ObservableCollection<Mafile> Clients { get; }
private static Timer Timer { get; }
private static readonly ReaderWriterLockSlim Lock = new();
private const string LOC_PATH = "MAAC";
static MultiAccountAutoConfirmer()
{
@@ -26,7 +27,37 @@ public static class MultiAccountAutoConfirmer
UpdateTimer();
}
private static readonly SemaphoreSlim ExecutionLock = new(1, 1);
// ReSharper disable once AsyncVoidMethod //Already safe
private static async void TimerConfirm(object? state)
{
bool isHeld = false;
try
{
isHeld = await ExecutionLock.WaitAsync(0);
if (!isHeld)
{
SnackbarController.SendSnackbar(GetLocalization("TimerPreventedOverlap"));
return;
}
await TimerConfirmInternal();
}
catch (Exception e)
{
Shell.Logger.Error(e, "Error in MAAC timer");
}
finally
{
if (isHeld)
{
ExecutionLock.Release();
}
}
}
private static async Task TimerConfirmInternal()
{
var clients = Lock.ReadLock(() => Clients.ToArray());
var enabledClients = clients.Where(x => x.LinkedClient is { IsError: false }).ToArray();
@@ -78,23 +109,22 @@ public static class MultiAccountAutoConfirmer
added = true;
}
}
}
while (added);
} while (added);
return result;
}
}
public static bool TryAddToConfirm(Mafile mafile)
{
return Lock.WriteLock(() =>
{
if (Clients.Contains(mafile)) return false;
Clients.Add(mafile);
mafile.LinkedClient = new PortableMaClient(mafile);
return true;
});
{
if (Clients.Contains(mafile)) return false;
Clients.Add(mafile);
mafile.LinkedClient = new PortableMaClient(mafile);
return true;
});
}
+38 -24
View File
@@ -1,4 +1,13 @@
using AchiesUtilities.Web.Proxy;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using AchiesUtilities.Web.Models;
using AchiesUtilities.Web.Proxy;
using CommunityToolkit.Mvvm.ComponentModel;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
@@ -9,30 +18,23 @@ using SteamLib.Core.Interfaces;
using SteamLib.Exceptions;
using SteamLib.SteamMobile.Confirmations;
using SteamLib.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using AchiesUtilities.Web.Models;
namespace NebulaAuth.Model.MAAC;
public partial class PortableMaClient : ObservableObject, IDisposable
{
private const string LOC_PATH = "MAAC";
public Mafile Mafile { get; }
private HttpClient Client { get; }
private HttpClientHandler ClientHandler { get; }
private DynamicProxy Proxy { get; }
[ObservableProperty] private bool _autoConfirmTrades;
[ObservableProperty] private bool _autoConfirmMarket;
[ObservableProperty] private bool _isError;
private const string LOC_PATH = "MAAC";
private readonly CancellationTokenSource _cts = new();
[ObservableProperty] private bool _autoConfirmMarket;
[ObservableProperty] private bool _autoConfirmTrades;
[ObservableProperty] private bool _isError;
public PortableMaClient(Mafile mafile)
{
Mafile = mafile;
@@ -45,7 +47,7 @@ public partial class PortableMaClient : ObservableObject, IDisposable
Mafile.PropertyChanged += Mafile_PropertyChanged;
}
private void Mafile_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
private void Mafile_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Mafile.SessionData))
{
@@ -84,12 +86,14 @@ public partial class PortableMaClient : ObservableObject, IDisposable
Shell.Logger.Warn(ex, "Timer {accountName}: Error GetConf in timer.", Mafile.AccountName);
return 0;
}
var toConfirm = new List<Confirmation>();
if (AutoConfirmMarket)
{
var market = conf.Where(c => c.ConfType == ConfirmationType.MarketSellTransaction);
toConfirm.AddRange(market);
}
if (AutoConfirmTrades)
{
var trade = conf.Where(c => c.ConfType == ConfirmationType.Trade);
@@ -99,7 +103,8 @@ public partial class PortableMaClient : ObservableObject, IDisposable
if (toConfirm.Count == 0) return 0;
try
{
Shell.Logger.Debug("Timer {accountName}: Sending confirmations. Count: {count}", Mafile.AccountName, toConfirm.Count);
Shell.Logger.Debug("Timer {accountName}: Sending confirmations. Count: {count}", Mafile.AccountName,
toConfirm.Count);
var success = await HandleTimerRequest(() => SendConfirmations(toConfirm));
Shell.Logger.Debug("Timer {accountName}: Confirmation sent: {confirmResult}", Mafile.AccountName, success);
return toConfirm.Count;
@@ -114,12 +119,14 @@ public partial class PortableMaClient : ObservableObject, IDisposable
private async Task<IEnumerable<Confirmation>> GetConfirmations()
{
return await SteamMobileConfirmationsApi.GetConfirmations(Client, Mafile, Mafile.SessionData!.SteamId, _cts.Token);
return await SteamMobileConfirmationsApi.GetConfirmations(Client, Mafile, Mafile.SessionData!.SteamId,
_cts.Token);
}
private async Task<bool> SendConfirmations(IEnumerable<Confirmation> confirmations)
{
return await SteamMobileConfirmationsApi.SendMultipleConfirmations(Client, confirmations, Mafile.SessionData!.SteamId, Mafile, true, _cts.Token);
return await SteamMobileConfirmationsApi.SendMultipleConfirmations(Client, confirmations,
Mafile.SessionData!.SteamId, Mafile, true, _cts.Token);
}
private async Task<T> HandleTimerRequest<T>(Func<Task<T>> func)
@@ -131,26 +138,30 @@ public partial class PortableMaClient : ObservableObject, IDisposable
}
catch (OperationCanceledException ex)
{
innerException = ex; //Ignored
innerException = ex; //Ignored
}
catch (SessionInvalidException ex)
{
if (IgnoreTimerErrors())
{
Shell.Logger.Warn("Timer {accountName}: Session error while requesting in timer. Ignored due to IgnorePatchTuesdayErrors setting", Mafile.AccountName);
Shell.Logger.Warn(
"Timer {accountName}: Session error while requesting in timer. Ignored due to IgnorePatchTuesdayErrors setting",
Mafile.AccountName);
}
else
{
Shell.Logger.Warn("Timer {accountName}: Session error while requesting in timer. Timer disabled", Mafile.AccountName);
Shell.Logger.Warn("Timer {accountName}: Session error while requesting in timer. Timer disabled",
Mafile.AccountName);
SetError();
}
innerException = ex;
}
catch (Exception ex) when (ExceptionHandler.Handle(ex, prefix: GetTimerPrefix()))
catch (Exception ex) when (ExceptionHandler.Handle(ex, GetTimerPrefix()))
{
innerException = ex;
}
throw new ApplicationException("Swallowed", innerException);
}
@@ -163,13 +174,16 @@ public partial class PortableMaClient : ObservableObject, IDisposable
var pstNow = TimeZoneInfo.ConvertTime(DateTime.UtcNow, pstZone);
var startTime = pstNow.Date.AddHours(15).AddMinutes(55); // 15:55 PST //22:55 GMT //00:55 GMT+2
var endTime = pstNow.Date.AddHours(17).AddMinutes(15); // 17:15 PST //00:15 GMT //02:15 GMT+2
var endTime = pstNow.Date.AddHours(17).AddMinutes(15); // 17:15 PST //00:15 GMT //02:15 GMT+2
return pstNow.DayOfWeek == DayOfWeek.Tuesday && pstNow >= startTime && pstNow <= endTime;
}
private HttpClientHandlerPair Chp() => new(Client, ClientHandler);
private HttpClientHandlerPair Chp()
{
return new HttpClientHandlerPair(Client, ClientHandler);
}
private static string GetLocalization(string key)
{
+25 -15
View File
@@ -1,4 +1,9 @@
using AchiesUtilities.Web.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using AchiesUtilities.Web.Models;
using AchiesUtilities.Web.Proxy;
using NebulaAuth.Model.Entities;
using SteamLib.Api.Mobile;
@@ -8,15 +13,9 @@ using SteamLib.Exceptions;
using SteamLib.ProtoCore.Services;
using SteamLib.SteamMobile.Confirmations;
using SteamLib.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace NebulaAuth.Model;
public static class MaClient
{
private static HttpClientHandler ClientHandler { get; }
@@ -26,7 +25,6 @@ public static class MaClient
private static DynamicProxy Proxy { get; }
public static ProxyData? DefaultProxy { get; set; }
public static HttpClientHandlerPair Chp => new(Client, ClientHandler);
static MaClient()
{
@@ -52,6 +50,7 @@ public static class MaClient
ClientHandler.CookieContainer.AddMinimalMobileCookies();
AdmissionHelper.TransferCommunityCookies(ClientHandler.CookieContainer);
}
Proxy.SetData(account.Proxy?.Data);
}
}
@@ -66,7 +65,8 @@ public static class MaClient
public static Task LoginAgain(Mafile mafile, string password, bool savePassword, ICaptchaResolver? resolver)
{
SetProxy(mafile);
return SessionHandler.LoginAgain(Chp, mafile, password, savePassword);
return SessionHandler.LoginAgain(new HttpClientHandlerPair(Client, ClientHandler), mafile, password,
savePassword);
}
@@ -74,27 +74,30 @@ public static class MaClient
{
ValidateMafile(mafile, true);
SetProxy(mafile);
return SessionHandler.RefreshMobileToken(Chp, mafile);
return SessionHandler.RefreshMobileToken(new HttpClientHandlerPair(Client, ClientHandler), mafile);
}
public static Task<bool> SendConfirmation(Mafile mafile, Confirmation confirmation, bool confirm)
{
ValidateMafile(mafile);
SetProxy(mafile);
return SteamMobileConfirmationsApi.SendConfirmation(Client, confirmation, mafile.SessionData!.SteamId, mafile, confirm);
return SteamMobileConfirmationsApi.SendConfirmation(Client, confirmation, mafile.SessionData!.SteamId, mafile,
confirm);
}
public static Task<bool> SendMultipleConfirmation(Mafile mafile, IEnumerable<Confirmation> confirmations, bool confirm)
public static Task<bool> SendMultipleConfirmation(Mafile mafile, IEnumerable<Confirmation> confirmations,
bool confirm)
{
var enumerable = confirmations.ToList();
if (enumerable.Count == 0)
{
return Task.FromResult(result: false);
return Task.FromResult(false);
}
ValidateMafile(mafile);
SetProxy(mafile);
return SteamMobileConfirmationsApi.SendMultipleConfirmations(Client, enumerable, mafile.SessionData!.SteamId, mafile, confirm);
return SteamMobileConfirmationsApi.SendMultipleConfirmations(Client, enumerable, mafile.SessionData!.SteamId,
mafile, confirm);
}
public static Task<RemoveAuthenticator_Response> RemoveAuthenticator(Mafile mafile)
@@ -105,6 +108,7 @@ public static class MaClient
{
throw new InvalidOperationException("This mafile does not have R-Code");
}
var token = mafile.SessionData!.GetMobileToken()!;
return SteamMobileApi.RemoveAuthenticator(Client, token.Value.Token, mafile.RevocationCode);
}
@@ -126,7 +130,6 @@ public static class MaClient
if (access == null || access.Value.IsExpired)
throw new SessionPermanentlyExpiredException();
}
}
public static async Task<LoginConfirmationResult> ConfirmLoginRequest(Mafile mafile)
@@ -143,6 +146,7 @@ public static class MaClient
Error = LoginConfirmationError.NoRequests
};
}
if (sessions.ClientIds.Count > 1)
{
return new LoginConfirmationResult
@@ -169,4 +173,10 @@ public static class MaClient
Success = true
};
}
public static HttpClientHandlerPair GetHttpClientHandlerPair(Mafile mafile)
{
SetProxy(mafile);
return new HttpClientHandlerPair(Client, ClientHandler);
}
}
+9 -11
View File
@@ -1,11 +1,11 @@
using NebulaAuth.Model.Entities;
using System;
using System.Collections.Generic;
using NebulaAuth.Model.Entities;
using NebulaAuth.Model.Exceptions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SteamLib;
using SteamLib.Utility.MafileSerialization;
using System.Collections.Generic;
using System;
using NebulaAuth.Model.Exceptions;
using Newtonsoft.Json;
namespace NebulaAuth.Model;
@@ -34,13 +34,13 @@ public static class NebulaSerializer
var info = data.Info;
if (info.IsExtended == false)
throw new FormatException("Mafile is not extended data");
var props = info.UnusedProperties ?? new Dictionary<string, JProperty>();
var proxy = GetPropertyValue<MaProxy>("Proxy", props);
var group = GetPropertyValue<string>("Group", props);
var password = GetPropertyValue<string>("Password", props);
var mafile = Mafile.FromMobileDataExtended((MobileDataExtended)mobileData, proxy, group, password);
var mafile = Mafile.FromMobileDataExtended((MobileDataExtended) mobileData, proxy, group, password);
if (!info.SteamIdValid)
@@ -82,9 +82,7 @@ public static class NebulaSerializer
{
return MafileSerializer.SerializeLegacy(data, Formatting.Indented, properties);
}
else
{
return MafileSerializer.Serialize(data);
}
return MafileSerializer.Serialize(data);
}
}
+14 -4
View File
@@ -7,15 +7,14 @@ namespace NebulaAuth.Model;
public static class PHandler
{
public static bool IsPasswordSet => _k.Length > 0;
private static byte[] _k = [];
public static bool IsPasswordSet => _k.Length > 0;
/// <summary>
///
/// </summary>
/// <param name="password"></param>
/// <returns><see langword="true"/> if password was set and not empty. Otherwise - <see langword="false"/></returns>
/// <returns><see langword="true" /> if password was set and not empty. Otherwise - <see langword="false" /></returns>
public static bool SetPassword(string? password)
{
if (string.IsNullOrWhiteSpace(password))
@@ -80,5 +79,16 @@ public static class PHandler
return decryptedText;
}
public static string? DecryptPassword(string? encryptedPassword)
{
if (string.IsNullOrWhiteSpace(encryptedPassword)) return null;
try
{
return Decrypt(encryptedPassword);
}
catch (Exception)
{
return null;
}
}
}
+3 -5
View File
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AchiesUtilities.Collections;
using AchiesUtilities.Web.Proxy;
using System.Linq;
using AchiesUtilities.Web.Proxy.Parsing;
using NebulaAuth.Core;
using Newtonsoft.Json;
@@ -12,14 +12,13 @@ namespace NebulaAuth.Model;
public static class ProxyStorage
{
public const string FORMAT = ADDRESS_FORMAT + ":{USER}:{PASS}";
public const string ADDRESS_FORMAT = "{IP}:{PORT}";
public static readonly ProxyParser DefaultScheme = new(
ProxyDefaultFormats.UniversalColon, false, ProxyProtocol.HTTP,
ProxyPatternProtocol.All,
ProxyPatternHostFormat.Domain | ProxyPatternHostFormat.IPv4,
ProxyPatternHostFormat.Domain | ProxyPatternHostFormat.IPv4,
PatternRequirement.Optional,
PatternRequirement.Optional);
@@ -29,7 +28,6 @@ public static class ProxyStorage
static ProxyStorage()
{
if (File.Exists("proxies.json") == false)
return;
try
@@ -145,7 +143,7 @@ public static class ProxyStorage
private class ProxiesSchema
{
public ObservableDictionary<int, ProxyData> ProxiesData = [];
public int? DefaultProxy;
public ObservableDictionary<int, ProxyData> ProxiesData = [];
}
}
+28 -27
View File
@@ -1,25 +1,24 @@
using AchiesUtilities.Web.Models;
using MaterialDesignThemes.Wpf;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
using SteamLib.Exceptions;
using System;
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using AchiesUtilities.Web.Models;
using MaterialDesignThemes.Wpf;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
using NebulaAuth.View.Dialogs;
using SteamLib.Exceptions;
namespace NebulaAuth.Model;
public static partial class SessionHandler
{
private static readonly SemaphoreSlim Semaphore = new(1, 1);
public static async Task<T> Handle<T>(Func<Task<T>> func, Mafile mafile,
HttpClientHandlerPair? chp = null, string? snackbarPrefix = null)
{
chp ??= MaClient.Chp;
chp ??= MaClient.GetHttpClientHandlerPair(mafile);
await Semaphore.WaitAsync();
try
{
@@ -50,12 +49,14 @@ public static partial class SessionHandler
{
if (ex is SessionPermanentlyExpiredException)
{
Shell.Logger.Debug(ex, "RefreshToken on mafile {name} {steamid} is expired", mafile.AccountName, mafile.SessionData?.SteamId);
Shell.Logger.Debug(ex, "RefreshToken on mafile {name} {steamid} is expired", mafile.AccountName,
mafile.SessionData?.SteamId);
refreshTokenExpired = true;
}
else
{
Shell.Logger.Debug(ex, "MobileToken on mafile {name} {steamid} is expired", mafile.AccountName, mafile.SessionData?.SteamId);
Shell.Logger.Debug(ex, "MobileToken on mafile {name} {steamid} is expired", mafile.AccountName,
mafile.SessionData?.SteamId);
}
}
}
@@ -67,21 +68,25 @@ public static partial class SessionHandler
var refreshed = await RefreshInternal(chp, mafile);
if (refreshed)
{
SnackbarController.SendSnackbar(snackbarPrefix + LocManager.GetCodeBehindOrDefault("SessionWasRefreshedAutomatically", "SessionHandler", "SessionWasRefreshedAutomatically"));
SnackbarController.SendSnackbar(snackbarPrefix +
LocManager.GetCodeBehindOrDefault("SessionWasRefreshedAutomatically",
"SessionHandler", "SessionWasRefreshedAutomatically"));
try
{
return await func();
}
catch (SessionInvalidException ex)
{
Shell.Logger.Info(ex, "MobileToken on {name} {steamid} was refreshed but after it, error occured", mafile.AccountName, mafile.SessionData?.SteamId);
Shell.Logger.Info(ex, "MobileToken on {name} {steamid} was refreshed but after it, error occured",
mafile.AccountName, mafile.SessionData?.SteamId);
if (password == null)
throw;
}
}
}
Shell.Logger.Debug("Session on mafile {name} {steamid} is invalid/expired", mafile.AccountName, mafile.SessionData?.SteamId);
Shell.Logger.Debug("Session on mafile {name} {steamid} is invalid/expired", mafile.AccountName,
mafile.SessionData?.SteamId);
//State: mobileToken invalid/expired, refreshToken invalid/expired
if (password != null)
@@ -89,7 +94,8 @@ public static partial class SessionHandler
var logged = await LoginAgainInternal(chp, mafile, password, true);
if (logged)
{
Shell.Logger.Debug("Mafile {name} {steamid} was succesfully auto-relogined", mafile.AccountName, mafile.SessionData?.SteamId);
Shell.Logger.Debug("Mafile {name} {steamid} was succesfully auto-relogined", mafile.AccountName,
mafile.SessionData?.SteamId);
return await func();
}
}
@@ -99,7 +105,6 @@ public static partial class SessionHandler
}
private static bool MobileTokenExpired(Mafile mafile)
{
var mobileToken = mafile.SessionData?.GetMobileToken();
@@ -108,7 +113,8 @@ public static partial class SessionHandler
private static bool RefreshTokenExpired(Mafile mafile)
{
return mafile.SessionData?.RefreshToken.IsExpired != false;
var refreshToken = mafile.SessionData?.RefreshToken;
return refreshToken == null || refreshToken.Value.IsExpired;
}
private static string? GetPassword(Mafile mafile)
@@ -136,9 +142,10 @@ public static partial class SessionHandler
await RefreshMobileToken(chp, mafile);
return true;
}
catch(Exception ex)
catch (SessionInvalidException ex)
{
Shell.Logger.Debug(ex, "Failed to refresh session on mafile {name} {steamid}", mafile.AccountName, mafile.SessionData?.SteamId);
Shell.Logger.Debug(ex, "Failed to refresh session on mafile {name} {steamid}", mafile.AccountName,
mafile.SessionData?.SteamId);
return false;
}
}
@@ -149,11 +156,10 @@ public static partial class SessionHandler
var t = Task.Run(OnLoginStarted);
try
{
await LoginAgain(chp, mafile, password, savePassword);
return true;
}
catch (Exception ex)
catch (Exception ex) //TODO: this will catch any error, even Proxy/Http/Socket errors.
{
Shell.Logger.Debug(ex, "Failed to relogin mafile {name} {steamid}", mafile.AccountName,
mafile.SessionData?.SteamId);
@@ -169,10 +175,7 @@ public static partial class SessionHandler
private static async Task OnLoginStarted()
{
if (DialogHost.IsDialogOpen(null)) return;
await Application.Current.Dispatcher.BeginInvoke(async () =>
{
await DialogHost.Show(new WaitLoginDialog());
});
await Application.Current.Dispatcher.BeginInvoke(async () => { await DialogHost.Show(new WaitLoginDialog()); });
}
private static void OnLoginCompleted()
@@ -180,7 +183,7 @@ public static partial class SessionHandler
var currentSession = DialogHost.GetDialogSession(null);
Application.Current.Dispatcher.BeginInvoke(() =>
{
if (currentSession is { Content: WaitLoginDialog, IsEnded: false })
if (currentSession is {Content: WaitLoginDialog, IsEnded: false})
{
try
{
@@ -193,6 +196,4 @@ public static partial class SessionHandler
}
});
}
}
+9 -7
View File
@@ -1,4 +1,5 @@
using AchiesUtilities.Web.Models;
using System.Threading.Tasks;
using AchiesUtilities.Web.Models;
using NebulaAuth.Model.Entities;
using SteamLib.Account;
using SteamLib.Api.Mobile;
@@ -6,7 +7,6 @@ using SteamLib.Authentication;
using SteamLib.Authentication.LoginV2;
using SteamLib.Exceptions;
using SteamLib.SteamMobile;
using System.Threading.Tasks;
namespace NebulaAuth.Model;
@@ -14,11 +14,13 @@ public partial class SessionHandler //API
{
public static async Task RefreshMobileToken(HttpClientHandlerPair chp, Mafile mafile)
{
if (mafile.SessionData is not { RefreshToken.IsExpired: false })
if (mafile.SessionData is not {RefreshToken.IsExpired: false})
throw new SessionPermanentlyExpiredException(SessionInvalidException.SESSION_NULL_MSG);
var mobileToken = await SteamMobileApi.RefreshJwt(chp.Client, mafile.SessionData.RefreshToken.Token, mafile.SessionData.SteamId);
Shell.Logger.Info("MobileToken on {name} {steamid} successfully refreshed", mafile.AccountName, mafile.SessionData.SteamId);
var mobileToken = await SteamMobileApi.RefreshJwt(chp.Client, mafile.SessionData.RefreshToken.Token,
mafile.SessionData.SteamId);
Shell.Logger.Info("MobileToken on {name} {steamid} successfully refreshed", mafile.AccountName,
mafile.SessionData.SteamId);
var newToken = SteamTokenHelper.Parse(mobileToken);
mafile.SessionData.SetMobileToken(newToken);
@@ -38,7 +40,7 @@ public partial class SessionHandler //API
Logger = Shell.ExtensionsLogger,
SteamGuardProvider = sgGenerator,
DeviceDetails = LoginV2ExecutorOptions.GetMobileDefaultDevice(),
WebsiteId = "Mobile",
WebsiteId = "Mobile"
};
chp.Handler.CookieContainer.ClearMobileSessionCookies();
var result = await LoginV2Executor.DoLogin(options, mafile.AccountName, password);
@@ -47,7 +49,7 @@ public partial class SessionHandler //API
//Triggers PropertyChanged event for PortableMaClient handling session updated from MaClient
//RETHINK: it makes double operation when session handled from PortableMaClient (more often scenario) which is unwanted behaviour
mafile.SetSessionData((MobileSessionData)result);
mafile.SetSessionData((MobileSessionData) result);
if (PHandler.IsPasswordSet)
mafile.Password = savePassword ? PHandler.Encrypt(password) : null;
Storage.UpdateMafile(mafile);
+25 -22
View File
@@ -1,36 +1,22 @@
using NebulaAuth.Core;
using Newtonsoft.Json;
using System;
using System;
using System.ComponentModel;
using System.IO;
using System.Windows.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using NebulaAuth.Core;
using Newtonsoft.Json;
namespace NebulaAuth.Model;
public partial class Settings : ObservableObject
{
#region Properties
[ObservableProperty] private BackgroundMode _backgroundMode = BackgroundMode.Default;
[ObservableProperty] private bool _hideToTray;
[ObservableProperty] private int _timerSeconds = 60;
[ObservableProperty] private Color? _backgroundColor;
[ObservableProperty] private Color? _iconColor;
[ObservableProperty] private bool _isPasswordSet;
[ObservableProperty] private LocalizationLanguage _language = LocalizationLanguage.English;
[ObservableProperty] private bool _legacyMode = true;
[ObservableProperty] private bool _allowAutoUpdate;
[ObservableProperty] private bool _useAccountNameAsMafileName;
[ObservableProperty] private bool _ignorePatchTuesdayErrors;
#endregion
public static Settings Instance { get; }
static Settings()
{
if (File.Exists("settings.json") == false)
{
Instance = new();
Instance = new Settings();
Instance.PropertyChanged += SettingsOnPropertyChanged;
return;
}
@@ -45,8 +31,9 @@ public partial class Settings : ObservableObject
{
SnackbarController.SendSnackbar("Ошибка при загрузке настроек. Настройки были сброшены");
SnackbarController.SendSnackbar(ex.Message);
Instance = new();
Instance = new Settings();
}
Instance.PropertyChanged += SettingsOnPropertyChanged;
}
@@ -61,10 +48,26 @@ public partial class Settings : ObservableObject
File.WriteAllText("settings.json", json);
}
}
#region Properties
[ObservableProperty] private BackgroundMode _backgroundMode = BackgroundMode.Default;
[ObservableProperty] private bool _hideToTray;
[ObservableProperty] private int _timerSeconds = 60;
[ObservableProperty] private Color? _backgroundColor;
[ObservableProperty] private Color? _iconColor;
[ObservableProperty] private bool _isPasswordSet;
[ObservableProperty] private LocalizationLanguage _language = LocalizationLanguage.English;
[ObservableProperty] private bool _legacyMode = true;
[ObservableProperty] private bool _allowAutoUpdate;
[ObservableProperty] private bool _useAccountNameAsMafileName;
[ObservableProperty] private bool _ignorePatchTuesdayErrors;
#endregion
}
public enum BackgroundMode
{
Default, Custom, Color
Default,
Custom,
Color
}
+9 -7
View File
@@ -1,9 +1,10 @@
using NebulaAuth.Model.Exceptions;
using System;
using Microsoft.Extensions.Logging;
using NebulaAuth.Model.Exceptions;
using NLog;
using NLog.Extensions.Logging;
using SteamLib.Core;
using SteamLib.SteamMobile;
using System;
using Microsoft.Extensions.Logging;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace NebulaAuth.Model;
@@ -12,15 +13,15 @@ public static class Shell
{
public static Logger Logger { get; } = LogManager.GetLogger("Logger");
public static ILogger ExtensionsLogger { get; private set; } = null!;
public static void Initialize()
{
var lp = new NLog.Extensions.Logging.NLogLoggerProvider();
var lp = new NLogLoggerProvider();
var logger = lp.CreateLogger("SteamLib");
SteamLibErrorMonitor.MonitorLogger = logger;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
var loggerFactory = new NLog.Extensions.Logging.NLogLoggerFactory();
var loggerFactory = new NLogLoggerFactory();
ExtensionsLogger = loggerFactory.CreateLogger("Logger");
try
@@ -31,11 +32,12 @@ public static class Shell
{
throw new CantAlignTimeException("", ex);
}
ExtensionsLogger.LogDebug("Application started");
}
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Logger.Fatal((Exception)e.ExceptionObject);
Logger.Fatal((Exception) e.ExceptionObject);
}
}
+28 -20
View File
@@ -1,16 +1,14 @@
using NebulaAuth.Model.Entities;
using SteamLib.Core.Models;
using SteamLib.Exceptions;
using SteamLib.SteamMobile;
using System;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using AchiesUtilities.Extensions;
using NebulaAuth.Model.Entities;
using NebulaAuth.Model.Exceptions;
using NLog.Targets;
using SteamLib;
using SteamLib.Core.Models;
using SteamLib.Exceptions;
using SteamLib.SteamMobile;
namespace NebulaAuth.Model;
@@ -20,12 +18,13 @@ public static class Storage
public const string MAFILE_F = "maFiles";
public const string REMOVED_F = "maFiles_removed";
public static readonly int DuplicateFound;
public static string MafileFolder { get; } = Path.GetFullPath(MAFILE_F);
public static string RemovedMafileFolder { get; } = Path.GetFullPath(REMOVED_F);
public static ObservableCollection<Mafile> MaFiles { get; } = new();
public static readonly int DuplicateFound;
static Storage()
{
if (Directory.Exists(MafileFolder) == false)
@@ -55,6 +54,7 @@ public static class Storage
Shell.Logger.Error("Duplicate mafile {file}", Path.GetFileName(file));
continue;
}
hashNames.Add(data.AccountName);
if (data.SessionData != null) hashIds.Add(data.SteamId);
MaFiles.Add(data);
@@ -69,7 +69,6 @@ public static class Storage
}
/// <summary>
///
/// </summary>
/// <param name="path"></param>
/// <param name="overwrite"></param>
@@ -84,11 +83,12 @@ public static class Storage
data = ReadMafile(path);
}
catch (Exception ex)
when(ex is not MafileNeedReloginException)
when (ex is not MafileNeedReloginException)
{
Shell.Logger.Warn(ex, "Can't load mafile");
throw new FormatException("File data is not valid", ex);
}
if (string.IsNullOrWhiteSpace(data.AccountName))
throw new FormatException("File data is not valid. Missing AccountName");
@@ -153,6 +153,7 @@ public static class Storage
i++;
copyPathCompleted = copyPath + $" ({i})";
}
File.Copy(path, copyPathCompleted, false);
File.Delete(path);
MaFiles.Remove(data);
@@ -167,8 +168,15 @@ public static class Storage
return Path.Combine(MafileFolder, fileName);
}
private static string CreateFileNameWithAccountName(string accountName) => accountName + ".mafile";
private static string CreateFileNameWithSteamId(SteamId steamId) => steamId.Steam64.Id + ".mafile";
private static string CreateFileNameWithAccountName(string accountName)
{
return accountName + ".mafile";
}
private static string CreateFileNameWithSteamId(SteamId steamId)
{
return steamId.Steam64.Id + ".mafile";
}
public static string? TryFindMafilePath(Mafile data)
{
@@ -186,10 +194,12 @@ public static class Storage
{
return Settings.Instance.UseAccountNameAsMafileName ? pathFileName : pathSteamId;
}
if (steamIdExist ^ accountNameExist)
{
return steamIdExist ? pathSteamId : pathFileName;
}
return null;
}
}
@@ -197,9 +207,10 @@ public static class Storage
//TODO: Refactor
internal class MafileNameComparer : IComparer<string>
{
public bool MafileNameMode { get; }
private const string MAF_64_START = "765";
private static readonly IComparer<string> DefaultComparer = Comparer<string>.Default;
public bool MafileNameMode { get; }
public MafileNameComparer(bool mafileNameMode)
{
MafileNameMode = mafileNameMode;
@@ -213,8 +224,8 @@ internal class MafileNameComparer : IComparer<string>
if (y == null) return 1;
bool xisSteamId = Path.GetFileName(x).StartsWith(MAF_64_START);
bool yisSteamId = Path.GetFileName(y).StartsWith(MAF_64_START);
var xisSteamId = Path.GetFileName(x).StartsWith(MAF_64_START);
var yisSteamId = Path.GetFileName(y).StartsWith(MAF_64_START);
if (xisSteamId ^ yisSteamId)
{
@@ -222,13 +233,10 @@ internal class MafileNameComparer : IComparer<string>
{
return xisSteamId ? 1 : -1;
}
else
{
return yisSteamId ? 1 : -1;
}
return yisSteamId ? 1 : -1;
}
return DefaultComparer.Compare(x, y);
}
}
+6 -6
View File
@@ -1,22 +1,22 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
throwExceptions="true">
<targets>
<target xsi:type="File" name="File" fileName="log.log"
deleteOldFileOnStartup="true"
>
deleteOldFileOnStartup="true">
<layout xsi:type='CompoundLayout'>
<layout xsi:type="JsonLayout" includeEventProperties="true" IncludeScopeProperties="true">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level:upperCase=true}"/>
<attribute name="level" layout="${level:upperCase=true}" />
<attribute name="message" layout="${message}" />
<attribute name="exception" layout="${exception:format=@}" encode="false"/>
<attribute name="exception" layout="${exception:format=@}" encode="false" />
</layout>
<layout type='SimpleLayout' text="," />
</layout>
</target>
</targets>
+1 -1
View File
@@ -10,7 +10,7 @@
<SatelliteResourceLanguages>en;ru;ua</SatelliteResourceLanguages>
<ApplicationIcon>Theme\lock.ico</ApplicationIcon>
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
<AssemblyVersion>1.5.5</AssemblyVersion>
<AssemblyVersion>1.5.6</AssemblyVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
+82 -62
View File
@@ -6,51 +6,15 @@ namespace NebulaAuth.Theme;
public class FontScaleWindow : Window
{
private readonly Func<double, double, double> _diagonal = (h, w) => Math.Sqrt(h * h + w * w);
private double _currentDiagonal;
private double _defaultDiagonal = 1;
private readonly HashSet<FrameworkElement> _cachedObjects = new();
private bool _loaded;
public FontScaleWindow()
{
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
var w = (FontScaleWindow)sender;
w._defaultDiagonal = _diagonal(MinHeight, MinWidth);
w.SizeChanged += OnSizeChanged;
w.Loaded -= OnLoaded;
_loaded = true;
w.Width += 1;
w.Width -= 1;
}
//<-------------------Window-------------------->
public double DefaultFontSize
{
get => (double)GetValue(DefaultFontSizeProperty);
set => SetValue(DefaultFontSizeProperty, value);
}
public double ScaleCoefficient
{
get => (double)GetValue(ScaleCoefficientProperty);
set => SetValue(ScaleCoefficientProperty, value);
}
// Using a DependencyProperty as the backing store for ScaleCoefficient. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScaleCoefficientProperty =
DependencyProperty.Register("ScaleCoefficient", typeof(double), typeof(FontScaleWindow), new PropertyMetadata(1d));
DependencyProperty.Register("ScaleCoefficient", typeof(double), typeof(FontScaleWindow),
new PropertyMetadata(1d));
public static readonly DependencyProperty DefaultFontSizeProperty =
DependencyProperty.Register("DefaultFontSize", typeof(double), typeof(FontScaleWindow), new PropertyMetadata(20d));
DependencyProperty.Register("DefaultFontSize", typeof(double), typeof(FontScaleWindow),
new PropertyMetadata(20d));
private static readonly DependencyPropertyKey ParentScaleWindowKey
@@ -63,19 +27,74 @@ public class FontScaleWindow : Window
public static readonly DependencyProperty ParentScaleWindowProperty
= ParentScaleWindowKey.DependencyProperty;
private static FontScaleWindow? GetParentScaleWindow(DependencyObject element) =>
(FontScaleWindow)element.GetValue(ParentScaleWindowProperty);
private static void SetParentScaleWindow(DependencyObject element, FontScaleWindow value) =>
element.SetValue(ParentScaleWindowKey, value);
public static readonly DependencyProperty ResizeFontProperty = DependencyProperty.RegisterAttached(
"ResizeFont", typeof(bool), typeof(FontScaleWindow), new FrameworkPropertyMetadata(false, ResizeCallBack));
//<-------------------Window-------------------->
//<-------------------Scaling-------------------->
public static readonly DependencyProperty ScaleProperty = DependencyProperty.RegisterAttached(
"Scale", typeof(double), typeof(FontScaleWindow),
new FrameworkPropertyMetadata(0.9999d, FrameworkPropertyMetadataOptions.Inherits, ScalePropertyCallback));
//<-------------------Window-------------------->
public double DefaultFontSize
{
get => (double) GetValue(DefaultFontSizeProperty);
set => SetValue(DefaultFontSizeProperty, value);
}
public double ScaleCoefficient
{
get => (double) GetValue(ScaleCoefficientProperty);
set => SetValue(ScaleCoefficientProperty, value);
}
private readonly HashSet<FrameworkElement> _cachedObjects = new();
private readonly Func<double, double, double> _diagonal = (h, w) => Math.Sqrt(h * h + w * w);
private double _currentDiagonal;
private double _defaultDiagonal = 1;
private bool _loaded;
public FontScaleWindow()
{
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
var w = (FontScaleWindow) sender;
w._defaultDiagonal = _diagonal(MinHeight, MinWidth);
w.SizeChanged += OnSizeChanged;
w.Loaded -= OnLoaded;
_loaded = true;
w.Width += 1;
w.Width -= 1;
}
private static FontScaleWindow? GetParentScaleWindow(DependencyObject element)
{
return (FontScaleWindow) element.GetValue(ParentScaleWindowProperty);
}
private static void SetParentScaleWindow(DependencyObject element, FontScaleWindow value)
{
element.SetValue(ParentScaleWindowKey, value);
}
public static void SetResizeFont(DependencyObject element, bool value)
=> element.SetValue(ResizeFontProperty, value);
{
element.SetValue(ResizeFontProperty, value);
}
public static bool GetResizeFont(DependencyObject element)
=> (bool)element.GetValue(ResizeFontProperty);
{
return (bool) element.GetValue(ResizeFontProperty);
}
private static bool SetWindow(FrameworkElement el)
{
@@ -91,7 +110,7 @@ public class FontScaleWindow : Window
private static void ObjOnLoaded(object sender, RoutedEventArgs e)
{
var el = (FrameworkElement)sender;
var el = (FrameworkElement) sender;
if (GetParentScaleWindow(el) == null)
{
if (!SetWindow(el))
@@ -100,6 +119,7 @@ public class FontScaleWindow : Window
return;
}
}
ResizeCallBack(sender, new DependencyPropertyChangedEventArgs());
}
@@ -116,17 +136,19 @@ public class FontScaleWindow : Window
obj.Loaded += ObjOnLoaded;
}
if (window is not { _loaded: true }) return;
if (window is not {_loaded: true}) return;
CalculateFontSizeResized(obj);
}
private static void ObjOnUnloaded(object sender, RoutedEventArgs e)
{
var obj = (FrameworkElement)sender;
var obj = (FrameworkElement) sender;
var w = GetParentScaleWindow(obj)!;
w._cachedObjects.Remove(obj);
obj.Unloaded -= ObjOnUnloaded;
obj.Loaded -= ObjOnLoaded;
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
_currentDiagonal = _diagonal(e.NewSize.Width, e.NewSize.Height);
@@ -135,18 +157,16 @@ public class FontScaleWindow : Window
CalculateFontSizeResized(cached);
}
}
//<-------------------Window-------------------->
//<-------------------Scaling-------------------->
public static readonly DependencyProperty ScaleProperty = DependencyProperty.RegisterAttached(
"Scale", typeof(double), typeof(FontScaleWindow), new FrameworkPropertyMetadata(0.9999d ,FrameworkPropertyMetadataOptions.Inherits, ScalePropertyCallback));
public static void SetScale(DependencyObject element, double value)
=> element.SetValue(ScaleProperty, value);
{
element.SetValue(ScaleProperty, value);
}
public static double GetScale(DependencyObject element)
=> (double)element.GetValue(ScaleProperty);
{
return (double) element.GetValue(ScaleProperty);
}
private static void ScalePropertyCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
@@ -160,6 +180,7 @@ public class FontScaleWindow : Window
SetParentScaleWindow(d, fsWindow);
}
}
ResizeElement(d);
}
@@ -176,9 +197,9 @@ public class FontScaleWindow : Window
{
CalculateFontSize(d);
}
}
}
public static void CalculateFontSize(DependencyObject d)
{
var window = GetParentScaleWindow(d);
@@ -196,5 +217,4 @@ public class FontScaleWindow : Window
var fontSize = window.DefaultFontSize * elScale * windowsScale;
d.SetValue(FontSizeProperty, fontSize);
}
}
}
+33 -33
View File
@@ -2,33 +2,33 @@
x:Class="LolzFucker.Theme.Palette"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300">
<UserControl.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="DemiBold"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="FontWeight" Value="DemiBold" />
<Setter Property="Margin" Value="4" />
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Border
@@ -36,7 +36,7 @@
Grid.ColumnSpan="3">
<TextBlock
Foreground="{DynamicResource PrimaryHueMidForegroundBrush}"
Text="Primary - Mid"/>
Text="Primary - Mid" />
</Border>
<Border
@@ -46,7 +46,7 @@
<TextBlock
FontWeight="Bold"
Foreground="{DynamicResource PrimaryHueLightForegroundBrush}"
Text="Light"/>
Text="Light" />
</Border>
<Border
@@ -55,7 +55,7 @@
Grid.Column="1">
<TextBlock
Foreground="{DynamicResource PrimaryHueMidForegroundBrush}"
Text="Mid"/>
Text="Mid" />
</Border>
<Border
@@ -64,7 +64,7 @@
Grid.Column="2">
<TextBlock
Foreground="{DynamicResource PrimaryHueDarkForegroundBrush}"
Text="Dark"/>
Text="Dark" />
</Border>
<Border
@@ -73,7 +73,7 @@
Grid.Column="0">
<TextBlock
Foreground="{DynamicResource SecondaryHueLightForegroundBrush}"
Text="Light"/>
Text="Light" />
</Border>
<Border
Background="{DynamicResource SecondaryHueMidBrush}"
@@ -81,7 +81,7 @@
Grid.Column="1">
<TextBlock
Foreground="{DynamicResource SecondaryHueMidForegroundBrush}"
Text="Mid"/>
Text="Mid" />
</Border>
<Border
Background="{DynamicResource SecondaryHueDarkBrush}"
@@ -89,7 +89,7 @@
Grid.Column="2">
<TextBlock
Foreground="{DynamicResource SecondaryHueDarkForegroundBrush}"
Text="Dark"/>
Text="Dark" />
</Border>
<Border
@@ -98,16 +98,16 @@
Grid.Column="0">
<TextBlock
Foreground="{DynamicResource SecondaryHueDarkForegroundBrush}"
Text="Background"/>
Text="Background" />
</Border>
<Border
Background="{DynamicResource MaterialDesignCardBackground}"
Grid.Row="3"
Grid.Column="1">
<TextBlock
Foreground="{DynamicResource SecondaryHueMidForegroundBrush}"
Text="CardBack"/>
Grid.Row="3"
Grid.Column="1">
<TextBlock
Foreground="{DynamicResource SecondaryHueMidForegroundBrush}"
Text="CardBack" />
</Border>
<Border
@@ -116,7 +116,7 @@
Grid.Column="2">
<TextBlock
Foreground="{DynamicResource SecondaryHueMidForegroundBrush}"
Text="Paper"/>
Text="Paper" />
</Border>
<Border
@@ -124,8 +124,8 @@
Grid.Row="4"
Grid.Column="0">
<TextBlock
Text="Body"/>
Text="Body" />
</Border>
<Border
Background="{DynamicResource MaterialDesignBodyLight}"
@@ -133,14 +133,14 @@
Grid.Column="1">
<TextBlock
Foreground="{DynamicResource SecondaryHueMidForegroundBrush}"
Text="BodyLight"/>
Text="BodyLight" />
</Border>
<Border
Background="{DynamicResource MaterialDesignToolTipBackground}"
Grid.Row="4"
Grid.Column="2">
<TextBlock
Text="ToolTipBack"/>
Text="ToolTipBack" />
</Border>
</Grid>
</UserControl>
</UserControl>
+30 -25
View File
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
// ReSharper disable IdentifierTypo
@@ -8,18 +9,6 @@ namespace NebulaAuth.Theme.WindowStyle;
// ReSharper disable once PartialTypeWithSinglePart //Required
public static partial class NativeMethods
{
public const int WM_NCCALCSIZE = 0x83;
public const int WM_NCPAINT = 0x85;
[DllImport("kernel32", SetLastError = true)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern bool DwmIsCompositionEnabled();
[DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
public enum DWMWINDOWATTRIBUTE : uint
{
NCRenderingEnabled = 1,
@@ -39,16 +28,17 @@ public static partial class NativeMethods
FreezeRepresentation
}
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
public int leftWidth;
public int rightWidth;
public int topHeight;
public int bottomHeight;
}
public const int WM_NCCALCSIZE = 0x83;
public const int WM_NCPAINT = 0x85;
private delegate int DwmExtendFrameIntoClientAreaDelegate(IntPtr hwnd, ref MARGINS margins);
[DllImport("kernel32", SetLastError = true)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern bool DwmIsCompositionEnabled();
[DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
public static int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins)
{
@@ -66,7 +56,9 @@ public static partial class NativeMethods
return 0;
}
var delegateForFunctionPointer = (DwmExtendFrameIntoClientAreaDelegate)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(DwmExtendFrameIntoClientAreaDelegate));
var delegateForFunctionPointer =
(DwmExtendFrameIntoClientAreaDelegate) Marshal.GetDelegateForFunctionPointer(procAddress,
typeof(DwmExtendFrameIntoClientAreaDelegate));
return delegateForFunctionPointer(hwnd, ref margins);
}
@@ -77,9 +69,25 @@ public static partial class NativeMethods
{
return false;
}
return true;
}
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy,
int uFlags);
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
public int leftWidth;
public int rightWidth;
public int topHeight;
public int bottomHeight;
}
private delegate int DwmExtendFrameIntoClientAreaDelegate(IntPtr hwnd, ref MARGINS margins);
internal enum WVR
{
ALIGNTOP = 0x0010,
@@ -91,7 +99,4 @@ public static partial class NativeMethods
VALIDRECTS = 0x0400,
REDRAW = HREDRAW | VREDRAW
}
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
}
@@ -9,10 +9,11 @@ namespace NebulaAuth.Theme.WindowStyle;
public static class WindowChromeHelper
{
public static Thickness LayoutOffsetThickness => new(0d, 0d, 0d, SystemParameters.WindowResizeBorderThickness.Bottom);
public static Thickness LayoutOffsetThickness =>
new(0d, 0d, 0d, SystemParameters.WindowResizeBorderThickness.Bottom);
/// <summary>
/// Gets the properly adjusted window resize border thickness from system parameters.
/// Gets the properly adjusted window resize border thickness from system parameters.
/// </summary>
public static Thickness WindowResizeBorderThickness
{
@@ -52,24 +53,25 @@ public static class WindowChromeHelper
float dpi;
try
{
dpi = GetDeviceCaps(dc, (int)index);
dpi = GetDeviceCaps(dc, (int) index);
}
finally
{
ReleaseDC(desktopWnd, dc);
}
return dpi / 96f;
}
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(GetSystemMetricsIndex nIndex);
private enum GetDeviceCapsIndex
{
LOGPIXELSX = 88,
LOGPIXELSY = 90
}
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(GetSystemMetricsIndex nIndex);
private enum GetSystemMetricsIndex
{
CXFRAME = 32,
@@ -60,11 +60,11 @@ public class WindowChromeRenderedBehavior : Behavior<Window>
break;
case NativeMethods.WM_NCCALCSIZE:
handled = true;
var rcClientArea = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT));
rcClientArea.Bottom += (int)(WindowChromeHelper.WindowResizeBorderThickness.Bottom / 2);
var rcClientArea = (RECT) Marshal.PtrToStructure(lParam, typeof(RECT));
rcClientArea.Bottom += (int) (WindowChromeHelper.WindowResizeBorderThickness.Bottom / 2);
Marshal.StructureToPtr(rcClientArea, lParam, false);
return wParam == new IntPtr(1) ? new IntPtr((int)NativeMethods.WVR.REDRAW) : IntPtr.Zero;
return wParam == new IntPtr(1) ? new IntPtr((int) NativeMethods.WVR.REDRAW) : IntPtr.Zero;
}
return IntPtr.Zero;
+20 -20
View File
@@ -8,7 +8,7 @@
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True" />
</Style>
<ControlTemplate x:Key="WindowTemplate" TargetType="{x:Type Window}" >
<ControlTemplate x:Key="WindowTemplate" TargetType="{x:Type Window}">
<!--<i:Interaction.Behaviors>
<local:WindowChromeLoadedBehavior />
</i:Interaction.Behaviors>-->
@@ -24,43 +24,42 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid x:Name="TitleBar"
Grid.Row="0"
Height="28"
Background="{DynamicResource WindowBackground}">
Grid.Row="0"
Height="28"
Background="{DynamicResource WindowBackground}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryHueMidBrush}"
Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Title}" FontSize="17"/>
Foreground="{DynamicResource PrimaryHueMidBrush}"
Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Title}"
FontSize="17" />
<!-- Window Buttons -->
<StackPanel
HorizontalAlignment="Right"
Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="materialDesign:PackIcon">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</StackPanel.Resources>
<Button x:Name="MinimizeButton"
Click="OnMinimizeClick"
>
<materialDesign:PackIcon Kind="WindowMinimize"/>
Click="OnMinimizeClick">
<materialDesign:PackIcon Kind="WindowMinimize" />
</Button>
<Button x:Name="MaximizeRestoreButton"
Click="OnMaximizeRestoreClick"
>
<materialDesign:PackIcon Kind="WindowMaximize"/>
Click="OnMaximizeRestoreClick">
<materialDesign:PackIcon Kind="WindowMaximize" />
</Button>
<Button x:Name="CloseButton"
Click="OnCloseClick">
<materialDesign:PackIcon Kind="WindowClose"/>
<materialDesign:PackIcon Kind="WindowClose" />
</Button>
</StackPanel>
</Grid>
<!-- Main Window Content -->
<Grid x:Name="MainGrid"
Grid.Row="1"
Background="{DynamicResource MainBackgroundBrush}">
Grid.Row="1"
Background="{DynamicResource MainBackgroundBrush}">
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
@@ -74,11 +73,12 @@
</Trigger>
<Trigger Property="WindowState" Value="Maximized">
<Setter TargetName="RootBorder" Property="BorderThickness" Value="{Binding Source={x:Static local:WindowChromeHelper.WindowResizeBorderThickness}}" />
<Setter TargetName="RootBorder" Property="BorderThickness"
Value="{Binding Source={x:Static local:WindowChromeHelper.WindowResizeBorderThickness}}" />
<Setter TargetName="RootBorder" Property="BorderBrush" Value="Transparent" />
<Setter TargetName="MaximizeRestoreButton" Property="Content" >
<Setter TargetName="MaximizeRestoreButton" Property="Content">
<Setter.Value>
<materialDesign:PackIcon Kind="WindowRestore"/>
<materialDesign:PackIcon Kind="WindowRestore" />
</Setter.Value>
</Setter>
</Trigger>
@@ -3,7 +3,7 @@
namespace NebulaAuth.Theme.WindowStyle;
/// <summary>
/// Логика взаимодействия для WindowStyle.xaml
/// Логика взаимодействия для WindowStyle.xaml
/// </summary>
partial class WindowStyle
{
@@ -14,21 +14,21 @@ partial class WindowStyle
private void OnCloseClick(object sender, RoutedEventArgs e)
{
var window = (Window)((FrameworkElement)sender).TemplatedParent;
var window = (Window) ((FrameworkElement) sender).TemplatedParent;
window.Close();
}
private void OnMaximizeRestoreClick(object sender, RoutedEventArgs e)
{
var window = (Window)((FrameworkElement)sender).TemplatedParent;
var window = (Window) ((FrameworkElement) sender).TemplatedParent;
window.WindowState = window.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal;
}
private void OnMinimizeClick(object sender, RoutedEventArgs e)
{
var window = (Window)((FrameworkElement)sender).TemplatedParent;
var window = (Window) ((FrameworkElement) sender).TemplatedParent;
window.WindowState = WindowState.Minimized;
}
+5 -5
View File
@@ -1,8 +1,8 @@
using NebulaAuth.Core;
using NebulaAuth.Model;
using System;
using System;
using System.Collections.Specialized;
using System.Windows;
using NebulaAuth.Core;
using NebulaAuth.Model;
namespace NebulaAuth.Utility;
@@ -25,8 +25,8 @@ public class ClipboardHelper
Shell.Logger.Error(ex);
SnackbarController.SendSnackbar(LocManager.GetCommonOrDefault("Error", "Error"));
}
}
i++;
}
@@ -50,8 +50,8 @@ public class ClipboardHelper
Shell.Logger.Error(ex);
SnackbarController.SendSnackbar(LocManager.GetCommonOrDefault("Error", "Error"));
}
}
i++;
}
@@ -8,7 +8,6 @@ namespace NebulaAuth.Utility;
public static class ErrorTranslatorHelper
{
public static string TranslateLoginError(LoginError error)
{
var result = GetMessage("Login", error.ToString());
@@ -20,7 +19,6 @@ public static class ErrorTranslatorHelper
{
var result = GetMessage("EResult", eResult.ToString());
return result ?? eResult.ToString();
}
public static string TranslateLinkerError(AuthenticatorLinkerError error)
@@ -34,6 +32,5 @@ public static class ErrorTranslatorHelper
var message = Loc.Tr(fullPath, "|ABSENT|");
if (message == "|ABSENT|") return null;
return message;
}
}
+69 -62
View File
@@ -1,93 +1,99 @@
using NebulaAuth.Core;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using NebulaAuth.Core;
using NebulaAuth.Model;
using SteamLib.Exceptions;
using SteamLib.Exceptions.General;
using SteamLib.ProtoCore.Exceptions;
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace NebulaAuth.Utility;
public static class ExceptionHandler
{
private const string EXCEPTION_HANDLER_LOC_PATH = "ExceptionHandler";
public static bool Handle(Exception ex, string? prefix = null, string? postfix = null, bool handleAllExceptions = false)
public static bool Handle(Exception ex, string? prefix = null, string? postfix = null,
bool handleAllExceptions = false)
{
string msg;
Shell.Logger.Error(ex);
switch (ex)
{
case SessionPermanentlyExpiredException:
{
msg = "SessionExpiredException".GetCodeBehindLocalization();
break;
}
{
msg = "SessionExpiredException".GetCodeBehindLocalization();
break;
}
case SessionInvalidException:
{
msg = "SessionExpiredException".GetCodeBehindLocalization();
break;
}
{
msg = "SessionExpiredException".GetCodeBehindLocalization();
break;
}
case TaskCanceledException e:
{
msg = e.InnerException is TimeoutException
? "TimeoutException".GetCodeBehindLocalization()
: "TaskCanceledException".GetCodeBehindLocalization();
break;
}
{
msg = e.InnerException is TimeoutException
? "TimeoutException".GetCodeBehindLocalization()
: "TaskCanceledException".GetCodeBehindLocalization();
break;
}
case HttpRequestException e:
{
var str = "RequestError".GetCommonLocalization() + ": ";
if (e.StatusCode != null)
{
var str = "RequestError".GetCommonLocalization() + ": ";
if (e.StatusCode != null)
{
msg = str + e.StatusCode;
}
else if (e.InnerException != null)
{
msg = (str + e.InnerException.Message);
}
else
{
msg = (str + e.Message);
}
msg = str + e.StatusCode;
}
else if (e.InnerException != null)
{
msg = str + e.InnerException.Message;
}
else
{
msg = str + e.Message;
}
break;
}
break;
}
case UnsupportedResponseException:
{
msg = "UnsupportedResponseException".GetCodeBehindLocalization();
break;
}
{
msg = "UnsupportedResponseException".GetCodeBehindLocalization();
break;
}
case CantLoadConfirmationsException e:
{
msg = LocManager.GetCodeBehindOrDefault(nameof(CantLoadConfirmationsException),
EXCEPTION_HANDLER_LOC_PATH, nameof(CantLoadConfirmationsException), "Common");
if (e.Error == LoadConfirmationsError.Unknown)
{
msg = LocManager.GetCodeBehindOrDefault(nameof(CantLoadConfirmationsException), EXCEPTION_HANDLER_LOC_PATH, nameof(CantLoadConfirmationsException), "Common");
if (e.Error == LoadConfirmationsError.Unknown)
{
msg += e.ErrorMessage;
msg += ' ';
msg += e.ErrorDetails;
}
else
{
msg += LocManager.GetCodeBehindOrDefault(e.Error.ToString(), EXCEPTION_HANDLER_LOC_PATH, nameof(CantLoadConfirmationsException), e.Error.ToString());
}
break;
msg += e.ErrorMessage;
msg += ' ';
msg += e.ErrorDetails;
}
else
{
msg += LocManager.GetCodeBehindOrDefault(e.Error.ToString(), EXCEPTION_HANDLER_LOC_PATH,
nameof(CantLoadConfirmationsException), e.Error.ToString());
}
break;
}
case EResultException e:
{
msg = "Error".GetCommonLocalization() + ": " + ErrorTranslatorHelper.TranslateEResult(e.Result);
break;
}
{
msg = "Error".GetCommonLocalization() + ": " + ErrorTranslatorHelper.TranslateEResult(e.Result);
break;
}
case LoginException e:
{
msg = "LoginException".GetCodeBehindLocalization() + ": " + ErrorTranslatorHelper.TranslateLoginError(e.Error);
break;
}
{
msg = "LoginException".GetCodeBehindLocalization() + ": " +
ErrorTranslatorHelper.TranslateLoginError(e.Error);
break;
}
case not null when handleAllExceptions:
{
msg = "UnknownException".GetCodeBehindLocalization() + ex.Message;
break;
}
{
msg = "UnknownException".GetCodeBehindLocalization() + ex.Message;
break;
}
default:
return false;
}
@@ -95,6 +101,7 @@ public static class ExceptionHandler
SnackbarController.SendSnackbar(prefix + msg + postfix);
return true;
}
private static string GetCommonLocalization(this string key)
{
return LocManager.GetCommonOrDefault(key, key);
+96 -71
View File
@@ -9,18 +9,21 @@
<DataTemplate DataType="{x:Type confirmations:Confirmation}">
<Grid >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" DockPanel.Dock="Left" Kind="QuestionMark" Margin="0,0,10,0"/>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" DockPanel.Dock="Left"
Kind="QuestionMark" Margin="0,0,10,0" />
<TextBlock VerticalAlignment="Center" Grid.Column="1" Text="{Binding TypeName}" />
<TextBlock VerticalAlignment="Center" Grid.Column="2" HorizontalAlignment="Right" Text="{Binding Time, StringFormat=t}"/>
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="3" Style="{StaticResource MaterialDesignIconButton}"
<TextBlock VerticalAlignment="Center" Grid.Column="2" HorizontalAlignment="Right"
Text="{Binding Time, StringFormat=t}" />
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="3"
Style="{StaticResource MaterialDesignIconButton}"
Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.(vm:MainVM.ConfirmCommand)}"
CommandParameter="{Binding }">
<materialDesign:PackIcon Kind="Check" />
@@ -33,25 +36,31 @@
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type confirmations:TradeConfirmation}">
<Grid >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<materialDesign:PackIcon VerticalAlignment="Center" Width="20" Height="20" Kind="AccountArrowRight" Margin="0,0,10,0" />
<Image Grid.Column="1" VerticalAlignment="Center" DockPanel.Dock="Left" Width="24" Height="24" Source="{Binding UserAvatarUri}" Margin="0,0,10,0" />
<TextBlock VerticalAlignment="Center" Grid.Column="2" TextWrapping="WrapWithOverflow" >
<Run Text="{Tr MainWindow.ConfirmationTemplates.TradeWith, IsDynamic=False}"/>
<materialDesign:PackIcon VerticalAlignment="Center" Width="20" Height="20" Kind="AccountArrowRight"
Margin="0,0,10,0" />
<Image Grid.Column="1" VerticalAlignment="Center" DockPanel.Dock="Left" Width="24" Height="24"
Source="{Binding UserAvatarUri}" Margin="0,0,10,0" />
<TextBlock VerticalAlignment="Center" Grid.Column="2" TextWrapping="WrapWithOverflow">
<Run Text="{Tr MainWindow.ConfirmationTemplates.TradeWith, IsDynamic=False}" />
<Run Text="{Binding UserName}" FontWeight="Bold" />
</TextBlock>
<materialDesign:PackIcon Grid.Column="3" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5,0,5,0" Kind="Gift" Visibility="{Binding IsReceiveNothing, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock VerticalAlignment="Center" Grid.Column="4" HorizontalAlignment="Right" Text="{Binding Time, StringFormat=t}"/>
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="5" Style="{StaticResource MaterialDesignIconButton}"
<materialDesign:PackIcon Grid.Column="3" HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="5,0,5,0" Kind="Gift"
Visibility="{Binding IsReceiveNothing, Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBlock VerticalAlignment="Center" Grid.Column="4" HorizontalAlignment="Right"
Text="{Binding Time, StringFormat=t}" />
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="5"
Style="{StaticResource MaterialDesignIconButton}"
Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.(vm:MainVM.ConfirmCommand)}"
CommandParameter="{Binding }">
<materialDesign:PackIcon Kind="Check" />
@@ -64,18 +73,21 @@
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type confirmations:AccountRecoveryConfirmation}">
<Grid >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" DockPanel.Dock="Left" Kind="LockOutline" Margin="0,0,10,0"/>
<TextBlock VerticalAlignment="Center" Grid.Column="1" Text="{Tr MainWindow.ConfirmationTemplates.Recovery}"/>
<TextBlock VerticalAlignment="Center" Grid.Column="2" HorizontalAlignment="Right" Text="{Binding Time, StringFormat=t}"/>
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="3" Style="{StaticResource MaterialDesignIconButton}"
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" DockPanel.Dock="Left"
Kind="LockOutline" Margin="0,0,10,0" />
<TextBlock VerticalAlignment="Center" Grid.Column="1" Text="{Tr MainWindow.ConfirmationTemplates.Recovery}" />
<TextBlock VerticalAlignment="Center" Grid.Column="2" HorizontalAlignment="Right"
Text="{Binding Time, StringFormat=t}" />
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="3"
Style="{StaticResource MaterialDesignIconButton}"
Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.(vm:MainVM.ConfirmCommand)}"
CommandParameter="{Binding }">
<materialDesign:PackIcon Kind="Check" />
@@ -88,36 +100,43 @@
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type confirmations:MarketConfirmation}">
<Grid >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<materialDesign:PackIcon VerticalAlignment="Center" Width="20" Height="20" Kind="ShoppingCart" Margin="0,0,10,0" />
<Border Grid.Column="1" Background="{DynamicResource MaterialDesignPaper}" MaxHeight="36" HorizontalAlignment="Center" BorderBrush="{DynamicResource PrimaryHueMidBrush}" BorderThickness="0.6" Margin="0,0,10,0">
<Image HorizontalAlignment="Center" VerticalAlignment="Center" MaxWidth="32" MaxHeight="32" Source="{Binding ItemImageUri}" />
<materialDesign:PackIcon VerticalAlignment="Center" Width="20" Height="20" Kind="ShoppingCart"
Margin="0,0,10,0" />
<Border Grid.Column="1" Background="{DynamicResource MaterialDesignPaper}" MaxHeight="36"
HorizontalAlignment="Center" BorderBrush="{DynamicResource PrimaryHueMidBrush}"
BorderThickness="0.6" Margin="0,0,10,0">
<Image HorizontalAlignment="Center" VerticalAlignment="Center" MaxWidth="32" MaxHeight="32"
Source="{Binding ItemImageUri}" />
</Border>
<Grid Grid.Column="2">
<TextBlock VerticalAlignment="Center" x:Name="ItemName" theme:FontScaleWindow.ResizeFont="True" TextWrapping="WrapWithOverflow" Text="{Binding ItemName}"/>
<TextBlock VerticalAlignment="Center" x:Name="ItemName" theme:FontScaleWindow.ResizeFont="True"
TextWrapping="WrapWithOverflow" Text="{Binding ItemName}" />
<TextBlock Foreground="LightGray" Text="{Binding PriceString}">
<TextBlock.FontSize>
<Binding ElementName="ItemName" Path="FontSize" ConverterParameter="0.7">
<Binding.Converter>
<converters:CoefficientConverter/>
<converters:CoefficientConverter />
</Binding.Converter>
</Binding>
</TextBlock.FontSize>
</TextBlock>
</Grid>
<TextBlock VerticalAlignment="Center" Grid.Column="4" HorizontalAlignment="Left" Margin="5,0,0,0" Text="{Binding Time, StringFormat=t}"/>
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="5" Style="{StaticResource MaterialDesignIconButton}"
<TextBlock VerticalAlignment="Center" Grid.Column="4" HorizontalAlignment="Left" Margin="5,0,0,0"
Text="{Binding Time, StringFormat=t}" />
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="5"
Style="{StaticResource MaterialDesignIconButton}"
Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.(vm:MainVM.ConfirmCommand)}"
CommandParameter="{Binding }">
<materialDesign:PackIcon Kind="Check" />
@@ -130,18 +149,21 @@
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type confirmations:RegisterApiKeyConfirmation}">
<Grid >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" DockPanel.Dock="Left" Kind="KeyLink" Margin="0,0,10,0"/>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" DockPanel.Dock="Left"
Kind="KeyLink" Margin="0,0,10,0" />
<TextBlock VerticalAlignment="Center" Grid.Column="1" Text="{Tr MainWindow.ConfirmationTemplates.ApiKey}" />
<TextBlock VerticalAlignment="Center" Grid.Column="2" HorizontalAlignment="Right" Text="{Binding Time, StringFormat=t}"/>
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="3" Style="{StaticResource MaterialDesignIconButton}"
<TextBlock VerticalAlignment="Center" Grid.Column="2" HorizontalAlignment="Right"
Text="{Binding Time, StringFormat=t}" />
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="3"
Style="{StaticResource MaterialDesignIconButton}"
Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.(vm:MainVM.ConfirmCommand)}"
CommandParameter="{Binding }">
<materialDesign:PackIcon Kind="Check" />
@@ -154,23 +176,26 @@
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type entities:MarketMultiConfirmation}">
<Grid >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<materialDesign:PackIcon VerticalAlignment="Center" Width="20" Height="20" Kind="ShoppingCartPlus" Margin="0,0,10,0" />
<materialDesign:PackIcon VerticalAlignment="Center" Width="20" Height="20" Kind="ShoppingCartPlus"
Margin="0,0,10,0" />
<TextBlock VerticalAlignment="Center" Grid.Column="1">
<Run Text="{Tr MainWindow.ConfirmationTemplates.Market, IsDynamic=False}"/>
<Run Text="{Binding Confirmations.Count, Mode=OneWay}"/>
<Run Text="{Tr Common.Abbreviations.Count.Items, IsDynamic=False}"/>
<Run Text="{Tr MainWindow.ConfirmationTemplates.Market, IsDynamic=False}" />
<Run Text="{Binding Confirmations.Count, Mode=OneWay}" />
<Run Text="{Tr Common.Abbreviations.Count.Items, IsDynamic=False}" />
</TextBlock>
<TextBlock VerticalAlignment="Center" Grid.Column="2" HorizontalAlignment="Left" Margin="5,0,0,0" Text="{Binding Time, StringFormat=t}"/>
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="3" Style="{StaticResource MaterialDesignIconButton}"
<TextBlock VerticalAlignment="Center" Grid.Column="2" HorizontalAlignment="Left" Margin="5,0,0,0"
Text="{Binding Time, StringFormat=t}" />
<Button Margin="5,0,0,0" VerticalAlignment="Center" Grid.Column="3"
Style="{StaticResource MaterialDesignIconButton}"
Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.(vm:MainVM.ConfirmCommand)}"
CommandParameter="{Binding }">
<materialDesign:PackIcon Kind="Check" />
@@ -1,31 +1,31 @@
<UserControl x:Class="NebulaAuth.View.Dialogs.ConfirmCancelDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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: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"
Background="{DynamicResource WindowBackground}">
<Grid Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock theme:FontScaleWindow.Scale="0.8"
theme:FontScaleWindow.ResizeFont="True"
HorizontalAlignment="Center" Margin="10,10,10,15"
Text="Подтвердите действие"
x:Name="ConfirmTextBlock"
TextWrapping="WrapWithOverflow"/>
TextWrapping="WrapWithOverflow" />
<Grid Grid.Row="1" Margin="10,0,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button DockPanel.Dock="Left"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
<Button DockPanel.Dock="Left"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource True}"
FontSize="{Binding ElementName=ConfirmTextBlock, Path=FontSize,
Converter={StaticResource CoefficientConverter},
@@ -33,7 +33,7 @@
ОК
</Button>
<Button Grid.Column="1" DockPanel.Dock="Right"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource False}"
FontSize="{Binding ElementName=ConfirmTextBlock, Path=FontSize,
Converter={StaticResource CoefficientConverter},
@@ -42,4 +42,4 @@
</Button>
</Grid>
</Grid>
</UserControl>
</UserControl>
@@ -1,7 +1,7 @@
namespace NebulaAuth.View.Dialogs;
/// <summary>
/// Логика взаимодействия для ConfirmCancelDialog.xaml
/// Логика взаимодействия для ConfirmCancelDialog.xaml
/// </summary>
public partial class ConfirmCancelDialog
{
+28 -18
View File
@@ -1,38 +1,48 @@
<UserControl x:Class="NebulaAuth.View.Dialogs.LoginAgainDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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:theme="clr-namespace:NebulaAuth.Theme"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:model="clr-namespace:NebulaAuth.Model"
mc:Ignorable="d"
mc:Ignorable="d"
theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True"
Foreground="WhiteSmoke"
Foreground="WhiteSmoke"
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
Background="{DynamicResource WindowBackground}">
<Grid MinHeight="100" MinWidth="300" Margin="20">
<Grid MinHeight="100" MinWidth="300" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True" Margin="10,0,0,0" HorizontalAlignment="Left">
<Run Text="{Tr LoginAgainDialog.LoginFor, IsDynamic=False}"/>
<Run FontWeight="Bold" Text="{Binding UserName}"/>
<TextBlock theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True" Margin="10,0,0,0"
HorizontalAlignment="Left">
<Run Text="{Tr LoginAgainDialog.LoginFor, IsDynamic=False}" />
<Run FontWeight="Bold" Text="{Binding UserName}" />
</TextBlock>
<TextBox Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,10,0" Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintTextBox}" materialDesign:HintAssist.Hint="{Tr LoginAgainDialog.PasswordBox}" />
<CheckBox Grid.Row="2" Margin="10,10,10,0" IsEnabled="{Binding Source={x:Static model:PHandler.IsPasswordSet}}" IsChecked="{Binding SavePassword}" Content="{Tr LoginAgainDialog.SaveEncryptedPassword}"/>
<TextBox Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,10,0" Grid.Row="1"
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
materialDesign:HintAssist.Hint="{Tr LoginAgainDialog.PasswordBox}" />
<CheckBox Grid.Row="2" Margin="10,10,10,0" IsEnabled="{Binding Source={x:Static model:PHandler.IsPasswordSet}}"
IsChecked="{Binding SavePassword}" Content="{Tr LoginAgainDialog.SaveEncryptedPassword}" />
<Grid Grid.Row="3" Margin="10,10,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button IsDefault="True" IsEnabled="{Binding IsFormValid}" Margin="0,0,5,5" Style="{StaticResource MaterialDesignOutlinedButton}" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" CommandParameter="{StaticResource True}" Content="{Tr LoginAgainDialog.LoginButton}"/>
<Button IsCancel="True" Grid.Column="1" Margin="5,0,0,5" Style="{StaticResource MaterialDesignOutlinedButton}" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" CommandParameter="{StaticResource False}" Content="{Tr LoginAgainDialog.CancelButton}"/>
<Button IsDefault="True" IsEnabled="{Binding IsFormValid}" Margin="0,0,5,5"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource True}" Content="{Tr LoginAgainDialog.LoginButton}" />
<Button IsCancel="True" Grid.Column="1" Margin="5,0,0,5"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource False}" Content="{Tr LoginAgainDialog.CancelButton}" />
</Grid>
</Grid>
</UserControl>
</UserControl>
@@ -1,7 +1,7 @@
namespace NebulaAuth.View.Dialogs;
/// <summary>
/// Логика взаимодействия для LoginAgainDialog.xaml
/// Логика взаимодействия для LoginAgainDialog.xaml
/// </summary>
public partial class LoginAgainDialog
{
@@ -1,34 +1,39 @@
<UserControl x:Class="NebulaAuth.View.Dialogs.LoginAgainOnImportDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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:theme="clr-namespace:NebulaAuth.Theme"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:model="clr-namespace:NebulaAuth.Model"
xmlns:entities="clr-namespace:NebulaAuth.Model.Entities"
mc:Ignorable="d"
mc:Ignorable="d"
theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True"
Foreground="WhiteSmoke"
d:DataContext="{d:DesignInstance other:LoginAgainOnImportVM}"
Background="{DynamicResource WindowBackground}">
<Grid MinHeight="100" MinWidth="300" Margin="20">
<Grid MinHeight="100" MinWidth="300" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True" Margin="10,0,0,0" HorizontalAlignment="Left">
<Run Text="{Tr LoginAgainDialog.LoginFor, IsDynamic=False}"/>
<Run FontWeight="Bold" Text="{Binding UserName}"/>
<TextBlock theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True" Margin="10,0,0,0"
HorizontalAlignment="Left">
<Run Text="{Tr LoginAgainDialog.LoginFor, IsDynamic=False}" />
<Run FontWeight="Bold" Text="{Binding UserName}" />
</TextBlock>
<TextBox Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,10,0" Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintTextBox}" materialDesign:HintAssist.Hint="{Tr LoginAgainDialog.PasswordBox}" />
<ComboBox ToolTip="{Tr LoginAgainDialog.ProxyToolTip}" Grid.Row="2" Margin="10,18,10,0" materialDesign:HintAssist.Hint="{Tr Common.Proxy}" ItemsSource="{Binding Proxies}" SelectedItem="{Binding SelectedProxy}" >
<TextBox Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,10,0" Grid.Row="1"
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
materialDesign:HintAssist.Hint="{Tr LoginAgainDialog.PasswordBox}" />
<ComboBox ToolTip="{Tr LoginAgainDialog.ProxyToolTip}" Grid.Row="2" Margin="10,18,10,0"
materialDesign:HintAssist.Hint="{Tr Common.Proxy}" ItemsSource="{Binding Proxies}"
SelectedItem="{Binding SelectedProxy}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type entities:MaProxy}">
<TextBlock Text="{Binding Converter={StaticResource ProxyTextConverter}, Mode=OneWay}" />
@@ -38,15 +43,23 @@
<KeyBinding Key="Delete" Command="{Binding RemoveProxyCommand}" />
</UIElement.InputBindings>
</ComboBox>
<CheckBox Grid.Row="3" Margin="10,10,10,0" IsEnabled="{Binding Source={x:Static model:PHandler.IsPasswordSet}}" IsChecked="{Binding SavePassword}" Content="{Tr LoginAgainDialog.SaveEncryptedPassword}"/>
<CheckBox Grid.Row="4" Margin="10,10,10,0" IsEnabled="{Binding MafileHasProxy}" Content="{Tr LoginAgainDialog.UseMafileProxy}" IsChecked="{Binding UseMafileProxy}"/>
<CheckBox Grid.Row="3" Margin="10,10,10,0" IsEnabled="{Binding Source={x:Static model:PHandler.IsPasswordSet}}"
IsChecked="{Binding SavePassword}" Content="{Tr LoginAgainDialog.SaveEncryptedPassword}" />
<CheckBox Grid.Row="4" Margin="10,10,10,0" IsEnabled="{Binding MafileHasProxy}"
Content="{Tr LoginAgainDialog.UseMafileProxy}" IsChecked="{Binding UseMafileProxy}" />
<Grid Grid.Row="5" Margin="10,10,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button IsEnabled="{Binding IsFormValid}" IsDefault="True" Margin="0,5,5,5" Style="{StaticResource MaterialDesignOutlinedButton}" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" CommandParameter="{StaticResource True}" Content="{Tr LoginAgainDialog.LoginButton}"/>
<Button IsCancel="True" Grid.Column="1" Margin="5,5,0,5" Style="{StaticResource MaterialDesignOutlinedButton}" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" CommandParameter="{StaticResource False}" Content="{Tr LoginAgainDialog.CancelButton}"/>
<Button IsEnabled="{Binding IsFormValid}" IsDefault="True" Margin="0,5,5,5"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource True}" Content="{Tr LoginAgainDialog.LoginButton}" />
<Button IsCancel="True" Grid.Column="1" Margin="5,5,0,5"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource False}" Content="{Tr LoginAgainDialog.CancelButton}" />
</Grid>
</Grid>
</UserControl>
</UserControl>
@@ -1,7 +1,7 @@
namespace NebulaAuth.View.Dialogs;
/// <summary>
/// Логика взаимодействия для LoginAgainDialog.xaml
/// Логика взаимодействия для LoginAgainDialog.xaml
/// </summary>
public partial class LoginAgainOnImportDialog
{
@@ -1,32 +1,42 @@
<UserControl x:Class="NebulaAuth.View.Dialogs.SetCryptPasswordDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:theme="clr-namespace:NebulaAuth.Theme"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
mc:Ignorable="d"
Foreground="WhiteSmoke"
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
Background="{DynamicResource WindowBackground}">
<Grid MinHeight="100" MinWidth="300" MaxWidth="400" Margin="20">
<Grid MinHeight="100" MinWidth="300" MaxWidth="400" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal" Text="{Tr SetEncryptedPasswordDialog.DialogText}" theme:FontScaleWindow.Scale="0.8" theme:FontScaleWindow.ResizeFont="True" Margin="10,0,0,0" HorizontalAlignment="Left"/>
<PasswordBox FontSize="16" materialDesign:PasswordBoxAssist.Password="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Margin="10" Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}" materialDesign:HintAssist.Hint="{Tr SetEncryptedPasswordDialog.Password}" />
<TextBlock IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal"
Text="{Tr SetEncryptedPasswordDialog.DialogText}" theme:FontScaleWindow.Scale="0.8"
theme:FontScaleWindow.ResizeFont="True" Margin="10,0,0,0" HorizontalAlignment="Left" />
<PasswordBox FontSize="16"
materialDesign:PasswordBoxAssist.Password="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
Margin="10" Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
materialDesign:HintAssist.Hint="{Tr SetEncryptedPasswordDialog.Password}" />
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button IsDefault="True" Margin="10,5,5,5" Style="{StaticResource MaterialDesignOutlinedButton}" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" CommandParameter="{StaticResource True}" Content="{Tr SetEncryptedPasswordDialog.Ok}"/>
<Button IsCancel="True" Grid.Column="1" Margin="5,5,10,5" Style="{StaticResource MaterialDesignOutlinedButton}" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" CommandParameter="{StaticResource False}" Content="{Tr SetEncryptedPasswordDialog.Cancel}"/>
<Button IsDefault="True" Margin="10,5,5,5" Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource True}" Content="{Tr SetEncryptedPasswordDialog.Ok}" />
<Button IsCancel="True" Grid.Column="1" Margin="5,5,10,5"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource False}" Content="{Tr SetEncryptedPasswordDialog.Cancel}" />
</Grid>
</Grid>
</UserControl>
@@ -1,7 +1,7 @@
namespace NebulaAuth.View.Dialogs;
/// <summary>
/// Логика взаимодействия для SetCryptPasswordDialog.xaml
/// Логика взаимодействия для SetCryptPasswordDialog.xaml
/// </summary>
public partial class SetCryptPasswordDialog
{
+15 -15
View File
@@ -1,42 +1,42 @@
<UserControl x:Class="NebulaAuth.View.Dialogs.WaitLoginDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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:theme="clr-namespace:NebulaAuth.Theme"
mc:Ignorable="d"
mc:Ignorable="d"
theme:FontScaleWindow.ResizeFont="True" theme:FontScaleWindow.Scale="1"
Foreground="WhiteSmoke"
Foreground="WhiteSmoke"
Background="{DynamicResource WindowBackground}">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" IsIndeterminate="True" />
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" IsIndeterminate="True" />
<TextBlock Margin="10,0,0,0" Grid.Column="1" Text="{Tr WaitLoginDialog.Text}" VerticalAlignment="Center" />
</Grid>
<Grid x:Name="CaptchaGrid" Margin="0,25,0,0" Visibility="Collapsed" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image x:Name="CaptchaImage" Stretch="Uniform" />
<TextBox Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintTextBox}" x:Name="CaptchaTB"/>
<TextBox Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintTextBox}" x:Name="CaptchaTB" />
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Click="SendCaptchaBtn_Click">Отправить</Button>
<Button Grid.Column="1" Click="CancelButton_OnClick">Отмена</Button>
</Grid>
</Grid>
</Grid>
</UserControl>
</UserControl>
@@ -10,11 +10,12 @@ using SteamLib.Exceptions;
namespace NebulaAuth.View.Dialogs;
/// <summary>
/// Логика взаимодействия для WaitLoginDialog.xaml
/// Логика взаимодействия для WaitLoginDialog.xaml
/// </summary>
public partial class WaitLoginDialog : ICaptchaResolver
{
private TaskCompletionSource<string> _tcs = new();
public WaitLoginDialog()
{
InitializeComponent();
@@ -22,7 +23,6 @@ public partial class WaitLoginDialog : ICaptchaResolver
public async Task<string> Resolve(Uri imageUrl, HttpClient client)
{
CaptchaGrid.Visibility = Visibility.Visible;
var stream = await client.GetStreamAsync(imageUrl);
return await Application.Current.Dispatcher.Invoke(async () =>
+79 -61
View File
@@ -1,11 +1,11 @@
<UserControl x:Class="NebulaAuth.View.LinkerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
mc:Ignorable="d"
mc:Ignorable="d"
Foreground="WhiteSmoke"
FontFamily="{materialDesign:MaterialDesignFont}"
MinHeight="640"
@@ -20,56 +20,61 @@
</d:DesignerProperties.DesignStyle>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="materialDesign:PackIcon">
<Style TargetType="materialDesign:PackIcon">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Tag}" Value="False">
<Setter Property="Foreground" Value="IndianRed"/>
<Setter Property="Kind" Value="CheckBoxOutlineBlank"/>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Tag}"
Value="False">
<Setter Property="Foreground" Value="IndianRed" />
<Setter Property="Kind" Value="CheckBoxOutlineBlank" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Tag}" Value="True">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="Kind" Value="CheckBoxOutline"/>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Tag}"
Value="True">
<Setter Property="Foreground" Value="Green" />
<Setter Property="Kind" Value="CheckBoxOutline" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Tag}" Value="True">
<Setter Property="Foreground" Value="Gray"/>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Tag}"
Value="True">
<Setter Property="Foreground" Value="Gray" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock FontStyle="Normal" Foreground="DarkGray" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="18" Text="{Tr LinkerDialog.Title}"/>
<TextBlock Margin="5,0,0,0" VerticalAlignment="Center" FontSize="12" >
<Hyperlink Command="{Binding OpenTroubleshootingCommand}">
<TextBlock FontStyle="Normal" Foreground="DarkGray" HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr LinkerDialog.Title}" />
<TextBlock Margin="5,0,0,0" VerticalAlignment="Center" FontSize="12">
<Hyperlink Command="{Binding OpenTroubleshootingCommand}">
<Run Text="{Tr LinkerDialog.GotErrorHyperlinkText, IsDynamic=False}" />
</Hyperlink>
</Hyperlink>
</TextBlock>
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}" HorizontalAlignment="Right" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
@@ -77,72 +82,85 @@
<Grid Grid.Row="2" Margin="10,20,10,10">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox Padding="10" FontSize="16" Style="{StaticResource MaterialDesignOutlinedComboBox}" SelectedValue="{Binding SelectedProxy}" ItemsSource="{Binding Proxies}" materialDesign:HintAssist.Hint="{Tr LinkerDialog.Proxy}" IsEnabled="{Binding IsPasswordFieldVisible}">
<ComboBox Padding="10" FontSize="16" Style="{StaticResource MaterialDesignOutlinedComboBox}"
SelectedValue="{Binding SelectedProxy}" ItemsSource="{Binding Proxies}"
materialDesign:HintAssist.Hint="{Tr LinkerDialog.Proxy}"
IsEnabled="{Binding IsPasswordFieldVisible}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Key, Mode=OneWay}"/><Run Text=":"/>
<Run Text="{Binding Value.Address, Mode=OneWay}"/>
<Run Text="{Binding Key, Mode=OneWay}" /><Run Text=":" />
<Run Text="{Binding Value.Address, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Grid.Column="1" IsEnabled="{Binding IsPasswordFieldVisible}" Margin="5,0,0,0" Command="{Binding ResetProxyCommand}" Content="{materialDesign:PackIcon Trash}"/>
<Button Grid.Column="1" IsEnabled="{Binding IsPasswordFieldVisible}" Margin="5,0,0,0"
Command="{Binding ResetProxyCommand}" Content="{materialDesign:PackIcon Trash}" />
</Grid>
<StackPanel Grid.Row="3" Orientation="Horizontal" Margin="7" Tag="{Binding IsLogin}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0"/>
<TextBlock FontSize="16" Text="{Tr LinkerDialog.Authorization}"/>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.Authorization}" />
</StackPanel>
<StackPanel Grid.Row="4" Orientation="Horizontal" Margin="7" Tag="{Binding IsEmailCode}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0"/>
<TextBlock FontSize="16" Text="{Tr LinkerDialog.EmailCode}"/>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.EmailCode}" />
</StackPanel>
<StackPanel Grid.Row="5" Orientation="Horizontal" Margin="7" Tag="{Binding IsPhoneNumber}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0"/>
<TextBlock FontSize="16" Text="{Tr LinkerDialog.PhoneNumber}"/>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.PhoneNumber}" />
</StackPanel>
<StackPanel Grid.Row="6" Orientation="Horizontal" Margin="7" Tag="{Binding IsEmailConfirmation}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0"/>
<TextBlock FontSize="16" Text="{Tr LinkerDialog.EmailLink}"/>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.EmailLink}" />
</StackPanel>
<StackPanel Grid.Row="7" Orientation="Horizontal" Margin="7" Tag="{Binding IsLinkCode}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0"/>
<TextBlock FontSize="16" Text="{Tr LinkerDialog.SmsOrCode}"/>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.SmsOrCode}" />
</StackPanel>
<StackPanel Grid.Row="8" Orientation="Horizontal" Margin="7" Tag="{Binding IsCompleted}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0"/>
<TextBlock FontSize="16" Text="{Tr LinkerDialog.Completed}"/>
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.Completed}" />
</StackPanel>
<Grid Grid.Row="9" Margin="10,20,10,10">
<Grid Grid.Row="9" Margin="10,20,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Padding="7" Text="{Binding FieldText}" Visibility="{Binding IsFieldVisible, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource MaterialDesignOutlinedTextBox}" FontSize="16" Margin="0,0,0,10" />
<TextBox Grid.Row="1" Padding="7" Text="{Binding PassFieldText}" Visibility="{Binding IsPasswordFieldVisible, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource MaterialDesignOutlinedTextBox}" FontSize="16"/>
<GroupBox Grid.Row="2" MaxWidth="400" BorderBrush="{StaticResource PrimaryHueMidBrush}" VerticalAlignment="Bottom" BorderThickness="1" Margin="0,10,0,0" Padding="5">
<TextBox Padding="7" Text="{Binding FieldText}"
Visibility="{Binding IsFieldVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
Style="{StaticResource MaterialDesignOutlinedTextBox}" FontSize="16" Margin="0,0,0,10" />
<TextBox Grid.Row="1" Padding="7" Text="{Binding PassFieldText}"
Visibility="{Binding IsPasswordFieldVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
Style="{StaticResource MaterialDesignOutlinedTextBox}" FontSize="16" />
<GroupBox Grid.Row="2" MaxWidth="400" BorderBrush="{StaticResource PrimaryHueMidBrush}"
VerticalAlignment="Bottom" BorderThickness="1" Margin="0,10,0,0" Padding="5">
<GroupBox.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Tr LinkerDialog.Message}" FontSize="16" Foreground="GhostWhite"/>
<TextBlock Text="{Tr LinkerDialog.Message}" FontSize="16" Foreground="GhostWhite" />
</DataTemplate>
</GroupBox.HeaderTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Foreground="GhostWhite" FontSize="16" Text="{Binding HintText}" HorizontalAlignment="Stretch" TextWrapping="Wrap"/>
<Button Command="{Binding CopyCodeCommand}" Visibility="{Binding IsCompleted, Converter={StaticResource BooleanToVisibilityConverter}}" Grid.Row="1">
<TextBlock Foreground="GhostWhite" FontSize="16" Text="{Binding HintText}"
HorizontalAlignment="Stretch" TextWrapping="Wrap" />
<Button Command="{Binding CopyCodeCommand}"
Visibility="{Binding IsCompleted, Converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Row="1">
<materialDesign:PackIcon Kind="ContentCopy" />
</Button>
</Grid>
</GroupBox>
</Grid>
<Button Grid.Row="10" Height="35" FontSize="17" Command="{Binding ProceedCommand}" Content="{Tr LinkerDialog.ProceedButton}"/>
<Button Grid.Row="10" Height="35" FontSize="17" Command="{Binding ProceedCommand}"
Content="{Tr LinkerDialog.ProceedButton}" />
</Grid>
</UserControl>
</UserControl>
+1 -1
View File
@@ -1,7 +1,7 @@
namespace NebulaAuth.View;
/// <summary>
/// Логика взаимодействия для LinkerView.xaml
/// Логика взаимодействия для LinkerView.xaml
/// </summary>
public partial class LinkerView
{
+53 -41
View File
@@ -1,11 +1,11 @@
<UserControl x:Class="NebulaAuth.View.ProxyManagerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
mc:Ignorable="d"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="400"
Foreground="WhiteSmoke"
FontFamily="{md:MaterialDesignFont}"
@@ -16,19 +16,22 @@
Background="{DynamicResource WindowBackground}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Margin="10" FontStyle="Normal" Foreground="DarkGray" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="18" Text="{Tr ProxyManagerDialog.Title}"/>
<Button Margin="0,0,10,0" IsCancel="True" Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}" HorizontalAlignment="Right" Command="{x:Static md:DialogHost.CloseDialogCommand}">
<TextBlock Margin="10" FontStyle="Normal" Foreground="DarkGray" HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr ProxyManagerDialog.Title}" />
<Button Margin="0,0,10,0" IsCancel="True" Grid.Column="1" Width="30" Height="30"
Style="{StaticResource MaterialDesignIconForegroundButton}" HorizontalAlignment="Right"
Command="{x:Static md:DialogHost.CloseDialogCommand}">
<md:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
@@ -36,14 +39,15 @@
<Separator Grid.Row="1" />
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Stretch"
<TextBlock HorizontalAlignment="Stretch"
Margin="15" FontSize="16">
<Run Text="{Tr ProxyManagerDialog.DefaultProxy, IsDynamic=False}"/>
<Run Text="{Binding DefaultProxy.Key, StringFormat='&#x0a;0:', FallbackValue='-', Mode=OneWay}"/>
<Run Text="{Binding DefaultProxy.Value, Converter='{StaticResource ProxyDataTextConverter}', Mode=OneWay, FallbackValue=''}"/>
<Run Text="{Tr ProxyManagerDialog.DefaultProxy, IsDynamic=False}" />
<Run Text="{Binding DefaultProxy.Key, StringFormat='&#x0a;0:', FallbackValue='-', Mode=OneWay}" />
<Run
Text="{Binding DefaultProxy.Value, Converter='{StaticResource ProxyDataTextConverter}', Mode=OneWay, FallbackValue=''}" />
</TextBlock>
<Button Grid.Column="1" Command="{Binding RemoveDefaultCommand}">
@@ -51,26 +55,29 @@
</Button>
</Grid>
<md:Card Grid.Row="3" Margin="10">
<ListBox VirtualizingStackPanel.VirtualizationMode="Recycling" FontSize="14" SelectedValue="{Binding SelectedProxy}" ItemsSource="{Binding Proxies}">
<ListBox VirtualizingStackPanel.VirtualizationMode="Recycling" FontSize="14"
SelectedValue="{Binding SelectedProxy}" ItemsSource="{Binding Proxies}">
<ListBox.InputBindings>
<KeyBinding Key="Delete" Command="{Binding DataContext.RemoveProxyCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" />
<KeyBinding Key="Delete"
Command="{Binding DataContext.RemoveProxyCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</ListBox.InputBindings>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource MaterialDesignListBoxItem}">
<Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext}"/>
<Setter Property="Tag"
Value="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext}" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="{Tr MainWindow.ContextMenus.Proxy.Copy}"
Command="{Binding PlacementTarget.Tag.CopyProxyCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding Value}"/>
Command="{Binding PlacementTarget.Tag.CopyProxyCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding Value}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Proxy.CopyAddress}"
Command="{Binding PlacementTarget.Tag.CopyProxyAddressCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding Value}"/>
Command="{Binding PlacementTarget.Tag.CopyProxyAddressCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding Value}" />
</ContextMenu>
</Setter.Value>
</Setter>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
@@ -78,36 +85,41 @@
<ListBox.ItemTemplate>
<DataTemplate>
<Grid >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center">
<Run Text="{Binding Key, Mode=OneWay}"/><Run Text=": "/>
<Run Text="{Binding Value, Mode=OneWay, Converter={StaticResource ProxyDataTextConverter}}"/>
<TextBlock VerticalAlignment="Center">
<Run Text="{Binding Key, Mode=OneWay}" /><Run Text=": " />
<Run
Text="{Binding Value, Mode=OneWay, Converter={StaticResource ProxyDataTextConverter}}" />
</TextBlock>
<Button Style="{StaticResource MaterialDesignIconButton}" Padding="0" Width="24" Height="24" md:RippleAssist.IsDisabled="True" Grid.Column="1" HorizontalAlignment="Right"
Command="{Binding DataContext.SetDefaultCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
<Button Style="{StaticResource MaterialDesignIconButton}" Padding="0" Width="24"
Height="24" md:RippleAssist.IsDisabled="True" Grid.Column="1"
HorizontalAlignment="Right"
Command="{Binding DataContext.SetDefaultCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}">
<md:PackIcon Height="16" Width="16" Kind="Heart" />
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</md:Card>
<Grid Grid.Row="4" Margin="5,0,15,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Text="{Binding AddProxyField}" FontSize="12" md:TextFieldAssist.HasClearButton="True" AcceptsReturn="True" MaxHeight="100" Style="{StaticResource MaterialDesignOutlinedTextBox}" Margin="15" md:HintAssist.Hint="IP:PORT:USER:PASS{ID}" />
<Button IsDefault="True" Grid.Column="1" Command="{Binding AddProxyCommand}">
<TextBox Text="{Binding AddProxyField}" FontSize="12" md:TextFieldAssist.HasClearButton="True"
AcceptsReturn="True" MaxHeight="100" Style="{StaticResource MaterialDesignOutlinedTextBox}"
Margin="15" md:HintAssist.Hint="IP:PORT:USER:PASS{ID}" />
<Button IsDefault="True" Grid.Column="1" Command="{Binding AddProxyCommand}">
<md:PackIcon Kind="Add" />
</Button>
<Button Grid.Column="2" Command="{Binding RemoveProxyCommand}">
@@ -117,4 +129,4 @@
</Grid>
</UserControl>
</UserControl>
+1 -1
View File
@@ -1,7 +1,7 @@
namespace NebulaAuth.View;
/// <summary>
/// Логика взаимодействия для ProxyManagerView.xaml
/// Логика взаимодействия для ProxyManagerView.xaml
/// </summary>
public partial class ProxyManagerView
{
+52 -33
View File
@@ -1,71 +1,90 @@
<UserControl x:Class="NebulaAuth.View.SettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
mc:Ignorable="d"
d:DesignHeight="650"
mc:Ignorable="d"
d:DesignHeight="650"
Foreground="WhiteSmoke"
FontFamily="{materialDesign:MaterialDesignFont}"
MinHeight="600"
MinWidth="400"
MaxWidth="200"
d:DataContext="{d:DesignInstance other:SettingsVM}"
Background="{DynamicResource WindowBackground}">
<Grid>
<Grid Margin="15,10,15,15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock FontStyle="Normal" Foreground="DarkGray" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="18" Text="{Tr SettingsDialog.Title}"/>
<Button IsCancel="True" Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}" HorizontalAlignment="Right" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<TextBlock FontStyle="Normal" Foreground="DarkGray" HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr SettingsDialog.Title}" />
<Button IsCancel="True" Grid.Column="1" Width="30" Height="30"
Style="{StaticResource MaterialDesignIconForegroundButton}" HorizontalAlignment="Right"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Margin="0,10,0,0" />
<StackPanel Grid.Row="2" Margin="10,30,10,10" Orientation="Vertical" HorizontalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignOutlinedComboBox}" FontSize="16" ItemsSource="{Binding BackgroundModes}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding BackgroundMode}" materialDesign:HintAssist.Hint="{Tr SettingsDialog.BackgroundHint}" />
<ComboBox Style="{StaticResource MaterialDesignFloatingHintComboBox}" Margin="0,20,0,0" FontSize="16" ItemsSource="{Binding Languages}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding Language}" materialDesign:HintAssist.Hint="{Tr LanguageWord}" />
<CheckBox Margin="0,10,0,0" FontSize="16" IsChecked="{Binding HideToTray}" Content="{Tr SettingsDialog.MinimizeToTray}"/>
<CheckBox Margin="0,10,0,0" FontSize="16" IsChecked="{Binding UseIcon}" Content="{Tr SettingsDialog.UseIndicator}" ToolTip="{Tr SettingsDialog.UseIndicatorHint}"/>
<materialDesign:ColorPicker IsEnabled="{Binding UseIcon}" Color="{Binding IconColor, Delay=50}" />
<CheckBox Margin="0,10,0,5" FontSize="16" IsChecked="{Binding UseBackground}" Content="{Tr SettingsDialog.UseCustomColor}"/>
<materialDesign:ColorPicker Height="100" IsEnabled="{Binding UseBackground}" Color="{Binding BackgroundColor, Delay=50}" />
<StackPanel Grid.Row="2" Margin="10,30,10,10" Orientation="Vertical" HorizontalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignOutlinedComboBox}" FontSize="16"
ItemsSource="{Binding BackgroundModes}" DisplayMemberPath="Value" SelectedValuePath="Key"
SelectedValue="{Binding BackgroundMode}"
materialDesign:HintAssist.Hint="{Tr SettingsDialog.BackgroundHint}" />
<ComboBox Style="{StaticResource MaterialDesignFloatingHintComboBox}" Margin="0,20,0,0" FontSize="16"
ItemsSource="{Binding Languages}" DisplayMemberPath="Value" SelectedValuePath="Key"
SelectedValue="{Binding Language}" materialDesign:HintAssist.Hint="{Tr LanguageWord}" />
<CheckBox Margin="0,10,0,0" FontSize="16" IsChecked="{Binding HideToTray}"
Content="{Tr SettingsDialog.MinimizeToTray}" />
<CheckBox Margin="0,10,0,0" FontSize="16" IsChecked="{Binding UseIcon}"
Content="{Tr SettingsDialog.UseIndicator}" ToolTip="{Tr SettingsDialog.UseIndicatorHint}" />
<materialDesign:ColorPicker IsEnabled="{Binding UseIcon}" Color="{Binding IconColor, Delay=50}" />
<CheckBox Margin="0,10,0,5" FontSize="16" IsChecked="{Binding UseBackground}"
Content="{Tr SettingsDialog.UseCustomColor}" />
<materialDesign:ColorPicker Height="100" IsEnabled="{Binding UseBackground}"
Color="{Binding BackgroundColor, Delay=50}" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<PasswordBox MinWidth="250" materialDesign:PasswordBoxAssist.Password="{Binding Password}" Height="Auto" VerticalAlignment="Center" FontSize="16" Margin="0,10,0,0"
Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
materialDesign:HintAssist.Hint="{Tr SettingsDialog.PasswordBox.CurrentCryptPassword}"
materialDesign:HintAssist.HelperText="{Tr SettingsDialog.PasswordBox.Hint}" />
<Button Command="{Binding SetPasswordCommand}" Margin="5,0,0,0" VerticalAlignment="Bottom" Grid.Column="1"> <materialDesign:PackIcon Kind="ContentSave"/></Button>
<PasswordBox MinWidth="250" materialDesign:PasswordBoxAssist.Password="{Binding Password}"
Height="Auto" VerticalAlignment="Center" FontSize="16" Margin="0,10,0,0"
Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
materialDesign:HintAssist.Hint="{Tr SettingsDialog.PasswordBox.CurrentCryptPassword}"
materialDesign:HintAssist.HelperText="{Tr SettingsDialog.PasswordBox.Hint}" />
<Button Command="{Binding SetPasswordCommand}" Margin="5,0,0,0" VerticalAlignment="Bottom"
Grid.Column="1">
<materialDesign:PackIcon Kind="ContentSave" />
</Button>
</Grid>
<CheckBox Margin="0,20,0,0" FontSize="16" IsChecked="{Binding LegacyMode}" Content="{Tr SettingsDialog.LegacyMafileMode}" ToolTip="{Tr SettingsDialog.LegacyMafileModeHint}"/>
<CheckBox Margin="0,20,0,0" FontSize="16" IsChecked="{Binding LegacyMode}"
Content="{Tr SettingsDialog.LegacyMafileMode}"
ToolTip="{Tr SettingsDialog.LegacyMafileModeHint}" />
<!--<CheckBox IsEnabled="False" Margin="0,10,0,0" FontSize="16" IsChecked="{Binding AllowAutoUpdate}" Content="{Tr SettingsDialog.AllowAutoUpdate}"/>-->
<CheckBox Margin="0,10,0,0" FontSize="16" IsChecked="{Binding UseAccountNameAsMafileName}" >
<CheckBox Margin="0,10,0,0" FontSize="16" IsChecked="{Binding UseAccountNameAsMafileName}">
<TextBlock TextWrapping="WrapWithOverflow" Text="{Tr SettingsDialog.UseAccountName}" />
</CheckBox>
<CheckBox IsChecked="{Binding IgnorePatchTuesdayErrors}" Margin="0,10,0,0" FontSize="16" ToolTip="{Tr SettingsDialog.IgnorePatchTuesdayErrorsHint}">
<CheckBox IsChecked="{Binding IgnorePatchTuesdayErrors}" Margin="0,10,0,0" FontSize="16"
ToolTip="{Tr SettingsDialog.IgnorePatchTuesdayErrorsHint}">
<TextBlock TextWrapping="WrapWithOverflow" Text="{Tr SettingsDialog.IgnorePatchTuesdayErrors}" />
</CheckBox>
</StackPanel>
</Grid>
</Grid>
</UserControl>
</UserControl>
+1 -1
View File
@@ -1,7 +1,7 @@
namespace NebulaAuth.View;
/// <summary>
/// Логика взаимодействия для SettingsView.xaml
/// Логика взаимодействия для SettingsView.xaml
/// </summary>
public partial class SettingsView
{
+20 -19
View File
@@ -1,11 +1,11 @@
<UserControl x:Class="NebulaAuth.View.UpdaterView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
mc:Ignorable="d"
mc:Ignorable="d"
Foreground="WhiteSmoke"
FontFamily="{materialDesign:MaterialDesignFont}"
d:DataContext="{d:DesignInstance other:UpdaterVM}"
@@ -19,22 +19,22 @@
</d:DesignerProperties.DesignStyle>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock FontSize="24" Text="Обновления"/>
<TextBlock FontSize="24" Text="Обновления" />
<Separator Grid.Row="1" />
<TextBlock FontSize="16" Margin="5,10,0,10" TextWrapping="WrapWithOverflow" Grid.Row="2" >
<Run Text="Доступна новая версия:"/>
<Run FontWeight="Bold" Text="{Binding UpdateInfoEventArgs.CurrentVersion}"/>
<Run Text="&#x0a;Вы используете версию"/>
<Run FontWeight="Bold" Text="{Binding UpdateInfoEventArgs.InstalledVersion}"/>
<Run Text="Хотите обновить программу?"/>
<TextBlock FontSize="16" Margin="5,10,0,10" TextWrapping="WrapWithOverflow" Grid.Row="2">
<Run Text="Доступна новая версия:" />
<Run FontWeight="Bold" Text="{Binding UpdateInfoEventArgs.CurrentVersion}" />
<Run Text="&#x0a;Вы используете версию" />
<Run FontWeight="Bold" Text="{Binding UpdateInfoEventArgs.InstalledVersion}" />
<Run Text="Хотите обновить программу?" />
</TextBlock>
<Expander Header="Что изменилось?" Grid.Row="3">
<!--<wpf:WebView2 HorizontalAlignment="Stretch" Height="300"
@@ -43,12 +43,13 @@
</Expander>
<Grid Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Content="OK" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" />
<Button IsCancel="True" Grid.Column="1" Content="Cancel" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" />
<Button Content="OK" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" />
<Button IsCancel="True" Grid.Column="1" Content="Cancel"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}" />
</Grid>
</Grid>
</UserControl>
</UserControl>
+1 -1
View File
@@ -1,7 +1,7 @@
namespace NebulaAuth.View;
/// <summary>
/// Логика взаимодействия для UpdaterView.xaml
/// Логика взаимодействия для UpdaterView.xaml
/// </summary>
public partial class UpdaterView
{
+29 -20
View File
@@ -1,4 +1,9 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using JetBrains.Annotations;
using MaterialDesignThemes.Wpf;
@@ -9,21 +14,12 @@ using NebulaAuth.Utility;
using NebulaAuth.View.Dialogs;
using SteamLib.Exceptions;
using SteamLib.SteamMobile;
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Threading.Tasks;
namespace NebulaAuth.ViewModel;
public partial class MainVM : ObservableObject
{
[ObservableProperty]
private ObservableCollection<Mafile> _maFiles = Storage.MaFiles;
[UsedImplicitly]
public SnackbarMessageQueue MessageQueue => SnackbarController.MessageQueue;
[UsedImplicitly] public SnackbarMessageQueue MessageQueue => SnackbarController.MessageQueue;
public Mafile? SelectedMafile
@@ -31,10 +27,13 @@ public partial class MainVM : ObservableObject
get => _selectedMafile;
set => SetMafile(value);
}
private Mafile? _selectedMafile;
public bool IsMafileSelected => SelectedMafile != null;
[ObservableProperty] private ObservableCollection<Mafile> _maFiles = Storage.MaFiles;
private Mafile? _selectedMafile;
public MainVM()
{
@@ -63,7 +62,7 @@ public partial class MainVM : ObservableObject
OnPropertyChanged(nameof(MarketTimerEnabled));
MaClient.SetAccount(mafile);
OnPropertyChanged(nameof(ConfirmationsVisible));
SetCurrentProxy();
SetProxy(mafile?.Proxy, true);
OnPropertyChanged(nameof(IsDefaultProxy));
if (mafile != null) Code = SteamGuardCodeGenerator.GenerateCode(mafile.SharedSecret);
OnPropertyChanged(nameof(IsMafileSelected));
@@ -78,7 +77,9 @@ public partial class MainVM : ObservableObject
{
return;
}
var loginAgainVm = await DialogsController.ShowLoginAgainDialog(SelectedMafile.AccountName);
var currentPassword = PHandler.DecryptPassword(SelectedMafile.Password);
var loginAgainVm = await DialogsController.ShowLoginAgainDialog(SelectedMafile.AccountName, currentPassword);
if (loginAgainVm == null)
{
return;
@@ -94,7 +95,8 @@ public partial class MainVM : ObservableObject
}
catch (LoginException ex)
{
SnackbarController.SendSnackbar(ErrorTranslatorHelper.TranslateLoginError(ex.Error), TimeSpan.FromSeconds(1.5));
SnackbarController.SendSnackbar(ErrorTranslatorHelper.TranslateLoginError(ex.Error),
TimeSpan.FromSeconds(1.5));
}
catch (Exception ex)
when (ExceptionHandler.Handle(ex))
@@ -107,6 +109,7 @@ public partial class MainVM : ObservableObject
await wait;
}
}
private void MaFilesOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
SearchText = string.Empty;
@@ -141,16 +144,21 @@ public partial class MainVM : ObservableObject
if (selectedMafile == null) return;
if (string.IsNullOrWhiteSpace(selectedMafile.RevocationCode))
{
SnackbarController.SendSnackbar(LocManager.GetCommonOrDefault("Error", "Error") + ": " + GetLocalization("MissingRCode"));
SnackbarController.SendSnackbar(LocManager.GetCommonOrDefault("Error", "Error") + ": " +
GetLocalization("MissingRCode"));
return;
}
try
{
if (await DialogsController.ShowConfirmCancelDialog(GetLocalization("ConfirmRemovingAuthenticator")))
{
var result = await SessionHandler.Handle(() => MaClient.RemoveAuthenticator(selectedMafile), selectedMafile);
var result =
await SessionHandler.Handle(() => MaClient.RemoveAuthenticator(selectedMafile), selectedMafile);
SnackbarController.SendSnackbar(
result.Success ? GetLocalization("AuthenticatorRemoved") : GetLocalization("AuthenticatorNotRemoved"));
result.Success
? GetLocalization("AuthenticatorRemoved")
: GetLocalization("AuthenticatorNotRemoved"));
if (result.Success)
{
@@ -184,10 +192,11 @@ public partial class MainVM : ObservableObject
}
else
{
string msg = res.Error switch
var msg = res.Error switch
{
LoginConfirmationError.NoRequests => GetLocalization("ConfirmLoginFailedNoRequests"),
LoginConfirmationError.MoreThanOneRequest => GetLocalization("ConfirmLoginFailedMoreThanOneRequest"), //TODO
LoginConfirmationError.MoreThanOneRequest =>
GetLocalization("ConfirmLoginFailedMoreThanOneRequest"), //TODO
_ => throw new ArgumentOutOfRangeException()
};
SnackbarController.SendSnackbar(msg);
+8 -10
View File
@@ -1,22 +1,22 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Core;
using NebulaAuth.Model;
using SteamLib.SteamMobile;
using System;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Core;
using NebulaAuth.Model;
using SteamLib.SteamMobile;
namespace NebulaAuth.ViewModel;
public partial class MainVM
{
private Timer _codeTimer;
[ObservableProperty] private double _codeProgress;
[ObservableProperty] private string _code = "Code";
[ObservableProperty] private double _codeProgress;
private Timer _codeTimer;
[MemberNotNull(nameof(_codeTimer))]
@@ -26,7 +26,6 @@ public partial class MainVM
}
private void UpdateCode(object? state = null)
{
var currentTime = TimeAligner.GetSteamTime();
@@ -70,6 +69,5 @@ public partial class MainVM
if (selectedMafile != null)
Code = SteamGuardCodeGenerator.GenerateCode(selectedMafile.SharedSecret);
}
}
}
+10 -10
View File
@@ -1,23 +1,22 @@
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.Model.Entities;
using NebulaAuth.Utility;
using SteamLib.SteamMobile.Confirmations;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
namespace NebulaAuth.ViewModel;
public partial class MainVM //Confirmations
{
public ObservableCollection<Confirmation> Confirmations { get; } = new();
private Mafile? _confirmationsLoadedForMafile;
public bool ConfirmationsVisible => SelectedMafile == _confirmationsLoadedForMafile;
private Mafile? _confirmationsLoadedForMafile;
[RelayCommand]
private async Task GetConfirmations()
@@ -69,6 +68,7 @@ public partial class MainVM //Confirmations
if (SelectedMafile == null || confirmation == null) return Task.CompletedTask;
return SendConfirmation(SelectedMafile, confirmation, true);
}
[RelayCommand]
private Task Cancel(Confirmation? confirmation)
{
@@ -81,7 +81,7 @@ public partial class MainVM //Confirmations
bool result;
try
{
if (confirmation is MarketMultiConfirmation multi)
if (confirmation is MarketMultiConfirmation multi)
{
result = await MaClient.SendMultipleConfirmation(mafile, multi.Confirmations, confirm);
}
@@ -91,7 +91,7 @@ public partial class MainVM //Confirmations
}
}
catch (Exception ex)
when(ExceptionHandler.Handle(ex))
when (ExceptionHandler.Handle(ex))
{
return;
}
+51 -23
View File
@@ -1,11 +1,4 @@
using CommunityToolkit.Mvvm.Input;
using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.View;
using NebulaAuth.ViewModel.Other;
using System;
using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
@@ -13,17 +6,23 @@ using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using AchiesUtilities.Extensions;
using CommunityToolkit.Mvvm.Input;
using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.Model.Entities;
using NebulaAuth.Model.Exceptions;
using SteamLib.Exceptions;
using NebulaAuth.Utility;
using NebulaAuth.View;
using NebulaAuth.View.Dialogs;
using NebulaAuth.ViewModel.Other;
using SteamLib.Exceptions;
namespace NebulaAuth.ViewModel;
public partial class MainVM //File //TODO: Refactor
{
public Settings Settings => Settings.Instance;
[RelayCommand]
@@ -37,6 +36,7 @@ public partial class MainVM //File //TODO: Refactor
{
mafilePath = Storage.TryFindMafilePath(mafile);
}
if (mafilePath != null)
{
path = $"/select, \"{mafilePath}\"";
@@ -60,15 +60,14 @@ public partial class MainVM //File //TODO: Refactor
var openFileDialog = new OpenFileDialog
{
Filter = "Mafile|*.mafile;*.maFile",
Multiselect = false,
Multiselect = false
};
var fs = openFileDialog.ShowDialog();
if (fs != true) return Task.CompletedTask;
var path = openFileDialog.FileName;
return AddMafile([path]);
}
public async Task AddMafile(string[] path)
{
bool? confirmOverwrite = null;
@@ -88,7 +87,8 @@ public partial class MainVM //File //TODO: Refactor
}
catch (IOException)
{
confirmOverwrite ??= await DialogsController.ShowConfirmCancelDialog(GetLocalization("ConfirmMafileOverwrite"));
confirmOverwrite ??=
await DialogsController.ShowConfirmCancelDialog(GetLocalization("ConfirmMafileOverwrite"));
if (confirmOverwrite == true)
{
@@ -116,7 +116,9 @@ public partial class MainVM //File //TODO: Refactor
}
else
{
SnackbarController.SendSnackbar($"{GetLocalization("MafileImportError")} {Path.GetFileName(str)}{GetLocalization("MissingSessionInMafile")}", TimeSpan.FromSeconds(4));
SnackbarController.SendSnackbar(
$"{GetLocalization("MafileImportError")} {Path.GetFileName(str)}{GetLocalization("MissingSessionInMafile")}",
TimeSpan.FromSeconds(4));
}
}
}
@@ -126,6 +128,7 @@ public partial class MainVM //File //TODO: Refactor
{
msg += $" {GetLocalization("ImportAdded")} {added}.";
}
if (notAdded > 0)
{
msg += $" {GetLocalization("ImportSkipped")} {notAdded}.";
@@ -135,6 +138,7 @@ public partial class MainVM //File //TODO: Refactor
{
msg += $" {GetLocalization("ImportErrors")} {errors}.";
}
SnackbarController.SendSnackbar(msg, TimeSpan.FromSeconds(2));
}
@@ -151,6 +155,7 @@ public partial class MainVM //File //TODO: Refactor
{
data.Proxy = loginAgainVm.SelectedProxy;
}
var waitDialog = new WaitLoginDialog();
var wait = DialogHost.Show(waitDialog);
try
@@ -160,7 +165,8 @@ public partial class MainVM //File //TODO: Refactor
}
catch (LoginException ex)
{
SnackbarController.SendSnackbar(ErrorTranslatorHelper.TranslateLoginError(ex.Error), TimeSpan.FromSeconds(1.5));
SnackbarController.SendSnackbar(ErrorTranslatorHelper.TranslateLoginError(ex.Error),
TimeSpan.FromSeconds(1.5));
}
catch (Exception ex)
when (ExceptionHandler.Handle(ex))
@@ -172,6 +178,7 @@ public partial class MainVM //File //TODO: Refactor
DialogsController.CloseDialog();
await wait;
}
var result = data.SessionData != null;
if (!result) return result;
Storage.SaveMafile(data);
@@ -181,7 +188,6 @@ public partial class MainVM //File //TODO: Refactor
SelectedMafile = data;
} //As this operation used only for 1 mafile at time, we can safely assume that we can select it for convenience
return result;
}
[RelayCommand]
@@ -211,7 +217,7 @@ public partial class MainVM //File //TODO: Refactor
private async Task OpenSettingsDialog()
{
var vm = new SettingsVM();
var view = new SettingsView()
var view = new SettingsView
{
DataContext = vm
};
@@ -236,15 +242,14 @@ public partial class MainVM //File //TODO: Refactor
if (arr.All(p => p.ContainsIgnoreCase("mafile") == false)) return;
await AddMafile(arr);
}
[RelayCommand]
private void CopyLogin(object? mafile)
{
if(mafile is not Mafile maf) return;
if(ClipboardHelper.Set(maf.AccountName))
if (mafile is not Mafile maf) return;
if (ClipboardHelper.Set(maf.AccountName))
SnackbarController.SendSnackbar(GetLocalization("LoginCopied"));
}
@@ -253,7 +258,7 @@ public partial class MainVM //File //TODO: Refactor
{
if (mafile is not Mafile maf) return;
if(ClipboardHelper.Set(maf.SteamId.ToString()))
if (ClipboardHelper.Set(maf.SteamId.ToString()))
SnackbarController.SendSnackbar(GetLocalization("SteamIdCopied"));
}
@@ -262,7 +267,30 @@ public partial class MainVM //File //TODO: Refactor
{
if (mafile is not Mafile maf) return;
var path = Storage.TryFindMafilePath(maf);
if(ClipboardHelper.SetFiles([path]))
if (ClipboardHelper.SetFiles([path]))
SnackbarController.SendSnackbar(GetLocalization("MafileCopied"));
}
[RelayCommand(CanExecute = nameof(CanCopyPassword))]
private void CopyPassword(object? mafile)
{
if (mafile is not Mafile maf) return;
if (maf.Password == null) return;
try
{
var pass = PHandler.Decrypt(maf.Password);
if (ClipboardHelper.Set(pass))
SnackbarController.SendSnackbar(GetLocalization("PasswordCopied"));
}
catch
{
SnackbarController.SendSnackbar(GetLocalization("CantDecryptPassword"));
}
}
private bool CanCopyPassword(object? mafile)
{
if (mafile is not Mafile maf) return false;
return maf.Password != null && PHandler.IsPasswordSet;
}
}
+17 -18
View File
@@ -1,19 +1,15 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
using System.Linq;
using AchiesUtilities.Extensions;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Model;
using NebulaAuth.Model.Entities;
using System.Collections.ObjectModel;
using System.Linq;
using AchiesUtilities.Extensions;
namespace NebulaAuth.ViewModel;
public partial class MainVM //Groups
{
[ObservableProperty]
private ObservableCollection<string> _groups = [];
public string? SelectedGroup
{
get => _selectedGroup;
@@ -24,21 +20,21 @@ public partial class MainVM //Groups
}
}
private string? _selectedGroup;
public string SearchText
{
get => _searchText;
set
{
if(SetProperty(ref _searchText, value))
if (SetProperty(ref _searchText, value))
PerformQuery();
}
}
[ObservableProperty] private ObservableCollection<string> _groups = [];
private string _searchText = string.Empty;
private string? _selectedGroup;
[RelayCommand]
@@ -53,7 +49,6 @@ public partial class MainVM //Groups
QueryGroups();
SelectedGroup = value;
OnPropertyChanged(nameof(SelectedMafile)); //For bindings
}
[RelayCommand]
@@ -62,8 +57,8 @@ public partial class MainVM //Groups
if (value == null) return;
if (value.Length < 2) return;
var group = (string?)value[0];
var mafile = (Mafile?)value[1];
var group = (string?) value[0];
var mafile = (Mafile?) value[1];
if (group == null || mafile == null) return;
mafile.Group = group;
@@ -86,6 +81,7 @@ public partial class MainVM //Groups
{
SelectedGroup = null;
}
PerformQuery();
}
@@ -103,7 +99,6 @@ public partial class MainVM //Groups
}
private void PerformQuery()
{
MaacDisplay = false;
@@ -112,20 +107,24 @@ public partial class MainVM //Groups
MaFiles = Storage.MaFiles;
return;
}
long? searchSteamId = null;
if (long.TryParse(SearchText, out var steamId))
{
searchSteamId = steamId;
}
var query = Storage.MaFiles.AsEnumerable();
if (!string.IsNullOrWhiteSpace(SearchText))
{
query = query.Where(SearchPredicate);
}
if (!string.IsNullOrWhiteSpace(SelectedGroup))
{
query = query.Where(m => m.Group != null && m.Group.Equals(SelectedGroup));
}
var perform = query.ToList();
MaFiles = new ObservableCollection<Mafile>(perform);
SelectedMafile = MaFiles.FirstOrDefault();
@@ -136,7 +135,7 @@ public partial class MainVM //Groups
return mafile.AccountName.ContainsIgnoreCase(SearchText) || mafile.SteamId.Steam64.Id.Equals(searchSteamId);
}
}
private void ResetQuery()
{
_selectedGroup = null;
+20 -8
View File
@@ -21,13 +21,13 @@ public partial class MainVM //MAAC
}
}
}
private bool _maacDisplay;
public bool MarketTimerEnabled
{
get => SelectedMafile?.LinkedClient?.AutoConfirmMarket ?? false;
set => SetMarketTimer(value);
}
public bool TradeTimerEnabled
{
get => SelectedMafile?.LinkedClient?.AutoConfirmTrades ?? false;
@@ -40,6 +40,8 @@ public partial class MainVM //MAAC
set => SetTimer(value);
}
private bool _maacDisplay;
private void SetMarketTimer(bool value)
{
var selectedMafile = SelectedMafile;
@@ -48,7 +50,8 @@ public partial class MainVM //MAAC
{
MultiAccountAutoConfirmer.TryAddToConfirm(selectedMafile);
}
if (!value && selectedMafile is { LinkedClient.AutoConfirmTrades: false })
if (!value && selectedMafile is {LinkedClient.AutoConfirmTrades: false})
{
MultiAccountAutoConfirmer.RemoveFromConfirm(selectedMafile);
}
@@ -68,7 +71,7 @@ public partial class MainVM //MAAC
MultiAccountAutoConfirmer.TryAddToConfirm(selectedMafile);
}
if (!value && selectedMafile is { LinkedClient.AutoConfirmMarket: false })
if (!value && selectedMafile is {LinkedClient.AutoConfirmMarket: false})
{
MultiAccountAutoConfirmer.RemoveFromConfirm(selectedMafile);
}
@@ -87,11 +90,13 @@ public partial class MainVM //MAAC
{
timerCheckSeconds = 10; //Guard
}
if (value < 10)
{
value = timerCheckSeconds;
SnackbarController.SendSnackbar(GetLocalization("TimerTooFast"));
}
Settings.TimerSeconds = value;
OnPropertyChanged(nameof(TimerCheckSeconds));
if (timerCheckSeconds != TimerCheckSeconds)
@@ -110,7 +115,7 @@ public partial class MainVM //MAAC
private void SwitchMAACOnGroup(bool market)
{
var group = SelectedGroup;
if(group == null) return;
if (group == null) return;
var mafilesInGroup = MaFiles.Where(m => group.Equals(m.Group));
SwitchMAACOn(mafilesInGroup, market);
}
@@ -133,22 +138,29 @@ public partial class MainVM //MAAC
MultiAccountAutoConfirmer.TryAddToConfirm(mafile);
SetCurrentMode(mafile.LinkedClient, turnOn);
}
}
else
{
foreach (var mafile in mafiles)
{
SetCurrentMode(mafile.LinkedClient, turnOn);
if(PretendsToRemove(mafile))
if (PretendsToRemove(mafile))
MultiAccountAutoConfirmer.RemoveFromConfirm(mafile);
}
}
return;
bool PretendsToRemove(Mafile mafile) => mafile.LinkedClient is {AutoConfirmMarket: false, AutoConfirmTrades: false};
bool GetCurrentMode(PortableMaClient linkedClient) => market ? linkedClient.AutoConfirmMarket : linkedClient.AutoConfirmTrades;
bool PretendsToRemove(Mafile mafile)
{
return mafile.LinkedClient is {AutoConfirmMarket: false, AutoConfirmTrades: false};
}
bool GetCurrentMode(PortableMaClient linkedClient)
{
return market ? linkedClient.AutoConfirmMarket : linkedClient.AutoConfirmTrades;
}
void SetCurrentMode(PortableMaClient? linkedClient, bool value)
{
if (linkedClient == null) return;
+45 -73
View File
@@ -1,12 +1,10 @@
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.Model.Entities;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
namespace NebulaAuth.ViewModel;
@@ -17,84 +15,56 @@ public partial class MainVM
public MaProxy? SelectedProxy
{
get => _selectedProxy;
set
{
if (SetProperty(ref _selectedProxy, value))
{
OnPropertyChanged(nameof(IsDefaultProxy));
OnProxyChanged();
}
}
set => SetProxy(value, false);
}
private MaProxy? _selectedProxy;
public bool IsDefaultProxy => SelectedProxy == null && MaClient.DefaultProxy != null && SelectedMafile != null;
private bool _internalProxyRefreshInProgress;
[ObservableProperty] private bool _proxyExist = true;
public bool IsDefaultProxy => SelectedProxy == null && MaClient.DefaultProxy != null && SelectedMafile != null;
private bool _handleProxyChange;
private MaProxy? _selectedProxy;
//TODO: Refactor this method
private void SetCurrentProxy()
private void SetProxy(MaProxy? proxy, bool system)
{
if (ReferenceEquals(_selectedProxy, SelectedMafile?.Proxy) == false && _selectedProxy?.Equals(SelectedMafile?.Proxy) == false)
_handleProxyChange = true;
if (SelectedMafile == null)
if (_internalProxyRefreshInProgress)
{
SelectedProxy = null;
ProxyExist = true;
return;
}
if (SelectedMafile.Proxy == null)
if (!SetProperty(ref _selectedProxy, proxy, nameof(SelectedProxy)))
{
SelectedProxy = SelectedMafile.Proxy;
return;
}
else
if (!system && SelectedMafile != null)
{
var existed = Proxies.FirstOrDefault(p => p.Id == SelectedMafile.Proxy.Id);
if (existed == null || existed.Data.Equals(SelectedMafile.Proxy.Data) == false)
{
SelectedProxy = SelectedMafile.Proxy;
}
else
{
SelectedProxy = existed;
}
SelectedMafile.Proxy = SelectedProxy;
Storage.UpdateMafile(SelectedMafile);
}
CheckProxyExist();
}
private void CheckProxyExist()
{
if (SelectedProxy == null)
{
ProxyExist = true;
return;
}
var selectedId = SelectedProxy.Id;
ProxyExist = ProxyStorage.Proxies.TryGetValue(selectedId, out var existedProxy)
&& SelectedProxy.Data.Equals(existedProxy); //Id is not important in 'Equals()' as we extract it from the dictionary
}
[RelayCommand]
private async Task OpenProxyManager()
{
await DialogsController.ShowProxyManager(SelectedProxy);
var oldSelection = SelectedProxy;
Proxies.Clear();
foreach (var kvp in ProxyStorage.Proxies)
try
{
Proxies.Add(new MaProxy(kvp.Key, kvp.Value));
var anyChanges = await DialogsController.ShowProxyManager();
if (!anyChanges) return;
_internalProxyRefreshInProgress = true;
Proxies.Clear();
foreach (var kvp in ProxyStorage.Proxies)
{
Proxies.Add(new MaProxy(kvp.Key, kvp.Value));
}
}
SelectedProxy = oldSelection;
SetCurrentProxy();
OnPropertyChanged(nameof(IsDefaultProxy));
_handleProxyChange = false;
finally
{
_internalProxyRefreshInProgress = false;
}
CheckProxyExist();
}
[RelayCommand]
@@ -103,23 +73,25 @@ public partial class MainVM
if (SelectedProxy == null) return;
if (SelectedMafile == null) return;
SelectedMafile.Proxy = null;
SelectedProxy = null;
Storage.UpdateMafile(SelectedMafile);
ProxyExist = true;
SetProxy(null, false); //Not system, triggered by user
}
private void OnProxyChanged()
private void CheckProxyExist()
{
if (_handleProxyChange)
if (SelectedProxy == null)
{
_handleProxyChange = false;
return;
ProxyExist = true;
}
else
{
var selectedId = SelectedProxy.Id;
ProxyExist = ProxyStorage.Proxies.TryGetValue(selectedId, out var existedProxy)
&& SelectedProxy.Data
.Equals(
existedProxy); //Id is not important in 'Equals()' as we extract it from the dictionary
}
if (SelectedMafile == null) return;
ProxyExist = true;
SelectedMafile.Proxy = SelectedProxy;
Storage.UpdateMafile(SelectedMafile);
OnPropertyChanged(nameof(ProxyExist));
OnPropertyChanged(nameof(IsDefaultProxy));
}
}
+128 -133
View File
@@ -1,4 +1,12 @@
using AchiesUtilities.Collections;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using AchiesUtilities.Collections;
using AchiesUtilities.Web.Proxy;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
@@ -18,14 +26,7 @@ using SteamLib.Exceptions.Mobile;
using SteamLib.ProtoCore.Exceptions;
using SteamLib.SteamMobile.AuthenticatorLinker;
using SteamLib.Web;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace NebulaAuth.ViewModel.Other;
@@ -33,69 +34,7 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
{
private const string LOCALIZATION_KEY = "LinkVM";
private static Logger Logger => Shell.Logger;
private static Microsoft.Extensions.Logging.ILogger Logger2 => Shell.ExtensionsLogger;
#region Properties
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsPasswordFieldVisible))]
private bool _isLogin;
[ObservableProperty] private bool _isEmailCode;
[ObservableProperty] private bool _isPhoneNumber;
[ObservableProperty] private bool _isEmailConfirmation;
[ObservableProperty] private bool _isLinkCode;
[ObservableProperty] private bool _isCompleted;
[ObservableProperty] private bool _isFieldVisible = true;
[ObservableProperty] private string _fieldText;
[ObservableProperty] private string _passFieldText;
[ObservableProperty] private string _hintText = GetLocalizationOrDefault("EnterLoginAndPassword");
private TaskCompletionSource<string> _emailCodeTcs = new();
private TaskCompletionSource<long?> _phoneNumberTcs = new();
private TaskCompletionSource _emailConfTcs = new();
private TaskCompletionSource<string> _linkCodeTcs = new();
private bool _isLinkStarted;
private string _rCode = string.Empty;
private string _password = string.Empty;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ProceedCommand))]
private bool _canProceed = true;
public bool IsPasswordFieldVisible => !IsLogin;
private LoginV2ExecutorOptions _loginV2ExecutorOptions;
private SteamAuthenticatorLinker _linker;
private MobileSessionData _sessionData;
#endregion
#region HttpClient
private static HttpClient Client { get; }
private static HttpClientHandler Handler { get; }
private static DynamicProxy Proxy { get; }
public ObservableDictionary<int, ProxyData> Proxies => ProxyStorage.Proxies;
public KeyValuePair<int, ProxyData>? SelectedProxy
{
get => _selectedProxy;
set
{
SetProperty(ref _selectedProxy, value);
SetProxy();
}
}
private KeyValuePair<int, ProxyData>? _selectedProxy;
#endregion
private static ILogger Logger2 => Shell.ExtensionsLogger;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public LinkAccountVM()
@@ -142,7 +81,8 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
FieldText = string.Empty;
IsFieldVisible = false;
HintText = string.Empty;
_sessionData = (MobileSessionData)await LoginV2Executor.DoLogin(_loginV2ExecutorOptions, userName, pass);
_sessionData =
(MobileSessionData) await LoginV2Executor.DoLogin(_loginV2ExecutorOptions, userName, pass);
Handler.CookieContainer.SetSteamMobileCookiesWithMobileToken(_sessionData);
IsEmailCode = true;
}
@@ -167,7 +107,6 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
InvokeOnDispatcher(ResetState);
return;
}
}
if (IsEmailCode == false)
@@ -189,7 +128,7 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
{
_isLinkStarted = true;
var linkOptions = new LinkOptions(Client, LoginV2Executor.NullConsumer, this,
null, this, this, backupHandler: Backup, Logger2);
null, this, this, Backup, Logger2);
_linker = new SteamAuthenticatorLinker(linkOptions);
var result = await _linker.LinkAccount(_sessionData);
IsLinkCode = true;
@@ -224,7 +163,6 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
HintText = $"{GetLocalizationCommon("Error")}: {ErrorTranslatorHelper.TranslateLinkerError(ex.Error)}";
InvokeOnDispatcher(ResetState);
return;
}
catch (HttpRequestException ex)
{
@@ -249,7 +187,7 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
}
linkStarted:
linkStarted:
if (IsPhoneNumber == false)
{
var phoneText = FieldText;
@@ -260,31 +198,30 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
HintText = string.Empty;
IsFieldVisible = false;
_phoneNumberTcs.SetResult(null);
_phoneNumberTcs = new();
_phoneNumberTcs = new TaskCompletionSource<long?>();
return;
}
if (!string.IsNullOrWhiteSpace(phoneText) && phoneText.Length >= 4 && long.TryParse(phoneText, out var phone))
if (!string.IsNullOrWhiteSpace(phoneText) && phoneText.Length >= 4 &&
long.TryParse(phoneText, out var phone))
{
HintText = string.Empty;
IsFieldVisible = false;
_phoneNumberTcs.SetResult(phone);
_phoneNumberTcs = new();
return;
}
else
{
HintText = GetLocalizationOrDefault("PleaseEnterCorrectPhone");
CanProceed = true;
_phoneNumberTcs = new TaskCompletionSource<long?>();
return;
}
HintText = GetLocalizationOrDefault("PleaseEnterCorrectPhone");
CanProceed = true;
return;
}
if (IsEmailConfirmation == false)
{
HintText = string.Empty;
_emailConfTcs.SetResult();
_emailConfTcs = new();
_emailConfTcs = new TaskCompletionSource();
CanProceed = false;
return;
}
@@ -298,17 +235,14 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
HintText = string.Empty;
IsFieldVisible = false;
_linkCodeTcs.SetResult(linkCode);
_linkCodeTcs = new();
return;
_linkCodeTcs = new TaskCompletionSource<string>();
}
else
{
HintText = GetLocalizationOrDefault("PleaseEnterCorrectCode");
CanProceed = true;
return;
}
}
}
[RelayCommand]
@@ -344,13 +278,113 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
{
Directory.CreateDirectory("mafiles_backup");
}
var json = NebulaSerializer.SerializeMafile(data, null);
File.WriteAllText(Path.Combine("mafiles_backup", data.AccountName + ".mafile"), json); //TODO: Move logic to Storage
File.WriteAllText(Path.Combine("mafiles_backup", data.AccountName + ".mafile"),
json); //TODO: Move logic to Storage
}
[RelayCommand]
private void OpenTroubleshooting()
{
const string troubleshootingURI =
"https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/docs/{0}/LinkingTroubleshooting";
var localized = string.Format(troubleshootingURI, LocManager.GetCurrentLanguageCode());
Process.Start(new ProcessStartInfo(new Uri(localized).ToString())
{
UseShellExecute = true
});
}
[RelayCommand]
private void CopyCode()
{
try
{
Clipboard.SetText(_rCode);
}
catch (Exception ex)
{
Shell.Logger.Error(ex, "Error whily copying RCode");
}
}
private static string GetLocalizationOrDefault(string key)
{
return LocManager.GetCodeBehindOrDefault(key, LOCALIZATION_KEY, key);
}
private static string GetLocalizationCommon(string key)
{
return LocManager.GetCommonOrDefault(key, key);
}
#region Properties
[ObservableProperty] [NotifyPropertyChangedFor(nameof(IsPasswordFieldVisible))]
private bool _isLogin;
[ObservableProperty] private bool _isEmailCode;
[ObservableProperty] private bool _isPhoneNumber;
[ObservableProperty] private bool _isEmailConfirmation;
[ObservableProperty] private bool _isLinkCode;
[ObservableProperty] private bool _isCompleted;
[ObservableProperty] private bool _isFieldVisible = true;
[ObservableProperty] private string _fieldText;
[ObservableProperty] private string _passFieldText;
[ObservableProperty] private string _hintText = GetLocalizationOrDefault("EnterLoginAndPassword");
private TaskCompletionSource<string> _emailCodeTcs = new();
private TaskCompletionSource<long?> _phoneNumberTcs = new();
private TaskCompletionSource _emailConfTcs = new();
private TaskCompletionSource<string> _linkCodeTcs = new();
private bool _isLinkStarted;
private string _rCode = string.Empty;
private string _password = string.Empty;
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(ProceedCommand))]
private bool _canProceed = true;
public bool IsPasswordFieldVisible => !IsLogin;
private LoginV2ExecutorOptions _loginV2ExecutorOptions;
private SteamAuthenticatorLinker _linker;
private MobileSessionData _sessionData;
#endregion
#region HttpClient
private static HttpClient Client { get; }
private static HttpClientHandler Handler { get; }
private static DynamicProxy Proxy { get; }
public ObservableDictionary<int, ProxyData> Proxies => ProxyStorage.Proxies;
public KeyValuePair<int, ProxyData>? SelectedProxy
{
get => _selectedProxy;
set
{
SetProperty(ref _selectedProxy, value);
SetProxy();
}
}
private KeyValuePair<int, ProxyData>? _selectedProxy;
#endregion
#region Providers
public int MaxRetryCount { get; }
public Task<string> GetEmailAuthCode(ILoginConsumer caller)
{
CanProceed = true;
@@ -384,6 +418,7 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
IsFieldVisible = true;
return _phoneNumberTcs.Task;
}
public async Task<int> GetSmsCode(ILoginConsumer caller, long? phoneNumber, string? hint)
{
IsPhoneNumber = true;
@@ -402,7 +437,7 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
static LinkAccountVM()
{
Proxy = new DynamicProxy(null);
Proxy = new DynamicProxy();
var clientPair = ClientBuilder.BuildMobileClient(Proxy, null);
Client = clientPair.Client;
Handler = clientPair.Handler;
@@ -419,44 +454,4 @@ public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNum
}
#endregion
[RelayCommand]
private void OpenTroubleshooting()
{
const string troubleshootingURI =
"https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/docs/{0}/LinkingTroubleshooting";
var localized = string.Format(troubleshootingURI, LocManager.GetCurrentLanguageCode());
Process.Start(new ProcessStartInfo(new Uri(localized).ToString())
{
UseShellExecute = true
});
}
[RelayCommand]
private void CopyCode()
{
try
{
Clipboard.SetText(_rCode);
}
catch (Exception ex)
{
Shell.Logger.Error(ex, "Error whily copying RCode");
return;
}
}
private static string GetLocalizationOrDefault(string key)
{
return LocManager.GetCodeBehindOrDefault(key, LOCALIZATION_KEY, key);
}
private static string GetLocalizationCommon(string key)
{
return LocManager.GetCommonOrDefault(key, key);
}
}
@@ -1,20 +1,14 @@
using CommunityToolkit.Mvvm.ComponentModel;
using NebulaAuth.Model.Entities;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Model.Entities;
namespace NebulaAuth.ViewModel.Other;
public partial class LoginAgainOnImportVM : ObservableObject
{
public ObservableCollection<MaProxy> Proxies { get; } = new();
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsFormValid))]
private string _password = null!;
[ObservableProperty] private bool _savePassword;
[ObservableProperty] private string _userName = null!;
[ObservableProperty] private bool _mafileHasProxy;
public MaProxy? SelectedProxy
{
@@ -27,6 +21,7 @@ public partial class LoginAgainOnImportVM : ObservableObject
}
}
}
public bool UseMafileProxy
{
get => _useMafileProxy;
@@ -40,20 +35,29 @@ public partial class LoginAgainOnImportVM : ObservableObject
}
public bool IsFormValid => !string.IsNullOrWhiteSpace(Password);
[ObservableProperty] private bool _mafileHasProxy;
[ObservableProperty] [NotifyPropertyChangedFor(nameof(IsFormValid))]
private string _password = null!;
[ObservableProperty] private bool _savePassword;
private MaProxy? _selectedProxy;
private bool _useMafileProxy;
[ObservableProperty] private string _userName = null!;
public LoginAgainOnImportVM(Mafile mafile, IEnumerable<MaProxy> proxies)
{
UserName = mafile.AccountName;
MafileHasProxy = mafile.Proxy != null;
UseMafileProxy = MafileHasProxy;
Proxies = new(proxies);
Proxies = new ObservableCollection<MaProxy>(proxies);
}
public LoginAgainOnImportVM()
{ }
{
}
[RelayCommand]
private void RemoveProxy()
+5 -9
View File
@@ -4,16 +4,12 @@ namespace NebulaAuth.ViewModel.Other;
public partial class LoginAgainVM : ObservableObject
{
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsFormValid))]
public bool IsFormValid => !string.IsNullOrWhiteSpace(Password);
[ObservableProperty] [NotifyPropertyChangedFor(nameof(IsFormValid))]
private string _password = null!;
[ObservableProperty]
private bool _savePassword;
[ObservableProperty] private bool _savePassword;
[ObservableProperty]
private string _userName = null!;
public bool IsFormValid => !string.IsNullOrWhiteSpace(Password);
[ObservableProperty] private string _userName = null!;
}
+17 -12
View File
@@ -1,14 +1,14 @@
using AchiesUtilities.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using AchiesUtilities.Collections;
using AchiesUtilities.Web.Proxy;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Core;
using NebulaAuth.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
namespace NebulaAuth.ViewModel.Other;
@@ -16,13 +16,14 @@ public partial class ProxyManagerVM : ObservableObject
{
private const string LOCALIZATION_KEY = "ProxyManagerVM";
[ObservableProperty] private KeyValuePair<int, ProxyData>? _selectedProxy;
[ObservableProperty] private string _addProxyField = string.Empty;
[ObservableProperty] private KeyValuePair<int, ProxyData>? _defaultProxy;
private static readonly Regex IdRegex = new(@"\{(\d+)\}$", RegexOptions.Compiled);
public ObservableDictionary<int, ProxyData> Proxies => ProxyStorage.Proxies;
private static readonly Regex IdRegex = new(@"\{(\d+)\}$", RegexOptions.Compiled);
public bool AnyChanges { get; private set; }
[ObservableProperty] private string _addProxyField = string.Empty;
[ObservableProperty] private KeyValuePair<int, ProxyData>? _defaultProxy;
[ObservableProperty] private KeyValuePair<int, ProxyData>? _selectedProxy;
public ProxyManagerVM()
{
@@ -33,6 +34,7 @@ public partial class ProxyManagerVM : ObservableObject
[RelayCommand]
private void AddProxy()
{
AnyChanges = true;
var input = AddProxyField;
if (string.IsNullOrEmpty(input)) return;
@@ -69,7 +71,6 @@ public partial class ProxyManagerVM : ObservableObject
}
if (ProxyStorage.DefaultScheme.TryParse(str, out var proxy))
{
if (id != null && proxies.Any(kvp => kvp.Key == id))
@@ -77,6 +78,7 @@ public partial class ProxyManagerVM : ObservableObject
SnackbarController.SendSnackbar(string.Format(GetLocalizationOrDefault("DuplicateId"), id));
return;
}
proxies.Add(KeyValuePair.Create(id, proxy));
}
else
@@ -86,6 +88,7 @@ public partial class ProxyManagerVM : ObservableObject
SnackbarController.SendSnackbar(GetLocalizationOrDefault("WrongFormat"));
return;
}
SnackbarController.SendSnackbar(string.Format(GetLocalizationOrDefault("WrongFormatOnLine"), i));
return;
}
@@ -108,6 +111,7 @@ public partial class ProxyManagerVM : ObservableObject
[RelayCommand]
private void RemoveProxy()
{
AnyChanges = true;
var selected = SelectedProxy;
if (selected == null) return;
var s = selected.Value;
@@ -137,6 +141,7 @@ public partial class ProxyManagerVM : ObservableObject
private void SetDefault(object? arg)
{
if (arg is not KeyValuePair<int, ProxyData> proxy) return;
AnyChanges = true;
DefaultProxy = proxy;
MaClient.DefaultProxy = proxy.Value;
ProxyStorage.Save();
@@ -145,6 +150,7 @@ public partial class ProxyManagerVM : ObservableObject
[RelayCommand]
private void RemoveDefault()
{
AnyChanges = true;
DefaultProxy = null;
MaClient.DefaultProxy = null;
ProxyStorage.Save();
@@ -162,7 +168,6 @@ public partial class ProxyManagerVM : ObservableObject
{
Shell.Logger.Error(ex);
}
}
[RelayCommand]
+5 -8
View File
@@ -1,9 +1,9 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Model;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Windows.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Core;
using NebulaAuth.Model;
namespace NebulaAuth.ViewModel.Other;
@@ -27,7 +27,7 @@ public partial class SettingsVM : ObservableObject
{
{BackgroundMode.Default, LocManager.GetOrDefault("Default", "SettingsDialog", "BackgroundMode", "Default")},
{BackgroundMode.Custom, LocManager.GetOrDefault("Default", "SettingsDialog", "BackgroundMode", "Custom")},
{BackgroundMode.Color, LocManager.GetOrDefault("Default", "SettingsDialog", "BackgroundMode", "NoBackground")},
{BackgroundMode.Color, LocManager.GetOrDefault("Default", "SettingsDialog", "BackgroundMode", "NoBackground")}
};
public Dictionary<LocalizationLanguage, string> Languages { get; } = new()
@@ -47,7 +47,6 @@ public partial class SettingsVM : ObservableObject
{
get => Settings.IconColor;
set => Settings.IconColor = value;
}
public bool UseIcon
@@ -81,7 +80,6 @@ public partial class SettingsVM : ObservableObject
}
public LocalizationLanguage Language
{
get => Settings.Language;
@@ -124,5 +122,4 @@ public partial class SettingsVM : ObservableObject
{
Settings.IsPasswordSet = PHandler.SetPassword(Password);
}
}
+1 -1
View File
@@ -5,8 +5,8 @@ namespace NebulaAuth.ViewModel.Other;
public class UpdaterVM : ObservableObject
{
public UpdateInfoEventArgs UpdateInfoEventArgs { get; }
public UpdaterVM(UpdateInfoEventArgs args)
{
UpdateInfoEventArgs = args;
+56 -18
View File
@@ -70,9 +70,12 @@
"ua": "Завантаження..."
},
"StartTip": {
"ru": "Чтобы начать пользоваться программой вы можете привязать аккаунт через меню \"Аккаунт\", либо импортировать существующие мафайлы одним из способов:\n1. Скопировать их в папку mafiles и перезапустить приложение\n2. Перетянуть файлы прямо в окно программы\n3. Скопировать файлы и нажать CTRL+V в окне программы\n4. Через меню \"Файл\" - \"Импорт\"",
"en": "To start using the program, you can link an account through the \"Account\" menu, or import existing mafiles in one of the following ways:\n1. Copy them to the mafiles folder and restart the application\n2. Drag files directly into the program window\n3. Copy files and press CTRL+V in the program window\n4. Through the \"File\" - \"Import\" menu",
"ua": "Щоб почати користуватися програмою, ви можете прив'язати акаунт через меню \"Акаунт\", або імпортувати існуючі мафайли одним із способів:\n1. Скопіювати їх у папку mafiles та перезапустити програму\n2. Перетягнути файли безпосередньо в вікно програми\n3. Скопіювати файли та натиснути CTRL+V в вікні програми\n4. Через меню \"Файл\" - \"Імпорт\""
"ru":
"Чтобы начать пользоваться программой вы можете привязать аккаунт через меню \"Аккаунт\", либо импортировать существующие мафайлы одним из способов:\n1. Скопировать их в папку mafiles и перезапустить приложение\n2. Перетянуть файлы прямо в окно программы\n3. Скопировать файлы и нажать CTRL+V в окне программы\n4. Через меню \"Файл\" - \"Импорт\"",
"en":
"To start using the program, you can link an account through the \"Account\" menu, or import existing mafiles in one of the following ways:\n1. Copy them to the mafiles folder and restart the application\n2. Drag files directly into the program window\n3. Copy files and press CTRL+V in the program window\n4. Through the \"File\" - \"Import\" menu",
"ua":
"Щоб почати користуватися програмою, ви можете прив'язати акаунт через меню \"Акаунт\", або імпортувати існуючі мафайли одним із способів:\n1. Скопіювати їх у папку mafiles та перезапустити програму\n2. Перетягнути файли безпосередньо в вікно програми\n3. Скопіювати файли та натиснути CTRL+V в вікні програми\n4. Через меню \"Файл\" - \"Імпорт\""
}
},
"Menu": {
@@ -283,6 +286,11 @@
"en": "Remove from group",
"ru": "Удалить из группы",
"ua": "Видалити з групи"
},
"CopyPassword": {
"en": "Copy password",
"ru": "Скопировать пароль",
"ua": "Скопіювати пароль"
}
},
"Proxy": {
@@ -385,9 +393,12 @@
"ua": "Ігнорувати помилки Patch Tuesday у таймері (експ.)"
},
"IgnorePatchTuesdayErrorsHint": {
"en": "Ignore errors that occur every Tuesday (Wednesday night in GMT) when Steam doing technical works and auto-confirm timers turns off unnecessarily",
"ru": "Игнорировать ошибки, которые возникают каждый вторник (ночь среды по GMT) когда Steam проводит технические работы и автоподтверждения отключаются без надобности",
"ua": "Ігнорувати помилки, які виникають щосереди (ніч середи за GMT) коли Steam проводить технічні роботи і автопідтвердження вимикаються без потреби"
"en":
"Ignore errors that occur every Tuesday (Wednesday night in GMT) when Steam doing technical works and auto-confirm timers turns off unnecessarily",
"ru":
"Игнорировать ошибки, которые возникают каждый вторник (ночь среды по GMT) когда Steam проводит технические работы и автоподтверждения отключаются без надобности",
"ua":
"Ігнорувати помилки, які виникають щосереди (ніч середи за GMT) коли Steam проводить технічні роботи і автопідтвердження вимикаються без потреби"
}
@@ -517,9 +528,12 @@
},
"SetEncryptedPasswordDialog": {
"DialogText": {
"en": "You have previously set an encryption password for passwords in mafiles, specify it so that the application can automatically log in in case of problems with the session. (Optional)",
"ru": "Ранее вы устанавливали пароль шифрования для паролей в мафайлах, укажите его, чтобы приложение могло автоматически авторизоваться в случае проблем с сессией. (Не обязательно)",
"ua": "Раніше ви встановлювали пароль шифрування для паролів в мафайлах, вкажіть його, щоб додаток міг автоматично авторизуватися у випадку проблем з сесією. (Не обов'язково)"
"en":
"You have previously set an encryption password for passwords in mafiles, specify it so that the application can automatically log in in case of problems with the session. (Optional)",
"ru":
"Ранее вы устанавливали пароль шифрования для паролей в мафайлах, укажите его, чтобы приложение могло автоматически авторизоваться в случае проблем с сессией. (Не обязательно)",
"ua":
"Раніше ви встановлювали пароль шифрування для паролів в мафайлах, вкажіть його, щоб додаток міг автоматично авторизуватися у випадку проблем з сесією. (Не обов'язково)"
},
"Ok": {
"en": "Ok",
@@ -625,9 +639,12 @@
"ua": "помилки:"
},
"RemoveMafileConfirmation": {
"ru": "Удалить мафайл? Мафайл будет перемещен в папку 'mafiles_removed' (Это действие не удаляет Steam Guard с аккаунта)",
"en": "Remove mafile? Mafile will be moved to 'mafiles_removed' directory (This action does not remove the Steam Guard from the account)",
"ua": "Видалити мафайл? Мафайл буде переміщено у каталог 'mafiles_removed' (Ця дія не видаляє автентифікатор з облікового запису)"
"ru":
"Удалить мафайл? Мафайл будет перемещен в папку 'mafiles_removed' (Это действие не удаляет Steam Guard с аккаунта)",
"en":
"Remove mafile? Mafile will be moved to 'mafiles_removed' directory (This action does not remove the Steam Guard from the account)",
"ua":
"Видалити мафайл? Мафайл буде переміщено у каталог 'mafiles_removed' (Ця дія не видаляє автентифікатор з облікового запису)"
},
"CantRemoveAlreadyExist": {
"ru": "Не удалось переместить мафайл, возможно в папке уже существует мафайл с таким именем.",
@@ -678,6 +695,17 @@
"en": "Mafile not copied",
"ru": "Мафайл не скопирован",
"ua": "Мафайл не скопійовано"
},
"PasswordCopied": {
"en": "Password copied",
"ru": "Пароль скопирован",
"ua": "Пароль скопійовано"
},
"CantDecryptPassword": {
"en": "Can't decrypt password. Maybe password from this mafile was encrypted with another encryption password",
"ru":
"Не удалось расшифровать пароль. Возможно пароль из этого мафайла был зашифрован другим паролем шифрования",
"ua": "Не вдалося розшифрувати пароль. Можливо пароль з цього мафайла був зашифрований іншим паролем шифрування"
}
},
"ErrorTranslator": {
@@ -927,8 +955,10 @@
},
"InvalidStateWithStatus2": {
"ru": "Неверное состояние (InvalidState) со статусом 2. Откройте ссылку на руководство сверху этого окна.",
"en": "Invalid state (InvalidState) with status 2. Open link to the troubleshooting guide at the top of this window.",
"ua": "Невірний стан (InvalidState) зі статусом 2. Відкрийте посилання на посібник з усунення несправностей у верхній частині цього вікна."
"en":
"Invalid state (InvalidState) with status 2. Open link to the troubleshooting guide at the top of this window.",
"ua":
"Невірний стан (InvalidState) зі статусом 2. Відкрийте посилання на посібник з усунення несправностей у верхній частині цього вікна."
},
"GeneralFailure": {
"ru": "General Failure",
@@ -1098,12 +1128,20 @@
"ru": "Авто ",
"en": "Auto ",
"ua": "Авто "
},
"TimerPreventedOverlap": {
"ru": "Авто: таймер подтверждений пытался начать новый цикл, когда предыдущий еще не завершился. Советуем увеличить задержку",
"en": "Auto: confirmation timer tried to start new cycle when previous one was not finished yet. We recommend to increase delay",
"ua": "Авто: таймер підтверджень намагався запустити новий цикл, коли попередній ще не закінчився. Рекомендуємо збільшити затримку"
}
}
},
"CantAlignTimeError": {
"ru": "Не удается синхронизировать время со Steam. Возможно отсутствует подключение к интернету или Steam недоступен. Подробная ошибка сохранена в log.log",
"en": "Can't align time with Steam. Maybe no internet connection or Steam is unavailable. Detailed error saved in log.log",
"ua": "Не вдається синхронізувати час з Steam. Можливо відсутнє підключення до інтернету або Steam недоступний. Детальна помилка збережена в log.log"
"ru":
"Не удается синхронизировать время со Steam. Возможно отсутствует подключение к интернету или Steam недоступен. Подробная ошибка сохранена в log.log",
"en":
"Can't align time with Steam. Maybe no internet connection or Steam is unavailable. Detailed error saved in log.log",
"ua":
"Не вдається синхронізувати час з Steam. Можливо відсутнє підключення до інтернету або Steam недоступний. Детальна помилка збережена в log.log"
}
}
}
+4 -3
View File
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.5.5.0</version>
<url>https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.5.5/NebulaAuth.1.5.5.zip</url>
<changelog>https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.5.5.html</changelog>
<version>1.5.6.0</version>
<url>https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.5.6/NebulaAuth.1.5.6.zip</url>
<changelog>https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.5.6.html</changelog>
<mandatory>false</mandatory>
</item>