Files
Taskbar-Launcher/Services/ConfigService.cs
2026-08-26 21:38:57 -04:00

311 lines
9.1 KiB
C#

using System.Diagnostics;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using TaskbarLauncher.Models;
namespace TaskbarLauncher.Services;
public static class ConfigService
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = true,
PropertyNameCaseInsensitive = true
};
static ConfigService()
{
JsonOptions.Converters.Add(new JsonStringEnumConverter());
}
public static string AppFolder => AppContext.BaseDirectory;
public static string ConfigPath => Path.Combine(AppFolder, "config.json");
public static string BackupFolder => Path.Combine(AppFolder, "backups");
public static LauncherConfig Load()
{
if (!File.Exists(ConfigPath))
{
LauncherConfig defaults = CreateDefaultConfig();
Save(defaults);
return defaults;
}
string json = File.ReadAllText(ConfigPath);
LauncherConfig config = JsonSerializer.Deserialize<LauncherConfig>(json, JsonOptions) ?? CreateDefaultConfig();
NormalizeConfig(config);
Save(config);
return config;
}
public static void Save(LauncherConfig config)
{
string json = JsonSerializer.Serialize(config, JsonOptions);
File.WriteAllText(ConfigPath, json);
}
public static string Backup()
{
Directory.CreateDirectory(BackupFolder);
if (!File.Exists(ConfigPath))
{
Save(CreateDefaultConfig());
}
string timestamp = DateTime.Now.ToString("yyyyMMdd-HHmmss");
string backupPath = Path.Combine(BackupFolder, $"config-{timestamp}.json");
File.Copy(ConfigPath, backupPath, overwrite: false);
return backupPath;
}
public static string ExportTo(string destinationPath, LauncherConfig config)
{
if (string.IsNullOrWhiteSpace(destinationPath))
{
throw new ArgumentException("Choose a destination path for the exported config.", nameof(destinationPath));
}
string? destinationFolder = Path.GetDirectoryName(destinationPath);
if (!string.IsNullOrWhiteSpace(destinationFolder))
{
Directory.CreateDirectory(destinationFolder);
}
NormalizeConfig(config);
string json = JsonSerializer.Serialize(config, JsonOptions);
File.WriteAllText(destinationPath, json);
return destinationPath;
}
public static string ExportItemTo(string destinationPath, LauncherItem item)
{
if (string.IsNullOrWhiteSpace(destinationPath))
{
throw new ArgumentException("Choose a destination path for the exported item.", nameof(destinationPath));
}
string? destinationFolder = Path.GetDirectoryName(destinationPath);
if (!string.IsNullOrWhiteSpace(destinationFolder))
{
Directory.CreateDirectory(destinationFolder);
}
NormalizeDisplayModes(item);
string json = JsonSerializer.Serialize(item, JsonOptions);
File.WriteAllText(destinationPath, json);
return destinationPath;
}
public static LauncherItem ImportItemFrom(string sourcePath)
{
if (!File.Exists(sourcePath))
{
throw new FileNotFoundException("The selected item file was not found.", sourcePath);
}
string json = File.ReadAllText(sourcePath);
LauncherItem item;
try
{
item = JsonSerializer.Deserialize<LauncherItem>(json, JsonOptions)
?? throw new InvalidDataException("The selected item file could not be read.");
}
catch (JsonException ex)
{
throw new InvalidDataException("The selected file is not a valid Taskbar Launcher item export.", ex);
}
ValidateItem(item);
NormalizeDisplayModes(item);
return item;
}
public static LauncherConfig ImportFrom(string sourcePath)
{
LauncherConfig config = ReadConfigFile(sourcePath);
Save(config);
return config;
}
public static LauncherConfig ResetToDefaults()
{
LauncherConfig config = CreateDefaultConfig();
Save(config);
return config;
}
public static LauncherConfig Restore(string sourcePath)
{
LauncherConfig config = ReadConfigFile(sourcePath);
Save(config);
return config;
}
public static void OpenConfigFolder()
{
Directory.CreateDirectory(AppFolder);
Process.Start(new ProcessStartInfo
{
FileName = AppFolder,
UseShellExecute = true
});
}
private static LauncherConfig CreateDefaultConfig()
{
LauncherConfig config = new()
{
Items =
[
new LauncherItem
{
Title = "Folders",
Type = LauncherItemType.Menu,
Children =
[
new LauncherItem
{
Title = "Documents",
Type = LauncherItemType.Folder,
Target = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
},
new LauncherItem
{
Title = "Downloads",
Type = LauncherItemType.Folder,
Target = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads")
}
]
},
new LauncherItem
{
Title = "Apps",
Type = LauncherItemType.Menu,
Children =
[
new LauncherItem
{
Title = "Notepad",
Type = LauncherItemType.App,
Target = "notepad.exe",
IconPath = "notepad.exe"
}
]
}
]
};
NormalizeConfig(config);
return config;
}
private static LauncherConfig ReadConfigFile(string sourcePath)
{
if (!File.Exists(sourcePath))
{
throw new FileNotFoundException("The selected config file was not found.", sourcePath);
}
string json = File.ReadAllText(sourcePath);
LauncherConfig config;
try
{
config = JsonSerializer.Deserialize<LauncherConfig>(json, JsonOptions)
?? throw new InvalidDataException("The selected config file could not be read.");
}
catch (JsonException ex)
{
throw new InvalidDataException("The selected file is not a valid Taskbar Launcher config.", ex);
}
ValidateConfig(config);
NormalizeConfig(config);
return config;
}
private static void ValidateConfig(LauncherConfig config)
{
if (config.Items is null)
{
throw new InvalidDataException("The selected config is missing launcher items.");
}
if (config.RecentItems is null)
{
config.RecentItems = [];
}
foreach (LauncherItem item in config.Items)
{
ValidateItem(item);
}
foreach (LauncherItem item in config.RecentItems)
{
ValidateItem(item);
}
}
private static void ValidateItem(LauncherItem item)
{
if (item.Children is null)
{
throw new InvalidDataException($"The item '{item.Title}' has an invalid children list.");
}
if (!Enum.IsDefined(item.Type))
{
throw new InvalidDataException($"The item '{item.Title}' has an invalid type.");
}
foreach (LauncherItem child in item.Children)
{
ValidateItem(child);
}
}
private static void NormalizeConfig(LauncherConfig config)
{
if (!Enum.IsDefined(config.DisplayMode))
{
config.DisplayMode = LauncherDisplayMode.CompactList;
}
if (!Enum.IsDefined(config.ThemeScheme))
{
config.ThemeScheme = LauncherThemeScheme.MarkHaven;
}
config.RecentItems ??= [];
config.RecentItems.RemoveAll(item => item.Type == LauncherItemType.Menu || item.IsDisabled || string.IsNullOrWhiteSpace(item.Target));
foreach (LauncherItem item in config.RecentItems)
{
item.IsFavorite = false;
item.IsDisabled = false;
item.Children = [];
NormalizeDisplayModes(item);
}
foreach (LauncherItem item in config.Items)
{
NormalizeDisplayModes(item);
}
}
private static void NormalizeDisplayModes(LauncherItem item)
{
if (!Enum.IsDefined(item.DisplayMode))
{
item.DisplayMode = LauncherDisplayMode.CompactList;
}
foreach (LauncherItem child in item.Children)
{
NormalizeDisplayModes(child);
}
}
}