Rename app to EasyView and make APK build cross-platform
- App display name -> EasyView (Android label, PWA manifest, page titles, about/guide text, APK artifact name) - scripts/build-apk.mjs: auto-detect JDK/SDK/Gradle toolchain instead of hardcoded Windows paths; pick highest build-tools; platform 34 fallback; path.delimiter classpaths; npm run build without cmd.exe on POSIX - Add build-apk.sh one-shot Linux build wrapper (loads ven env + keystore) - Signing keystore renamed to easyview.jks (alias easyview), env vars EASYVIEW_KEYSTORE_PASS / EASYVIEW_KEY_PASS
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ android/app/src/main/assets/www/
|
||||
android/keystore/
|
||||
*.jks
|
||||
*.keystore
|
||||
PhoneViewer-*.apk
|
||||
EasyView-*.apk
|
||||
*.dwg
|
||||
*.DWG
|
||||
.env
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# PhoneViewer / 万能看图
|
||||
# EasyView / 万能看图
|
||||
|
||||
手机 / 平板上的本地 DWG、PDF、EPUB、FB2、XPS/OXPS、CBZ 和图片浏览器。
|
||||
|
||||
@@ -19,16 +19,25 @@ npm run build
|
||||
|
||||
## 构建 Android APK
|
||||
|
||||
需要 JDK 17、Android SDK 34 和 Gradle 的 Kotlin 编译器(脚本位于 `E:\AiCodeGitea\ven\AndroidDev`,可在 `scripts/build-apk.mjs` 中调整路径)。
|
||||
需要 JDK 17+/21、Android SDK(platform 34、build-tools)以及带 Kotlin 编译器的 Gradle 发行版。
|
||||
本工作区已把这些工具链放在 `../ven/` 下,脚本会自动探测:
|
||||
|
||||
签名信息不写入仓库。构建前设置:
|
||||
| 工具 | 位置 |
|
||||
| --- | --- |
|
||||
| JDK | `ven/jdk21`(或 `JAVA_HOME`) |
|
||||
| Android SDK | `ven/android-sdk`(或 `ANDROID_HOME`) |
|
||||
| Gradle + Kotlin 编译器的 lib | `ven/gradle-dist/gradle-8.9`(或 `GRADLE_HOME`) |
|
||||
|
||||
签名信息不写入仓库,首次构建会自动生成 `android/keystore/easyview.jks`。构建前设置口令:
|
||||
|
||||
```bash
|
||||
PHONEVIEWER_KEYSTORE_PASS=your-keystore-password
|
||||
PHONEVIEWER_KEY_PASS=your-key-password
|
||||
source ../ven/node-env.sh # Node 工具链(可选)
|
||||
export EASYVIEW_KEYSTORE_PASS=your-keystore-password
|
||||
export EASYVIEW_KEY_PASS=your-key-password # 省略则与上面相同
|
||||
npm run apk
|
||||
```
|
||||
|
||||
产物:`EasyView-<version>.apk`(仓库根目录),`android/build/` 为中间产物。
|
||||
`android/keystore/`、测试 DWG、APK、`dist/`、`node_modules/` 均已加入 `.gitignore`。图纸不会上传,解析完全在本地进行。
|
||||
|
||||
## 许可
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">万能看图</string>
|
||||
<string name="app_name">EasyView</string>
|
||||
</resources>
|
||||
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# 一键构建 EasyView APK(Linux / 本工作区 ven 工具链)
|
||||
# 用法:./build-apk.sh
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ven="$(cd "$here/../ven" && pwd)"
|
||||
|
||||
source "$ven/node-env.sh"
|
||||
export npm_config_cache="$ven/npm"
|
||||
export ANDROID_HOME="$ven/android-sdk"
|
||||
export ANDROID_SDK_ROOT="$ANDROID_HOME"
|
||||
|
||||
# 签名口令:优先取 android/keystore/.env.keystore(已 gitignore)
|
||||
if [[ -f "$here/android/keystore/.env.keystore" ]]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
. "$here/android/keystore/.env.keystore"
|
||||
set +a
|
||||
fi
|
||||
: "${EASYVIEW_KEYSTORE_PASS:?未设置签名口令:请在 android/keystore/.env.keystore 中写入 EASYVIEW_KEYSTORE_PASS}"
|
||||
|
||||
cd "$here"
|
||||
node scripts/build-apk.mjs
|
||||
+3
-3
@@ -10,17 +10,17 @@
|
||||
<meta name="theme-color" content="#0b0e14" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="万能看图" />
|
||||
<meta name="apple-mobile-web-app-title" content="EasyView" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="icon" type="image/svg+xml" href="./icons/favicon.svg" />
|
||||
<link rel="apple-touch-icon" href="./icons/apple-touch-icon.png" />
|
||||
<title>万能看图 · DWG/PDF 浏览器</title>
|
||||
<title>EasyView · DWG/PDF 浏览器</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="toasts" aria-live="polite" aria-atomic="false"></div>
|
||||
<div id="modal-root"></div>
|
||||
<noscript>需要启用 JavaScript 才能使用万能看图。</noscript>
|
||||
<noscript>需要启用 JavaScript 才能使用 EasyView。</noscript>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Generated
-42
@@ -2083,9 +2083,6 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2307,9 +2304,6 @@
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2324,9 +2318,6 @@
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2341,9 +2332,6 @@
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2358,9 +2346,6 @@
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2375,9 +2360,6 @@
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2392,9 +2374,6 @@
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2409,9 +2388,6 @@
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2426,9 +2402,6 @@
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2443,9 +2416,6 @@
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2460,9 +2430,6 @@
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2477,9 +2444,6 @@
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2494,9 +2458,6 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2511,9 +2472,6 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
|
||||
+116
-33
@@ -4,19 +4,92 @@ import { execFileSync } from 'node:child_process'
|
||||
import AdmZip from 'adm-zip'
|
||||
|
||||
const root = process.cwd()
|
||||
const devRoot = process.env.ANDROID_DEV_ROOT || 'E:\\AiCodeGitea\\ven\\AndroidDev'
|
||||
const jdkHome = fs.existsSync(path.join(process.env.JAVA_HOME || '', 'bin', 'java.exe'))
|
||||
? process.env.JAVA_HOME
|
||||
: path.join(devRoot, 'jdk17')
|
||||
const sdkHome = fs.existsSync(path.join(process.env.ANDROID_HOME || '', 'platforms'))
|
||||
? process.env.ANDROID_HOME
|
||||
: path.join(devRoot, 'Sdk')
|
||||
const gradleHome = path.join(devRoot, 'gradle-8.7')
|
||||
const buildTools = path.join(sdkHome, 'build-tools', '34.0.0')
|
||||
const androidJar = path.join(sdkHome, 'platforms', 'android-34', 'android.jar')
|
||||
const java = path.join(jdkHome, 'bin', 'java.exe')
|
||||
const jar = path.join(jdkHome, 'bin', 'jar.exe')
|
||||
const keytool = path.join(jdkHome, 'bin', 'keytool.exe')
|
||||
const isWin = process.platform === 'win32'
|
||||
const exeSuffix = isWin ? '.exe' : ''
|
||||
const devRoot =
|
||||
process.env.ANDROID_DEV_ROOT ||
|
||||
(isWin ? 'E:\\AiCodeGitea\\ven\\AndroidDev' : path.resolve(root, '..', 'ven'))
|
||||
|
||||
const isFile = (p) => {
|
||||
try {
|
||||
return fs.statSync(p).isFile()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
const isDir = (p) => {
|
||||
try {
|
||||
return fs.statSync(p).isDirectory()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const jdkHome = (() => {
|
||||
const candidates = [
|
||||
process.env.JAVA_HOME,
|
||||
path.join(devRoot, 'jdk21'),
|
||||
path.join(devRoot, 'jdk17'),
|
||||
path.join(devRoot, 'AndroidDev', 'jdk17')
|
||||
].filter(Boolean)
|
||||
const found = candidates.find((dir) => isFile(path.join(dir, 'bin', `java${exeSuffix}`)))
|
||||
if (!found) throw new Error('JDK not found: set JAVA_HOME (workspace: source ../ven/*-env.sh)')
|
||||
return found
|
||||
})()
|
||||
|
||||
const sdkHome = (() => {
|
||||
const candidates = [
|
||||
process.env.ANDROID_HOME,
|
||||
process.env.ANDROID_SDK_ROOT,
|
||||
path.join(devRoot, 'android-sdk'),
|
||||
path.join(devRoot, 'Sdk')
|
||||
].filter(Boolean)
|
||||
const found = candidates.find((dir) => isDir(path.join(dir, 'platforms')))
|
||||
if (!found) throw new Error('Android SDK not found: set ANDROID_HOME')
|
||||
return found
|
||||
})()
|
||||
|
||||
function findGradleHome() {
|
||||
const explicit = [process.env.GRADLE_HOME, path.join(devRoot, 'gradle-8.7')].filter(Boolean)
|
||||
const found = explicit.find((dir) => isFile(path.join(dir, 'lib', 'kotlin-stdlib-1.9.23.jar')))
|
||||
if (found) return found
|
||||
const distRoot = path.join(devRoot, 'gradle-dist')
|
||||
const candidates = isDir(distRoot)
|
||||
? fs
|
||||
.readdirSync(distRoot)
|
||||
.filter((name) => name.startsWith('gradle-'))
|
||||
.sort()
|
||||
.reverse()
|
||||
.map((name) => path.join(distRoot, name))
|
||||
: []
|
||||
const hit = candidates.find((dir) => isDir(path.join(dir, 'lib')))
|
||||
if (!hit) throw new Error(`Gradle distribution with Kotlin compiler not found under ${distRoot}`)
|
||||
return hit
|
||||
}
|
||||
const gradleHome = findGradleHome()
|
||||
|
||||
const buildToolsVersion =
|
||||
process.env.BUILD_TOOLS_VERSION ||
|
||||
fs
|
||||
.readdirSync(path.join(sdkHome, 'build-tools'))
|
||||
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
|
||||
.pop()
|
||||
const buildTools = path.join(sdkHome, 'build-tools', buildToolsVersion)
|
||||
|
||||
const platformId =
|
||||
process.env.COMPILE_SDK ||
|
||||
(isDir(path.join(sdkHome, 'platforms', 'android-34'))
|
||||
? 'android-34'
|
||||
: fs
|
||||
.readdirSync(path.join(sdkHome, 'platforms'))
|
||||
.filter((name) => name.startsWith('android-'))
|
||||
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
|
||||
.pop())
|
||||
const androidJar = path.join(sdkHome, 'platforms', platformId, 'android.jar')
|
||||
|
||||
const java = path.join(jdkHome, 'bin', `java${exeSuffix}`)
|
||||
const jar = path.join(jdkHome, 'bin', `jar${exeSuffix}`)
|
||||
const keytool = path.join(jdkHome, 'bin', `keytool${exeSuffix}`)
|
||||
const kotlincJars = path.join(gradleHome, 'lib', '*')
|
||||
const kotlinStdlib = fs
|
||||
.readdirSync(path.join(gradleHome, 'lib'))
|
||||
@@ -25,6 +98,9 @@ const kotlinStdlib = fs
|
||||
.pop()
|
||||
if (!kotlinStdlib) throw new Error('kotlin-stdlib not found in Gradle lib')
|
||||
|
||||
const appVersion = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).version
|
||||
const versionCode = Number(process.env.APP_VERSION_CODE || 7)
|
||||
|
||||
const env = {
|
||||
...process.env,
|
||||
JAVA_HOME: jdkHome,
|
||||
@@ -35,9 +111,13 @@ const env = {
|
||||
buildTools,
|
||||
path.join(sdkHome, 'platform-tools'),
|
||||
process.env.PATH || ''
|
||||
].join(';')
|
||||
].join(path.delimiter)
|
||||
}
|
||||
|
||||
console.log(`JDK : ${jdkHome}`)
|
||||
console.log(`Android SDK: ${sdkHome} (build-tools ${buildToolsVersion}, platform ${platformId})`)
|
||||
console.log(`Gradle lib : ${gradleHome}`)
|
||||
|
||||
const appDir = path.join(root, 'android', 'app', 'src', 'main')
|
||||
const manifest = path.join(appDir, 'AndroidManifest.xml')
|
||||
const resDir = path.join(appDir, 'res')
|
||||
@@ -47,15 +127,17 @@ const sourceDir = path.join(appDir, 'java')
|
||||
const outDir = path.join(root, 'android', 'build')
|
||||
const classesDir = path.join(outDir, 'classes')
|
||||
const dexDir = path.join(outDir, 'dex')
|
||||
const apkName = 'PhoneViewer-0.5.0.apk'
|
||||
const apkName = `EasyView-${appVersion}.apk`
|
||||
|
||||
function run(command, args, options = {}) {
|
||||
console.log('>', path.basename(command), args.join(' '))
|
||||
execFileSync(command, args, { stdio: 'inherit', env, ...options })
|
||||
}
|
||||
|
||||
function runBat(batFile, args, options = {}) {
|
||||
run('cmd.exe', ['/c', batFile, ...args], options)
|
||||
// Android build-tools ship .bat wrappers on Windows and plain scripts elsewhere.
|
||||
function runTool(name, args, options = {}) {
|
||||
const tool = path.join(buildTools, `${name}${isWin ? '.bat' : ''}`)
|
||||
return isWin ? run('cmd.exe', ['/c', tool, ...args], options) : run(tool, args, options)
|
||||
}
|
||||
|
||||
fs.rmSync(outDir, { recursive: true, force: true })
|
||||
@@ -64,7 +146,8 @@ fs.mkdirSync(classesDir, { recursive: true })
|
||||
fs.mkdirSync(dexDir, { recursive: true })
|
||||
|
||||
console.log('== building web assets ==')
|
||||
run('cmd.exe', ['/c', 'npm run build'], { cwd: root })
|
||||
if (isWin) run('cmd.exe', ['/c', 'npm run build'], { cwd: root })
|
||||
else run(process.env.NPM_BIN || 'npm', ['run', 'build'], { cwd: root, shell: false })
|
||||
|
||||
console.log('== copying web assets into Android assets ==')
|
||||
fs.rmSync(wwwDir, { recursive: true, force: true })
|
||||
@@ -93,7 +176,7 @@ run(java, [
|
||||
'-no-stdlib',
|
||||
'-no-reflect',
|
||||
'-classpath',
|
||||
`${androidJar};${path.join(gradleHome, 'lib', kotlinStdlib)}`,
|
||||
[androidJar, path.join(gradleHome, 'lib', kotlinStdlib)].join(path.delimiter),
|
||||
'-jvm-target',
|
||||
'17',
|
||||
'-d',
|
||||
@@ -106,7 +189,7 @@ const classesJar = path.join(outDir, 'classes.jar')
|
||||
run(jar, ['cf', classesJar, '-C', classesDir, '.'])
|
||||
|
||||
console.log('== dexing with d8 ==')
|
||||
runBat(path.join(buildTools, 'd8.bat'), [
|
||||
runTool('d8', [
|
||||
'--release',
|
||||
'--lib',
|
||||
androidJar,
|
||||
@@ -120,11 +203,11 @@ runBat(path.join(buildTools, 'd8.bat'), [
|
||||
|
||||
console.log('== compiling resources ==')
|
||||
const resZip = path.join(outDir, 'resources.zip')
|
||||
run(path.join(buildTools, 'aapt2.exe'), ['compile', '-o', resZip, '--dir', resDir])
|
||||
run(path.join(buildTools, `aapt2${exeSuffix}`), ['compile', '-o', resZip, '--dir', resDir])
|
||||
|
||||
console.log('== linking base apk ==')
|
||||
const baseApk = path.join(outDir, 'base.apk')
|
||||
run(path.join(buildTools, 'aapt2.exe'), [
|
||||
run(path.join(buildTools, `aapt2${exeSuffix}`), [
|
||||
'link',
|
||||
'-o',
|
||||
baseApk,
|
||||
@@ -139,9 +222,9 @@ run(path.join(buildTools, 'aapt2.exe'), [
|
||||
'--target-sdk-version',
|
||||
'34',
|
||||
'--version-code',
|
||||
'6',
|
||||
String(versionCode),
|
||||
'--version-name',
|
||||
'0.5.0',
|
||||
appVersion,
|
||||
'--auto-add-overlay'
|
||||
])
|
||||
|
||||
@@ -167,17 +250,17 @@ zip.writeZip(unsigned)
|
||||
|
||||
console.log('== zipalign ==')
|
||||
const aligned = path.join(outDir, 'aligned.apk')
|
||||
run(path.join(buildTools, 'zipalign.exe'), ['-p', '-f', '4', unsigned, aligned])
|
||||
run(path.join(buildTools, `zipalign${exeSuffix}`), ['-p', '-f', '4', unsigned, aligned])
|
||||
|
||||
console.log('== signing ==')
|
||||
const keystoreDir = path.join(root, 'android', 'keystore')
|
||||
const keystore = path.join(keystoreDir, 'phoneviewer.jks')
|
||||
const storePass = process.env.PHONEVIEWER_KEYSTORE_PASS
|
||||
const keyPass = process.env.PHONEVIEWER_KEY_PASS ?? storePass
|
||||
const keystore = path.join(keystoreDir, 'easyview.jks')
|
||||
const storePass = process.env.EASYVIEW_KEYSTORE_PASS ?? process.env.PHONEVIEWER_KEYSTORE_PASS
|
||||
const keyPass = process.env.EASYVIEW_KEY_PASS ?? process.env.PHONEVIEWER_KEY_PASS ?? storePass
|
||||
if (!storePass) {
|
||||
throw new Error('Set PHONEVIEWER_KEYSTORE_PASS before building the signed APK.')
|
||||
throw new Error('Set EASYVIEW_KEYSTORE_PASS before building the signed APK.')
|
||||
}
|
||||
const alias = 'phoneviewer'
|
||||
const alias = 'easyview'
|
||||
if (!fs.existsSync(keystore)) {
|
||||
fs.mkdirSync(keystoreDir, { recursive: true })
|
||||
run(keytool, [
|
||||
@@ -200,12 +283,12 @@ if (!fs.existsSync(keystore)) {
|
||||
'-keypass',
|
||||
keyPass,
|
||||
'-dname',
|
||||
'CN=PhoneViewer, OU=Android, O=PhoneViewer, L=Beijing, ST=Beijing, C=CN',
|
||||
'CN=EasyView, OU=Android, O=EasyView, L=Beijing, ST=Beijing, C=CN',
|
||||
'-noprompt'
|
||||
])
|
||||
}
|
||||
const finalApk = path.join(outDir, apkName)
|
||||
runBat(path.join(buildTools, 'apksigner.bat'), [
|
||||
runTool('apksigner', [
|
||||
'sign',
|
||||
'--ks',
|
||||
keystore,
|
||||
@@ -219,7 +302,7 @@ runBat(path.join(buildTools, 'apksigner.bat'), [
|
||||
finalApk,
|
||||
aligned
|
||||
])
|
||||
runBat(path.join(buildTools, 'apksigner.bat'), ['verify', '--verbose', '--print-certs', finalApk])
|
||||
runTool('apksigner', ['verify', '--verbose', '--print-certs', finalApk])
|
||||
|
||||
const rootApk = path.join(root, apkName)
|
||||
fs.copyFileSync(finalApk, rootApk)
|
||||
|
||||
+4
-4
@@ -117,7 +117,7 @@ function buildHome(): HTMLElement {
|
||||
'div',
|
||||
{ class: 'home-brand' },
|
||||
h('div', { class: 'brand-mark', html: LOGO_SVG }),
|
||||
h('div', { class: 'brand-text' }, h('div', { class: 'brand-name', text: '万能看图' }))
|
||||
h('div', { class: 'brand-text' }, h('div', { class: 'brand-name', text: 'EasyView' }))
|
||||
)
|
||||
|
||||
const top = h(
|
||||
@@ -275,7 +275,7 @@ async function openFile(file: File): Promise<void> {
|
||||
viewerRoot.appendChild(host.root)
|
||||
viewerRoot.hidden = false
|
||||
homeEl.hidden = true
|
||||
document.title = `${file.name} · 万能看图`
|
||||
document.title = `${file.name} · EasyView`
|
||||
await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()))
|
||||
|
||||
let createdViewer: ActiveViewer | null = null
|
||||
@@ -326,7 +326,7 @@ async function openFile(file: File): Promise<void> {
|
||||
activeViewer = null
|
||||
viewerRoot.hidden = true
|
||||
homeEl.hidden = false
|
||||
document.title = '万能看图 · DWG/PDF 浏览器'
|
||||
document.title = 'EasyView · DWG/PDF 浏览器'
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
console.error(error)
|
||||
modalMessage(
|
||||
@@ -353,7 +353,7 @@ function closeActiveViewer(): void {
|
||||
viewerRoot.innerHTML = ''
|
||||
viewerRoot.hidden = true
|
||||
homeEl.hidden = false
|
||||
document.title = '万能看图 · DWG/PDF 浏览器'
|
||||
document.title = 'EasyView · DWG/PDF 浏览器'
|
||||
void refreshRecent()
|
||||
}
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ export class DocViewer {
|
||||
add('rotate', 'rotate-cw', '旋转 90°', () => this.rotatePage())
|
||||
add('invert', 'moon', '反色阅读', () => this.toggleInvert())
|
||||
this.fullscreenBtn = add('fullscreen', 'maximize', '全屏', () => void this.toggleFullscreen())
|
||||
add('about', 'info', '关于万能看图', () => showAbout())
|
||||
add('about', 'info', '关于 EasyView', () => showAbout())
|
||||
return menu
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -10,7 +10,7 @@ export function showAbout(): void {
|
||||
h(
|
||||
'p',
|
||||
{ class: 'modal-text' },
|
||||
'万能看图是一个完全在本地运行的手机 / 平板图纸与文档浏览器。文件只在本机解析,不会上传到任何服务器。'
|
||||
'EasyView 是一个完全在本地运行的手机 / 平板图纸与文档浏览器。文件只在本机解析,不会上传到任何服务器。'
|
||||
),
|
||||
h('h3', { text: '支持的格式' }),
|
||||
h(
|
||||
@@ -36,12 +36,12 @@ export function showAbout(): void {
|
||||
h('li', {}, '文档渲染:MuPDF.js(SumatraPDF 同源渲染内核家族)— AGPL-3.0'),
|
||||
h('li', {}, '本应用以 AGPL-3.0 发布;完整许可文本见项目 LICENSE 文件。')
|
||||
),
|
||||
h('p', { class: 'about-version', text: `万能看图 v${VERSION} · PWA · 本地解析` })
|
||||
h('p', { class: 'about-version', text: `EasyView v${VERSION} · PWA · 本地解析` })
|
||||
)
|
||||
|
||||
const close = h('button', { class: 'btn btn-primary', type: 'button', text: '关闭' })
|
||||
const modal = openModal({
|
||||
title: '关于万能看图',
|
||||
title: '关于 EasyView',
|
||||
subtitle: '手机 / 平板上的 DWG 图纸 & 文档浏览器',
|
||||
content: body,
|
||||
actions: [close],
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ export function showGuide(): void {
|
||||
h(
|
||||
'p',
|
||||
{ class: 'modal-text' },
|
||||
'万能看图把 DWG 图纸浏览和文档阅读放在同一个本地 App 里。文件只在本机解析,不会上传到服务器。'
|
||||
'EasyView 把 DWG 图纸浏览和文档阅读放在同一个本地 App 里。文件只在本机解析,不会上传到服务器。'
|
||||
),
|
||||
section(
|
||||
'支持格式',
|
||||
|
||||
+2
-2
@@ -16,8 +16,8 @@ export default defineConfig({
|
||||
injectRegister: false,
|
||||
includeAssets: ['icons/favicon.svg', 'icons/apple-touch-icon.png'],
|
||||
manifest: {
|
||||
name: '万能看图 · DWG/PDF 浏览',
|
||||
short_name: '万能看图',
|
||||
name: 'EasyView · DWG/PDF 浏览',
|
||||
short_name: 'EasyView',
|
||||
description:
|
||||
'手机与平板上的 DWG 图纸浏览器,支持模型空间与布局空间、图层控制、测量,以及 PDF / EPUB / XPS / CBZ / 图片阅读。',
|
||||
lang: 'zh-CN',
|
||||
|
||||
Reference in New Issue
Block a user