mirror of
https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies.git
synced 2026-07-26 14:51:42 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16f0cc2b2d | |||
| cd0416705f | |||
| 2d06cb81f9 | |||
| ed5d3c2eda | |||
| 07eb9f15a9 | |||
| c39660fc55 | |||
| 038f62b4db | |||
| 5029f78247 | |||
| b9452c4baf | |||
| ec71b9881e | |||
| 4b727af1fa | |||
| 9897ca21a6 | |||
| 631068e2f3 | |||
| 0cc9a3d100 | |||
| 7348bc2673 | |||
| 3a9d929c9a | |||
| 25818997af | |||
| 5836ed4508 | |||
| 537d5d907f | |||
| 0e90f1826b |
@@ -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">
|
<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/CodeInspection/Highlighting/InspectionSeverities/=CheckNamespace/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue"><Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
|
||||||
|
<TypePattern DisplayName="Non-reorderable types" Priority="99999999">
|
||||||
|
<TypePattern.Match>
|
||||||
|
<Or>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Interface" />
|
||||||
|
<Or>
|
||||||
|
<HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
|
||||||
|
<HasAttribute Name="System.Runtime.InteropServices.ComImport" />
|
||||||
|
</Or>
|
||||||
|
</And>
|
||||||
|
<Kind Is="Struct" />
|
||||||
|
<HasAttribute Name="System.Runtime.InteropServices.StructLayoutAttribute" />
|
||||||
|
<HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" />
|
||||||
|
</Or>
|
||||||
|
</TypePattern.Match>
|
||||||
|
</TypePattern>
|
||||||
|
<TypePattern DisplayName="xUnit.net Test Classes" RemoveRegions="All">
|
||||||
|
<TypePattern.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Class" />
|
||||||
|
<HasMember>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Method" />
|
||||||
|
<HasAttribute Inherited="True" Name="Xunit.FactAttribute" />
|
||||||
|
<HasAttribute Inherited="True" Name="Xunit.TheoryAttribute" />
|
||||||
|
</And>
|
||||||
|
</HasMember>
|
||||||
|
</And>
|
||||||
|
</TypePattern.Match>
|
||||||
|
<Entry DisplayName="Fields">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Field" />
|
||||||
|
<Not>
|
||||||
|
<Static />
|
||||||
|
</Not>
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Readonly />
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Constructors">
|
||||||
|
<Entry.Match>
|
||||||
|
<Kind Is="Constructor" />
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Static />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Teardown Methods">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Method" />
|
||||||
|
<ImplementsInterface Name="System.IDisposable" />
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="All other members" />
|
||||||
|
<Entry DisplayName="Test Methods" Priority="100">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Method" />
|
||||||
|
<HasAttribute Name="Xunit.FactAttribute" />
|
||||||
|
<HasAttribute Name="Xunit.TheoryAttribute" />
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
</TypePattern>
|
||||||
|
<TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
|
||||||
|
<TypePattern.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Class" />
|
||||||
|
<Or>
|
||||||
|
<HasAttribute Inherited="True" Name="NUnit.Framework.TestFixtureAttribute" />
|
||||||
|
<HasAttribute Inherited="True" Name="NUnit.Framework.TestFixtureSourceAttribute" />
|
||||||
|
<HasMember>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Method" />
|
||||||
|
<HasAttribute Name="NUnit.Framework.TestAttribute" />
|
||||||
|
<HasAttribute Name="NUnit.Framework.TestCaseAttribute" />
|
||||||
|
<HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" />
|
||||||
|
</And>
|
||||||
|
</HasMember>
|
||||||
|
</Or>
|
||||||
|
</And>
|
||||||
|
</TypePattern.Match>
|
||||||
|
<Entry DisplayName="Setup/Teardown Methods">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Method" />
|
||||||
|
<Or>
|
||||||
|
<HasAttribute Inherited="True" Name="NUnit.Framework.SetUpAttribute" />
|
||||||
|
<HasAttribute Inherited="True" Name="NUnit.Framework.TearDownAttribute" />
|
||||||
|
<HasAttribute Inherited="True" Name="NUnit.Framework.TestFixtureSetUpAttribute" />
|
||||||
|
<HasAttribute Inherited="True" Name="NUnit.Framework.TestFixtureTearDownAttribute" />
|
||||||
|
<HasAttribute Inherited="True" Name="NUnit.Framework.OneTimeSetUpAttribute" />
|
||||||
|
<HasAttribute Inherited="True" Name="NUnit.Framework.OneTimeTearDownAttribute" />
|
||||||
|
</Or>
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="All other members" />
|
||||||
|
<Entry DisplayName="Test Methods" Priority="100">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Method" />
|
||||||
|
<HasAttribute Name="NUnit.Framework.TestAttribute" />
|
||||||
|
<HasAttribute Name="NUnit.Framework.TestCaseAttribute" />
|
||||||
|
<HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" />
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
</TypePattern>
|
||||||
|
<TypePattern DisplayName="Grains">
|
||||||
|
<TypePattern.Match>
|
||||||
|
<And>
|
||||||
|
<Or>
|
||||||
|
<ImplementsInterface Name="^Orleans\.IGrain$" />
|
||||||
|
<ImplementsInterface Name="Orleans.IGrainBase" />
|
||||||
|
<ImplementsInterface Name="Achiefy.Orleans.Tenancy.Abstractions.ITenantGrain" />
|
||||||
|
<InheritsFromType Name="Orleans.Grain" />
|
||||||
|
<InheritsFromType Name="Achiefy.Tenant.Application.Stateful.Core.TenantGrain" />
|
||||||
|
</Or>
|
||||||
|
<Not>
|
||||||
|
<Abstract />
|
||||||
|
</Not>
|
||||||
|
<Kind Is="Class" />
|
||||||
|
</And>
|
||||||
|
</TypePattern.Match>
|
||||||
|
<Entry DisplayName="Public Delegates" Priority="100">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Access Is="Public" />
|
||||||
|
<Kind Is="Delegate" />
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Public Enums" Priority="100">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Access Is="Public" />
|
||||||
|
<Kind Is="Enum" />
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Nested Records">
|
||||||
|
<Entry.Match>
|
||||||
|
<Kind Is="Record" />
|
||||||
|
</Entry.Match>
|
||||||
|
</Entry>
|
||||||
|
<Group DisplayName="Group">
|
||||||
|
<Entry DisplayName="Static Fields and Constants">
|
||||||
|
<Entry.Match>
|
||||||
|
<Or>
|
||||||
|
<Kind Is="Constant" />
|
||||||
|
<And>
|
||||||
|
<Kind Is="Field" />
|
||||||
|
<Static />
|
||||||
|
</And>
|
||||||
|
</Or>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Kind Is="0" Order="Constant Field" />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Properties, Indexers">
|
||||||
|
<Entry.Match>
|
||||||
|
<Or>
|
||||||
|
<Kind Is="Property" />
|
||||||
|
<Kind Is="Indexer" />
|
||||||
|
</Or>
|
||||||
|
</Entry.Match>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Fields">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Field" />
|
||||||
|
<Not>
|
||||||
|
<Static />
|
||||||
|
</Not>
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Readonly />
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
</Group>
|
||||||
|
<Entry DisplayName="Constructors">
|
||||||
|
<Entry.Match>
|
||||||
|
<Kind Is="Constructor" />
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Static />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Lifecycle Methods">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Method" />
|
||||||
|
<Name Is="^On(Activate|Deactivate)Async.*$" />
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="All other members" />
|
||||||
|
<Entry DisplayName="Nested Types">
|
||||||
|
<Entry.Match>
|
||||||
|
<Kind Is="Type" />
|
||||||
|
</Entry.Match>
|
||||||
|
</Entry>
|
||||||
|
</TypePattern>
|
||||||
|
<TypePattern DisplayName="Default Pattern">
|
||||||
|
<Entry DisplayName="Public Enums" Priority="100">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Access Is="Public" />
|
||||||
|
<Kind Is="Enum" />
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Public Delegates" Priority="100">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Access Is="Public" />
|
||||||
|
<Kind Is="Delegate" />
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Nested Records">
|
||||||
|
<Entry.Match>
|
||||||
|
<Kind Is="Record" />
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Static />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Group DisplayName="Group">
|
||||||
|
<Entry DisplayName="Static Fields and Constants">
|
||||||
|
<Entry.Match>
|
||||||
|
<Or>
|
||||||
|
<Kind Is="Constant" />
|
||||||
|
<And>
|
||||||
|
<Kind Is="Field" />
|
||||||
|
<Static />
|
||||||
|
</And>
|
||||||
|
</Or>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Kind Is="0" Order="Constant Field" />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Properties, Indexers">
|
||||||
|
<Entry.Match>
|
||||||
|
<Or>
|
||||||
|
<Kind Is="Property" />
|
||||||
|
<Kind Is="Indexer" />
|
||||||
|
</Or>
|
||||||
|
</Entry.Match>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="Fields">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Kind Is="Field" />
|
||||||
|
<Not>
|
||||||
|
<Static />
|
||||||
|
</Not>
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Readonly />
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
</Group>
|
||||||
|
<Entry DisplayName="Constructors">
|
||||||
|
<Entry.Match>
|
||||||
|
<Kind Is="Constructor" />
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Static />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
|
<Entry DisplayName="All other members" />
|
||||||
|
<Entry DisplayName="Nested Types">
|
||||||
|
<Entry.Match>
|
||||||
|
<Kind Is="Type" />
|
||||||
|
</Entry.Match>
|
||||||
|
</Entry>
|
||||||
|
</TypePattern>
|
||||||
|
</Patterns></s:String>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=MAAC/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=MAAC/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"Website": "https://achiefy.pro/?nebula=true",
|
||||||
|
"Documentation": "https://achiefy-project.gitbook.io/nebulaauth"
|
||||||
|
}
|
||||||
+18
-18
@@ -63,25 +63,25 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="changelog-container">
|
<div class="changelog-container">
|
||||||
<div class="change">
|
<div class="change">
|
||||||
<div class="version">Version 1.8.1</div>
|
<div class="version">Version 1.8.1</div>
|
||||||
<div class="date">25.01.2026</div>
|
<div class="date">25.01.2026</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>NEW:</b> Added Mafile Export tool with templates, batch export and flexible field filtering.</li>
|
<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>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>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>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>FIX:</b> Fixed crashes related to duplicate mafiles, timers, search filtering and import logic.</li>
|
||||||
<li>
|
<li>
|
||||||
<b>DETAILS:</b> Full patch notes:
|
<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-eng">ENG</a> |
|
||||||
<a href="https://teletype.in/@achies_raw/nebula-1-8-1-rus">RUS</a>
|
<a href="https://teletype.in/@achies_raw/nebula-1-8-1-rus">RUS</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -63,16 +63,16 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="changelog-container">
|
<div class="changelog-container">
|
||||||
<div class="change">
|
<div class="change">
|
||||||
<div class="version">Version 1.8.2</div>
|
<div class="version">Version 1.8.2</div>
|
||||||
<div class="date">10.02.2026</div>
|
<div class="date">10.02.2026</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>FIX:</b> AutoConfirm timer now correctly resets the status after a successful request (Warning → Ok).</li>
|
<li><b>FIX:</b> AutoConfirm timer now correctly resets the status after a successful request (Warning → Ok).</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"version": "1.8.5",
|
||||||
|
"date": "2026-06-19",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"type": "NEW",
|
||||||
|
"text": "Bulk proxy assignment: assign proxies to multiple accounts at once via flexible login:proxy, login:ID or login-only input",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/22"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "NEW",
|
||||||
|
"text": "Import dialog now allows assigning imported mafiles to a group directly; added option to skip confirmation when no conflicts are detected",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/24"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "NEW",
|
||||||
|
"text": "Assign random free proxy to the account from context menu",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/22"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "NEW",
|
||||||
|
"text": "Export: added ZIP archive output, export-all mode when the input field is empty, and support for login:password input format",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/28"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "IMPROVEMENT",
|
||||||
|
"text": "When a session permanently expires during a user-initiated action, a login dialog is now shown instead of a generic error notification",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "IMPROVEMENT",
|
||||||
|
"text": "Proxy manager: account count badges now show how many accounts are assigned to each proxy entry",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/22"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "IMPROVEMENT",
|
||||||
|
"text": "Added login:pass@ip:port proxy format support",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "IMPROVEMENT",
|
||||||
|
"text": "Improved dialog header design",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/27"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "IMPROVEMENT",
|
||||||
|
"text": "Website and Documentation links are now available from the links window",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/30"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "FIX",
|
||||||
|
"text": "Application no longer fails to start when Steam time synchronization is unavailable (network issues, firewall)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "FIX",
|
||||||
|
"text": "Fixed incorrect Steam Guard error message shown in the Mafile Mover dialog",
|
||||||
|
"link": "https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/pull/23"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -77,6 +77,10 @@ public partial class HintBox : UserControl
|
|||||||
IconKind = PackIconKind.ErrorOutline;
|
IconKind = PackIconKind.ErrorOutline;
|
||||||
IconBrush = (Brush) Application.Current.FindResource("ErrorBrush")!;
|
IconBrush = (Brush) Application.Current.FindResource("ErrorBrush")!;
|
||||||
break;
|
break;
|
||||||
|
case HintBoxSeverity.Warning:
|
||||||
|
IconKind = PackIconKind.WarningOutline;
|
||||||
|
IconBrush = (Brush) Application.Current.FindResource("WarningBrush")!;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
IconKind = PackIconKind.InfoCircleOutline;
|
IconKind = PackIconKind.InfoCircleOutline;
|
||||||
IconBrush = (Brush) Application.Current.FindResource("InfoBrush")!;
|
IconBrush = (Brush) Application.Current.FindResource("InfoBrush")!;
|
||||||
@@ -94,5 +98,6 @@ public partial class HintBox : UserControl
|
|||||||
public enum HintBoxSeverity
|
public enum HintBoxSeverity
|
||||||
{
|
{
|
||||||
Info,
|
Info,
|
||||||
|
Warning,
|
||||||
Error
|
Error
|
||||||
}
|
}
|
||||||
@@ -15,13 +15,15 @@ namespace NebulaAuth.Core;
|
|||||||
|
|
||||||
public static class DialogsController
|
public static class DialogsController
|
||||||
{
|
{
|
||||||
public static async Task<LoginAgainVM?> ShowLoginAgainDialog(string username, string? currentPassword = null)
|
public static async Task<LoginAgainVM?> ShowLoginAgainDialog(string username, string? currentPassword = null,
|
||||||
|
bool showNoProxyWarning = false)
|
||||||
{
|
{
|
||||||
var vm = new LoginAgainVM
|
var vm = new LoginAgainVM
|
||||||
{
|
{
|
||||||
UserName = username,
|
UserName = username,
|
||||||
Password = currentPassword ?? string.Empty,
|
Password = currentPassword ?? string.Empty,
|
||||||
SavePassword = PHandler.IsPasswordSet
|
SavePassword = PHandler.IsPasswordSet,
|
||||||
|
ShowNoProxyWarning = showNoProxyWarning
|
||||||
};
|
};
|
||||||
var content = new LoginAgainDialog
|
var content = new LoginAgainDialog
|
||||||
{
|
{
|
||||||
@@ -73,6 +75,22 @@ public static class DialogsController
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<MafileImportDialogResult?> ShowMafileImportDialog(IEnumerable<string> groups,
|
||||||
|
int totalCount, int conflictCount)
|
||||||
|
{
|
||||||
|
var vm = new MafileImportDialogVM(groups, totalCount, conflictCount);
|
||||||
|
var content = new MafileImportDialog
|
||||||
|
{
|
||||||
|
DataContext = vm
|
||||||
|
};
|
||||||
|
var result = await DialogHost.Show(content);
|
||||||
|
return result is MafileImportDialogVM
|
||||||
|
? new MafileImportDialogResult(
|
||||||
|
!vm.AddToGroup || string.IsNullOrWhiteSpace(vm.Group) ? null : vm.Group.Trim(),
|
||||||
|
vm.OverwriteConflicts)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<bool> ShowProxyManager()
|
public static async Task<bool> ShowProxyManager()
|
||||||
{
|
{
|
||||||
var vm = new ProxyManagerVM();
|
var vm = new ProxyManagerVM();
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NebulaAuth.Model;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace NebulaAuth.Core;
|
||||||
|
|
||||||
|
public static class LinksManager
|
||||||
|
{
|
||||||
|
private const string LINKS_URL =
|
||||||
|
"https://raw.githubusercontent.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/master/NebulaAuth/links.json";
|
||||||
|
|
||||||
|
private static readonly HttpClient HttpClient = new();
|
||||||
|
|
||||||
|
public static string? WebsiteUrl { get; private set; }
|
||||||
|
public static string? DocumentationUrl { get; private set; }
|
||||||
|
|
||||||
|
public static async Task FetchAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = await HttpClient.GetStringAsync(LINKS_URL).ConfigureAwait(false);
|
||||||
|
var links = JsonConvert.DeserializeObject<RemoteLinks>(json);
|
||||||
|
WebsiteUrl = links?.Website;
|
||||||
|
DocumentationUrl = links?.Documentation;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Shell.Logger.Debug(ex, "Failed to fetch remote links");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -196,6 +196,16 @@
|
|||||||
"es": "Grupo",
|
"es": "Grupo",
|
||||||
"tr": "Grup",
|
"tr": "Grup",
|
||||||
"kk": "Топ"
|
"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": {
|
"Tooltips": {
|
||||||
@@ -288,17 +298,27 @@
|
|||||||
"es": "Incluir datos de grupo compatibles con Nebula.",
|
"es": "Incluir datos de grupo compatibles con Nebula.",
|
||||||
"tr": "Nebula uyumlu grup verilerini dahil et.",
|
"tr": "Nebula uyumlu grup verilerini dahil et.",
|
||||||
"kk": "Nebula үйлесімді топ деректерін қосу."
|
"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": {
|
"ExportAccountsPlaceholder": {
|
||||||
"ru": "Введите логины аккаунтов или SteamID (по одному на строку) для экспорта в выбранную директорию.",
|
"ru": "Введите логины или SteamID (по одному на строку). Поддерживается формат логин:пароль — пароль будет проигнорирован. Оставьте пустым для экспорта всех аккаунтов.",
|
||||||
"en": "Enter account logins or SteamIDs (one per line) to export to the selected directory.",
|
"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 (по одному на рядок) для експорту у вибрану директорію.",
|
"uk": "Введіть логіни або SteamID (по одному на рядок). Підтримується формат логін:пароль — пароль буде проігноровано. Залиште порожнім для експорту всіх акаунтів.",
|
||||||
"fr": "Entrez les identifiants de compte ou les SteamID (un par ligne) pour exporter vers le répertoire sélectionné.",
|
"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(每行一个)。",
|
"zh": "输入登录名或 SteamID(每行一个)。支持 login:password 格式——密码将被忽略。留空则导出所有账户。",
|
||||||
"es": "Introduce los logins de las cuentas o SteamID (uno por línea) para exportarlos al directorio seleccionado.",
|
"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": "Seçilen dizine dışa aktarmak için hesap girişlerini veya SteamID’leri (her satıra bir tane) girin.",
|
"tr": "Girişleri veya SteamID’leri 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 (әр жолға біреуден) енгізіңіз."
|
"kk": "Логиндерді немесе SteamID (әр жолға біреуден) енгізіңіз. логин:құпиясөз форматы қолданылады — құпиясөз еленбейді. Барлық аккаунттарды экспорттау үшін бос қалдырыңыз."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,5 +35,67 @@
|
|||||||
"tr": "Değer girin",
|
"tr": "Değer girin",
|
||||||
"kk": "Мән енгізіңіз"
|
"kk": "Мән енгізіңіз"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"MafileImportDialog": {
|
||||||
|
"Title": {
|
||||||
|
"en": "Mafile import",
|
||||||
|
"ru": "Импорт мафайлов",
|
||||||
|
"zh": "导入 mafile",
|
||||||
|
"uk": "Імпорт mafile",
|
||||||
|
"fr": "Import de mafiles",
|
||||||
|
"es": "Importación de mafiles",
|
||||||
|
"tr": "Mafile içe aktarma",
|
||||||
|
"kk": "Mafile импорттау"
|
||||||
|
},
|
||||||
|
"TotalCount": {
|
||||||
|
"en": "Mafiles to import",
|
||||||
|
"ru": "Мафайлов к импорту",
|
||||||
|
"zh": "要导入的 mafile:",
|
||||||
|
"uk": "Mafile до імпорту:",
|
||||||
|
"fr": "Mafiles à importer :",
|
||||||
|
"es": "Mafiles para importar:",
|
||||||
|
"tr": "İçe aktarılacak mafile:",
|
||||||
|
"kk": "Импортталатын mafile:"
|
||||||
|
},
|
||||||
|
"ConflictCount": {
|
||||||
|
"en": "Already exist",
|
||||||
|
"ru": "Уже существуют",
|
||||||
|
"zh": "已存在:",
|
||||||
|
"uk": "Уже існують:",
|
||||||
|
"fr": "Déjà existants :",
|
||||||
|
"es": "Ya existen:",
|
||||||
|
"tr": "Zaten mevcut:",
|
||||||
|
"kk": "Бұрыннан бар:"
|
||||||
|
},
|
||||||
|
"OverwriteConflicts": {
|
||||||
|
"en": "Overwrite conflicting mafiles",
|
||||||
|
"ru": "Перезаписать конфликтующие мафайлы",
|
||||||
|
"zh": "覆盖冲突的 mafile",
|
||||||
|
"uk": "Перезаписати конфліктні mafile",
|
||||||
|
"fr": "Remplacer les mafiles en conflit",
|
||||||
|
"es": "Sobrescribir mafiles en conflicto",
|
||||||
|
"tr": "Çakışan mafile'ların üzerine yaz",
|
||||||
|
"kk": "Қақтығысатын mafile файлдарын қайта жазу"
|
||||||
|
},
|
||||||
|
"AddToGroup": {
|
||||||
|
"en": "Add imported accounts to a group",
|
||||||
|
"ru": "Добавить импортированные аккаунты в группу",
|
||||||
|
"zh": "将导入的账号添加到组",
|
||||||
|
"uk": "Додати імпортовані акаунти до групи",
|
||||||
|
"fr": "Ajouter les comptes importés à un groupe",
|
||||||
|
"es": "Añadir las cuentas importadas a un grupo",
|
||||||
|
"tr": "İçe aktarılan hesapları bir gruba ekle",
|
||||||
|
"kk": "Импортталған аккаунттарды топқа қосу"
|
||||||
|
},
|
||||||
|
"GroupFieldHint": {
|
||||||
|
"en": "Existing or new group",
|
||||||
|
"ru": "Существующая или новая группа",
|
||||||
|
"zh": "现有或新组",
|
||||||
|
"uk": "Наявна або нова група",
|
||||||
|
"fr": "Groupe existant ou nouveau",
|
||||||
|
"es": "Grupo existente o nuevo",
|
||||||
|
"tr": "Mevcut veya yeni grup",
|
||||||
|
"kk": "Бар немесе жаңа топ"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,16 @@
|
|||||||
"es": "Pulsa 'DEL' para eliminar",
|
"es": "Pulsa 'DEL' para eliminar",
|
||||||
"tr": "Silmek için 'DEL' tuşuna bas",
|
"tr": "Silmek için 'DEL' tuşuna bas",
|
||||||
"kk": "Жою үшін 'DEL' пернесін басыңыз"
|
"kk": "Жою үшін 'DEL' пернесін басыңыз"
|
||||||
|
},
|
||||||
|
"NoProxyWarning": {
|
||||||
|
"en": "No proxy is assigned",
|
||||||
|
"ru": "Прокси не установлен",
|
||||||
|
"zh": "未分配代理",
|
||||||
|
"uk": "Проксі не призначено",
|
||||||
|
"fr": "Aucun proxy assigné",
|
||||||
|
"es": "No hay ningún proxy asignado",
|
||||||
|
"tr": "Proxy atanmamış",
|
||||||
|
"kk": "Прокси тағайындалмаған"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,14 +42,14 @@
|
|||||||
"kk": "RCode: {0}\r\nФайл атауы: {1}.mafile"
|
"kk": "RCode: {0}\r\nФайл атауы: {1}.mafile"
|
||||||
},
|
},
|
||||||
"GuardIsNotActive": {
|
"GuardIsNotActive": {
|
||||||
"ru": "Steam Guard установлен на данном аккаунте. Чтобы привязать mafile к аккаунту, воспользуйтесь окном \"Привязать\"",
|
"ru": "Steam Guard НЕ установлен на данном аккаунте. Чтобы привязать mafile к аккаунту, воспользуйтесь окном \"Привязать\"",
|
||||||
"en": "Steam Guard is set on this account. To link mafile to the account, use the 'Link' window",
|
"en": "Steam Guard is NOT set on this account. To link mafile to the account, use the 'Link' window",
|
||||||
"zh": "此账户已启用令牌。要将 mafile 绑定到此账户,请使用“绑定”窗口。",
|
"zh": "此账户尚未启用令牌。要将 mafile 绑定到此账户,请使用“绑定”窗口。",
|
||||||
"uk": "Steam Guard встановлено на цьому акаунті. Щоб прив'язати mafile до акаунту, скористайтеся вікном 'Прив'язати'",
|
"uk": "Steam Guard НЕ встановлено на цьому акаунті. Щоб прив'язати mafile до акаунту, скористайтеся вікном 'Прив'язати'",
|
||||||
"fr": "Steam Guard est configuré sur ce compte. Pour lier mafile au compte, utilisez la fenêtre 'Lien'",
|
"fr": "Steam Guard n'est PAS configuré sur ce compte. Pour lier le mafile au compte, utilisez la fenêtre 'Lier'",
|
||||||
"es": "Steam Guard está activado en esta cuenta. Para vincular el mafile a la cuenta, usa la ventana 'Vincular'",
|
"es": "Steam Guard NO está activado en esta cuenta. Para vincular el mafile a la cuenta, usa la ventana 'Vincular'",
|
||||||
"tr": "Steam Guard bu hesapta zaten etkin. Mafile'ı hesaba bağlamak için 'Bağla' penceresini kullanın",
|
"tr": "Steam Guard bu hesapta etkin DEĞİL. Mafile'ı hesaba bağlamak için 'Bağla' penceresini kullanın",
|
||||||
"kk": "Бұл аккаунтта Steam Guard орнатылған. Mafile-ды аккаунтқа байланыстыру үшін 'Байланыстыру' терезесін пайдаланыңыз"
|
"kk": "Бұл аккаунтта Steam Guard орнатылмаған. Mafile-ды аккаунтқа байланыстыру үшін 'Байланыстыру' терезесін пайдаланыңыз"
|
||||||
},
|
},
|
||||||
"SeemsNoPhoneNumber": {
|
"SeemsNoPhoneNumber": {
|
||||||
"en": "The account has no phone number linked, returned Fail code (2)",
|
"en": "The account has no phone number linked, returned Fail code (2)",
|
||||||
|
|||||||
@@ -262,25 +262,25 @@
|
|||||||
"kk": "Дискке сақталмайды"
|
"kk": "Дискке сақталмайды"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"LegacyMafileMode": {
|
"ConfirmMafileImport": {
|
||||||
"en": "Common mafiles format",
|
"en": "Ask confirmation when importing mafiles",
|
||||||
"ru": "Общепринятый формат мафайлов",
|
"ru": "Спрашивать подтверждение при импорте мафайлов",
|
||||||
"zh": "常见的邮件文件格式",
|
"zh": "导入 mafile 时请求确认",
|
||||||
"uk": "Загальноприйнятий формат мафайлів",
|
"uk": "Запитувати підтвердження під час імпорту mafile",
|
||||||
"fr": "Format de mafiles commun",
|
"fr": "Demander confirmation lors de l'import des mafiles",
|
||||||
"es": "Formato común de mafiles",
|
"es": "Pedir confirmación al importar mafiles",
|
||||||
"tr": "Ortak mafile formatı",
|
"tr": "Mafile içe aktarırken onay sor",
|
||||||
"kk": "Жалпы mafile форматы"
|
"kk": "Mafile импорттау кезінде растауды сұрау"
|
||||||
},
|
},
|
||||||
"LegacyMafileModeHint": {
|
"ConfirmMafileImportHint": {
|
||||||
"en": "Save mafiles in compatibility format with Steam Desktop Authenticator and other applications",
|
"en": "Allows selecting a group when importing maFiles. Does not affect showing the dialog when file conflicts occur",
|
||||||
"ru": "Сохранять мафайлы в старом формате для совместимости со Steam Desktop Authenticator и другими приложениями",
|
"ru": "Позволяет выбрать группу при импорте maFiles. Не влияет на показ окна при конфликте файлов",
|
||||||
"zh": "以与 Steam 桌面认证器及其他应用程序兼容的格式保存 mafiles",
|
"zh": "允许在导入 maFiles 时选择分组。不影响发生文件冲突时窗口的显示",
|
||||||
"uk": "Зберігати мафайли у старому форматі для сумісності зі Steam Desktop Authenticator та іншими додатками",
|
"uk": "Дозволяє вибрати групу під час імпорту maFiles. Не впливає на показ вікна при конфлікті файлів",
|
||||||
"fr": "Enregistrer les mafiles dans un format compatible avec Steam Desktop Authenticator et d'autres applications",
|
"fr": "Permet de choisir un groupe lors de l'import des maFiles. N'affecte pas l'affichage de la fenêtre en cas de conflit de fichiers",
|
||||||
"es": "Guardar mafiles en formato compatible con Steam Desktop Authenticator y otras aplicaciones",
|
"es": "Permite seleccionar un grupo al importar maFiles. No afecta a la aparición de la ventana cuando hay conflictos de archivos",
|
||||||
"tr": "Mafile'ları Steam Desktop Authenticator ve diğer uygulamalarla uyumlu formatta kaydet",
|
"tr": "maFiles içe aktarılırken grup seçilmesine izin verir. Dosya çakışmalarında pencerenin gösterilmesini etkilemez",
|
||||||
"kk": "Mafile файлдарын Steam Desktop Authenticator және басқа қолданбалармен үйлесімді форматта сақтау"
|
"kk": "maFiles импорттау кезінде топ таңдауға мүмкіндік береді. Файл қайшылықтары болғанда терезенің көрсетілуіне әсер етпейді"
|
||||||
},
|
},
|
||||||
"AllowAutoUpdate": {
|
"AllowAutoUpdate": {
|
||||||
"en": "Allow auto update",
|
"en": "Allow auto update",
|
||||||
@@ -333,4 +333,4 @@
|
|||||||
"kk": "Steam техникалық жұмыстар жүргізген кезде әр сейсенбіде (GMT бойынша сәрсенбі түні) пайда болатын және авторастау таймерлерін қажетсіз өшіретін қателерді елемеу"
|
"kk": "Steam техникалық жұмыстар жүргізген кезде әр сейсенбіде (GMT бойынша сәрсенбі түні) пайда болатын және авторастау таймерлерін қажетсіз өшіретін қателерді елемеу"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,16 +101,6 @@
|
|||||||
"tr": "Onay hatası",
|
"tr": "Onay hatası",
|
||||||
"kk": "Растау қатесі"
|
"kk": "Растау қатесі"
|
||||||
},
|
},
|
||||||
"ConfirmMafileOverwrite": {
|
|
||||||
"ru": "Внимание, мафайл(-ы) уже присутствует в папке mafiles.\r\nПерезаписать мафайлы, которые конфликтуют?",
|
|
||||||
"en": "Attention, mafile(-s) already exists in mafiles folder.\r\nOverwrite conflicting mafiles?",
|
|
||||||
"zh": "注意,mafile 已经存在于 mafiles 文件夹中。\r\n覆盖冲突的 mafiles 吗?",
|
|
||||||
"uk": "Увага, мафайл(-и) вже присутній у папці mafiles.\r\nПерезаписати мафайли, які конфліктують?",
|
|
||||||
"fr": "Attention, mafiles déjà présents dans le dossier mafiles.\r\nRemplacer les mafiles en conflit?",
|
|
||||||
"es": "Atención, los mafiles ya existen en la carpeta mafiles.\r\n¿Sobrescribir los mafiles en conflicto?",
|
|
||||||
"tr": "Dikkat, mafile(ler) zaten mafiles klasöründe mevcut.\r\nÇakışan mafile'lar üzerine yazılsın mı?",
|
|
||||||
"kk": "Назар аударыңыз, mafile(дер) mafiles қалтасында бар.\r\nҚайшылық тудырған mafile файлдарының үстінен жазу керек пе?"
|
|
||||||
},
|
|
||||||
"MafileImportError": {
|
"MafileImportError": {
|
||||||
"ru": "Ошибка при импорте мафайла",
|
"ru": "Ошибка при импорте мафайла",
|
||||||
"en": "Mafile import error",
|
"en": "Mafile import error",
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
DialogClosed="DialogHost_DialogClosed"
|
DialogClosed="DialogHost_DialogClosed"
|
||||||
ApplyBlurBackground="{Binding Settings.ApplyBlurBackground}"
|
ApplyBlurBackground="{Binding Settings.ApplyBlurBackground}"
|
||||||
BlurRadius="12"
|
BlurRadius="12"
|
||||||
|
DialogContentUniformCornerRadius="12"
|
||||||
x:Name="DialogHostInstance">
|
x:Name="DialogHostInstance">
|
||||||
|
|
||||||
<Grid ZIndex="0">
|
<Grid ZIndex="0">
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public static class MAACRequestHandler
|
|||||||
{
|
{
|
||||||
return withSessionHandler
|
return withSessionHandler
|
||||||
? Result<T>.Success(await SessionHandler.Handle(req, client.Mafile, client.Chp(),
|
? Result<T>.Success(await SessionHandler.Handle(req, client.Mafile, client.Chp(),
|
||||||
GetTimerPrefix(client.Mafile)))
|
GetTimerPrefix(client.Mafile), false))
|
||||||
: Result<T>.Success(await req());
|
: Result<T>.Success(await req());
|
||||||
}
|
}
|
||||||
catch (SessionInvalidException ex)
|
catch (SessionInvalidException ex)
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ public class MafileExportTemplate
|
|||||||
public bool IncludeNebulaPassword { get; set; }
|
public bool IncludeNebulaPassword { get; set; }
|
||||||
public bool IncludeNebulaGroup { get; set; }
|
public bool IncludeNebulaGroup { get; set; }
|
||||||
public string? Path { 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;
|
||||||
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AchiesUtilities.Extensions;
|
using AchiesUtilities.Extensions;
|
||||||
using NebulaAuth.Core;
|
using NebulaAuth.Core;
|
||||||
@@ -36,48 +39,79 @@ public static class MafileExporter
|
|||||||
return new ExportResult(LocManager.GetCodeBehindOrDefault("AccessDenied", "MafileExporter.AccessDenied"));
|
return new ExportResult(LocManager.GetCodeBehindOrDefault("AccessDenied", "MafileExporter.AccessDenied"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var exported = new Dictionary<Mafile, string>();
|
var exported = new Dictionary<Mafile, string>();
|
||||||
var notFound = new List<string>();
|
var notFound = new List<string>();
|
||||||
var conflict = new List<string>();
|
var conflict = new List<string>();
|
||||||
|
|
||||||
|
var toExport = new List<(string key, Mafile mafile)>();
|
||||||
foreach (var key in keys)
|
foreach (var key in keys)
|
||||||
{
|
{
|
||||||
SteamId? steamId = null;
|
SteamId? steamId = null;
|
||||||
if (SteamId64.TryParse(key, out var id64))
|
if (SteamId64.TryParse(key, out var id64))
|
||||||
{
|
|
||||||
steamId = id64;
|
steamId = id64;
|
||||||
}
|
|
||||||
|
|
||||||
var maf = Storage.MaFiles.FirstOrDefault(m => m.AccountName.EqualsIgnoreCase(key) || m.SteamId == steamId);
|
var maf = Storage.MaFiles.FirstOrDefault(m => m.AccountName.EqualsIgnoreCase(key) || m.SteamId == steamId);
|
||||||
if (maf != null)
|
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);
|
var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||||
if (fileName == null)
|
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);
|
conflict.Add(key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
exported[maf] = fileName;
|
await File.WriteAllTextAsync(fullPath, content);
|
||||||
}
|
exported[maf] = fullPath;
|
||||||
else
|
|
||||||
{
|
|
||||||
notFound.Add(key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ExportResult(exported, notFound, conflict);
|
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
|
var session = template.IncludeSessionData
|
||||||
? mafile.SessionData
|
? mafile.SessionData
|
||||||
: new MobileSessionData(null!, mafile.SteamId, default, null, tokens: null);
|
: new MobileSessionData(null!, mafile.SteamId, default, null, tokens: null);
|
||||||
|
|
||||||
|
|
||||||
var serializeMaf = new Mafile
|
var serializeMaf = new Mafile
|
||||||
{
|
{
|
||||||
SharedSecret = template.IncludeSharedSecret ? mafile.SharedSecret : null!,
|
SharedSecret = template.IncludeSharedSecret ? mafile.SharedSecret : null!,
|
||||||
@@ -102,14 +136,7 @@ public static class MafileExporter
|
|||||||
var serialized = NebulaSerializer.SerializeMafile(serializeMaf);
|
var serialized = NebulaSerializer.SerializeMafile(serializeMaf);
|
||||||
var strategy = template.UseLoginAsMafileName ? MafileNamingStrategy.Login : MafileNamingStrategy.SteamId;
|
var strategy = template.UseLoginAsMafileName ? MafileNamingStrategy.Login : MafileNamingStrategy.SteamId;
|
||||||
var fileName = strategy.GetMafileName(serializeMaf);
|
var fileName = strategy.GetMafileName(serializeMaf);
|
||||||
var fullPath = Path.Combine(path, fileName);
|
return (serialized, fileName);
|
||||||
if (File.Exists(fullPath))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
await File.WriteAllTextAsync(fullPath, serialized);
|
|
||||||
return fullPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool PathIsValid(string path)
|
private static bool PathIsValid(string path)
|
||||||
|
|||||||
@@ -85,11 +85,6 @@ public static class NebulaSerializer
|
|||||||
|
|
||||||
public static string SerializeMafile(MobileDataExtended data, Dictionary<string, object?>? properties)
|
public static string SerializeMafile(MobileDataExtended data, Dictionary<string, object?>? properties)
|
||||||
{
|
{
|
||||||
if (Settings.Instance.LegacyMode)
|
return MafileSerializer.SerializeLegacy(data, Serializer.Settings.SerializationOptions, properties);
|
||||||
{
|
|
||||||
return MafileSerializer.SerializeLegacy(data, Serializer.Settings.SerializationOptions, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Serializer.Serialize(data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,13 @@ public static class ProxyStorage
|
|||||||
PatternRequirement.Optional,
|
PatternRequirement.Optional,
|
||||||
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();
|
public static ObservableDictionary<int, ProxyData> Proxies { get; } = new();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace NebulaAuth.Model;
|
||||||
|
|
||||||
|
public class RemoteLinks
|
||||||
|
{
|
||||||
|
public string? Website { get; set; }
|
||||||
|
public string? Documentation { get; set; }
|
||||||
|
}
|
||||||
@@ -6,7 +6,9 @@ using AchiesUtilities.Web.Models;
|
|||||||
using MaterialDesignThemes.Wpf;
|
using MaterialDesignThemes.Wpf;
|
||||||
using NebulaAuth.Core;
|
using NebulaAuth.Core;
|
||||||
using NebulaAuth.Model.Entities;
|
using NebulaAuth.Model.Entities;
|
||||||
|
using NebulaAuth.Utility;
|
||||||
using NebulaAuth.View.Dialogs;
|
using NebulaAuth.View.Dialogs;
|
||||||
|
using NebulaAuth.ViewModel.Other;
|
||||||
using SteamLib.Exceptions.Authorization;
|
using SteamLib.Exceptions.Authorization;
|
||||||
|
|
||||||
namespace NebulaAuth.Model;
|
namespace NebulaAuth.Model;
|
||||||
@@ -16,13 +18,13 @@ public static partial class SessionHandler
|
|||||||
private static readonly SemaphoreSlim Semaphore = new(1, 1);
|
private static readonly SemaphoreSlim Semaphore = new(1, 1);
|
||||||
|
|
||||||
public static async Task<T> Handle<T>(Func<Task<T>> func, Mafile mafile,
|
public static async Task<T> Handle<T>(Func<Task<T>> func, Mafile mafile,
|
||||||
HttpClientHandlerPair? chp = null, string? snackbarPrefix = null)
|
HttpClientHandlerPair? chp = null, string? snackbarPrefix = null, bool allowInteractiveLogin = true)
|
||||||
{
|
{
|
||||||
chp ??= MaClient.GetHttpClientHandlerPair(mafile);
|
chp ??= MaClient.GetHttpClientHandlerPair(mafile);
|
||||||
await Semaphore.WaitAsync();
|
await Semaphore.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await HandleInternal(func, chp.Value, mafile, snackbarPrefix);
|
return await HandleInternal(func, chp.Value, mafile, snackbarPrefix, allowInteractiveLogin);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -31,7 +33,7 @@ public static partial class SessionHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<T> HandleInternal<T>(Func<Task<T>> func, HttpClientHandlerPair chp, Mafile mafile,
|
private static async Task<T> HandleInternal<T>(Func<Task<T>> func, HttpClientHandlerPair chp, Mafile mafile,
|
||||||
string? snackbarPrefix = null)
|
string? snackbarPrefix = null, bool allowInteractiveLogin = true)
|
||||||
{
|
{
|
||||||
using var scope = Shell.Logger.PushScopeProperty("Scope", "SessionHandler");
|
using var scope = Shell.Logger.PushScopeProperty("Scope", "SessionHandler");
|
||||||
Exception? currentException = null;
|
Exception? currentException = null;
|
||||||
@@ -86,6 +88,32 @@ public static partial class SessionHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allowInteractiveLogin && !DialogHost.IsDialogOpen(null))
|
||||||
|
{
|
||||||
|
var noProxy = mafile.Proxy == null && MaClient.DefaultProxy == null;
|
||||||
|
var currentPassword = GetPassword(mafile);
|
||||||
|
|
||||||
|
Task<LoginAgainVM?> dialogTask = null!;
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
dialogTask = DialogsController.ShowLoginAgainDialog(mafile.AccountName, currentPassword, noProxy);
|
||||||
|
});
|
||||||
|
|
||||||
|
var vm = await dialogTask;
|
||||||
|
if (vm != null)
|
||||||
|
{
|
||||||
|
Shell.Logger.Info("User provided credentials interactively for {name}, attempting login",
|
||||||
|
mafile.AccountName);
|
||||||
|
var logged = await LoginAgainInternal(chp, mafile, vm.Password, vm.SavePassword);
|
||||||
|
if (logged)
|
||||||
|
{
|
||||||
|
Shell.Logger.Debug("Interactive login for {name} succeeded, retrying operation",
|
||||||
|
mafile.AccountName);
|
||||||
|
return await func();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw new SessionPermanentlyExpiredException(SessionPermanentlyExpiredException.SESSION_EXPIRED_MSG,
|
throw new SessionPermanentlyExpiredException(SessionPermanentlyExpiredException.SESSION_EXPIRED_MSG,
|
||||||
currentException);
|
currentException);
|
||||||
}
|
}
|
||||||
@@ -118,6 +146,7 @@ public static partial class SessionHandler
|
|||||||
{
|
{
|
||||||
Shell.Logger.Debug(ex, "Failed to relogin mafile {name} {steamid}", mafile.AccountName,
|
Shell.Logger.Debug(ex, "Failed to relogin mafile {name} {steamid}", mafile.AccountName,
|
||||||
mafile.SessionData?.SteamId);
|
mafile.SessionData?.SteamId);
|
||||||
|
ExceptionHandler.Handle(ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public partial class Settings : ObservableObject
|
|||||||
[ObservableProperty] private Color? _iconColor;
|
[ObservableProperty] private Color? _iconColor;
|
||||||
[ObservableProperty] private bool _isPasswordSet;
|
[ObservableProperty] private bool _isPasswordSet;
|
||||||
[ObservableProperty] private LocalizationLanguage _language = LocalizationLanguage.English;
|
[ObservableProperty] private LocalizationLanguage _language = LocalizationLanguage.English;
|
||||||
[ObservableProperty] private bool _legacyMode = true;
|
[ObservableProperty] private bool _confirmMafileImport = true;
|
||||||
[ObservableProperty] private bool _allowAutoUpdate;
|
[ObservableProperty] private bool _allowAutoUpdate;
|
||||||
[ObservableProperty] private bool _useAccountNameAsMafileName;
|
[ObservableProperty] private bool _useAccountNameAsMafileName;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System.IO;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using NebulaAuth.Core;
|
using NebulaAuth.Core;
|
||||||
using NebulaAuth.Model.Exceptions;
|
|
||||||
using NebulaAuth.Model.MAAC;
|
using NebulaAuth.Model.MAAC;
|
||||||
using NebulaAuth.Model.MafileExport;
|
using NebulaAuth.Model.MafileExport;
|
||||||
using NebulaAuth.Model.Mafiles;
|
using NebulaAuth.Model.Mafiles;
|
||||||
@@ -40,7 +39,8 @@ public static class Shell
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new CantAlignTimeException("", ex);
|
Logger.Error(ex, "Failed to align time with Steam");
|
||||||
|
TimeAligner.SetTimeDifference(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
var threads = Environment.ProcessorCount > 0 ? Environment.ProcessorCount : 1;
|
var threads = Environment.ProcessorCount > 0 ? Environment.ProcessorCount : 1;
|
||||||
@@ -48,6 +48,7 @@ public static class Shell
|
|||||||
ProxyAssignmentCache.Initialize(Storage.MaFiles);
|
ProxyAssignmentCache.Initialize(Storage.MaFiles);
|
||||||
MAACStorage.Initialize();
|
MAACStorage.Initialize();
|
||||||
MafileExporterStorage.Initialize();
|
MafileExporterStorage.Initialize();
|
||||||
|
_ = LinksManager.FetchAsync();
|
||||||
|
|
||||||
ExtensionsLogger.LogDebug("Application started");
|
ExtensionsLogger.LogDebug("Application started");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,20 +3,20 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace NebulaAuth.Model.Update;
|
namespace NebulaAuth.Model.Update;
|
||||||
|
|
||||||
public class ChangelogEntry
|
public class ChangelogEntry
|
||||||
{
|
{
|
||||||
[JsonProperty("version")] public string Version { get; set; } = string.Empty;
|
[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
|
public class ChangeItem
|
||||||
{
|
{
|
||||||
[JsonProperty("type")] public string Type { get; set; } = string.Empty;
|
[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; }
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<SatelliteResourceLanguages>en;ru;ua</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en;ru;ua</SatelliteResourceLanguages>
|
||||||
<ApplicationIcon>Theme\lock.ico</ApplicationIcon>
|
<ApplicationIcon>Theme\lock.ico</ApplicationIcon>
|
||||||
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
||||||
<AssemblyVersion>1.8.4</AssemblyVersion>
|
<AssemblyVersion>1.8.5</AssemblyVersion>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,8 @@
|
|||||||
<!-- Window Buttons -->
|
<!-- Window Buttons -->
|
||||||
<StackPanel
|
<StackPanel
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal"
|
||||||
|
TextElement.Foreground="{DynamicResource PrimaryContentBrush}">
|
||||||
<StackPanel.Resources>
|
<StackPanel.Resources>
|
||||||
<Style TargetType="materialDesign:PackIcon">
|
<Style TargetType="materialDesign:PackIcon">
|
||||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public static class ExceptionHandler
|
|||||||
}
|
}
|
||||||
case LoginException e:
|
case LoginException e:
|
||||||
{
|
{
|
||||||
return "LoginException".GetCodeBehindLocalization() + ": " +
|
return "LoginException".GetCodeBehindLocalization() +
|
||||||
ErrorTranslatorHelper.TranslateLoginError(e.Error);
|
ErrorTranslatorHelper.TranslateLoginError(e.Error);
|
||||||
}
|
}
|
||||||
case UnsupportedAuthTypeException e:
|
case UnsupportedAuthTypeException e:
|
||||||
|
|||||||
@@ -12,31 +12,10 @@
|
|||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader Title="{Tr ConfirmCancelDialog.Title}"
|
||||||
<Grid.ColumnDefinitions>
|
CloseParameter="{StaticResource False}" />
|
||||||
<ColumnDefinition Width="*" />
|
<Grid Grid.Row="1" Margin="12">
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<!--<materialDesign:PackIcon Kind="WarningCircleOutline" Width="20" Height="20" Margin="0,0,5,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Foreground="{DynamicResource PrimaryContentBrush}" />-->
|
|
||||||
<TextBlock FontStyle="Normal" Foreground="{DynamicResource BaseContentBrush}"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center" FontSize="18" Text="{Tr ConfirmCancelDialog.Title}" />
|
|
||||||
</StackPanel>
|
|
||||||
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
|
|
||||||
HorizontalAlignment="Right" CommandParameter="{StaticResource False}"
|
|
||||||
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
|
|
||||||
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
|
|
||||||
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
<Separator Grid.Row="1" Opacity="0.7" />
|
|
||||||
<Grid Grid.Row="2" Margin="12">
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
||||||
xmlns:model="clr-namespace:NebulaAuth.Model"
|
xmlns:model="clr-namespace:NebulaAuth.Model"
|
||||||
|
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
||||||
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
|
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
|
||||||
@@ -15,53 +16,39 @@
|
|||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader IconKind="Login"
|
||||||
<Grid.ColumnDefinitions>
|
Title="{Tr LoginAgainDialog.Title}"
|
||||||
<ColumnDefinition Width="*" />
|
CloseParameter="{StaticResource False}" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<Grid Grid.Row="1" Margin="12">
|
||||||
</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">
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBox TabIndex="0" Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
|
<nebulaAuth:HintBox Grid.Row="0"
|
||||||
|
Margin="10,10,10,0"
|
||||||
|
Severity="Warning"
|
||||||
|
FontSize="14"
|
||||||
|
Visibility="{Binding ShowNoProxyWarning, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||||
|
Text="{Tr LoginAgainDialog.NoProxyWarning}" />
|
||||||
|
<TextBox TabIndex="0" Grid.Row="1" Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
|
||||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||||
Padding="10"
|
Padding="10"
|
||||||
FontSize="15"
|
FontSize="15"
|
||||||
Margin="10,10,10,0"
|
Margin="10,10,10,0"
|
||||||
Grid.Row="0"
|
|
||||||
Style="{StaticResource MaterialDesignOutlinedTextBox}"
|
Style="{StaticResource MaterialDesignOutlinedTextBox}"
|
||||||
|
|
||||||
materialDesign:HintAssist.Hint="{Tr LoginAgainDialog.PasswordBox}"
|
materialDesign:HintAssist.Hint="{Tr LoginAgainDialog.PasswordBox}"
|
||||||
materialDesign:HintAssist.IsFloating="False"
|
materialDesign:HintAssist.IsFloating="False"
|
||||||
materialDesign:TextFieldAssist.LeadingIcon="Key"
|
materialDesign:TextFieldAssist.LeadingIcon="Key"
|
||||||
materialDesign:TextFieldAssist.HasLeadingIcon="True" />
|
materialDesign:TextFieldAssist.HasLeadingIcon="True" />
|
||||||
<CheckBox FontSize="15" Grid.Row="1" Margin="10,5,10,0"
|
<CheckBox FontSize="15" Grid.Row="2" Margin="10,5,10,0"
|
||||||
IsEnabled="{Binding Source={x:Static model:PHandler.IsPasswordSet}}"
|
IsEnabled="{Binding Source={x:Static model:PHandler.IsPasswordSet}}"
|
||||||
IsChecked="{Binding SavePassword}" Content="{Tr LoginAgainDialog.SaveEncryptedPassword}" />
|
IsChecked="{Binding SavePassword}" Content="{Tr LoginAgainDialog.SaveEncryptedPassword}" />
|
||||||
<Grid Grid.Row="2" Margin="10,10,10,0">
|
<Grid Grid.Row="3" Margin="10,10,10,0">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
||||||
xmlns:model="clr-namespace:NebulaAuth.Model"
|
xmlns:model="clr-namespace:NebulaAuth.Model"
|
||||||
xmlns:entities="clr-namespace:NebulaAuth.Model.Entities"
|
xmlns:entities="clr-namespace:NebulaAuth.Model.Entities"
|
||||||
|
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
||||||
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
|
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
|
||||||
@@ -16,32 +17,12 @@
|
|||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader IconKind="Login"
|
||||||
<Grid.ColumnDefinitions>
|
Title="{Tr LoginAgainDialog.LoginFor, IsDynamic=False}"
|
||||||
<ColumnDefinition Width="*" />
|
TitleAccent="{Binding UserName}"
|
||||||
<ColumnDefinition Width="Auto" />
|
CloseParameter="{StaticResource False}" />
|
||||||
</Grid.ColumnDefinitions>
|
<Grid Grid.Row="1" Margin="12">
|
||||||
<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">
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
<UserControl x:Class="NebulaAuth.View.Dialogs.MafileImportDialog"
|
||||||
|
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:nebulaAuth="clr-namespace:NebulaAuth"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Height="Auto" Width="Auto" MaxWidth="520"
|
||||||
|
Background="{DynamicResource WindowBackground}">
|
||||||
|
<Grid MinHeight="240" MinWidth="440">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<nebulaAuth:DialogHeader Title="{Tr MafileImportDialog.Title}" />
|
||||||
|
|
||||||
|
<Grid Grid.Row="1" Margin="14,14,14,16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Border Margin="6,0,6,12" Padding="12,10"
|
||||||
|
CornerRadius="8"
|
||||||
|
BorderThickness="1">
|
||||||
|
<Border.Background>
|
||||||
|
<SolidColorBrush Color="{DynamicResource BaseContentColor}" Opacity="0.07" />
|
||||||
|
</Border.Background>
|
||||||
|
<Border.BorderBrush>
|
||||||
|
<SolidColorBrush Color="{DynamicResource BaseContentColor}" Opacity="0.12" />
|
||||||
|
</Border.BorderBrush>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Text="{Tr MafileImportDialog.TotalCount}" Opacity="0.82" />
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding TotalCount, Mode=OneWay}" FontWeight="SemiBold" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Text="{Tr MafileImportDialog.ConflictCount}" Opacity="0.82"
|
||||||
|
Visibility="{Binding HasConflicts, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding ConflictCount, Mode=OneWay}"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{DynamicResource WarningBrush}"
|
||||||
|
Visibility="{Binding HasConflicts, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<CheckBox Grid.Row="1"
|
||||||
|
Margin="10,4,10,8"
|
||||||
|
IsChecked="{Binding OverwriteConflicts}"
|
||||||
|
Visibility="{Binding HasConflicts, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||||
|
Content="{Tr MafileImportDialog.OverwriteConflicts}" />
|
||||||
|
|
||||||
|
<Separator Grid.Row="2"
|
||||||
|
Margin="10,2,10,2" Opacity="0.35"
|
||||||
|
Visibility="{Binding HasConflicts, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||||
|
|
||||||
|
<CheckBox Grid.Row="3"
|
||||||
|
Margin="10,4,10,0"
|
||||||
|
IsChecked="{Binding AddToGroup}"
|
||||||
|
Content="{Tr MafileImportDialog.AddToGroup}" />
|
||||||
|
|
||||||
|
<ComboBox x:Name="GroupBox"
|
||||||
|
Grid.Row="4"
|
||||||
|
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}" />
|
||||||
|
|
||||||
|
<Grid Grid.Row="5" Margin="10,16,10,5">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button Width="130"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Margin="2,0,4,0"
|
||||||
|
Style="{StaticResource MaterialDesignFlatDarkBgButton}"
|
||||||
|
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
Content="{Tr Common.OK}"
|
||||||
|
IsDefault="True" />
|
||||||
|
<Button Grid.Column="1"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Width="130"
|
||||||
|
Margin="0,0,2,0"
|
||||||
|
Style="{StaticResource MaterialDesignOutlinedButton}"
|
||||||
|
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
|
||||||
|
CommandParameter="{x:Null}"
|
||||||
|
Content="{Tr Common.Cancel}"
|
||||||
|
IsCancel="True" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace NebulaAuth.View.Dialogs;
|
||||||
|
|
||||||
|
public partial class MafileImportDialog
|
||||||
|
{
|
||||||
|
public MafileImportDialog()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
||||||
|
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
||||||
d:DataContext="{d:DesignInstance other:SdaPasswordDialogVM}"
|
d:DataContext="{d:DesignInstance other:SdaPasswordDialogVM}"
|
||||||
@@ -14,29 +15,11 @@
|
|||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader IconKind="Lock"
|
||||||
<Grid.ColumnDefinitions>
|
Title="{Tr SdaPasswordDialog.Title}"
|
||||||
<ColumnDefinition Width="*" />
|
CloseParameter="{StaticResource False}" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<Grid Grid.Row="1" Margin="12">
|
||||||
</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">
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
|
||||||
mc:Ignorable="d"
|
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">
|
<Grid MinHeight="100" MinWidth="300" MaxWidth="400">
|
||||||
@@ -15,38 +17,19 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader IconKind="Encryption"
|
||||||
<Grid.ColumnDefinitions>
|
Title="{Tr SetEncryptionPasswordDialog.Title}"
|
||||||
<ColumnDefinition Width="*" />
|
CloseParameter="{StaticResource False}" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<TextBlock Grid.Row="1" IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal"
|
||||||
</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"
|
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
Text="{Tr SetEncryptionPasswordDialog.DialogText}"
|
Text="{Tr SetEncryptionPasswordDialog.DialogText}"
|
||||||
Margin="10" HorizontalAlignment="Left" />
|
Margin="10" HorizontalAlignment="Left" />
|
||||||
<PasswordBox TabIndex="0" FontSize="16" x:Name="PasswordBox"
|
<PasswordBox TabIndex="0" FontSize="16" x:Name="PasswordBox"
|
||||||
materialDesign:PasswordBoxAssist.Password="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
|
materialDesign:PasswordBoxAssist.Password="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Margin="10" Grid.Row="3" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
|
Margin="10" Grid.Row="2" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
|
||||||
materialDesign:HintAssist.Hint="{Tr SetEncryptionPasswordDialog.Password}" />
|
materialDesign:HintAssist.Hint="{Tr SetEncryptionPasswordDialog.Password}" />
|
||||||
<Grid Grid.Row="4" Margin="10">
|
<Grid Grid.Row="3" Margin="10">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Height="Auto" Width="Auto" MaxWidth="500"
|
Height="Auto" Width="Auto" MaxWidth="500"
|
||||||
Background="{DynamicResource WindowBackground}">
|
Background="{DynamicResource WindowBackground}">
|
||||||
@@ -11,31 +12,10 @@
|
|||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader x:Name="TitleHeader"
|
||||||
<Grid.ColumnDefinitions>
|
Title="{Tr TextFieldDialog.Title}" />
|
||||||
<ColumnDefinition Width="*" />
|
<Grid Grid.Row="1" Margin="12">
|
||||||
<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">
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public partial class TextFieldDialog
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(title))
|
if (!string.IsNullOrWhiteSpace(title))
|
||||||
TitleTextBlock.Text = title;
|
TitleHeader.Title = title;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(msg))
|
if (!string.IsNullOrEmpty(msg))
|
||||||
HintAssist.SetHint(TextField, msg);
|
HintAssist.SetHint(TextField, msg);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
|
||||||
|
xmlns:nebulaAuth="clr-namespace:NebulaAuth"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
||||||
d:DataContext="{d:DesignInstance other:UpdateDialogVM}"
|
d:DataContext="{d:DesignInstance other:UpdateDialogVM}"
|
||||||
@@ -15,37 +16,15 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader IconKind="Update"
|
||||||
<Grid.ColumnDefinitions>
|
Title="{Tr UpdateDialog.Title, IsDynamic=False}"
|
||||||
<ColumnDefinition Width="*" />
|
TitleAccent="{Binding Version, Mode=OneWay}" />
|
||||||
<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" />
|
|
||||||
|
|
||||||
<!-- Changelog -->
|
<!-- Changelog -->
|
||||||
<Grid Grid.Row="2" Margin="12,10,12,4">
|
<Grid Grid.Row="1" Margin="12,10,12,4">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@@ -120,7 +99,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- Buttons -->
|
<!-- Buttons -->
|
||||||
<Grid Grid.Row="3" Margin="12,6,12,14">
|
<Grid Grid.Row="2" Margin="12,6,12,14">
|
||||||
|
|
||||||
<!-- Normal buttons -->
|
<!-- Normal buttons -->
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
|||||||
@@ -56,30 +56,7 @@
|
|||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</Grid.Resources>
|
</Grid.Resources>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader IconKind="LinkBoxOutline" Title="{Tr LinkerDialog.Title}" />
|
||||||
<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:HintBox FontSize="14"
|
<nebulaAuth:HintBox FontSize="14"
|
||||||
Visibility="{Binding Tip, Converter={StaticResource NullableToVisibilityConverter}}"
|
Visibility="{Binding Tip, Converter={StaticResource NullableToVisibilityConverter}}"
|
||||||
Grid.Row="2" Margin="10,10,10,0"
|
Grid.Row="2" Margin="10,10,10,0"
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
RenderOptions.BitmapScalingMode="HighQuality">
|
RenderOptions.BitmapScalingMode="HighQuality"
|
||||||
|
Loaded="LinksView_Loaded">
|
||||||
|
|
||||||
<materialDesign:Card Padding="24" HorizontalAlignment="Center" VerticalAlignment="Center" UniformCornerRadius="12">
|
<materialDesign:Card Padding="24" HorizontalAlignment="Center" VerticalAlignment="Center" UniformCornerRadius="12">
|
||||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
@@ -49,16 +50,20 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button Margin="0,0,0,5" FontSize="18" Style="{StaticResource MaterialDesignFlatButton}"
|
<Button x:Name="WebsiteButton" Margin="0,0,0,5" FontSize="18"
|
||||||
Click="Website_Click" IsEnabled="False">
|
Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
IsEnabled="False"
|
||||||
|
Click="Website_Click">
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
<materialDesign:PackIcon Kind="Web" Width="24" Height="24" Margin="0 0 8 0" />
|
<materialDesign:PackIcon Kind="Web" Width="24" Height="24" Margin="0 0 8 0" />
|
||||||
<TextBlock Text="Web-site" VerticalAlignment="Center" />
|
<TextBlock Text="Achiefy" VerticalAlignment="Center" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button Margin="0,0,0,5" FontSize="18" Style="{StaticResource MaterialDesignFlatButton}"
|
<Button x:Name="DocumentationButton" Margin="0,0,0,5" FontSize="18"
|
||||||
Click="Documentation_Click" IsEnabled="False">
|
Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
IsEnabled="False"
|
||||||
|
Click="Documentation_Click">
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
<Viewbox Width="22" Height="22" Margin="0 0 8 0">
|
<Viewbox Width="22" Height="22" Margin="0 0 8 0">
|
||||||
<Canvas Width="22" Height="22">
|
<Canvas Width="22" Height="22">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using MaterialDesignThemes.Wpf;
|
using MaterialDesignThemes.Wpf;
|
||||||
@@ -13,6 +13,12 @@ public partial class LinksView : UserControl
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LinksView_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
WebsiteButton.IsEnabled = LinksManager.WebsiteUrl != null;
|
||||||
|
DocumentationButton.IsEnabled = LinksManager.DocumentationUrl != null;
|
||||||
|
}
|
||||||
|
|
||||||
private void Telegram_Click(object sender, RoutedEventArgs e)
|
private void Telegram_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Process.Start(new ProcessStartInfo("https://t.me/nebulaauth") {UseShellExecute = true});
|
Process.Start(new ProcessStartInfo("https://t.me/nebulaauth") {UseShellExecute = true});
|
||||||
@@ -26,12 +32,14 @@ public partial class LinksView : UserControl
|
|||||||
|
|
||||||
private void Website_Click(object sender, RoutedEventArgs e)
|
private void Website_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Process.Start(new ProcessStartInfo("https://yourwebsite.com") {UseShellExecute = true});
|
if (LinksManager.WebsiteUrl != null)
|
||||||
|
Process.Start(new ProcessStartInfo(LinksManager.WebsiteUrl) {UseShellExecute = true});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Documentation_Click(object sender, RoutedEventArgs e)
|
private void Documentation_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Process.Start(new ProcessStartInfo("https://yourwebsite.com") {UseShellExecute = true});
|
if (LinksManager.DocumentationUrl != null)
|
||||||
|
Process.Start(new ProcessStartInfo(LinksManager.DocumentationUrl) {UseShellExecute = true});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckForUpdates_Click(object sender, RoutedEventArgs e)
|
private void CheckForUpdates_Click(object sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
TextElement.Foreground="{DynamicResource BaseContentBrush}"
|
||||||
FontFamily="{materialDesign:MaterialDesignFont}"
|
FontFamily="{materialDesign:MaterialDesignFont}"
|
||||||
MinWidth="400"
|
MinWidth="500"
|
||||||
MaxWidth="400"
|
MaxWidth="500"
|
||||||
Background="{DynamicResource WindowBackground}"
|
Background="{DynamicResource WindowBackground}"
|
||||||
d:DataContext="{d:DesignInstance other:MafileExporterVM}"
|
d:DataContext="{d:DesignInstance other:MafileExporterVM}"
|
||||||
d:Background="#141119"
|
d:Background="#141119"
|
||||||
@@ -19,32 +19,12 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader IconKind="FileExport" Title="{Tr ExportDialog.ExportTitle}" />
|
||||||
<Grid.ColumnDefinitions>
|
<Grid Grid.Row="1" Margin="15" TextElement.FontSize="14">
|
||||||
<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">
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
@@ -133,6 +113,12 @@
|
|||||||
IsEnabled="{Binding CurrentTemplate, Converter={StaticResource NullableToBooleanConverter}}">
|
IsEnabled="{Binding CurrentTemplate, Converter={StaticResource NullableToBooleanConverter}}">
|
||||||
|
|
||||||
<StackPanel>
|
<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"
|
<TextBlock FontWeight="DemiBold"
|
||||||
Text="{Tr ExportDialog.ExportSettingsCommon}" />
|
Text="{Tr ExportDialog.ExportSettingsCommon}" />
|
||||||
|
|
||||||
@@ -233,8 +219,8 @@
|
|||||||
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Separator Grid.Row="3" />
|
<Separator Grid.Row="2" />
|
||||||
<Button Command="{Binding ExportCommand}" Style="{StaticResource MaterialDesignFlatDarkBgButton}" Grid.Row="4"
|
<Button Command="{Binding ExportCommand}" Style="{StaticResource MaterialDesignFlatDarkBgButton}" Grid.Row="3"
|
||||||
Margin="20,7,20,7" MaxWidth="150" Content="{Tr ExportDialog.ExportButton}" />
|
Margin="20,7,20,7" MaxWidth="150" Content="{Tr ExportDialog.ExportButton}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -29,9 +29,6 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
|
|
||||||
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
<Style TargetType="materialDesign:PackIcon">
|
<Style TargetType="materialDesign:PackIcon">
|
||||||
@@ -58,35 +55,17 @@
|
|||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</Grid.Resources>
|
</Grid.Resources>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader IconKind="FileMove" Title="{Tr MafileMoverView.Title}" />
|
||||||
<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:HintBox FontSize="14"
|
<nebulaAuth:HintBox FontSize="14"
|
||||||
Visibility="{Binding Tip, Converter={StaticResource NullableToVisibilityConverter}}"
|
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}" />
|
Text="{Binding Tip}" />
|
||||||
<ContentControl
|
<ContentControl
|
||||||
Grid.Row="3" Margin="20" Content="{Binding CurrentStep}" />
|
Grid.Row="2" Margin="20" Content="{Binding CurrentStep}" />
|
||||||
|
|
||||||
<nebulaAuth:HintBox FontSize="14"
|
<nebulaAuth:HintBox FontSize="14"
|
||||||
Visibility="{Binding Error, Converter={StaticResource NullableToVisibilityConverter}}"
|
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}" />
|
Text="{Binding Error}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -20,34 +20,14 @@
|
|||||||
FontSize="16">
|
FontSize="16">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Title -->
|
<nebulaAuth:DialogHeader IconKind="Proxy" Title="{Tr ProxyManagerDialog.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" />
|
|
||||||
|
|
||||||
<!-- Tabs -->
|
<!-- Tabs -->
|
||||||
<TabControl Grid.Row="2"
|
<TabControl Grid.Row="1"
|
||||||
md:ColorZoneAssist.Background="{DynamicResource Base100Brush}"
|
md:ColorZoneAssist.Background="{DynamicResource Base100Brush}"
|
||||||
Style="{StaticResource MaterialDesignUniformTabControl}">
|
Style="{StaticResource MaterialDesignUniformTabControl}">
|
||||||
|
|
||||||
@@ -154,17 +134,18 @@
|
|||||||
</Run>
|
</Run>
|
||||||
</TextBlock>
|
</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}"
|
Foreground="{DynamicResource MaterialDesign.Brush.ForegroundLight}"
|
||||||
Text="{Binding Key, Converter={StaticResource ProxyAccountCountConverter}}" />
|
Text="{Binding Key, Converter={StaticResource ProxyAccountCountConverter}}" />
|
||||||
<Button Style="{StaticResource MaterialDesignIconButton}" Padding="0"
|
<Button Style="{StaticResource MaterialDesignIconButton}" Padding="0"
|
||||||
Width="24"
|
Width="24"
|
||||||
Height="24" md:RippleAssist.IsDisabled="True" Grid.Column="2"
|
Height="24" md:RippleAssist.IsDisabled="True" Grid.Column="2"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Command="{Binding DataContext.SetDefaultCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
Command="{Binding DataContext.SetDefaultCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||||||
CommandParameter="{Binding}">
|
CommandParameter="{Binding}">
|
||||||
<md:PackIcon Height="16" Width="16" Kind="Heart" />
|
<md:PackIcon Height="16" Width="16" Kind="Heart" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
FontSize="16">
|
FontSize="16">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
@@ -29,36 +28,10 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- ===== HEADER ===== -->
|
<nebulaAuth:DialogHeader IconKind="ShieldKey" Title="{Tr SetAccountPasswordsView.Title}" />
|
||||||
<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" />
|
|
||||||
|
|
||||||
<!-- ===== ENCRYPTION PASSWORD SECTION ===== -->
|
<!-- ===== ENCRYPTION PASSWORD SECTION ===== -->
|
||||||
<Grid Grid.Row="2">
|
<Grid Grid.Row="1">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
@@ -109,7 +82,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- ===== ACCOUNTS INPUT ===== -->
|
<!-- ===== ACCOUNTS INPUT ===== -->
|
||||||
<TextBox Grid.Row="3"
|
<TextBox Grid.Row="2"
|
||||||
Margin="15,0,15,10"
|
Margin="15,0,15,10"
|
||||||
Text="{Binding AccountsPasswords, UpdateSourceTrigger=PropertyChanged}"
|
Text="{Binding AccountsPasswords, UpdateSourceTrigger=PropertyChanged}"
|
||||||
FontSize="13"
|
FontSize="13"
|
||||||
@@ -124,14 +97,14 @@
|
|||||||
md:TextFieldAssist.TextBoxViewVerticalAlignment="Top"
|
md:TextFieldAssist.TextBoxViewVerticalAlignment="Top"
|
||||||
VerticalContentAlignment="Top" />
|
VerticalContentAlignment="Top" />
|
||||||
<!-- ===== INFO TEXT ===== -->
|
<!-- ===== INFO TEXT ===== -->
|
||||||
<TextBlock Grid.Row="4"
|
<TextBlock Grid.Row="3"
|
||||||
Margin="20,0,20,15"
|
Margin="20,0,20,15"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
FontSize="12"
|
FontSize="12"
|
||||||
Foreground="{DynamicResource BaseContentBrush}"
|
Foreground="{DynamicResource BaseContentBrush}"
|
||||||
Text="{Tr SetAccountPasswordsView.EncryptionHint}" />
|
Text="{Tr SetAccountPasswordsView.EncryptionHint}" />
|
||||||
|
|
||||||
<Button Grid.Row="5"
|
<Button Grid.Row="4"
|
||||||
Margin="10,0,0,10"
|
Margin="10,0,0,10"
|
||||||
Width="120"
|
Width="120"
|
||||||
Content="{Tr Common.Save}"
|
Content="{Tr Common.Save}"
|
||||||
@@ -139,7 +112,7 @@
|
|||||||
Style="{StaticResource MaterialDesignOutlinedButton}" Cursor="Hand" />
|
Style="{StaticResource MaterialDesignOutlinedButton}" Cursor="Hand" />
|
||||||
|
|
||||||
<!-- ===== HINT / RESULT BOX ===== -->
|
<!-- ===== HINT / RESULT BOX ===== -->
|
||||||
<nebulaAuth:HintBox Grid.Row="6"
|
<nebulaAuth:HintBox Grid.Row="5"
|
||||||
Margin="15,0,15,10"
|
Margin="15,0,15,10"
|
||||||
Visibility="{Binding Tip, Converter={StaticResource NullableToVisibilityConverter}}"
|
Visibility="{Binding Tip, Converter={StaticResource NullableToVisibilityConverter}}"
|
||||||
CloseCommand="{Binding ClearTipCommand}"
|
CloseCommand="{Binding ClearTipCommand}"
|
||||||
|
|||||||
@@ -18,36 +18,15 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="10,10,10,5">
|
<nebulaAuth:DialogHeader IconKind="Settings"
|
||||||
<Grid.ColumnDefinitions>
|
Title="{Tr SettingsDialog.Title}"
|
||||||
<ColumnDefinition Width="*" />
|
IsCloseEnabled="{Binding ApplyRenameSettingCommand.IsRunning, Converter={StaticResource ReverseBooleanConverter}, Mode=OneWay}" />
|
||||||
<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" />
|
|
||||||
|
|
||||||
<TabControl materialDesign:ColorZoneAssist.Background="{DynamicResource Base100Brush}"
|
<TabControl materialDesign:ColorZoneAssist.Background="{DynamicResource Base100Brush}"
|
||||||
Style="{StaticResource MaterialDesignUniformTabControl}" Grid.Row="2">
|
Style="{StaticResource MaterialDesignUniformTabControl}" Grid.Row="1">
|
||||||
<TabItem Header="{Tr SettingsDialog.MainSettings}">
|
<TabItem Header="{Tr SettingsDialog.MainSettings}">
|
||||||
<StackPanel Width="400" Margin="10,18,10,40" Orientation="Vertical" HorizontalAlignment="Center">
|
<StackPanel Width="400" Margin="10,18,10,40" Orientation="Vertical" HorizontalAlignment="Center">
|
||||||
<ComboBox Style="{StaticResource MaterialDesignFloatingHintComboBox}" Margin="0,15,0,0"
|
<ComboBox Style="{StaticResource MaterialDesignFloatingHintComboBox}" Margin="0,15,0,0"
|
||||||
@@ -59,9 +38,9 @@
|
|||||||
Content="{Tr SettingsDialog.MinimizeToTray}" />
|
Content="{Tr SettingsDialog.MinimizeToTray}" />
|
||||||
|
|
||||||
|
|
||||||
<CheckBox Margin="0,5,0,0" IsChecked="{Binding LegacyMode}"
|
<CheckBox Margin="0,5,0,0" IsChecked="{Binding ConfirmMafileImport}"
|
||||||
Content="{Tr SettingsDialog.LegacyMafileMode}"
|
Content="{Tr SettingsDialog.ConfirmMafileImport}"
|
||||||
ToolTip="{Tr SettingsDialog.LegacyMafileModeHint}" />
|
ToolTip="{Tr SettingsDialog.ConfirmMafileImportHint}" />
|
||||||
<!--<CheckBox IsEnabled="False" Margin="0,10,0,0" FontSize="16" IsChecked="{Binding AllowAutoUpdate}" Content="{Tr SettingsDialog.AllowAutoUpdate}"/>-->
|
<!--<CheckBox IsEnabled="False" Margin="0,10,0,0" FontSize="16" IsChecked="{Binding AllowAutoUpdate}" Content="{Tr SettingsDialog.AllowAutoUpdate}"/>-->
|
||||||
|
|
||||||
<!--<CheckBox Margin="0,12,0,0" IsChecked="{Binding UseAccountNameAsMafileName}">
|
<!--<CheckBox Margin="0,12,0,0" IsChecked="{Binding UseAccountNameAsMafileName}">
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -30,6 +31,8 @@ public partial class MainVM //File //TODO: Refactor
|
|||||||
bool SdaPasswordPrompted,
|
bool SdaPasswordPrompted,
|
||||||
SDAEncryptionHelper.Context? SdaContext);
|
SDAEncryptionHelper.Context? SdaContext);
|
||||||
|
|
||||||
|
private record MafileImportPlanItem(Mafile Mafile, bool RequiresRelogin, bool HasConflict);
|
||||||
|
|
||||||
public Settings Settings => Settings.Instance;
|
public Settings Settings => Settings.Instance;
|
||||||
|
|
||||||
|
|
||||||
@@ -76,10 +79,11 @@ public partial class MainVM //File //TODO: Refactor
|
|||||||
: Task.CompletedTask;
|
: Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: extract flow and refactor, this method is too long and does too many things
|
||||||
public async Task AddMafile(string[] path)
|
public async Task AddMafile(string[] path)
|
||||||
{
|
{
|
||||||
bool? confirmOverwrite = null;
|
|
||||||
var summary = new MafileImportSummary();
|
var summary = new MafileImportSummary();
|
||||||
|
var items = new List<MafileImportPlanItem>();
|
||||||
SDAEncryptionHelper.Context? sdaContext = null;
|
SDAEncryptionHelper.Context? sdaContext = null;
|
||||||
var sdaPasswordPrompted = false;
|
var sdaPasswordPrompted = false;
|
||||||
foreach (var str in path)
|
foreach (var str in path)
|
||||||
@@ -95,16 +99,7 @@ public partial class MainVM //File //TODO: Refactor
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var overwrite = confirmOverwrite ?? false;
|
items.Add(new MafileImportPlanItem(mafile, false, HasImportConflict(mafile)));
|
||||||
var res = await Storage.AddNewMafileFromData(mafile, overwrite);
|
|
||||||
if (res == AddMafileResult.AlreadyExist && confirmOverwrite == null)
|
|
||||||
{
|
|
||||||
confirmOverwrite =
|
|
||||||
await DialogsController.ShowConfirmCancelDialog(GetLocalization("ConfirmMafileOverwrite"));
|
|
||||||
res = await Storage.AddNewMafileFromData(mafile, confirmOverwrite.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
summary.Apply(res);
|
|
||||||
}
|
}
|
||||||
catch (FormatException)
|
catch (FormatException)
|
||||||
{
|
{
|
||||||
@@ -114,18 +109,11 @@ public partial class MainVM //File //TODO: Refactor
|
|||||||
{
|
{
|
||||||
if (path.Length == 1 && ex.Mafile != null)
|
if (path.Length == 1 && ex.Mafile != null)
|
||||||
{
|
{
|
||||||
var mafile = ex.Mafile;
|
items.Add(new MafileImportPlanItem(ex.Mafile, true, HasImportConflict(ex.Mafile)));
|
||||||
if (await HandleAddMafileWithoutSession(mafile))
|
|
||||||
{
|
|
||||||
summary.AddedOne();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
summary.ErrorOne();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
summary.ErrorOne();
|
||||||
SnackbarController.SendSnackbar(
|
SnackbarController.SendSnackbar(
|
||||||
$"{GetLocalization("MafileImportError")} {Path.GetFileName(str)}{GetLocalization("MissingSessionInMafile")}",
|
$"{GetLocalization("MafileImportError")} {Path.GetFileName(str)}{GetLocalization("MissingSessionInMafile")}",
|
||||||
TimeSpan.FromSeconds(4));
|
TimeSpan.FromSeconds(4));
|
||||||
@@ -133,9 +121,78 @@ public partial class MainVM //File //TODO: Refactor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (items.Count == 0)
|
||||||
|
{
|
||||||
|
ShowImportSummary(summary);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var conflictCount = items.Count(i => i.HasConflict);
|
||||||
|
var showImportDialog = Settings.ConfirmMafileImport || conflictCount > 0;
|
||||||
|
MafileImportDialogResult? importOptions = null;
|
||||||
|
if (showImportDialog)
|
||||||
|
{
|
||||||
|
importOptions = await DialogsController.ShowMafileImportDialog(Groups, items.Count, conflictCount);
|
||||||
|
if (importOptions == null)
|
||||||
|
{
|
||||||
|
SnackbarController.SendSnackbar(LocManager.GetCommonOrDefault("Canceled", "Canceled"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var importGroup = importOptions?.Group;
|
||||||
|
var overwriteConflicts = importOptions?.OverwriteConflicts ?? false;
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
ApplyImportGroup(item.Mafile, importGroup);
|
||||||
|
if (item.RequiresRelogin)
|
||||||
|
{
|
||||||
|
if (item.HasConflict && !overwriteConflicts)
|
||||||
|
{
|
||||||
|
summary.SkippedOne();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await HandleAddMafileWithoutSession(item.Mafile))
|
||||||
|
{
|
||||||
|
summary.AddedOne();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
summary.ErrorOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var res = await Storage.AddNewMafileFromData(item.Mafile, overwriteConflicts);
|
||||||
|
summary.Apply(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (summary.Added > 0)
|
||||||
|
{
|
||||||
|
QueryGroups();
|
||||||
|
if (!string.IsNullOrWhiteSpace(importGroup))
|
||||||
|
{
|
||||||
|
SelectedGroup = importGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ShowImportSummary(summary);
|
ShowImportSummary(summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ApplyImportGroup(Mafile mafile, string? group)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(group)) return;
|
||||||
|
mafile.Group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool HasImportConflict(Mafile mafile)
|
||||||
|
{
|
||||||
|
var fileName = MafilesStorageHelper.CreateMafileFileName(mafile, Settings.Instance.UseAccountNameAsMafileName);
|
||||||
|
return File.Exists(Path.Combine(Storage.MafilesDirectory, fileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task<MafileReadResult> TryReadMafile(string path, SDAEncryptionHelper.Context? sdaContext,
|
private async Task<MafileReadResult> TryReadMafile(string path, SDAEncryptionHelper.Context? sdaContext,
|
||||||
bool sdaPasswordPrompted)
|
bool sdaPasswordPrompted)
|
||||||
@@ -218,6 +275,7 @@ public partial class MainVM //File //TODO: Refactor
|
|||||||
|
|
||||||
var result = data.SessionData != null;
|
var result = data.SessionData != null;
|
||||||
if (!result) return result;
|
if (!result) return result;
|
||||||
|
data.Filename = null;
|
||||||
await Storage.SaveMafileAsync(data);
|
await Storage.SaveMafileAsync(data);
|
||||||
{
|
{
|
||||||
ResetQuery();
|
ResetQuery();
|
||||||
|
|||||||
@@ -11,5 +11,7 @@ public partial class LoginAgainVM : ObservableObject
|
|||||||
|
|
||||||
[ObservableProperty] private bool _savePassword;
|
[ObservableProperty] private bool _savePassword;
|
||||||
|
|
||||||
|
[ObservableProperty] private bool _showNoProxyWarning;
|
||||||
|
|
||||||
[ObservableProperty] private string _userName = null!;
|
[ObservableProperty] private string _userName = null!;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
@@ -10,6 +10,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
|||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using NebulaAuth.Core;
|
using NebulaAuth.Core;
|
||||||
using NebulaAuth.Model.MafileExport;
|
using NebulaAuth.Model.MafileExport;
|
||||||
|
using NebulaAuth.Model.Mafiles;
|
||||||
|
|
||||||
namespace NebulaAuth.ViewModel.Other;
|
namespace NebulaAuth.ViewModel.Other;
|
||||||
|
|
||||||
@@ -24,8 +25,7 @@ public partial class MafileExporterVM : ObservableObject
|
|||||||
|
|
||||||
public ObservableCollection<MafileExportTemplateVM> Templates { get; }
|
public ObservableCollection<MafileExportTemplateVM> Templates { get; }
|
||||||
|
|
||||||
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(ExportCommand))]
|
[ObservableProperty] private string? _accountsText;
|
||||||
private string? _accountsText;
|
|
||||||
|
|
||||||
private string? _cachedName;
|
private string? _cachedName;
|
||||||
private MafileExportTemplateVM? _currentTemplate;
|
private MafileExportTemplateVM? _currentTemplate;
|
||||||
@@ -160,6 +160,7 @@ public partial class MafileExporterVM : ObservableObject
|
|||||||
IncludeNebulaProxy = true,
|
IncludeNebulaProxy = true,
|
||||||
IncludeNebulaPassword = true,
|
IncludeNebulaPassword = true,
|
||||||
IncludeNebulaGroup = true,
|
IncludeNebulaGroup = true,
|
||||||
|
ExportToZip = false,
|
||||||
Path = null
|
Path = null
|
||||||
};
|
};
|
||||||
MafileExporterStorage.AddTemplate(template);
|
MafileExporterStorage.AddTemplate(template);
|
||||||
@@ -211,21 +212,26 @@ public partial class MafileExporterVM : ObservableObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand(CanExecute = nameof(ExportCanExecute))]
|
[RelayCommand(CanExecute = nameof(CurrentTemplateNotNull))]
|
||||||
private async Task Export()
|
private async Task Export()
|
||||||
{
|
{
|
||||||
var lines = AccountsText;
|
|
||||||
var template = CurrentTemplate;
|
var template = CurrentTemplate;
|
||||||
if (string.IsNullOrWhiteSpace(lines) || template == null)
|
if (template == null) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var split = Regex
|
string[] split;
|
||||||
.Split(lines, "\r\n|\r|\n")
|
if (string.IsNullOrWhiteSpace(AccountsText))
|
||||||
.Select(x => x.Trim())
|
{
|
||||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
split = Storage.MaFiles.Select(m => m.AccountName).ToArray();
|
||||||
.ToArray();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
split = Regex
|
||||||
|
.Split(AccountsText, "\r\n|\r|\n")
|
||||||
|
.Select(x => x.Trim())
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||||
|
.Select(ExtractLogin)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
ResetHintText();
|
ResetHintText();
|
||||||
ExportResult res;
|
ExportResult res;
|
||||||
@@ -268,6 +274,14 @@ public partial class MafileExporterVM : ObservableObject
|
|||||||
AccountsText = text;
|
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)
|
private void SetHintText(string? text, HintBoxSeverity severity = HintBoxSeverity.Error)
|
||||||
{
|
{
|
||||||
HintText = text;
|
HintText = text;
|
||||||
@@ -281,12 +295,6 @@ public partial class MafileExporterVM : ObservableObject
|
|||||||
|
|
||||||
#region CanExecute
|
#region CanExecute
|
||||||
|
|
||||||
private bool ExportCanExecute()
|
|
||||||
{
|
|
||||||
return CurrentTemplateNotNull() && !string.IsNullOrWhiteSpace(AccountsText);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private bool CurrentTemplateNotNull()
|
private bool CurrentTemplateNotNull()
|
||||||
{
|
{
|
||||||
return CurrentTemplate != null;
|
return CurrentTemplate != null;
|
||||||
@@ -307,6 +315,7 @@ public partial class MafileExporterVM : ObservableObject
|
|||||||
|
|
||||||
public partial class MafileExportTemplateVM : ObservableObject
|
public partial class MafileExportTemplateVM : ObservableObject
|
||||||
{
|
{
|
||||||
|
[ObservableProperty] private bool _exportToZip;
|
||||||
[ObservableProperty] private bool _includeIdentitySecret;
|
[ObservableProperty] private bool _includeIdentitySecret;
|
||||||
[ObservableProperty] private bool _includeNebulaGroup;
|
[ObservableProperty] private bool _includeNebulaGroup;
|
||||||
[ObservableProperty] private bool _includeNebulaPassword;
|
[ObservableProperty] private bool _includeNebulaPassword;
|
||||||
@@ -334,6 +343,7 @@ public partial class MafileExportTemplateVM : ObservableObject
|
|||||||
IncludeNebulaProxy = x.IncludeNebulaProxy,
|
IncludeNebulaProxy = x.IncludeNebulaProxy,
|
||||||
IncludeNebulaPassword = x.IncludeNebulaPassword,
|
IncludeNebulaPassword = x.IncludeNebulaPassword,
|
||||||
IncludeNebulaGroup = x.IncludeNebulaGroup,
|
IncludeNebulaGroup = x.IncludeNebulaGroup,
|
||||||
|
ExportToZip = x.ExportToZip,
|
||||||
Path = x.Path
|
Path = x.Path
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -352,6 +362,7 @@ public partial class MafileExportTemplateVM : ObservableObject
|
|||||||
IncludeNebulaProxy = IncludeNebulaProxy,
|
IncludeNebulaProxy = IncludeNebulaProxy,
|
||||||
IncludeNebulaPassword = IncludeNebulaPassword,
|
IncludeNebulaPassword = IncludeNebulaPassword,
|
||||||
IncludeNebulaGroup = IncludeNebulaGroup,
|
IncludeNebulaGroup = IncludeNebulaGroup,
|
||||||
|
ExportToZip = ExportToZip,
|
||||||
Path = Path
|
Path = Path
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -368,6 +379,7 @@ public partial class MafileExportTemplateVM : ObservableObject
|
|||||||
model.IncludeNebulaProxy = IncludeNebulaProxy;
|
model.IncludeNebulaProxy = IncludeNebulaProxy;
|
||||||
model.IncludeNebulaPassword = IncludeNebulaPassword;
|
model.IncludeNebulaPassword = IncludeNebulaPassword;
|
||||||
model.IncludeNebulaGroup = IncludeNebulaGroup;
|
model.IncludeNebulaGroup = IncludeNebulaGroup;
|
||||||
|
model.ExportToZip = ExportToZip;
|
||||||
model.Path = Path;
|
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);
|
||||||
@@ -80,7 +80,7 @@ public partial class ProxyManagerVM
|
|||||||
|
|
||||||
resolvedProxy = new MaProxy(parsedId, byId);
|
resolvedProxy = new MaProxy(parsedId, byId);
|
||||||
}
|
}
|
||||||
else if (ProxyStorage.DefaultScheme.TryParse(proxyPart, out var parsedProxy))
|
else if (ProxyStorage.DefaultScheme.TryParse(proxyPart, out var parsedProxy) || ProxyStorage.SignAtScheme.TryParse(proxyPart, out parsedProxy))
|
||||||
{
|
{
|
||||||
// Mode: login:proxy_string — find existing or add
|
// Mode: login:proxy_string — find existing or add
|
||||||
resolvedProxy = FindOrAddProxy(parsedProxy);
|
resolvedProxy = FindOrAddProxy(parsedProxy);
|
||||||
|
|||||||
@@ -168,10 +168,10 @@ public partial class SettingsVM : ObservableObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LegacyMode
|
public bool ConfirmMafileImport
|
||||||
{
|
{
|
||||||
get => Settings.LegacyMode;
|
get => Settings.ConfirmMafileImport;
|
||||||
set => Settings.LegacyMode = value;
|
set => Settings.ConfirmMafileImport = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AllowAutoUpdate
|
public bool AllowAutoUpdate
|
||||||
|
|||||||
@@ -80,4 +80,10 @@ public static class TimeAligner
|
|||||||
client.Dispose();
|
client.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetTimeDifference(int timeDifference)
|
||||||
|
{
|
||||||
|
_timeDifference = timeDifference;
|
||||||
|
_aligned = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user