XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEToolBox

【WPF】XFE工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.IO;
using System.Text.Json;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using CommunityToolkit.Mvvm.ComponentModel;
using XFEToolBox.Client.Models;
using XFEToolBox.Client.Utilities;
using XFEToolBox.Core.Tools;

namespace XFEToolBox.Client.ViewModel.Pages;

internal partial class ToolProjectCardViewModel : ObservableObject
{
    private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
    private readonly ToolProjectHistoryItem project;

    public ToolProjectCardViewModel(ToolProjectHistoryItem project)
    {
        this.project = project;
        iconSource = CreateFallbackIcon();
        IconLoadingTask = LoadIconAsync();
    }

    internal Task IconLoadingTask { get; }
    public string Name => project.Name;
    public string ProjectPath => project.ProjectPath;
    public string StateText => project.StateText;
    public string LastOpenedText => project.LastOpenedText;
    public bool IsPinned => PinnedItemService.IsPinned(LauncherItemKind.Project, ProjectPath);
    public string PinText => IsPinned ? "取消固定" : "固定此项";

    [ObservableProperty]
    private ImageSource iconSource;

    public bool TogglePinned()
    {
        var success = IsPinned
            ? PinnedItemService.Unpin(LauncherItemKind.Project, ProjectPath)
            : PinnedItemService.TryPin(LauncherItemKind.Project, ProjectPath);
        OnPropertyChanged(nameof(IsPinned));
        OnPropertyChanged(nameof(PinText));
        return success;
    }

    private async Task LoadIconAsync()
    {
        if (!Directory.Exists(ProjectPath)) return;
        try
        {
            var manifestPath = Path.Combine(ProjectPath, "manifest.json");
            var manifest = JsonSerializer.Deserialize<ToolPackageManifest>(await File.ReadAllTextAsync(manifestPath), JsonOptions);
            if (string.IsNullOrWhiteSpace(manifest?.Icon)) return;

            var root = Path.GetFullPath(ProjectPath);
            var iconPath = Path.GetFullPath(Path.Combine(root, manifest.Icon));
            var relativePath = Path.GetRelativePath(root, iconPath);
            if (Path.IsPathRooted(relativePath)
                || relativePath.Equals("..", StringComparison.Ordinal)
                || relativePath.StartsWith($"..{Path.DirectorySeparatorChar}", StringComparison.Ordinal))
                return;

            var file = new FileInfo(iconPath);
            if (!file.Exists || file.Length == 0 || file.Length > WebImageSourceLoader.MaximumImageBytes) return;
            IconSource = await WebImageSourceLoader.DecodeAsync(await File.ReadAllBytesAsync(iconPath), sourceName: iconPath);
        }
        catch
        {
            // 清单或预览图标无效时保留内置默认工具图标。
        }
    }

    private static ImageSource CreateFallbackIcon()
    {
        var image = new BitmapImage(new Uri("/XFEToolBox;component/Resources/Image/default_tool_icon.png", UriKind.Relative));
        image.Freeze();
        return image;
    }
}