Initial commit
25
.gitignore
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
coverage/
|
||||
bower_components/
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
typings/
|
||||
out/
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
lib-cov
|
||||
.nyc_output
|
||||
.grunt
|
||||
.lock-wscript
|
||||
.npm
|
||||
.eslintcache
|
||||
.node_repl_history
|
||||
*.tgz
|
||||
.yarn-integrity
|
||||
.env
|
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
10
.idea/YukiHookAPI-ProjectBuilder.iml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="electron" level="application" />
|
||||
</component>
|
||||
</module>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
21
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,21 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="HtmlFormInputWithoutLabel" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="myValues">
|
||||
<value>
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="mdui-dialog-close" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myCustomValuesEnabled" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
.idea/jsLibraryMappings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<file url="PROJECT" libraries="{electron}" />
|
||||
</component>
|
||||
</project>
|
7
.idea/libraries/KotlinJavaRuntime.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<component name="libraryTable">
|
||||
<library name="KotlinJavaRuntime" type="repository">
|
||||
<CLASSES />
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
7
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="FLOW" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="liberica-11" project-jdk-type="JavaSDK" />
|
||||
</project>
|
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/YukiHookAPI-ProjectBuilder.iml" filepath="$PROJECT_DIR$/.idea/YukiHookAPI-ProjectBuilder.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
67
package.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "yukihookapi-projectbuilder",
|
||||
"productName": "YukiHookAPI Project Builder",
|
||||
"version": "1.0.0",
|
||||
"description": "A Xposed Project Builder by YukiHookAPI",
|
||||
"main": "src/app.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Hello YukiHookAPI-ProjectBuilder!\" && exit 1",
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make"
|
||||
},
|
||||
"author": "HighCapable",
|
||||
"license": "AGPL-3.0",
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "^6.0.0-beta.64",
|
||||
"@electron-forge/maker-deb": "^6.0.0-beta.64",
|
||||
"@electron-forge/maker-rpm": "^6.0.0-beta.64",
|
||||
"@electron-forge/maker-squirrel": "^6.0.0-beta.64",
|
||||
"@electron-forge/maker-zip": "^6.0.0-beta.64",
|
||||
"electron": "^19.0.7",
|
||||
"electron-icon-builder": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"dayjs": "^1.11.3",
|
||||
"decompress-zip": "^0.3.3",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"electron-store": "^8.0.2",
|
||||
"fs-extra": "^10.1.0"
|
||||
},
|
||||
"config": {
|
||||
"forge": {
|
||||
"packagerConfig": {
|
||||
"packageManager": "npm",
|
||||
"icon": "src/icons/icon",
|
||||
"asar": true,
|
||||
"overwrite": true
|
||||
},
|
||||
"makers": [
|
||||
{
|
||||
"name": "@electron-forge/maker-squirrel",
|
||||
"config": {
|
||||
"name": "yukihookapi_projectbuilder"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "@electron-forge/maker-zip",
|
||||
"platforms": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@electron-forge/maker-deb",
|
||||
"config": {
|
||||
"name": "yukihookapi_projectbuilder"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "@electron-forge/maker-rpm",
|
||||
"config": {
|
||||
"name": "yukihookapi_projectbuilder"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
BIN
public/project-template.zip
Normal file
384
src/app-space.js
Normal file
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/21.
|
||||
*/
|
||||
|
||||
const {app, ipcMain, dialog, BrowserWindow, Menu, MenuItem} = require('electron');
|
||||
const {locale} = require('./libs/locale');
|
||||
const {fileSystem} = require('./libs/file-system');
|
||||
const {store} = require('./libs/store');
|
||||
const {system} = require("./libs/system");
|
||||
|
||||
/** 主窗口 */
|
||||
let mainWindow = null;
|
||||
|
||||
/**
|
||||
* 应用程序初始化命名空间
|
||||
*/
|
||||
const appSpace = {
|
||||
/** 开始装载窗口 */
|
||||
loadFrame: () => {
|
||||
appSpace.createWindow();
|
||||
appSpace.createMenu();
|
||||
},
|
||||
/** 创建窗口 */
|
||||
createWindow: () => {
|
||||
mainWindow = new BrowserWindow({
|
||||
title: locale.i18n.windowTitle,
|
||||
width: 1000,
|
||||
height: 1050,
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
}
|
||||
});
|
||||
mainWindow.loadFile('src/content/index.html').then(() => {
|
||||
appWindow.webContents.methods.page.init(localeConfig.currentLocale(), app.getVersion());
|
||||
});
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show();
|
||||
});
|
||||
},
|
||||
/** 创建菜单 */
|
||||
createMenu: () => {
|
||||
const menu = new Menu();
|
||||
const separatorItem = new MenuItem({type: 'separator'});
|
||||
const aboutChildItem = new MenuItem({
|
||||
label: locale.i18n.about,
|
||||
accelerator: system.isMacOS ? 'command+a' : 'ctrl+a',
|
||||
click: () => {
|
||||
appWindow.webContents.methods.page.showAbout(app.getName(), app.getVersion());
|
||||
}
|
||||
});
|
||||
const checkUpdateChildItem = new MenuItem({
|
||||
label: locale.i18n.checkUpdate,
|
||||
click: () => {
|
||||
appWindow.webContents.methods.page.checkForUpdates();
|
||||
}
|
||||
});
|
||||
const projectAddressChildItem = new MenuItem({
|
||||
label: locale.i18n.projectAddress,
|
||||
accelerator: system.isMacOS ? 'command+w' : 'ctrl+w',
|
||||
click: () => {
|
||||
system.openBrowser('https://github.com/fankes/YukiHookAPI');
|
||||
}
|
||||
});
|
||||
const helpDocumentationChildItem = new MenuItem({
|
||||
label: locale.i18n.helpDocumentation,
|
||||
accelerator: system.isMacOS ? 'command+h' : 'ctrl+h',
|
||||
click: () => {
|
||||
system.openBrowser('https://fankes.github.io/YukiHookAPI');
|
||||
}
|
||||
});
|
||||
const openSourceChildItem = new MenuItem({
|
||||
label: locale.i18n.openSource,
|
||||
accelerator: system.isMacOS ? 'command+o' : 'ctrl+o',
|
||||
click: () => {
|
||||
appWindow.webContents.methods.page.showOpenSource();
|
||||
}
|
||||
});
|
||||
const laguageSubChildItems = [];
|
||||
laguageSubChildItems.push(new MenuItem({
|
||||
type: 'radio',
|
||||
label: locale.i18n.followSystem,
|
||||
checked: localeConfig.isFollowSystem,
|
||||
click: () => {
|
||||
localeConfig.changeLocale();
|
||||
}
|
||||
}));
|
||||
for (const la in locale.languageSupports)
|
||||
laguageSubChildItems.push(new MenuItem({
|
||||
type: 'radio',
|
||||
label: locale.languageSupports[la],
|
||||
checked: la === locale.name && !localeConfig.isFollowSystem,
|
||||
click: () => {
|
||||
localeConfig.changeLocale(la);
|
||||
}
|
||||
}));
|
||||
const languageChildItem = new MenuItem({
|
||||
label: locale.i18n.language + ' (Language)',
|
||||
submenu: laguageSubChildItems
|
||||
});
|
||||
const quitChildItem = new MenuItem({
|
||||
label: locale.i18n.quit,
|
||||
accelerator: system.isMacOS ? 'command+q' : 'ctrl+q',
|
||||
click: () => {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
const runBuildChildItem = new MenuItem({
|
||||
label: locale.i18n.runBuild,
|
||||
accelerator: system.isMacOS ? 'command+b' : 'ctrl+b',
|
||||
click: () => {
|
||||
appWindow.webContents.methods.build.checking();
|
||||
}
|
||||
});
|
||||
const newTemplateChildItem = new MenuItem({
|
||||
label: locale.i18n.newTemplate,
|
||||
accelerator: system.isMacOS ? 'command+n' : 'ctrl+n',
|
||||
click: () => {
|
||||
appWindow.webContents.methods.configTemplate.createNew();
|
||||
}
|
||||
});
|
||||
const templateSubChildItems = [];
|
||||
const clearAllTemplateChildItem = new MenuItem({
|
||||
label: locale.i18n.clearAllTemplate,
|
||||
accelerator: system.isMacOS ? 'command+d' : 'ctrl+d',
|
||||
click: () => {
|
||||
appWindow.webContents.methods.configTemplate.clearAll();
|
||||
}
|
||||
});
|
||||
const templates = store.get('config-templates', []);
|
||||
if (templates.length > 0) {
|
||||
templates.forEach((value) => {
|
||||
templateSubChildItems.push(new MenuItem({
|
||||
label: value.name,
|
||||
click: () => {
|
||||
appWindow.webContents.methods.configTemplate.load(value);
|
||||
}
|
||||
}));
|
||||
});
|
||||
templateSubChildItems.push(separatorItem);
|
||||
templateSubChildItems.push(clearAllTemplateChildItem);
|
||||
} else templateSubChildItems.push(new MenuItem({
|
||||
label: locale.i18n.nothing,
|
||||
enabled: false
|
||||
}));
|
||||
const savedTemplateChildItem = new MenuItem({
|
||||
label: locale.i18n.savedTemplate,
|
||||
submenu: templateSubChildItems
|
||||
});
|
||||
const configTemplateChildItem = new MenuItem({
|
||||
label: locale.i18n.configTemplate,
|
||||
submenu: [newTemplateChildItem, savedTemplateChildItem]
|
||||
});
|
||||
const resetCurrentConfigChildItem = new MenuItem({
|
||||
label: locale.i18n.resetCurrentConfig,
|
||||
accelerator: system.isMacOS ? 'command+r' : 'ctrl+r',
|
||||
click: () => {
|
||||
appWindow.webContents.methods.page.restore();
|
||||
}
|
||||
});
|
||||
const fileMainItem = new MenuItem({
|
||||
label: system.isMacOS ? app.name : locale.i18n.file,
|
||||
submenu: system.isMacOS ? [aboutChildItem, separatorItem, checkUpdateChildItem, separatorItem,
|
||||
projectAddressChildItem, helpDocumentationChildItem, separatorItem, openSourceChildItem, separatorItem,
|
||||
languageChildItem, separatorItem, quitChildItem] : [languageChildItem, separatorItem, quitChildItem]
|
||||
});
|
||||
const projectMainItem = new MenuItem({
|
||||
label: locale.i18n.project,
|
||||
submenu: [runBuildChildItem, separatorItem, configTemplateChildItem, resetCurrentConfigChildItem]
|
||||
});
|
||||
const helpMainItem = new MenuItem({
|
||||
label: (locale.i18n.help),
|
||||
submenu: [aboutChildItem, separatorItem, checkUpdateChildItem, separatorItem,
|
||||
projectAddressChildItem, helpDocumentationChildItem, separatorItem, openSourceChildItem]
|
||||
});
|
||||
menu.append(fileMainItem);
|
||||
menu.append(projectMainItem);
|
||||
if (!system.isMacOS) menu.append(helpMainItem);
|
||||
Menu.setApplicationMenu(menu);
|
||||
},
|
||||
/**
|
||||
* 注册 ipc 监听
|
||||
* @param option 回调选项
|
||||
*/
|
||||
registerIpcListener: (option) => {
|
||||
ipcMain.on('run-packaging-project', (_, configs) => {
|
||||
option['run-packaging-project'](configs);
|
||||
});
|
||||
ipcMain.on('open-complete-project', () => {
|
||||
option['open-complete-project']();
|
||||
});
|
||||
ipcMain.on('save-config-template', (_, configs) => {
|
||||
const templates = store.get('config-templates', []);
|
||||
templates.push(configs);
|
||||
store.set('config-templates', templates);
|
||||
appSpace.createMenu();
|
||||
});
|
||||
ipcMain.on('clear-all-config-template', () => {
|
||||
store.set('config-templates', []);
|
||||
appSpace.createMenu();
|
||||
});
|
||||
ipcMain.on('reload-current-page', () => {
|
||||
setTimeout(() => {
|
||||
mainWindow.reload();
|
||||
appWindow.webContents.methods.page.init(localeConfig.currentLocale(), app.getVersion());
|
||||
}, 150);
|
||||
});
|
||||
ipcMain.on('relaunch-app', () => {
|
||||
mainWindow.close();
|
||||
app.relaunch();
|
||||
});
|
||||
ipcMain.on('open-system-browser', (_, url) => {
|
||||
system.openBrowser(url);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 应用程序配置命名空间
|
||||
*/
|
||||
const appConfig = {
|
||||
/**
|
||||
* 项目根路径
|
||||
* @return string
|
||||
*/
|
||||
sourcePath: app.isPackaged ? app.getAppPath() : '.',
|
||||
/**
|
||||
* 项目外部路径
|
||||
* @return string
|
||||
*/
|
||||
dataPath: fileSystem.path(app.getPath('appData'), 'YukiHookAPI'),
|
||||
/** 创建应用数据目录 */
|
||||
createDataDir: () => {
|
||||
const dataPath = appConfig.dataPath;
|
||||
if (!fileSystem.exists(dataPath)) fileSystem.mkdir(dataPath);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 语言区域配置命名空间
|
||||
*/
|
||||
const localeConfig = {
|
||||
/**
|
||||
* 语言是否跟随系统
|
||||
* @return boolean
|
||||
*/
|
||||
isFollowSystem: store.get('locale-follow-system', true),
|
||||
/**
|
||||
* 当前存储的语言名称
|
||||
* @return string
|
||||
*/
|
||||
storeLocaleName: store.get('store-locale-name', locale.default),
|
||||
/**
|
||||
* 获取当前语言区域名称
|
||||
* @return string
|
||||
*/
|
||||
currentLocale: () => {
|
||||
return localeConfig.isFollowSystem ? app.getLocale() : localeConfig.storeLocaleName;
|
||||
},
|
||||
/**
|
||||
* 修改语言
|
||||
* @param name 语言名称
|
||||
*/
|
||||
changeLocale: (name = 'default') => {
|
||||
if (name === 'default') {
|
||||
store.set('locale-follow-system', true);
|
||||
store.set('store-locale-name', locale.default);
|
||||
} else {
|
||||
store.set('locale-follow-system', false);
|
||||
store.set('store-locale-name', name);
|
||||
}
|
||||
appWindow.webContents.methods.page.relaunch();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 应用程序窗口命名空间
|
||||
*/
|
||||
const appWindow = {
|
||||
/**
|
||||
* 打开目录
|
||||
* @param option 选项
|
||||
* @param callback 回调结果
|
||||
* @param onError 回调错误
|
||||
*/
|
||||
showOpenDirectory: (option, callback, onError) => {
|
||||
dialog.showOpenDialog(mainWindow, {
|
||||
properties: ['openDirectory'],
|
||||
title: option['title'],
|
||||
message: option['message'],
|
||||
buttonLabel: option['buttonLabel']
|
||||
}).then(result => {
|
||||
callback(result);
|
||||
}).catch((e) => {
|
||||
onError(e);
|
||||
});
|
||||
},
|
||||
/** 窗口内网页交互调用桥 */
|
||||
webContents: {
|
||||
/**
|
||||
* 执行内部 JS
|
||||
* @param code 执行代码
|
||||
*/
|
||||
execJs: (code) => {
|
||||
mainWindow.webContents.executeJavaScript(code).then(() => null);
|
||||
},
|
||||
methods: {
|
||||
configTemplate: {
|
||||
load: (configs) => {
|
||||
appWindow.webContents.execJs('configTemplate.load(\'' + encodeURI(JSON.stringify(configs)) + '\')');
|
||||
},
|
||||
createNew: () => {
|
||||
appWindow.webContents.execJs('configTemplate.createNew()');
|
||||
},
|
||||
clearAll: () => {
|
||||
appWindow.webContents.execJs('configTemplate.clearAll()');
|
||||
}
|
||||
},
|
||||
page: {
|
||||
init: (localeName, appVersion) => {
|
||||
appWindow.webContents.execJs('page.init(\'' + localeName + '\',\'' + appVersion + '\')');
|
||||
},
|
||||
snack: (message) => {
|
||||
appWindow.webContents.execJs('page.snack(\'' + message + '\')');
|
||||
},
|
||||
showAbout: (name, version) => {
|
||||
appWindow.webContents.execJs('page.showAbout(\'' + name + '\',\'' + version + '\')');
|
||||
},
|
||||
showOpenSource: () => {
|
||||
appWindow.webContents.execJs('page.showOpenSource()');
|
||||
},
|
||||
checkForUpdates: () => {
|
||||
appWindow.webContents.execJs('page.checkForUpdates()');
|
||||
},
|
||||
restore: () => {
|
||||
appWindow.webContents.execJs('page.restore()');
|
||||
},
|
||||
relaunch: () => {
|
||||
appWindow.webContents.execJs('page.relaunch()');
|
||||
}
|
||||
},
|
||||
build: {
|
||||
checking: () => {
|
||||
appWindow.webContents.execJs('build.checking()');
|
||||
},
|
||||
changeStatus: (msg) => {
|
||||
appWindow.webContents.execJs('build.changeStatus(\'' + msg + '\')');
|
||||
},
|
||||
complete: (msg) => {
|
||||
appWindow.webContents.execJs('build.complete(\'' + msg + '\')');
|
||||
},
|
||||
failure: (msg) => {
|
||||
appWindow.webContents.execJs('build.failure(\'' + msg + '\')');
|
||||
},
|
||||
cancel: () => {
|
||||
appWindow.webContents.execJs('build.cancel()');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {appSpace, appWindow, appConfig, localeConfig};
|
47
src/app.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/5.
|
||||
*/
|
||||
|
||||
const {app} = require('electron');
|
||||
const {locale} = require('./libs/locale');
|
||||
const {appSpace, appConfig, localeConfig} = require('./app-space');
|
||||
const {transaction} = require('./transaction');
|
||||
|
||||
/** 忽略跨域访问警告 */
|
||||
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
|
||||
|
||||
/** 当应用程序启动时完成创建 */
|
||||
app.whenReady().then(() => {
|
||||
appConfig.createDataDir();
|
||||
locale.initLocale(localeConfig.currentLocale());
|
||||
app.setName(locale.i18n.appName);
|
||||
appSpace.loadFrame();
|
||||
appSpace.registerIpcListener({
|
||||
['run-packaging-project']: (configs) => {
|
||||
transaction.start(configs);
|
||||
},
|
||||
['open-complete-project']: () => {
|
||||
transaction.openProject();
|
||||
}
|
||||
});
|
||||
}).catch((e) => {
|
||||
console.log('[Warning] An error occurred during app startup ↓\n' + e);
|
||||
});
|
13559
src/content/css/mdui.css
Normal file
1
src/content/css/mdui.css.map
Normal file
6
src/content/css/mdui.min.css
vendored
Normal file
1
src/content/css/mdui.min.css.map
Normal file
201
src/content/fonts/roboto/LICENSE.txt
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
BIN
src/content/fonts/roboto/Roboto-Black.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-Black.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-BlackItalic.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-BlackItalic.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-Bold.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-Bold.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-BoldItalic.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-BoldItalic.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-Light.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-Light.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-LightItalic.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-LightItalic.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-Medium.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-Medium.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-MediumItalic.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-MediumItalic.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-Regular.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-Regular.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-RegularItalic.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-RegularItalic.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-Thin.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-Thin.woff2
Normal file
BIN
src/content/fonts/roboto/Roboto-ThinItalic.woff
Normal file
BIN
src/content/fonts/roboto/Roboto-ThinItalic.woff2
Normal file
393
src/content/icons/material-icons/LICENSE.txt
Normal file
@@ -0,0 +1,393 @@
|
||||
Attribution 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More_considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution 4.0 International Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution 4.0 International Public License ("Public License"). To the
|
||||
extent this Public License may be interpreted as a contract, You are
|
||||
granted the Licensed Rights in consideration of Your acceptance of
|
||||
these terms and conditions, and the Licensor grants You such rights in
|
||||
consideration of benefits the Licensor receives from making the
|
||||
Licensed Material available under these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
d. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
e. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
f. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
g. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
h. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
i. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
j. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
k. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
4. If You Share Adapted Material You produce, the Adapter's
|
||||
License You apply must not prevent recipients of the Adapted
|
||||
Material from complying with this Public License.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material; and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public licenses.
|
||||
Notwithstanding, Creative Commons may elect to apply one of its public
|
||||
licenses to material it publishes and in those instances will be
|
||||
considered the "Licensor." Except for the limited purpose of indicating
|
||||
that material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the public
|
||||
licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
BIN
src/content/icons/material-icons/MaterialIcons-Regular.woff
Normal file
BIN
src/content/icons/material-icons/MaterialIcons-Regular.woff2
Normal file
323
src/content/index.html
Executable file
@@ -0,0 +1,323 @@
|
||||
<!--
|
||||
YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
Copyright (C) 2019-2022 HighCapable
|
||||
https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
|
||||
This software is non-free but opensource software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU Affero General Public License
|
||||
as published by the Free Software Foundation; either
|
||||
version 3 of the License, or any later version.
|
||||
|
||||
This software 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
|
||||
Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
and eula along with this software. If not, see
|
||||
<https://www.gnu.org/licenses/>
|
||||
|
||||
This file is Created by fankes on 2022/6/27.
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no" name="viewport">
|
||||
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
|
||||
<meta content="webkit" name="renderer">
|
||||
<meta content="no-siteapp">
|
||||
<meta content="light dark" name="color-scheme">
|
||||
<title> </title>
|
||||
<link href="css/mdui.min.css" rel="stylesheet">
|
||||
<link href="render.css" rel="stylesheet">
|
||||
<script src="js/mdui.min.js"></script>
|
||||
</head>
|
||||
<body class="mdui-container-fluid mdui-theme-primary-orange mdui-theme-accent-orange mdui-theme-layout-auto">
|
||||
<div id="root_div" style="font-size:12pt;line-height:150%;padding-top:5pt;padding-left:10pt;padding-right:10pt;display:none">
|
||||
<div class="mdui-row mdui-center">
|
||||
<div class="mdui-col-xs-6">
|
||||
<div style="margin-top: 15px"></div>
|
||||
<div class="mdui-typo-subheading-opacity i18n" style="margin-left: 5px">{{basicConfig}}</div>
|
||||
<div class="mdui-textfield mdui-textfield-floating-label">
|
||||
<i class="mdui-icon material-icons">create_new_folder</i>
|
||||
<label class="mdui-textfield-label i18n">{{projectNameTip}}</label>
|
||||
<input class="mdui-textfield-input" id="project_name_text" required/>
|
||||
</div>
|
||||
<div class="mdui-textfield mdui-textfield-floating-label">
|
||||
<i class="mdui-icon material-icons">folder</i>
|
||||
<label class="mdui-textfield-label i18n">{{modulePackageName}} (Package Name)</label>
|
||||
<input class="mdui-textfield-input" id="package_name_text" required/>
|
||||
</div>
|
||||
<div class="mdui-textfield mdui-textfield-floating-label">
|
||||
<i class="mdui-icon material-icons">edit</i>
|
||||
<label class="mdui-textfield-label i18n">{{moduleName}} (App Name)</label>
|
||||
<input class="mdui-textfield-input" id="app_name_text" required/>
|
||||
</div>
|
||||
<div class="mdui-textfield mdui-textfield-floating-label">
|
||||
<i class="mdui-icon material-icons">edit</i>
|
||||
<label class="mdui-textfield-label i18n">{{moduleDescription}} (Xposed Module Description)</label>
|
||||
<textarea class="mdui-textfield-input" id="module_description_text" required
|
||||
style="max-height: 80px;overflow: hidden"></textarea>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">widgets</i>
|
||||
<label class="mdui-textfield-label i18n">{{uiComponents}}</label>
|
||||
<select class="mdui-select" id="compoment_select">
|
||||
<option class="i18n" value="0">{{createDefaultActivity}}</option>
|
||||
<option class="i18n" value="1">{{createBlankActivity}}</option>
|
||||
<option class="i18n" value="2">{{withoutUiComponents}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mdui-row">
|
||||
<div class="mdui-textfield mdui-textfield-floating-label mdui-col-xs-6">
|
||||
<i class="mdui-icon material-icons">details</i>
|
||||
<label class="mdui-textfield-label i18n">{{appMinApiVersion}}</label>
|
||||
<input class="mdui-textfield-input" id="app_min_api_text" required type="number" value="27"/>
|
||||
</div>
|
||||
<div class="mdui-textfield mdui-textfield-floating-label mdui-col-xs-6">
|
||||
<i class="mdui-icon material-icons">change_history</i>
|
||||
<label class="mdui-textfield-label i18n">{{appTargetApiVersion}}</label>
|
||||
<input class="mdui-textfield-input" id="app_target_api_text" required type="number"
|
||||
value="32"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdui-textfield mdui-textfield-floating-label">
|
||||
<i class="mdui-icon material-icons">extension</i>
|
||||
<label class="mdui-textfield-label i18n">{{xposedMinApiVersion}} (Xposed Min API Version)</label>
|
||||
<input class="mdui-textfield-input" id="xposed_min_api_text" required type="number" value="93"/>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">settings_input_hdmi</i>
|
||||
<label class="mdui-textfield-label i18n">{{targetXposedPlatform}} (Xposed Platform)</label>
|
||||
<select class="mdui-select" id="target_xposed_platform_select">
|
||||
<option class="i18n" value="0">{{universal}}</option>
|
||||
<option value="1">LSPosed</option>
|
||||
<!-- TODO LSPatch WIP -->
|
||||
<option disabled value="2">LSPatch (WIP)</option>
|
||||
<option value="3">TaiChi</option>
|
||||
<option class="i18n" value="4">{{nativeXposed}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mdui-textfield" id="new_xshare_prefs_div">
|
||||
<i class="mdui-icon material-icons">style</i>
|
||||
<label class="mdui-textfield-label i18n">{{declarationNewXSharePrefs}}</label>
|
||||
<select class="mdui-select" id="new_xshare_prefs_select">
|
||||
<option class="i18n" value="0">{{notConfigure}}</option>
|
||||
<option class="i18n" value="1">{{yesOfConfigure}}</option>
|
||||
<option class="i18n" value="2">{{noOfConfigure}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="module_scope_div">
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">view_list</i>
|
||||
<label class="mdui-textfield-label i18n" style="margin-bottom: 7px">{{moduleScope}}</label>
|
||||
</div>
|
||||
<div class="mdui-list" id="scope_list"
|
||||
style="margin-left: 40px; margin-top: -15px; max-height:100px; overflow:auto"></div>
|
||||
<button class="mdui-btn mdui-round-btn mdui-btn-block mdui-color-theme-accent mdui-ripple"
|
||||
onclick="moduleScope.showAddDialog()"
|
||||
style="margin-left: 40px;width: 92%">
|
||||
<i class="mdui-icon material-icons" style="margin-bottom: 4px;margin-right: 4px">add</i>
|
||||
<span class="i18n" style="text-transform: none">{{addApps}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div style="margin-top: 15px"></div>
|
||||
</div>
|
||||
<div class="mdui-col-xs-6">
|
||||
<div style="margin-top: 15px"></div>
|
||||
<div class="mdui-typo-subheading-opacity i18n" style="margin-left: 5px">{{yukiHookApiConfig}}</div>
|
||||
<div class="mdui-textfield mdui-textfield-floating-label">
|
||||
<i class="mdui-icon material-icons">code</i>
|
||||
<label class="mdui-textfield-label i18n">{{entryClassName}}</label>
|
||||
<input class="mdui-textfield-input" id="entry_class_name_text"/>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">photo_library</i>
|
||||
<label class="mdui-textfield-label i18n">{{addResourcesHookSupport}}</label>
|
||||
<select class="mdui-select" id="support_resources_hook_select">
|
||||
<option class="i18n" value="0">{{notConfigureDefYes}}</option>
|
||||
<option class="i18n" value="1">{{yesOfConfigure}}</option>
|
||||
<option class="i18n" value="2">{{noOfConfigure}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mdui-textfield mdui-textfield-floating-label">
|
||||
<i class="mdui-icon material-icons">local_offer</i>
|
||||
<label class="mdui-textfield-label i18n">{{debugTagName}}</label>
|
||||
<input class="mdui-textfield-input" id="debug_tag_name_text"/>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">bug_report</i>
|
||||
<label class="mdui-textfield-label i18n">{{enableDebugMode}}</label>
|
||||
<select class="mdui-select" id="enable_debug_select">
|
||||
<option class="i18n" value="0">{{notConfigureDefYes}}</option>
|
||||
<option class="i18n" value="1">{{yesOfConfigure}}</option>
|
||||
<option class="i18n" value="2">{{noOfConfigure}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">pageview</i>
|
||||
<label class="mdui-textfield-label i18n">{{enablePrintLogcat}}</label>
|
||||
<select class="mdui-select" id="enable_print_logcat_select">
|
||||
<option class="i18n" value="0">{{notConfigureDefYes}}</option>
|
||||
<option class="i18n" value="1">{{yesOfConfigure}}</option>
|
||||
<option class="i18n" value="2">{{noOfConfigure}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">storage</i>
|
||||
<label class="mdui-textfield-label i18n">{{enableYukiHookModulePrefsCache}}</label>
|
||||
<select class="mdui-select" id="enable_yprefs_cache_select">
|
||||
<option class="i18n" value="0">{{notConfigureDefYes}}</option>
|
||||
<option class="i18n" value="1">{{yesOfConfigure}}</option>
|
||||
<option class="i18n" value="2">{{noOfConfigure}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">satellite</i>
|
||||
<label class="mdui-textfield-label i18n">{{enableModuleResourcesCache}}</label>
|
||||
<select class="mdui-select" id="enable_resources_cache_select">
|
||||
<option class="i18n" value="0">{{notConfigureDefYes}}</option>
|
||||
<option class="i18n" value="1">{{yesOfConfigure}}</option>
|
||||
<option class="i18n" value="2">{{noOfConfigure}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">done_all</i>
|
||||
<label class="mdui-textfield-label i18n">{{enableModuleStatus}}</label>
|
||||
<select class="mdui-select" id="enable_module_status_select">
|
||||
<option class="i18n" value="0">{{notConfigureDefYes}}</option>
|
||||
<option class="i18n" value="1">{{yesOfConfigure}}</option>
|
||||
<option class="i18n" value="2">{{noOfConfigure}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">settings_input_composite</i>
|
||||
<label class="mdui-textfield-label i18n">{{enableYukiHookDataChannel}}</label>
|
||||
<select class="mdui-select" id="enable_ychannel_select">
|
||||
<option class="i18n" value="0">{{notConfigureDefYes}}</option>
|
||||
<option class="i18n" value="1">{{yesOfConfigure}}</option>
|
||||
<option class="i18n" value="2">{{noOfConfigure}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mdui-textfield">
|
||||
<i class="mdui-icon material-icons">texture</i>
|
||||
<label class="mdui-textfield-label i18n">{{enableMemberCache}}</label>
|
||||
<select class="mdui-select" id="enable_member_cache_select">
|
||||
<option class="i18n" value="0">{{notConfigureDefYes}}</option>
|
||||
<option class="i18n" value="1">{{yesOfConfigure}}</option>
|
||||
<option class="i18n" value="2">{{noOfConfigure}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="margin-top: 15px"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="mdui-fab mdui-fab-fixed mdui-color-theme-accent mdui-ripple" onclick="build.checking()"
|
||||
style="margin-right: 10px;margin-bottom: 10px">
|
||||
<i class="mdui-icon material-icons">archive</i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="mdui-dialog" id="module_scope_dialog" style="max-width: 500px">
|
||||
<div class="mdui-dialog-title i18n">{{addApps}}</div>
|
||||
<div>
|
||||
<span class="i18n" style="margin-left: 24px">{{selectScopeAppsOrEnterOnceTip}}</span>
|
||||
<select class="mdui-select" id="module_scope_select" style="margin-left: 26px;margin-top: 10px">
|
||||
<option class="i18n" selected value="0">-- {{customize}} --</option>
|
||||
<option class="i18n" value="1">{{systemFramework}}</option>
|
||||
<option class="i18n" value="2">{{systemUi}}</option>
|
||||
</select>
|
||||
<div class="mdui-textfield" style="margin-left: 26px;margin-right: 33px">
|
||||
<input class="mdui-textfield-input i18n" id="module_scope_text" placeholder="{{enterAppNameTip}}" type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdui-dialog-actions">
|
||||
<button class="mdui-btn mdui-ripple i18n" mdui-dialog-close>{{cancel}}</button>
|
||||
<button class="mdui-btn mdui-ripple i18n" onclick="moduleScope.saveData()">{{ok}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdui-dialog" id="search_depend_dialog" style="max-width: 500px">
|
||||
<div class="mdui-dialog-title i18n">{{pleaseWait}}</div>
|
||||
<div class="mdui-dialog-content">
|
||||
<span class="i18n">{{autoSearchingDependsTip}}</span>
|
||||
<div style="height: 15px"></div>
|
||||
<div class="mdui-progress">
|
||||
<div class="mdui-progress-indeterminate"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdui-dialog" id="config_package_dialog" style="max-width: 500px">
|
||||
<div class="mdui-dialog-title i18n">{{configProjectDepends}}</div>
|
||||
<div>
|
||||
<span class="i18n" style="margin-left: 24px">{{gradlePaper}}</span>
|
||||
<select class="mdui-select" id="gradle_version_select"
|
||||
style="margin-left: 26px;margin-top: 10px;margin-bottom: 15px">
|
||||
</select>
|
||||
<span class="i18n" style="margin-left: 24px">{{agpVersion}}</span>
|
||||
<select class="mdui-select" id="agp_version_select"
|
||||
style="margin-left: 26px;margin-top: 10px;margin-bottom: 15px">
|
||||
</select>
|
||||
<span class="i18n" style="margin-left: 24px">{{kotlinVersion}}</span>
|
||||
<select class="mdui-select" id="kotlin_version_select"
|
||||
style="margin-left: 26px;margin-top: 10px;margin-bottom: 15px">
|
||||
</select>
|
||||
<span class="i18n" style="margin-left: 24px">{{yukiHookApiVersion}}</span>
|
||||
<select class="mdui-select" id="yukihookapi_version_select"
|
||||
style="margin-left: 26px;margin-top: 10px;margin-bottom: 20px">
|
||||
</select>
|
||||
<div style="margin-left: 24px;margin-right: 24px;margin-bottom: 20px">
|
||||
<span class="i18n" style="font-size:9pt;opacity: 0.55">{{oldDependsWarnTip}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdui-dialog-actions">
|
||||
<button class="mdui-btn mdui-ripple i18n" mdui-dialog-close onclick="build.unlockStatus()">{{cancel}}</button>
|
||||
<button class="mdui-btn mdui-ripple i18n" onclick="build.run()">{{runBuild}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdui-dialog" id="packaging_progress_dialog" style="max-width: 500px">
|
||||
<div class="mdui-dialog-title i18n">{{pleaseWait}}</div>
|
||||
<div class="mdui-dialog-content">
|
||||
<span id="packaging_progress_text"></span>
|
||||
<div style="height: 15px"></div>
|
||||
<div class="mdui-progress">
|
||||
<div class="mdui-progress-indeterminate"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdui-dialog" id="about_dialog" style="max-width: 500px">
|
||||
<div class="mdui-dialog-title i18n">{{about}}</div>
|
||||
<div class="mdui-dialog-content" style="line-height: 35px">
|
||||
<span id="about_name_text"></span><br/>
|
||||
<span id="about_version_text"></span><br/>
|
||||
<span class="i18n">{{aboutTip}}</span><br/>
|
||||
<span class="i18n">{{projectAddress}}: </span>
|
||||
<span class="url-link">https://github.com/fankes/YukiHookAPI</span><br/>
|
||||
<div style="margin-top: 10px"></div>
|
||||
<span class="i18n" style="font-size: 10pt;opacity: 0.6;line-height: 18px">{{noticeTip}}</span>
|
||||
</div>
|
||||
<div class="mdui-dialog-actions">
|
||||
<button class="mdui-btn mdui-ripple i18n" mdui-dialog-close onclick="page.checkForUpdates()">{{checkUpdate}}</button>
|
||||
<button class="mdui-btn mdui-ripple i18n" mdui-dialog-close>{{close}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdui-dialog" id="open_source_dialog" style="max-width: 500px">
|
||||
<div class="mdui-dialog-title i18n">{{openSource}}</div>
|
||||
<div class="mdui-dialog-content" style="line-height: 35px">
|
||||
<span>Electron</span>  <span class="license-text">MIT</span><br/>
|
||||
<span class="url-link">https://github.com/electron</span><br/>
|
||||
<span>Node.js</span>  <span class="license-text">MIT</span><br/>
|
||||
<span class="url-link">https://github.com/nodejs</span><br/>
|
||||
<span>Node.js: fs-extra</span>  <span class="license-text">MIT</span><br/>
|
||||
<span class="url-link">https://github.com/jprichardson/node-fs-extra</span><br/>
|
||||
<span>DecompressZip</span>  <span class="license-text">MIT</span><br/>
|
||||
<span class="url-link">https://github.com/NASGO/decompress-zip</span><br/>
|
||||
<span>DAY.JS</span>  <span class="license-text">MIT</span><br/>
|
||||
<span class="url-link">https://github.com/iamkun/dayjs</span><br/>
|
||||
<span>DrawableToolbox</span>  <span class="license-text">Apache-2.0</span><br/>
|
||||
<span class="url-link">https://github.com/duanhong169/DrawableToolbox</span>
|
||||
</div>
|
||||
<div class="mdui-dialog-actions">
|
||||
<button class="mdui-btn mdui-ripple i18n" mdui-dialog-close>{{close}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="render.js"></script>
|
||||
</html>
|
10881
src/content/js/jquery.js
vendored
Executable file
2
src/content/js/jquery.min.js
vendored
Executable file
5976
src/content/js/mdui.esm.js
Normal file
1
src/content/js/mdui.esm.js.map
Normal file
6474
src/content/js/mdui.js
Normal file
1
src/content/js/mdui.js.map
Normal file
7
src/content/js/mdui.min.js
vendored
Normal file
1
src/content/js/mdui.min.js.map
Normal file
79
src/content/render.css
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/9.
|
||||
*/
|
||||
|
||||
body {
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.mdui-dialog {
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.mdui-textfield-label {
|
||||
white-space: nowrap
|
||||
}
|
||||
|
||||
.mdui-select {
|
||||
margin-left: 55px;
|
||||
width: 88%;
|
||||
}
|
||||
|
||||
.mdui-round-btn {
|
||||
border-radius: 50px;
|
||||
font-size: 11pt;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.red-circle-btn {
|
||||
background: #ff5252;
|
||||
border-style: hidden;
|
||||
border-radius: 50px;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.url-link {
|
||||
color: #FF9800;
|
||||
cursor: hand;
|
||||
}
|
||||
|
||||
.license-text {
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: #2d2d2d;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
body {
|
||||
background-color: #fcfcfc;
|
||||
}
|
||||
}
|
800
src/content/render.js
Normal file
@@ -0,0 +1,800 @@
|
||||
// noinspection JSUnusedGlobalSymbols, JSUnusedLocalSymbols
|
||||
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/8.
|
||||
*/
|
||||
|
||||
const {ipcRenderer, ipcMain} = require('electron');
|
||||
const {locale} = require('../libs/locale');
|
||||
|
||||
/** 防止 jQuery 与 Electron 冲突 */
|
||||
window.$ = window.jQuery = require('./js/jquery.min.js');
|
||||
|
||||
/**
|
||||
* 对话框集合命名空间
|
||||
*/
|
||||
const dialogs = {
|
||||
/** 添加模块作用域对话框 */
|
||||
moduleScope: new mdui.Dialog('#module_scope_dialog'),
|
||||
/** 搜索项目依赖对话框 */
|
||||
searchDepend: new mdui.Dialog('#search_depend_dialog', {modal: true, closeOnEsc: false}),
|
||||
/** 配置项目依赖对话框 */
|
||||
configPackage: new mdui.Dialog('#config_package_dialog', {modal: true, closeOnEsc: false}),
|
||||
/** 创建进行中对话框 */
|
||||
packagingProgress: new mdui.Dialog('#packaging_progress_dialog', {modal: true, closeOnEsc: false})
|
||||
}
|
||||
|
||||
/** 当前获取到的在线依赖内容 */
|
||||
const dependenciesConfigs = {
|
||||
gradlePapers: [],
|
||||
androidGradlePluginVersions: [],
|
||||
kotlinVersions: [],
|
||||
yukiHookApiVersions: []
|
||||
};
|
||||
|
||||
/** 当前项目的配置内容 */
|
||||
const projectConfigs = {
|
||||
basicConfig: {
|
||||
projectName: '',
|
||||
packageName: '',
|
||||
appName: '',
|
||||
moduleDescription: '',
|
||||
appMinApi: 0,
|
||||
appTargetApi: 0,
|
||||
xposedMinApi: 0,
|
||||
moduleCompoment: 0,
|
||||
targetXposedPlatform: 0,
|
||||
newXSharePrefs: 0,
|
||||
moduleScopes: []
|
||||
},
|
||||
yukiHookApiConfig: {
|
||||
entryClassName: '',
|
||||
debugTagName: '',
|
||||
supportResourcesHook: 0,
|
||||
enableDebug: 0,
|
||||
enablePrintLogcat: 0,
|
||||
enableYPrefsCache: 0,
|
||||
enableResourcesCache: 0,
|
||||
enableModuleStatus: 0,
|
||||
enableYChannel: 0,
|
||||
enableMemberCache: 0
|
||||
},
|
||||
projectDependencies: {
|
||||
gradlePaper: '',
|
||||
androidGradlePluginVersion: '',
|
||||
kotlinVersion: '',
|
||||
kotlinKspVersion: '',
|
||||
yukiHookApiVersion: ''
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 字符串工具命名空间
|
||||
*/
|
||||
const valUtils = {
|
||||
/**
|
||||
* 字符串是否为空
|
||||
* @param string 字符串
|
||||
* @return boolean
|
||||
*/
|
||||
isEmpty: (string) => {
|
||||
if (string === '') return true;
|
||||
return new RegExp('^ +$').test(string);
|
||||
},
|
||||
/**
|
||||
* 字符串是否包含字母和数字以外的内容
|
||||
* @param string 字符串
|
||||
* @return boolean
|
||||
*/
|
||||
hasSpecialChar: (string) => {
|
||||
return !valUtils.isEmpty(string) && !(/^[a-zA-Z_]\w*$/.test(string));
|
||||
},
|
||||
/**
|
||||
* 字符串是否包含非法包名
|
||||
* @param string 字符串
|
||||
* @param isAllowAndroid 是否允许 "android" 包名 - 默认否
|
||||
* @return boolean
|
||||
*/
|
||||
hasIncorrectPkgName: (string, isAllowAndroid = false) => {
|
||||
return !((string.indexOf('.') >= 0 &&
|
||||
string.indexOf('..') < 0 &&
|
||||
!string.startsWith('.') &&
|
||||
!string.endsWith('.')) || (string === 'android' && isAllowAndroid));
|
||||
},
|
||||
/**
|
||||
* 转换为整型
|
||||
* @return number
|
||||
*/
|
||||
integerOf: (value) => {
|
||||
return Number.parseInt(value);
|
||||
},
|
||||
/**
|
||||
* 字符串是否以数字开头
|
||||
* @param string 字符串
|
||||
* @return boolean
|
||||
*/
|
||||
startsWithNumber: (string) => {
|
||||
return string.startsWith('0') || string.startsWith('1') ||
|
||||
string.startsWith('2') || string.startsWith('3') ||
|
||||
string.startsWith('4') || string.startsWith('5') ||
|
||||
string.startsWith('6') || string.startsWith('7') ||
|
||||
string.startsWith('8') || string.startsWith('9');
|
||||
}
|
||||
};
|
||||
|
||||
/** 开始装载 */
|
||||
window.onload = () => {
|
||||
$('#module_scope_text').bind('input propertychange', () => {
|
||||
monitor.onModuleScopeTextChange();
|
||||
});
|
||||
$('#module_scope_select').on('change', () => {
|
||||
monitor.onModuleScopeSelectChange();
|
||||
});
|
||||
$('#target_xposed_platform_select').on('change', () => {
|
||||
monitor.onTargetXposedPlatformSelect();
|
||||
});
|
||||
$('#module_scope_dialog').on('closed.mdui.dialog', () => {
|
||||
moduleScope.clearAndCloseDialog();
|
||||
});
|
||||
$('.url-link').each((_, element) => {
|
||||
$(element).on('click', () => {
|
||||
page.openBrowser(element.innerText);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 页面监听器命名空间
|
||||
*/
|
||||
const monitor = {
|
||||
/** 文本改变监听 */
|
||||
onModuleScopeTextChange: () => {
|
||||
const value = $('#module_scope_text').val();
|
||||
if (value === 'android') $('#module_scope_select').val(1);
|
||||
else if (value === 'com.android.systemui') $('#module_scope_select').val(2);
|
||||
else $('#module_scope_select').val(0);
|
||||
},
|
||||
/** 选项改变监听 */
|
||||
onModuleScopeSelectChange: () => {
|
||||
const moduleScopeText = $('#module_scope_text');
|
||||
switch (valUtils.integerOf($('#module_scope_select option:selected').val())) {
|
||||
case 0:
|
||||
moduleScopeText.val('');
|
||||
break;
|
||||
|
||||
case 1:
|
||||
moduleScopeText.val('android');
|
||||
break;
|
||||
|
||||
case 2:
|
||||
moduleScopeText.val('com.android.systemui');
|
||||
break;
|
||||
}
|
||||
},
|
||||
/** 选项改变监听 */
|
||||
onTargetXposedPlatformSelect: () => {
|
||||
const newXSharePrefsDiv = $('#new_xshare_prefs_div');
|
||||
const moduleScopeDiv = $('#module_scope_div');
|
||||
switch (valUtils.integerOf($('#target_xposed_platform_select option:selected').val())) {
|
||||
case 3:
|
||||
case 4:
|
||||
$('#scope_list').empty();
|
||||
$('#new_xshare_prefs_select').val(0);
|
||||
newXSharePrefsDiv.hide();
|
||||
moduleScopeDiv.hide();
|
||||
break;
|
||||
|
||||
default:
|
||||
newXSharePrefsDiv.show();
|
||||
moduleScopeDiv.show();
|
||||
break;
|
||||
}
|
||||
},
|
||||
/** 刷新回调全部监听 */
|
||||
refresh: () => {
|
||||
monitor.onModuleScopeTextChange();
|
||||
monitor.onModuleScopeSelectChange();
|
||||
monitor.onTargetXposedPlatformSelect();
|
||||
mdui.updateTextFields();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 控制模块作用域命名空间
|
||||
*/
|
||||
const moduleScope = {
|
||||
/**
|
||||
* 获取当前已添加的模块定义域数组
|
||||
* @return Array
|
||||
*/
|
||||
moduleScopesData: () => {
|
||||
const scopes = [];
|
||||
$('#scope_list div').each((p, dom) => {
|
||||
scopes.push($(dom).text());
|
||||
});
|
||||
return scopes;
|
||||
},
|
||||
/** 显示添加模块作用域对话框 */
|
||||
showAddDialog: () => {
|
||||
dialogs.moduleScope.open();
|
||||
},
|
||||
/** 添加模块作用域 - 使用当前对话框文本 */
|
||||
saveData: () => {
|
||||
const moduleScopeText = $('#module_scope_text').val();
|
||||
if (valUtils.isEmpty(moduleScopeText)) page.snack(locale.i18n.enterPkgNameOrSelectFromListTip);
|
||||
else if (valUtils.hasIncorrectPkgName(moduleScopeText, true)) page.snack(locale.i18n.invalidEnterPkgNameTip);
|
||||
else if (moduleScope.moduleScopesData().includes(moduleScopeText)) page.snack(locale.i18n.existEnterPkgNameTip);
|
||||
else {
|
||||
moduleScope.addData(moduleScopeText);
|
||||
dialogs.moduleScope.close();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 添加模块作用域
|
||||
* @param packageName 包名
|
||||
*/
|
||||
addData: (packageName) => {
|
||||
const listId = Date.now();
|
||||
const scopeList = $('#scope_list')
|
||||
scopeList.append('<label class="mdui-list-item mdui-ripple" id="' + listId + '" style="padding-right: 5px">' +
|
||||
'<div class="mdui-list-item-content">' + packageName + '</div>' +
|
||||
'<button class="red-circle-btn mdui-ripple" onclick="moduleScope.removeData(\'' + packageName + '\',\''
|
||||
+ listId + '\')">—</button>' +
|
||||
'</label>');
|
||||
scopeList.scrollTop(scopeList.prop("scrollHeight"));
|
||||
},
|
||||
/**
|
||||
* 移除模块作用域
|
||||
* @param name 名称
|
||||
* @param id 列表 Id
|
||||
*/
|
||||
removeData: (name, id) => {
|
||||
mdui.confirm(locale.format(locale.i18n.areYouSureRemoveItemTip, name), locale.i18n.notice, () => {
|
||||
$('#' + id).remove();
|
||||
}, () => null, {confirmText: locale.i18n.ok, cancelText: locale.i18n.cancel});
|
||||
},
|
||||
/**
|
||||
* 刷新当前作用域列表布局
|
||||
* @param data 作用域数组
|
||||
*/
|
||||
refresh: (data) => {
|
||||
$('#scope_list').html('');
|
||||
if (data.length > 0) data.forEach((value) => {
|
||||
moduleScope.addData(value);
|
||||
});
|
||||
},
|
||||
/** 恢复默认并关闭添加模块作用域对话框 */
|
||||
clearAndCloseDialog: () => {
|
||||
$('#module_scope_select').val(0);
|
||||
$('#module_scope_text').val('');
|
||||
dialogs.moduleScope.close();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 当前配置表单命名空间
|
||||
*/
|
||||
const configForm = {
|
||||
projectNameText: () => $('#project_name_text').val(),
|
||||
packageNameText: () => $('#package_name_text').val(),
|
||||
appNameText: () => $('#app_name_text').val(),
|
||||
moduleDescriptionText: () => $('#module_description_text').val(),
|
||||
appMinApiText: () => $('#app_min_api_text').val(),
|
||||
appTargetApiText: () => $('#app_target_api_text').val(),
|
||||
xposedMinApiText: () => $('#xposed_min_api_text').val(),
|
||||
entryClassNameText: () => $('#entry_class_name_text').val(),
|
||||
debugTagNameText: () => $('#debug_tag_name_text').val(),
|
||||
compomentSelect: () => valUtils.integerOf($('#compoment_select option:selected').val()),
|
||||
targetXposedPlatformSelect: () => valUtils.integerOf($('#target_xposed_platform_select option:selected').val()),
|
||||
newXSharePrefsSelect: () => valUtils.integerOf($('#new_xshare_prefs_select option:selected').val()),
|
||||
supportResourcesHookSelect: () => valUtils.integerOf($('#support_resources_hook_select option:selected').val()),
|
||||
enableDebugSelect: () => valUtils.integerOf($('#enable_debug_select option:selected').val()),
|
||||
enablePrintLogcatSelect: () => valUtils.integerOf($('#enable_print_logcat_select option:selected').val()),
|
||||
enableYPrefsCacheSelect: () => valUtils.integerOf($('#enable_yprefs_cache_select option:selected').val()),
|
||||
enableResourcesCacheSelect: () => valUtils.integerOf($('#enable_resources_cache_select option:selected').val()),
|
||||
enableModuleStatusSelect: () => valUtils.integerOf($('#enable_module_status_select option:selected').val()),
|
||||
enableYChannelSelect: () => valUtils.integerOf($('#enable_ychannel_select option:selected').val()),
|
||||
enableMemberCacheSelect: () => valUtils.integerOf($('#enable_member_cache_select option:selected').val())
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建项目命名空间
|
||||
*/
|
||||
const build = {
|
||||
/** 标识是否正在配置创建项目功能 - 不能重复执行 */
|
||||
isLocked: false,
|
||||
/**
|
||||
* 判断是否正在创建项目 - 自动弹出消息提示
|
||||
* @return boolean
|
||||
*/
|
||||
isLockAndMsg: () => {
|
||||
if (build.isLocked) page.snack(locale.i18n.taskIsRunningTip);
|
||||
return build.isLocked;
|
||||
},
|
||||
/** 创建配置表单 */
|
||||
create: () => {
|
||||
projectConfigs.basicConfig.projectName = configForm.projectNameText();
|
||||
projectConfigs.basicConfig.packageName = configForm.packageNameText();
|
||||
projectConfigs.basicConfig.appName = configForm.appNameText();
|
||||
projectConfigs.basicConfig.moduleDescription = configForm.moduleDescriptionText();
|
||||
projectConfigs.basicConfig.appMinApi = valUtils.integerOf(configForm.appMinApiText());
|
||||
projectConfigs.basicConfig.appTargetApi = valUtils.integerOf(configForm.appTargetApiText());
|
||||
projectConfigs.basicConfig.xposedMinApi = valUtils.integerOf(configForm.xposedMinApiText());
|
||||
projectConfigs.basicConfig.moduleCompoment = configForm.compomentSelect();
|
||||
projectConfigs.basicConfig.targetXposedPlatform = configForm.targetXposedPlatformSelect();
|
||||
projectConfigs.basicConfig.newXSharePrefs = configForm.newXSharePrefsSelect();
|
||||
projectConfigs.basicConfig.moduleScopes = moduleScope.moduleScopesData();
|
||||
projectConfigs.yukiHookApiConfig.entryClassName = configForm.entryClassNameText();
|
||||
projectConfigs.yukiHookApiConfig.debugTagName = configForm.debugTagNameText();
|
||||
projectConfigs.yukiHookApiConfig.supportResourcesHook = configForm.supportResourcesHookSelect();
|
||||
projectConfigs.yukiHookApiConfig.enableDebug = configForm.enableDebugSelect();
|
||||
projectConfigs.yukiHookApiConfig.enablePrintLogcat = configForm.enablePrintLogcatSelect();
|
||||
projectConfigs.yukiHookApiConfig.enableYPrefsCache = configForm.enableYPrefsCacheSelect();
|
||||
projectConfigs.yukiHookApiConfig.enableResourcesCache = configForm.enableResourcesCacheSelect();
|
||||
projectConfigs.yukiHookApiConfig.enableModuleStatus = configForm.enableModuleStatusSelect();
|
||||
projectConfigs.yukiHookApiConfig.enableYChannel = configForm.enableYChannelSelect();
|
||||
projectConfigs.yukiHookApiConfig.enableMemberCache = configForm.enableMemberCacheSelect();
|
||||
projectConfigs.projectDependencies = {
|
||||
gradlePaper: '',
|
||||
androidGradlePluginVersion: '',
|
||||
kotlinVersion: '',
|
||||
kotlinKspVersion: '',
|
||||
yukiHookApiVersion: ''
|
||||
};
|
||||
},
|
||||
/** 检查并开始创建项目 */
|
||||
checking: () => {
|
||||
if (build.isLockAndMsg()) return;
|
||||
if (valUtils.isEmpty(configForm.projectNameText())) page.snack(locale.i18n.enterProjectNameTip);
|
||||
else if (valUtils.hasSpecialChar(configForm.projectNameText())) page.snack(locale.i18n.projectNameRuleTip);
|
||||
else if (valUtils.isEmpty(configForm.packageNameText())) page.snack(locale.i18n.enterModulePackageNameTip);
|
||||
else if (valUtils.hasIncorrectPkgName(configForm.packageNameText())) page.snack(locale.i18n.invalidModulePackageNameTip);
|
||||
else if (valUtils.isEmpty(configForm.appNameText())) page.snack(locale.i18n.enterModuleAppNameTip);
|
||||
else if (valUtils.isEmpty(configForm.moduleDescriptionText())) page.snack(locale.i18n.enterModuleDescriptionTip);
|
||||
else if (valUtils.isEmpty(configForm.appMinApiText())) page.snack(locale.i18n.enterAppMinApiVersionTip);
|
||||
else if (configForm.targetXposedPlatformSelect() === 2 && configForm.appMinApiText() < 27) page.snack(locale.i18n.lsposedSupportMinAppApiWarnTip);
|
||||
else if (configForm.appMinApiText() < 21) page.snack(locale.i18n.tooLowAppMinApiVersionWarnTip);
|
||||
else if (configForm.appMinApiText() > 33) page.snack(locale.i18n.tooHighAppMinApiVersionWarnTip);
|
||||
else if (valUtils.isEmpty(configForm.appTargetApiText())) page.snack(locale.i18n.enterAppTargetApiVersionTip);
|
||||
else if (configForm.appTargetApiText() < configForm.appMinApiText()) page.snack(locale.i18n.tooLowAppTargetApiVersionWarnTip);
|
||||
else if (configForm.appTargetApiText() > 33) page.snack(locale.i18n.maybeInvalidAppTargetApiVersionTip);
|
||||
else if (valUtils.isEmpty(configForm.xposedMinApiText())) page.snack(locale.i18n.enterXposedMinApiVersionTip);
|
||||
else if (configForm.xposedMinApiText() < 82) page.snack(locale.i18n.tooLowXposedMinApiVersionWarnTip);
|
||||
else if (configForm.xposedMinApiText() > 93) page.snack(locale.i18n.tooHighXposedMinApiVersionWarnTip);
|
||||
else if (valUtils.hasSpecialChar(configForm.entryClassNameText())) page.snack(locale.i18n.entryClassNameRuleTip);
|
||||
else if (configForm.targetXposedPlatformSelect() !== 3 && configForm.targetXposedPlatformSelect() !== 4
|
||||
&& moduleScope.moduleScopesData().length <= 0) page.snack(locale.i18n.moduleScopeRuleTip);
|
||||
else {
|
||||
build.create();
|
||||
projectDepends.search();
|
||||
}
|
||||
},
|
||||
/** 开始创建项目 */
|
||||
run: () => {
|
||||
projectConfigs.projectDependencies.gradlePaper = $('#gradle_version_select option:selected').text();
|
||||
projectConfigs.projectDependencies.androidGradlePluginVersion = $('#agp_version_select option:selected').text();
|
||||
const kotlinVersionSelect = $('#kotlin_version_select option:selected');
|
||||
projectConfigs.projectDependencies.kotlinVersion = kotlinVersionSelect.text();
|
||||
projectConfigs.projectDependencies.kotlinKspVersion = kotlinVersionSelect.val();
|
||||
projectConfigs.projectDependencies.yukiHookApiVersion = $('#yukihookapi_version_select option:selected').text();
|
||||
dialogs.configPackage.close();
|
||||
dialogs.packagingProgress.open();
|
||||
build.changeStatus(locale.i18n.waitingForBuildingTip);
|
||||
ipcRenderer.send('run-packaging-project', projectConfigs);
|
||||
},
|
||||
/**
|
||||
* 改变创建过程提示文本
|
||||
* @param msg 文本内容
|
||||
*/
|
||||
changeStatus: (msg) => {
|
||||
$('#packaging_progress_text').html(msg);
|
||||
},
|
||||
/**
|
||||
* 完成创建项目
|
||||
* @param msg 文本内容
|
||||
*/
|
||||
complete: (msg) => {
|
||||
dialogs.packagingProgress.close();
|
||||
mdui.confirm(msg, locale.i18n.buildComplete, () => {
|
||||
ipcRenderer.send('open-complete-project');
|
||||
build.unlockStatus();
|
||||
page.reload();
|
||||
}, () => {
|
||||
build.unlockStatus();
|
||||
page.reload();
|
||||
}, {confirmText: locale.i18n.openProject, cancelText: locale.i18n.done, modal: true, closeOnEsc: false});
|
||||
},
|
||||
/**
|
||||
* 创建项目失败
|
||||
* @param msg 文本内容
|
||||
*/
|
||||
failure: (msg) => {
|
||||
dialogs.packagingProgress.close();
|
||||
build.unlockStatus();
|
||||
mdui.alert(msg, locale.i18n.notice, () => null, {confirmText: locale.i18n.ok});
|
||||
},
|
||||
/** 取消创建项目任务 */
|
||||
cancel: () => {
|
||||
dialogs.packagingProgress.close();
|
||||
build.unlockStatus();
|
||||
page.snack(locale.i18n.operationCancelledTip);
|
||||
},
|
||||
/** 锁定创建项目状态 */
|
||||
lockStatus: () => {
|
||||
build.isLocked = true;
|
||||
},
|
||||
/** 解锁创建项目状态 */
|
||||
unlockStatus: () => {
|
||||
build.isLocked = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 依赖查找功能命名空间
|
||||
*/
|
||||
const projectDepends = {
|
||||
/** 依赖 API 获取地址 */
|
||||
urls: {
|
||||
gradlePaper: 'https://services.gradle.org/distributions',
|
||||
androidGradlePlugin: 'https://developer.android.google.cn/studio/releases/gradle-plugin.html',
|
||||
kotlin: 'https://api.github.com/repos/JetBrains/kotlin/releases',
|
||||
kotlinKsp: 'https://api.github.com/repos/google/ksp/releases',
|
||||
yukiHookApi: 'https://s01.oss.sonatype.org/content/repositories/releases/com/highcapable/yukihookapi/api'
|
||||
},
|
||||
/** 搜索项目依赖 */
|
||||
search() {
|
||||
build.lockStatus();
|
||||
dialogs.searchDepend.open();
|
||||
projectDepends.findGradlePaper();
|
||||
},
|
||||
/** 依赖装载完成 */
|
||||
loaded() {
|
||||
dialogs.searchDepend.close();
|
||||
const gradleVersionSelect = $('#gradle_version_select');
|
||||
gradleVersionSelect.html('');
|
||||
dependenciesConfigs.gradlePapers.forEach((value) => {
|
||||
gradleVersionSelect.append('<option value="' + value + '">' + value + '</option>');
|
||||
});
|
||||
const agpVersionSelect = $('#agp_version_select');
|
||||
agpVersionSelect.html('');
|
||||
dependenciesConfigs.androidGradlePluginVersions.forEach((value) => {
|
||||
agpVersionSelect.append('<option value="' + value + '">' + value + '</option>');
|
||||
});
|
||||
const kotlinVersionSelect = $('#kotlin_version_select');
|
||||
kotlinVersionSelect.html('');
|
||||
dependenciesConfigs.kotlinVersions.forEach((value) => {
|
||||
kotlinVersionSelect.append('<option value="' + value.ksp + '">' + value.main + '</option>');
|
||||
});
|
||||
const yukiHookApiVersionSelect = $('#yukihookapi_version_select');
|
||||
yukiHookApiVersionSelect.html('');
|
||||
dependenciesConfigs.yukiHookApiVersions.forEach((value) => {
|
||||
yukiHookApiVersionSelect.append('<option value="' + value + '">' + value + '</option>');
|
||||
});
|
||||
dialogs.configPackage.open();
|
||||
},
|
||||
/**
|
||||
* 回调检索失败
|
||||
* @param name 名称
|
||||
* @param isNetFail 是否为网络错误
|
||||
*/
|
||||
failure: (name, isNetFail = true) => {
|
||||
dialogs.searchDepend.close();
|
||||
build.unlockStatus();
|
||||
mdui.alert(isNetFail ? locale.i18n.networkErrorTip : locale.i18n.ruleCheckFailTip,
|
||||
locale.format(locale.i18n.findDependContentFail, name), () => null, {confirmText: locale.i18n.ok});
|
||||
},
|
||||
/** 获取 Gradle 构建器 */
|
||||
findGradlePaper: () => {
|
||||
httpClient.requestDepends('Gradle', projectDepends.urls.gradlePaper, (body) => {
|
||||
dependenciesConfigs.gradlePapers = [];
|
||||
let index = 0;
|
||||
$(body).find('.items .name').each((_, element) => {
|
||||
const isValied = (element.innerText.endsWith('bin.zip') || element.innerText.endsWith('all.zip'))
|
||||
&& element.innerText.indexOf('-rc-') < 0 && element.innerText.indexOf('mile') < 0;
|
||||
if (isValied) index++;
|
||||
if (index <= 20 && isValied) dependenciesConfigs.gradlePapers.push(element.innerText.trim());
|
||||
});
|
||||
if (dependenciesConfigs.gradlePapers.length > 0)
|
||||
projectDepends.findAgpVersion();
|
||||
else projectDepends.failure('Gradle', false);
|
||||
});
|
||||
},
|
||||
/** 获取 AGP 版本 */
|
||||
findAgpVersion: () => {
|
||||
httpClient.requestDepends('Android Gradle Plugin', projectDepends.urls.androidGradlePlugin, (body) => {
|
||||
dependenciesConfigs.androidGradlePluginVersions = [];
|
||||
$(body).find('h2').each((_, element) => {
|
||||
if (valUtils.startsWithNumber(element.innerText))
|
||||
if (element.innerText.indexOf('(') > 0)
|
||||
dependenciesConfigs.androidGradlePluginVersions.push(element.innerText.split('(')[0].trim());
|
||||
else dependenciesConfigs.androidGradlePluginVersions.push(element.innerText.split('(')[0].trim());
|
||||
});
|
||||
$(body).find('.android-updates-box b').each((_, element) => {
|
||||
if (valUtils.startsWithNumber(element.innerText))
|
||||
if (element.innerText.indexOf('(') > 0)
|
||||
dependenciesConfigs.androidGradlePluginVersions.push(element.innerText.split('(')[0].trim());
|
||||
else dependenciesConfigs.androidGradlePluginVersions.push(element.innerText.split('(')[0].trim());
|
||||
});
|
||||
dependenciesConfigs.androidGradlePluginVersions.sort((a, b) => {
|
||||
return b.localeCompare(a);
|
||||
});
|
||||
if (dependenciesConfigs.androidGradlePluginVersions.length > 0)
|
||||
projectDepends.findKotlinVersion();
|
||||
else projectDepends.failure('Android Gradle Plugin', false);
|
||||
});
|
||||
},
|
||||
/** 获取 Kotlin 版本 */
|
||||
findKotlinVersion: () => {
|
||||
httpClient.requestDepends('Kotlin', projectDepends.urls.kotlin, (body) => {
|
||||
dependenciesConfigs.kotlinVersions = [];
|
||||
body.forEach((value) => {
|
||||
const tagName = value['tag_name'];
|
||||
if (tagName.indexOf('-') < 0)
|
||||
dependenciesConfigs.kotlinVersions.push({main: tagName.replace('v', ''), ksp: ''});
|
||||
});
|
||||
if (dependenciesConfigs.kotlinVersions.length > 0)
|
||||
projectDepends.findKotlinKspVersion();
|
||||
else projectDepends.failure('Kotlin', false);
|
||||
});
|
||||
},
|
||||
/** 获取 Kotlin-Ksp 版本 */
|
||||
findKotlinKspVersion: () => {
|
||||
httpClient.requestDepends('Kotlin-Ksp', projectDepends.urls.kotlinKsp, (body) => {
|
||||
body.forEach((value) => {
|
||||
const tagName = value['tag_name'];
|
||||
if (tagName.toLowerCase().indexOf('rc') < 0 && tagName.toLowerCase().indexOf('beta') < 0)
|
||||
dependenciesConfigs.kotlinVersions.forEach((each) => {
|
||||
if (tagName.startsWith(each.main)) each.ksp = tagName;
|
||||
});
|
||||
});
|
||||
dependenciesConfigs.kotlinVersions = dependenciesConfigs.kotlinVersions.filter((value) => {
|
||||
return !valUtils.isEmpty(value.ksp);
|
||||
});
|
||||
if (dependenciesConfigs.kotlinVersions.length > 0)
|
||||
projectDepends.findYukiHookApiVersion();
|
||||
else projectDepends.failure('Kotlin-Ksp', false);
|
||||
});
|
||||
},
|
||||
/** 获取 YukiHookAPI 版本 */
|
||||
findYukiHookApiVersion: () => {
|
||||
httpClient.requestDepends('YukiHookAPI', projectDepends.urls.yukiHookApi, (body) => {
|
||||
dependenciesConfigs.yukiHookApiVersions = [];
|
||||
$(body).find('td').each((_, element) => {
|
||||
if (element.innerText.endsWith('/') && element.innerText.indexOf('fix') < 0)
|
||||
dependenciesConfigs.yukiHookApiVersions.push(element.innerText.replace('/', '').trim());
|
||||
});
|
||||
if (dependenciesConfigs.yukiHookApiVersions.length > 0) {
|
||||
dependenciesConfigs.yukiHookApiVersions.sort((a, b) => {
|
||||
return b.localeCompare(a);
|
||||
});
|
||||
const latestVersion = dependenciesConfigs.yukiHookApiVersions[0];
|
||||
dependenciesConfigs.yukiHookApiVersions = [];
|
||||
dependenciesConfigs.yukiHookApiVersions.push(latestVersion);
|
||||
projectDepends.loaded();
|
||||
} else projectDepends.failure('YukiHookAPI', false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 配置模板命名空间
|
||||
*/
|
||||
const configTemplate = {
|
||||
/**
|
||||
* 从模板加载并覆盖当前配置
|
||||
* @param configs 模板
|
||||
*/
|
||||
load: (configs) => {
|
||||
if (build.isLockAndMsg()) return;
|
||||
const parse = JSON.parse(decodeURI(configs));
|
||||
const data = parse.value;
|
||||
mdui.confirm(locale.format(locale.i18n.doYouWantLoadConfigTemplateTip, parse.name), locale.i18n.notice, () => {
|
||||
$('#project_name_text').val(data.basicConfig.projectName);
|
||||
$('#package_name_text').val(data.basicConfig.packageName);
|
||||
$('#app_name_text').val(data.basicConfig.appName);
|
||||
$('#module_description_text').val(data.basicConfig.moduleDescription);
|
||||
$('#app_min_api_text').val(data.basicConfig.appMinApi);
|
||||
$('#app_target_api_text').val(data.basicConfig.appTargetApi);
|
||||
$('#xposed_min_api_text').val(data.basicConfig.xposedMinApi);
|
||||
$('#entry_class_name_text').val(data.yukiHookApiConfig.entryClassName);
|
||||
$('#debug_tag_name_text').val(data.yukiHookApiConfig.debugTagName);
|
||||
$('#compoment_select').val(data.basicConfig.moduleCompoment);
|
||||
$('#target_xposed_platform_select').val(data.basicConfig.targetXposedPlatform);
|
||||
$('#new_xshare_prefs_select').val(data.basicConfig.newXSharePrefs);
|
||||
$('#support_resources_hook_select').val(data.yukiHookApiConfig.supportResourcesHook);
|
||||
$('#enable_debug_select').val(data.yukiHookApiConfig.enableDebug);
|
||||
$('#enable_print_logcat_select').val(data.yukiHookApiConfig.enablePrintLogcat);
|
||||
$('#enable_yprefs_cache_select').val(data.yukiHookApiConfig.enableYPrefsCache);
|
||||
$('#enable_resources_cache_select').val(data.yukiHookApiConfig.enableResourcesCache);
|
||||
$('#enable_module_status_select').val(data.yukiHookApiConfig.enableModuleStatus);
|
||||
$('#enable_ychannel_select').val(data.yukiHookApiConfig.enableYChannel);
|
||||
$('#enable_member_cache_select').val(data.yukiHookApiConfig.enableMemberCache);
|
||||
monitor.refresh();
|
||||
moduleScope.refresh(data.basicConfig.moduleScopes);
|
||||
page.snack(locale.format(locale.i18n.configTemplateLoaded, parse.name));
|
||||
}, () => null, {confirmText: locale.i18n.ok, cancelText: locale.i18n.cancel});
|
||||
},
|
||||
/** 保存当前配置到模板 */
|
||||
createNew: () => {
|
||||
if (build.isLockAndMsg()) return;
|
||||
mdui.prompt(locale.i18n.enterTemplateNameTip, locale.i18n.newTemplateByCurrentConfig, (value, dialog) => {
|
||||
if (valUtils.isEmpty(value)) page.snack(locale.i18n.enterTemplateNameTip);
|
||||
else {
|
||||
build.create();
|
||||
ipcRenderer.send('save-config-template', {name: value, value: projectConfigs});
|
||||
dialog.close();
|
||||
page.snack(locale.format(locale.i18n.configTemplateSaved, value));
|
||||
}
|
||||
}, () => null, {confirmText: locale.i18n.ok, cancelText: locale.i18n.cancel, closeOnConfirm: false});
|
||||
},
|
||||
/** 清空全部模板 */
|
||||
clearAll: () => {
|
||||
if (build.isLockAndMsg()) return;
|
||||
mdui.confirm(locale.i18n.areYouSureClearAllTemplateTip, locale.i18n.notice, () => {
|
||||
ipcRenderer.send('clear-all-config-template');
|
||||
page.snack(locale.i18n.configTemplateCleared);
|
||||
}, () => null, {confirmText: locale.i18n.ok, cancelText: locale.i18n.cancel});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 当前页面命名空间
|
||||
*/
|
||||
const page = {
|
||||
/** 当前应用程序版本 */
|
||||
appVersion: '',
|
||||
/**
|
||||
* 初始化页面
|
||||
*
|
||||
* 启动时调用 - 不完成初始化页面将显示为空白
|
||||
* @param localeName 语言区域名称
|
||||
* @param appVersion 应用程序版本
|
||||
*/
|
||||
init: (localeName, appVersion) => {
|
||||
page.appVersion = appVersion;
|
||||
locale.initLocale(localeName);
|
||||
$('title').text(locale.i18n.windowTitle);
|
||||
$('.i18n').each((_, element) => {
|
||||
const placeholder = $(element).attr('placeholder');
|
||||
const isUsePlaceholder = placeholder !== undefined;
|
||||
const innerHtml = isUsePlaceholder ? placeholder : element.innerHTML;
|
||||
if (innerHtml.indexOf('{{') < 0 || innerHtml.indexOf('}}') < 0) return;
|
||||
const i18nText = locale.i18n[innerHtml.split('{{')[1].split('}}')[0].trim()];
|
||||
if (i18nText !== undefined)
|
||||
if (isUsePlaceholder)
|
||||
$(element).attr('placeholder', innerHtml.replace(/\{\{(.*)}}/, i18nText));
|
||||
else element.innerHTML = innerHtml.replace(/\{\{(.*)}}/, i18nText);
|
||||
});
|
||||
$('#root_div').show();
|
||||
page.checkForUpdates(false);
|
||||
},
|
||||
/**
|
||||
* 弹出提示
|
||||
* @param message 消息
|
||||
*/
|
||||
snack: (message) => {
|
||||
mdui.snackbar({message: message});
|
||||
},
|
||||
/**
|
||||
* 打开系统默认浏览器
|
||||
* @param url 地址
|
||||
*/
|
||||
openBrowser: (url) => {
|
||||
ipcRenderer.send('open-system-browser', url);
|
||||
},
|
||||
/**
|
||||
* 显示关于
|
||||
* @param name 名称
|
||||
* @param version 版本号
|
||||
*/
|
||||
showAbout: (name, version) => {
|
||||
if (build.isLockAndMsg()) return;
|
||||
$('#about_name_text').html(name);
|
||||
$('#about_version_text').html(locale.i18n.version + ': ' + version);
|
||||
new mdui.Dialog('#about_dialog').open();
|
||||
},
|
||||
/** 显示开源相关 */
|
||||
showOpenSource: () => {
|
||||
if (build.isLockAndMsg()) return;
|
||||
new mdui.Dialog('#open_source_dialog').open();
|
||||
},
|
||||
/**
|
||||
* 检查更新
|
||||
* @param isShowProcess 是否显示正在检查更新的提示
|
||||
*/
|
||||
checkForUpdates: (isShowProcess = true) => {
|
||||
if (build.isLockAndMsg()) return;
|
||||
if (isShowProcess) page.snack(locale.i18n.checkUpdateTip);
|
||||
const repoAuthor = 'fankes';
|
||||
const repoName = 'YukiHookAPI-ProjectBuilder';
|
||||
httpClient.requestGet('https://api.github.com/repos/' + repoAuthor + '/' + repoName + '/releases/latest', (body) => {
|
||||
const newVersion = body['name'] ?? '';
|
||||
const updateLogs = body['body']?.replace(/\n/g, "<br/>") ?? '';
|
||||
const updateUrl = body['html_url'] ?? '';
|
||||
if (newVersion !== page.appVersion)
|
||||
mdui.confirm(locale.i18n.version + ': ' + newVersion + '<br/><br/>' +
|
||||
'<strong>' + locale.i18n.updateLogs + '</strong><br/><br/>' + updateLogs, locale.i18n.newVersionFound, () => {
|
||||
page.openBrowser(updateUrl);
|
||||
}, () => null, {
|
||||
confirmText: locale.i18n.updateNow,
|
||||
cancelText: locale.i18n.cancel,
|
||||
modal: true,
|
||||
closeOnEsc: false
|
||||
});
|
||||
else if (isShowProcess) page.snack(locale.i18n.upToDateTip);
|
||||
}, () => {
|
||||
if (isShowProcess) page.snack(locale.i18n.checkUpdateFailTip);
|
||||
});
|
||||
},
|
||||
/** 重置当前配置 */
|
||||
restore: () => {
|
||||
if (build.isLockAndMsg()) return;
|
||||
mdui.confirm(locale.i18n.areYouSureRestoreChangeTip, locale.i18n.notice, () => {
|
||||
page.reload();
|
||||
}, () => null, {confirmText: locale.i18n.ok, cancelText: locale.i18n.cancel});
|
||||
},
|
||||
/** 初始化页面 */
|
||||
reload: () => {
|
||||
ipcRenderer.send('reload-current-page');
|
||||
},
|
||||
/** 重启以生效更改 */
|
||||
relaunch: () => {
|
||||
if (build.isLockAndMsg()) return;
|
||||
mdui.confirm(locale.i18n.mustRestartTakeEffectTip, locale.i18n.notice, () => {
|
||||
ipcRenderer.send('relaunch-app');
|
||||
}, () => null, {confirmText: locale.i18n.ok, cancelText: locale.i18n.later});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 网络请求命名空间
|
||||
*/
|
||||
const httpClient = {
|
||||
/**
|
||||
* 请求获取每个依赖的发布页面内容
|
||||
* @param name 名称
|
||||
* @param url 地址
|
||||
* @param onSuccess 回调成功结果
|
||||
*/
|
||||
requestDepends: (name, url, onSuccess) => {
|
||||
httpClient.requestGet(url, onSuccess, () => {
|
||||
projectDepends.failure(name);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 请求页面内容 GET
|
||||
* @param url 地址
|
||||
* @param onSuccess 回调成功结果
|
||||
* @param onFaiure 回调失败结果
|
||||
*/
|
||||
requestGet: (url, onSuccess, onFaiure) => {
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: 'get',
|
||||
success: (body) => {
|
||||
onSuccess(body);
|
||||
},
|
||||
error: () => {
|
||||
onFaiure();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
BIN
src/icons/1024x1024.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
src/icons/128x128.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src/icons/16x16.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
src/icons/24x24.png
Normal file
After Width: | Height: | Size: 593 B |
BIN
src/icons/256x256.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
src/icons/32x32.png
Normal file
After Width: | Height: | Size: 835 B |
BIN
src/icons/48x48.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/icons/512x512.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
src/icons/64x64.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/icons/icon.icns
Normal file
BIN
src/icons/icon.ico
Normal file
After Width: | Height: | Size: 353 KiB |
63
src/libs/date-time.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/14.
|
||||
*/
|
||||
|
||||
const dayjs = require('dayjs');
|
||||
|
||||
/**
|
||||
* 日期时间命名空间
|
||||
*/
|
||||
const dateTime = {
|
||||
/**
|
||||
* 获取当前 CST 时间
|
||||
* @return string
|
||||
*/
|
||||
cstTime: () => {
|
||||
const today = dayjs(new Date());
|
||||
let week = '';
|
||||
switch (today.day()) {
|
||||
case 0:
|
||||
week = 'Sun';
|
||||
break;
|
||||
case 1:
|
||||
week = 'Mon';
|
||||
break;
|
||||
case 2:
|
||||
week = 'Tue';
|
||||
break;
|
||||
case 3:
|
||||
week = 'Wed';
|
||||
break;
|
||||
case 4:
|
||||
week = 'Thu';
|
||||
break;
|
||||
case 5:
|
||||
week = 'Fri';
|
||||
break;
|
||||
case 6:
|
||||
week = 'Sat';
|
||||
break;
|
||||
}
|
||||
return week + today.format(' MMM DD HH:mm:ss CST YYYY');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {dateTime};
|
206
src/libs/file-system.js
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/12.
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const fse = require('fs-extra');
|
||||
|
||||
/**
|
||||
* 文件系统命名空间
|
||||
*/
|
||||
const fileSystem = {
|
||||
/**
|
||||
* 文件分隔符
|
||||
* @return string
|
||||
*/
|
||||
separator: process.platform === 'win32' ? '\\' : '/',
|
||||
/**
|
||||
* 自动拼接字符串到路径
|
||||
* @param names 文件、目录名数组 - 可传入子数组
|
||||
* @return string
|
||||
*/
|
||||
path: (...names) => {
|
||||
if (names.length <= 0) return '';
|
||||
let path = '';
|
||||
names.forEach((value) => {
|
||||
if (value instanceof Array) value.forEach((value) => {
|
||||
path = path.concat(value, fileSystem.separator);
|
||||
}); else path = path.concat(value, fileSystem.separator);
|
||||
});
|
||||
path = path.substring(0, path.lastIndexOf(fileSystem.separator));
|
||||
return path;
|
||||
},
|
||||
/**
|
||||
* 是否为文件
|
||||
* @param path 文件、目录路径
|
||||
* @return boolean
|
||||
*/
|
||||
isFile: (path) => fs.lstatSync(path).isFile(),
|
||||
/**
|
||||
* 是否为目录
|
||||
* @param path 文件、目录路径
|
||||
* @return boolean
|
||||
*/
|
||||
isDirectory: (path) => fs.lstatSync(path).isDirectory(),
|
||||
/**
|
||||
* 判断文件、目录是否存在
|
||||
* @param paths 文件、目录路径数组
|
||||
* @return boolean
|
||||
*/
|
||||
exists: (...paths) => {
|
||||
if (paths.length < 0) return false;
|
||||
let isExists = true;
|
||||
paths.forEach((value) => {
|
||||
isExists &= fs.existsSync(value);
|
||||
});
|
||||
return isExists;
|
||||
},
|
||||
/**
|
||||
* 创建单层目录
|
||||
* @param path 预期目录路径
|
||||
* @param callback 回调结果
|
||||
*/
|
||||
mkdir: (path, callback) => {
|
||||
fs.mkdir(path, callback ?? (() => null));
|
||||
},
|
||||
/**
|
||||
* 删除文件或目录
|
||||
* @param path 文件、目录路径
|
||||
* @param callback 回调结果
|
||||
*/
|
||||
delete: (path, callback) => {
|
||||
if (!fileSystem.exists(path)) return;
|
||||
if (fileSystem.isDirectory(path))
|
||||
fs.rm(path, {recursive: true}, callback ?? (() => null));
|
||||
else fs.unlink(path, callback ?? (() => null));
|
||||
},
|
||||
/**
|
||||
* 删除多个文件或目录
|
||||
* @param callback 全部完成后回调结果
|
||||
* @param paths 文件、目录路径数组
|
||||
*/
|
||||
deletes: (callback, ...paths) => {
|
||||
if (paths.length <= 0) return;
|
||||
let index = 0;
|
||||
|
||||
/** 递归所有路径 */
|
||||
function recursion() {
|
||||
fileSystem.delete(paths[index], () => {
|
||||
if (index < paths.length - 1) {
|
||||
index++;
|
||||
recursion();
|
||||
} else callback();
|
||||
});
|
||||
}
|
||||
|
||||
recursion();
|
||||
},
|
||||
/**
|
||||
* 复制文件 (不能复制目录)
|
||||
* @param fromPath 原始路径
|
||||
* @param toPath 目标路径
|
||||
* @param callback 复制结束回调
|
||||
*/
|
||||
copy: (fromPath, toPath, callback) => {
|
||||
if (fileSystem.isFile(fromPath))
|
||||
fs.copyFile(fromPath, toPath, callback ?? (() => null));
|
||||
else fse.copy(fromPath, toPath, {recursive: true}, callback ?? (() => null));
|
||||
},
|
||||
/**
|
||||
* 重命名文件、目录
|
||||
* @param path 文件、目录路径
|
||||
* @param oldName 原名称
|
||||
* @param newName 新名称
|
||||
* @param callback 回调结果
|
||||
*/
|
||||
rename: (path, oldName, newName, callback) => {
|
||||
fs.rename(path, path.replace(oldName, newName), callback ?? (() => null));
|
||||
},
|
||||
/**
|
||||
* 读取文件
|
||||
* @param path 文件路径
|
||||
* @param callback 回调文件内容
|
||||
*/
|
||||
read: (path, callback) => {
|
||||
fs.readFile(path, (_, buffer) => {
|
||||
callback(buffer.toString());
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 写入文件
|
||||
* @param path 文件路径
|
||||
* @param content 文件内容
|
||||
* @param callback 回调结果
|
||||
*/
|
||||
write: (path, content, callback) => {
|
||||
fs.writeFile(path, content, callback ?? (() => null));
|
||||
},
|
||||
/**
|
||||
* 替换写入文件
|
||||
* @param path 文件路径
|
||||
* @param param 替换内容
|
||||
* @param callback 回调结果
|
||||
*/
|
||||
replace: (path, param, callback) => {
|
||||
fileSystem.read(path, (content) => {
|
||||
let finalContent = content;
|
||||
param.forEach((value) => {
|
||||
while (finalContent.indexOf(value['placeholder']) > 0)
|
||||
finalContent = finalContent.replace(value['placeholder'], value['value']);
|
||||
});
|
||||
fileSystem.write(path, finalContent, callback ?? (() => null));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 替换写入当前目录下全部文件
|
||||
* @param path 目录路径
|
||||
* @param filters 文件类型筛选数组
|
||||
* @param param 替换内容
|
||||
* @param callback 全部完成后回调结果
|
||||
*/
|
||||
replaces: (path, filters, param, callback) => {
|
||||
/**
|
||||
* 递归所有目录
|
||||
* @param path 路径
|
||||
*/
|
||||
function recursion(path) {
|
||||
fs.readdir(path, (_, paths) => {
|
||||
if (paths.length > 0)
|
||||
paths.forEach((value) => {
|
||||
const finalPath = fileSystem.path(path, value);
|
||||
if (fileSystem.isDirectory(finalPath)) recursion(finalPath);
|
||||
else if (filters.find(e => value.endsWith(e))) fileSystem.replace(finalPath, param);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
recursion(path);
|
||||
/**
|
||||
* 递归最长等待 1.5 秒执行下一步
|
||||
* FIXME 递归无法大概估算出其目录层次深度全部循环完毕后回调的结果 - 有待优化
|
||||
*/
|
||||
setTimeout(() => {
|
||||
callback();
|
||||
}, 1500);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {fileSystem};
|
469
src/libs/locale.js
Normal file
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/8.
|
||||
*/
|
||||
|
||||
const locale = {
|
||||
/** Current using locale name */
|
||||
name: '',
|
||||
/** Default locale name */
|
||||
default: 'en',
|
||||
/** The locale String */
|
||||
i18n: {},
|
||||
/**
|
||||
* Init locale
|
||||
* @param name the locale name
|
||||
*/
|
||||
initLocale: (name) => {
|
||||
const data = locale.languages[name];
|
||||
locale.name = data === undefined ? locale.default : name;
|
||||
locale.i18n = data ?? locale.languages[locale.default];
|
||||
},
|
||||
/**
|
||||
* Formatting special placeholder String
|
||||
* @param string Current String
|
||||
* @param objArrs Placeholder Strings
|
||||
* @return string
|
||||
*/
|
||||
format: (string, ...objArrs) => {
|
||||
let finalString = string;
|
||||
if (objArrs === []) return string;
|
||||
objArrs.forEach((value, index) => {
|
||||
finalString = finalString.replace('{%' + (index + 1) + '}', value);
|
||||
});
|
||||
return finalString;
|
||||
},
|
||||
/** All supports languages */
|
||||
languageSupports: {
|
||||
"en": "English",
|
||||
"zh-CN": "简体中文",
|
||||
"ja": "日本語"
|
||||
},
|
||||
/** All languages configs */
|
||||
languages: {
|
||||
"en": {
|
||||
"language": "Language",
|
||||
"followSystem": "Follow System",
|
||||
"appName": "YukiHookAPI Project Builder",
|
||||
"windowTitle": "Create a new Xposed Module Project",
|
||||
"nothing": "nothing",
|
||||
"about": "About",
|
||||
"openSource": "Open Source",
|
||||
"checkUpdate": "Check for Updates...",
|
||||
"checkUpdateTip": "Checking for updates...",
|
||||
"checkUpdateFailTip": "Check for updates failed",
|
||||
"newVersionFound": "New Version Found",
|
||||
"upToDateTip": "Application is up-to-date",
|
||||
"updateLogs": "Update Logs",
|
||||
"updateNow": "Update Now",
|
||||
"file": "File",
|
||||
"help": "Help",
|
||||
"projectAddress": "Project Address",
|
||||
"helpDocumentation": "Help Documentation",
|
||||
"quit": "Quit",
|
||||
"project": "Project",
|
||||
"runBuild": "Run Build",
|
||||
"configTemplate": "Config Template",
|
||||
"savedTemplate": "Saved Template",
|
||||
"newTemplate": "New Template",
|
||||
"newTemplateByCurrentConfig": "New Template By Current Config",
|
||||
"enterTemplateNameTip": "Please enter the template name",
|
||||
"clearAllTemplate": "Clear All Template",
|
||||
"configTemplateSaved": "\"{%1}\" config template saved",
|
||||
"configTemplateLoaded": "\"{%1}\" config template loaded",
|
||||
"configTemplateCleared": "All config templates have been cleared",
|
||||
"resetCurrentConfig": "Reset Current Config",
|
||||
"selectProjectPath": "Please select a location to create the project",
|
||||
"selectProjectPathTip": "The project will be created in the directory of your choice in the format: directory of choice/project name",
|
||||
"selectThisDirectory": "Select this directory",
|
||||
"buildCompleteTip": "The project has been created and packaged for you, here is the build checklist.",
|
||||
"buildPathNoticeTip": "The project has been created to the following path, please check and use it with peace of mind!",
|
||||
"basicConfig": "Basic Config",
|
||||
"yukiHookApiConfig": "YukiHookAPI Config",
|
||||
"projectName": "Project Name",
|
||||
"projectNameTip": "Project Name (Please use English name)",
|
||||
"modulePackageName": "Module Package Name",
|
||||
"moduleName": "Module Name",
|
||||
"moduleDescription": "Module Description",
|
||||
"uiComponents": "UI Components",
|
||||
"gradlePaper": "Gradle Paper",
|
||||
"agpVersion": "Android Gradle Plugin Version",
|
||||
"kotlinVersion": "Kotlin Version",
|
||||
"yukiHookApiVersion": "YukiHookAPI Version",
|
||||
"createDefaultActivity": "Create default Activity (with active state)",
|
||||
"createBlankActivity": "Create a blank Activity",
|
||||
"withoutUiComponents": "No UI components required",
|
||||
"appMinApiVersion": "App Min API Version",
|
||||
"appTargetApiVersion": "App Target API Version",
|
||||
"xposedMinApiVersion": "Xposed Min API Version",
|
||||
"targetXposedPlatform": "Target Xposed Platform",
|
||||
"universal": "Universal",
|
||||
"nativeXposed": "Native Xposed",
|
||||
"declarationNewXSharePrefs": "Declaration New XShare Prefs (Xposed Min API ≥ 93 was optional)",
|
||||
"moduleScope": "Module Scope",
|
||||
"addApps": "Add apps",
|
||||
"entryClassName": "Entry class name (When blank use the default value)",
|
||||
"addResourcesHookSupport": "Add Resources Hook support",
|
||||
"debugTagName": "Debug TAG name (Default is YukiHookAPI)",
|
||||
"enableDebugMode": "Enable debug mode",
|
||||
"enablePrintLogcat": "Enable debug log output",
|
||||
"enableYukiHookModulePrefsCache": "Enable YukiHookModulePrefs key-value caching",
|
||||
"enableModuleResourcesCache": "Enable module Resources caching",
|
||||
"enableModuleStatus": "Enable module activation status listening",
|
||||
"enableYukiHookDataChannel": "Enable YukiHookDataChannel feature",
|
||||
"enableMemberCache": "Enable founded reflection class, method, variable caching",
|
||||
"selectScopeAppsOrEnterOnceTip": "Please select the app you need to add to the scope from the list",
|
||||
"customize": "Customize",
|
||||
"systemFramework": "System Framework",
|
||||
"systemUi": "System UI",
|
||||
"enterAppNameTip": "Please enter the app package name",
|
||||
"autoSearchingDependsTip": "Automatically searching for available project dependencies",
|
||||
"configProjectDepends": "Configure Project Dependencies",
|
||||
"oldDependsWarnTip": "It is recommended to always keep dependencies to the latest version, older versions may not continue to work.",
|
||||
"enterPkgNameOrSelectFromListTip": "Please enter the package name to add or select from the drop-down list",
|
||||
"invalidEnterPkgNameTip": "The package name to be added is invalid",
|
||||
"existEnterPkgNameTip": "The package name to be added already exists",
|
||||
"areYouSureRemoveItemTip": "Are you sure you want to remove \"{%1}\"?",
|
||||
"taskIsRunningTip": "There is currently a task in progress, please wait for it to complete",
|
||||
"enterProjectNameTip": "Please enter a project name",
|
||||
"projectNameRuleTip": "Project name can only be letters and numbers and underscore, and cannot start with a number",
|
||||
"enterModulePackageNameTip": "Please enter the module package name",
|
||||
"invalidModulePackageNameTip": "Invalid module package name",
|
||||
"enterModuleAppNameTip": "Please enter a module name",
|
||||
"enterModuleDescriptionTip": "Please enter a module description",
|
||||
"enterAppMinApiVersionTip": "Please enter the app Min API version",
|
||||
"lsposedSupportMinAppApiWarnTip": "The Min API version of the module app supported by LSPosed cannot be lower than 27 (Android 8.1)",
|
||||
"tooLowAppMinApiVersionWarnTip": "App Min API version must not be lower than 21 (Android 5.1)",
|
||||
"tooHighAppMinApiVersionWarnTip": "App Min API version is too high",
|
||||
"enterAppTargetApiVersionTip": "Please enter the app Target API version",
|
||||
"tooLowAppTargetApiVersionWarnTip": "The app Target API version cannot be lower than the app Min API version",
|
||||
"maybeInvalidAppTargetApiVersionTip": "App Target API version may be invalid",
|
||||
"enterXposedMinApiVersionTip": "Please enter the Xposed Min API version",
|
||||
"tooLowXposedMinApiVersionWarnTip": "Xposed Min API version cannot be lower than 82",
|
||||
"tooHighXposedMinApiVersionWarnTip": "Xposed Min API version cannot be higher than 93",
|
||||
"entryClassNameRuleTip": "Entry Class name can only be letters and numbers and underscore, and cannot start with a number",
|
||||
"moduleScopeRuleTip": "Please add apps in module scope",
|
||||
"findDependContentFail": "Failed to get content of {%1} dependencies",
|
||||
"waitingForBuildingTip": "Preparing to build and create project",
|
||||
"fileAlreadyExistsTip": "Directory path already exists, please select again.",
|
||||
"unpackingTemplateTip": "Unpacking project template: {%1} of {%2}",
|
||||
"packagingAndBuildingTip": "Packaging and building project: {%1} of {%2}",
|
||||
"buildDependProblemTip": "The dependent files required by the project are missing or damaged. Please check whether the installation files are complete.",
|
||||
"buildingFailureTip": "An error occurred during project creation, please check whether the project template file dependencies are complete or the path is correct.",
|
||||
"readOnlyFileSystemTip": "Read-Only File System, please changed the file path and retry.",
|
||||
"operationCancelledTip": "Operation cancelled",
|
||||
"buildComplete": "Build Complete",
|
||||
"openProject": "Open Project",
|
||||
"notice": "Notice",
|
||||
"pleaseWait": "Please Wait",
|
||||
"ok": "OK",
|
||||
"cancel": "Cancel",
|
||||
"close": "Close",
|
||||
"done": "Done",
|
||||
"later": "Later",
|
||||
"notConfigure": "Not configured",
|
||||
"notConfigureDefYes": "Not configured (Default Yes/Enabled)",
|
||||
"yesOfConfigure": "Yes/Enabled",
|
||||
"noOfConfigure": "No/Disabled",
|
||||
"version": "Version",
|
||||
"somethingWentWrongTip": "Something went wrong",
|
||||
"areYouSureRestoreChangeTip": "Are you sure you want to reset all current configs?",
|
||||
"areYouSureClearAllTemplateTip": "Are you sure you want to clear all config template?",
|
||||
"doYouWantLoadConfigTemplateTip": "Do you want to load \"{%1}\"? The current config will be overwritten by the template.",
|
||||
"ruleCheckFailTip": "Rules retrieval failed, please try again.",
|
||||
"networkErrorTip": "A network error occurred, please try again.",
|
||||
"aboutTip": "Helps you quickly create an Xposed project template using YukiHookAPI.",
|
||||
"noticeTip": "Project templates created with this tool are only available for the latest version of Android Studio and IntelliJ IDEA integrated development tools.",
|
||||
"mustRestartTakeEffectTip": "You must restart the application for this change to take effect, and restarting will lose any operations currently in progress."
|
||||
},
|
||||
"zh-CN": {
|
||||
"language": "语言",
|
||||
"followSystem": "跟随系统",
|
||||
"appName": "YukiHookAPI 构建工具",
|
||||
"windowTitle": "创建新的 Xposed 模块项目",
|
||||
"nothing": "无",
|
||||
"about": "关于",
|
||||
"openSource": "开源相关",
|
||||
"checkUpdate": "检查更新",
|
||||
"checkUpdateTip": "正在检查更新...",
|
||||
"checkUpdateFailTip": "检查更新失败",
|
||||
"newVersionFound": "发现新版本",
|
||||
"upToDateTip": "当前已是最新版本",
|
||||
"updateLogs": "更新日志",
|
||||
"updateNow": "立即更新",
|
||||
"file": "文件",
|
||||
"help": "帮助",
|
||||
"projectAddress": "项目地址",
|
||||
"helpDocumentation": "帮助文档",
|
||||
"quit": "退出",
|
||||
"project": "项目",
|
||||
"runBuild": "开始创建",
|
||||
"configTemplate": "配置模板",
|
||||
"savedTemplate": "已保存的模板",
|
||||
"newTemplate": "新建模板",
|
||||
"newTemplateByCurrentConfig": "使用当前配置新建模板",
|
||||
"enterTemplateNameTip": "请输入模板名称",
|
||||
"clearAllTemplate": "清空全部模板",
|
||||
"configTemplateSaved": "已保存 \"{%1}\" 配置模板",
|
||||
"configTemplateLoaded": "已加载 \"{%1}\" 配置模板",
|
||||
"configTemplateCleared": "已清空全部配置模板",
|
||||
"resetCurrentConfig": "重置当前配置",
|
||||
"selectProjectPath": "请选择要创建项目的位置",
|
||||
"selectProjectPathTip": "项目将会在你选择的目录内创建,格式为:选择的目录/项目名称",
|
||||
"selectThisDirectory": "选择此目录",
|
||||
"buildCompleteTip": "已为你完成项目的创建和打包,以下是生成清单。",
|
||||
"buildPathNoticeTip": "项目已创建到如下路径,请客官查收并安心食用!",
|
||||
"basicConfig": "基本配置",
|
||||
"yukiHookApiConfig": "YukiHookAPI 配置",
|
||||
"projectName": "项目名称",
|
||||
"projectNameTip": "项目名称 (请使用英文名称)",
|
||||
"modulePackageName": "模块包名",
|
||||
"moduleName": "模块名称",
|
||||
"moduleDescription": "模块描述",
|
||||
"uiComponents": "UI 组件",
|
||||
"gradlePaper": "Gradle 构建器",
|
||||
"agpVersion": "Android Gradle Plugin 版本",
|
||||
"kotlinVersion": "Kotlin 版本",
|
||||
"yukiHookApiVersion": "YukiHookAPI 版本",
|
||||
"createDefaultActivity": "创建默认 Activity (包含激活状态)",
|
||||
"createBlankActivity": "创建空白 Activity",
|
||||
"withoutUiComponents": "不需要 UI 组件",
|
||||
"appMinApiVersion": "应用最低 API 版本",
|
||||
"appTargetApiVersion": "应用目标 API 版本",
|
||||
"xposedMinApiVersion": "Xposed 最低 API 版本",
|
||||
"targetXposedPlatform": "目标 Xposed 平台",
|
||||
"universal": "通用",
|
||||
"nativeXposed": "原生 Xposed",
|
||||
"declarationNewXSharePrefs": "声明 New XShare Prefs (Xposed 最低 API ≥ 93 无需声明)",
|
||||
"moduleScope": "模块作用域",
|
||||
"addApps": "添加应用",
|
||||
"entryClassName": "入口类名 (不填使用默认值生成)",
|
||||
"addResourcesHookSupport": "添加 Resources Hook 支持",
|
||||
"debugTagName": "Debug TAG 名称 (不填默认为 YukiHookAPI)",
|
||||
"enableDebugMode": "启用 Debug 模式",
|
||||
"enablePrintLogcat": "启用调试日志输出功能",
|
||||
"enableYukiHookModulePrefsCache": "启用 YukiHookModulePrefs 键值缓存功能",
|
||||
"enableModuleResourcesCache": "启用模块 Resources 缓存功能",
|
||||
"enableModuleStatus": "启用模块激活状态监听功能",
|
||||
"enableYukiHookDataChannel": "启用 YukiHookDataChannel 功能",
|
||||
"enableMemberCache": "启用已查询的反射类、方法、变量缓存功能",
|
||||
"selectScopeAppsOrEnterOnceTip": "请从下面的列表中选择你需要添加到作用域中的应用",
|
||||
"customize": "自定义",
|
||||
"systemFramework": "系统框架",
|
||||
"systemUi": "系统界面 (系统 UI)",
|
||||
"enterAppNameTip": "请输入应用包名",
|
||||
"autoSearchingDependsTip": "正在自动搜索可用的项目依赖",
|
||||
"configProjectDepends": "配置项目依赖",
|
||||
"oldDependsWarnTip": "建议始终保持依赖为最新版本,较旧版本可能无法继续使用。",
|
||||
"enterPkgNameOrSelectFromListTip": "请输入要添加的应用包名或从下拉列表选择",
|
||||
"invalidEnterPkgNameTip": "要添加的应用包名无效",
|
||||
"existEnterPkgNameTip": "要添加的应用包名已存在",
|
||||
"areYouSureRemoveItemTip": "你确定要移除 \"{%1}\" 吗?",
|
||||
"taskIsRunningTip": "当前有任务正在进行,请等待其完成",
|
||||
"enterProjectNameTip": "请输入项目名称",
|
||||
"projectNameRuleTip": "项目名称只能是字母和数字以及下划线,且不能以数字开头",
|
||||
"enterModulePackageNameTip": "请输入模块包名",
|
||||
"invalidModulePackageNameTip": "模块包名无效",
|
||||
"enterModuleAppNameTip": "请输入模块名称",
|
||||
"enterModuleDescriptionTip": "请输入模块描述",
|
||||
"enterAppMinApiVersionTip": "请输入应用最低 API 版本",
|
||||
"lsposedSupportMinAppApiWarnTip": "LSPosed 支持的模块应用最低 API 版本不能低于 27 (Android 8.1)",
|
||||
"tooLowAppMinApiVersionWarnTip": "应用最低 API 版本不能低于 21 (Android 5.1)",
|
||||
"tooHighAppMinApiVersionWarnTip": "应用最低 API 版本过高",
|
||||
"enterAppTargetApiVersionTip": "请输入应用目标 API 版本",
|
||||
"tooLowAppTargetApiVersionWarnTip": "应用目标 API 版本不能低于应用最低 API 版本",
|
||||
"maybeInvalidAppTargetApiVersionTip": "应用目标 API 版本可能无效",
|
||||
"enterXposedMinApiVersionTip": "请输入 Xposed 最低 API 版本",
|
||||
"tooLowXposedMinApiVersionWarnTip": "Xposed 最低 API 版本不能低于 82",
|
||||
"tooHighXposedMinApiVersionWarnTip": "Xposed 最低 API 版本不能高于 93",
|
||||
"entryClassNameRuleTip": "入口类名只能是字母和数字以及下划线,且不能以数字开头",
|
||||
"moduleScopeRuleTip": "请添加模块作用域中的应用",
|
||||
"findDependContentFail": "获取 {%1} 依赖内容失败",
|
||||
"waitingForBuildingTip": "正在准备生成并创建项目",
|
||||
"fileAlreadyExistsTip": "目录路径已存在,请重新选择。",
|
||||
"unpackingTemplateTip": "正在解压缩项目模板:第 {%1} 个,共 {%2} 个",
|
||||
"packagingAndBuildingTip": "正在打包并生成项目:第 {%1} 步,共 {%2} 步",
|
||||
"buildDependProblemTip": "项目所需依赖文件已丢失或已被损坏,请检查安装文件是否完整且可用。",
|
||||
"buildingFailureTip": "创建项目过程发生错误,请检查项目模板文件依赖是否完整或路径是否正确。",
|
||||
"readOnlyFileSystemTip": "目标目录不可写,请更换目录并重新开始。",
|
||||
"operationCancelledTip": "已取消操作",
|
||||
"buildComplete": "创建成功",
|
||||
"openProject": "打开项目",
|
||||
"notice": "提示",
|
||||
"pleaseWait": "请稍后",
|
||||
"ok": "确定",
|
||||
"cancel": "取消",
|
||||
"close": "关闭",
|
||||
"done": "完成",
|
||||
"later": "稍后",
|
||||
"notConfigure": "未配置",
|
||||
"notConfigureDefYes": "未配置 (默认 是/Yes)",
|
||||
"yesOfConfigure": "是/Yes",
|
||||
"noOfConfigure": "否/No",
|
||||
"version": "版本",
|
||||
"somethingWentWrongTip": "发生了一点问题",
|
||||
"areYouSureRestoreChangeTip": "还原当前所做的全部更改吗?",
|
||||
"areYouSureClearAllTemplateTip": "清空全部已保存的配置模板吗?",
|
||||
"doYouWantLoadConfigTemplateTip": "要加载 \"{%1}\" 吗?当前配置会被模板覆盖。",
|
||||
"ruleCheckFailTip": "规则检索失败,请再试一次。",
|
||||
"networkErrorTip": "网络发生错误,请再试一次。",
|
||||
"aboutTip": "帮助你快速创建一个使用 YukiHookAPI 打造的 Xposed 项目模板。",
|
||||
"noticeTip": "使用本工具创建的项目模板仅适用于 Android Studio 以及 IntelliJ IDEA 集成化开发工具的最新版本。",
|
||||
"mustRestartTakeEffectTip": "你必须要重启应用程序才能使这项更改生效,重启会丢失当前正在进行的操作。"
|
||||
},
|
||||
"ja": {
|
||||
"language": "言語",
|
||||
"followSystem": "システムに従って",
|
||||
"appName": "YukiHookAPI 作成ツール",
|
||||
"windowTitle": "新しいXposedモジュールプロジェクトを作成する",
|
||||
"nothing": "ない",
|
||||
"about": "について",
|
||||
"openSource": "オープンソース関連",
|
||||
"checkUpdate": "アップデートを探す",
|
||||
"checkUpdateTip": "アップデートを探しています...",
|
||||
"checkUpdateFailTip": "アップデートを探すは失敗した",
|
||||
"newVersionFound": "新しいバージョンが見た",
|
||||
"upToDateTip": "アプリケーションは最新です",
|
||||
"updateLogs": "変更ログ",
|
||||
"updateNow": "すぐにアップデート",
|
||||
"file": "フェルオ",
|
||||
"help": "ヘルプ",
|
||||
"projectAddress": "プロジェクトアドレス",
|
||||
"helpDocumentation": "ヘルプドキュメント",
|
||||
"quit": "終了する",
|
||||
"project": "プロジェクト",
|
||||
"runBuild": "作成をスタートする",
|
||||
"configTemplate": "構成テンプレート",
|
||||
"savedTemplate": "保存されたテンプレート",
|
||||
"newTemplate": "テンプレートを追加",
|
||||
"newTemplateByCurrentConfig": "現在の構成で新しいテンプレートを追加",
|
||||
"enterTemplateNameTip": "テンプレート名を入力してください",
|
||||
"clearAllTemplate": "すべてのテンプレートをクリア",
|
||||
"configTemplateSaved": "「{%1}」構成テンプレートが保存されました",
|
||||
"configTemplateLoaded": "「{%1}」構成テンプレートがロードされました",
|
||||
"configTemplateCleared": "すべての構成テンプレートがクリアされました",
|
||||
"resetCurrentConfig": "現在の構成をリセット",
|
||||
"selectProjectPath": "プロジェクトを作成する場所を選択してください",
|
||||
"selectProjectPathTip": "プロジェクトは、選択したディレクトリに次の形式で作成されます:選択したディレクトリ/プロジェクト名",
|
||||
"selectThisDirectory": "このディレクトリを選択",
|
||||
"buildCompleteTip": "プロジェクトが作成され、パッケージ化されました。ビルドチェックリストは次のとおりです。",
|
||||
"buildPathNoticeTip": "プロジェクトは以下のパスで作成されていますので、安心してチェックしてご利用ください!",
|
||||
"basicConfig": "基本構成",
|
||||
"yukiHookApiConfig": "YukiHookAPI 構成",
|
||||
"projectName": "プロジェクト名",
|
||||
"projectNameTip": "プロジェクト名 (英語名を使用してください)",
|
||||
"modulePackageName": "モジュールパッケージ名",
|
||||
"moduleName": "モジュール名",
|
||||
"moduleDescription": "モジュールの説明",
|
||||
"uiComponents": "UI コンポーネント",
|
||||
"gradlePaper": "グラドルペーパー",
|
||||
"agpVersion": "Android Gradle プラグインバージョン",
|
||||
"kotlinVersion": "Kotlin バージョン",
|
||||
"yukiHookApiVersion": "YukiHookAPI バージョン",
|
||||
"createDefaultActivity": "デフォルトのActivityを作成(アクティブ状態)",
|
||||
"createBlankActivity": "空白のActivityを作成",
|
||||
"withoutUiComponents": "UIコンポーネントは必要ありません",
|
||||
"appMinApiVersion": "最小APIバージョンを適用",
|
||||
"appTargetApiVersion": "アプリターゲットAPIバージョン",
|
||||
"xposedMinApiVersion": "Xposedの最小APIバージョン",
|
||||
"targetXposedPlatform": "ターゲットXposedプラットフォーム",
|
||||
"universal": "ユニバーサル",
|
||||
"nativeXposed": "ネイティブXposed",
|
||||
"declarationNewXSharePrefs": "宣言新しいXShare設定(Xposed最小API≥93宣言は不要)",
|
||||
"moduleScope": "モジュールスコープ",
|
||||
"addApps": "アプリを追加",
|
||||
"entryClassName": "エントリクラス名(デフォルトを使用するには空)",
|
||||
"addResourcesHookSupport": "リソースフックのサポートを追加",
|
||||
"debugTagName": "デバッグタグ名(デフォルトはYukiHookAPI)",
|
||||
"enableDebugMode": "デバッグモードを有効にする",
|
||||
"enablePrintLogcat": "デバッグログ出力を有効にする",
|
||||
"enableYukiHookModulePrefsCache": "YukiHookModulePrefsのKey-Valueキャッシングを有効にする",
|
||||
"enableModuleResourcesCache": "モジュールリソースのキャッシュを有効にする",
|
||||
"enableModuleStatus": "モジュールのアクティブ化ステータスの監視を有効にする",
|
||||
"enableYukiHookDataChannel": "YukiHookDataChannel機能を有効にする",
|
||||
"enableMemberCache": "クエリされたリフレクションクラス、メソッド、変数キャッシングを有効にする",
|
||||
"selectScopeAppsOrEnterOnceTip": "以下のリストからスコープに追加するアプリを選択してください",
|
||||
"customize": "カスタマイズ",
|
||||
"systemFramework": "システムフレームワーク",
|
||||
"systemUi": "システムインターフェース",
|
||||
"enterAppNameTip": "アプリケーションパッケージ名を入力してください",
|
||||
"autoSearchingDependsTip": "利用可能なプロジェクトの依存関係を自動的に検索しています",
|
||||
"configProjectDepends": "プロジェクトの依存関係を構成",
|
||||
"oldDependsWarnTip": "常に最新バージョンへの依存関係を維持することをお勧めします。古いバージョンは引き続き機能しない可能性があります。",
|
||||
"enterPkgNameOrSelectFromListTip": "追加するパッケージ名を入力するか、ドロップダウンリストから選択してください",
|
||||
"invalidEnterPkgNameTip": "追加するパッケージ名が無効です",
|
||||
"existEnterPkgNameTip": "追加するパッケージ名は既に存在します",
|
||||
"areYouSureRemoveItemTip": "「{%1}」を削除してもよろしいですか",
|
||||
"taskIsRunningTip": "現在進行中のタスクがあります。完了するまでお待ちください",
|
||||
"enterProjectNameTip": "プロジェクト名を入力してください",
|
||||
"projectNameRuleTip": "アイテム名は文字と数字とアンダースコアのみで、数字で始めることはできません",
|
||||
"enterModulePackageNameTip": "モジュールパッケージ名を入力してください",
|
||||
"invalidModulePackageNameTip": "モジュールパッケージ名が無効です",
|
||||
"enterModuleAppNameTip": "モジュール名を入力してください",
|
||||
"enterModuleDescriptionTip": "モジュールの説明を入力してください",
|
||||
"enterAppMinApiVersionTip": "アプリの最小APIバージョンを入力してください",
|
||||
"lsposedSupportMinAppApiWarnTip": "LSPosedでサポートされているモジュールアプリケーションの最小APIバージョンは27より低くすることはできません(Android 8.1)",
|
||||
"tooLowAppMinApiVersionWarnTip": "アプリの最小APIバージョンは21以上である必要があります(Android 5.1)",
|
||||
"tooHighAppMinApiVersionWarnTip": "アプリの最小APIバージョンが高すぎます",
|
||||
"enterAppTargetApiVersionTip": "アプリケーションターゲットAPIバージョンを入力してください",
|
||||
"tooLowAppTargetApiVersionWarnTip": "アプリのターゲットAPIバージョンは、アプリの最小APIバージョンより低くすることはできません",
|
||||
"maybeInvalidAppTargetApiVersionTip": "アプリのターゲットAPIバージョンが無効である可能性があります",
|
||||
"enterXposedMinApiVersionTip": "Xposedの最小APIバージョンを入力してください",
|
||||
"tooLowXposedMinApiVersionWarnTip": "Xposedの最小APIバージョンは82より低くすることはできません",
|
||||
"tooHighXposedMinApiVersionWarnTip": "Xposedの最小APIバージョンは93を超えることはできません",
|
||||
"entryClassNameRuleTip": "エントリクラス名は、文字と数字、およびアンダースコアのみにすることができ、数字で始めることはできません",
|
||||
"moduleScopeRuleTip": "モジュールスコープにアプリを追加してください",
|
||||
"findDependContentFail": "{%1} 依存関係のコンテンツを取得できませんでした",
|
||||
"waitingForBuildingTip": "プロジェクトの構築と作成の準備",
|
||||
"fileAlreadyExistsTip": "ディレクトリパスはすでに存在します。もう一度選択してください。",
|
||||
"unpackingTemplateTip": "プロジェクトテンプレートの解凍:{%2} の {%1}",
|
||||
"packagingAndBuildingTip": "パッケージングおよび構築プロジェクト:{%2} の {%1}",
|
||||
"buildDependProblemTip": "プロジェクトに必要な依存ファイルが欠落しているか破損しています。インストールファイルが完全かどうかを確認してください。",
|
||||
"buildingFailureTip": "プロジェクトの作成中にエラーが発生しました。プロジェクトテンプレートファイルの依存関係が完全であるか、パスが正しいかどうかを確認してください。",
|
||||
"readOnlyFileSystemTip": "宛先ディレクトリは書き込み可能ではありません。ディレクトリを変更して最初からやり直してください。",
|
||||
"operationCancelledTip": "操作がキャンセルされました",
|
||||
"buildComplete": "作成完了",
|
||||
"openProject": "プロジェクトを開く",
|
||||
"notice": "ヒント",
|
||||
"pleaseWait": "お待ちください",
|
||||
"ok": "確認",
|
||||
"cancel": "キャンセル",
|
||||
"close": "消す",
|
||||
"done": "完了",
|
||||
"later": "後で",
|
||||
"notConfigure": "構成されていません",
|
||||
"notConfigureDefYes": "構成されていません (デフォルトは はい/Yes)",
|
||||
"yesOfConfigure": "はい/Yes",
|
||||
"noOfConfigure": "いいえ/No",
|
||||
"version": "バージョン",
|
||||
"somethingWentWrongTip": "何かがうまくいかなかった",
|
||||
"areYouSureRestoreChangeTip": "現在のすべての変更を元に戻しますか",
|
||||
"areYouSureClearAllTemplateTip": "保存されているすべての構成テンプレートをクリアしますか",
|
||||
"doYouWantLoadConfigTemplateTip": "「{%1}」をロードしますか?現在の構成はテンプレートによって上書きされます。",
|
||||
"ruleCheckFailTip": "ルールの取得に失敗しました。もう一度やり直してください。",
|
||||
"networkErrorTip": "ネットワークエラーが発生しました。もう一度やり直してください。",
|
||||
"aboutTip": "YukiHookAPIを使用してXposedプロジェクトテンプレートをすばやく作成するのに役立ちます。",
|
||||
"noticeTip": "このツールで作成されたプロジェクトテンプレートは、Android Studio および最新バージョンの IntelliJ IDEA 統合開発ツールでのみ使用できます。",
|
||||
"mustRestartTakeEffectTip": "この変更を有効にするには、アプリケーションをリスタートする必要があります。リスタートすると、現在進行中の操作がすべて失われます。"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {locale};
|
50
src/libs/store.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/14.
|
||||
*/
|
||||
|
||||
const Store = require('electron-store');
|
||||
|
||||
/** Key-Value 存储对象 */
|
||||
const store = {
|
||||
/** 当前实例 */
|
||||
instance: undefined,
|
||||
/**
|
||||
* 获取数据
|
||||
* @param key 键值名称
|
||||
* @param value 默认值
|
||||
* @return
|
||||
*/
|
||||
get: (key, value) => {
|
||||
store.instance ??= new Store();
|
||||
return store.instance.get(key, value);
|
||||
},
|
||||
/**
|
||||
* 写入数据
|
||||
* @param key 键值名称
|
||||
* @param value 键值内容
|
||||
*/
|
||||
set: (key, value) => {
|
||||
store.instance ??= new Store();
|
||||
store.instance.set(key, value);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {store};
|
61
src/libs/system.js
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/15.
|
||||
*/
|
||||
|
||||
const {shell} = require('electron');
|
||||
const {exec} = require('child_process');
|
||||
|
||||
/**
|
||||
* 系统操作命名空间
|
||||
*/
|
||||
const system = {
|
||||
/**
|
||||
* 是否为 macOS
|
||||
* @return boolean
|
||||
*/
|
||||
isMacOS: process.platform === 'darwin',
|
||||
/**
|
||||
* 打开系统默认浏览器
|
||||
* @param url 地址
|
||||
*/
|
||||
openBrowser: (url) => {
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
exec('open ' + url);
|
||||
break;
|
||||
case 'win32':
|
||||
exec('start ' + url);
|
||||
break;
|
||||
default:
|
||||
exec('xdg-open', [url]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 打开资源文件管理器/访达
|
||||
* @param path 文件路径
|
||||
*/
|
||||
openExplorer: (path) => {
|
||||
shell.openPath(path).then(() => null);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {system};
|
63
src/libs/unzip.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/12.
|
||||
*/
|
||||
|
||||
const DecompressZip = require('decompress-zip');
|
||||
|
||||
/**
|
||||
* 解压缩命名空间
|
||||
*/
|
||||
const unzip = {
|
||||
/** 当前实例 */
|
||||
instance: null,
|
||||
/**
|
||||
* 解压目标文件
|
||||
* @param filePath 压缩文件路径
|
||||
* @param outPath 解压目录
|
||||
*/
|
||||
extract: (filePath, outPath) => {
|
||||
unzip.instance = new DecompressZip(filePath);
|
||||
unzip.instance.extract({path: outPath});
|
||||
},
|
||||
/**
|
||||
* 监听解压进度
|
||||
* @param callback 回调
|
||||
*/
|
||||
progress: (callback) => {
|
||||
unzip.instance.on('progress', callback);
|
||||
},
|
||||
/**
|
||||
* 监听解压成功
|
||||
* @param callback 回调
|
||||
*/
|
||||
success: (callback) => {
|
||||
unzip.instance.on('extract', callback);
|
||||
},
|
||||
/**
|
||||
* 监听解压失败
|
||||
* @param callback 回调
|
||||
*/
|
||||
failure: (callback) => {
|
||||
unzip.instance.on('error', callback);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {unzip};
|
554
src/transaction.js
Normal file
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* YukiHookAPI Project Builder - A Xposed Project Builder by YukiHookAPI.
|
||||
* Copyright (C) 2019-2022 HighCapable
|
||||
* https://github.com/fankes/YukiHookAPI-ProjectBuilder
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/7/21.
|
||||
*/
|
||||
|
||||
const {system} = require('./libs/system');
|
||||
const {locale} = require('./libs/locale');
|
||||
const {fileSystem} = require('./libs/file-system');
|
||||
const {unzip} = require('./libs/unzip');
|
||||
const {dateTime} = require('./libs/date-time');
|
||||
const {appWindow, appConfig} = require('./app-space');
|
||||
|
||||
/**
|
||||
* 创建项目事务命名空间
|
||||
*/
|
||||
const transaction = {
|
||||
/** 项目模板名称 */
|
||||
templateName: 'project-template',
|
||||
/** 当前项目创建路径 */
|
||||
projectPath: '',
|
||||
/** 打开已创建的项目 */
|
||||
openProject: () => {
|
||||
system.openExplorer(transaction.projectPath);
|
||||
},
|
||||
/**
|
||||
* 开始任务
|
||||
* @param configs 项目配置
|
||||
*/
|
||||
start: (configs) => {
|
||||
appWindow.showOpenDirectory({
|
||||
title: locale.i18n.selectProjectPath,
|
||||
message: locale.i18n.selectProjectPathTip,
|
||||
buttonLabel: locale.i18n.selectThisDirectory
|
||||
}, (result) => {
|
||||
if (!result.canceled) {
|
||||
transaction.projectPath = fileSystem.path(result.filePaths[0], configs.basicConfig.projectName);
|
||||
if (!fileSystem.exists(transaction.projectPath)) {
|
||||
const ossPath = fileSystem.path(appConfig.sourcePath, 'public', transaction.templateName.concat('.zip'));
|
||||
const outPath = fileSystem.path(appConfig.dataPath, transaction.templateName.concat('.zip'));
|
||||
const targetPath = fileSystem.path(appConfig.dataPath, transaction.templateName);
|
||||
if (fileSystem.exists(ossPath))
|
||||
if (fileSystem.exists(targetPath))
|
||||
fileSystem.delete(targetPath, () => {
|
||||
transaction.packaing(configs, ossPath, outPath, targetPath);
|
||||
});
|
||||
else transaction.packaing(configs, ossPath, outPath, targetPath);
|
||||
else appWindow.webContents.methods.build.failure(locale.i18n.buildDependProblemTip);
|
||||
} else appWindow.webContents.methods.build.failure(locale.i18n.fileAlreadyExistsTip);
|
||||
} else appWindow.webContents.methods.build.cancel();
|
||||
}, () => {
|
||||
appWindow.webContents.methods.page.snack(locale.i18n.somethingWentWrongTip);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 开始打包
|
||||
* @param configs 项目配置
|
||||
* @param ossPath 原始路径 (应用程序内部路径)
|
||||
* @param outPath 导出路径 (外部数据临时路径)
|
||||
* @param targetPath 目标路径 (解包打包操作路径)
|
||||
*/
|
||||
packaing: (configs, ossPath, outPath, targetPath) => {
|
||||
|
||||
/**
|
||||
* 代码文件模板命名空间
|
||||
*/
|
||||
const codeFiles = {
|
||||
/**
|
||||
* 获取代码缩进空格
|
||||
* @param count 空格个数
|
||||
* @return string
|
||||
*/
|
||||
space: (count) => {
|
||||
let space = '';
|
||||
for (let i = 1; i <= count; i++) space = space.concat(' ');
|
||||
return space;
|
||||
},
|
||||
/**
|
||||
* 插入代码
|
||||
* @param origCode 原始代码
|
||||
* @param newCodes 新的代码数组
|
||||
* @return string
|
||||
*/
|
||||
append: (origCode, ...newCodes) => {
|
||||
if (newCodes.length <= 0) return;
|
||||
let finalCode = origCode;
|
||||
newCodes.forEach((value) => {
|
||||
if (value !== '') finalCode = finalCode.concat(value, '\n', codeFiles.space(8));
|
||||
});
|
||||
return finalCode;
|
||||
},
|
||||
/**
|
||||
* 注入依赖 - 适用于 'build.gradle' 文件
|
||||
* @param origCode 原始代码
|
||||
* @param dependencies 依赖内容数组
|
||||
* @return string
|
||||
*/
|
||||
implement: (origCode, ...dependencies) => {
|
||||
if (dependencies.length <= 0) return;
|
||||
let finalCode = origCode;
|
||||
dependencies.forEach((value) => {
|
||||
finalCode = finalCode.concat(value.type, codeFiles.space(1), '\'',
|
||||
value.groupId, ':', value.artifactId, ':', value.version, '\'\n', codeFiles.space(4));
|
||||
});
|
||||
return finalCode;
|
||||
},
|
||||
'build.gradle': {
|
||||
dependencies: {
|
||||
androidXposed: {
|
||||
type: 'compileOnly',
|
||||
groupId: 'de.robv.android.xposed',
|
||||
artifactId: 'api',
|
||||
version: '82'
|
||||
},
|
||||
yukiHookApiApi: {
|
||||
type: 'implementation',
|
||||
groupId: 'com.highcapable.yukihookapi',
|
||||
artifactId: 'api',
|
||||
version: configs.projectDependencies.yukiHookApiVersion
|
||||
},
|
||||
yukiHookApiKsp: {
|
||||
type: 'ksp',
|
||||
groupId: 'com.highcapable.yukihookapi',
|
||||
artifactId: 'ksp-xposed',
|
||||
version: configs.projectDependencies.yukiHookApiVersion
|
||||
},
|
||||
drawabletoolbox: {
|
||||
type: 'implementation',
|
||||
groupId: 'com.github.duanhong169',
|
||||
artifactId: 'drawabletoolbox',
|
||||
version: '1.0.7'
|
||||
},
|
||||
androidxCoreKtx: {
|
||||
type: 'implementation',
|
||||
groupId: 'androidx.core',
|
||||
artifactId: 'core-ktx',
|
||||
version: '1.8.0'
|
||||
},
|
||||
appcompat: {
|
||||
type: 'implementation',
|
||||
groupId: 'androidx.appcompat',
|
||||
artifactId: 'appcompat',
|
||||
version: '1.4.2'
|
||||
},
|
||||
material: {
|
||||
type: 'implementation',
|
||||
groupId: 'com.google.android.material',
|
||||
artifactId: 'material',
|
||||
version: '1.6.1'
|
||||
},
|
||||
constraintlayout: {
|
||||
type: 'implementation',
|
||||
groupId: 'androidx.constraintlayout',
|
||||
artifactId: 'constraintlayout',
|
||||
version: '2.1.4'
|
||||
},
|
||||
junit: {
|
||||
type: 'testImplementation',
|
||||
groupId: 'junit',
|
||||
artifactId: 'junit',
|
||||
version: '4.13.2'
|
||||
},
|
||||
androidxTestExt: {
|
||||
type: 'androidTestImplementation',
|
||||
groupId: 'androidx.test.ext',
|
||||
artifactId: 'junit',
|
||||
version: '1.1.3'
|
||||
},
|
||||
androidxTestEspresso: {
|
||||
type: 'androidTestImplementation',
|
||||
groupId: 'androidx.test.espresso',
|
||||
artifactId: 'espresso-core',
|
||||
version: '3.4.0'
|
||||
}
|
||||
}
|
||||
},
|
||||
'AndroidManifest.xml': {
|
||||
newXSharePrefs: (isEnabled) => ('<meta-data\n' +
|
||||
codeFiles.space(12) + 'android:name="xposedsharedprefs"\n' +
|
||||
codeFiles.space(12) + 'android:value="' + (isEnabled ? 'true' : 'false') + '" />'),
|
||||
xposedModule: () => ('<meta-data\n' +
|
||||
codeFiles.space(12) + 'android:name="xposedmodule"\n' +
|
||||
codeFiles.space(12) + 'android:value="true" />'),
|
||||
moduleScope: () => ('<meta-data\n' +
|
||||
codeFiles.space(12) + 'android:name="xposedscope"\n' +
|
||||
codeFiles.space(12) + 'android:resource="@array/module_scope" />')
|
||||
},
|
||||
'array.xml': {
|
||||
item: (name) => '<item>' + name + '</item>'
|
||||
},
|
||||
'HookEntry.kt': {
|
||||
annotations: {
|
||||
entryClassName: (name) => 'entryClassName = "' + name + '"',
|
||||
supportResourcesHook: (isEnabled) => 'isUsingResourcesHook = ' + (isEnabled ? 'true' : 'false')
|
||||
},
|
||||
configs: {
|
||||
debugTagName: (name) => 'debugTag = "' + name + '"',
|
||||
enableDebug: (isEnabled) => 'isDebug = ' + (isEnabled ? 'true' : 'false'),
|
||||
enablePrintLogcat: (isEnabled) => 'isAllowPrintingLogs = ' + (isEnabled ? 'true' : 'false'),
|
||||
enableYPrefsCache: (isEnabled) => 'isEnableModulePrefsCache = ' + (isEnabled ? 'true' : 'false'),
|
||||
enableResourcesCache: (isEnabled) => 'isEnableModuleAppResourcesCache = ' + (isEnabled ? 'true' : 'false'),
|
||||
enableModuleStatus: (isEnabled) => 'isEnableHookModuleStatus = ' + (isEnabled ? 'true' : 'false'),
|
||||
enableYChannel: (isEnabled) => 'isEnableDataChannel = ' + (isEnabled ? 'true' : 'false'),
|
||||
enableMemberCache: (isEnabled) => 'isEnableMemberCache = ' + (isEnabled ? 'true' : 'false')
|
||||
}
|
||||
},
|
||||
'MainActivity.kt': {
|
||||
isModuleActive: () => 'YukiHookAPI.Status.isModuleActive',
|
||||
isXposedModuleActive: () => 'YukiHookAPI.Status.isXposedModuleActive',
|
||||
isTaiChiModuleActive: () => 'YukiHookAPI.Status.isTaiChiModuleActive'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新创建进度显示
|
||||
* @param progress 当前进度
|
||||
*/
|
||||
function changeProgress(progress) {
|
||||
appWindow.webContents.methods.build.changeStatus(locale.format(locale.i18n.packagingAndBuildingTip, progress, 4));
|
||||
}
|
||||
|
||||
/** 结束创建项目 */
|
||||
function finishBuild() {
|
||||
changeProgress(4);
|
||||
fileSystem.copy(targetPath, transaction.projectPath, () => {
|
||||
if (fileSystem.exists(transaction.projectPath))
|
||||
fileSystem.deletes(() => {
|
||||
transaction.finish(configs);
|
||||
}, outPath, targetPath);
|
||||
else appWindow.webContents.methods.build.failure(locale.i18n.readOnlyFileSystemTip);
|
||||
});
|
||||
}
|
||||
|
||||
/** 移动项目代码到包名目录 */
|
||||
function moveToPackageName() {
|
||||
changeProgress(3);
|
||||
const folderNames = configs.basicConfig.packageName.split('.');
|
||||
const androidTestSpPath = fileSystem.path(targetPath, 'app', 'src', 'androidTest', 'java', 'scope');
|
||||
const androidTestPath = fileSystem.path(targetPath, 'app', 'src', 'androidTest', 'java', folderNames);
|
||||
const testSpPath = fileSystem.path(targetPath, 'app', 'src', 'test', 'java', 'scope');
|
||||
const testPath = fileSystem.path(targetPath, 'app', 'src', 'test', 'java', folderNames);
|
||||
const mainSpPath = fileSystem.path(targetPath, 'app', 'src', 'main', 'java', 'scope');
|
||||
const mainPath = fileSystem.path(targetPath, 'app', 'src', 'main', 'java', folderNames);
|
||||
if (fileSystem.exists(androidTestSpPath, testSpPath, mainSpPath))
|
||||
fileSystem.copy(androidTestSpPath, androidTestPath, () => {
|
||||
fileSystem.copy(testSpPath, testPath, () => {
|
||||
fileSystem.copy(mainSpPath, mainPath, () => {
|
||||
fileSystem.deletes(() => {
|
||||
finishBuild();
|
||||
}, androidTestSpPath, testSpPath, mainSpPath);
|
||||
});
|
||||
});
|
||||
});
|
||||
else appWindow.webContents.methods.build.failure(locale.i18n.buildDependProblemTip);
|
||||
}
|
||||
|
||||
/** 替换代码文件中的配置信息 */
|
||||
function replaceFiles() {
|
||||
changeProgress(2);
|
||||
let manifestMetaDataCode = '';
|
||||
const newXShareCode = configs.basicConfig.newXSharePrefs === 0 ? '' :
|
||||
codeFiles['AndroidManifest.xml'].newXSharePrefs(configs.basicConfig.newXSharePrefs === 1);
|
||||
switch (configs.basicConfig.targetXposedPlatform) {
|
||||
case 0:
|
||||
manifestMetaDataCode = codeFiles.append(manifestMetaDataCode, codeFiles['AndroidManifest.xml'].xposedModule(),
|
||||
newXShareCode, codeFiles['AndroidManifest.xml'].moduleScope());
|
||||
break;
|
||||
case 1:
|
||||
manifestMetaDataCode = codeFiles.append(manifestMetaDataCode, newXShareCode,
|
||||
codeFiles['AndroidManifest.xml'].moduleScope());
|
||||
break;
|
||||
case 2:
|
||||
// TODO LSPatch WIP
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
manifestMetaDataCode = codeFiles.append(manifestMetaDataCode, codeFiles['AndroidManifest.xml'].xposedModule());
|
||||
/** 不需要作用域直接删掉作用域定义的数组文件 */
|
||||
fileSystem.delete(fileSystem.path(targetPath, 'app', 'src', 'main', 'res', 'values', 'array.xml'));
|
||||
break;
|
||||
}
|
||||
manifestMetaDataCode = manifestMetaDataCode.trim();
|
||||
let moduleActiveStatusCode = '';
|
||||
switch (configs.basicConfig.targetXposedPlatform) {
|
||||
case 2:
|
||||
// TODO LSPatch WIP
|
||||
break;
|
||||
case 0:
|
||||
moduleActiveStatusCode = codeFiles['MainActivity.kt'].isModuleActive();
|
||||
break;
|
||||
case 1:
|
||||
case 4:
|
||||
moduleActiveStatusCode = codeFiles['MainActivity.kt'].isXposedModuleActive();
|
||||
break;
|
||||
case 3:
|
||||
moduleActiveStatusCode = codeFiles['MainActivity.kt'].isTaiChiModuleActive();
|
||||
break;
|
||||
}
|
||||
moduleActiveStatusCode = moduleActiveStatusCode.trim();
|
||||
let moduleScopesCode = '';
|
||||
if (configs.basicConfig.moduleScopes.length > 0)
|
||||
configs.basicConfig.moduleScopes.forEach((value) => {
|
||||
moduleScopesCode = codeFiles.append(moduleScopesCode, codeFiles['array.xml'].item(value));
|
||||
});
|
||||
moduleScopesCode = moduleScopesCode.trim();
|
||||
let hookEntryAnnotationCode = '';
|
||||
if (configs.yukiHookApiConfig.entryClassName !== '')
|
||||
hookEntryAnnotationCode = hookEntryAnnotationCode.concat(
|
||||
codeFiles['HookEntry.kt'].annotations.entryClassName(configs.yukiHookApiConfig.entryClassName), ', ');
|
||||
if (configs.yukiHookApiConfig.supportResourcesHook !== 0)
|
||||
hookEntryAnnotationCode = hookEntryAnnotationCode.concat(
|
||||
codeFiles['HookEntry.kt'].annotations.supportResourcesHook(configs.yukiHookApiConfig.supportResourcesHook === 1));
|
||||
if (hookEntryAnnotationCode.trim() !== '')
|
||||
hookEntryAnnotationCode = '(' + (hookEntryAnnotationCode.trim().endsWith(',') ?
|
||||
hookEntryAnnotationCode.trim().substring(0, hookEntryAnnotationCode.trim().lastIndexOf(',')) :
|
||||
hookEntryAnnotationCode.trim()) + ')';
|
||||
let hookEntryConfigsCode = '';
|
||||
if (configs.yukiHookApiConfig.debugTagName !== '')
|
||||
hookEntryConfigsCode = codeFiles.append(hookEntryConfigsCode,
|
||||
codeFiles['HookEntry.kt'].configs.debugTagName(configs.yukiHookApiConfig.debugTagName));
|
||||
if (configs.yukiHookApiConfig.enableDebug !== 0)
|
||||
hookEntryConfigsCode = codeFiles.append(hookEntryConfigsCode,
|
||||
codeFiles['HookEntry.kt'].configs.enableDebug(configs.yukiHookApiConfig.enableDebug === 1));
|
||||
if (configs.yukiHookApiConfig.enablePrintLogcat !== 0)
|
||||
hookEntryConfigsCode = codeFiles.append(hookEntryConfigsCode,
|
||||
codeFiles['HookEntry.kt'].configs.enablePrintLogcat(configs.yukiHookApiConfig.enablePrintLogcat === 1));
|
||||
if (configs.yukiHookApiConfig.enableYPrefsCache !== 0)
|
||||
hookEntryConfigsCode = codeFiles.append(hookEntryConfigsCode,
|
||||
codeFiles['HookEntry.kt'].configs.enableYPrefsCache(configs.yukiHookApiConfig.enableYPrefsCache === 1));
|
||||
if (configs.yukiHookApiConfig.enableResourcesCache !== 0)
|
||||
hookEntryConfigsCode = codeFiles.append(hookEntryConfigsCode,
|
||||
codeFiles['HookEntry.kt'].configs.enableResourcesCache(configs.yukiHookApiConfig.enableResourcesCache === 1));
|
||||
if (configs.yukiHookApiConfig.enableModuleStatus !== 0)
|
||||
hookEntryConfigsCode = codeFiles.append(hookEntryConfigsCode,
|
||||
codeFiles['HookEntry.kt'].configs.enableModuleStatus(configs.yukiHookApiConfig.enableModuleStatus === 1));
|
||||
if (configs.yukiHookApiConfig.enableYChannel !== 0)
|
||||
hookEntryConfigsCode = codeFiles.append(hookEntryConfigsCode,
|
||||
codeFiles['HookEntry.kt'].configs.enableYChannel(configs.yukiHookApiConfig.enableYChannel === 1));
|
||||
if (configs.yukiHookApiConfig.enableMemberCache !== 0)
|
||||
hookEntryConfigsCode = codeFiles.append(hookEntryConfigsCode,
|
||||
codeFiles['HookEntry.kt'].configs.enableMemberCache(configs.yukiHookApiConfig.enableMemberCache === 1));
|
||||
hookEntryConfigsCode = hookEntryConfigsCode.trim();
|
||||
if (hookEntryConfigsCode === '') hookEntryConfigsCode = '// Your code here.';
|
||||
let gradleDependenciesCode = '';
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.androidXposed);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.yukiHookApiApi);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.yukiHookApiKsp);
|
||||
switch (configs.basicConfig.moduleCompoment) {
|
||||
case 0:
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.drawabletoolbox);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.androidxCoreKtx);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.appcompat);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.material);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.constraintlayout);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.junit);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.androidxTestExt);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.androidxTestEspresso);
|
||||
break;
|
||||
case 1:
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.androidxCoreKtx);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.appcompat);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.material);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.constraintlayout);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.junit);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.androidxTestExt);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.androidxTestEspresso);
|
||||
break;
|
||||
case 2:
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.junit);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.androidxTestExt);
|
||||
gradleDependenciesCode = codeFiles.implement(gradleDependenciesCode,
|
||||
codeFiles['build.gradle'].dependencies.androidxTestEspresso);
|
||||
break;
|
||||
}
|
||||
gradleDependenciesCode = gradleDependenciesCode.trim();
|
||||
fileSystem.replaces(targetPath, ['gradle', 'properties', 'kt', 'xml'], [
|
||||
{
|
||||
placeholder: '{GRADLE_PAPER}',
|
||||
value: configs.projectDependencies.gradlePaper
|
||||
}, {
|
||||
placeholder: '{GRADLE_PROPERTIES_DATE}',
|
||||
value: dateTime.cstTime()
|
||||
}, {
|
||||
placeholder: '{AGP_VERSION}',
|
||||
value: configs.projectDependencies.androidGradlePluginVersion
|
||||
}, {
|
||||
placeholder: '{KOTLIN_VERSION}',
|
||||
value: configs.projectDependencies.kotlinVersion
|
||||
}, {
|
||||
placeholder: '{KOTLIN_KSP_VERSION}',
|
||||
value: configs.projectDependencies.kotlinKspVersion
|
||||
}, {
|
||||
placeholder: '{YUKIHOOKAPI_VERSION}',
|
||||
value: configs.projectDependencies.yukiHookApiVersion
|
||||
}, {
|
||||
placeholder: '{PROJECT_NAME}',
|
||||
value: configs.basicConfig.projectName
|
||||
}, {
|
||||
placeholder: '{PACKAGE_NAME}',
|
||||
value: configs.basicConfig.packageName
|
||||
}, {
|
||||
placeholder: '{APP_NAME}',
|
||||
value: configs.basicConfig.appName
|
||||
}, {
|
||||
placeholder: '{MODULE_DESCRIPTION}',
|
||||
value: configs.basicConfig.moduleDescription
|
||||
}, {
|
||||
placeholder: '{APP_MIN_API}',
|
||||
value: configs.basicConfig.appMinApi
|
||||
}, {
|
||||
placeholder: '{APP_TARGET_API}',
|
||||
value: configs.basicConfig.appTargetApi
|
||||
}, {
|
||||
placeholder: '{XPOSED_MIN_API}',
|
||||
value: configs.basicConfig.xposedMinApi
|
||||
}, {
|
||||
placeholder: '{META_DATA}',
|
||||
value: manifestMetaDataCode
|
||||
}, {
|
||||
placeholder: '{SCOPE_ITEMS}',
|
||||
value: moduleScopesCode
|
||||
}, {
|
||||
placeholder: '{GRADLE_DEPENDENCIES}',
|
||||
value: gradleDependenciesCode
|
||||
}, {
|
||||
placeholder: '{YUKIHOOKAPI_MODULE_ACTIVE_STATUS}',
|
||||
value: moduleActiveStatusCode
|
||||
}, {
|
||||
placeholder: '{YUKIHOOKAPI_ANNOTATION}',
|
||||
value: hookEntryAnnotationCode
|
||||
}, {
|
||||
placeholder: '{YUKIHOOKAPI_CONFIGS}',
|
||||
value: hookEntryConfigsCode
|
||||
}
|
||||
], () => {
|
||||
moveToPackageName();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化为 main 目录路径
|
||||
* @param name 目录名称
|
||||
* @return string
|
||||
*/
|
||||
function parseMainPath(name) {
|
||||
return fileSystem.path(targetPath, 'app', 'src', name);
|
||||
}
|
||||
|
||||
/** 开始创建项目 */
|
||||
function preToBuild() {
|
||||
changeProgress(1);
|
||||
if (fileSystem.exists(parseMainPath('main-fully'), parseMainPath('main-blank'), parseMainPath('main-nogui')))
|
||||
switch (configs.basicConfig.moduleCompoment) {
|
||||
case 0:
|
||||
fileSystem.rename(parseMainPath('main-fully'), 'main-fully', 'main', () => {
|
||||
fileSystem.deletes(() => {
|
||||
replaceFiles();
|
||||
}, parseMainPath('main-blank'), parseMainPath('main-nogui'));
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
fileSystem.rename(parseMainPath('main-blank'), 'main-blank', 'main', () => {
|
||||
fileSystem.deletes(() => {
|
||||
replaceFiles();
|
||||
}, parseMainPath('main-fully'), parseMainPath('main-nogui'));
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
fileSystem.rename(parseMainPath('main-nogui'), 'main-nogui', 'main', () => {
|
||||
fileSystem.deletes(() => {
|
||||
replaceFiles();
|
||||
}, parseMainPath('main-fully'), parseMainPath('main-blank'));
|
||||
});
|
||||
break;
|
||||
default:
|
||||
appWindow.webContents.methods.build.failure(locale.i18n.buildingFailureTip);
|
||||
break;
|
||||
}
|
||||
else appWindow.webContents.methods.build.failure(locale.i18n.buildDependProblemTip);
|
||||
}
|
||||
|
||||
fileSystem.copy(ossPath, outPath, () => {
|
||||
if (fileSystem.exists(outPath)) {
|
||||
unzip.extract(outPath, appConfig.dataPath);
|
||||
unzip.progress((fileIndex, fileCount) => {
|
||||
appWindow.webContents.methods.build.changeStatus(locale.format(locale.i18n.unpackingTemplateTip,
|
||||
fileIndex, fileCount));
|
||||
});
|
||||
unzip.success(() => {
|
||||
preToBuild();
|
||||
});
|
||||
unzip.failure((error) => {
|
||||
appWindow.webContents.methods.build.failure(locale.i18n.buildingFailureTip + '<br/>' + error.toString());
|
||||
});
|
||||
} else appWindow.webContents.methods.build.failure(locale.i18n.buildingFailureTip);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 完成任务
|
||||
* @param configs 项目配置
|
||||
*/
|
||||
finish: (configs) => {
|
||||
appWindow.webContents.methods.build.complete(
|
||||
(locale.i18n.buildCompleteTip + '<br/><br/>' +
|
||||
locale.i18n.projectName + ': ' + configs.basicConfig.projectName + '<br/>' +
|
||||
locale.i18n.moduleName + ': ' + configs.basicConfig.appName + '<br/>' +
|
||||
locale.i18n.moduleDescription + ': ' + configs.basicConfig.moduleDescription.replace(/\n/g, ' ') + '<br/>' +
|
||||
locale.i18n.gradlePaper + ': ' + configs.projectDependencies.gradlePaper + '<br/>' +
|
||||
locale.i18n.agpVersion + ': ' + configs.projectDependencies.androidGradlePluginVersion + '<br/>' +
|
||||
locale.i18n.kotlinVersion + ': ' + configs.projectDependencies.kotlinVersion + '<br/>' +
|
||||
locale.i18n.yukiHookApiVersion + ': ' + configs.projectDependencies.yukiHookApiVersion + '<br/><br/>' +
|
||||
locale.i18n.buildPathNoticeTip + '<br/><br/>' + transaction.projectPath.replace(/\\/g, '\')
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {transaction};
|