0
0
mirror of https://github.com/sp-tarkov/launcher.git synced 2025-02-12 20:50:43 -05:00

Merge branch '3.10.0-DEV'

This commit is contained in:
Refringe 2024-11-26 09:53:59 -05:00
commit b899cf0882
Signed by: Refringe
SSH Key Fingerprint: SHA256:t865XsQpfTeqPRBMN2G6+N8wlDjkgUCZF3WGW6O9N/k
30 changed files with 519 additions and 1577 deletions

View File

@ -1,35 +0,0 @@
name: Trigger Main Build Pipeline
on:
push:
tags:
- '*'
jobs:
trigger-main-build:
runs-on: ubuntu-latest
steps:
- name: Setup Git Config
run: |
git config --global user.email "noreply@sp-tarkov.com"
git config --global user.name "TriggerBot"
- name: Clone Build Repository
run: |
rm -rf ../Build
git clone https://${{ secrets.BUILD_USERNAME }}:${{ secrets.BUILD_ACCESS_TOKEN }}@dev.sp-tarkov.com/SPT-AKI/Build.git ../Build
- name: Trigger Branch
working-directory: ../Build
run: git checkout -b trigger || git checkout trigger
- name: Create Trigger File
working-directory: ../Build
run: |
echo "${GITHUB_REF_NAME}" > .gitea/trigger
git add .gitea/trigger
git commit -m "Launcher triggered build with tag '${GITHUB_REF_NAME}'"
- name: Force Push
working-directory: ../Build
run: git push --force origin trigger

22
.github/workflows/build-trigger.yaml vendored Normal file
View File

@ -0,0 +1,22 @@
name: Trigger Main Build Pipeline
on:
push:
tags:
- "*"
jobs:
trigger-main-build:
runs-on: ubuntu-latest
steps:
- name: Trigger Build Workflow
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.BUILD_REPO_ACCESS_TOKEN }}
repository: sp-tarkov/build
event-type: build-trigger
client-payload: |
{
"repository": "${{ github.repository }}",
"tag": "${{ github.ref_name }}"
}

View File

@ -19,7 +19,7 @@ git config --local user.email "USERNAME@SOMETHING.com"
## Requirements ## Requirements
- Escape From Tarkov 31124 - Escape From Tarkov 33420
- .NET 8 SDK - .NET 8 SDK
- Visual Studio Code - Visual Studio Code
- [PowerShell v7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows) - [PowerShell v7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows)

View File

@ -289,6 +289,7 @@ namespace SPT.Launcher
} }
SelectedAccount.edition = edition; SelectedAccount.edition = edition;
SelectedAccount.wipe = true;
LogManager.Instance.Info($"Account Wiped: {data.username} -> {edition}"); LogManager.Instance.Info($"Account Wiped: {data.username} -> {edition}");
return AccountStatus.OK; return AccountStatus.OK;
} }

View File

@ -21,6 +21,7 @@ using SPT.Launcher.Controllers;
using SPT.Launcher.Interfaces; using SPT.Launcher.Interfaces;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SPT.Launcher.Models.SPT; using SPT.Launcher.Models.SPT;
using Newtonsoft.Json.Linq;
namespace SPT.Launcher namespace SPT.Launcher
{ {
@ -90,7 +91,7 @@ namespace SPT.Launcher
if (account.wipe) if (account.wipe)
{ {
LogManager.Instance.Info("[LaunchGame] Wipe profile requested"); LogManager.Instance.Info("[LaunchGame] Wipe profile requested");
RemoveRegistryKeys(); RemoveProfileRegistryKeys(account.id);
CleanTempFiles(); CleanTempFiles();
} }
@ -288,27 +289,24 @@ namespace SPT.Launcher
} }
/// <summary> /// <summary>
/// Remove the registry keys /// Remove the SPT JSON-based registry keys associated with the given profile ID
/// </summary> /// </summary>
/// <returns>returns true if the keys were removed. returns false if an exception occured</returns> public void RemoveProfileRegistryKeys(string profileId)
public bool RemoveRegistryKeys()
{ {
try var registryFile = new FileInfo(Path.Combine(Environment.CurrentDirectory, "user\\sptRegistry\\registry.json"));
{
var key = Registry.CurrentUser.OpenSubKey(registrySettings, true);
foreach (var value in key.GetValueNames()) if (!registryFile.Exists)
{ {
key.DeleteValue(value); return;
}
}
catch (Exception ex)
{
LogManager.Instance.Exception(ex);
return false;
} }
return true; JObject registryData = JObject.Parse(File.ReadAllText(registryFile.FullName));
// Find any property that has a key containing the profileId, and remove it
var propsToRemove = registryData.Properties().Where(prop => prop.Name.Contains(profileId, StringComparison.CurrentCultureIgnoreCase)).ToList();
propsToRemove.ForEach(prop => prop.Remove());
File.WriteAllText(registryFile.FullName, registryData.ToString());
} }
/// <summary> /// <summary>

View File

