From 38d1433a82d6c22c9bb6db681533c93e788e4cff Mon Sep 17 00:00:00 2001
From: viarotel <viarotel@foxmail.com>
Date: Sat, 28 Dec 2024 19:02:33 +0800
Subject: [PATCH] =?UTF-8?q?perf:=20=E2=99=BB=EF=B8=8F=20Optimize=20device?=
 =?UTF-8?q?=20details=20performance?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 electron/exposes/adb/index.js                 | 26 +++-----
 package.json                                  |  2 +-
 src/components/ControlBar/index.vue           |  2 +-
 .../device/components/DevicePopover/index.vue | 63 ++++++++++++++-----
 src/pages/device/index.vue                    | 13 +---
 5 files changed, 61 insertions(+), 45 deletions(-)

diff --git a/electron/exposes/adb/index.js b/electron/exposes/adb/index.js
index a560c4ba..2b52b197 100644
--- a/electron/exposes/adb/index.js
+++ b/electron/exposes/adb/index.js
@@ -128,18 +128,12 @@ const tcpip = async (id, port = 5555) => client.getDevice(id).tcpip(port)
 const screencap = async (deviceId, options = {}) => {
   const { returnBase64 = false } = options
 
-  let fileStream = null
-  try {
-    const device = client.getDevice(deviceId)
-    fileStream = await device.screencap()
-  }
-  catch (error) {
-    console.warn(error?.message || error)
-    return false
-  }
+  const device = client.getDevice(deviceId)
+
+  const fileStream = await device.screencap()
 
   if (!fileStream) {
-    return false
+    throw new Error('Failed to obtain screenshot data')
   }
 
   if (returnBase64) {
@@ -292,17 +286,11 @@ async function connectCode(password, options = {}) {
 }
 
 async function battery(id) {
-  try {
-    const res = await deviceShell(id, 'dumpsys battery')
+  const res = await deviceShell(id, 'dumpsys battery')
 
-    const value = parseBatteryDump(res)
+  const value = parseBatteryDump(res)
 
-    return value
-  }
-  catch (error) {
-    console.warn(error?.message || error)
-    return {}
-  }
+  return value
 }
 
 function init() {
diff --git a/package.json b/package.json
index bd1aae18..a794ac88 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
   },
   "devDependencies": {
     "@antfu/eslint-config": "3.8.0",
-    "@devicefarmer/adbkit": "3.2.6",
+    "@devicefarmer/adbkit": "3.3.8",
     "@electron-toolkit/preload": "3.0.1",
     "@electron-toolkit/utils": "3.0.0",
     "@electron/remote": "2.1.2",
diff --git a/src/components/ControlBar/index.vue b/src/components/ControlBar/index.vue
index 0838d5b6..9a33203a 100644
--- a/src/components/ControlBar/index.vue
+++ b/src/components/ControlBar/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    class="bg-primary-100 dark:bg-gray-800 flex items-center group h-9 overflow-hidden"
+    class="bg-primary-100 dark:bg-gray-800 flex items-center group h-7 lg:h-9 overflow-hidden"
   >
     <el-button
       type="primary"
diff --git a/src/pages/device/components/DevicePopover/index.vue b/src/pages/device/components/DevicePopover/index.vue
index 719b2ba4..8981d8ec 100644
--- a/src/pages/device/components/DevicePopover/index.vue
+++ b/src/pages/device/components/DevicePopover/index.vue
@@ -3,10 +3,10 @@
     ref="popoverRef"
     placement="right"
     :width="500"
-    trigger="click"
+    trigger="hover"
     popper-class="!p-0 !overflow-hidden !rounded-xl"
     @before-enter="onBeforeEnter"
-    @hide="onHide"
+    @after-leave="onAfterLeave"
   >
     <template #reference>
       <el-link type="primary" :underline="false" icon="InfoFilled" class="mr-1"></el-link>
@@ -14,7 +14,7 @@
 
     <div v-loading="loading" :element-loading-text="$t('common.loading')" :class="connectFlag ? 'h-60' : ''" class="flex items-stretch p-2 space-x-2">
       <div v-if="connectFlag" class="flex-none pb-1">
-        <el-image :src="deviceInfo.screencap" :preview-src-list="[deviceInfo.screencap]" class="!h-full !overflow-hidden !rounded-xl !shadow" />
+        <img :src="deviceInfo.screencap" class="!h-full !overflow-hidden !rounded-xl !shadow min-w-24 max-w-56 bg-gray-200 dark:bg-black object-contain cursor-pointer" alt="" @click="handlePreview" />
       </div>
 
       <div class="flex-1 w-0 overflow-auto">
@@ -43,6 +43,8 @@
         </el-descriptions>
       </div>
     </div>
+
+    <el-image-viewer v-if="imageViewerProps.visible" :url-list="[deviceInfo.screencap]" @close="onViewerClose" />
   </el-popover>
 </template>
 
@@ -67,6 +69,18 @@ const connectFlag = computed(() => ['device'].includes(props.device.status))
 
 const screencapTimer = ref()
 
+const imageViewerProps = ref({
+  visible: false,
+})
+
+function handlePreview() {
+  imageViewerProps.value.visible = true
+}
+
+function onViewerClose() {
+  imageViewerProps.value.visible = false
+}
+
 async function onBeforeEnter() {
   Object.assign(deviceInfo.value, { ...props.device })
 
@@ -74,37 +88,58 @@ async function onBeforeEnter() {
     return false
   }
 
-  loading.value = true
-
-  await Promise.allSettled([getScreencap(), getBattery()])
+  if (!deviceInfo.value.screencap) {
+    loading.value = true
+  }
 
   screencapTimer.value = setInterval(() => {
     getScreencap()
     getBattery()
   }, 5 * 1000)
 
+  await Promise.allSettled([getScreencap(), getBattery()])
+
   loading.value = false
 }
 
 async function getScreencap() {
-  const screencap = await window.adb.screencap(props.device.id, { returnBase64: true })
-
-  Object.assign(deviceInfo.value, { screencap: `data:image/png;base64,${screencap}` })
+  try {
+    const screencap = await window.adb.screencap(props.device.id, { returnBase64: true })
+    Object.assign(deviceInfo.value, { screencap: `data:image/png;base64,${screencap}` })
+  }
+  catch (error) {
+    onError()
+    console.warn(error?.message || error)
+  }
 }
 
 async function getBattery() {
-  const battery = await window.adb.battery(props.device.id)
-
-  Object.assign(deviceInfo.value, { battery: battery.computed })
+  try {
+    const battery = await window.adb.battery(props.device.id)
+    Object.assign(deviceInfo.value, { battery: battery.computed })
+  }
+  catch (error) {
+    onError()
+    console.warn(error?.message || error)
+  }
 }
 
-function onHide() {
+function onAfterLeave() {
   clearInterval(screencapTimer.value)
 
-  deviceInfo.value = {}
+  onViewerClose()
 
   loading.value = false
 }
+
+function onError() {
+  clearInterval(screencapTimer.value)
+  props.device.status = 'offline'
+}
+
+onBeforeUnmount(() => {
+  onAfterLeave()
+})
 </script>
 
 <style lang="postcss" scoped>
diff --git a/src/pages/device/index.vue b/src/pages/device/index.vue
index 7a8868f1..18c2c57e 100644
--- a/src/pages/device/index.vue
+++ b/src/pages/device/index.vue
@@ -33,7 +33,7 @@
         >
           <template #default="{ row }">
             <div class="flex items-center">
-              <DevicePopover :device="row" />
+              <DevicePopover :key="row.status" :device="row" />
 
               <span class="">
                 {{ row.name }}
@@ -157,7 +157,7 @@
 </template>
 
 <script>
-import { isIPWithPort, sleep } from '$/utils/index.js'
+import { sleep } from '$/utils/index.js'
 import BatchActions from './components/BatchActions/index.vue'
 import ControlBar from '$/components/ControlBar/index.vue'
 import MirrorAction from './components/MirrorAction/index.vue'
@@ -219,7 +219,7 @@ export default {
       return uniqBy(value, 'value')
     },
   },
-  async created() {
+  async mounted() {
     this.getDeviceData()
     this.unAdbWatch = await this.$adb.watch(this.onAdbWatch)
   },
@@ -243,13 +243,6 @@ export default {
         this.getDeviceData()
       }
 
-      if (type === 'add' && !isIPWithPort(ret.id) && ret.$host) {
-        this.formData = {
-          ...this.formData,
-          host: ret.$host,
-        }
-      }
-
       if (type === 'remove') {
         this.mirrorActionRefs = this.mirrorActionRefs.filter(
           item => item.row.id !== ret.id,