diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/AppxInfoPanel.xaml b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/AppxInfoPanel.xaml index caac10f..636c730 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/AppxInfoPanel.xaml +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/AppxInfoPanel.xaml @@ -165,6 +165,7 @@ Grid.Column="1" Grid.ColumnSpan="2" Margin="0,0,16,16" + BorderThickness="0.4" Header="Capabilities"> diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs index 4576ce4..9ccad0b 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs @@ -48,7 +48,7 @@ public class Plugin : IViewer //".har", // HarmonyOS Archive // Others - //".wgt", ".wgtu", // UniApp Widget + ".wgt", ".wgtu", // UniApp Widget ]; private IAppInfoPanel _ip; @@ -70,7 +70,8 @@ public class Plugin : IViewer context.PreferredSize = Path.GetExtension(path).ToLower() switch { ".msi" => new Size { Width = 520, Height = 230 }, - ".msix" or ".msixbundle" or ".appx" or ".appxbundle" => new Size { Width = 560, Height = 320 }, + ".msix" or ".msixbundle" or ".appx" or ".appxbundle" => new Size { Width = 560, Height = 328 }, + ".wgt" or ".wgtu" => new Size { Width = 600, Height = 328 }, _ => throw new NotSupportedException("Extension is not supported."), }; } @@ -82,6 +83,7 @@ public class Plugin : IViewer { ".msi" => new MsiInfoPanel(), ".msix" or ".msixbundle" or ".appx" or ".appxbundle" => new AppxInfoPanel(), + ".wgt" or ".wgtu" => new WgtInfoPanel(), _ => throw new NotSupportedException("Extension is not supported."), }; diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/QuickLook.Plugin.AppViewer.csproj b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/QuickLook.Plugin.AppViewer.csproj index 8912532..865f509 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/QuickLook.Plugin.AppViewer.csproj +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/QuickLook.Plugin.AppViewer.csproj @@ -59,6 +59,11 @@ + + + + + Properties\GitVersion.cs @@ -67,8 +72,10 @@ + + @@ -77,4 +84,9 @@ + + + + + diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Resources/uni-app.png b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Resources/uni-app.png new file mode 100644 index 0000000..6b4c81a Binary files /dev/null and b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Resources/uni-app.png differ diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Translations.config b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Translations.config index cebd5d5..0eab804 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Translations.config +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Translations.config @@ -9,6 +9,10 @@ Last Modified Publisher Capabilities + Application + Version + Version Code + Permissions Versão do produto @@ -18,6 +22,10 @@ Modificado em Editora Recursos + Nome do aplicativo + Versão + Código da versão + Permissões 产品版本 @@ -27,6 +35,10 @@ 修改时间 发布者 功能 + 应用名称 + 版本名称 + 版本号 + 权限 產品版本 @@ -36,6 +48,10 @@ 修改時間 發行者 功能 + 程式名稱 + 版本名稱 + 版本號 + 權限 製品バージョン @@ -45,5 +61,9 @@ 更新日時 発行元 機能 + アプリケーションネーム + バージョン + バージョンコード + 権限 diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtInfoPanel.xaml b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtInfoPanel.xaml new file mode 100644 index 0000000..85a1930 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtInfoPanel.xaml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtInfoPanel.xaml.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtInfoPanel.xaml.cs new file mode 100644 index 0000000..38cd48e --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtInfoPanel.xaml.cs @@ -0,0 +1,70 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using QuickLook.Common.ExtensionMethods; +using QuickLook.Common.Helpers; +using QuickLook.Plugin.AppViewer.WgtPackageParser; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows.Controls; + +namespace QuickLook.Plugin.AppViewer; + +public partial class WgtInfoPanel : UserControl, IAppInfoPanel +{ + public WgtInfoPanel() + { + DataContext = this; + InitializeComponent(); + + string translationFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Translations.config"); + applicationNameTitle.Text = TranslationHelper.Get("APP_NAME", translationFile); + versionTitle.Text = TranslationHelper.Get("APP_VERSION", translationFile); + versionCodeTitle.Text = TranslationHelper.Get("APP_VERSION_CODE", translationFile); + totalSizeTitle.Text = TranslationHelper.Get("TOTAL_SIZE", translationFile); + modDateTitle.Text = TranslationHelper.Get("LAST_MODIFIED", translationFile); + permissionsGroupBox.Header = TranslationHelper.Get("PERMISSIONS", translationFile); + } + + public void DisplayInfo(string path) + { + var name = Path.GetFileName(path); + filename.Text = string.IsNullOrEmpty(name) ? path : name; + + _ = Task.Run(() => + { + if (File.Exists(path)) + { + var size = new FileInfo(path).Length; + WgtInfo wgtInfo = WgtParser.Parse(path); + var last = File.GetLastWriteTime(path); + + Dispatcher.Invoke(() => + { + applicationName.Text = wgtInfo.AppNameLocale ?? wgtInfo.AppName; + version.Text = wgtInfo.AppVersion; + versionCode.Text = wgtInfo.AppVersionCode; + totalSize.Text = size.ToPrettySize(2); + modDate.Text = last.ToString(CultureInfo.CurrentCulture); + permissions.ItemsSource = wgtInfo.Permissions; + }); + } + }); + } +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtPackageParser/WgtInfo.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtPackageParser/WgtInfo.cs new file mode 100644 index 0000000..9553d15 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtPackageParser/WgtInfo.cs @@ -0,0 +1,115 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Newtonsoft.Json.Linq; +using QuickLook.Plugin.AppViewer.AppxPackageParser; +using System.Collections.Generic; +using System.Globalization; +using System.Resources; +using System.Text.RegularExpressions; + +namespace QuickLook.Plugin.AppViewer.WgtPackageParser; + +public sealed class WgtInfo +{ + /// + /// Json path: @platforms + /// + public string[] Platforms { get; set; } + + /// + /// Json path: id + /// + public string AppId { get; set; } + + /// + /// Json path: name + /// + public string AppName { get; set; } + + /// + /// Json path: plus.locales.xxx.name + /// + public Dictionary AppNameLocales { get; set; } = []; + + public string AppNameLocale + { + get + { + try + { + CultureInfo culture = CultureInfo.CurrentCulture; + + while (!AppNameLocales.ContainsKey(culture.Name)) + { + if (culture.Parent == CultureInfo.InvariantCulture) + { + culture = CultureInfo.InvariantCulture; + break; + } + culture = culture.Parent; + } + + return AppNameLocales[culture.Name]; + } + catch + { + return null; + } + } + } + + /// + /// Json path: plus.uni-app.vueVersion + /// + public string VueVersion { get; set; } + + /// + /// Json path: plus.uni-app.compilerVersion + /// + public string CompilerVersion { get; set; } + + /// + /// Json path: version.name + /// + public string AppVersion { get; set; } + + /// + /// Json path: version.code + /// + public string AppVersionCode { get; set; } + + /// + /// Json path: description + /// + public string AppDescription { get; set; } + + /// + /// Json path: descriptionLocales + /// + public Dictionary AppDescriptionLocales { get; set; } = []; + + /// + /// Json path: descriptionLocales + /// + public string[] Permissions { get; set; } + + /// + /// Json path: fallbackLocale + /// + public string FallbackLocale { get; set; } +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtPackageParser/WgtParser.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtPackageParser/WgtParser.cs new file mode 100644 index 0000000..08fb3f5 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/WgtPackageParser/WgtParser.cs @@ -0,0 +1,130 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; + +namespace QuickLook.Plugin.AppViewer.WgtPackageParser; + +internal static class WgtParser +{ + public static WgtInfo Parse(string path) + { + using var fileStream = File.OpenRead(path); + using var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read); + var manifestEntry = zipArchive.GetEntry("manifest.json"); + + if (manifestEntry != null) + { + using var stream = manifestEntry.Open(); + using var reader = new StreamReader(stream, Encoding.UTF8); + string content = reader.ReadToEnd(); + var dict = JsonConvert.DeserializeObject>(content); + + if (dict == null) return null; + + var wgtInfo = new WgtInfo(); + + if (dict.ContainsKey("@platforms")) + { + wgtInfo.Platforms = ((JArray)dict["@platforms"]).Values().Select(v => v.ToString()).ToArray(); + } + if (dict.ContainsKey("id")) wgtInfo.AppId = dict["id"].ToString(); + if (dict.ContainsKey("name")) wgtInfo.AppName = dict["name"].ToString(); + if (dict.ContainsKey("version")) + { + var version = (JObject)dict["version"]; + + if (version != null) + { + if (version.ContainsKey("name")) wgtInfo.AppVersion = version["name"].ToString(); + if (version.ContainsKey("code")) wgtInfo.AppVersionCode = version["code"].ToString(); + } + } + if (dict.ContainsKey("description")) wgtInfo.AppDescription = dict["description"].ToString(); + if (dict.ContainsKey("permissions")) + { + var permissions = (JObject)dict["permissions"]; + + if (permissions != null) + { + List permissionNames = []; + foreach (var permission in permissions) + { + permissionNames.Add(permission.Key); + } + wgtInfo.Permissions = [.. permissionNames]; + } + } + if (dict.ContainsKey("plus")) + { + var plus = (JObject)dict["plus"]; + + if (plus != null) + { + if (plus.ContainsKey("locales")) + { + var locales = plus["locales"]; + var dictionary = locales.ToObject>>(); + + foreach (var locale in dictionary) + { + foreach (var kv in locale.Value) + { + if (kv.Key == "name") + { + wgtInfo.AppNameLocales.Add(locale.Key, kv.Value.ToString()); + } + } + } + } + + if (plus.ContainsKey("uni-app")) + { + var uni_app = plus["uni-app"]; + var dictionary = uni_app.ToObject>(); + + if (dictionary.ContainsKey("vueVersion")) wgtInfo.VueVersion = dictionary["vueVersion"].ToString(); + if (dictionary.ContainsKey("compilerVersion")) wgtInfo.CompilerVersion = dictionary["compilerVersion"].ToString(); + } + } + } + if (dict.ContainsKey("descriptionLocales")) + { + var descriptionLocales = (JObject)dict["descriptionLocales"]; + + if (descriptionLocales != null) + { + foreach (var descriptionLocale in descriptionLocales) + { + wgtInfo.AppDescriptionLocales.Add(descriptionLocale.Key, descriptionLocale.Value.ToString()); + } + } + } + if (dict.ContainsKey("fallbackLocale")) wgtInfo.FallbackLocale = dict["fallbackLocale"].ToString(); + + return wgtInfo; + } + + return null; + } +}