Merge branch 'main' of github.com:fanchenio/DawnLauncher

This commit is contained in:
fanchenio 2023-11-16 09:38:12 +08:00
commit 426e261397
10 changed files with 335 additions and 291 deletions

View File

@ -31,6 +31,10 @@
[dawnlauncher.com](https://dawnlauncher.com/)
# QQ 群
369652112
# 捐赠(微信)
![微信](/images/wechat.png)

View File

@ -31,6 +31,10 @@ features = [
"Win32_UI_Input_Ime",
"Win32_Globalization",
"Win32_Graphics_Dwm",
"Management_Deployment",
"ApplicationModel",
"Foundation_Collections",
"ApplicationModel_Core",
]
[build-dependencies]

View File

@ -185,15 +185,18 @@ function getSubClassification({
itemAreaNameFontSize = 14,
itemAreaNameFontWeight = 700,
itemAreaNameFontLineHeight = 1.25,
itemAreaNameAlign = "left",
}: {
itemAreaNameFontSize?: number | null;
itemAreaNameFontWeight?: number | null;
itemAreaNameFontLineHeight?: number | null;
itemAreaNameAlign?: "left" | "center" | "right" | null;
}): SubClassification {
return {
itemAreaNameFontSize: itemAreaNameFontSize ?? 14,
itemAreaNameFontWeight: itemAreaNameFontWeight ?? 700,
itemAreaNameFontLineHeight: itemAreaNameFontLineHeight ?? 1.25,
itemAreaNameAlign: itemAreaNameAlign ?? "left",
};
}

View File

@ -15,9 +15,7 @@ import { getAbsolutePath, getFileIcon } from "../commons/utils";
// AppxInfo
export interface AppxInfo {
packageFamilyName: string;
installLocation: string;
appId: string | null;
id: string | null;
icon: string | null;
name: string | null;
}
@ -191,76 +189,15 @@ async function getAppxItemList() {
// ID
let id = 1;
// 获取APPX信息
let stdout = execSync(
'powershell -Command "Get-AppxPackage | Select-Object PackageFamilyName, InstallLocation | Format-list"'
);
let strAppxInfo = stdout.toString("utf-8");
// 按换行符分割
let lines = strAppxInfo
.trim()
.split("\r\n")
.filter((str) => str.trim() !== "");
let appxList = global.addon.getAppxList();
// 临时列表
let tempList: Array<AppxInfo> = [];
// APPX包名
let packageFamilyName: string | null = null;
// APPX路径
let installLocation: string | null = null;
// 循环的前一个信息
let prev = null;
// 解析每一行
for (let i = 0; i < lines.length; i++) {
let line = lines[i].trim();
let arr = line.split(" : ");
if (arr.length > 1) {
if (arr[0].trim() === "PackageFamilyName") {
if (packageFamilyName && installLocation) {
tempList.push({
packageFamilyName: packageFamilyName,
installLocation: installLocation,
appId: null,
icon: null,
name: null,
});
packageFamilyName = arr[1].trim();
installLocation = null;
prev = "PackageFamilyName";
} else {
packageFamilyName = arr[1].trim();
prev = "PackageFamilyName";
}
} else if (arr[0].trim() === "InstallLocation") {
installLocation = arr[1].trim();
prev = "InstallLocation";
}
} else {
if (prev === "PackageFamilyName") {
packageFamilyName += line;
} else if (prev === "InstallLocation") {
installLocation += line;
}
}
}
if (packageFamilyName && installLocation) {
tempList.push({
packageFamilyName: packageFamilyName,
installLocation: installLocation,
appId: null,
icon: null,
name: null,
});
}
let tempList = [];
// 读取XML获取图标路径和名称
for (let temp of tempList) {
let appxInfo = await getAppxInfo(temp.installLocation);
temp.appId = appxInfo.appId;
temp.icon = appxInfo.icon;
temp.name = appxInfo.name;
for (let appx of appxList) {
tempList.push(...(await getAppxInfo(appx)));
}
// 过滤
let filterList = tempList.filter((e) => e.icon && e.appId && e.name);
// 图标转BASE64
for (let appxInfo of filterList) {
for (let appxInfo of tempList) {
try {
let buffer = readFileSync(appxInfo.icon);
let icon =
@ -274,20 +211,16 @@ async function getAppxItemList() {
}
}
// 筛选出有图标的数据
filterList = filterList.filter((e) => e.icon);
tempList = tempList.filter((e) => e.icon);
// 返回列表
for (const appxInfo of filterList) {
for (const appxInfo of tempList) {
resultList.push(
newCommonItem({
id: id++,
name: appxInfo.name,
data: newCommonItemData({
icon: appxInfo.icon,
target:
"Shell:AppsFolder\\" +
appxInfo.packageFamilyName +
"!" +
appxInfo.appId,
target: "Shell:AppsFolder\\" + appxInfo.id,
}),
})
);
@ -301,264 +234,272 @@ async function getAppxItemList() {
/**
* Appx信息
*/
async function getAppxInfo(installLocation: string) {
// appx信息
let appxInfo: AppxInfo = {
packageFamilyName: null,
installLocation: null,
appId: null,
icon: null,
name: null,
};
async function getAppxInfo(appx: any) {
// 结果列表
let resultList = [];
// buffer, 解析结果
let buffer: Buffer, result: any;
try {
// 解析
buffer = readFileSync(installLocation + "\\AppxManifest.xml");
buffer = readFileSync(join(appx.path, "AppxManifest.xml"));
result = await xml2jsSync(buffer);
// 备用名称
let executable = null;
// targetsize图标
let targetSizeIcon: string | null = null;
let targetSizeIconMax: number | null = null;
// scale图标
let scaleIcon = null;
let scaleIconMax = null;
// 图标 APPID
if (result.Package.Applications && result.Package.Applications[0]) {
if (result.Package.Applications[0].Application[0]) {
// APPID
appxInfo.appId = result.Package.Applications[0].Application[0].$.Id;
// Executable
executable = result.Package.Applications[0].Application[0].$.Executable;
// 获取图标
if (
result.Package.Applications[0].Application[0]["uap:VisualElements"] !=
null
) {
// logo地址
let logo =
result.Package.Applications[0].Application[0][
"uap:VisualElements"
][0].$.Square44x44Logo;
// 解析路径
let parsedPath = parse(logo);
// 获取文件夹下所有文件
let fileNameList = readdirSync(
installLocation + "\\" + parsedPath.dir
);
// 筛选出和包含logo名称的文件名
let filterList = fileNameList.filter(
(f) => f.indexOf(parsedPath.name) >= 0
);
if (filterList.length > 1) {
// 获取targetsize图片
let targetSizeList = filterList.filter(
(f) => f.indexOf(parsedPath.name + ".targetsize") >= 0
// 循环Application
if (
result.Package.Applications &&
result.Package.Applications[0] &&
result.Package.Applications[0].Application &&
result.Package.Applications[0].Application.length > 0
) {
for (
let i = 0;
i < result.Package.Applications[0].Application.length;
i++
) {
// appx信息
let appxInfo: AppxInfo = {
id: null,
icon: null,
name: null,
};
// Application
const application = result.Package.Applications[0].Application[i];
// 名称
if (appx["appName" + i] && appx["appName" + i].trim() !== "") {
appxInfo.name = appx["appName" + i];
} else {
appxInfo.name = appx.displayName;
}
// 获取ID
let id = application.$.Id;
if (!id || id.trim() === "") {
continue;
}
appxInfo.id = appx.familyName + "!" + id;
// 图标
try {
// targetsize图标
let targetSizeIcon: string | null = null;
let targetSizeIconMax: number | null = null;
// scale图标
let scaleIcon = null;
let scaleIconMax = null;
// 图标
if (application["uap:VisualElements"]) {
// logo地址
let logo = application["uap:VisualElements"][0].$.Square44x44Logo;
// 解析路径
let parsedPath = parse(logo);
// 获取文件夹下所有文件
let fileNameList = readdirSync(join(appx.path, parsedPath.dir));
// 筛选出和包含logo名称的文件名
let filterList = fileNameList.filter(
(f) => f.indexOf(parsedPath.name) >= 0
);
if (targetSizeList.length > 0) {
// 获取最大图标尺寸
let max = getMaxIconSize(
targetSizeList,
parsedPath.name,
"targetsize"
if (filterList.length > 1) {
// 获取targetsize图片
let targetSizeList = filterList.filter(
(f) => f.indexOf(parsedPath.name + ".targetsize") >= 0
);
if (max) {
// 记录max
targetSizeIconMax = max;
// 先获取最终图标
let defaultList = targetSizeList.filter(
(f) =>
f ===
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated_devicefamily-colorfulunplated.png"
if (targetSizeList.length > 0) {
// 获取最大图标尺寸
let max = getMaxIconSize(
targetSizeList,
parsedPath.name,
"targetsize"
);
targetSizeIcon =
defaultList.length > 0
? installLocation +
"\\" +
parsedPath.dir +
"\\" +
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated_devicefamily-colorfulunplated.png"
: null;
if (!targetSizeIcon) {
// 获取 名称.targetsize-{max}_altform-unplated.png
let defaultUnplatedList = targetSizeList.filter(
if (max) {
// 记录max
targetSizeIconMax = max;
// 先获取最终图标
let defaultList = targetSizeList.filter(
(f) =>
f ===
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated.png"
"_altform-unplated_devicefamily-colorfulunplated.png"
);
if (defaultUnplatedList.length > 0) {
targetSizeIcon =
installLocation +
"\\" +
parsedPath.dir +
"\\" +
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated.png";
} else {
// 获取 名称.targetsize-{max}_altform.png
let defaultAltFormList = targetSizeList.filter(
(f) =>
f ===
parsedPath.name + ".targetsize-" + max + "_altform.png"
);
if (defaultAltFormList.length > 0) {
targetSizeIcon =
installLocation +
targetSizeIcon =
defaultList.length > 0
? appx.path +
"\\" +
parsedPath.dir +
"\\" +
parsedPath.name +
".targetsize-" +
max +
"_altform.png";
"_altform-unplated_devicefamily-colorfulunplated.png"
: null;
if (!targetSizeIcon) {
// 获取 名称.targetsize-{max}_altform-unplated.png
let defaultUnplatedList = targetSizeList.filter(
(f) =>
f ===
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated.png"
);
if (defaultUnplatedList.length > 0) {
targetSizeIcon =
appx.path +
"\\" +
parsedPath.dir +
"\\" +
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated.png";
} else {
// 获取 名称.targetsize-{max}.png
let defaultTargetSizeList = targetSizeList.filter(
// 获取 名称.targetsize-{max}_altform.png
let defaultAltFormList = targetSizeList.filter(
(f) =>
f === parsedPath.name + ".targetsize-" + max + ".png"
f ===
parsedPath.name +
".targetsize-" +
max +
"_altform.png"
);
if (defaultTargetSizeList.length > 0) {
if (defaultAltFormList.length > 0) {
targetSizeIcon =
installLocation +
appx.path +
"\\" +
parsedPath.dir +
"\\" +
defaultTargetSizeList[0];
parsedPath.name +
".targetsize-" +
max +
"_altform.png";
} else {
// 获取 名称.targetsize-{max}.png
let defaultTargetSizeList = targetSizeList.filter(
(f) =>
f ===
parsedPath.name + ".targetsize-" + max + ".png"
);
if (defaultTargetSizeList.length > 0) {
targetSizeIcon =
appx.path +
"\\" +
parsedPath.dir +
"\\" +
defaultTargetSizeList[0];
}
}
}
}
}
}
}
// 获取scale图片
let scaleList = filterList.filter(
(f) => f.indexOf(parsedPath.name + ".scale") >= 0
);
if (scaleList.length > 0) {
// 获取最大图标尺寸
let max = getMaxIconSize(scaleList, parsedPath.name, "scale");
if (max) {
// 记录max
scaleIconMax = max;
// 获取 名称.scale-{max}.png
let defaultList = scaleList.filter(
(f) => f === parsedPath.name + ".scale-" + max + ".png"
);
if (defaultList.length > 0) {
scaleIcon =
installLocation +
"\\" +
parsedPath.dir +
"\\" +
defaultList[0];
}
}
} else {
scaleList = filterList.filter(
(f) => f.indexOf(parsedPath.name + ".Theme-Dark_Scale") >= 0
// 获取scale图片
let scaleList = filterList.filter(
(f) => f.indexOf(parsedPath.name + ".scale") >= 0
);
if (scaleList.length > 0) {
let max = getMaxIconSize(
scaleList,
parsedPath.name,
"Theme-Dark_Scale"
);
// 获取最大图标尺寸
let max = getMaxIconSize(scaleList, parsedPath.name, "scale");
if (max) {
// 记录max
scaleIconMax = max;
// 获取 名称.Theme-Dark_Scale{max}.png
// 获取 名称.scale-{max}.png
let defaultList = scaleList.filter(
(f) =>
f ===
parsedPath.name + ".Theme-Dark_Scale-" + max + ".png"
(f) => f === parsedPath.name + ".scale-" + max + ".png"
);
if (defaultList.length > 0) {
scaleIcon =
installLocation +
"\\" +
parsedPath.dir +
"\\" +
defaultList[0];
appx.path + "\\" + parsedPath.dir + "\\" + defaultList[0];
}
}
} else {
scaleList = filterList.filter(
(f) => f.indexOf(parsedPath.name + ".Theme-Dark_Scale") >= 0
);
if (scaleList.length > 0) {
let max = getMaxIconSize(
scaleList,
parsedPath.name,
"Theme-Dark_Scale"
);
if (max) {
// 记录max
scaleIconMax = max;
// 获取 名称.Theme-Dark_Scale{max}.png
let defaultList = scaleList.filter(
(f) =>
f ===
parsedPath.name + ".Theme-Dark_Scale-" + max + ".png"
);
if (defaultList.length > 0) {
scaleIcon =
appx.path +
"\\" +
parsedPath.dir +
"\\" +
defaultList[0];
}
}
}
}
} else {
if (filterList.length === 1) {
// 只有一张图片
appxInfo.icon =
appx.path + "\\" + parsedPath.dir + "\\" + filterList[0];
}
}
} else {
if (filterList.length === 1) {
// 只有一张图片
appxInfo.icon =
installLocation + "\\" + parsedPath.dir + "\\" + filterList[0];
}
if (!appxInfo.icon) {
// 判断图标大小
if (targetSizeIcon && !scaleIcon) {
appxInfo.icon = targetSizeIcon;
} else if (!targetSizeIcon && scaleIcon) {
appxInfo.icon = scaleIcon;
} else if (targetSizeIcon && scaleIcon) {
if (
targetSizeIconMax === 256 ||
targetSizeIconMax > scaleIconMax
) {
appxInfo.icon = targetSizeIcon;
} else if (targetSizeIconMax < scaleIconMax) {
appxInfo.icon = scaleIcon;
} else {
appxInfo.icon = targetSizeIcon;
}
} else if (!targetSizeIcon && !scaleIcon) {
let propertiesIcon = getPropertiesIcon(appx.path, result);
if (propertiesIcon) {
appxInfo.icon = propertiesIcon;
}
}
}
} catch (e) {
if (result) {
let propertiesIcon = getPropertiesIcon(appx.path, result);
if (propertiesIcon) {
appxInfo.icon = propertiesIcon;
}
}
}
}
}
if (!appxInfo.icon) {
// 判断图标大小
if (targetSizeIcon && !scaleIcon) {
appxInfo.icon = targetSizeIcon;
} else if (!targetSizeIcon && scaleIcon) {
appxInfo.icon = scaleIcon;
} else if (targetSizeIcon && scaleIcon) {
if (targetSizeIconMax === 256 || targetSizeIconMax > scaleIconMax) {
appxInfo.icon = targetSizeIcon;
} else if (targetSizeIconMax < scaleIconMax) {
appxInfo.icon = scaleIcon;
} else {
appxInfo.icon = targetSizeIcon;
if (
(!appxInfo.icon || appxInfo.icon.trim() === "") &&
appx.logo &&
appx.logo.trim() !== ""
) {
appxInfo.icon = appx.logo;
}
} else if (!targetSizeIcon && !scaleIcon) {
let propertiesIcon = getPropertiesIcon(installLocation, result);
if (propertiesIcon) {
appxInfo.icon = propertiesIcon;
if (
appxInfo.name &&
appxInfo.name.trim() !== "" &&
appxInfo.id &&
appxInfo.id.trim() !== "" &&
appxInfo.icon &&
appxInfo.icon.trim() !== ""
) {
resultList.push(appxInfo);
}
}
}
// 名称
if (result.Package.Properties) {
if (result.Package.Properties[0].DisplayName) {
appxInfo.name = result.Package.Properties[0].DisplayName[0];
}
}
if (
!appxInfo.name ||
(appxInfo.name && appxInfo.name.indexOf("ms-resource:") >= 0)
) {
if (executable && executable.indexOf("ms-resource:") < 0) {
appxInfo.name = parse(executable).name;
} else {
appxInfo.name = null;
}
}
if (!appxInfo.name) {
if (result.Package.Identity && result.Package.Identity[0]) {
let name = result.Package.Identity[0].$.Name;
if (name && name.indexOf("ms-resource:") < 0) {
appxInfo.name = name;
}
}
}
} catch (ex) {
if (result) {
let propertiesIcon = getPropertiesIcon(installLocation, result);
if (propertiesIcon) {
appxInfo.icon = propertiesIcon;
}
}
}
return appxInfo;
} catch (ex) {}
return resultList;
}
/**

View File

@ -1,7 +1,7 @@
{
"name": "dawn-launcher",
"productName": "Dawn Launcher",
"version": "1.3.3",
"version": "1.3.4",
"main": "dist-electron/main/index.js",
"description": "Windows 快捷启动工具,帮助您整理杂乱无章的桌面,分门别类管理您的桌面快捷方式,让您的桌面保持干净整洁。",
"author": "FanChenIO",
@ -43,7 +43,7 @@
"tailwindcss": "^3.3.5",
"typescript": "^5.2.2",
"vite": "^4.4.11",
"vite-plugin-electron": "^0.14.1",
"vite-plugin-electron": "^0.15.4",
"vue": "^3.3.7",
"vue-tsc": "^1.8.22"
},

View File

@ -126,7 +126,7 @@ fn disable_mouse_hook() {
*/
#[allow(dead_code)]
#[napi]
pub fn get_cursor_pos_window_class_name() -> String {
fn get_cursor_pos_window_class_name() -> String {
windows::get_cursor_pos_window_class_name()
}
@ -135,7 +135,7 @@ pub fn get_cursor_pos_window_class_name() -> String {
*/
#[allow(dead_code)]
#[napi]
pub fn get_clipboard_file_list() -> Vec<String> {
fn get_clipboard_file_list() -> Vec<String> {
windows::get_clipboard_file_list()
}
@ -144,7 +144,7 @@ pub fn get_clipboard_file_list() -> Vec<String> {
*/
#[allow(dead_code)]
#[napi]
pub fn clipboard_has_bitmap() -> bool {
fn clipboard_has_bitmap() -> bool {
windows::clipboard_has_bitmap()
}
@ -153,7 +153,7 @@ pub fn clipboard_has_bitmap() -> bool {
*/
#[allow(dead_code)]
#[napi]
pub fn get_clipboard_bitmap_base64() -> Option<String> {
fn get_clipboard_bitmap_base64() -> Option<String> {
windows::get_clipboard_bitmap_base64()
}
@ -162,7 +162,7 @@ pub fn get_clipboard_bitmap_base64() -> Option<String> {
*/
#[allow(dead_code)]
#[napi]
pub fn empty_recycle_bin(window: i32) {
fn empty_recycle_bin(window: i32) {
windows::empty_recycle_bin(window)
}
@ -171,6 +171,15 @@ pub fn empty_recycle_bin(window: i32) {
*/
#[allow(dead_code)]
#[napi]
pub fn remove_window_animation(window: i32) {
fn remove_window_animation(window: i32) {
windows::remove_window_animation(window);
}
/**
* APPX列表
*/
#[allow(dead_code)]
#[napi]
fn get_appx_list() -> Vec<HashMap<String, String>> {
windows::get_appx_list()
}

View File

@ -13,6 +13,7 @@ use std::{
process::Command,
sync::atomic::{AtomicBool, Ordering},
};
use windows::Management::Deployment::PackageManager;
use windows::{
core::{ComInterface, HSTRING, PCSTR, PCWSTR},
w,
@ -691,3 +692,60 @@ pub fn remove_window_animation(window: i32) {
);
};
}
/**
* APPX列表
*/
pub fn get_appx_list() -> Vec<HashMap<String, String>> {
let mut result_list = vec![];
let package_manager: Result<PackageManager, windows::core::Error> = PackageManager::new();
if package_manager.is_err() {
return result_list;
}
let packages = package_manager
.unwrap()
.FindPackagesByUserSecurityId(&HSTRING::default());
if packages.is_err() {
return result_list;
}
for package in packages.unwrap() {
let mut map = HashMap::new();
if let Ok(diaplay_name) = package.DisplayName() {
map.insert(String::from("displayName"), diaplay_name.to_string());
}
if let Ok(path) = package.InstalledPath() {
map.insert(String::from("path"), path.to_string());
}
if let Ok(id) = package.Id() {
if let Ok(family_name) = id.FamilyName() {
map.insert(String::from("familyName"), family_name.to_string());
}
}
if let Ok(logo) = package.Logo() {
if let Ok(path) = logo.Path() {
map.insert(String::from("logo"), path.to_string());
}
}
if let Ok(app_list) = package.GetAppListEntriesAsync() {
if let Ok(app_list) = app_list.get() {
for (index, app) in app_list.into_iter().enumerate() {
if app.DisplayInfo().is_err()
|| app.DisplayInfo().unwrap().DisplayName().is_err()
{
continue;
}
map.insert(
format!("appName{}", index),
app.DisplayInfo()
.unwrap()
.DisplayName()
.unwrap()
.to_string(),
);
}
}
}
result_list.push(map);
}
result_list
}

View File

@ -41,6 +41,7 @@
lineHeight:
store.setting.subClassification.itemAreaNameFontLineHeight +
'rem',
textAlign: store.setting.subClassification.itemAreaNameAlign,
}"
>
{{ classification.name }}

View File

@ -771,6 +771,13 @@
<div class="mx-2" v-if="selectedMenuId === 3">
<NForm label-placement="left" :show-feedback="false" size="small">
<span class="block font-semibold">{{ store.language.name }}</span>
<NFormItem :label="store.language.align" class="mt-1">
<NSelect
v-model:value="setting.subClassification.itemAreaNameAlign"
:options="itemAreaSubclassificationNameAlignOptions"
size="small"
></NSelect>
</NFormItem>
<NFormItem :label="store.language.fontSize" class="mt-1">
<NInputNumber
v-model:value="setting.subClassification.itemAreaNameFontSize"
@ -1771,6 +1778,21 @@ let backgroundImagePositionOptions = ref([
value: "right",
},
]);
//
let itemAreaSubclassificationNameAlignOptions = ref([
{
label: store.language.left,
value: "left",
},
{
label: store.language.center,
value: "center",
},
{
label: store.language.right,
value: "right",
},
]);
//
watch(
() => setting.value,

2
types/setting.d.ts vendored
View File

@ -118,6 +118,8 @@ export interface SubClassification {
itemAreaNameFontWeight: number;
// 名称字体行高(项目区域)
itemAreaNameFontLineHeight: number;
// 名称对齐(项目区域)
itemAreaNameAlign: "left" | "center" | "right";
}
// 项目