Compare commits

...

8 Commits

Author SHA1 Message Date
achiez 5029f78247 feat(export): add zip export, export-all, and login:password input parsing 2026-06-19 21:18:34 +03:00
Achies b9452c4baf Merge pull request #27 from achiez/feat/dialog-header
feat(ui): add DialogHeader component and restyle dialog headers
2026-06-19 20:45:30 +03:00
achiez ec71b9881e feat(ui): add DialogHeader component and restyle dialog headers 2026-06-19 20:43:43 +03:00
achiez 4b727af1fa chore(resharper): perform resharper cleanup and add shared cleanup profile 2026-06-19 19:26:26 +03:00
achiez 9897ca21a6 fix: add missing MafileImportDialogVM from #24 2026-06-19 19:05:58 +03:00
Achies 631068e2f3 Merge pull request #25 from achiez/feat/proxy-signat-scheme
feat(proxy): add SignAtScheme support for improved proxy parsing
2026-06-19 19:03:56 +03:00
Achies 0cc9a3d100 Merge pull request #24 from achiez/feat/group-on-import
feat(import): add group assignment and skip-confirmation setting
2026-06-19 19:03:33 +03:00
achiez 5836ed4508 feat(proxy): add SignAtScheme support for improved proxy parsing 2026-06-19 18:55:39 +03:00
35 changed files with 696 additions and 460 deletions
+311
View File
@@ -1,3 +1,314 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CheckNamespace/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;&#xD;
&lt;TypePattern DisplayName="Non-reorderable types" Priority="99999999"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Interface" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.ComImport" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;Kind Is="Struct" /&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.StructLayoutAttribute" /&gt;&#xD;
&lt;HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="xUnit.net Test Classes" RemoveRegions="All"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Class" /&gt;&#xD;
&lt;HasMember&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="Xunit.FactAttribute" /&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="Xunit.TheoryAttribute" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/HasMember&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;Entry DisplayName="Fields"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Not&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Not&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Readonly /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Constructors"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Constructor" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Teardown Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;ImplementsInterface Name="System.IDisposable" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;Entry DisplayName="Test Methods" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;HasAttribute Name="Xunit.FactAttribute" /&gt;&#xD;
&lt;HasAttribute Name="Xunit.TheoryAttribute" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Class" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="NUnit.Framework.TestFixtureAttribute" /&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="NUnit.Framework.TestFixtureSourceAttribute" /&gt;&#xD;
&lt;HasMember&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestAttribute" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestCaseAttribute" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/HasMember&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;Entry DisplayName="Setup/Teardown Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="NUnit.Framework.SetUpAttribute" /&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="NUnit.Framework.TearDownAttribute" /&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="NUnit.Framework.TestFixtureSetUpAttribute" /&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="NUnit.Framework.TestFixtureTearDownAttribute" /&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="NUnit.Framework.OneTimeSetUpAttribute" /&gt;&#xD;
&lt;HasAttribute Inherited="True" Name="NUnit.Framework.OneTimeTearDownAttribute" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;Entry DisplayName="Test Methods" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestAttribute" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestCaseAttribute" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="Grains"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;ImplementsInterface Name="^Orleans\.IGrain$" /&gt;&#xD;
&lt;ImplementsInterface Name="Orleans.IGrainBase" /&gt;&#xD;
&lt;ImplementsInterface Name="Achiefy.Orleans.Tenancy.Abstractions.ITenantGrain" /&gt;&#xD;
&lt;InheritsFromType Name="Orleans.Grain" /&gt;&#xD;
&lt;InheritsFromType Name="Achiefy.Tenant.Application.Stateful.Core.TenantGrain" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;Not&gt;&#xD;
&lt;Abstract /&gt;&#xD;
&lt;/Not&gt;&#xD;
&lt;Kind Is="Class" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;Entry DisplayName="Public Delegates" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Delegate" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Public Enums" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Enum" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Nested Records"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Record" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Group DisplayName="Group"&gt;&#xD;
&lt;Entry DisplayName="Static Fields and Constants"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Constant" /&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Kind Is="0" Order="Constant Field" /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Properties, Indexers"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Property" /&gt;&#xD;
&lt;Kind Is="Indexer" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Fields"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Not&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Not&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Readonly /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/Group&gt;&#xD;
&lt;Entry DisplayName="Constructors"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Constructor" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Lifecycle Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;Name Is="^On(Activate|Deactivate)Async.*$" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;Entry DisplayName="Nested Types"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Type" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="Default Pattern"&gt;&#xD;
&lt;Entry DisplayName="Public Enums" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Enum" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Public Delegates" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Delegate" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Nested Records"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Record" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Group DisplayName="Group"&gt;&#xD;
&lt;Entry DisplayName="Static Fields and Constants"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Constant" /&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Kind Is="0" Order="Constant Field" /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Properties, Indexers"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Property" /&gt;&#xD;
&lt;Kind Is="Indexer" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Fields"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Not&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Not&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Readonly /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/Group&gt;&#xD;
&lt;Entry DisplayName="Constructors"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Constructor" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;Entry DisplayName="Nested Types"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Type" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;/Patterns&gt;</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=MAAC/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
+18 -18
View File
@@ -63,25 +63,25 @@
</head>
<body>
<div class="changelog-container">
<div class="change">
<div class="version">Version 1.8.1</div>
<div class="date">25.01.2026</div>
<div class="description">
<ul>
<li><b>NEW:</b> Added Mafile Export tool with templates, batch export and flexible field filtering.</li>
<li><b>IMPROVEMENT:</b> Reworked auto-confirmation error handling logic (MAAC) — fewer false disables, smarter retries.</li>
<li><b>UPDATE:</b> Added “Unattach Proxy” option to the account context menu.</li>
<li><b>LOCALIZATION:</b> Added Chinese (Simplified) and French languages.</li>
<li><b>FIX:</b> Fixed crashes related to duplicate mafiles, timers, search filtering and import logic.</li>
<li>
<b>DETAILS:</b> Full patch notes:
<a href="https://teletype.in/@achies_raw/nebula-1-8-1-eng">ENG</a> |
<a href="https://teletype.in/@achies_raw/nebula-1-8-1-rus">RUS</a>
</li>
</ul>
</div>
<div class="changelog-container">
<div class="change">
<div class="version">Version 1.8.1</div>
<div class="date">25.01.2026</div>
<div class="description">
<ul>
<li><b>NEW:</b> Added Mafile Export tool with templates, batch export and flexible field filtering.</li>
<li><b>IMPROVEMENT:</b> Reworked auto-confirmation error handling logic (MAAC) — fewer false disables, smarter retries.</li>
<li><b>UPDATE:</b> Added “Unattach Proxy” option to the account context menu.</li>
<li><b>LOCALIZATION:</b> Added Chinese (Simplified) and French languages.</li>
<li><b>FIX:</b> Fixed crashes related to duplicate mafiles, timers, search filtering and import logic.</li>
<li>
<b>DETAILS:</b> Full patch notes:
<a href="https://teletype.in/@achies_raw/nebula-1-8-1-eng">ENG</a> |
<a href="https://teletype.in/@achies_raw/nebula-1-8-1-rus">RUS</a>
</li>
</ul>
</div>
</div>
</div>
</body>
</html>
+9 -9
View File
@@ -63,16 +63,16 @@
</head>
<body>
<div class="changelog-container">
<div class="change">
<div class="version">Version 1.8.2</div>
<div class="date">10.02.2026</div>
<div class="description">
<ul>
<li><b>FIX:</b> AutoConfirm timer now correctly resets the status after a successful request (Warning → Ok).</li>
</ul>
</div>
<div class="changelog-container">
<div class="change">
<div class="version">Version 1.8.2</div>
<div class="date">10.02.2026</div>
<div class="description">
<ul>
<li><b>FIX:</b> AutoConfirm timer now correctly resets the status after a successful request (Warning → Ok).</li>
</ul>
</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,49 @@
<UserControl x:Class="NebulaAuth.DialogHeader"
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"
mc:Ignorable="d"
x:Name="Root">
<StackPanel>
<Border Background="{DynamicResource Base300Brush}" Padding="10,6,10,6">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<materialDesign:PackIcon
Kind="{Binding IconKind, ElementName=Root}"
Width="20" Height="20" Margin="0,0,8,0"
VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}">
<materialDesign:PackIcon.Style>
<Style TargetType="materialDesign:PackIcon">
<Style.Triggers>
<Trigger Property="Kind" Value="None">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</materialDesign:PackIcon.Style>
</materialDesign:PackIcon>
<TextBlock VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}"
FontSize="18">
<Run Text="{Binding Title, ElementName=Root}" />
<Run FontWeight="Bold" Text="{Binding TitleAccent, ElementName=Root}" />
</TextBlock>
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30"
Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right"
IsEnabled="{Binding IsCloseEnabled, ElementName=Root}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{Binding CloseParameter, ElementName=Root}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
</Border>
</StackPanel>
</UserControl>
@@ -0,0 +1,63 @@
using System.Windows;
using System.Windows.Controls;
using MaterialDesignThemes.Wpf;
namespace NebulaAuth;
public partial class DialogHeader : UserControl
{
public static readonly DependencyProperty IconKindProperty =
DependencyProperty.Register(nameof(IconKind), typeof(PackIconKind), typeof(DialogHeader),
new PropertyMetadata(PackIconKind.None));
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register(nameof(Title), typeof(string), typeof(DialogHeader),
new PropertyMetadata(null));
public static readonly DependencyProperty TitleAccentProperty =
DependencyProperty.Register(nameof(TitleAccent), typeof(string), typeof(DialogHeader),
new PropertyMetadata(null));
public static readonly DependencyProperty CloseParameterProperty =
DependencyProperty.Register(nameof(CloseParameter), typeof(object), typeof(DialogHeader),
new PropertyMetadata(null));
public static readonly DependencyProperty IsCloseEnabledProperty =
DependencyProperty.Register(nameof(IsCloseEnabled), typeof(bool), typeof(DialogHeader),
new PropertyMetadata(true));
public PackIconKind IconKind
{
get => (PackIconKind) GetValue(IconKindProperty);
set => SetValue(IconKindProperty, value);
}
public string? Title
{
get => (string?) GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
public string? TitleAccent
{
get => (string?) GetValue(TitleAccentProperty);
set => SetValue(TitleAccentProperty, value);
}
public object? CloseParameter
{
get => GetValue(CloseParameterProperty);
set => SetValue(CloseParameterProperty, value);
}
public bool IsCloseEnabled
{
get => (bool) GetValue(IsCloseEnabledProperty);
set => SetValue(IsCloseEnabledProperty, value);
}
public DialogHeader()
{
InitializeComponent();
}
}
+1 -1
View File
@@ -190,4 +190,4 @@ public static class DialogsController
}
#endregion
}
}
@@ -196,6 +196,16 @@
"es": "Grupo",
"tr": "Grup",
"kk": "Топ"
},
"ExportToZip": {
"ru": "Экспортировать в ZIP архив",
"en": "Export to ZIP archive",
"uk": "Експортувати в ZIP архів",
"fr": "Exporter en archive ZIP",
"zh": "导出为 ZIP 压缩包",
"es": "Exportar a archivo ZIP",
"tr": "ZIP arşivine aktar",
"kk": "ZIP мұрағатқа экспорттау"
}
},
"Tooltips": {
@@ -288,17 +298,27 @@
"es": "Incluir datos de grupo compatibles con Nebula.",
"tr": "Nebula uyumlu grup verilerini dahil et.",
"kk": "Nebula үйлесімді топ деректерін қосу."
},
"ExportToZip": {
"ru": "Экспортировать в ZIP архив вместо папки. Архив будет сохранён в выбранной директории с именем вида N_timestamp.zip.",
"en": "Export to a ZIP archive instead of a folder. The archive will be saved in the selected directory as N_timestamp.zip.",
"uk": "Експортувати в ZIP архів замість папки. Архів буде збережено у вибраній директорії з назвою N_timestamp.zip.",
"fr": "Exporter dans une archive ZIP plutôt que dans un dossier. L'archive sera enregistrée dans le répertoire sélectionné sous le nom N_timestamp.zip.",
"zh": "导出为 ZIP 压缩包而非文件夹。压缩包将保存在所选目录中,名称格式为 N_timestamp.zip。",
"es": "Exportar a un archivo ZIP en lugar de una carpeta. El archivo se guardará en el directorio seleccionado como N_timestamp.zip.",
"tr": "Klasör yerine ZIP arşivine aktar. Arşiv, seçilen dizine N_timestamp.zip adıyla kaydedilecektir.",
"kk": "Қалта орнына ZIP мұрағатына экспорттау. Мұрағат таңдалған каталогта N_timestamp.zip атауымен сақталады."
}
},
"ExportAccountsPlaceholder": {
"ru": "Введите логины аккаунтов или SteamID (по одному на строку) для экспорта в выбранную директорию.",
"en": "Enter account logins or SteamIDs (one per line) to export to the selected directory.",
"uk": "Введіть логіни акаунтів або SteamID (по одному на рядок) для експорту у вибрану директорію.",
"fr": "Entrez les identifiants de compte ou les SteamID (un par ligne) pour exporter vers le répertoire sélectionné.",
"zh": "输入要导出到所选目录的账户登录名或 SteamID(每行一个)。",
"es": "Introduce los logins de las cuentas o SteamID (uno por línea) para exportarlos al directorio seleccionado.",
"tr": "Seçilen dizine dışa aktarmak için hesap girişlerini veya SteamIDleri (her satıra bir tane) girin.",
"kk": "Таңдалған каталогқа экспорттау үшін аккаунт логиндерін немесе SteamID (әр жолға біреуден) енгізіңіз."
"ru": "Введите логины или SteamID (по одному на строку). Поддерживается формат логин:пароль — пароль будет проигнорирован. Оставьте пустым для экспорта всех аккаунтов.",
"en": "Enter logins or SteamIDs (one per line). Supports login:password format — the password will be ignored. Leave empty to export all accounts.",
"uk": "Введіть логіни або SteamID (по одному на рядок). Підтримується формат логін:пароль — пароль буде проігноровано. Залиште порожнім для експорту всіх акаунтів.",
"fr": "Entrez les identifiants ou SteamID (un par ligne). Supporte le format login:mot_de_passe — le mot de passe sera ignoré. Laissez vide pour exporter tous les comptes.",
"zh": "输入登录名或 SteamID(每行一个)。支持 login:password 格式——密码将被忽略。留空则导出所有账户。",
"es": "Introduce logins o SteamID (uno por línea). Soporta el formato login:contraseña — la contraseña será ignorada. Déjalo vacío para exportar todas las cuentas.",
"tr": "Girişleri veya SteamIDleri girin (her satıra bir tane). login:şifre formatı desteklenir — şifre yok sayılır. Tüm hesapları dışa aktarmak için boş bırakın.",
"kk": "Логиндерді немесе SteamID (әр жолға біреуден) енгізіңіз. логин:құпиясөз форматы қолданылады — құпиясөз еленбейді. Барлық аккаунттарды экспорттау үшін бос қалдырыңыз."
}
}
}
+1
View File
@@ -42,6 +42,7 @@
DialogClosed="DialogHost_DialogClosed"
ApplyBlurBackground="{Binding Settings.ApplyBlurBackground}"
BlurRadius="12"
DialogContentUniformCornerRadius="12"
x:Name="DialogHostInstance">
<Grid ZIndex="0">
@@ -13,4 +13,5 @@ public class MafileExportTemplate
public bool IncludeNebulaPassword { get; set; }
public bool IncludeNebulaGroup { get; set; }
public string? Path { get; set; }
public bool ExportToZip { get; set; }
}
@@ -1,6 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AchiesUtilities.Extensions;
using NebulaAuth.Core;
@@ -36,48 +39,79 @@ public static class MafileExporter
return new ExportResult(LocManager.GetCodeBehindOrDefault("AccessDenied", "MafileExporter.AccessDenied"));
}
var exported = new Dictionary<Mafile, string>();
var notFound = new List<string>();
var conflict = new List<string>();
var toExport = new List<(string key, Mafile mafile)>();
foreach (var key in keys)
{
SteamId? steamId = null;
if (SteamId64.TryParse(key, out var id64))
{
steamId = id64;
}
var maf = Storage.MaFiles.FirstOrDefault(m => m.AccountName.EqualsIgnoreCase(key) || m.SteamId == steamId);
if (maf != null)
toExport.Add((key, maf));
else
notFound.Add(key);
}
if (template.ExportToZip)
{
if (toExport.Count > 0)
{
var fileName = await ExportMafile(template.Path, template, maf);
if (fileName == null)
var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
var zipName = $"{toExport.Count}_{timestamp}.zip";
var zipPath = Path.Combine(template.Path, zipName);
await using var zipStream = File.Create(zipPath);
using var archive = new ZipArchive(zipStream, ZipArchiveMode.Create);
var addedEntries = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var (key, maf) in toExport)
{
var (content, fileName) = BuildMafileContent(template, maf);
if (!addedEntries.Add(fileName))
{
conflict.Add(key);
continue;
}
var entry = archive.CreateEntry(fileName);
await using var entryStream = entry.Open();
await using var writer = new StreamWriter(entryStream, Encoding.UTF8);
await writer.WriteAsync(content);
exported[maf] = fileName;
}
}
}
else
{
foreach (var (key, maf) in toExport)
{
var (content, fileName) = BuildMafileContent(template, maf);
var fullPath = Path.Combine(template.Path, fileName);
if (File.Exists(fullPath))
{
conflict.Add(key);
continue;
}
exported[maf] = fileName;
}
else
{
notFound.Add(key);
await File.WriteAllTextAsync(fullPath, content);
exported[maf] = fullPath;
}
}
return new ExportResult(exported, notFound, conflict);
}
private static async Task<string?> ExportMafile(string path, MafileExportTemplate template, Mafile mafile)
private static (string content, string fileName) BuildMafileContent(MafileExportTemplate template, Mafile mafile)
{
// We preserve SteamId even if other info is not included
var session = template.IncludeSessionData
? mafile.SessionData
: new MobileSessionData(null!, mafile.SteamId, default, null, tokens: null);
var serializeMaf = new Mafile
{
SharedSecret = template.IncludeSharedSecret ? mafile.SharedSecret : null!,
@@ -102,14 +136,7 @@ public static class MafileExporter
var serialized = NebulaSerializer.SerializeMafile(serializeMaf);
var strategy = template.UseLoginAsMafileName ? MafileNamingStrategy.Login : MafileNamingStrategy.SteamId;
var fileName = strategy.GetMafileName(serializeMaf);
var fullPath = Path.Combine(path, fileName);
if (File.Exists(fullPath))
{
return null;
}
await File.WriteAllTextAsync(fullPath, serialized);
return fullPath;
return (serialized, fileName);
}
private static bool PathIsValid(string path)
+1 -1
View File
@@ -87,4 +87,4 @@ public static class NebulaSerializer
{
return MafileSerializer.SerializeLegacy(data, Serializer.Settings.SerializationOptions, properties);
}
}
}
+7
View File
@@ -22,6 +22,13 @@ public static class ProxyStorage
PatternRequirement.Optional,
PatternRequirement.Optional);
public static readonly ProxyParser SignAtScheme = new(
ProxyDefaultFormats.UniversalSignAt, false, ProxyProtocol.HTTP,
ProxyPatternProtocol.All,
ProxyPatternHostFormat.Domain | ProxyPatternHostFormat.IPv4,
PatternRequirement.Required,
PatternRequirement.Required);
public static ObservableDictionary<int, ProxyData> Proxies { get; } = new();
+1 -1
View File
@@ -127,4 +127,4 @@ public enum ThemeType
Light = 2,
Luxury = 3,
Shadcn = 4
}
}
+12 -12
View File
@@ -3,20 +3,20 @@ using Newtonsoft.Json;
namespace NebulaAuth.Model.Update;
public class ChangelogEntry
{
[JsonProperty("version")] public string Version { get; set; } = string.Empty;
public class ChangelogEntry
{
[JsonProperty("version")] public string Version { get; set; } = string.Empty;
[JsonProperty("date")] public string Date { get; set; } = string.Empty;
[JsonProperty("date")] public string Date { get; set; } = string.Empty;
[JsonProperty("changes")] public List<ChangeItem> Changes { get; set; } = new();
}
[JsonProperty("changes")] public List<ChangeItem> Changes { get; set; } = new();
}
public class ChangeItem
{
[JsonProperty("type")] public string Type { get; set; } = string.Empty;
public class ChangeItem
{
[JsonProperty("type")] public string Type { get; set; } = string.Empty;
[JsonProperty("text")] public string Text { get; set; } = string.Empty;
[JsonProperty("text")] public string Text { get; set; } = string.Empty;
[JsonProperty("link")] public string? Link { get; set; }
}
[JsonProperty("link")] public string? Link { get; set; }
}
@@ -36,7 +36,8 @@
<!-- Window Buttons -->
<StackPanel
HorizontalAlignment="Right"
Orientation="Horizontal">
Orientation="Horizontal"
TextElement.Foreground="{DynamicResource PrimaryContentBrush}">
<StackPanel.Resources>
<Style TargetType="materialDesign:PackIcon">
<Setter Property="HorizontalAlignment" Value="Center" />
@@ -12,31 +12,10 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<!--<materialDesign:PackIcon Kind="WarningCircleOutline" Width="20" Height="20" Margin="0,0,5,0"
VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}" />-->
<TextBlock FontStyle="Normal" Foreground="{DynamicResource BaseContentBrush}"
HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr ConfirmCancelDialog.Title}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" CommandParameter="{StaticResource False}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Opacity="0.7" />
<Grid Grid.Row="2" Margin="12">
<nebulaAuth:DialogHeader Title="{Tr ConfirmCancelDialog.Title}"
CloseParameter="{StaticResource False}" />
<Grid Grid.Row="1" Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -6,6 +6,7 @@
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:model="clr-namespace:NebulaAuth.Model"
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
mc:Ignorable="d"
TextElement.Foreground="{DynamicResource BaseContentBrush}"
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
@@ -15,31 +16,11 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Login" 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 LoginAgainDialog.Title}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" CommandParameter="{StaticResource False}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Opacity="0.7" />
<Grid Grid.Row="2" Margin="12">
<nebulaAuth:DialogHeader IconKind="Login"
Title="{Tr LoginAgainDialog.Title}"
CloseParameter="{StaticResource False}" />
<Grid Grid.Row="1" Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -7,6 +7,7 @@
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:model="clr-namespace:NebulaAuth.Model"
xmlns:entities="clr-namespace:NebulaAuth.Model.Entities"
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
mc:Ignorable="d"
TextElement.Foreground="{DynamicResource BaseContentBrush}"
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
@@ -16,32 +17,12 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Login" Width="20" Height="20" Margin="0,0,5,0"
VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}" />
<TextBlock FontSize="16" VerticalAlignment="Center" Foreground="{DynamicResource BaseContentBrush}"
Margin="7,0,0,0" HorizontalAlignment="Left">
<Run Text="{Tr LoginAgainDialog.LoginFor, IsDynamic=False}" />
<Run FontWeight="Bold" Text="{Binding UserName}" />
</TextBlock>
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" CommandParameter="{StaticResource False}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Opacity="0.7" />
<Grid Grid.Row="2" Margin="12">
<nebulaAuth:DialogHeader IconKind="Login"
Title="{Tr LoginAgainDialog.LoginFor, IsDynamic=False}"
TitleAccent="{Binding UserName}"
CloseParameter="{StaticResource False}" />
<Grid Grid.Row="1" Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -4,6 +4,7 @@
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:nebulaAuth="clr-namespace:NebulaAuth"
mc:Ignorable="d"
Height="Auto" Width="Auto" MaxWidth="520"
Background="{DynamicResource WindowBackground}">
@@ -11,27 +12,11 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock FontStyle="Normal" Foreground="{DynamicResource BaseContentBrush}"
HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr MafileImportDialog.Title}" />
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" CommandParameter="{x:Null}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<nebulaAuth:DialogHeader Title="{Tr MafileImportDialog.Title}" />
<Separator Grid.Row="1" Opacity="0.7" />
<Grid Grid.Row="2" Margin="14,14,14,16">
<Grid Grid.Row="1" Margin="14,14,14,16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -45,10 +30,10 @@
CornerRadius="8"
BorderThickness="1">
<Border.Background>
<SolidColorBrush Color="{DynamicResource BaseContentColor}" Opacity="0.07"/>
<SolidColorBrush Color="{DynamicResource BaseContentColor}" Opacity="0.07" />
</Border.Background>
<Border.BorderBrush>
<SolidColorBrush Color="{DynamicResource BaseContentColor}" Opacity="0.12"/>
<SolidColorBrush Color="{DynamicResource BaseContentColor}" Opacity="0.12" />
</Border.BorderBrush>
<Grid>
<Grid.ColumnDefinitions>
@@ -92,14 +77,12 @@
Margin="42,0,10,0"
IsEditable="True"
ItemsSource="{Binding Groups}"
Text="{Binding Group, UpdateSourceTrigger=PropertyChanged}"
materialDesign:HintAssist.Hint="{Tr MafileImportDialog.GroupFieldHint}"
materialDesign:HintAssist.IsFloating="False"
Visibility="{Binding AddToGroup, Converter={StaticResource BooleanToVisibilityConverter}}"
Style="{StaticResource MaterialDesignFloatingHintComboBox}"
/>
Style="{StaticResource MaterialDesignFloatingHintComboBox}" />
<Grid Grid.Row="5" Margin="10,16,10,5">
<Grid.ColumnDefinitions>
@@ -126,4 +109,4 @@
</Grid>
</Grid>
</Grid>
</UserControl>
</UserControl>
@@ -6,4 +6,4 @@ public partial class MafileImportDialog
{
InitializeComponent();
}
}
}
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
mc:Ignorable="d"
TextElement.Foreground="{DynamicResource BaseContentBrush}"
d:DataContext="{d:DesignInstance other:SdaPasswordDialogVM}"
@@ -14,29 +15,11 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Lock" Width="20" Height="20" Margin="0,0,5,0"
VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}" />
<TextBlock FontSize="16" VerticalAlignment="Center" Foreground="{DynamicResource BaseContentBrush}"
Margin="7,0,0,0" HorizontalAlignment="Left"
Text="{Tr SdaPasswordDialog.Title}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" CommandParameter="{StaticResource False}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Opacity="0.7" />
<Grid Grid.Row="2" Margin="12">
<nebulaAuth:DialogHeader IconKind="Lock"
Title="{Tr SdaPasswordDialog.Title}"
CloseParameter="{StaticResource False}" />
<Grid Grid.Row="1" Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -5,8 +5,10 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance other:LoginAgainVM}">
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
Background="{DynamicResource WindowBackground}">
<Grid MinHeight="100" MinWidth="300" MaxWidth="400">
@@ -15,38 +17,19 @@
<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 SetEncryptionPasswordDialog.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"
<nebulaAuth:DialogHeader IconKind="Encryption"
Title="{Tr SetEncryptionPasswordDialog.Title}"
CloseParameter="{StaticResource False}" />
<TextBlock Grid.Row="1" IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal"
FontSize="16"
Text="{Tr SetEncryptionPasswordDialog.DialogText}"
Margin="10" HorizontalAlignment="Left" />
<PasswordBox TabIndex="0" FontSize="16" x:Name="PasswordBox"
materialDesign:PasswordBoxAssist.Password="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
Margin="10" Grid.Row="3" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
Margin="10" Grid.Row="2" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
materialDesign:HintAssist.Hint="{Tr SetEncryptionPasswordDialog.Password}" />
<Grid Grid.Row="4" Margin="10">
<Grid Grid.Row="3" Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
@@ -4,6 +4,7 @@
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:nebulaAuth="clr-namespace:NebulaAuth"
mc:Ignorable="d"
Height="Auto" Width="Auto" MaxWidth="500"
Background="{DynamicResource WindowBackground}">
@@ -11,31 +12,10 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<!--<materialDesign:PackIcon Kind="WarningCircleOutline" Width="20" Height="20" Margin="0,0,5,0"
VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}" />-->
<TextBlock x:Name="TitleTextBlock" FontStyle="Normal" Foreground="{DynamicResource BaseContentBrush}"
HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr TextFieldDialog.Title}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" CommandParameter="{x:Null}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Opacity="0.7" />
<Grid Grid.Row="2" Margin="12">
<nebulaAuth:DialogHeader x:Name="TitleHeader"
Title="{Tr TextFieldDialog.Title}" />
<Grid Grid.Row="1" Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -14,7 +14,7 @@ public partial class TextFieldDialog
InitializeComponent();
if (!string.IsNullOrWhiteSpace(title))
TitleTextBlock.Text = title;
TitleHeader.Title = title;
if (!string.IsNullOrEmpty(msg))
HintAssist.SetHint(TextField, msg);
+6 -27
View File
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
mc:Ignorable="d"
TextElement.Foreground="{DynamicResource BaseContentBrush}"
d:DataContext="{d:DesignInstance other:UpdateDialogVM}"
@@ -15,37 +16,15 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Header -->
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Update" 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">
<Run Text="{Tr UpdateDialog.Title, IsDynamic=False}" />
<Run FontWeight="Bold" Text="{Binding Version, Mode=OneWay}" />
</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 Grid.Row="1" Opacity="0.7" />
<nebulaAuth:DialogHeader IconKind="Update"
Title="{Tr UpdateDialog.Title, IsDynamic=False}"
TitleAccent="{Binding Version, Mode=OneWay}" />
<!-- Changelog -->
<Grid Grid.Row="2" Margin="12,10,12,4">
<Grid Grid.Row="1" Margin="12,10,12,4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -120,7 +99,7 @@
</Grid>
<!-- Buttons -->
<Grid Grid.Row="3" Margin="12,6,12,14">
<Grid Grid.Row="2" Margin="12,6,12,14">
<!-- Normal buttons -->
<StackPanel
+1 -24
View File
@@ -56,30 +56,7 @@
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="LinkBoxOutline" 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 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" Opacity="0.4" Grid.Row="1" />
<nebulaAuth:DialogHeader IconKind="LinkBoxOutline" Title="{Tr LinkerDialog.Title}" />
<nebulaAuth:HintBox FontSize="14"
Visibility="{Binding Tip, Converter={StaticResource NullableToVisibilityConverter}}"
Grid.Row="2" Margin="10,10,10,0"
+12 -26
View File
@@ -9,8 +9,8 @@
mc:Ignorable="d"
TextElement.Foreground="{DynamicResource BaseContentBrush}"
FontFamily="{materialDesign:MaterialDesignFont}"
MinWidth="400"
MaxWidth="400"
MinWidth="500"
MaxWidth="500"
Background="{DynamicResource WindowBackground}"
d:DataContext="{d:DesignInstance other:MafileExporterVM}"
d:Background="#141119"
@@ -19,32 +19,12 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="*" />
<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="FileExport" 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 ExportDialog.ExportTitle}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
IsCancel="True">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Background="DarkGray" Opacity="0.4" Grid.Row="1" />
<Grid Grid.Row="2" Margin="15" TextElement.FontSize="14">
<nebulaAuth:DialogHeader IconKind="FileExport" Title="{Tr ExportDialog.ExportTitle}" />
<Grid Grid.Row="1" Margin="15" TextElement.FontSize="14">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
@@ -133,6 +113,12 @@
IsEnabled="{Binding CurrentTemplate, Converter={StaticResource NullableToBooleanConverter}}">
<StackPanel>
<CheckBox IsChecked="{Binding CurrentTemplate.ExportToZip, FallbackValue=False}"
Margin="3,0,0,3"
Content="{Tr ExportDialog.ExportOptions.ExportToZip}"
ToolTipService.InitialShowDelay="200"
ToolTip="{Tr ExportDialog.Tooltips.ExportToZip}" />
<TextBlock FontWeight="DemiBold"
Text="{Tr ExportDialog.ExportSettingsCommon}" />
@@ -233,8 +219,8 @@
</Grid>
<Separator Grid.Row="3" />
<Button Command="{Binding ExportCommand}" Style="{StaticResource MaterialDesignFlatDarkBgButton}" Grid.Row="4"
<Separator Grid.Row="2" />
<Button Command="{Binding ExportCommand}" Style="{StaticResource MaterialDesignFlatDarkBgButton}" Grid.Row="3"
Margin="20,7,20,7" MaxWidth="150" Content="{Tr ExportDialog.ExportButton}" />
</Grid>
</UserControl>
+4 -25
View File
@@ -29,9 +29,6 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="materialDesign:PackIcon">
@@ -58,35 +55,17 @@
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="FileMove" 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 MafileMoverView.Title}" />
</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" Opacity="0.4" Grid.Row="1" />
<nebulaAuth:DialogHeader IconKind="FileMove" Title="{Tr MafileMoverView.Title}" />
<nebulaAuth:HintBox FontSize="14"
Visibility="{Binding Tip, Converter={StaticResource NullableToVisibilityConverter}}"
Grid.Row="2" Margin="10,10,10,0"
Grid.Row="1" Margin="10,10,10,0"
Text="{Binding Tip}" />
<ContentControl
Grid.Row="3" Margin="20" Content="{Binding CurrentStep}" />
Grid.Row="2" Margin="20" Content="{Binding CurrentStep}" />
<nebulaAuth:HintBox FontSize="14"
Visibility="{Binding Error, Converter={StaticResource NullableToVisibilityConverter}}"
Grid.Row="4" Margin="10,0,10,10"
Grid.Row="3" Margin="10,0,10,10"
Text="{Binding Error}" />
</Grid>
</UserControl>
+6 -25
View File
@@ -20,34 +20,14 @@
FontSize="16">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Title -->
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</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">
<md:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" />
<nebulaAuth:DialogHeader IconKind="Proxy" Title="{Tr ProxyManagerDialog.Title}" />
<!-- Tabs -->
<TabControl Grid.Row="2"
<TabControl Grid.Row="1"
md:ColorZoneAssist.Background="{DynamicResource Base100Brush}"
Style="{StaticResource MaterialDesignUniformTabControl}">
@@ -154,17 +134,18 @@
</Run>
</TextBlock>
<TextBlock Grid.Column="1" VerticalAlignment="Center" FontSize="10" Margin="0,0,2,0"
<TextBlock Grid.Column="1" VerticalAlignment="Center" FontSize="10"
Margin="0,0,2,0"
Foreground="{DynamicResource MaterialDesign.Brush.ForegroundLight}"
Text="{Binding Key, Converter={StaticResource ProxyAccountCountConverter}}" />
<Button Style="{StaticResource MaterialDesignIconButton}" Padding="0"
Width="24"
Height="24" md:RippleAssist.IsDisabled="True" Grid.Column="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding DataContext.SetDefaultCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}">
<md:PackIcon Height="16" Width="16" Kind="Heart" />
<md:PackIcon Height="16" Width="16" Kind="Heart" />
</Button>
</Grid>
</DataTemplate>
@@ -20,7 +20,6 @@
FontSize="16">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
@@ -29,36 +28,10 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- ===== HEADER ===== -->
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<md:PackIcon Kind="ShieldKey" Width="20" Height="20"
Margin="0,0,5,0" VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}" />
<TextBlock Text="{Tr SetAccountPasswordsView.Title}"
FontSize="18"
VerticalAlignment="Center"
Foreground="{DynamicResource BaseContentBrush}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30"
Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right"
Command="{x:Static md:DialogHost.CloseDialogCommand}"
IsCancel="True">
<md:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" />
<nebulaAuth:DialogHeader IconKind="ShieldKey" Title="{Tr SetAccountPasswordsView.Title}" />
<!-- ===== ENCRYPTION PASSWORD SECTION ===== -->
<Grid Grid.Row="2">
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
@@ -109,7 +82,7 @@
<!-- ===== ACCOUNTS INPUT ===== -->
<TextBox Grid.Row="3"
<TextBox Grid.Row="2"
Margin="15,0,15,10"
Text="{Binding AccountsPasswords, UpdateSourceTrigger=PropertyChanged}"
FontSize="13"
@@ -124,14 +97,14 @@
md:TextFieldAssist.TextBoxViewVerticalAlignment="Top"
VerticalContentAlignment="Top" />
<!-- ===== INFO TEXT ===== -->
<TextBlock Grid.Row="4"
<TextBlock Grid.Row="3"
Margin="20,0,20,15"
TextWrapping="Wrap"
FontSize="12"
Foreground="{DynamicResource BaseContentBrush}"
Text="{Tr SetAccountPasswordsView.EncryptionHint}" />
<Button Grid.Row="5"
<Button Grid.Row="4"
Margin="10,0,0,10"
Width="120"
Content="{Tr Common.Save}"
@@ -139,7 +112,7 @@
Style="{StaticResource MaterialDesignOutlinedButton}" Cursor="Hand" />
<!-- ===== HINT / RESULT BOX ===== -->
<nebulaAuth:HintBox Grid.Row="6"
<nebulaAuth:HintBox Grid.Row="5"
Margin="15,0,15,10"
Visibility="{Binding Tip, Converter={StaticResource NullableToVisibilityConverter}}"
CloseCommand="{Binding ClearTipCommand}"
+5 -26
View File
@@ -18,36 +18,15 @@
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Settings" 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 SettingsDialog.Title}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30"
Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
IsEnabled="{Binding ApplyRenameSettingCommand.IsRunning, Converter={StaticResource ReverseBooleanConverter}, Mode=OneWay}"
IsCancel="True">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Margin="0,10,0,0" />
<nebulaAuth:DialogHeader IconKind="Settings"
Title="{Tr SettingsDialog.Title}"
IsCloseEnabled="{Binding ApplyRenameSettingCommand.IsRunning, Converter={StaticResource ReverseBooleanConverter}, Mode=OneWay}" />
<TabControl materialDesign:ColorZoneAssist.Background="{DynamicResource Base100Brush}"
Style="{StaticResource MaterialDesignUniformTabControl}" Grid.Row="2">
Style="{StaticResource MaterialDesignUniformTabControl}" Grid.Row="1">
<TabItem Header="{Tr SettingsDialog.MainSettings}">
<StackPanel Width="400" Margin="10,18,10,40" Orientation="Vertical" HorizontalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignFloatingHintComboBox}" Margin="0,15,0,0"
@@ -196,4 +175,4 @@
</TabControl>
</Grid>
</Grid>
</UserControl>
</UserControl>
+3 -8
View File
@@ -31,6 +31,8 @@ public partial class MainVM //File //TODO: Refactor
bool SdaPasswordPrompted,
SDAEncryptionHelper.Context? SdaContext);
private record MafileImportPlanItem(Mafile Mafile, bool RequiresRelogin, bool HasConflict);
public Settings Settings => Settings.Instance;
@@ -408,11 +410,4 @@ public partial class MainVM //File //TODO: Refactor
if (mafile is not Mafile maf) return false;
return maf.Password != null && PHandler.IsPasswordSet;
}
private record MafileReadResult(
Mafile? Mafile,
bool SdaPasswordPrompted,
SDAEncryptionHelper.Context? SdaContext);
private record MafileImportPlanItem(Mafile Mafile, bool RequiresRelogin, bool HasConflict);
}
}
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
@@ -10,6 +10,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NebulaAuth.Core;
using NebulaAuth.Model.MafileExport;
using NebulaAuth.Model.Mafiles;
namespace NebulaAuth.ViewModel.Other;
@@ -24,8 +25,7 @@ public partial class MafileExporterVM : ObservableObject
public ObservableCollection<MafileExportTemplateVM> Templates { get; }
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(ExportCommand))]
private string? _accountsText;
[ObservableProperty] private string? _accountsText;
private string? _cachedName;
private MafileExportTemplateVM? _currentTemplate;
@@ -160,6 +160,7 @@ public partial class MafileExporterVM : ObservableObject
IncludeNebulaProxy = true,
IncludeNebulaPassword = true,
IncludeNebulaGroup = true,
ExportToZip = false,
Path = null
};
MafileExporterStorage.AddTemplate(template);
@@ -211,21 +212,26 @@ public partial class MafileExporterVM : ObservableObject
}
}
[RelayCommand(CanExecute = nameof(ExportCanExecute))]
[RelayCommand(CanExecute = nameof(CurrentTemplateNotNull))]
private async Task Export()
{
var lines = AccountsText;
var template = CurrentTemplate;
if (string.IsNullOrWhiteSpace(lines) || template == null)
{
return;
}
if (template == null) return;
var split = Regex
.Split(lines, "\r\n|\r|\n")
.Select(x => x.Trim())
.Where(x => !string.IsNullOrWhiteSpace(x))
.ToArray();
string[] split;
if (string.IsNullOrWhiteSpace(AccountsText))
{
split = Storage.MaFiles.Select(m => m.AccountName).ToArray();
}
else
{
split = Regex
.Split(AccountsText, "\r\n|\r|\n")
.Select(x => x.Trim())
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(ExtractLogin)
.ToArray();
}
ResetHintText();
ExportResult res;
@@ -268,6 +274,14 @@ public partial class MafileExporterVM : ObservableObject
AccountsText = text;
}
// Strips the password part from "login:password" input lines.
// SteamId64 values contain no colon, so any colon signals the login:password format.
private static string ExtractLogin(string line)
{
var idx = line.IndexOf(':');
return idx > 0 ? line[..idx] : line;
}
private void SetHintText(string? text, HintBoxSeverity severity = HintBoxSeverity.Error)
{
HintText = text;
@@ -281,12 +295,6 @@ public partial class MafileExporterVM : ObservableObject
#region CanExecute
private bool ExportCanExecute()
{
return CurrentTemplateNotNull() && !string.IsNullOrWhiteSpace(AccountsText);
}
private bool CurrentTemplateNotNull()
{
return CurrentTemplate != null;
@@ -307,6 +315,7 @@ public partial class MafileExporterVM : ObservableObject
public partial class MafileExportTemplateVM : ObservableObject
{
[ObservableProperty] private bool _exportToZip;
[ObservableProperty] private bool _includeIdentitySecret;
[ObservableProperty] private bool _includeNebulaGroup;
[ObservableProperty] private bool _includeNebulaPassword;
@@ -334,6 +343,7 @@ public partial class MafileExportTemplateVM : ObservableObject
IncludeNebulaProxy = x.IncludeNebulaProxy,
IncludeNebulaPassword = x.IncludeNebulaPassword,
IncludeNebulaGroup = x.IncludeNebulaGroup,
ExportToZip = x.ExportToZip,
Path = x.Path
};
}
@@ -352,6 +362,7 @@ public partial class MafileExportTemplateVM : ObservableObject
IncludeNebulaProxy = IncludeNebulaProxy,
IncludeNebulaPassword = IncludeNebulaPassword,
IncludeNebulaGroup = IncludeNebulaGroup,
ExportToZip = ExportToZip,
Path = Path
};
}
@@ -368,6 +379,7 @@ public partial class MafileExportTemplateVM : ObservableObject
model.IncludeNebulaProxy = IncludeNebulaProxy;
model.IncludeNebulaPassword = IncludeNebulaPassword;
model.IncludeNebulaGroup = IncludeNebulaGroup;
model.ExportToZip = ExportToZip;
model.Path = Path;
}
}
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
namespace NebulaAuth.ViewModel.Other;
public partial class MafileImportDialogVM : ObservableObject
{
public ObservableCollection<string> Groups { get; }
public int TotalCount { get; }
public int ConflictCount { get; }
public bool HasConflicts => ConflictCount > 0;
[ObservableProperty] private bool _addToGroup;
[ObservableProperty] private string? _group;
[ObservableProperty] private bool _overwriteConflicts;
public MafileImportDialogVM(IEnumerable<string> groups, int totalCount, int conflictCount)
{
Groups = new ObservableCollection<string>(groups);
TotalCount = totalCount;
ConflictCount = conflictCount;
}
}
public record MafileImportDialogResult(string? Group, bool OverwriteConflicts);
+1 -1
View File
@@ -249,4 +249,4 @@ public partial class SettingsVM : ObservableObject
}
#endregion
}
}