@ -33,7 +33,7 @@ namespace SPT.Launcher.Helpers
switch (result.Result) switch (result.Result)
{ {
case PatchResultType.Success: case PatchResultType.Success:
File.Copy(targetfile, $"{targetfile}.bak"); File.Copy(targetfile, $"{targetfile}.spt-bak");
VFS.WriteFile(targetfile, result.PatchedData); VFS.WriteFile(targetfile, result.PatchedData);
break; break;
@ -109,7 +109,7 @@ namespace SPT.Launcher.Helpers
foreach (var file in files) foreach (var file in files)
{ {
if (file.Extension == ".bak") if (file.Extension == ".spt-bak")
{ {
var target = Path.ChangeExtension(file.FullName, null); var target = Path.ChangeExtension(file.FullName, null);

View File

@ -13,6 +13,7 @@ using Newtonsoft.Json;
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using SPT.Launcher.Utilities;
using SPT.Launcher.Controllers; using SPT.Launcher.Controllers;
namespace SPT.Launcher.Helpers namespace SPT.Launcher.Helpers
@ -23,7 +24,7 @@ namespace SPT.Launcher.Helpers
public static Settings Instance { get; } = Json.Load<Settings>(DefaultSettingsFileLocation) ?? new Settings(); public static Settings Instance { get; } = Json.Load<Settings>(DefaultSettingsFileLocation) ?? new Settings();
} }
public class Settings : INotifyPropertyChanged public class Settings : NotifyPropertyChangedBase
{ {
public bool FirstRun { get; set; } = true; public bool FirstRun { get; set; } = true;
@ -72,121 +73,65 @@ namespace SPT.Launcher.Helpers
public string DefaultLocale { get; set; } = "English"; public string DefaultLocale { get; set; } = "English";
private bool _IsAddingServer; private bool _isAddingServer;
[JsonIgnore] [JsonIgnore]
public bool IsAddingServer public bool IsAddingServer
{ {
get => _IsAddingServer; get => _isAddingServer;
set set => SetProperty(ref _isAddingServer, value);
{
if (_IsAddingServer != value)
{
_IsAddingServer = value;
RaisePropertyChanged(nameof(IsAddingServer));
}
}
} }
private bool _AllowSettings; private bool _allowSettings;
[JsonIgnore] [JsonIgnore]
public bool AllowSettings public bool AllowSettings
{ {
get => _AllowSettings; get => _allowSettings;
set set => SetProperty(ref _allowSettings, value);
{
if (_AllowSettings != value)
{
_AllowSettings = value;
RaisePropertyChanged(nameof(AllowSettings));
}
}
} }
private bool _GameRunning; private bool _gameRunning;
[JsonIgnore] [JsonIgnore]
public bool GameRunning public bool GameRunning
{ {
get => _GameRunning; get => _gameRunning;
set set => SetProperty(ref _gameRunning, value);
{
if (_GameRunning != value)
{
_GameRunning = value;
RaisePropertyChanged(nameof(GameRunning));
}
}
} }
private LauncherAction _LauncherStartGameAction; private LauncherAction _launcherStartGameAction;
public LauncherAction LauncherStartGameAction public LauncherAction LauncherStartGameAction
{ {
get => _LauncherStartGameAction; get => _launcherStartGameAction;
set set => SetProperty(ref _launcherStartGameAction, value);
{
if (_LauncherStartGameAction != value)
{
_LauncherStartGameAction = value;
RaisePropertyChanged(nameof(LauncherStartGameAction));
}
}
} }
private bool _UseAutoLogin; private bool _useAutoLogin;
public bool UseAutoLogin public bool UseAutoLogin
{ {
get => _UseAutoLogin; get => _useAutoLogin;
set set => SetProperty(ref _useAutoLogin, value);
{
if (_UseAutoLogin != value)
{
_UseAutoLogin = value;
RaisePropertyChanged(nameof(UseAutoLogin));
}
}
} }
private bool _IsDevMode; private bool _isDevMode;
public bool IsDevMode public bool IsDevMode
{ {
get => _IsDevMode; get => _isDevMode;
set set => SetProperty(ref _isDevMode, value);
{
if (_IsDevMode != value)
{
_IsDevMode = value;
RaisePropertyChanged(nameof(IsDevMode));
}
}
} }
private string _GamePath; private string _gamePath;
public string GamePath public string GamePath
{ {
get => _GamePath; get => _gamePath;
set set => SetProperty(ref _gamePath, value);
{
if (_GamePath != value)
{
_GamePath = value;
RaisePropertyChanged(nameof(GamePath));
}
}
} }
private string[] _ExcludeFromCleanup; private string[] _excludeFromCleanup = [];
public string[] ExcludeFromCleanup public string[] ExcludeFromCleanup
{ {
get => _ExcludeFromCleanup ??= Array.Empty<string>(); get => _excludeFromCleanup;
set set => SetProperty(ref _excludeFromCleanup, value);
{
if (_ExcludeFromCleanup != value)
{
_ExcludeFromCleanup = value;
RaisePropertyChanged(nameof(ExcludeFromCleanup));
}
}
} }
public ServerSetting Server { get; set; } = new ServerSetting(); public ServerSetting Server { get; set; } = new ServerSetting();
@ -202,18 +147,15 @@ namespace SPT.Launcher.Helpers
GamePath = Environment.CurrentDirectory; GamePath = Environment.CurrentDirectory;
IsDevMode = false; IsDevMode = false;
Server = new ServerSetting { Name = "SPT", Url = "http://127.0.0.1:6969" }; Server = new ServerSetting
{
Name = "SPT",
Url = "http://127.0.0.1:6969"
};
SaveSettings(); SaveSettings();
} }
LogManager.Instance.Info($"Using launcher config at: {LauncherSettingsProvider.DefaultSettingsFileLocation}"); LogManager.Instance.Info($"Using launcher config at: {LauncherSettingsProvider.DefaultSettingsFileLocation}");
} }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -6,45 +6,24 @@
*/ */
using System.ComponentModel; using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher namespace SPT.Launcher.Models.Launcher
{ {
public class ConnectServerModel : INotifyPropertyChanged public class ConnectServerModel : NotifyPropertyChangedBase
{ {
private string _InfoText; private string _infoText;
public string InfoText public string InfoText
{ {
get => _InfoText; get => _infoText;
set set => SetProperty(ref _infoText, value);
{
if (_InfoText != value)
{
_InfoText = value;
RaisePropertyChanged(nameof(InfoText));
}
}
} }
private bool _ConnectionFailed; private bool _connectionFailed;
public bool ConnectionFailed public bool ConnectionFailed
{ {
get => _ConnectionFailed; get => _connectionFailed;
set set => SetProperty(ref _connectionFailed, value);
{
if(_ConnectionFailed != value)
{
_ConnectionFailed = value;
RaisePropertyChanged(nameof(ConnectionFailed));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
} }
} }
} }

View File

@ -9,53 +9,32 @@
using SPT.Launcher.Models.SPT; using SPT.Launcher.Models.SPT;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher namespace SPT.Launcher.Models.Launcher
{ {
public class EditionCollection : INotifyPropertyChanged public class EditionCollection : NotifyPropertyChangedBase
{ {
private bool _HasSelection; private bool _hasSelection;
public bool HasSelection public bool HasSelection
{ {
get => _HasSelection; get => _hasSelection;
set set => SetProperty(ref _hasSelection, value);
{
if(_HasSelection != value)
{
_HasSelection = value;
RaisePropertyChanged(nameof(HasSelection));
} }
} private int _selectedEditionIndex;
}
private int _SelectedEditionIndex;
public int SelectedEditionIndex public int SelectedEditionIndex
{ {
get => _SelectedEditionIndex; get => _selectedEditionIndex;
set set => SetProperty(ref _selectedEditionIndex, value);
{
if (_SelectedEditionIndex != value)
{
_SelectedEditionIndex = value;
RaisePropertyChanged(nameof(SelectedEditionIndex));
}
}
} }
private SPTEdition _SelectedEdition; private SPTEdition _selectedEdition;
public SPTEdition SelectedEdition public SPTEdition SelectedEdition
{ {
get => _SelectedEdition; get => _selectedEdition;
set set => SetProperty(ref _selectedEdition, value, () => HasSelection = _selectedEdition != null);
{
if (_SelectedEdition != value)
{
_SelectedEdition = value;
HasSelection = _SelectedEdition != null;
RaisePropertyChanged(nameof(SelectedEdition));
} }
} public ObservableCollection<SPTEdition> AvailableEditions { get; private set; } = [];
}
public ObservableCollection<SPTEdition> AvailableEditions { get; private set; } = new ObservableCollection<SPTEdition>();
public EditionCollection() public EditionCollection()
{ {
@ -66,12 +45,5 @@ namespace SPT.Launcher.Models.Launcher
AvailableEditions.Add(new SPTEdition(edition)); AvailableEditions.Add(new SPTEdition(edition));
} }
} }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
} }
} }

View File

@ -11,38 +11,24 @@ using SPT.Launcher.Helpers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher namespace SPT.Launcher.Models.Launcher
{ {
public class LocaleCollection : INotifyPropertyChanged public class LocaleCollection : NotifyPropertyChangedBase
{ {
private string _SelectedLocale; private string _selectedLocale;
public string SelectedLocale public string SelectedLocale
{ {
get => _SelectedLocale; get => _selectedLocale;
set set => SetProperty(ref _selectedLocale, value, () => LocalizationProvider.LoadLocalByName(value));
{
if (_SelectedLocale != value)
{
_SelectedLocale = value;
RaisePropertyChanged(nameof(SelectedLocale));
LocalizationProvider.LoadLocalByName(value);
}
}
} }
public ObservableCollection<string> AvailableLocales { get; set; } = LocalizationProvider.GetAvailableLocales(); public ObservableCollection<string> AvailableLocales { get; set; } = LocalizationProvider.GetAvailableLocales();
public event PropertyChangedEventHandler PropertyChanged;
public LocaleCollection() public LocaleCollection()
{ {
SelectedLocale = LocalizationProvider.LocaleNameDictionary.GetValueOrDefault(LauncherSettingsProvider.Instance.DefaultLocale, "English"); SelectedLocale = LocalizationProvider.LocaleNameDictionary.GetValueOrDefault(LauncherSettingsProvider.Instance.DefaultLocale, "English");
} }
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
} }
} }

View File

@ -2,25 +2,19 @@
using SPT.Launcher.Models.Launcher; using SPT.Launcher.Models.Launcher;
using System.ComponentModel; using System.ComponentModel;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models namespace SPT.Launcher.Models
{ {
public class LocalizedLauncherAction : INotifyPropertyChanged public class LocalizedLauncherAction : NotifyPropertyChangedBase
{ {
public LauncherAction Action { get; set; } public LauncherAction Action { get; set; }
private string _Name; private string _name;
public string Name public string Name
{ {
get => _Name; get => _name;
set set => SetProperty(ref _name, value);
{
if(_Name != value)
{
_Name = value;
RaisePropertyChanged(nameof(Name));
}
}
} }
public void UpdateLocaleName() public void UpdateLocaleName()
@ -49,12 +43,5 @@ namespace SPT.Launcher.Models
UpdateLocaleName(); UpdateLocaleName();
} }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
} }
} }

View File

