Release v0.1.2

This commit is contained in:
nikit3s
2026-10-10 14:58:04 +03:00
parent b2ae91b5b3
commit 3cdc30ec2a
33 changed files with 1218 additions and 212 deletions
+18 -28
View File
@@ -1,7 +1,8 @@
// SbLauncher — GUI для sing-box.
//
// ПРИНЦИП (изменён по сравнению с прошлой версией):
// Источник правды — profiles.json (серверы, общее) и local.json (ключ,
// Источник правды — profiles.base.json (базовые серверы), profiles.json
// (личные серверы) и local.json (ключ,
// адрес, адаптер — своё на каждой машине). Конфиг sing-box НЕ хранится:
// он собирается из шаблона templates\*.json при каждом запуске и кладётся
// в run\config.json. Поэтому папок conf_* больше нет, и править один и
@@ -338,13 +339,12 @@ namespace SbLauncher
get { return _showSettings; }
set
{
if (_showSettings == value) return;
_showSettings = value;
Raise(); Raise("LogVis"); Raise("SettingsVis");
Raise();
Raise("TabLogBrush"); Raise("TabSettingsBrush");
}
}
public Visibility LogVis { get { return _showSettings ? Visibility.Collapsed : Visibility.Visible; } }
public Visibility SettingsVis { get { return _showSettings ? Visibility.Visible : Visibility.Collapsed; } }
public Brush TabLogBrush { get { return Theme.Res(_showSettings ? "Muted" : "Accent"); } }
public Brush TabSettingsBrush { get { return Theme.Res(_showSettings ? "Accent" : "Muted"); } }
@@ -478,15 +478,14 @@ namespace SbLauncher
// ── тема ─────────────────────────────────────────────────────────
public string ThemeName { get { return _theme; } }
// показываем действие, а не состояние: в тёмной теме — солнце
// (E706 Brightness), в светлой — луна (E708 QuietHours)
public string ThemeGlyph { get { return _theme == Theme.Light ? "" : ""; } }
// Иконки в XAML показывают действие: в тёмной теме — солнце, в светлой — луна.
public string ThemeAction { get { return _theme == Theme.Light ? "Включить тёмную тему" : "Включить светлую тему"; } }
public void SetTheme(string t)
{
_theme = (t == Theme.Light) ? Theme.Light : Theme.Dark;
if (ThemeApplier != null) ThemeApplier(_theme);
Raise("ThemeName"); Raise("ThemeGlyph");
Raise("ThemeName"); Raise("ThemeAction");
Raise("StatusBrush");
Raise("LogBrush");
Raise("TabLogBrush"); Raise("TabSettingsBrush");
@@ -533,7 +532,8 @@ namespace SbLauncher
Raise();
if (_sel != null)
{
Local.LastServer = _sel.IsWgOnly ? "*wg" : _sel.Code;
Local.LastServer = _sel.IsWgOnly ? "*wg" :
(_sel.Cfg.BaseId.Length > 0 ? "base:" + _sel.Cfg.BaseId : _sel.Code);
Local.Mode = CurrentMode;
SaveLocal();
}
@@ -546,6 +546,7 @@ namespace SbLauncher
{
P = paths;
Prof = Profiles.Load(P.Profiles);
if (Prof.NeedsMigration) Prof.Save(P.Profiles);
Local = LocalCfg.Load(P.Local);
_wg = Local.Mode != ConfigBuilder.ModeDirect;
@@ -568,7 +569,7 @@ namespace SbLauncher
RefreshAdapters();
AppendLog("серверов: " + Prof.Servers.Count + " корень: " + P.Root);
if (!File.Exists(P.Profiles)) AppendLog("! нет " + P.Profiles);
if (!File.Exists(P.Profiles) && !File.Exists(P.BaseProfiles)) AppendLog("! нет списка серверов");
if (!File.Exists(P.Local)) AppendLog("! нет local.json — задайте ключ и адрес во вкладке «настройки»");
if (!File.Exists(P.SbExe)) AppendLog("! нет " + P.SbExe);
if (!File.Exists(P.RuleSet)) AppendLog("! нет " + P.RuleSet);
@@ -578,7 +579,8 @@ namespace SbLauncher
foreach (ServerVm vm in Servers)
{
bool match = Local.LastServer == "*wg" ? vm.IsWgOnly
: (!vm.IsWgOnly && vm.Code == Local.LastServer);
: (!vm.IsWgOnly && (vm.Code == Local.LastServer ||
(vm.Cfg.BaseId.Length > 0 && "base:" + vm.Cfg.BaseId == Local.LastServer)));
if (match) { want = vm; break; }
}
if (want == null)
@@ -836,10 +838,7 @@ namespace SbLauncher
Profiles CopyProfiles()
{
Profiles next = new Profiles();
next.Wg = Prof.Wg;
next.Servers.AddRange(Prof.Servers);
return next;
return Prof.Copy();
}
sealed class ImportWork
@@ -852,17 +851,7 @@ namespace SbLauncher
static void GiveUniqueCode(ServerCfg server, List<ServerCfg> all)
{
string code = server.Code;
int number = 2;
bool used = true;
while (used)
{
used = false;
foreach (ServerCfg existing in all)
if (string.Equals(existing.Code, code, StringComparison.OrdinalIgnoreCase))
{ used = true; code = server.Code + (number++).ToString(CultureInfo.InvariantCulture); break; }
}
server.Code = code;
Profiles.GiveUniqueCode(server, all);
}
public async Task<bool> AddFromLinkAsync(string link)
@@ -954,7 +943,8 @@ namespace SbLauncher
}
string msg = "Вы действительно хотите удалить сервер \"" + vm.Title + "\" (" +
vm.Code + " / " + vm.Cfg.Endpoint + ")?\n\nСервер будет удален из profiles.json.";
vm.Code + " / " + vm.Cfg.Endpoint + ")?\n\n" +
(vm.Cfg.BaseId.Length > 0 ? "Базовый сервер будет скрыт и после обновления." : "Личный сервер будет удалён.");
if (MessageBox.Show(msg, "Подтверждение удаления", MessageBoxButton.YesNo,
MessageBoxImage.Question) != MessageBoxResult.Yes) return;
@@ -962,7 +952,7 @@ namespace SbLauncher
try
{
Profiles next = CopyProfiles();
next.Servers.Remove(vm.Cfg);
next.Remove(vm.Cfg);
await Task.Run(delegate { next.Save(P.Profiles); });
Prof = next;
int index = Servers.IndexOf(vm);