diff --git a/package.json b/package.json
index d1bad508..53e9f729 100644
--- a/package.json
+++ b/package.json
@@ -43,12 +43,16 @@
"husky": "^8.0.0",
"lodash-es": "^4.17.21",
"pinia": "^2.1.7",
+ "postcss": "^8.4.31",
+ "postcss-nested": "^6.0.1",
+ "postcss-scss": "^4.0.9",
"typescript": "^5.2.2",
"vite": "^4.5.0",
"vite-plugin-electron": "^0.14.1",
"vite-plugin-electron-renderer": "^0.14.5",
"vite-plugin-eslint": "^1.8.1",
"vite-svg-loader": "^4.0.0",
+ "vue-command": "^35.2.1",
"vue-i18n": "^9.5.0",
"which": "^4.0.0"
}
diff --git a/postcss.config.mjs b/postcss.config.mjs
new file mode 100644
index 00000000..49e53551
--- /dev/null
+++ b/postcss.config.mjs
@@ -0,0 +1,7 @@
+import nested from 'postcss-nested'
+import postcssScss from 'postcss-scss'
+
+export default {
+ parser: postcssScss,
+ plugins: [nested],
+}
diff --git a/src/components/Device/components/Terminal/components/TerminalDialog/composables/adb.js b/src/components/Device/components/Terminal/components/TerminalDialog/composables/adb.js
new file mode 100644
index 00000000..1c98529b
--- /dev/null
+++ b/src/components/Device/components/Terminal/components/TerminalDialog/composables/adb.js
@@ -0,0 +1,24 @@
+import { createStderr, createStdout } from 'vue-command'
+
+const $adb = window.adbkit
+
+export function useAdb({ loading }) {
+ const adb = async (args) => {
+ loading.value = true
+ const command = args.slice(1).join(' ')
+
+ const { stderr, stdout } = await $adb.shell(command || 'help')
+
+ if (stderr) {
+ return createStderr(stderr)
+ }
+
+ loading.value = false
+
+ return createStdout(stdout)
+ }
+
+ return {
+ adb,
+ }
+}
diff --git a/src/components/Device/components/Terminal/components/TerminalDialog/composables/gnirehtet.js b/src/components/Device/components/Terminal/components/TerminalDialog/composables/gnirehtet.js
new file mode 100644
index 00000000..b9147566
--- /dev/null
+++ b/src/components/Device/components/Terminal/components/TerminalDialog/composables/gnirehtet.js
@@ -0,0 +1,50 @@
+import { debounce } from 'lodash-es'
+import { createStderr, createStdout, textFormatter } from 'vue-command'
+
+const $gnirehtet = window.gnirehtet
+
+const fixCursor = (history) => {
+ const length = history.value.length
+ if (history.value[length - 1]?.__name === 'VueCommandQuery') {
+ history.value.splice(length - 1, 1, textFormatter('Waiting...'))
+ }
+}
+
+export function useGnirehtet({ vShell, history, loading } = {}) {
+ const gnirehtet = async (args) => {
+ loading.value = true
+
+ const command = args.slice(1).join(' ')
+
+ const appendToHistory = debounce(vShell.value.appendToHistory, 500)
+
+ let stdoutText = ''
+ let stderrText = ''
+ $gnirehtet.shell(command, {
+ stdout(text) {
+ loading.value = false
+
+ stdoutText += text
+
+ fixCursor(history)
+
+ appendToHistory(createStdout(stdoutText))
+ },
+ stderr(text) {
+ loading.value = false
+
+ stderrText += text
+
+ fixCursor(history)
+
+ appendToHistory(createStderr(stderrText))
+ },
+ })
+
+ return textFormatter('Loading...')
+ }
+
+ return {
+ gnirehtet,
+ }
+}
diff --git a/src/components/Device/components/Terminal/components/TerminalDialog/composables/scrcpy.js b/src/components/Device/components/Terminal/components/TerminalDialog/composables/scrcpy.js
new file mode 100644
index 00000000..4f8ca327
--- /dev/null
+++ b/src/components/Device/components/Terminal/components/TerminalDialog/composables/scrcpy.js
@@ -0,0 +1,50 @@
+import { debounce } from 'lodash-es'
+import { createStderr, createStdout, textFormatter } from 'vue-command'
+
+const $scrcpy = window.scrcpy
+
+const fixCursor = (history) => {
+ const length = history.value.length
+ if (history.value[length - 1]?.__name === 'VueCommandQuery') {
+ history.value.splice(length - 1, 1, textFormatter('Waiting...'))
+ }
+}
+
+export function useScrcpy({ vShell, history, loading } = {}) {
+ const scrcpy = async (args) => {
+ loading.value = true
+
+ const command = args.slice(1).join(' ')
+
+ const appendToHistory = debounce(vShell.value.appendToHistory, 500)
+
+ let stdoutText = ''
+ let stderrText = ''
+ $scrcpy.shell(command, {
+ stdout(text) {
+ loading.value = false
+
+ stdoutText += text
+
+ fixCursor(history)
+
+ appendToHistory(createStdout(stdoutText))
+ },
+ stderr(text) {
+ loading.value = false
+
+ stderrText += text
+
+ fixCursor(history)
+
+ appendToHistory(createStderr(stderrText))
+ },
+ })
+
+ return textFormatter('Loading...')
+ }
+
+ return {
+ scrcpy,
+ }
+}
diff --git a/src/components/Device/components/Terminal/components/TerminalDialog/index.vue b/src/components/Device/components/Terminal/components/TerminalDialog/index.vue
new file mode 100644
index 00000000..f0c8c74a
--- /dev/null
+++ b/src/components/Device/components/Terminal/components/TerminalDialog/index.vue
@@ -0,0 +1,113 @@
+
+