@ -6,44 +6,24 @@
*/ */
using System.ComponentModel; using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher namespace SPT.Launcher.Models.Launcher
{ {
public class LoginModel : INotifyPropertyChanged public class LoginModel : NotifyPropertyChangedBase
{ {
private string _Username = ""; private string _username = "";
public string Username public string Username
{ {
get => _Username; get => _username;
set set => SetProperty(ref _username, value);
{
if (_Username != value)
{
_Username = value;
RaisePropertyChanged(nameof(Username));
}
}
} }
private string _Password = ""; private string _password = "";
public string Password public string Password
{ {
get => _Password; get => _password;
set set => SetProperty(ref _password, value);
{
if (_Password != value)
{
_Password = value;
RaisePropertyChanged(nameof(Password));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
} }
} }
} }

View File

@ -9,62 +9,35 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher namespace SPT.Launcher.Models.Launcher
{ {
public class MenuBarItem : INotifyPropertyChanged public class MenuBarItem : NotifyPropertyChangedBase
{ {
private string _Name; private string _name;
public string Name public string Name
{ {
get => _Name; get => _name;
set set => SetProperty(ref _name, value);
{
if (_Name != value)
{
_Name = value;
RaisePropertyChanged(nameof(Name));
}
}
} }
private bool _IsSelected; private bool _isSelected;
public bool IsSelected public bool IsSelected
{ {
get => _IsSelected; get => _isSelected;
set set => SetProperty(ref _isSelected, value);
{
if (_IsSelected != value)
{
_IsSelected = value;
RaisePropertyChanged(nameof(IsSelected));
}
}
} }
private Action _ItemAction; private Action _itemAction;
public Action ItemAction public Action ItemAction
{ {
get => _ItemAction; get => _itemAction;
set set => SetProperty(ref _itemAction, value);
{
if (_ItemAction != value)
{
_ItemAction = value;
RaisePropertyChanged(nameof(ItemAction));
}
}
} }
public Func<Task<bool>> CanUseAction = async () => await Task.FromResult(true); public Func<Task<bool>> CanUseAction = async () => await Task.FromResult(true);
public Action OnFailedToUseAction = null; public Action OnFailedToUseAction = null;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
} }
} }

View File

@ -2,55 +2,35 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher namespace SPT.Launcher.Models.Launcher
{ {
public class ModInfoCollection : INotifyPropertyChanged public class ModInfoCollection : NotifyPropertyChangedBase
{ {
private int _serverModsCount; private int _serverModsCount;
public int ServerModsCount public int ServerModsCount
{ {
get => _serverModsCount; get => _serverModsCount;
set set => SetProperty(ref _serverModsCount, value);
{
if (_serverModsCount != value)
{
_serverModsCount = value;
RaisePropertyChanged(nameof(ServerModsCount));
}
}
} }
private int _profileModsCount; private int _profileModsCount;
public int ProfileModsCount public int ProfileModsCount
{ {
get => _profileModsCount; get => _profileModsCount;
set set => SetProperty(ref _profileModsCount, value);
{
if (_profileModsCount != value)
{
_profileModsCount = value;
RaisePropertyChanged(nameof(ProfileModsCount));
}
}
} }
private bool _hasMods; private bool _hasMods;
public bool HasMods public bool HasMods
{ {
get => _hasMods; get => _hasMods;
set set => SetProperty(ref _hasMods, value);
{
if (_hasMods != value)
{
_hasMods = value;
RaisePropertyChanged(nameof(HasMods));
}
}
} }
public ObservableCollection<SPTMod> ActiveMods { get; private set; } = new ObservableCollection<SPTMod>(); public ObservableCollection<SPTMod> ActiveMods { get; private set; } = [];
public ObservableCollection<SPTMod> InactiveMods { get; private set; } = new ObservableCollection<SPTMod>(); public ObservableCollection<SPTMod> InactiveMods { get; private set; } = [];
public ModInfoCollection() public ModInfoCollection()
{ {
@ -68,7 +48,7 @@ namespace SPT.Launcher.Models.Launcher
foreach (var inactiveMod in profileMods) foreach (var inactiveMod in profileMods)
{ {
var existingMod = ActiveMods.Where(x => x.Name == inactiveMod.Name && x.Version == inactiveMod.Version && x.Author == inactiveMod.Author).FirstOrDefault(); var existingMod = ActiveMods.FirstOrDefault(x => x.Name == inactiveMod.Name && x.Version == inactiveMod.Version && x.Author == inactiveMod.Author);
if (existingMod != null) if (existingMod != null)
{ {
@ -82,11 +62,5 @@ namespace SPT.Launcher.Models.Launcher
HasMods = ActiveMods.Count > 0 || InactiveMods.Count > 0; HasMods = ActiveMods.Count > 0 || InactiveMods.Count > 0;
} }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
} }
} }

View File

@ -9,75 +9,48 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher.Notifications namespace SPT.Launcher.Models.Launcher.Notifications
{ {
public class NotificationItem : INotifyPropertyChanged public class NotificationItem : NotifyPropertyChangedBase
{ {
private string _Message; private string _message;
public string Message public string Message
{ {
get => _Message; get => _message;
set set => SetProperty(ref _message, value);
{
if (_Message != value)
{
_Message = value;
RaisePropertyChanged(nameof(Message));
}
}
} }
private string _ButtonText; private string _buttonText;
public string ButtonText public string ButtonText
{ {
get => _ButtonText; get => _buttonText;
set set => SetProperty(ref _buttonText, value);
{
if (_ButtonText != value)
{
_ButtonText = value;
RaisePropertyChanged(nameof(ButtonText));
}
}
} }
private bool _HasButton; private bool _hasButton;
public bool HasButton public bool HasButton
{ {
get => _HasButton; get => _hasButton;
set set => SetProperty(ref _hasButton, value);
{
if (_HasButton != value)
{
_HasButton = value;
RaisePropertyChanged(nameof(HasButton));
}
}
} }
public Action ItemAction = null; public Action ItemAction = null;
public NotificationItem(string Message) public NotificationItem(string message)
{ {
this.Message = Message; Message = message;
ButtonText = string.Empty; ButtonText = string.Empty;
HasButton = false; HasButton = false;
} }
public NotificationItem(string Message, string ButtonText, Action ItemAction) public NotificationItem(string message, string buttonText, Action itemAction)
{ {
this.Message = Message; Message = message;
this.ButtonText = ButtonText; ButtonText = buttonText;
HasButton = true; HasButton = true;
this.ItemAction = ItemAction; ItemAction = itemAction;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
} }
} }
} }

View File

@ -13,35 +13,29 @@ using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Timers; using System.Timers;
using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher.Notifications namespace SPT.Launcher.Models.Launcher.Notifications
{ {
public class NotificationQueue : INotifyPropertyChanged, IDisposable public class NotificationQueue : NotifyPropertyChangedBase, IDisposable
{ {
public Timer queueTimer = new Timer(); public Timer queueTimer = new Timer();
private Timer animateChangeTimer = new Timer(230); private Timer animateChangeTimer = new Timer(230);
private Timer animateCloseTimer = new Timer(230); private Timer animateCloseTimer = new Timer(230);
public ObservableCollection<NotificationItem> queue { get; set; } = new ObservableCollection<NotificationItem>(); public ObservableCollection<NotificationItem> queue { get; set; } = [];
private bool _ShowBanner; private bool _showBanner;
public bool ShowBanner public bool ShowBanner
{ {
get => _ShowBanner; get => _showBanner;
set set => SetProperty(ref _showBanner, value);
{
if (_ShowBanner != value)
{
_ShowBanner = value;
RaisePropertyChanged(nameof(ShowBanner));
}
}
} }
public NotificationQueue(int ShowTimeInMiliseconds) public NotificationQueue(int showTimeInMilliseconds)
{ {
ShowBanner = false; ShowBanner = false;
queueTimer.Interval = ShowTimeInMiliseconds; queueTimer.Interval = showTimeInMilliseconds;
queueTimer.Elapsed += QueueTimer_Elapsed; queueTimer.Elapsed += QueueTimer_Elapsed;
animateChangeTimer.Elapsed += AnimateChange_Elapsed; animateChangeTimer.Elapsed += AnimateChange_Elapsed;
@ -71,43 +65,43 @@ namespace SPT.Launcher.Models.Launcher.Notifications
} }
} }
public void Enqueue(string Message, bool AutowNext = false, bool NoDefaultButton = false) public void Enqueue(string message, bool autoNext = false, bool noDefaultButton = false)
{ {
if (queue.Where(x => x.Message == Message).Count() == 0) if (queue.All(x => x.Message != message))
{ {
if (NoDefaultButton) if (noDefaultButton)
{ {
queue.Add(new NotificationItem(Message)); queue.Add(new NotificationItem(message));
} }
else else
{ {
queue.Add(new NotificationItem(Message, LocalizationProvider.Instance.ok, () => { })); queue.Add(new NotificationItem(message, LocalizationProvider.Instance.ok, () => { }));
} }
CheckAndShowNotifications(); CheckAndShowNotifications();
if (AutowNext && queue.Count == 2) if (autoNext && queue.Count == 2)
{ {
Next(true); Next(true);
} }
} }
} }
public void Enqueue(string Message, string ButtonText, Action ButtonAction, bool AllowNext = false) public void Enqueue(string message, string buttonText, Action buttonAction, bool allowNext = false)
{ {
if (queue.Where(x => x.Message == Message && x.ButtonText == ButtonText).Count() == 0) if (queue.All(x=>x.Message != message && x.ButtonText != buttonText))
{ {
queue.Add(new NotificationItem(Message, ButtonText, ButtonAction)); queue.Add(new NotificationItem(message, buttonText, buttonAction));
CheckAndShowNotifications(); CheckAndShowNotifications();
if (AllowNext && queue.Count == 2) if (allowNext && queue.Count == 2)
{ {
Next(true); Next(true);
} }
} }
} }
public void Next(bool ResetTimer = false) public void Next(bool resetTimer = false)
{ {
if (queue.Count - 1 <= 0) if (queue.Count - 1 <= 0)
{ {
@ -115,7 +109,7 @@ namespace SPT.Launcher.Models.Launcher.Notifications
return; return;
} }
if (ResetTimer) if (resetTimer)
{ {
queueTimer.Stop(); queueTimer.Stop();
queueTimer.Start(); queueTimer.Start();
@ -142,13 +136,6 @@ namespace SPT.Launcher.Models.Launcher.Notifications
ShowBanner = true; ShowBanner = true;
} }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public void Dispose() public void Dispose()
{ {
queueTimer.Dispose(); queueTimer.Dispose();

View File

@ -12,210 +12,127 @@ using SPT.Launcher.Models.SPT;
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher namespace SPT.Launcher.Models.Launcher
{ {
public class ProfileInfo : INotifyPropertyChanged public class ProfileInfo : NotifyPropertyChangedBase
{ {
private string _Username; private string _username;
public string Username public string Username
{ {
get => _Username; get => _username;
set set => SetProperty(ref _username, value);
{
if(_Username != value)
{
_Username = value;
RaisePropertyChanged(nameof(Username));
}
}
} }
private string _Nickname; private string _nickname;
public string Nickname public string Nickname
{ {
get => _Nickname; get => _nickname;
set set => SetProperty(ref _nickname, value);
{
if (_Nickname != value)
{
_Nickname = value;
RaisePropertyChanged(nameof(Nickname));
}
}
} }
private string _SideImage; private string _sideImage;
public string SideImage public string SideImage
{ {
get => _SideImage; get => _sideImage;
set set => SetProperty(ref _sideImage, value);
{
if (_SideImage != value)
{
_SideImage = value;
RaisePropertyChanged(nameof(SideImage));
}
}
} }
private string _Side; private string _side;
public string Side public string Side
{ {
get => _Side; get => _side;
set set => SetProperty(ref _side, value);
{
if (_Side != value)
{
_Side = value;
RaisePropertyChanged(nameof(Side));
}
}
} }
private string _Level; private string _level;
public string Level public string Level
{ {
get => _Level; get => _level;
set set => SetProperty(ref _level, value);
{
if (_Level != value)
{
_Level = value;
RaisePropertyChanged(nameof(Level));
}
}
} }
private int _XPLevelProgress; private int _XPLevelProgress;
public int XPLevelProgress public int XPLevelProgress
{ {
get => _XPLevelProgress; get => _XPLevelProgress;
set set => SetProperty(ref _XPLevelProgress, value);
{
if (_XPLevelProgress != value)
{
_XPLevelProgress = value;
RaisePropertyChanged(nameof(XPLevelProgress));
}
}
} }
private long _CurrentXP; private long _currentXP;
public long CurrentExp public long CurrentExp
{ {
get => _CurrentXP; get => _currentXP;
set set => SetProperty(ref _currentXP, value);
{
if (_CurrentXP != value)
{
_CurrentXP = value;
RaisePropertyChanged(nameof(CurrentExp));
}
}
} }
private long _RemainingExp; private long _remainingExp;
public long RemainingExp public long RemainingExp
{ {
get => _RemainingExp; get => _remainingExp;
set set => SetProperty(ref _remainingExp, value);
{
if (_RemainingExp != value)
{
_RemainingExp = value;
RaisePropertyChanged(nameof(RemainingExp));
}
}
} }
private long _NextLvlExp; private long _nextLvlExp;
public long NextLvlExp public long NextLvlExp
{ {
get => _NextLvlExp; get => _nextLvlExp;
set set => SetProperty(ref _nextLvlExp, value);
{
if (_NextLvlExp != value)
{
_NextLvlExp = value;
RaisePropertyChanged(nameof(NextLvlExp));
}
}
} }
private bool _HasData; private bool _hasData;
public bool HasData public bool HasData
{ {
get => _HasData; get => _hasData;
set set => SetProperty(ref _hasData, value);
{
if (_HasData != value)
{
_HasData = value;
RaisePropertyChanged(nameof(HasData));
}
}
} }
public string MismatchMessage => VersionMismatch ? LocalizationProvider.Instance.profile_version_mismath : null; public string MismatchMessage => VersionMismatch ? LocalizationProvider.Instance.profile_version_mismath : null;
private bool _VersionMismatch; private bool _versionMismatch;
public bool VersionMismatch public bool VersionMismatch
{ {
get => _VersionMismatch; get => _versionMismatch;
set set => SetProperty(ref _versionMismatch, value);
{
if(_VersionMismatch != value)
{
_VersionMismatch = value;
RaisePropertyChanged(nameof(VersionMismatch));
}
}
} }
private SPTData _SPT; private SPTData _spt;
public SPTData SPT public SPTData SPT
{ {
get => _SPT; get => _spt;
set set => SetProperty(ref _spt, value);
{
if(_SPT != value)
{
_SPT = value;
RaisePropertyChanged(nameof(SPT));
}
}
} }
public void UpdateDisplayedProfile(ProfileInfo PInfo) public void UpdateDisplayedProfile(ProfileInfo pInfo)
{ {
if (PInfo.Side == null || string.IsNullOrWhiteSpace(PInfo.Side) || PInfo.Side == "unknown") return; if (pInfo.Side == null || string.IsNullOrWhiteSpace(pInfo.Side) || pInfo.Side == "unknown") return;
HasData = true; HasData = true;
Nickname = PInfo.Nickname; Nickname = pInfo.Nickname;
Side = PInfo.Side; Side = pInfo.Side;
SideImage = PInfo.SideImage; SideImage = pInfo.SideImage;
Level = PInfo.Level; Level = pInfo.Level;
CurrentExp = PInfo.CurrentExp; CurrentExp = pInfo.CurrentExp;
NextLvlExp = PInfo.NextLvlExp; NextLvlExp = pInfo.NextLvlExp;
RemainingExp = PInfo.RemainingExp; RemainingExp = pInfo.RemainingExp;
XPLevelProgress = PInfo.XPLevelProgress; XPLevelProgress = pInfo.XPLevelProgress;
SPT = PInfo.SPT; SPT = pInfo.SPT;
} }
/// <summary> /// <summary>
/// Checks if the SPT versions are compatible (non-major changes) /// Checks if the SPT versions are compatible (non-major changes)
/// </summary> /// </summary>
/// <param name="CurrentVersion"></param> /// <param name="currentVersion"></param>
/// <param name="ExpectedVersion"></param> /// <param name="expectedVersion"></param>
/// <returns></returns> /// <returns></returns>
private bool CompareVersions(string CurrentVersion, string ExpectedVersion) private bool CompareVersions(string currentVersion, string expectedVersion)
{ {
if (ExpectedVersion == "") return false; if (expectedVersion == "") return false;
SPTVersion v1 = new SPTVersion(CurrentVersion); var v1 = new SPTVersion(currentVersion);
SPTVersion v2 = new SPTVersion(ExpectedVersion); var v2 = new SPTVersion(expectedVersion);
// check 'X'.x.x // check 'X'.x.x
if (v1.Major != v2.Major) return false; if (v1.Major != v2.Major) return false;
@ -242,14 +159,7 @@ namespace SPT.Launcher.Models.Launcher
SideImage = Path.Combine(ImageRequest.ImageCacheFolder, $"side_{Side.ToLower()}.png"); SideImage = Path.Combine(ImageRequest.ImageCacheFolder, $"side_{Side.ToLower()}.png");
if (Side != null && !string.IsNullOrWhiteSpace(Side) && Side != "unknown") HasData = Side != null && !string.IsNullOrWhiteSpace(Side) && Side != "unknown";
{
HasData = true;
}
else
{
HasData = false;
}
Level = serverProfileInfo.currlvl.ToString(); Level = serverProfileInfo.currlvl.ToString();
CurrentExp = serverProfileInfo.currexp; CurrentExp = serverProfileInfo.currexp;
@ -269,12 +179,5 @@ namespace SPT.Launcher.Models.Launcher
XPLevelProgress = (int)Math.Floor((((double)currentLvlTotal) - RemainingExp) / currentLvlTotal * 100); XPLevelProgress = (int)Math.Floor((((double)currentLvlTotal) - RemainingExp) / currentLvlTotal * 100);
} }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
} }
} }

View File

@ -6,47 +6,27 @@
*/ */
using System.ComponentModel; using SPT.Launcher.Utilities;
using SPT.Launcher.Models.Launcher;
namespace SPT.Launcher.Models.Launcher namespace SPT.Launch.Models.Launcher
{ {
public class RegisterModel : INotifyPropertyChanged public class RegisterModel : NotifyPropertyChangedBase
{ {
private string _Username; private string _username;
public string Username public string Username
{ {
get => _Username; get => _username;
set set => SetProperty(ref _username, value);
{
if (_Username != value)
{
_Username = value;
RaisePropertyChanged(nameof(Username));
}
}
} }
private string _Password; private string _password;
public string Password public string Password
{ {
get => _Password; get => _password;
set set => SetProperty(ref _password, value);
{
if (_Password != value)
{
_Password = value;
RaisePropertyChanged(nameof(Password));
}
}
} }
public EditionCollection EditionsCollection { get; set; } = new EditionCollection(); public EditionCollection EditionsCollection { get; set; } = new EditionCollection();
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
} }
} }

View File

@ -7,47 +7,26 @@
*/ */
using System.ComponentModel; using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.Launcher namespace SPT.Launcher.Models.Launcher
{ {
public class ServerSetting : INotifyPropertyChanged public class ServerSetting : NotifyPropertyChangedBase
{ {
public LoginModel AutoLoginCreds { get; set; } = null; public LoginModel AutoLoginCreds { get; set; } = null;
private string _Name; private string _name;
public string Name public string Name
{ {
get => _Name; get => _name;
set set => SetProperty(ref _name, value);
{
if (_Name != value)
{
_Name = value;
RaisePropertyChanged(nameof(Name));
}
}
} }
private string _Url; private string _url;
public string Url public string Url
{ {
get => _Url; get => _url;
set set => SetProperty(ref _url, value);
{
if (_Url != value)
{
_Url = value;
RaisePropertyChanged(nameof(Url));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
} }
} }
} }

View File

@ -1,42 +1,34 @@
using System.ComponentModel; using SPT.Launcher.Utilities;
namespace SPT.Launcher.Models.SPT namespace SPT.Launcher.Models.SPT
{ {
public class SPTVersion : INotifyPropertyChanged public class SPTVersion : NotifyPropertyChangedBase
{ {
public int Major; public int Major;
public int Minor; public int Minor;
public int Build; public int Build;
public bool HasTag => Tag != null; public bool HasTag => Tag != string.Empty;
private string _Tag = null; private string _tag = string.Empty;
public string Tag public string Tag
{ {
get => _Tag; get => _tag;
set set => SetProperty(ref _tag, value, () => RaisePropertyChanged(nameof(HasTag)));
{
if(_Tag != value)
{
_Tag = value;
RaisePropertyChanged(nameof(Tag));
RaisePropertyChanged(nameof(HasTag));
}
}
} }
public void ParseVersionInfo(string SPTVersion) public void ParseVersionInfo(string sptVersion)
{ {
if (SPTVersion.Contains('-')) if (sptVersion.Contains('-'))
{ {
string[] versionInfo = SPTVersion.Split('-'); string[] versionInfo = sptVersion.Split('-');
SPTVersion = versionInfo[0]; sptVersion = versionInfo[0];
Tag = versionInfo[1]; Tag = versionInfo[1];
} }
string[] splitVersion = SPTVersion.Split('.'); string[] splitVersion = sptVersion.Split('.');
if (splitVersion.Length >= 3) if (splitVersion.Length >= 3)
{ {
@ -48,16 +40,9 @@ namespace SPT.Launcher.Models.SPT
public SPTVersion() { } public SPTVersion() { }
public SPTVersion(string SPTVersion) public SPTVersion(string sptVersion)
{ {
ParseVersionInfo(SPTVersion); ParseVersionInfo(sptVersion);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
} }
public override string ToString() public override string ToString()

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<RootNamespace>SPT.Launch</RootNamespace> <RootNamespace>SPT.Launcher</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace SPT.Launcher.Utilities;
public abstract class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetProperty<T>(ref T field, T value, Action afterSetAction = null, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
RaisePropertyChanged(propertyName);
afterSetAction?.Invoke();
}
}
protected void SetNotNullableProperty<T>(ref T field, T value, Action afterSetAction = null, [CallerMemberName] string propertyName = null)
{
if (value is not null)
{
SetProperty(ref field, value, afterSetAction, propertyName );
}
}
}

View File

@ -80,5 +80,17 @@
FillRule="NonZero" FillRule="NonZero"
/> />
<PathGeometry x:Key="BackArrow" Figures="M12 2.001c5.524 0 10 4.477 10 10s-4.476 10-10 10c-5.522 0-10-4.477-10-10s4.478-10 10-10Zm.781 5.469-.084-.073a.75.75 0 0 0-.883-.007l-.094.08-.072.084a.75.75 0 0 0-.007.883l.08.094 2.719 2.72H7.75l-.102.006a.75.75 0 0 0-.641.642L7 12l.007.102a.75.75 0 0 0 .641.641l.102.007h6.69l-2.72 2.72-.073.085a.75.75 0 0 0 1.05 1.05l.083-.073 4.002-4 .072-.085a.75.75 0 0 0 .008-.882l-.08-.094-4-4.001-.085-.073.084.073Z"
FillRule="NonZero"
/>
<PathGeometry x:Key="Close" Figures="m4.21 4.387.083-.094a1 1 0 0 1 1.32-.083l.094.083L12 10.585l6.293-6.292a1 1 0 1 1 1.414 1.414L13.415 12l6.292 6.293a1 1 0 0 1 .083 1.32l-.083.094a1 1 0 0 1-1.32.083l-.094-.083L12 13.415l-6.293 6.292a1 1 0 0 1-1.414-1.414L10.585 12 4.293 5.707a1 1 0 0 1-.083-1.32l.083-.094-.083.094Z"
FillRule="NonZero"
/>
<PathGeometry x:Key="Minimize" Figures="M3.997 13H20a1 1 0 1 0 0-2H3.997a1 1 0 1 0 0 2Z"
FillRule="NonZero"
/>
</Application.Resources> </Application.Resources>
</Application> </Application>

View File

@ -23,8 +23,7 @@
/> />
<!-- Setting button --> <!-- Setting button -->
<Button x:Name="stb" <Button Grid.Column="2"
Grid.Column="2"
FontSize="12" FontSize="12"
Command="{Binding SettingsButtonCommand, RelativeSource={ Command="{Binding SettingsButtonCommand, RelativeSource={
RelativeSource AncestorType=UserControl}}" RelativeSource AncestorType=UserControl}}"
@ -33,14 +32,19 @@
IsVisible="{Binding Source={x:Static helpers:LauncherSettingsProvider.Instance}, Path=AllowSettings}" IsVisible="{Binding Source={x:Static helpers:LauncherSettingsProvider.Instance}, Path=AllowSettings}"
> >
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Path Data="{StaticResource Gear}" Fill="{Binding ElementName=stb, Path=Foreground}" <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
Margin="2"/> <Viewbox Width="14" Height="14" Margin="2">
<Path Data="{StaticResource Gear}"
Fill="{Binding $parent[TextBlock].Foreground}"
/>
</Viewbox>
</TextBlock>
<TextBlock Text="{Binding Source={x:Static helpers:LocalizationProvider.Instance}, Path=settings_menu}"/> <TextBlock Text="{Binding Source={x:Static helpers:LocalizationProvider.Instance}, Path=settings_menu}"/>
</StackPanel> </StackPanel>
</Button> </Button>
<!-- Minimize (-) Button --> <!-- Minimize (-) Button -->
<Button Content="&#xE949;" Grid.Column="4" <Button Grid.Column="4"
Foreground="{Binding ButtonForeground, RelativeSource={ Foreground="{Binding ButtonForeground, RelativeSource={
RelativeSource AncestorType=UserControl}}" RelativeSource AncestorType=UserControl}}"
Command="{Binding MinButtonCommand, RelativeSource={ Command="{Binding MinButtonCommand, RelativeSource={
@ -49,10 +53,16 @@
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
FontFamily="Segoe MDL2 Assets"
CornerRadius="0" CornerRadius="0"
Width="35" Width="35"
> >
<Viewbox Width="15" Height="15">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Path Data="{StaticResource Minimize}"
Fill="{Binding $parent[TextBlock].Foreground}"
/>
</TextBlock>
</Viewbox>
<Button.Styles> <Button.Styles>
<Style Selector="Button:pointerover /template/ ContentPresenter"> <Style Selector="Button:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentBrush2}"/> <Setter Property="Background" Value="{DynamicResource AccentBrush2}"/>
@ -65,7 +75,7 @@
</Button> </Button>
<!-- Close (X) Button --> <!-- Close (X) Button -->
<Button Content="&#xE106;" Grid.Column="5" <Button Grid.Column="5"
Foreground="{Binding ButtonForeground, RelativeSource={ Foreground="{Binding ButtonForeground, RelativeSource={
RelativeSource AncestorType=UserControl}}" RelativeSource AncestorType=UserControl}}"
Command="{Binding XButtonCommand, RelativeSource={ Command="{Binding XButtonCommand, RelativeSource={
@ -74,10 +84,16 @@
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
FontFamily="Segoe MDL2 Assets"
CornerRadius="0" CornerRadius="0"
Width="35" Width="35"
> >
<Viewbox Width="15" Height="15">
<TextBlock>
<Path Data="{StaticResource Close}"
Fill="{Binding $parent[TextBlock].Foreground}"
/>
</TextBlock>
</Viewbox>
<Button.Styles> <Button.Styles>
<Style Selector="Button:pointerover /template/ ContentPresenter"> <Style Selector="Button:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="IndianRed"/> <Setter Property="Background" Value="IndianRed"/>

View File

@ -6,6 +6,7 @@
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract> <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ApplicationIcon>Assets\spt-logo.ico</ApplicationIcon> <ApplicationIcon>Assets\spt-logo.ico</ApplicationIcon>
<NoWin32Manifest>true</NoWin32Manifest>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<AvaloniaResource Include="Assets\**" /> <AvaloniaResource Include="Assets\**" />
@ -22,12 +23,12 @@
<Content Include="Assets\icon.ico" /> <Content Include="Assets\icon.ico" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="11.1.0-rc2" /> <PackageReference Include="Avalonia" Version="11.1.1" />
<PackageReference Include="Avalonia.Desktop" Version="11.1.0-rc2" /> <PackageReference Include="Avalonia.Desktop" Version="11.1.1" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.--> <!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.12" /> <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.12" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.1.0-rc2" /> <PackageReference Include="Avalonia.ReactiveUI" Version="11.1.1" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.0-rc2" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.1" />
<PackageReference Include="DialogHost.Avalonia" Version="0.8.0-avalonia11dot1-3" /> <PackageReference Include="DialogHost.Avalonia" Version="0.8.0-avalonia11dot1-3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,103 +1,103 @@
{ {
"ietf_tag": "tr", "ietf_tag": "tr",
"native_name": "Turkish", "native_name": "Türkçe",
"retry": "Yeniden Dene", "retry": "Yeniden Dene",
"server_connecting": "Bağlanıyor", "server_connecting": "Bağlanıyor",
"server_unavailable_format_1": "Varsayılan sunucu '{0}' mevcut değil.", "server_unavailable_format_1": "Bağlanmak için Önce 'SPT.Server.exe' dosyasını çalıştırdığınızdan emin olun.",
"no_servers_available": "Sunucu bulunamadı. AyarlardSPT sunucu listesini kontrol edin.", "no_servers_available": "SPT Sunucusu bulunamadı. SPT sunucunuzun çalıştığından emin olun ve ayarlar sayfasında sunucu URL'sinin doğru olup olmadığını kontrol edin.",
"settings_menu": "Ayarlar", "settings_menu": "Ayarlar",
"back": "Geri dön", "back": "Geri dön",
"wipe_profile": "Profili Wipela", "wipe_profile": "Profili Sıfırla",
"username": "Kullanıcı Adı", "username": "Kullanıcı Adı",
"password": "Şifre", "password": "Şifre",
"update": "Güncelleme", "update": "Güncelle",
"edit_account_update_error": "Profilinizi güncellerken bir sorun oluştu.", "edit_account_update_error": "Profilinizi güncellerken bir sorun oluştu.",
"register": "Kayıt Ol", "register": "Kayıt Ol",
"go_to_register": "Kayıt Ol'a git", "go_to_register": "Kaydol'a git",
"login_or_register": "Giriş Yap / Kaydol", "login_or_register": "Giriş Yap / Kaydol",
"go_to_login": "Giriş Yap'a git", "go_to_login": "Giriş Yap'a git",
"login_automatically": "Otomatik Oturum Açma", "login_automatically": "Otomatik Giriş",
"incorrect_login": "Kullanıcı adı veya şifre yanlış.", "incorrect_login": "Kullanıcı adı veya şifre yanlış.",
"login_failed": "Oturum Açma Başarısız", "login_failed": "Giriş Başarısız",
"edition": "Sürüm", "edition": "Sürüm",
"id": "ID", "id": "ID",
"logout": "Oturumu Kapat", "logout": "Oturumu Kapat",
"account": "Profil", "account": "Profil",
"edit_account": "Profil Düzenle", "edit_account": "Profili Düzenle",
"start_game": "Oyunu Başlat", "start_game": "Oyunu Başlat",
"installed_in_live_game_warning": "SPT canlı oyun dizinine yüklenmemelidir. Lütfen SPT'yi bilgisayarınızın başka bir yerindeki oyun dizininin bir kopyasına yükleyin.", "installed_in_live_game_warning": "SPT canlı oyun dizinine yüklenmemelidir. Lütfen SPT'yi bilgisayarınızın başka bir yerindeki oyun dizininin bir kopyasına yükleyin.",
"no_official_game_warning": "Escape From Tarkov oyunu bilgisayarınızda yüklü değil. Lütfen oyunun bir kopyasını satın alın ve geliştiricileri destekleyin!", "no_official_game_warning": "Escape From Tarkov bilgisayarınızda yüklü değil. SPT'yi başlatmadan önce BSG başlatıcınızın oyunu başlatabildiğinden emin olun.",
"eft_exe_not_found_warning": "EscapeFromTarkov.exe oyun yolunda bulunamadı. Lütfen dizinin doğru olup olmadığını kontrol edin.", "eft_exe_not_found_warning": "EscapeFromTarkov.exe oyun yolunda bulunamadı. Lütfen SPT'yi yüklediğiniz klasörde bu dosyanın olup olmadığını kontrol edin.",
"account_exist": "Profil zaten mevcut", "account_exist": "Profil zaten mevcut",
"url": "URL", "url": "URL",
"default_language": "Varsayılan Dil", "default_language": "Varsayılan Dil",
"game_path": "SPT Oyun Klasörü", "game_path": "SPT Oyun Dosyası",
"clear_game_settings": "Oyun Ayarlarını Temizle", "clear_game_settings": "Oyun Ayarlarını Temizle",
"clear_game_settings_succeeded": "Oyun ayarları temizlendi.", "clear_game_settings_succeeded": "Oyun ayarları temizlendi.",
"clear_game_settings_failed": "Oyun ayarları temizlenirken bir sorun oluştu.", "clear_game_settings_failed": "Oyun ayarları temizlenirken bir sorun oluştu.",
"remove_registry_keys": "Kayıt Defteri Anahtarlarını Kaldır", "remove_registry_keys": "Kayıt Defteri Anahtarlarını Silme",
"remove_registry_keys_succeeded": "Kayıt defteri anahtarları kaldırıldı.", "remove_registry_keys_succeeded": "Kayıt defteri anahtarları silindi.",
"remove_registry_keys_failed": "Kayıt defteri anahtarları kaldırılırken bir sorun oluştu.", "remove_registry_keys_failed": "Kayıt defteri anahtarları silerken bir sorun oluştu.",
"clean_temp_files": "Temp Dosyalarını Temizleme", "clean_temp_files": "Temp Dosyalarını Temizle",
"clean_temp_files_succeeded": "Temp dosyaları temizlendi.", "clean_temp_files_succeeded": "Temp dosyaları temizlendi.",
"clean_temp_files_failed": "Temp dosyalar temizlenirken bir sorun oluştu.", "clean_temp_files_failed": "Temp dosyası temizlenirken bir sorun oluştu.",
"select_folder": "Klasör Seçin", "select_folder": "Klasör Seçin",
"registration_failed": "Kayıt başarısız oldu.", "registration_failed": "Kayıt başarısız oldu.",
"minimize_action": "Küçült", "minimize_action": "Küçült",
"do_nothing_action": "Hiçbir şey yapma", "do_nothing_action": "Hiçbir şey yapma",
"exit_action": "Başlatıcıyı Kapat", "exit_action": "Başlatıcıyı Kapat",
"on_game_start": "Oyun Başlayınca başlatıcıya ne yapılsın", "on_game_start": "Oyun Başlayınca launcher ne yapılsın",
"game": "Oyun", "game": "Oyun",
"new_password": "Yeni Parola", "new_password": "Yeni Şifre",
"cancel": "İptal", "cancel": "İptal et",
"need_an_account": "Henüz bir profiliniz yok mu?", "need_an_account": "Henüz bir profiliniz yok mu?",
"have_an_account": "Zaten bir profiliniz var mı?", "have_an_account": "Zaten bir profiliniz var mı?",
"reapply_patch": "Yamayı Yeniden Uygula", "reapply_patch": "Yamayı Yeniden Uygula",
"failed_to_receive_patches": "Yamalar alınamadı", "failed_to_receive_patches": "Yamalar alınamadı",
"failed_core_patch": "Core yaması başarısız", "failed_core_patch": "Çekirdek yaması başarısız oldu",
"failed_mod_patch": "Mod yaması başarısız oldu", "failed_mod_patch": "Mod yaması başarısız oldu",
"ok": "TAMAM.", "ok": "Tamam",
"account_page_denied": "Profil sayfası reddedildi. Ya giriş yapmadınız ya da oyun çalışıyor.", "account_page_denied": "Oyun çalışırken veya oturum açmamışken ayarlar sayfasına erişemezsiniz.",
"account_updated": "Profiliniz güncellendi", "account_updated": "Profiliniz güncellendi",
"nickname": "Kullanıcı adı", "nickname": "Takma ad",
"side": "Taraf", "side": "Taraf",
"level": "Level", "level": "Level",
"patching": "Yama", "patching": "Yamalanıyor",
"file_mismatch_dialog_message": "Girdi dosyası hash'i beklenen hash ile eşleşmiyor. İstemci dosyalarınız için SPT'nin yanlış sürümünü kullanıyor olabilirsiniz.\n\nDevam etmek istiyor musunuz?", "file_mismatch_dialog_message": "EFT dosyalarınız SPT için beklenenlerle eşleşmiyor: {0}\nEn son EFT sürümünün yüklü olup olmadığını kontrol edin\nEğer değilse, SPT'yi silin, canlı EFT'yi güncelleyin ve Yükleyiciyi boş bir klasörde tekrar çalıştırın\n\nDevam etmek istediğinizden emin misiniz?",
"yes": "Evet", "yes": "Evet",
"no": "Hayır", "no": "Hayır",
"open_folder": "Klasörü Aç", "open_folder": "Klasörü Aç",
"select_edition": "Versiyon Seçin", "select_edition": "Seçilmiş Sürüm",
"profile_created": "Profil Oluşturuldu", "profile_created": "Profil Oluşturuldu",
"registration_question_format_1": "Profil '{0}' mevcut değil.\n\nBunu oluşturmak ister misiniz?", "registration_question_format_1": "Profil '{0}' mevcut değil.\n\nBunu oluşturmak ister misiniz?",
"next_level_in": "Bir sonraki seviye", "next_level_in": "Sonraki seviyeye",
"wipe_warning": "Hesap sürümünüzü değiştirmek için profil silmeniz gerekir. Bu, oyun ilerlemenizi sıfırlayacaktır.", "wipe_warning": "Hesap sürümünüzü değiştirmek için profil silmeniz gerekir. Bu işlem profilinizi sıfırlayacaktır.",
"copied": "Kopyalandı", "copied": "Kopyalandı",
"no_profile_data": "Profil verisi yok", "no_profile_data": "Profil verileri yok",
"profile_version_mismath": "Profiliniz farklı bir SPT sürümü kullanılarak oluşturulmuştur ve sorunları olabilir", "profile_version_mismath": "Profiliniz SPT'nin farklı bir sürümü kullanılarak oluşturulmuştur ve sorunları olabilir",
"profile_removed": "Profil kaldırıldı", "profile_removed": "Profil silindi",
"profile_removal_failed": "Profil kaldırılamadı", "profile_removal_failed": "Profil silinemedi",
"profile_remove_question_format_1": "'{0}' profilini kalıcı olarak kaldıralım mı?", "profile_remove_question_format_1": "Profil '{0}' kalıcı olarak silinsinmi mi?",
"i_understand": "Anlıyorum.", "i_understand": "Anlıyorum.",
"game_version_mismatch_format_2": "SPT çalıştırılamıyor, bunun nedeni SPT'nin '{1}' EFT sürümünü bulmayı beklemesi, ancak bunun yerine '{0}' sürümünü bulmasıdır\n\nEFT'nizi SPT'yi indirdiğiniz sayfada değil\nkurulum kılavuzunda açıklandığı şekilde düşürdüğünüzden emin olun", "game_version_mismatch_format_2": "SPT çalıştırılamıyor çünkü SPT EFT sürümünü bulmayı bekliyordu: '{1}',\nancak bunun yerine sürümü buldu: '{0}'\n\nEFT'nizi yükleme kılavuzunda açıklandığı gibi düşürdüğünüzden emin olun SPT'yi indirdiğiniz sayfada değil",
"description": "Açıklama", "description": "Açıklama",
"author": "Yazar", "author": "Yazar",
"load_live_settings": "Canlı Ayarları Yükle", "load_live_settings": "Orjinal Oyun Ayarları Yükle",
"load_live_settings_succeeded": "Oyun ayarları canlıdan kopyalandı", "load_live_settings_succeeded": "Oyun ayarları kopyalandı",
"load_live_settings_failed": "Canlı ayarlar kopyalanamadı", "load_live_settings_failed": "Orjinal Oyun ayarları kopyalama başarısız oldu",
"wipe_on_start": "Oyun başladığında profili wipela", "wipe_on_start": "Oyun başladığında profili sıfırla",
"copy_live_settings_question": "Canlı oyun ayarlarınızı spt'ye kopyalamak ister misiniz", "copy_live_settings_question": "Orjinal oyun ayarlarınızı SPT'ye kopyalamak ister misiniz?",
"mod_not_in_server_warning":"Bu mod profilinizde bulundu, ancak sunucuda yüklü değil", "mod_not_in_server_warning": "Bu mod profilinizde bulundu, ancak sunucuda yüklü değil",
"active_server_mods": "Aktif Sunucu Modları", "active_server_mods": "Aktif Sunucu Modları",
"active_server_mods_info_text": "Bu modlar şu anda sunucuda çalışmaktadır", "active_server_mods_info_text": "Bu modlar şu anda sunucuda çalışmaktadır",
"inactive_server_mods": "Aktif Olmayan Sunucu Modları", "inactive_server_mods": "Etkin Olmayan Sunucu Modları",
"inactive_server_mods_info_text": "Bu modlar sunucu tarafından yüklenmedi, ancak profiliniz geçmişte bunları kullandı", "inactive_server_mods_info_text": "Bu modlar sunucu tarafından yüklenmedi, ancak profiliniz geçmişte bunları kullandı",
"open_link_question_format_1": "Aşağıdaki bağlantıyı açmak istediğinizden emin misiniz? \n{0}", "open_link_question_format_1": "Aşağıdaki bağlantıyı açmak istediğinizden emin misiniz? \n{0}",
"open_link": "Bağlantıyı Aç", "open_link": "Bağlantıyı Aç",
"dev_mode": "Developer Mode", "dev_mode": "Geliştirici Modu",
"failed_to_save_settings": "Failed to save settings", "failed_to_save_settings": "Ayarlar kaydedilemedi",
"core_dll_file_version_mismatch": "Your BepinEx/plugins/spt/spt-core.dll file version doesn't match what was expected and is unable to start. Try reinstalling SPT", "core_dll_file_version_mismatch": "BepinEx/plugins/spt/spt-core.dll dosya sürümünüz beklenenle eşleşmiyor ve başlatılamıyor. SPT'yi yeniden yüklemeyi deneyin",
"register_failed_name_limit": "name cannot exceed 15 characters", "register_failed_name_limit": "isim 15 karakteri geçemez",
"copy_failed": "Failed to copy data to clipboard", "copy_failed": "Veriler panoya kopyalanamadı",
"copy_logs_to_clipboard": "Copy logs to clipboard" "copy_logs_to_clipboard": "Günlükleri(Logs) panoya kopyala"
} }

View File

@ -2,9 +2,7 @@
using SPT.Launcher.Helpers; using SPT.Launcher.Helpers;
using SPT.Launcher.Models; using SPT.Launcher.Models;
using SPT.Launcher.Models.Launcher; using SPT.Launcher.Models.Launcher;
using SPT.Launcher.ViewModels.Dialogs;
using Avalonia; using Avalonia;
using Avalonia.Controls;
using ReactiveUI; using ReactiveUI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -50,18 +48,41 @@ namespace SPT.Launcher.ViewModels
return; return;
} }
var traceLogs = Directory.GetFiles(Path.Join(LauncherSettingsProvider.Instance.GamePath, "Logs"), $"{DateTime.Now:yyyy.MM.dd}_* traces.log", SearchOption.AllDirectories); var filesToCopy = new List<string> { LogManager.Instance.LogFile };
var traceLog = traceLogs.Length > 0 ? traceLogs[0] : ""; var serverLog = Path.Join(LauncherSettingsProvider.Instance.GamePath, @"\user\logs",
$"server-{DateTime.Now:yyyy-MM-dd}.log");
var bepinexLog = Path.Join(LauncherSettingsProvider.Instance.GamePath, @"BepInEx\LogOutput.log");
var filesToCopy = new string[] if (AccountManager.SelectedAccount?.id != null)
{ {
Path.Join(LauncherSettingsProvider.Instance.GamePath, @"\user\logs", $"server-{DateTime.Now:yyyy-MM-dd}.log"), filesToCopy.Add(Path.Join(LauncherSettingsProvider.Instance.GamePath, @"\user\profiles",
traceLog, $"{AccountManager.SelectedAccount.id}.json"));
Path.Join(LauncherSettingsProvider.Instance.GamePath, @"BepInEx\LogOutput.log"), }
Path.Join(LauncherSettingsProvider.Instance.GamePath, @"\user\profiles", $"{AccountManager.SelectedAccount.id}.json"),
LogManager.Instance.LogFile, if (File.Exists(serverLog))
}; {
filesToCopy.Add(serverLog);
}
if (File.Exists(bepinexLog))
{
filesToCopy.Add(bepinexLog);
}
var logsPath = Path.Join(LauncherSettingsProvider.Instance.GamePath, "Logs");
if (Directory.Exists(logsPath))
{
var traceLogs = Directory.GetFiles(logsPath, $"{DateTime.Now:yyyy.MM.dd}_* traces.log",
SearchOption.AllDirectories);
var log = traceLogs.Length > 0 ? traceLogs[0] : "";
if (!string.IsNullOrWhiteSpace(log))
{
filesToCopy.Add(log);
}
}
List<IStorageFile> files = new List<IStorageFile>(); List<IStorageFile> files = new List<IStorageFile>();
@ -130,23 +151,6 @@ namespace SPT.Launcher.ViewModels
} }
} }
public void RemoveRegistryKeysCommand()
{
LogManager.Instance.Info("[Settings] Removing registry keys ...");
bool regKeysRemoved = gameStarter.RemoveRegistryKeys();
if (regKeysRemoved)
{
LogManager.Instance.Info("[Settings] Registry keys removed");
SendNotification("", LocalizationProvider.Instance.remove_registry_keys_succeeded, Avalonia.Controls.Notifications.NotificationType.Success);
}
else
{
LogManager.Instance.Info("[Settings] Registry keys failed to remove");
SendNotification("", LocalizationProvider.Instance.remove_registry_keys_failed, Avalonia.Controls.Notifications.NotificationType.Error);
}
}
public async Task ResetGameSettingsCommand() public async Task ResetGameSettingsCommand()
{ {
LogManager.Instance.Info("[Settings] Reseting game settings ..."); LogManager.Instance.Info("[Settings] Reseting game settings ...");

View File

@ -16,10 +16,6 @@
Opacity=".7" Opacity=".7"
/> />
<WrapPanel Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal"> <WrapPanel Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Orientation="Horizontal">
<Button Content="{Binding Source={x:Static helpers:LocalizationProvider.Instance}, Path=remove_registry_keys}"
Command="{Binding RemoveRegistryKeysCommand}"
Classes="outlined" Margin="0 0 10 5"
/>
<Button Content="{Binding Source={x:Static helpers:LocalizationProvider.Instance}, Path=load_live_settings}" <Button Content="{Binding Source={x:Static helpers:LocalizationProvider.Instance}, Path=load_live_settings}"
Command="{Binding ResetGameSettingsCommand}" Command="{Binding ResetGameSettingsCommand}"
Classes="outlined" Margin="0 0 10 5" Classes="outlined" Margin="0 0 10 5"
@ -39,11 +35,17 @@
</WrapPanel> </WrapPanel>
<!-- Go Back --> <!-- Go Back -->
<Button Content="&#x279C;" FontSize="25" <Button Grid.Row="1" Grid.Column="3"
Grid.Row="1" Grid.Column="3"
Command="{Binding GoBackCommand}" Command="{Binding GoBackCommand}"
Classes="link" Classes="link">
<TextBlock>
<Viewbox Height="30" Width="30">
<Path Data="{StaticResource BackArrow}"
Fill="{Binding $parent[TextBlock].Foreground}"
/> />
</Viewbox>
</TextBlock>
</Button>
<!-- Default locale --> <!-- Default locale -->
<StackPanel Grid.Row="2" Grid.Column="1"> <StackPanel Grid.Row="2" Grid.Column="1">