Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
492 changes: 353 additions & 139 deletions package-lock.json

Large diffs are not rendered by default.

33 changes: 17 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,30 @@
"build-only": "vite build",
"type-check": "vue-tsc --noEmit",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"postinstall": "fetch-scrcpy-server 2.6.1"
"postinstall": "fetch-scrcpy-server 3.3.3"
},
"dependencies": {
"@mdi/font": "^7.4.47",
"@yume-chan/adb": "^0.0.24",
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0",
"@yume-chan/adb": "^2.3.1",
"@yume-chan/adb-backend-webusb": "^0.0.19",
"@yume-chan/adb-scrcpy": "^0.0.24",
"@yume-chan/android-bin": "^0.0.24",
"@yume-chan/aoa": "^0.0.24",
"@yume-chan/event": "^0.0.24",
"@yume-chan/fetch-scrcpy-server": "^0.0.24",
"@yume-chan/pcm-player": "^0.0.24",
"@yume-chan/scrcpy": "^0.0.24",
"@yume-chan/scrcpy-decoder-tinyh264": "^0.0.24",
"@yume-chan/scrcpy-decoder-webcodecs": "^0.0.24",
"@yume-chan/stream-extra": "^0.0.24",
"@yume-chan/struct": "^0.0.24",
"@yume-chan/adb-scrcpy": "^2.3.0",
"@yume-chan/android-bin": "^2.1.0",
"@yume-chan/aoa": "^1.0.0",
"@yume-chan/event": "^2.0.0",
"@yume-chan/fetch-scrcpy-server": "^1.0.0",
"@yume-chan/pcm-player": "^1.0.0",
"@yume-chan/scrcpy": "^2.3.0",
"@yume-chan/scrcpy-decoder-tinyh264": "^2.1.0",
"@yume-chan/scrcpy-decoder-webcodecs": "^2.1.0",
"@yume-chan/stream-extra": "^2.1.0",
"@yume-chan/struct": "^2.0.1",
"file-saver": "^2.0.5",
"markdown-it": "^14.1.0",
"vue": "^3.3.4",
"vuetify": "^3.3.5",
"webm-muxer": "^5.0.3",
"xterm": "^5.3.0",
"xterm-addon-fit": "^0.8.0"
"webm-muxer": "^5.0.3"
},
"devDependencies": {
"@mdi/font": "^7.1.96",
Expand All @@ -43,6 +43,7 @@
"@types/three": "^0.149.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.0.0",
"@vue/compiler-sfc": "^3.5.24",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^12.0.0",
"@vue/tsconfig": "^0.5.1",
Expand Down
Binary file removed public/scrcpy-server-v2.6.1
Binary file not shown.
Binary file added public/scrcpy-server-v3.3.3
Binary file not shown.
18 changes: 9 additions & 9 deletions src/components/Device/AppManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@
确认卸载
</v-card-title>
<v-card-text>
确定要卸载 <strong>{{ selectedApp?.appName }}</strong> 吗?
确定要卸载 <strong>{{ selectedApp?.[0]?.appName }}</strong> 吗?
<div class="text-caption mt-2">
包名: {{ selectedApp?.packageName }}
包名: {{ selectedApp?.[0]?.packageName }}
</div>
</v-card-text>
<v-card-actions>
Expand All @@ -179,7 +179,7 @@
color="error"
variant="tonal"
@click="confirmUninstall"
:loading="selectedApp?.uninstalling"
:loading="selectedApp?.[0]?.uninstalling"
>
卸载
</v-btn>
Expand Down Expand Up @@ -226,7 +226,7 @@ const refreshAppList = async () => {
const appList: ExtendedPackageInfo[] = [];

// 使用 spawnAndWaitLegacy 方法执行命令
const output = await client.device.subprocess.spawnAndWaitLegacy([
const output = await client.device.subprocess.noneProtocol!.spawnWaitText([
'pm',
'list',
'packages',
Expand Down Expand Up @@ -275,7 +275,7 @@ const confirmUninstall = async () => {
try {
selectedApp.value[0].uninstalling = true;

const output = await client.device.subprocess.spawnAndWaitLegacy([
const output = await client.device.subprocess.noneProtocol!.spawnWaitText([
'pm',
'uninstall',
selectedApp.value[0].packageName
Expand Down Expand Up @@ -316,7 +316,7 @@ const launchApp = async (app: ExtendedPackageInfo) => {
if (!client.device) return;

try {
await client.device.subprocess.spawnAndWaitLegacy([
await client.device.subprocess.noneProtocol!.spawnWait([
'monkey',
'-p',
app.packageName,
Expand Down Expand Up @@ -353,7 +353,7 @@ const exportApk = async (app: ExtendedPackageInfo) => {
const tempDir = '/data/local/tmp';
const tempFile = `${tempDir}/${app.packageName}.apk`;

await client.device.subprocess.spawnAndWaitLegacy([
await client.device.subprocess.noneProtocol!.spawnWait([
'cp',
sourceDir,
tempFile
Expand All @@ -378,15 +378,15 @@ const exportApk = async (app: ExtendedPackageInfo) => {
exportProgress.value = (receivedLength / totalSize) * 100;
}

const blob = new Blob(chunks, { type: 'application/vnd.android.package-archive' });
const blob = new Blob(chunks as BlobPart[], { type: 'application/vnd.android.package-archive' });
saveAs(blob, `${app.packageName}.apk`);

errorType.value = 'success';
showError.value = true;
errorMessage.value = 'APK导出成功';
} finally {
await sync.dispose();
await client.device.subprocess.spawnAndWaitLegacy([
await client.device.subprocess.noneProtocol!.spawnWait([
'rm',
tempFile
]);
Expand Down
65 changes: 56 additions & 9 deletions src/components/Device/BatteryInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,33 @@
<v-card class="battery-card" flat>
<v-card-text class="pa-6">
<div class="text-h6 font-weight-regular mb-4">电池</div>
<div
class="d-flex flex-column align-center justify-center"
style="height: 180px"
>
<div class="d-flex flex-column align-center justify-center">
<div class="battery-circle">
<div class="battery-background"></div>
<div class="battery-level" :style="batteryLevelStyle"></div>
<div class="battery-text">{{ batteryPercentage }}%</div>
</div>
<div class="mt-4 text-subtitle-1">
{{ formattedVoltage }}V {{ temperature }}°C
<div class="mt-4 field-container">
<div class="field-item" v-if="!isNaN(batteryChargeCounter)">
<span class="field-item-label">剩余电量</span>
<span class="field-item-value">{{ batteryChargeCounter }}mAh</span>
</div>
<div class="field-item" v-if="!isNaN(batteryCurrent)">
<span class="field-item-label">当前电流</span>
<span class="field-item-value">{{ formattedBatteryCurrent }}mA</span>
</div>
<div class="field-item" v-if="!isNaN(voltage)">
<span class="field-item-label">电池电压</span>
<span class="field-item-value">{{ formattedVoltage }}V</span>
</div>
<div class="field-item" v-if="!isNaN(temperature)">
<span class="field-item-label">电池温度</span>
<span class="field-item-value">{{ temperature }}°C</span>
</div>
<div class="field-item" v-if="!isNaN(batteryHealth)">
<span class="field-item-label">电池健康</span>
<span class="field-item-value">{{ batteryHealth }}%</span>
</div>
</div>
</div>
</v-card-text>
Expand All @@ -36,6 +52,18 @@ const props = defineProps({
type: Number,
required: true,
},
batteryHealth: {
type: Number,
required: true,
},
batteryChargeCounter: {
type: Number,
required: true,
},
batteryCurrent: {
type: Number,
required: true,
},
});

const batteryLevelStyle = computed(() => {
Expand All @@ -47,6 +75,10 @@ const batteryLevelStyle = computed(() => {
const formattedVoltage = computed(() => {
return isNaN(props.voltage) ? '0.000' : props.voltage.toFixed(3);
});

const formattedBatteryCurrent = computed(() => {
return props.batteryCurrent > 0 ? `+${props.batteryCurrent}` : props.batteryCurrent;
});
</script>

<style scoped>
Expand All @@ -59,8 +91,8 @@ const formattedVoltage = computed(() => {

.battery-circle {
position: relative;
width: 140px;
height: 140px;
width: 100px;
height: 100px;
border-radius: 50%;
overflow: hidden;
margin: 0 auto;
Expand Down Expand Up @@ -90,9 +122,24 @@ const formattedVoltage = computed(() => {
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 24px;
font-size: 18px;
font-weight: 500;
z-index: 2;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.field-item {
width: 100%;
font-size: 14px;
}

.field-item-label {
font-weight: 500;
color: var(--v-text-primary);
margin-right: .5em;
}

.field-item-value {
color: var(--v-text-secondary);
}
</style>
62 changes: 40 additions & 22 deletions src/components/Device/DeviceBasicInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<div class="info-row">
<div class="info-label">品牌</div>
<div class="info-value">{{ deviceInfo.brand }}</div>
<div class="info-label">连接状态</div>
<div class="info-value">{{ deviceInfo.type }}</div>
<div class="info-label">root 状态</div>
<div class="info-value">{{ deviceInfo.rootState }}</div>
</div>
<div class="info-row">
<div class="info-label">型号</div>
Expand Down Expand Up @@ -43,16 +43,24 @@
<div class="info-label">显示密度</div>
<div class="info-value">{{ deviceInfo.screenDensity }}</div>
<div class="info-label">闪存类型</div>
<div class="info-value">{{ storageType }}</div>
<div class="info-value">{{ deviceInfo.storageType }}</div>
</div>
<div class="info-row">
<div class="info-label">IP 地址</div>
<div class="info-value">{{ deviceInfo.ipAddress || '-' }}</div>
</div>
<div class="info-row">
<div class="info-label">主板 ID</div>
<div class="info-value">{{ deviceInfo.board || '-' }}</div>
</div>
<div class="info-row">
<div class="info-label">平台</div>
<div class="info-label">硬件平台</div>
<div class="info-value full-width">{{ deviceInfo.hardware }}</div>
</div>
<div class="info-row">
<div class="info-label">序列号</div>
<div class="info-value full-width">{{ deviceInfo.serialNumber }}</div>
</div>
<div class="info-row">
<div class="info-label">编译版本</div>
<div class="info-value full-width">{{ deviceInfo.fingerPrint }}</div>
Expand All @@ -78,32 +86,42 @@ const props = defineProps({

// 计算属性:Bootloader 状态
const bootloaderStatus = computed(() => {
// 这里可以添加实际的 bootloader 状态检测逻辑
return 'locked';
if (['green'].includes(props.deviceInfo.bootloader)) {
return 'locked';
}
return 'unlocked';
});

// 计算属性:A/B 分区状态
const abPartitionStatus = computed(() => {
// 这里可以添加实际的 A/B 分区检测逻辑
return 'A-Only设备';
switch (props.deviceInfo.abPartition) {
case '_a':
return 'Slot A';
case '_b':
return 'Slot B';
default:
return 'Unknown';
}
});


const formatSeconds = (seconds) => {
const parts = [];
const d = Math.floor(seconds / 86400);
const h = Math.floor(seconds % 86400 / 3600);
const m = Math.floor(seconds % 3600 / 60);
const s = Math.floor(seconds % 60);

if (d) parts.push(d + '天');
if (h) parts.push(h + '小时');
if (m) parts.push(m + '分');
if (s || !parts.length) parts.push(s + '秒');

return parts.join('');
};
// 计算属性:开机时间
const uptime = computed(() => {
// 这里可以添加实际的开机时间计算逻辑
return '0天6时44分44秒';
});

// 计算属性:存储类型
const storageType = computed(() => {
// 这里可以添加实际的存储类型检测逻辑
return 'UFS';
});

// 计算属性:内核版本
const kernelVersion = computed(() => {
// 这里可以添加实际的内核版本获取逻辑
return '49.537-UOTAN-PE14-STABLE+';
return formatSeconds(props.deviceInfo.uptime);
});
</script>

Expand Down
Loading