mirror of
https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies.git
synced 2026-07-25 22:31:42 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a641e99ae |
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
+22
-18
@@ -3,6 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33205.214
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaAuth", "NebulaAuth\NebulaAuth.csproj", "{0FD01700-6D5C-451B-93BA-0860647E8F13}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{09F02072-F91D-4DAA-87BC-A34D3E150570} = {09F02072-F91D-4DAA-87BC-A34D3E150570}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaAuth.LegacyConverter", "NebulaAuth.LegacyConverter\NebulaAuth.LegacyConverter.csproj", "{2D78A7D9-986A-4890-8A91-7ABD57A91830}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamLibForked", "SteamLibForked\SteamLibForked.csproj", "{09F02072-F91D-4DAA-87BC-A34D3E150570}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "changelog", "changelog", "{161BFADE-FCF3-45D1-82EA-8A1B187529F7}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
changelog\1.3.4.html = changelog\1.3.4.html
|
||||
@@ -19,32 +28,27 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "changelog", "changelog", "{
|
||||
changelog\1.5.4.html = changelog\1.5.4.html
|
||||
changelog\1.5.5.html = changelog\1.5.5.html
|
||||
changelog\1.5.6.html = changelog\1.5.6.html
|
||||
changelog\1.5.7.html = changelog\1.5.7.html
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SteamLibForked", "src\SteamLibForked\SteamLibForked.csproj", "{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NebulaAuth.LegacyConverter", "src\NebulaAuth.LegacyConverter\NebulaAuth.LegacyConverter.csproj", "{C8235305-E5C4-155B-C718-C0F239CA3AB7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NebulaAuth", "src\NebulaAuth\NebulaAuth.csproj", "{C42F63B6-32F7-ED08-5B86-CD51989761AD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C8235305-E5C4-155B-C718-C0F239CA3AB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C8235305-E5C4-155B-C718-C0F239CA3AB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C8235305-E5C4-155B-C718-C0F239CA3AB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C8235305-E5C4-155B-C718-C0F239CA3AB7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C42F63B6-32F7-ED08-5B86-CD51989761AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C42F63B6-32F7-ED08-5B86-CD51989761AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C42F63B6-32F7-ED08-5B86-CD51989761AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C42F63B6-32F7-ED08-5B86-CD51989761AD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0FD01700-6D5C-451B-93BA-0860647E8F13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0FD01700-6D5C-451B-93BA-0860647E8F13}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0FD01700-6D5C-451B-93BA-0860647E8F13}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0FD01700-6D5C-451B-93BA-0860647E8F13}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2D78A7D9-986A-4890-8A91-7ABD57A91830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2D78A7D9-986A-4890-8A91-7ABD57A91830}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2D78A7D9-986A-4890-8A91-7ABD57A91830}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2D78A7D9-986A-4890-8A91-7ABD57A91830}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{09F02072-F91D-4DAA-87BC-A34D3E150570}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{09F02072-F91D-4DAA-87BC-A34D3E150570}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{09F02072-F91D-4DAA-87BC-A34D3E150570}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{09F02072-F91D-4DAA-87BC-A34D3E150570}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:converters="clr-namespace:NebulaAuth.Converters"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime"
|
||||
xmlns:background="clr-namespace:NebulaAuth.Converters.Background">
|
||||
xmlns:background="clr-namespace:NebulaAuth.Converters.Background"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<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" />
|
||||
@@ -15,50 +19,32 @@
|
||||
<converters:ColorToBrushConverter x:Key="ColorToBrushConverter" />
|
||||
<converters:AnyMafilesToVisibilityConverter x:Key="AnyMafilesToVisibilityConverter" />
|
||||
<converters:PortableMaClientStatusToColorConverter x:Key="PortableMaClientStatusToColorConverter" />
|
||||
|
||||
<converters:NullableToBooleanConverter x:Key="NullableToBooleanConverter" />
|
||||
<!-- Background converters-->
|
||||
<background:BackgroundImageVisibleConverter x:Key="BackgroundImageVisibleConverter" />
|
||||
<background:BackgroundSourceConverter x:Key="BackgroundSourceConverter" />
|
||||
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<materialDesign:NullableToVisibilityConverter x:Key="NullableToVisibilityConverter" />
|
||||
|
||||
|
||||
<system:Boolean x:Key="True">True</system:Boolean>
|
||||
<system:Boolean x:Key="False">False</system:Boolean>
|
||||
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<ResourceDictionary Source="Theme/Themes/DefaultTheme.xaml" />
|
||||
<ResourceDictionary
|
||||
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
|
||||
<ResourceDictionary Source="Theme/Brushes.xaml" />
|
||||
<!--Controls-->
|
||||
|
||||
<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="View/ConfirmationTemplates.xaml" />
|
||||
<ResourceDictionary Source="View/LinkerStepTemplates.xaml" />
|
||||
<ResourceDictionary Source="View/MafileMoverStepTemplates.xaml" />
|
||||
|
||||
<!--Theme-->
|
||||
|
||||
<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/MaterialDesignThemes.Overrides.xaml" />
|
||||
|
||||
|
||||
<ResourceDictionary>
|
||||
<Style TargetType="ToolTip" BasedOn="{StaticResource {x:Type ToolTip}}">
|
||||
<Setter Property="Foreground" Value="{DynamicResource Base100Brush}" />
|
||||
<Setter Property="Background" Value="{DynamicResource BaseContentBrush}" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
|
||||
<!--Controls-->
|
||||
<ResourceDictionary Source="View/ConfirmationTemplates.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
</Application.Resources>
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using NebulaAuth.Core;
|
||||
using NebulaAuth.Model;
|
||||
using NebulaAuth.Model.Exceptions;
|
||||
|
||||
namespace NebulaAuth;
|
||||
|
||||
public partial class App
|
||||
{
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
|
||||
LocManager.Init();
|
||||
LocManager.SetApplicationLocalization(Settings.Instance.Language);
|
||||
try
|
||||
{
|
||||
Shell.Initialize();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var msg = ex.ToString();
|
||||
if (ex is CantAlignTimeException)
|
||||
{
|
||||
msg = LocManager.Get("CantAlignTimeError");
|
||||
}
|
||||
|
||||
MessageBox.Show(msg, "Error", MessageBoxButton.OK, MessageBoxImage.Stop, MessageBoxResult.OK,
|
||||
MessageBoxOptions.DefaultDesktopOnly);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -11,10 +11,10 @@ public class AnyMafilesToVisibilityConverter : IValueConverter
|
||||
|
||||
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
//if (_everAnyMafiles)
|
||||
//{
|
||||
// return Visibility.Collapsed;
|
||||
//}
|
||||
if (_everAnyMafiles)
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
if (value is 0)
|
||||
{
|
||||
+1
-1
@@ -18,7 +18,7 @@ public class BackgroundSourceConverter : IValueConverter
|
||||
}
|
||||
|
||||
|
||||
return new BitmapImage(new Uri("pack://application:,,,/Theme/Background.png"));
|
||||
return new BitmapImage(new Uri("pack://application:,,,/Theme/Background.jpg"));
|
||||
}
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
-1
@@ -14,7 +14,6 @@ public class PortableMaClientStatusToColorConverter : IValueConverter
|
||||
return new SolidColorBrush(Color.FromRgb(187, 224, 139));
|
||||
}
|
||||
|
||||
|
||||
return new SolidColorBrush(Color.FromRgb(224, 139, 139));
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ using NebulaAuth.Model;
|
||||
using NebulaAuth.Model.Entities;
|
||||
using NebulaAuth.View;
|
||||
using NebulaAuth.View.Dialogs;
|
||||
using NebulaAuth.ViewModel.Linker;
|
||||
using NebulaAuth.ViewModel.MafileMover;
|
||||
using NebulaAuth.ViewModel.Other;
|
||||
|
||||
namespace NebulaAuth.Core;
|
||||
@@ -88,37 +86,11 @@ public static class DialogsController
|
||||
|
||||
public static async Task ShowLinkerDialog()
|
||||
{
|
||||
LinkAccountVM? vm = null;
|
||||
try
|
||||
var vm = new LinkAccountVM();
|
||||
var view = new LinkerView
|
||||
{
|
||||
vm = new LinkAccountVM();
|
||||
var view = new LinkerView
|
||||
{
|
||||
DataContext = vm
|
||||
};
|
||||
await DialogHost.Show(view);
|
||||
}
|
||||
finally
|
||||
{
|
||||
vm?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ShowMafileMoverDialog()
|
||||
{
|
||||
MafileMoverVM? vm = null;
|
||||
try
|
||||
{
|
||||
vm = new MafileMoverVM();
|
||||
var view = new MafileMoverView
|
||||
{
|
||||
DataContext = vm
|
||||
};
|
||||
await DialogHost.Show(view);
|
||||
}
|
||||
finally
|
||||
{
|
||||
vm?.Dispose();
|
||||
}
|
||||
DataContext = vm
|
||||
};
|
||||
await DialogHost.Show(view);
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ public static class LocManager
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
Loc.Instance.LogOutMissingTranslations = true;
|
||||
Loc.LogOutMissingTranslations = true;
|
||||
|
||||
LocalizationLoader.Instance.FileLanguageLoaders.Add(new JsonFileLoader());
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shell;
|
||||
using NebulaAuth.Model;
|
||||
@@ -14,6 +14,7 @@ namespace NebulaAuth.Core;
|
||||
|
||||
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()
|
||||
@@ -23,7 +24,11 @@ public static class ThemeManager
|
||||
|
||||
private static void SettingsOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(Settings.IconColor))
|
||||
if (e.PropertyName == nameof(Settings.BackgroundColor))
|
||||
{
|
||||
UpdateBackground();
|
||||
}
|
||||
else if (e.PropertyName == nameof(Settings.IconColor))
|
||||
{
|
||||
UpdateIcon();
|
||||
}
|
||||
@@ -53,40 +58,15 @@ public static class ThemeManager
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void ApplyTheme(string themeName)
|
||||
private static void UpdateBackground()
|
||||
{
|
||||
var colorDict = new ResourceDictionary
|
||||
{
|
||||
Source = new Uri($"Theme/Themes/{themeName}.xaml", UriKind.Relative)
|
||||
};
|
||||
|
||||
var brushDict = new ResourceDictionary
|
||||
{
|
||||
Source = new Uri("Theme/Brushes.xaml", UriKind.Relative)
|
||||
};
|
||||
|
||||
var mergedDictionaries = Application.Current.Resources.MergedDictionaries;
|
||||
|
||||
|
||||
var toRemove = mergedDictionaries
|
||||
.Where(d => d.Source?.OriginalString.Contains("Theme/Themes/") == true ||
|
||||
d.Source?.OriginalString.EndsWith("Brushes.xaml") == true)
|
||||
.ToList();
|
||||
|
||||
foreach (var dict in toRemove)
|
||||
{
|
||||
mergedDictionaries.Remove(dict);
|
||||
}
|
||||
|
||||
mergedDictionaries.Insert(0, colorDict);
|
||||
mergedDictionaries.Insert(0, brushDict);
|
||||
var color = Settings.Instance.BackgroundColor ?? DefaultBackgroundColor;
|
||||
Application.Current.Resources["WindowBackground"] = new SolidColorBrush(color);
|
||||
}
|
||||
|
||||
|
||||
public static void InitializeTheme()
|
||||
{
|
||||
UpdateIcon();
|
||||
ApplyTheme(Settings.Instance.GetTheme());
|
||||
UpdateBackground();
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace NebulaAuth.Core;
|
||||
public static class UpdateManager
|
||||
{
|
||||
private const string UPDATE_URL =
|
||||
"https://raw.githubusercontent.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/master/misc/update.xml";
|
||||
"https://raw.githubusercontent.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/master/NebulaAuth/update.xml";
|
||||
|
||||
public static void CheckForUpdates()
|
||||
{
|
||||
@@ -9,14 +9,12 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:entities="clr-namespace:NebulaAuth.Model.Entities"
|
||||
xmlns:viewModel="clr-namespace:NebulaAuth.ViewModel"
|
||||
xmlns:controls="clr-namespace:NebulaAuth.Theme.Controls"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
MinHeight="500" MinWidth="500" DefaultFontSize="18" ScaleCoefficient="0.4"
|
||||
Title="NebulaAuth" Height="800" Width="730"
|
||||
Style="{StaticResource MainWindow}"
|
||||
RenderOptions.BitmapScalingMode="HighQuality"
|
||||
Title="NebulaAuth" Height="800" Width="730" Style="{StaticResource MainWindow}"
|
||||
RenderOptions.BitmapScalingMode="HighQuality" Foreground="#FFF5F5F5"
|
||||
FontFamily="{md:MaterialDesignFont}"
|
||||
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance viewModel:MainVM}">
|
||||
<b:Interaction.Behaviors>
|
||||
@@ -30,31 +28,20 @@
|
||||
</Window.InputBindings>
|
||||
<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"
|
||||
ApplyBlurBackground="{Binding Settings.ApplyBlurBackground}"
|
||||
BlurRadius="12"
|
||||
x:Name="DialogHostInstance">
|
||||
|
||||
<md:DialogHost DialogOpened="DialogHost_DialogOpened" DialogClosed="DialogHost_DialogClosed">
|
||||
<Grid ZIndex="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image Grid.RowSpan="2" Opacity="{Binding Settings.BackgroundOpacity}" Stretch="UniformToFill"
|
||||
<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}}">
|
||||
<Image.Effect>
|
||||
<BlurEffect Radius="{Binding Settings.BackgroundBlur}" />
|
||||
</Image.Effect>
|
||||
</Image>
|
||||
<Rectangle Grid.Row="0" Grid.RowSpan="2" Fill="Black" Stretch="UniformToFill"
|
||||
Opacity="{Binding Settings.BackgroundGamma}"
|
||||
IsHitTestVisible="False" />
|
||||
|
||||
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"
|
||||
@@ -64,10 +51,13 @@
|
||||
<md:PackIcon Foreground="#9a65b8" HorizontalAlignment="Center" Width="36" Height="36"
|
||||
Kind="FileReplaceOutline" />
|
||||
</StackPanel>
|
||||
<ToolBarTray>
|
||||
<ToolBar ClipToBounds="True" HorizontalContentAlignment="Stretch"
|
||||
Style="{StaticResource MaterialDesignToolBar}" FontSize="16">
|
||||
<Menu FontSize="16">
|
||||
<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">
|
||||
<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}" />
|
||||
@@ -85,11 +75,8 @@
|
||||
<MenuItem Header="{Tr MainWindow.Menu.Account.Caption}">
|
||||
<MenuItem Header="{Tr MainWindow.Menu.Account.Link}"
|
||||
Command="{Binding LinkAccountCommand}" />
|
||||
<MenuItem Header="{Tr MainWindow.Menu.Account.MoveSteamGuard}"
|
||||
Command="{Binding MoveAccountCommand}" />
|
||||
<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}"
|
||||
@@ -104,8 +91,7 @@
|
||||
md:HintAssist.Hint="{Tr MainWindow.AppBar.GroupsHint}"
|
||||
MinWidth="100" Margin="8,0,8,0" VerticalAlignment="Center" IsEditable="True"
|
||||
ItemsSource="{Binding Groups}"
|
||||
SelectedValue="{Binding SelectedGroup}"
|
||||
md:TextFieldAssist.HasClearButton="True">
|
||||
SelectedValue="{Binding SelectedGroup}">
|
||||
|
||||
<FrameworkElement.Resources>
|
||||
<ResourceDictionary>
|
||||
@@ -128,7 +114,6 @@
|
||||
md:HintAssist.Hint="{Tr MainWindow.AppBar.Proxy.ProxyHint}"
|
||||
md:ComboBoxAssist.ShowSelectedItem="False"
|
||||
SelectedValue="{Binding SelectedProxy}"
|
||||
|
||||
ItemsSource="{Binding Proxies}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type entities:MaProxy}">
|
||||
@@ -147,8 +132,7 @@
|
||||
</UIElement.InputBindings>
|
||||
</ComboBox>
|
||||
<md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center"
|
||||
Foreground="{DynamicResource ErrorBrush}" Margin="3"
|
||||
ToolTipService.InitialShowDelay="300">
|
||||
Foreground="#FFFF0000" Margin="3" ToolTipService.InitialShowDelay="300">
|
||||
<md:PackIcon.ToolTip>
|
||||
<TextBlock>
|
||||
<Run
|
||||
@@ -169,11 +153,12 @@
|
||||
</UIElement.Visibility>
|
||||
</md:PackIcon>
|
||||
<md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center"
|
||||
Foreground="{DynamicResource WarningBrush}" Margin="3"
|
||||
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}">
|
||||
@@ -190,6 +175,7 @@
|
||||
</FrameworkElement.ContextMenu>
|
||||
</ToggleButton>
|
||||
<ToggleButton ToolTip="{Tr MainWindow.AppBar.TradeTimerHint}"
|
||||
Foreground="{DynamicResource PrimaryHueDarkForegroundBrush}"
|
||||
IsEnabled="{Binding IsMafileSelected}" Margin="2"
|
||||
Style="{StaticResource MaterialDesignFlatToggleButton}"
|
||||
IsChecked="{Binding TradeTimerEnabled}">
|
||||
@@ -211,7 +197,7 @@
|
||||
PreviewTextInput="UIElement_OnPreviewTextInput" />
|
||||
<ToggleButton ToolTip="{Tr MainWindow.AppBar.ShowAutoConfirmAccountsHint}"
|
||||
HorizontalAlignment="Right" IsChecked="{Binding MaacDisplay}"
|
||||
Foreground="{DynamicResource BaseContentBrush}" VerticalAlignment="Center"
|
||||
Foreground="WhiteSmoke" VerticalAlignment="Center"
|
||||
Style="{StaticResource MaterialDesignFlatPrimaryToggleButton}" Margin="4">
|
||||
<md:PackIcon Kind="Accounts" />
|
||||
</ToggleButton>
|
||||
@@ -228,138 +214,117 @@
|
||||
<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.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem" BasedOn="{StaticResource MaterialDesignListBoxItem}">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock HorizontalAlignment="Stretch" Text="{Binding AccountName}">
|
||||
<TextBlock.Foreground>
|
||||
<Binding Mode="OneWay" Path="LinkedClient.IsError"
|
||||
Converter="{StaticResource PortableMaClientStatusToColorConverter}">
|
||||
<Binding.FallbackValue>
|
||||
<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>
|
||||
</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}}" />
|
||||
</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}">
|
||||
<ItemsControl.ItemContainerStyle>
|
||||
<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}">
|
||||
<Binding />
|
||||
<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.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"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12">
|
||||
<Border.BorderBrush>
|
||||
<SolidColorBrush Color="{DynamicResource Base300Color}" Opacity="0.3" />
|
||||
</Border.BorderBrush>
|
||||
Visibility="{Binding MaFiles.Count, Converter={StaticResource AnyMafilesToVisibilityConverter}, Mode=OneWay}">
|
||||
<Border.Background>
|
||||
<SolidColorBrush Color="{DynamicResource Base100Color}"
|
||||
Opacity="{Binding Settings.LeftOpacity}" />
|
||||
<SolidColorBrush Color="DarkGray" Opacity="0.5" />
|
||||
</Border.Background>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Margin="4"
|
||||
Visibility="{Binding MaFiles.Count, Converter={StaticResource AnyMafilesToVisibilityConverter}}"
|
||||
TextWrapping="WrapWithOverflow" FontSize="16"
|
||||
Text="{Tr MainWindow.LeftPart.NoMafiles}" />
|
||||
|
||||
<ListBox w:FontScaleWindow.Scale="0.8" w:FontScaleWindow.ResizeFont="True" Margin="2"
|
||||
ItemsSource="{Binding MaFiles}"
|
||||
SelectedValue="{Binding SelectedMafile}">
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem"
|
||||
BasedOn="{StaticResource MaterialDesignListBoxItem}">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock HorizontalAlignment="Stretch" Text="{Binding AccountName}">
|
||||
<TextBlock.Resources>
|
||||
<SolidColorBrush x:Key="BaseContentBrushProxy"
|
||||
Color="{DynamicResource BaseContentColor}" />
|
||||
</TextBlock.Resources>
|
||||
|
||||
<TextBlock.Foreground>
|
||||
<Binding Path="LinkedClient.IsError"
|
||||
Converter="{StaticResource PortableMaClientStatusToColorConverter}"
|
||||
FallbackValue="{StaticResource BaseContentBrushProxy}" />
|
||||
</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>
|
||||
</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}}" />
|
||||
</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}">
|
||||
<ItemsControl.ItemContainerStyle>
|
||||
<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}">
|
||||
<Binding />
|
||||
<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.CopyPassword}"
|
||||
Command="{Binding Path=CopyPasswordCommand}"
|
||||
CommandParameter="{Binding Path=PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
|
||||
|
||||
</ContextMenu>
|
||||
</FrameworkElement.ContextMenu>
|
||||
|
||||
</ListBox>
|
||||
|
||||
<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>
|
||||
|
||||
<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}" />
|
||||
</Grid>
|
||||
<md:Card BorderThickness="1" Style="{StaticResource MaterialDesignOutlinedCard}" Grid.Column="1"
|
||||
Margin="10,10,15,10" UniformCornerRadius="12" Opacity="{Binding Settings.RightOpacity}">
|
||||
<md:Card Grid.Column="1" Margin="10,10,15,10" UniformCornerRadius="15">
|
||||
<Control.Background>
|
||||
<SolidColorBrush Color="#FF1A1D25" Opacity="0.6" />
|
||||
</Control.Background>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="115*" />
|
||||
<RowDefinition Height="436*" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Row="0">
|
||||
@@ -369,50 +334,47 @@
|
||||
</Grid.RowDefinitions>
|
||||
<TextBox w:FontScaleWindow.Scale="1.1" w:FontScaleWindow.ResizeFont="True"
|
||||
IsReadOnly="True" HorizontalContentAlignment="Center" Background="#00FFFFFF"
|
||||
|
||||
Style="{StaticResource MaterialDesignTextBox}"
|
||||
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
Text="{Binding Code, FallbackValue=Code}">
|
||||
<TextBox.InputBindings>
|
||||
<MouseBinding Gesture="LeftClick" Command="{Binding CopyCodeCommand}" />
|
||||
</TextBox.InputBindings>
|
||||
</TextBox>
|
||||
<controls:CodeProgressBar
|
||||
Visibility="{Binding SelectedMafile, Converter={StaticResource NullableToVisibilityConverter}}"
|
||||
Grid.Row="1" Height="4" Style="{StaticResource MaterialDesignLinearProgressBar}"
|
||||
MaxTime="30" TimeRemaining="{Binding CodeProgress, Mode=OneWay}" />
|
||||
<Grid Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<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="0,10,0,10"
|
||||
HorizontalAlignment="Center"
|
||||
Content="{Tr MainWindow.RightPart.LoadConfirmations}"
|
||||
Style="{StaticResource MaterialDesignOutlinedButton}" Margin="10"
|
||||
Command="{Binding GetConfirmationsCommand}"
|
||||
Width="{Binding Path=ActualWidth, Converter={StaticResource CoefficientConverter}, ConverterParameter=0.6, RelativeSource={RelativeSource AncestorType=md:Card}}" />
|
||||
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,10,10,10"
|
||||
Margin="10"
|
||||
Visibility="{Binding ConfirmationsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
ItemsSource="{Binding Confirmations}" Grid.RowSpan="2" />
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}" Grid.Row="4"
|
||||
w:FontScaleWindow.Scale="0.8" w:FontScaleWindow.ResizeFont="True"
|
||||
Command="{Binding ConfirmLoginCommand}"
|
||||
|
||||
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>
|
||||
<Border Grid.Row="2" BorderBrush="#1e1e24">
|
||||
<Border Grid.Row="2" BorderBrush="#FF696969">
|
||||
<Border.Background>
|
||||
<SolidColorBrush Opacity="1" Color="{DynamicResource Base300Color}" />
|
||||
<SolidColorBrush Opacity="0.5" Color="DimGray" />
|
||||
</Border.Background>
|
||||
<Grid>
|
||||
|
||||
<ToolBarPanel TextElement.Foreground="{DynamicResource SecondaryContentBrush}"
|
||||
Orientation="Horizontal" Margin="5" w:FontScaleWindow.Scale="0.73"
|
||||
|
||||
<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}" />
|
||||
@@ -420,21 +382,19 @@
|
||||
<TextBlock FontWeight="Bold" Text="{Tr MainWindow.Footer.Group}" />
|
||||
<TextBlock FontWeight="Normal"
|
||||
Text="{Binding SelectedMafile.Group, TargetNullValue=' ', FallbackValue=' ', Mode=OneWay}" />
|
||||
<!--<Button Command="{Binding DebugCommand}">Debug</Button>-->
|
||||
</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 AccentBrush}"
|
||||
Command="{Binding OpenLinksViewCommand}">
|
||||
Foreground="{DynamicResource PrimaryHueMidBrush}"
|
||||
RequestNavigate="Hyperlink_OnRequestNavigate">
|
||||
by achies
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Border>
|
||||
<md:Snackbar Grid.Row="1" MessageQueue="{Binding MessageQueue}" />
|
||||
<md:Snackbar Grid.Row="1" FontSize="20" MessageQueue="{Binding MessageQueue}" />
|
||||
</Grid>
|
||||
</md:DialogHost>
|
||||
</Border>
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Threading;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using NebulaAuth.Core;
|
||||
@@ -28,13 +30,10 @@ public partial class MainWindow
|
||||
|
||||
private async void OnApplicationStarted(object? sender, EventArgs e)
|
||||
{
|
||||
((MainVM) DataContext).CurrentDialogHost = DialogHostInstance;
|
||||
if (Settings.Instance.IsPasswordSet == false) return;
|
||||
Topmost = false;
|
||||
await Dispatcher.InvokeAsync(ShowSetPasswordDialog, DispatcherPriority.ContextIdle);
|
||||
await Dispatcher.BeginInvoke(ShowSetPasswordDialog, DispatcherPriority.ContextIdle);
|
||||
}
|
||||
|
||||
|
||||
private async Task ShowSetPasswordDialog()
|
||||
{
|
||||
var vm = new SetEncryptPasswordVM();
|
||||
@@ -42,7 +41,6 @@ public partial class MainWindow
|
||||
{
|
||||
DataContext = vm
|
||||
};
|
||||
|
||||
var result = await DialogHost.Show(dialog);
|
||||
var pass = vm.Password;
|
||||
if (result is true && string.IsNullOrWhiteSpace(pass) == false)
|
||||
@@ -51,6 +49,15 @@ 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)
|
||||
@@ -2,7 +2,7 @@
|
||||
using NebulaAuth.Model.MAAC;
|
||||
using Newtonsoft.Json;
|
||||
using SteamLib;
|
||||
using SteamLibForked.Models.Session;
|
||||
using SteamLib.Account;
|
||||
|
||||
namespace NebulaAuth.Model.Entities;
|
||||
|
||||
+6
-5
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
||||
using AchiesUtilities.Extensions;
|
||||
using NebulaAuth.Core;
|
||||
using NebulaAuth.Model.Entities;
|
||||
using NLog;
|
||||
|
||||
namespace NebulaAuth.Model.MAAC;
|
||||
|
||||
@@ -15,8 +16,6 @@ public static class MultiAccountAutoConfirmer
|
||||
{
|
||||
private const string LOC_PATH = "MAAC";
|
||||
private static readonly ReaderWriterLockSlim Lock = new();
|
||||
|
||||
private static readonly SemaphoreSlim ExecutionLock = new(1, 1);
|
||||
public static ObservableCollection<Mafile> Clients { get; }
|
||||
private static Timer Timer { get; }
|
||||
|
||||
@@ -28,10 +27,12 @@ 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)
|
||||
{
|
||||
var isHeld = false;
|
||||
bool isHeld = false;
|
||||
try
|
||||
{
|
||||
isHeld = await ExecutionLock.WaitAsync(0);
|
||||
@@ -40,8 +41,8 @@ public static class MultiAccountAutoConfirmer
|
||||
SnackbarController.SendSnackbar(GetLocalization("TimerPreventedOverlap"));
|
||||
return;
|
||||
}
|
||||
|
||||
await TimerConfirmInternal();
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -59,7 +60,7 @@ public static class MultiAccountAutoConfirmer
|
||||
private static async Task TimerConfirmInternal()
|
||||
{
|
||||
var clients = Lock.ReadLock(() => Clients.ToArray());
|
||||
var enabledClients = clients.Where(x => x.LinkedClient is {IsError: false}).ToArray();
|
||||
var enabledClients = clients.Where(x => x.LinkedClient is { IsError: false }).ToArray();
|
||||
enabledClients = DistributeEvenly(enabledClients).ToArray();
|
||||
var confirmed = 0;
|
||||
await Task.Run(async () =>
|
||||
+2
-2
@@ -14,10 +14,10 @@ using NebulaAuth.Model.Entities;
|
||||
using NebulaAuth.Utility;
|
||||
using SteamLib.Api.Mobile;
|
||||
using SteamLib.Authentication;
|
||||
using SteamLib.Exceptions.Authorization;
|
||||
using SteamLib.Core.Interfaces;
|
||||
using SteamLib.Exceptions;
|
||||
using SteamLib.SteamMobile.Confirmations;
|
||||
using SteamLib.Web;
|
||||
using SteamLibForked.Abstractions;
|
||||
|
||||
namespace NebulaAuth.Model.MAAC;
|
||||
|
||||
@@ -7,9 +7,9 @@ using AchiesUtilities.Web.Models;
|
||||
using AchiesUtilities.Web.Proxy;
|
||||
using NebulaAuth.Model.Entities;
|
||||
using SteamLib.Api.Mobile;
|
||||
using SteamLib.Api.Services;
|
||||
using SteamLib.Authentication;
|
||||
using SteamLib.Exceptions.Authorization;
|
||||
using SteamLib.Core.Interfaces;
|
||||
using SteamLib.Exceptions;
|
||||
using SteamLib.ProtoCore.Services;
|
||||
using SteamLib.SteamMobile.Confirmations;
|
||||
using SteamLib.Web;
|
||||
@@ -26,7 +26,6 @@ public static class MaClient
|
||||
|
||||
public static ProxyData? DefaultProxy { get; set; }
|
||||
|
||||
|
||||
static MaClient()
|
||||
{
|
||||
Proxy = new DynamicProxy();
|
||||
@@ -63,7 +62,7 @@ public static class MaClient
|
||||
return SteamMobileConfirmationsApi.GetConfirmations(Client, mafile, mafile.SessionData!.SteamId);
|
||||
}
|
||||
|
||||
public static Task LoginAgain(Mafile mafile, string password, bool savePassword)
|
||||
public static Task LoginAgain(Mafile mafile, string password, bool savePassword, ICaptchaResolver? resolver)
|
||||
{
|
||||
SetProxy(mafile);
|
||||
return SessionHandler.LoginAgain(new HttpClientHandlerPair(Client, ClientHandler), mafile, password,
|
||||
@@ -138,7 +137,7 @@ public static class MaClient
|
||||
ValidateMafile(mafile);
|
||||
SetProxy(mafile);
|
||||
var token = mafile.SessionData!.GetMobileToken()!.Value;
|
||||
var sessions = await AuthenticationServiceApi.GetAuthSessionsForAccount(Client, token.Token);
|
||||
var sessions = await SteamMobileAuthenticatorApi.GetAuthSessionsForAccount(Client, token.Token);
|
||||
|
||||
if (sessions.ClientIds.Count == 0)
|
||||
{
|
||||
@@ -157,11 +156,16 @@ public static class MaClient
|
||||
}
|
||||
|
||||
var clientId = sessions.ClientIds.Single();
|
||||
var clientInfo = await AuthenticationServiceApi.GetAuthSessionInfo(Client, token.Token, clientId);
|
||||
var updateReq =
|
||||
AuthRequestHelper.CreateMobileConfirmationRequest(1, clientId, mafile.SessionData.SteamId.Steam64,
|
||||
mafile.SharedSecret);
|
||||
await AuthenticationServiceApi.UpdateAuthSessionWithMobileConfirmation(Client, token.Token, updateReq);
|
||||
var clientInfo = await SteamMobileAuthenticatorApi.GetAuthSessionInfo(Client, token.Token, clientId);
|
||||
var updateReq = new UpdateAuthSessionWithMobileConfirmation_Request
|
||||
{
|
||||
ClientId = clientId,
|
||||
Confirm = true,
|
||||
Persistence = 1,
|
||||
Steamid = mafile.SessionData.SteamId.Steam64.ToUlong(),
|
||||
Version = 1
|
||||
};
|
||||
await SteamMobileAuthenticatorApi.UpdateAuthSessionStatus(Client, token.Token, mafile.SharedSecret, updateReq);
|
||||
return new LoginConfirmationResult
|
||||
{
|
||||
Country = clientInfo.Country,
|
||||
@@ -22,11 +22,6 @@ public static class NebulaSerializer
|
||||
AllowDeviceIdGeneration = true,
|
||||
AllowSessionIdGeneration = true,
|
||||
ThrowIfInvalidSteamId = false
|
||||
},
|
||||
SerializationOptions =
|
||||
{
|
||||
Sign = true,
|
||||
Formatting = Formatting.Indented
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -85,9 +80,9 @@ public static class NebulaSerializer
|
||||
{
|
||||
if (Settings.Instance.LegacyMode)
|
||||
{
|
||||
return MafileSerializer.SerializeLegacy(data, Serializer.Settings.SerializationOptions, properties);
|
||||
return MafileSerializer.SerializeLegacy(data, Formatting.Indented, properties);
|
||||
}
|
||||
|
||||
return Serializer.Serialize(data);
|
||||
return MafileSerializer.Serialize(data);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using MaterialDesignThemes.Wpf;
|
||||
using NebulaAuth.Core;
|
||||
using NebulaAuth.Model.Entities;
|
||||
using NebulaAuth.View.Dialogs;
|
||||
using SteamLib.Exceptions.Authorization;
|
||||
using SteamLib.Exceptions;
|
||||
|
||||
namespace NebulaAuth.Model;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using System.Threading.Tasks;
|
||||
using AchiesUtilities.Web.Models;
|
||||
using NebulaAuth.Model.Entities;
|
||||
using SteamLib.Account;
|
||||
using SteamLib.Api.Mobile;
|
||||
using SteamLib.Authentication;
|
||||
using SteamLib.Authentication.LoginV2;
|
||||
using SteamLib.Exceptions.Authorization;
|
||||
using SteamLib.Factory.Helpers;
|
||||
using SteamLib.Exceptions;
|
||||
using SteamLib.SteamMobile;
|
||||
using SteamLibForked.Models.Session;
|
||||
|
||||
namespace NebulaAuth.Model;
|
||||
|
||||
@@ -36,11 +35,11 @@ public partial class SessionHandler //API
|
||||
public static async Task LoginAgain(HttpClientHandlerPair chp, Mafile mafile, string password, bool savePassword)
|
||||
{
|
||||
var sgGenerator = new SteamGuardCodeGenerator(mafile.SharedSecret);
|
||||
var options = new LoginV2ExecutorOptions(StaticLoginConsumer.Instance, chp.Client)
|
||||
var options = new LoginV2ExecutorOptions(LoginV2Executor.NullConsumer, chp.Client)
|
||||
{
|
||||
Logger = Shell.ExtensionsLogger,
|
||||
AuthProviders = [sgGenerator],
|
||||
DeviceDetails = DeviceDetailsDefaultBuilder.GetMobileDefaultDevice(),
|
||||
SteamGuardProvider = sgGenerator,
|
||||
DeviceDetails = LoginV2ExecutorOptions.GetMobileDefaultDevice(),
|
||||
WebsiteId = "Mobile"
|
||||
};
|
||||
chp.Handler.CookieContainer.ClearMobileSessionCookies();
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
@@ -13,15 +12,6 @@ public partial class Settings : ObservableObject
|
||||
{
|
||||
public static Settings Instance { get; }
|
||||
|
||||
private static IReadOnlyDictionary<ThemeType, string> ThemeNames { get; } = new Dictionary<ThemeType, string>
|
||||
{
|
||||
{ThemeType.Default, "DefaultTheme"},
|
||||
{ThemeType.Light, "LightTheme"},
|
||||
{ThemeType.Black, "BlackTheme"},
|
||||
{ThemeType.Luxury, "LuxuryTheme"},
|
||||
{ThemeType.Shadcn, "ShadcnTheme"}
|
||||
};
|
||||
|
||||
static Settings()
|
||||
{
|
||||
if (File.Exists("settings.json") == false)
|
||||
@@ -50,10 +40,6 @@ public partial class Settings : ObservableObject
|
||||
private static void SettingsOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
Save();
|
||||
if (e.PropertyName == nameof(ThemeType))
|
||||
{
|
||||
ThemeManager.ApplyTheme(ThemeNames[Instance.ThemeType]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Save()
|
||||
@@ -62,27 +48,12 @@ public partial class Settings : ObservableObject
|
||||
File.WriteAllText("settings.json", json);
|
||||
}
|
||||
|
||||
public static void ResetThemeDefaults()
|
||||
{
|
||||
Instance.BackgroundBlur = 0.0;
|
||||
Instance.BackgroundOpacity = 1.0;
|
||||
Instance.BackgroundGamma = 0.0;
|
||||
Instance.LeftOpacity = 0.4;
|
||||
Instance.RightOpacity = 0.8;
|
||||
Instance.ApplyBlurBackground = true;
|
||||
Save();
|
||||
}
|
||||
|
||||
public string GetTheme()
|
||||
{
|
||||
return ThemeNames.TryGetValue(ThemeType, out var themeName) ? themeName : ThemeNames[ThemeType.Default];
|
||||
}
|
||||
|
||||
|
||||
#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;
|
||||
@@ -91,15 +62,6 @@ public partial class Settings : ObservableObject
|
||||
[ObservableProperty] private bool _useAccountNameAsMafileName;
|
||||
[ObservableProperty] private bool _ignorePatchTuesdayErrors;
|
||||
|
||||
[ObservableProperty] private BackgroundMode _backgroundMode = BackgroundMode.Default;
|
||||
[ObservableProperty] private double _leftOpacity = 0.4;
|
||||
[ObservableProperty] private double _rightOpacity = 1.0;
|
||||
[ObservableProperty] private double _backgroundBlur;
|
||||
[ObservableProperty] private double _backgroundOpacity = 1;
|
||||
[ObservableProperty] private double _backgroundGamma;
|
||||
[ObservableProperty] private bool _applyBlurBackground = true;
|
||||
[ObservableProperty] private ThemeType _themeType = ThemeType.Default;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -108,13 +70,4 @@ public enum BackgroundMode
|
||||
Default,
|
||||
Custom,
|
||||
Color
|
||||
}
|
||||
|
||||
public enum ThemeType
|
||||
{
|
||||
Default = 0,
|
||||
Black = 1,
|
||||
Light = 2,
|
||||
Luxury = 3,
|
||||
Shadcn = 4
|
||||
}
|
||||
@@ -11,12 +11,11 @@ namespace NebulaAuth.Model;
|
||||
|
||||
public static class Shell
|
||||
{
|
||||
public static Logger Logger { get; private set; } = null!;
|
||||
public static Logger Logger { get; } = LogManager.GetLogger("Logger");
|
||||
public static ILogger ExtensionsLogger { get; private set; } = null!;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
Logger = LogManager.GetLogger("Logger");
|
||||
var lp = new NLogLoggerProvider();
|
||||
var logger = lp.CreateLogger("SteamLib");
|
||||
SteamLibErrorMonitor.MonitorLogger = logger;
|
||||
@@ -1,84 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AchiesUtilities.Extensions;
|
||||
using NebulaAuth.Model.Entities;
|
||||
using NebulaAuth.Model.Exceptions;
|
||||
using SteamLib;
|
||||
using SteamLib.Exceptions.Authorization;
|
||||
using SteamLib.Core.Models;
|
||||
using SteamLib.Exceptions;
|
||||
using SteamLib.SteamMobile;
|
||||
|
||||
namespace NebulaAuth.Model;
|
||||
|
||||
//RETHINK
|
||||
public static class Storage
|
||||
{
|
||||
public const string MAFILE_F = "maFiles";
|
||||
public const string REMOVED_F = "maFiles_removed";
|
||||
private static int _duplicateFound;
|
||||
|
||||
public static int DuplicateFound => _duplicateFound;
|
||||
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; private set; } = new();
|
||||
public static ObservableCollection<Mafile> MaFiles { get; } = new();
|
||||
|
||||
static Storage()
|
||||
{
|
||||
}
|
||||
|
||||
public static async Task Initialize(int threadCount, CancellationToken token = default)
|
||||
{
|
||||
if (!Directory.Exists(MafileFolder))
|
||||
Directory.CreateDirectory(MafileFolder);
|
||||
|
||||
if (!Directory.Exists(RemovedMafileFolder))
|
||||
Directory.CreateDirectory(RemovedMafileFolder);
|
||||
var comparer = new MafileNameComparer(Settings.Instance.UseAccountNameAsMafileName);
|
||||
var files = Directory
|
||||
.GetFiles(MafileFolder)
|
||||
.Where(file => Path.GetExtension(file).EqualsIgnoreCase(".mafile"))
|
||||
.Order(comparer)
|
||||
.ToList();
|
||||
|
||||
|
||||
var hashNames = new ConcurrentDictionary<string, byte>();
|
||||
var hashIds = new ConcurrentDictionary<SteamId, byte>();
|
||||
var localList = new ConcurrentBag<Mafile>();
|
||||
|
||||
var processed = 0;
|
||||
|
||||
await Task.Run(() =>
|
||||
if (Directory.Exists(MafileFolder) == false)
|
||||
{
|
||||
return Parallel.ForEachAsync(files,
|
||||
new ParallelOptions {CancellationToken = token, MaxDegreeOfParallelism = threadCount},
|
||||
async (file, ct) =>
|
||||
Directory.CreateDirectory(MafileFolder);
|
||||
}
|
||||
|
||||
if (Directory.Exists(RemovedMafileFolder) == false)
|
||||
{
|
||||
Directory.CreateDirectory(RemovedMafileFolder);
|
||||
}
|
||||
|
||||
var files = Directory.GetFiles(MafileFolder);
|
||||
var hashNames = new HashSet<string>();
|
||||
var hashIds = new HashSet<SteamId>();
|
||||
var comparer = new MafileNameComparer(Settings.Instance.UseAccountNameAsMafileName);
|
||||
var ordered = files.Order(comparer).ToList();
|
||||
foreach (var file in ordered.Where(file => Path.GetExtension(file).EqualsIgnoreCase(".mafile")))
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadMafile(file);
|
||||
|
||||
if (hashNames.Contains(data.AccountName) || hashIds.Contains(data.SteamId))
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = await ReadMafileAsync(file);
|
||||
DuplicateFound++;
|
||||
Shell.Logger.Error("Duplicate mafile {file}", Path.GetFileName(file));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hashNames.TryAdd(data.AccountName, 0) ||
|
||||
(data.SessionData != null && !hashIds.TryAdd(data.SteamId, 0)))
|
||||
{
|
||||
Interlocked.Increment(ref _duplicateFound);
|
||||
Shell.Logger.Error("Duplicate mafile {file}", Path.GetFileName(file));
|
||||
}
|
||||
hashNames.Add(data.AccountName);
|
||||
if (data.SessionData != null) hashIds.Add(data.SteamId);
|
||||
MaFiles.Add(data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Shell.Logger.Error(ex, "Can't load mafile {file}", Path.GetFileName(file));
|
||||
}
|
||||
}
|
||||
|
||||
localList.Add(data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Shell.Logger.Error(ex, "Can't load mafile {file}", Path.GetFileName(file));
|
||||
}
|
||||
});
|
||||
}, token);
|
||||
|
||||
MaFiles = new ObservableCollection<Mafile>(localList.OrderBy(m => m.AccountName));
|
||||
MaFiles = new ObservableCollection<Mafile>(MaFiles.OrderBy(m => m.AccountName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -130,12 +117,6 @@ public static class Storage
|
||||
return NebulaSerializer.Deserialize(str);
|
||||
}
|
||||
|
||||
public static async Task<Mafile> ReadMafileAsync(string path)
|
||||
{
|
||||
var str = await File.ReadAllTextAsync(path);
|
||||
return NebulaSerializer.Deserialize(str);
|
||||
}
|
||||
|
||||
public static void SaveMafile(Mafile data)
|
||||
{
|
||||
var path = CreatePathForMafile(data);
|
||||
@@ -221,35 +202,9 @@ public static class Storage
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void BackupHandler(MobileDataExtended data)
|
||||
{
|
||||
if (Directory.Exists("mafiles_backup") == false)
|
||||
{
|
||||
Directory.CreateDirectory("mafiles_backup");
|
||||
}
|
||||
|
||||
|
||||
var json = NebulaSerializer.SerializeMafile(data, null);
|
||||
File.WriteAllText(Path.Combine("mafiles_backup", data.AccountName + ".mafile"),
|
||||
json);
|
||||
}
|
||||
|
||||
public static void BackupHandlerStr(string accountName, string data)
|
||||
{
|
||||
if (Directory.Exists("mafiles_backup") == false)
|
||||
{
|
||||
Directory.CreateDirectory("mafiles_backup");
|
||||
}
|
||||
|
||||
|
||||
File.WriteAllText(Path.Combine("mafiles_backup", accountName + ".mafile"),
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Refactor
|
||||
//TODO: use numeric orderer when .net 10 released
|
||||
internal class MafileNameComparer : IComparer<string>
|
||||
{
|
||||
private const string MAF_64_START = "765";
|
||||
@@ -16,6 +16,7 @@
|
||||
</layout>
|
||||
<layout type='SimpleLayout' text="," />
|
||||
</layout>
|
||||
|
||||
</target>
|
||||
</targets>
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<SatelliteResourceLanguages>en;ru;ua</SatelliteResourceLanguages>
|
||||
<ApplicationIcon>Theme\lock.ico</ApplicationIcon>
|
||||
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
||||
<AssemblyVersion>1.5.7</AssemblyVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Theme\1140x641.jpg" />
|
||||
<None Remove="Theme\Background.jpg" />
|
||||
<None Remove="Theme\lock.ico" />
|
||||
<None Remove="Theme\SplashScreen.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autoupdater.NET.Official" Version="1.9.2" />
|
||||
<PackageReference Include="CodingSeb.Localization.JsonFileLoader" Version="1.3.1" />
|
||||
<PackageReference Include="CodingSeb.Localization.WPF" Version="1.3.3" />
|
||||
<PackageReference Include="CodingSebLocalization.Fody" Version="1.3.1" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
|
||||
<PackageReference Include="MaterialDesignColors" Version="2.1.4" />
|
||||
<PackageReference Include="MaterialDesignThemes" Version="4.9.0" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.122" />
|
||||
<PackageReference Include="NLog" Version="5.3.4" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.14" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Theme\Background.jpg">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
<Resource Include="Theme\lock.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SteamLibForked\SteamLibForked.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SplashScreen Include="Theme\SplashScreen.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="View\Dialogs\LoginAgainOnImportDialog.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="NLog.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="localization.loc.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -6,8 +6,4 @@
|
||||
• Добавить запоминание пароля при привязке мафайла
|
||||
• Функция переноса гуарда с мобильного устройства на ПК с созданием мафайла
|
||||
• Добавить полное шифрование мафайлов по аналогии с SDA
|
||||
• Сделать автоматический билд и загрузку обновления на Github при изменении в мастер ветке
|
||||
• Антик-окно как в MarketApp, возможность сразу открыть браузер напр. на CefSharp с залогиненым аккаунтом
|
||||
• Стабильность авто-подтверждений, возможность задать пользователю порог времени когда льются ошибки и только тогда выключать авто-подтверждение
|
||||
• Безопасное сохранение мафайлов через .tmp / .bak
|
||||
• Создание механизма накопления ошибок, чтобы исправить Patch Tuesday, условно аккаунт может игнорировать ошибки 1-2 часа (настриавемо)
|
||||
• Сделать автоматический билд и загрузку обновления на Github при изменении в мастер ветке
|
||||
|
Before Width: | Height: | Size: 713 KiB After Width: | Height: | Size: 713 KiB |
@@ -0,0 +1,9 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<!--Card-->
|
||||
<SolidColorBrush x:Key="MaterialDesignCardBackground" Color="#26292E" />
|
||||
<SolidColorBrush x:Key="PrimaryHueMidBrush" Color="#FF9056B1" />
|
||||
<SolidColorBrush x:Key="PrimaryHueLightBrush" Color="#FF9C70B5" />
|
||||
<SolidColorBrush x:Key="PrimaryHueDarkForegroundBrush" Color="#FF851BC1" />
|
||||
</ResourceDictionary>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 365 KiB |
+4
-6
@@ -17,8 +17,7 @@
|
||||
Margin="{x:Static local:WindowChromeHelper.LayoutOffsetThickness}"
|
||||
BorderBrush="Transparent"
|
||||
BorderThickness="1"
|
||||
Background="{DynamicResource Base200Brush}">
|
||||
|
||||
Background="{DynamicResource WindowBackground}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -27,12 +26,11 @@
|
||||
<Grid x:Name="TitleBar"
|
||||
Grid.Row="0"
|
||||
Height="28"
|
||||
Background="{DynamicResource Base300Brush}">
|
||||
Background="{DynamicResource WindowBackground}">
|
||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource PrimaryContentBrush}"
|
||||
Foreground="{DynamicResource PrimaryHueMidBrush}"
|
||||
Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Title}"
|
||||
FontSize="17" />
|
||||
|
||||
<!-- Window Buttons -->
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
@@ -61,7 +59,7 @@
|
||||
<!-- Main Window Content -->
|
||||
<Grid x:Name="MainGrid"
|
||||
Grid.Row="1"
|
||||
Background="{DynamicResource Base200Brush}">
|
||||
Background="{DynamicResource MainBackgroundBrush}">
|
||||
<AdornerDecorator>
|
||||
<ContentPresenter />
|
||||
</AdornerDecorator>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 490 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 906 KiB |
+6
-5
@@ -1,8 +1,8 @@
|
||||
using CodingSeb.Localization;
|
||||
using NebulaAuth.Core;
|
||||
using SteamLib.Core.StatusCodes;
|
||||
using SteamLib.Exceptions;
|
||||
using SteamLib.Exceptions.Mobile;
|
||||
using SteamLibForked.Exceptions.Authorization;
|
||||
using SteamLib.ProtoCore.Enums;
|
||||
|
||||
namespace NebulaAuth.Utility;
|
||||
|
||||
@@ -14,10 +14,11 @@ public static class ErrorTranslatorHelper
|
||||
return result ?? error.ToString();
|
||||
}
|
||||
|
||||
public static string TranslateSteamStatusCode(SteamStatusCode statusCode)
|
||||
|
||||
public static string TranslateEResult(EResult eResult)
|
||||
{
|
||||
var result = GetMessage("EResult", statusCode.Name);
|
||||
return result ?? statusCode.ToString();
|
||||
var result = GetMessage("EResult", eResult.ToString());
|
||||
return result ?? eResult.ToString();
|
||||
}
|
||||
|
||||
public static string TranslateLinkerError(AuthenticatorLinkerError error)
|
||||
+29
-30
@@ -4,9 +4,8 @@ using System.Threading.Tasks;
|
||||
using NebulaAuth.Core;
|
||||
using NebulaAuth.Model;
|
||||
using SteamLib.Exceptions;
|
||||
using SteamLib.Exceptions.Authorization;
|
||||
using SteamLib.Exceptions.General;
|
||||
using SteamLibForked.Exceptions.Authorization;
|
||||
using SteamLib.ProtoCore.Exceptions;
|
||||
|
||||
namespace NebulaAuth.Utility;
|
||||
|
||||
@@ -17,58 +16,53 @@ public static class ExceptionHandler
|
||||
public static bool Handle(Exception ex, string? prefix = null, string? postfix = null,
|
||||
bool handleAllExceptions = false)
|
||||
{
|
||||
string msg;
|
||||
Shell.Logger.Error(ex);
|
||||
var msg = GetExceptionString(ex, handleAllExceptions);
|
||||
if (msg == null) return false;
|
||||
SnackbarController.SendSnackbar(prefix + msg + postfix);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static string? GetExceptionString(Exception exception, bool handleAllExceptions = true)
|
||||
{
|
||||
switch (exception)
|
||||
switch (ex)
|
||||
{
|
||||
case SessionPermanentlyExpiredException:
|
||||
{
|
||||
return "SessionExpiredException".GetCodeBehindLocalization();
|
||||
msg = "SessionExpiredException".GetCodeBehindLocalization();
|
||||
break;
|
||||
}
|
||||
case SessionInvalidException:
|
||||
{
|
||||
return "SessionExpiredException".GetCodeBehindLocalization();
|
||||
msg = "SessionExpiredException".GetCodeBehindLocalization();
|
||||
break;
|
||||
}
|
||||
case TaskCanceledException e:
|
||||
{
|
||||
return e.InnerException is TimeoutException
|
||||
msg = e.InnerException is TimeoutException
|
||||
? "TimeoutException".GetCodeBehindLocalization()
|
||||
: "TaskCanceledException".GetCodeBehindLocalization();
|
||||
break;
|
||||
}
|
||||
case HttpRequestException e:
|
||||
{
|
||||
var str = "RequestError".GetCommonLocalization() + ": ";
|
||||
|
||||
if (e.StatusCode != null)
|
||||
{
|
||||
str = str + e.StatusCode;
|
||||
msg = str + e.StatusCode;
|
||||
}
|
||||
else if (e.InnerException != null)
|
||||
{
|
||||
str = str + e.InnerException.Message;
|
||||
msg = str + e.InnerException.Message;
|
||||
}
|
||||
else
|
||||
{
|
||||
str = str + e.Message;
|
||||
msg = str + e.Message;
|
||||
}
|
||||
|
||||
return str;
|
||||
break;
|
||||
}
|
||||
case UnsupportedResponseException:
|
||||
{
|
||||
return "UnsupportedResponseException".GetCodeBehindLocalization();
|
||||
msg = "UnsupportedResponseException".GetCodeBehindLocalization();
|
||||
break;
|
||||
}
|
||||
case CantLoadConfirmationsException e:
|
||||
{
|
||||
var msg = LocManager.GetCodeBehindOrDefault(nameof(CantLoadConfirmationsException),
|
||||
msg = LocManager.GetCodeBehindOrDefault(nameof(CantLoadConfirmationsException),
|
||||
EXCEPTION_HANDLER_LOC_PATH, nameof(CantLoadConfirmationsException), "Common");
|
||||
if (e.Error == LoadConfirmationsError.Unknown)
|
||||
{
|
||||
@@ -82,25 +76,30 @@ public static class ExceptionHandler
|
||||
nameof(CantLoadConfirmationsException), e.Error.ToString());
|
||||
}
|
||||
|
||||
return msg;
|
||||
break;
|
||||
}
|
||||
case SteamStatusCodeException e:
|
||||
case EResultException e:
|
||||
{
|
||||
return "Error".GetCommonLocalization() + ": " +
|
||||
ErrorTranslatorHelper.TranslateSteamStatusCode(e.StatusCode);
|
||||
msg = "Error".GetCommonLocalization() + ": " + ErrorTranslatorHelper.TranslateEResult(e.Result);
|
||||
break;
|
||||
}
|
||||
case LoginException e:
|
||||
{
|
||||
return "LoginException".GetCodeBehindLocalization() + ": " +
|
||||
ErrorTranslatorHelper.TranslateLoginError(e.Error);
|
||||
msg = "LoginException".GetCodeBehindLocalization() + ": " +
|
||||
ErrorTranslatorHelper.TranslateLoginError(e.Error);
|
||||
break;
|
||||
}
|
||||
case not null when handleAllExceptions:
|
||||
{
|
||||
return "UnknownException".GetCodeBehindLocalization() + exception.Message;
|
||||
msg = "UnknownException".GetCodeBehindLocalization() + ex.Message;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return null;
|
||||
SnackbarController.SendSnackbar(prefix + msg + postfix);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string GetCommonLocalization(this string key)
|
||||
@@ -0,0 +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: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"
|
||||
theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True"
|
||||
Foreground="WhiteSmoke"
|
||||
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
|
||||
Background="{DynamicResource WindowBackground}">
|
||||
|
||||
<Grid MinHeight="100" MinWidth="300" Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<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>
|
||||
<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 />
|
||||
</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}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,65 @@
|
||||
<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: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"
|
||||
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.RowDefinitions>
|
||||
<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>
|
||||
<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}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
<UIElement.InputBindings>
|
||||
<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}" />
|
||||
<Grid Grid.Row="5" Margin="10,10,10,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<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}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
+9
-30
@@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="NebulaAuth.View.Dialogs.SetCryptPasswordDialog"
|
||||
<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"
|
||||
@@ -7,46 +7,25 @@
|
||||
xmlns:theme="clr-namespace:NebulaAuth.Theme"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance other:LoginAgainVM}">
|
||||
Foreground="WhiteSmoke"
|
||||
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
|
||||
Background="{DynamicResource WindowBackground}">
|
||||
|
||||
|
||||
<Grid MinHeight="100" MinWidth="300" MaxWidth="400">
|
||||
<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" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Margin="10,10,10,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Encryption" Width="20" Height="20" Margin="0,0,5,0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource PrimaryContentBrush}" />
|
||||
<TextBlock FontStyle="Normal" Foreground="{DynamicResource BaseContentBrush}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center" FontSize="18" Text="{Tr SetEncryptedPasswordDialog.Title}" />
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
HorizontalAlignment="Right" CommandParameter="{StaticResource False}"
|
||||
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
|
||||
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
|
||||
|
||||
</Button>
|
||||
</Grid>
|
||||
<Separator Grid.Row="1" Opacity="0.7" />
|
||||
<TextBlock Grid.Row="2" IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal"
|
||||
<TextBlock IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal"
|
||||
Text="{Tr SetEncryptedPasswordDialog.DialogText}" theme:FontScaleWindow.Scale="0.8"
|
||||
theme:FontScaleWindow.ResizeFont="True" Margin="10" HorizontalAlignment="Left" />
|
||||
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="3" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
|
||||
Margin="10" Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
|
||||
materialDesign:HintAssist.Hint="{Tr SetEncryptedPasswordDialog.Password}" />
|
||||
<Grid Grid.Row="4" Margin="10">
|
||||
<Grid Grid.Row="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using SteamLib.Core.Interfaces;
|
||||
using SteamLib.Exceptions;
|
||||
|
||||
namespace NebulaAuth.View.Dialogs;
|
||||
|
||||
/// <summary>
|
||||
/// Логика взаимодействия для WaitLoginDialog.xaml
|
||||
/// </summary>
|
||||
public partial class WaitLoginDialog : ICaptchaResolver
|
||||
{
|
||||
private TaskCompletionSource<string> _tcs = new();
|
||||
|
||||
public WaitLoginDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
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 () =>
|
||||
{
|
||||
var image = await LoadImage(stream);
|
||||
CaptchaImage.Source = image;
|
||||
try
|
||||
{
|
||||
return await _tcs.Task;
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
throw new LoginException(LoginError.CaptchaRequired);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<BitmapImage> LoadImage(Stream stream)
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
await stream.CopyToAsync(ms);
|
||||
ms.Position = 0;
|
||||
|
||||
var image = new BitmapImage();
|
||||
|
||||
image.BeginInit();
|
||||
image.CacheOption = BitmapCacheOption.OnLoad;
|
||||
image.StreamSource = ms;
|
||||
image.EndInit();
|
||||
await stream.DisposeAsync();
|
||||
return image;
|
||||
}
|
||||
|
||||
private void CancelButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_tcs.SetCanceled();
|
||||
}
|
||||
|
||||
private void SendCaptchaBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(CaptchaTB.Text)) return;
|
||||
var oldTcs = _tcs;
|
||||
_tcs = new TaskCompletionSource<string>();
|
||||
oldTcs.SetResult(CaptchaTB.Text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<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: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"
|
||||
Foreground="WhiteSmoke"
|
||||
FontFamily="{materialDesign:MaterialDesignFont}"
|
||||
MinHeight="640"
|
||||
MinWidth="400"
|
||||
Background="{DynamicResource WindowBackground}"
|
||||
d:DataContext="{d:DesignInstance other:LinkAccountVM}"
|
||||
FontSize="18">
|
||||
<d:DesignerProperties.DesignStyle>
|
||||
<Style TargetType="UserControl">
|
||||
<Setter Property="Background" Value="{DynamicResource WindowBackground}" />
|
||||
</Style>
|
||||
</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" />
|
||||
|
||||
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.Resources>
|
||||
<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>
|
||||
<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>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Grid Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<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}">
|
||||
<Run Text="{Tr LinkerDialog.GotErrorHyperlinkText, IsDynamic=False}" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<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>
|
||||
<Separator Background="DarkGray" Grid.Row="1" />
|
||||
<Grid Grid.Row="2" Margin="10,20,10,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<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.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock>
|
||||
<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}" />
|
||||
</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}" />
|
||||
</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}" />
|
||||
</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}" />
|
||||
</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}" />
|
||||
</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}" />
|
||||
</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}" />
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="9" Margin="10,20,10,10">
|
||||
<Grid.RowDefinitions>
|
||||
<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">
|
||||
<GroupBox.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Tr LinkerDialog.Message}" FontSize="16" Foreground="GhostWhite" />
|
||||
</DataTemplate>
|
||||
</GroupBox.HeaderTemplate>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<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">
|
||||
<materialDesign:PackIcon Kind="ContentCopy" />
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
<Button Grid.Row="10" Height="35" FontSize="17" Command="{Binding ProceedCommand}"
|
||||
Content="{Tr LinkerDialog.ProceedButton}" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -7,12 +7,13 @@
|
||||
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="500" d:DesignWidth="400"
|
||||
Foreground="WhiteSmoke"
|
||||
FontFamily="{md:MaterialDesignFont}"
|
||||
MinHeight="500"
|
||||
MinWidth="400"
|
||||
MaxHeight="550"
|
||||
d:DataContext="{d:DesignInstance other:ProxyManagerVM}"
|
||||
Background="Transparent">
|
||||
Background="{DynamicResource WindowBackground}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -21,23 +22,19 @@
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Margin="10,10,10,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<md:PackIcon Kind="Proxy" Width="20" Height="20" Margin="0,0,5,0" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource PrimaryContentBrush}" />
|
||||
<TextBlock FontStyle="Normal" Foreground="{DynamicResource BaseContentBrush}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center" FontSize="18" Text="{Tr ProxyManagerDialog.Title}" />
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
HorizontalAlignment="Right" Command="{x:Static md:DialogHost.CloseDialogCommand}"
|
||||
IsCancel="True">
|
||||
<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>
|
||||
|
||||
</Grid>
|
||||
<Separator Grid.Row="1" />
|
||||
<Grid Grid.Row="2">
|
||||
@@ -0,0 +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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
||||
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 />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<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}">
|
||||
<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}" />
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<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>
|
||||
</Grid>
|
||||
<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}">
|
||||
<TextBlock TextWrapping="WrapWithOverflow" Text="{Tr SettingsDialog.UseAccountName}" />
|
||||
</CheckBox>
|
||||
<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>
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace NebulaAuth.View;
|
||||
|
||||
/// <summary>
|
||||
/// Логика взаимодействия для SettingsView.xaml
|
||||
/// </summary>
|
||||
public partial class SettingsView
|
||||
{
|
||||
public SettingsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,9 @@ using NebulaAuth.Core;
|
||||
using NebulaAuth.Model;
|
||||
using NebulaAuth.Model.Entities;
|
||||
using NebulaAuth.Utility;
|
||||
using NebulaAuth.View;
|
||||
using NebulaAuth.View.Dialogs;
|
||||
using SteamLib.Exceptions;
|
||||
using SteamLib.SteamMobile;
|
||||
using SteamLibForked.Exceptions.Authorization;
|
||||
|
||||
namespace NebulaAuth.ViewModel;
|
||||
|
||||
@@ -30,12 +29,12 @@ public partial class MainVM : ObservableObject
|
||||
}
|
||||
|
||||
public bool IsMafileSelected => SelectedMafile != null;
|
||||
public DialogHost CurrentDialogHost { get; set; } = null!;
|
||||
|
||||
[ObservableProperty] private ObservableCollection<Mafile> _maFiles = Storage.MaFiles;
|
||||
|
||||
private Mafile? _selectedMafile;
|
||||
|
||||
|
||||
public MainVM()
|
||||
{
|
||||
CreateCodeTimer();
|
||||
@@ -52,12 +51,6 @@ public partial class MainVM : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task Debug()
|
||||
{
|
||||
Shell.Logger.Info("test");
|
||||
}
|
||||
|
||||
|
||||
private void SetMafile(Mafile? mafile)
|
||||
{
|
||||
@@ -97,7 +90,7 @@ public partial class MainVM : ObservableObject
|
||||
var wait = DialogHost.Show(waitDialog);
|
||||
try
|
||||
{
|
||||
await MaClient.LoginAgain(SelectedMafile, password, loginAgainVm.SavePassword);
|
||||
await MaClient.LoginAgain(SelectedMafile, password, loginAgainVm.SavePassword, waitDialog);
|
||||
SnackbarController.SendSnackbar(GetLocalization("SuccessfulLogin"));
|
||||
}
|
||||
catch (LoginException ex)
|
||||
@@ -144,12 +137,6 @@ public partial class MainVM : ObservableObject
|
||||
await DialogsController.ShowLinkerDialog();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task MoveAccount()
|
||||
{
|
||||
await DialogsController.ShowMafileMoverDialog();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task RemoveAuthenticator()
|
||||
{
|
||||
@@ -222,15 +209,6 @@ public partial class MainVM : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task OpenLinksView()
|
||||
{
|
||||
CurrentDialogHost.CloseOnClickAway = true;
|
||||
var view = new LinksView();
|
||||
await DialogHost.Show(view);
|
||||
CurrentDialogHost.CloseOnClickAway = false;
|
||||
}
|
||||
|
||||
|
||||
private static string GetLocalization(string key)
|
||||
{
|
||||
@@ -22,36 +22,32 @@ public partial class MainVM
|
||||
[MemberNotNull(nameof(_codeTimer))]
|
||||
private void CreateCodeTimer()
|
||||
{
|
||||
CodeProgress = CalculateCodeProgress();
|
||||
_codeTimer = new Timer(UpdateCode, null, 0, 1000);
|
||||
}
|
||||
|
||||
|
||||
private void UpdateCode(object? state = null)
|
||||
{
|
||||
var currentTime = TimeAligner.GetSteamTime();
|
||||
var untilChange = currentTime % 30;
|
||||
if (untilChange != 0) return;
|
||||
var codeProgress = untilChange / 30D * 100;
|
||||
|
||||
string? code = null;
|
||||
if (untilChange == 0 && SelectedMafile != null)
|
||||
{
|
||||
code = SteamGuardCodeGenerator.GenerateCode(SelectedMafile!.SharedSecret);
|
||||
}
|
||||
|
||||
|
||||
if (Application.Current == null) return;
|
||||
Application.Current.Dispatcher.BeginInvoke(() =>
|
||||
Application.Current.Dispatcher.BeginInvoke((string? c) =>
|
||||
{
|
||||
CodeProgress = -1;
|
||||
CodeProgress = 30;
|
||||
if (Application.Current.MainWindow?.WindowState == WindowState.Minimized) return;
|
||||
if (SelectedMafile == null) return;
|
||||
Code = SteamGuardCodeGenerator.GenerateCode(SelectedMafile.SharedSecret);
|
||||
}, DispatcherPriority.Normal);
|
||||
CodeProgress = codeProgress;
|
||||
if (c != null) Code = c;
|
||||
}, DispatcherPriority.DataBind, code);
|
||||
}
|
||||
|
||||
|
||||
private long CalculateCodeProgress()
|
||||
{
|
||||
var currentTime = TimeAligner.GetSteamTime();
|
||||
var untilChange = currentTime % 30;
|
||||
return 30 - untilChange;
|
||||
}
|
||||
|
||||
|
||||
[RelayCommand(AllowConcurrentExecutions = false)]
|
||||
private async Task CopyCode()
|
||||
{
|
||||
@@ -17,7 +17,7 @@ using NebulaAuth.Utility;
|
||||
using NebulaAuth.View;
|
||||
using NebulaAuth.View.Dialogs;
|
||||
using NebulaAuth.ViewModel.Other;
|
||||
using SteamLibForked.Exceptions.Authorization;
|
||||
using SteamLib.Exceptions;
|
||||
|
||||
namespace NebulaAuth.ViewModel;
|
||||
|
||||
@@ -160,7 +160,7 @@ public partial class MainVM //File //TODO: Refactor
|
||||
var wait = DialogHost.Show(waitDialog);
|
||||
try
|
||||
{
|
||||
await MaClient.LoginAgain(data, password, loginAgainVm.SavePassword);
|
||||
await MaClient.LoginAgain(data, password, loginAgainVm.SavePassword, waitDialog);
|
||||
SnackbarController.SendSnackbar(GetLocalization("SuccessfulLogin"));
|
||||
}
|
||||
catch (LoginException ex)
|
||||
@@ -217,7 +217,7 @@ public partial class MainVM //File //TODO: Refactor
|
||||
private async Task OpenSettingsDialog()
|
||||
{
|
||||
var vm = new SettingsVM();
|
||||
var view = new SettingsView(CurrentDialogHost)
|
||||
var view = new SettingsView
|
||||
{
|
||||
DataContext = vm
|
||||
};
|
||||
@@ -37,7 +37,6 @@ public partial class MainVM
|
||||
}
|
||||
|
||||
if (!system && SelectedMafile != null)
|
||||
|
||||
{
|
||||
SelectedMafile.Proxy = SelectedProxy;
|
||||
Storage.UpdateMafile(SelectedMafile);
|
||||
@@ -0,0 +1,457 @@
|
||||
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;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using NebulaAuth.Core;
|
||||
using NebulaAuth.Model;
|
||||
using NebulaAuth.Model.Entities;
|
||||
using NebulaAuth.Utility;
|
||||
using NLog;
|
||||
using SteamLib;
|
||||
using SteamLib.Account;
|
||||
using SteamLib.Authentication;
|
||||
using SteamLib.Authentication.LoginV2;
|
||||
using SteamLib.Core.Interfaces;
|
||||
using SteamLib.Exceptions;
|
||||
using SteamLib.Exceptions.Mobile;
|
||||
using SteamLib.ProtoCore.Exceptions;
|
||||
using SteamLib.SteamMobile.AuthenticatorLinker;
|
||||
using SteamLib.Web;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
|
||||
namespace NebulaAuth.ViewModel.Other;
|
||||
|
||||
public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNumberProvider, ISmsCodeProvider
|
||||
{
|
||||
private const string LOCALIZATION_KEY = "LinkVM";
|
||||
private static Logger Logger => Shell.Logger;
|
||||
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()
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
{
|
||||
if (MaClient.DefaultProxy != null)
|
||||
{
|
||||
var def = Proxies.FirstOrDefault(p => p.Value.Equals(MaClient.DefaultProxy));
|
||||
if (def.Value != null!)
|
||||
{
|
||||
SelectedProxy = def;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand(AllowConcurrentExecutions = true, CanExecute = nameof(CanProceed))]
|
||||
public async Task Proceed()
|
||||
{
|
||||
if (IsCompleted)
|
||||
DialogHost.Close(null);
|
||||
|
||||
CanProceed = false;
|
||||
|
||||
#region Login
|
||||
|
||||
if (IsLogin == false)
|
||||
{
|
||||
SetProxy();
|
||||
ClearCookies();
|
||||
_loginV2ExecutorOptions = new LoginV2ExecutorOptions(LoginV2Executor.NullConsumer, Client)
|
||||
{
|
||||
DeviceDetails = LoginV2ExecutorOptions.GetMobileDefaultDevice(),
|
||||
WebsiteId = "Mobile",
|
||||
EmailAuthProvider = this,
|
||||
Logger = Logger2
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
IsLogin = true;
|
||||
var userName = FieldText;
|
||||
var pass = PassFieldText;
|
||||
_password = pass;
|
||||
FieldText = string.Empty;
|
||||
IsFieldVisible = false;
|
||||
HintText = string.Empty;
|
||||
_sessionData =
|
||||
(MobileSessionData) await LoginV2Executor.DoLogin(_loginV2ExecutorOptions, userName, pass);
|
||||
Handler.CookieContainer.SetSteamMobileCookiesWithMobileToken(_sessionData);
|
||||
IsEmailCode = true;
|
||||
}
|
||||
catch (EResultException ex)
|
||||
{
|
||||
Logger.Error(ex, "Link exception on login");
|
||||
HintText = GetLocalizationOrDefault("CantLogin") + ErrorTranslatorHelper.TranslateEResult(ex.Result);
|
||||
InvokeOnDispatcher(ResetState);
|
||||
return;
|
||||
}
|
||||
catch (LoginException ex)
|
||||
{
|
||||
Logger.Error(ex, "Link exception on login");
|
||||
HintText = GetLocalizationOrDefault("CantLogin") + ErrorTranslatorHelper.TranslateLoginError(ex.Error);
|
||||
InvokeOnDispatcher(ResetState);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex, "Link exception on login");
|
||||
HintText = GetLocalizationOrDefault("CantLogin") + ex.Message;
|
||||
InvokeOnDispatcher(ResetState);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsEmailCode == false)
|
||||
{
|
||||
_emailCodeTcs.SetResult(FieldText);
|
||||
HintText = string.Empty;
|
||||
FieldText = string.Empty;
|
||||
_emailCodeTcs = new TaskCompletionSource<string>();
|
||||
IsFieldVisible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
if (_isLinkStarted)
|
||||
goto linkStarted;
|
||||
|
||||
try
|
||||
{
|
||||
_isLinkStarted = true;
|
||||
var linkOptions = new LinkOptions(Client, LoginV2Executor.NullConsumer, this,
|
||||
null, this, this, Backup, Logger2);
|
||||
_linker = new SteamAuthenticatorLinker(linkOptions);
|
||||
var result = await _linker.LinkAccount(_sessionData);
|
||||
IsLinkCode = true;
|
||||
IsCompleted = true;
|
||||
var mafile = Mafile.FromMobileDataExtended(result);
|
||||
try
|
||||
{
|
||||
if (SelectedProxy.HasValue)
|
||||
mafile.Proxy = new MaProxy(SelectedProxy.Value.Key, SelectedProxy.Value.Value);
|
||||
if (Settings.Instance.IsPasswordSet)
|
||||
mafile.Password = PHandler.Encrypt(_password);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex, "Error during saving Nebula data to mafile");
|
||||
}
|
||||
|
||||
Storage.SaveMafile(mafile);
|
||||
File.Delete(Path.Combine("mafiles_backup", mafile.AccountName + ".mafile"));
|
||||
HintText =
|
||||
string.Format(GetLocalizationOrDefault("MafileLinked"),
|
||||
mafile.RevocationCode,
|
||||
mafile.SessionData?.SteamId.Steam64);
|
||||
|
||||
_rCode = mafile.RevocationCode ?? string.Empty;
|
||||
CanProceed = true;
|
||||
return;
|
||||
}
|
||||
catch (AuthenticatorLinkerException ex)
|
||||
{
|
||||
Logger.Error(ex, "Link exception");
|
||||
HintText = $"{GetLocalizationCommon("Error")}: {ErrorTranslatorHelper.TranslateLinkerError(ex.Error)}";
|
||||
InvokeOnDispatcher(ResetState);
|
||||
return;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
var msg = ex.StatusCode?.ToString() ?? ex.Message;
|
||||
HintText = $"{GetLocalizationCommon("RequestError")}: {msg}";
|
||||
InvokeOnDispatcher(ResetState);
|
||||
return;
|
||||
}
|
||||
catch (EResultException ex)
|
||||
{
|
||||
Logger.Error(ex, "Link exception");
|
||||
HintText = GetLocalizationOrDefault("ErrorWithCode") + ErrorTranslatorHelper.TranslateEResult(ex.Result);
|
||||
InvokeOnDispatcher(ResetState);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex, "Link exception");
|
||||
HintText = GetLocalizationOrDefault("UnknownError") + ex.Message;
|
||||
InvokeOnDispatcher(ResetState);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
linkStarted:
|
||||
if (IsPhoneNumber == false)
|
||||
{
|
||||
var phoneText = FieldText;
|
||||
FieldText = string.Empty;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(phoneText))
|
||||
{
|
||||
HintText = string.Empty;
|
||||
IsFieldVisible = false;
|
||||
_phoneNumberTcs.SetResult(null);
|
||||
_phoneNumberTcs = new TaskCompletionSource<long?>();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(phoneText) && phoneText.Length >= 4 &&
|
||||
long.TryParse(phoneText, out var phone))
|
||||
{
|
||||
HintText = string.Empty;
|
||||
IsFieldVisible = false;
|
||||
_phoneNumberTcs.SetResult(phone);
|
||||
_phoneNumberTcs = new TaskCompletionSource<long?>();
|
||||
return;
|
||||
}
|
||||
|
||||
HintText = GetLocalizationOrDefault("PleaseEnterCorrectPhone");
|
||||
CanProceed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsEmailConfirmation == false)
|
||||
{
|
||||
HintText = string.Empty;
|
||||
_emailConfTcs.SetResult();
|
||||
_emailConfTcs = new TaskCompletionSource();
|
||||
CanProceed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsLinkCode == false)
|
||||
{
|
||||
var linkCode = FieldText;
|
||||
FieldText = string.Empty;
|
||||
if (!string.IsNullOrWhiteSpace(linkCode) && linkCode.Length >= 4)
|
||||
{
|
||||
HintText = string.Empty;
|
||||
IsFieldVisible = false;
|
||||
_linkCodeTcs.SetResult(linkCode);
|
||||
_linkCodeTcs = new TaskCompletionSource<string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
HintText = GetLocalizationOrDefault("PleaseEnterCorrectCode");
|
||||
CanProceed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void ResetProxy()
|
||||
{
|
||||
if (IsPasswordFieldVisible == false) return;
|
||||
SelectedProxy = null;
|
||||
}
|
||||
|
||||
private void InvokeOnDispatcher(Action action)
|
||||
{
|
||||
Application.Current.Dispatcher.BeginInvoke(action, null);
|
||||
}
|
||||
|
||||
private void ResetState()
|
||||
{
|
||||
PassFieldText = string.Empty;
|
||||
IsLogin = false;
|
||||
IsFieldVisible = true;
|
||||
IsEmailCode = false;
|
||||
_isLinkStarted = false;
|
||||
IsPhoneNumber = false;
|
||||
IsEmailConfirmation = false;
|
||||
CanProceed = true;
|
||||
_emailCodeTcs = new TaskCompletionSource<string>();
|
||||
_rCode = string.Empty;
|
||||
_password = string.Empty;
|
||||
}
|
||||
|
||||
private void Backup(MobileDataExtended data)
|
||||
{
|
||||
if (Directory.Exists("mafiles_backup") == false)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
[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;
|
||||
HintText = GetLocalizationOrDefault("EnterEmailCode");
|
||||
IsFieldVisible = true;
|
||||
return _emailCodeTcs.Task;
|
||||
}
|
||||
|
||||
public Task<string> GetAddAuthenticatorCode(ILoginConsumer caller)
|
||||
{
|
||||
IsPhoneNumber = true;
|
||||
IsEmailConfirmation = true;
|
||||
CanProceed = true;
|
||||
HintText = GetLocalizationOrDefault("EnterEmailCode");
|
||||
IsFieldVisible = true;
|
||||
return _linkCodeTcs.Task;
|
||||
}
|
||||
|
||||
public Task ConfirmEmailLink(ILoginConsumer caller, EmailConfirmationType confirmationType)
|
||||
{
|
||||
IsPhoneNumber = true;
|
||||
CanProceed = true;
|
||||
HintText = GetLocalizationOrDefault("ClickOnEmailLink");
|
||||
return _emailConfTcs.Task;
|
||||
}
|
||||
|
||||
public Task<long?> GetPhoneNumber(ILoginConsumer caller)
|
||||
{
|
||||
CanProceed = true;
|
||||
HintText = GetLocalizationOrDefault("EnterPhoneNumber");
|
||||
IsFieldVisible = true;
|
||||
return _phoneNumberTcs.Task;
|
||||
}
|
||||
|
||||
public async Task<int> GetSmsCode(ILoginConsumer caller, long? phoneNumber, string? hint)
|
||||
{
|
||||
IsPhoneNumber = true;
|
||||
IsEmailConfirmation = true;
|
||||
CanProceed = true;
|
||||
HintText = string.Format(GetLocalizationOrDefault("PhoneHint"), hint);
|
||||
IsFieldVisible = true;
|
||||
var code = await _linkCodeTcs.Task;
|
||||
return int.Parse(code);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Client
|
||||
|
||||
static LinkAccountVM()
|
||||
{
|
||||
Proxy = new DynamicProxy();
|
||||
var clientPair = ClientBuilder.BuildMobileClient(Proxy, null);
|
||||
Client = clientPair.Client;
|
||||
Handler = clientPair.Handler;
|
||||
}
|
||||
|
||||
private void ClearCookies()
|
||||
{
|
||||
Handler.CookieContainer.ClearMobileSessionCookies();
|
||||
}
|
||||
|
||||
private void SetProxy()
|
||||
{
|
||||
Proxy.SetData(SelectedProxy?.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+26
-74
@@ -11,6 +11,11 @@ public partial class SettingsVM : ObservableObject
|
||||
{
|
||||
public Settings Settings => Settings.Instance;
|
||||
|
||||
public BackgroundMode BackgroundMode
|
||||
{
|
||||
get => Settings.BackgroundMode;
|
||||
set => Settings.BackgroundMode = value;
|
||||
}
|
||||
|
||||
public bool HideToTray
|
||||
{
|
||||
@@ -25,15 +30,6 @@ public partial class SettingsVM : ObservableObject
|
||||
{BackgroundMode.Color, LocManager.GetOrDefault("Default", "SettingsDialog", "BackgroundMode", "NoBackground")}
|
||||
};
|
||||
|
||||
public Dictionary<ThemeType, string> ThemeTypes => new()
|
||||
{
|
||||
{ThemeType.Default, "Default"},
|
||||
{ThemeType.Black, "Black"},
|
||||
{ThemeType.Light, "Light"},
|
||||
{ThemeType.Luxury, "Luxury"},
|
||||
{ThemeType.Shadcn, "Shadcn"}
|
||||
};
|
||||
|
||||
public Dictionary<LocalizationLanguage, string> Languages { get; } = new()
|
||||
{
|
||||
{LocalizationLanguage.English, "English"},
|
||||
@@ -41,6 +37,12 @@ public partial class SettingsVM : ObservableObject
|
||||
{LocalizationLanguage.Ukrainian, "Українська"}
|
||||
};
|
||||
|
||||
public Color? BackgroundColor
|
||||
{
|
||||
get => Settings.BackgroundColor;
|
||||
set => Settings.BackgroundColor = value;
|
||||
}
|
||||
|
||||
public Color? IconColor
|
||||
{
|
||||
get => Settings.IconColor;
|
||||
@@ -62,6 +64,21 @@ public partial class SettingsVM : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
public bool UseBackground
|
||||
{
|
||||
get => BackgroundColor != null;
|
||||
set
|
||||
{
|
||||
if (value == false)
|
||||
BackgroundColor = null;
|
||||
else
|
||||
BackgroundColor = Color.FromRgb(202, 39, 39);
|
||||
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(BackgroundColor));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public LocalizationLanguage Language
|
||||
{
|
||||
@@ -105,69 +122,4 @@ public partial class SettingsVM : ObservableObject
|
||||
{
|
||||
Settings.IsPasswordSet = PHandler.SetPassword(Password);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ResetThemeDefaults()
|
||||
{
|
||||
Settings.ResetThemeDefaults();
|
||||
OnPropertyChanged(nameof(BackgroundBlur));
|
||||
OnPropertyChanged(nameof(BackgroundOpacity));
|
||||
OnPropertyChanged(nameof(BackgroundGamma));
|
||||
OnPropertyChanged(nameof(LeftOpacity));
|
||||
OnPropertyChanged(nameof(RightOpacity));
|
||||
OnPropertyChanged(nameof(ApplyBlurBackground));
|
||||
}
|
||||
|
||||
|
||||
#region Theme
|
||||
|
||||
public BackgroundMode BackgroundMode
|
||||
{
|
||||
get => Settings.BackgroundMode;
|
||||
set => Settings.BackgroundMode = value;
|
||||
}
|
||||
|
||||
public double BackgroundBlur
|
||||
{
|
||||
get => Settings.BackgroundBlur;
|
||||
set => Settings.BackgroundBlur = value;
|
||||
}
|
||||
|
||||
public double BackgroundOpacity
|
||||
{
|
||||
get => Settings.BackgroundOpacity;
|
||||
set => Settings.BackgroundOpacity = value;
|
||||
}
|
||||
|
||||
public double BackgroundGamma
|
||||
{
|
||||
get => Settings.BackgroundGamma;
|
||||
set => Settings.BackgroundGamma = value;
|
||||
}
|
||||
|
||||
public double LeftOpacity
|
||||
{
|
||||
get => Settings.LeftOpacity;
|
||||
set => Settings.LeftOpacity = value;
|
||||
}
|
||||
|
||||
public double RightOpacity
|
||||
{
|
||||
get => Settings.RightOpacity;
|
||||
set => Settings.RightOpacity = value;
|
||||
}
|
||||
|
||||
public bool ApplyBlurBackground
|
||||
{
|
||||
get => Settings.ApplyBlurBackground;
|
||||
set => Settings.ApplyBlurBackground = value;
|
||||
}
|
||||
|
||||
public ThemeType ThemeType
|
||||
{
|
||||
get => Settings.ThemeType;
|
||||
set => Settings.ThemeType = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -68,6 +68,14 @@
|
||||
"en": "Loading...",
|
||||
"ru": "Загрузка...",
|
||||
"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. Через меню \"Файл\" - \"Імпорт\""
|
||||
}
|
||||
},
|
||||
"Menu": {
|
||||
@@ -109,11 +117,6 @@
|
||||
"ru": "Привязать",
|
||||
"ua": "Прив'язати"
|
||||
},
|
||||
"MoveSteamGuard": {
|
||||
"en": "Move Steam Guard",
|
||||
"ru": "Перенести Steam Guard",
|
||||
"ua": "Перенести Steam Guard"
|
||||
},
|
||||
"Unlink": {
|
||||
"en": "Unlink",
|
||||
"ru": "Отвязать",
|
||||
@@ -204,11 +207,6 @@
|
||||
"en": "Search",
|
||||
"ru": "Поиск",
|
||||
"ua": "Пошук"
|
||||
},
|
||||
"NoMafiles": {
|
||||
"en": "No mafiles found..",
|
||||
"ru": "Мафайлы не найдены..",
|
||||
"ua": "Мафайли не знайдено.."
|
||||
}
|
||||
},
|
||||
"RightPart": {
|
||||
@@ -315,58 +313,6 @@
|
||||
"ru": "Настройки",
|
||||
"ua": "Налаштування"
|
||||
},
|
||||
"MainSettings": {
|
||||
"en": "Main",
|
||||
"ru": "Основные",
|
||||
"ua": "Основні"
|
||||
},
|
||||
"ThemeSettings": {
|
||||
"en": "Theme",
|
||||
"ru": "Тема",
|
||||
"ua": "Тема"
|
||||
},
|
||||
"Theme": {
|
||||
"BackgroundBlur": {
|
||||
"en": "Background Blur",
|
||||
"ru": "Размытие фона",
|
||||
"ua": "Розмиття фону"
|
||||
},
|
||||
"BackgroundOpacity": {
|
||||
"en": "Background Opacity",
|
||||
"ru": "Непрозрачность фона",
|
||||
"ua": "Непрозорість фону"
|
||||
},
|
||||
"Gamma": {
|
||||
"en": "Gamma",
|
||||
"ru": "Гамма",
|
||||
"ua": "Гама"
|
||||
},
|
||||
"LeftOpacity": {
|
||||
"en": "Left Opacity",
|
||||
"ru": "Непрозрачность слева",
|
||||
"ua": "Непрозорість зліва"
|
||||
},
|
||||
"RightOpacity": {
|
||||
"en": "Right Opacity",
|
||||
"ru": "Непрозрачность справа",
|
||||
"ua": "Непрозорість справа"
|
||||
},
|
||||
"CurrentTheme": {
|
||||
"en": "Current Theme",
|
||||
"ru": "Текущая тема",
|
||||
"ua": "Поточна тема"
|
||||
},
|
||||
"DialogBlur": {
|
||||
"en": "Blur on Dialog",
|
||||
"ru": "Размытие при открытии диалог. окна",
|
||||
"ua": "Розмиття при відкритті діалог. вікна"
|
||||
},
|
||||
"Reset": {
|
||||
"en": "Reset",
|
||||
"ru": "Сбросить",
|
||||
"ua": "Скинути"
|
||||
}
|
||||
},
|
||||
"BackgroundHint": {
|
||||
"en": "Background",
|
||||
"ru": "Фон",
|
||||
@@ -422,15 +368,14 @@
|
||||
}
|
||||
},
|
||||
"LegacyMafileMode": {
|
||||
"en": "Common mafiles format",
|
||||
"ru": "Общепринятый формат мафайлов",
|
||||
"ua": "Загальноприйнятий формат мафайлів"
|
||||
"en": "Legacy mafile mode",
|
||||
"ru": "Режим старых мафайлов",
|
||||
"ua": "Режим старих мафайлів"
|
||||
},
|
||||
"LegacyMafileModeHint": {
|
||||
"en": "Save mafiles in compatibility format with Steam Desktop Authenticator and other applications",
|
||||
"ru":
|
||||
"Сохранять мафайлы в старом формате для совместимости со Steam Desktop Authenticator и другими приложениями",
|
||||
"ua": "Зберігати мафайли у старому форматі для сумісності зі Steam Desktop Authenticator та іншими додатками"
|
||||
"en": "Use old mafile format for compatibility with old versions of Steam Desktop Authenticator",
|
||||
"ru": "Использовать старый формат мафайлов для совместимости со старыми версиями Steam Desktop Authenticator",
|
||||
"ua": "Використовувати старий формат мафайлів для сумісності зі старими версіями Steam Desktop Authenticator"
|
||||
},
|
||||
"AllowAutoUpdate": {
|
||||
"en": "Allow auto update",
|
||||
@@ -542,8 +487,8 @@
|
||||
},
|
||||
"Authorization": {
|
||||
"en": "Authorization",
|
||||
"ru": "Вход в аккаунт",
|
||||
"ua": "Вхід в акаунт"
|
||||
"ru": "Авторизация",
|
||||
"ua": "Авторизація"
|
||||
},
|
||||
"EmailCode": {
|
||||
"en": "Email code",
|
||||
@@ -579,54 +524,9 @@
|
||||
"en": "Proceed",
|
||||
"ru": "Продолжить",
|
||||
"ua": "Продовжити"
|
||||
},
|
||||
"CancelButton": {
|
||||
"en": "Cancel",
|
||||
"ru": "Отмена",
|
||||
"ua": "Відміна"
|
||||
},
|
||||
"MafileLinked": {
|
||||
"en": "Mafile successfully linked",
|
||||
"ru": "Мафайл успешно привязан",
|
||||
"ua": "Мафайл успішно прив'язано"
|
||||
},
|
||||
"FinishButton": {
|
||||
"en": "Finish",
|
||||
"ru": "Завершить",
|
||||
"ua": "Завершити"
|
||||
},
|
||||
"CopyRCodeButton": {
|
||||
"en": "Copy RCode",
|
||||
"ru": "Скопировать RCode",
|
||||
"ua": "Скопіювати RCode"
|
||||
},
|
||||
"Login": {
|
||||
"en": "Login",
|
||||
"ru": "Логин",
|
||||
"ua": "Логін"
|
||||
},
|
||||
"Password": {
|
||||
"en": "Password",
|
||||
"ru": "Пароль",
|
||||
"ua": "Пароль"
|
||||
},
|
||||
"Code": {
|
||||
"en": "Code",
|
||||
"ru": "Код",
|
||||
"ua": "Код"
|
||||
},
|
||||
"SmsCode": {
|
||||
"en": "SMS code",
|
||||
"ru": "СМС код",
|
||||
"ua": "СМС код"
|
||||
}
|
||||
},
|
||||
"SetEncryptedPasswordDialog": {
|
||||
"Title": {
|
||||
"en": "Encryption password",
|
||||
"ru": "Пароль шифрования",
|
||||
"ua": "Пароль шифрування"
|
||||
},
|
||||
"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)",
|
||||
@@ -651,30 +551,6 @@
|
||||
"ua": "Пароль"
|
||||
}
|
||||
},
|
||||
"LinksView": {
|
||||
"UsefulLinks": {
|
||||
"en": "Useful links",
|
||||
"ru": "Полезные ссылки",
|
||||
"ua": "Корисні посилання"
|
||||
},
|
||||
"Documentation": {
|
||||
"en": "Documentation",
|
||||
"ru": "Документация",
|
||||
"ua": "Документація"
|
||||
}
|
||||
},
|
||||
"MafileMoverView": {
|
||||
"Title": {
|
||||
"en": "Move Steam Guard",
|
||||
"ru": "Перенести Steam Guard",
|
||||
"ua": "Перенести Steam Guard"
|
||||
},
|
||||
"Done": {
|
||||
"en": "Steam Guard moved",
|
||||
"ru": "Steam Guard перенесен",
|
||||
"ua": "Steam Guard перенесено"
|
||||
}
|
||||
},
|
||||
"CodeBehind": {
|
||||
"MainVM": {
|
||||
"SuccessfulLogin": {
|
||||
@@ -941,11 +817,6 @@
|
||||
"ua": "Скасовано (52)"
|
||||
|
||||
},
|
||||
"InvalidLoginAuthCode": {
|
||||
"ru": "Неверный код авторизации (65)",
|
||||
"en": "Invalid login auth code (65)",
|
||||
"ua": "Невірний код авторизації (65)"
|
||||
},
|
||||
"ExpiredLoginAuthCode": {
|
||||
"ru": "Истекло время кода (71)",
|
||||
"en": "Expired login auth code (71)",
|
||||
@@ -1191,15 +1062,10 @@
|
||||
"en": "Can't login: ",
|
||||
"ua": "Не вдалося залогінитися: "
|
||||
},
|
||||
"UnsupportedGuardType": {
|
||||
"ru": "Steam Guard уже активирован. Был запрошен код с мобильного устройства",
|
||||
"en": "Steam Guard already activated. Mobile device code was requested",
|
||||
"ua": "Steam Guard вже активовано. Був запрошений код з мобільного пристрою"
|
||||
},
|
||||
"MafileLinked": {
|
||||
"ru": "RCode: {0}\r\nИмя файла: {1}.mafile",
|
||||
"en": "RCode: {0}\r\nFile name: {1}.mafile",
|
||||
"ua": "RCode: {0}\r\nІм'я файлу: {1}.mafile"
|
||||
"ru": "Мафайл успешно привязан. RCode: {0}\r\nИмя файла: {1}.mafile",
|
||||
"en": "Mafile successfully linked. RCode: {0}\r\nFile name: {1}.mafile",
|
||||
"ua": "Мафайл успішно прив'язано. RCode: {0}\r\nІм'я файлу: {1}.mafile"
|
||||
},
|
||||
"ErrorWithCode": {
|
||||
"ru": "Ошибка с кодом: ",
|
||||
@@ -1211,23 +1077,25 @@
|
||||
"en": "Unknown error: ",
|
||||
"ua": "Невідома помилка: "
|
||||
},
|
||||
"PleaseEnterCorrectPhone": {
|
||||
"ru": "Пожалуйста, введите корректный номер телефона",
|
||||
"en": "Please enter correct phone number",
|
||||
"ua": "Будь ласка, введіть коректний номер телефону"
|
||||
},
|
||||
"PleaseEnterCorrectCode": {
|
||||
"ru": "Пожалуйста, введите корректный код",
|
||||
"en": "Please enter correct code",
|
||||
"ua": "Будь ласка, введіть коректний код"
|
||||
},
|
||||
"EnterEmailCode": {
|
||||
"ru": "Введите код, отправленный на вашу почту",
|
||||
"en": "Enter the code sent to your email",
|
||||
"ua": "Введіть код, надісланий на вашу пошту"
|
||||
"ru": "Введите код из письма",
|
||||
"en": "Enter code from email",
|
||||
"ua": "Введіть код з листа"
|
||||
},
|
||||
"ClickOnEmailLink": {
|
||||
"ru": "На почту было отправлено письмо, откройте ссылку из письма, а затем нажмите — 'Продолжить'",
|
||||
"en": "An email has been sent. Open the link from the email, then click 'Proceed'",
|
||||
"ua": "На пошту надіслано лист. Відкрийте посилання з листа, а потім натисніть — 'Продовжити'"
|
||||
},
|
||||
"ClickOnEmailLinkRetry": {
|
||||
"ru":
|
||||
"Не удалось подтвердить переход по ссылке. Убедитесь, что вы открыли ссылку из письма, затем нажмите — 'Продолжить'",
|
||||
"en":
|
||||
"We couldn’t verify that you clicked the link. Make sure you opened the link from the email, then click 'Proceed'",
|
||||
"ua":
|
||||
"Не вдалося підтвердити перехід за посиланням. Переконайтесь, що ви відкрили посилання з листа, а потім натисніть — 'Продовжити'"
|
||||
"ru": "На почту было отправлено письмо, нажмите по ссылке затем - 'Продолжить'",
|
||||
"en": "Email was sent, click on link and then - 'Proceed'",
|
||||
"ua": "На пошту було відправлено лист, натисніть по посиланню потім - 'Продовжити'"
|
||||
},
|
||||
"PhoneHint": {
|
||||
"ru": "На телефон {0} была отправлена СМС",
|
||||
@@ -1235,84 +1103,39 @@
|
||||
"ua": "На телефон {0} було відправлено СМС"
|
||||
},
|
||||
"EnterPhoneNumber": {
|
||||
"ru":
|
||||
"Введите номер в международном формате, только цифры (без '+', пробелов и скобок), или оставьте поле пустым, чтобы привязать без номера",
|
||||
"en":
|
||||
"Enter number in international format, digits only (no '+', spaces or brackets), or leave the field empty to link without a number",
|
||||
"ua":
|
||||
"Введіть номер у міжнародному форматі, лише цифри (без '+', пробілів і дужок), або залиште поле порожнім, щоб прив’язати без номера"
|
||||
"ru": "Введите номер телефона (без знака '+' и др. символов). По-желанию.",
|
||||
"en": "Enter phone number (without '+' and other symbols). Optional",
|
||||
"ua": "Введіть номер телефону (без знака '+' та ін. символів). За бажанням"
|
||||
}
|
||||
},
|
||||
"MafileMoverVM": {
|
||||
"EnterGuardCode": {
|
||||
"en": "Enter Steam Guard code or confirm login and click 'Proceed'",
|
||||
"ru": "Введите код Steam Guard либо подтвердите вход и нажмите \"Продолжить\"",
|
||||
"ua": "Введіть код Steam Guard або підтвердіть вхід і натисніть 'Продовжити'"
|
||||
"MAAC": {
|
||||
"TimerConfirmed": {
|
||||
"ru": "Авто: подтверждено ",
|
||||
"en": "Auto: confirmed ",
|
||||
"ua": "Авто: підтверджено "
|
||||
},
|
||||
"EnterGuardCodeRetrying": {
|
||||
"en": "Failed to confirm login. Enter Steam Guard code or try again",
|
||||
"ru": "Не удалось подтвердить вход. Введите код Steam Guard или попробуйте еще раз",
|
||||
"ua": "Не вдалося підтвердити вхід. Введіть код Steam Guard або спробуйте ще раз"
|
||||
"TimerNotConfirmed": {
|
||||
"ru": "Авто: подтверждение не сработало",
|
||||
"en": "Auto: confirmation was unsuccessful",
|
||||
"ua": "Авто: підтвердження не спрацювало"
|
||||
},
|
||||
"SmsCodeStepTip": {
|
||||
"en": "Enter the code from the SMS sent to your phone number",
|
||||
"ru": "Введите код из СМС, отправленный на ваш номер телефона",
|
||||
"ua": "Введіть код з СМС, надісланий на ваш номер телефону"
|
||||
"TimerSessionError": {
|
||||
"ru": "необходимо обновить сессию или перелогиниться",
|
||||
"en": "need to refresh session or relogin",
|
||||
"ua": "необхідно оновити сесію або перелогінитися"
|
||||
},
|
||||
"DoneStepTip": {
|
||||
"ru": "RCode: {0}\r\nИмя файла: {1}.mafile",
|
||||
"en": "RCode: {0}\r\nFile name: {1}.mafile",
|
||||
"ua": "RCode: {0}\r\nІм'я файлу: {1}.mafile"
|
||||
"TimerPrefix": {
|
||||
"ru": "Авто ",
|
||||
"en": "Auto ",
|
||||
"ua": "Авто "
|
||||
},
|
||||
"GuardIsNotActive": {
|
||||
"ru":
|
||||
"Steam Guard установлен на данном аккаунте. Чтобы привязать mafile к аккаунту, воспользуйтесь окном \"Привязать\"",
|
||||
"en": "Steam Guard is set on this account. To link mafile to the account, use the 'Link' window",
|
||||
"ua":
|
||||
"Steam Guard встановлено на цьому акаунті. Щоб прив'язати mafile до акаунту, скористайтеся вікном 'Прив'язати'"
|
||||
},
|
||||
"SeemsNoPhoneNumber": {
|
||||
"en": "The account has no phone number linked, returned Fail code (2)",
|
||||
"ru": "На аккаунте не привязан номер телефона, был возвращен код Fail (2)",
|
||||
"ua": "На акаунті не прив'язано номер телефону, повернуто код Fail (2)"
|
||||
},
|
||||
"SmsCodeFailed": {
|
||||
"en": "SMS code failed, try again",
|
||||
"ru": "Ошибка SMS-кода, попробуйте еще раз",
|
||||
"ua": "Помилка SMS-коду, спробуйте ще раз"
|
||||
"TimerPreventedOverlap": {
|
||||
"ru": "Авто: таймер подтверждений пытался начать новый цикл, когда предыдущий еще не завершился. Советуем увеличить задержку",
|
||||
"en": "Auto: confirmation timer tried to start new cycle when previous one was not finished yet. We recommend to increase delay",
|
||||
"ua": "Авто: таймер підтверджень намагався запустити новий цикл, коли попередній ще не закінчився. Рекомендуємо збільшити затримку"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MAAC": {
|
||||
"TimerConfirmed": {
|
||||
"ru": "Авто: подтверждено ",
|
||||
"en": "Auto: confirmed ",
|
||||
"ua": "Авто: підтверджено "
|
||||
},
|
||||
"TimerNotConfirmed": {
|
||||
"ru": "Авто: подтверждение не сработало",
|
||||
"en": "Auto: confirmation was unsuccessful",
|
||||
"ua": "Авто: підтвердження не спрацювало"
|
||||
},
|
||||
"TimerSessionError": {
|
||||
"ru": "необходимо обновить сессию или перелогиниться",
|
||||
"en": "need to refresh session or relogin",
|
||||
"ua": "необхідно оновити сесію або перелогінитися"
|
||||
},
|
||||
"TimerPrefix": {
|
||||
"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",
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<item>
|
||||
<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>
|
||||
<version>1.5.7.0</version>
|
||||
<url>https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.5.7/NebulaAuth.1.5.7.zip</url>
|
||||
<changelog>https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.5.7.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
</item>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user