Files
fluid-explorer/Services/AppSettings.cs
T

154 lines
5.1 KiB
C#

using System.Text.Json;
using System.Text.Json.Serialization;
using FluidExplorer.Models;
namespace FluidExplorer.Services;
/// <summary>外观模式:默认跟随系统(深浅色自动切换)。</summary>
public enum AppThemeMode
{
System,
Light,
Dark
}
public enum SearchScope
{
/// <summary>全盘(走 NTFS 索引,Everything 式,毫秒级)。</summary>
Global,
/// <summary>仅当前文件夹及其子目录。</summary>
CurrentFolder
}
public sealed class FolderViewState
{
public ViewMode ViewMode { get; set; } = ViewMode.Details;
public SortColumn SortColumn { get; set; } = SortColumn.Name;
public SortDirection SortDirection { get; set; } = SortDirection.Ascending;
public GroupBy GroupBy { get; set; } = GroupBy.None;
}
/// <summary>用户设置(%LOCALAPPDATA%\FluidExplorer\settings.json),失败时退回程序目录。</summary>
public sealed class AppSettings
{
public AppThemeMode ThemeMode { get; set; } = AppThemeMode.System;
// 视图
public bool ShowHiddenFiles { get; set; }
public bool ShowSystemFiles { get; set; }
public bool ShowFileExtensions { get; set; } = true;
public bool AlwaysShowCheckBoxes { get; set; }
public bool ShowStatusBar { get; set; } = true;
// 浏览
public bool OpenFoldersInNewTab { get; set; }
public bool DoubleClickToOpen { get; set; } = true;
public bool RestoreTabsOnStartup { get; set; } = true;
public string DefaultStartPath { get; set; } = "";
public List<string> PinnedFolders { get; set; } = [];
public List<string> RecentFolders { get; set; } = [];
public List<string> OpenTabs { get; set; } = [];
public bool DualPane { get; set; }
// 搜索
public SearchScope SearchScope { get; set; } = SearchScope.Global;
public List<string> IndexedVolumes { get; set; } = [];
public bool IndexOnStartup { get; set; } = true;
public bool SearchAsYouType { get; set; } = true;
// 文件操作
public bool DeleteToRecycleBin { get; set; } = true;
public ConflictPolicySetting DefaultConflictPolicy { get; set; } = ConflictPolicySetting.Ask;
public bool ConfirmPermanentDelete { get; set; } = true;
public bool KeepWindowOpenDuringOperations { get; set; } = true;
// 动效(克制:只保留系统原生的必要动画)
public bool AnimationsEnabled { get; set; } = true;
// 窗口
public double WindowLeft { get; set; } = double.NaN;
public double WindowTop { get; set; } = double.NaN;
public double WindowWidth { get; set; } = 1280;
public double WindowHeight { get; set; } = 800;
public bool WindowMaximized { get; set; }
/// <summary>按文件夹记住视图方式(对齐资源管理器的"按文件夹记住视图设置")。</summary>
public Dictionary<string, FolderViewState> FolderViews { get; set; } = new(StringComparer.OrdinalIgnoreCase);
[JsonIgnore]
public string SettingsFilePath { get; private set; } = string.Empty;
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
public static AppSettings Load()
{
foreach (var candidate in CandidatePaths())
{
try
{
if (!File.Exists(candidate)) continue;
var json = File.ReadAllText(candidate);
var loaded = JsonSerializer.Deserialize<AppSettings>(json, JsonOptions);
if (loaded is null) continue;
loaded.SettingsFilePath = candidate;
return loaded;
}
catch
{
// 设置文件损坏时忽略,使用默认值
}
}
var settings = new AppSettings();
settings.SettingsFilePath = CandidatePaths().First();
return settings;
}
public void Save()
{
foreach (var target in CandidatePaths())
{
try
{
var dir = Path.GetDirectoryName(target);
if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir);
SettingsFilePath = target;
File.WriteAllText(target, JsonSerializer.Serialize(this, JsonOptions));
return;
}
catch
{
// 换下一个候选位置(例如沙箱/只读环境)
}
}
}
public FolderViewState GetFolderView(string path)
{
if (FolderViews.TryGetValue(path, out var state)) return state;
state = new FolderViewState();
FolderViews[path] = state;
return state;
}
private static IEnumerable<string> CandidatePaths()
{
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
if (!string.IsNullOrEmpty(localAppData))
yield return Path.Combine(localAppData, "FluidExplorer", "settings.json");
yield return Path.Combine(AppContext.BaseDirectory, "settings.json");
}
}
public enum ConflictPolicySetting
{
Ask,
Replace,
Skip,
KeepBoth
}