Переглянути джерело

Merge branch '3.1.0' of Karl/MiWatchKleaner into master

Karl 3 роки тому
батько
коміт
a2cb5a7a49
15 змінених файлів з 650 додано та 381 видалено
  1. 1 2
      .gitignore
  2. 2 1
      app.js
  3. 6 3
      buildRelease.sh
  4. 0 2
      data/xiaomiPackageRemovalList.json
  5. 56 0
      lang/en.json
  6. 55 0
      lang/es.json
  7. 167 13
      lib/adb.js
  8. 47 9
      lib/common.js
  9. 15 2
      lib/files.js
  10. 1 0
      lib/globalVars.js
  11. 58 28
      lib/inquirer.js
  12. 0 11
      logger.lock
  13. 86 32
      package-lock.json
  14. 3 1
      package.json
  15. 153 277
      pages/pages.js

+ 1 - 2
.gitignore

@@ -1,8 +1,7 @@
 node_modules/
-data/MiWatch.json
 data/apps/*.apk
 release/
 data/*.log
 logger.lock
 null.log
-.gitignore
+my_apk/*.apk

+ 2 - 1
app.js

@@ -1,3 +1,4 @@
 const pages = require('./pages/pages')
 
-pages.connectWatch();
+pages.selectLanguage()
+

+ 6 - 3
buildRelease.sh

@@ -8,15 +8,18 @@ mv ./release/miwatchkleaner-macos-* ./release/MacOs && \
 cp ./data/xiaomiPackageRemovalList.json ./release/Windows/data/ && \
 cp ./data/xiaomiPackageRemovalList.json ./release/MacOS/data/ && \
 cp ./data/xiaomiPackageRemovalList.json ./release/Linux/data/ && \
+cp -rf ./lang/ ./release/Windows/ && \
+cp -rf ./lang/ ./release/MacOS/ && \
+cp -rf ./lang/ ./release/Linux/ && \
 chmod 0777 ./release/**/adb && \
 chmod 0777 ./release/**/miwatchkleaner-* && \
 chmod +x ./release/**/adb && \
 chmod +x ./release/**/miwatchkleaner-* && \
 cd release/MacOS/ && \
-tar -pcvzf miwatchkleaner.$buildNum-macos.tar.gz adb data/ my_apk/ miwatchkleaner-macos-x64 && \
+tar -pcvzf miwatchkleaner.$buildNum-macos.tar.gz adb data/ my_apk/ lang/ miwatchkleaner-macos-x64 && \
 cd .. && \
 cd Linux/ && \
-tar -pcvzf miwatchkleaner.$buildNum-Linux.tar.gz adb data/ my_apk/ miwatchkleaner-linux-x64 && \
+tar -pcvzf miwatchkleaner.$buildNum-Linux.tar.gz adb data/ my_apk/ lang/ miwatchkleaner-linux-x64 && \
 cd .. && \
 cd Windows/ && \
-zip -r miwatchkleaner.$buildNum-win.zip adb.exe AdbWinApi.dll AdbWinUsbApi.dll data/ my_apk/ miwatchkleaner-win-x86.exe
+zip -r miwatchkleaner.$buildNum-win.zip adb.exe AdbWinApi.dll AdbWinUsbApi.dll data/ my_apk/ lang/ miwatchkleaner-win-x86.exe

+ 0 - 2
data/xiaomiPackageRemovalList.json

@@ -1,7 +1,6 @@
 {
   "apps": [
       "com.android.messaging",
-      "com.eg.android.AlipayGphone",
       "com.google.android.clockwork.flashlight",
       "com.google.android.clockwork.gestures.tutorial",
       "com.google.android.clockwork.lesetup",
@@ -12,7 +11,6 @@
       "com.google.android.wearable.overlay.common.baiji",
       "com.google.android.wearable.overlay.helium.baiji",
       "com.google.android.wearable.overlay.home.baiji",
-      "com.google.android.wearable.overlay.home.baiji",
       "com.google.android.wearable.overlay.home.baiji.tiles",
       "com.gotokeep.keep",
       "com.onetrack.watch",

+ 56 - 0
lang/en.json

@@ -0,0 +1,56 @@
+{
+    "main-menu-question": "What do you want to do?",
+    "main-menu-item-1": "1-Click Karl0ss Klean",
+    "main-menu-item-2": "Remove Xiaomi Apps",
+    "main-menu-item-3": "Restore Xiaomi Apps",
+    "main-menu-item-4": "Install Compatible Apps",
+    "main-menu-item-5": "Restore ANY app",
+    "main-menu-item-6": "Remove ANY app",
+    "main-menu-item-7": "Batch Install Apps",
+    "main-menu-item-8": "Batch Remove Installed Apps",
+    "main-menu-item-9": "Quit",
+    "connection-type-message": "How do you want to connect?",
+    "connect-wifi-message":"What is your MiWatch IpAdress?",
+    "restore-app-message": "What apps do you want to restore?",
+    "install-compatible-apps-message": "What apps do you want to Install?",
+    "remove-installed-apps-message": "What Installed apps do you want to remove?",
+    "restore-any-app-message": "What App do you want to restore?",
+    "header-remove-installed-apps": "Remove Installed Apps",
+    "packages-recieved-from-watch": "Packages recieved from watch",
+    "device-not-authorised": "Device not authorised",
+    "restarting-adb": "Restarting ADB",
+    "please-reconnect-to-watch": "Please reconnect to watch",
+    "remove-installed-apps-failed": "Remove Installed Apps Failed",
+    "removing": "Removing",
+    "removal-complete": "Removal Complete",
+    "installing": "Installing",
+    "restoring": "Restoring",
+    "remove-selected-user-apps": "Removed Selected User Apps",
+    "install-compatible-apps-header": "Install Compatible Apps",
+    "simple-weather-activated-on-watch": "simpleWeather Activated On Watch",
+    "morelocale-activated-on-watch": "moreLocale Activated On Watch",
+    "alberto-locale-activated-on-watch": "Alberto Locale Activated On Watch",
+    "compatible-apps-installed": "Compatible Apps Installed",
+    "compatible-apps": "Compatible Apps",
+    "remove-xiaomi-apps": "Remove Xiaomi Apps",
+    "downloading-compatible-apps": "Downloading Compatible Apps",
+    "installing-apps": "Installing Apps",
+    "downloading-latest": "Downloading Latest",
+    "complete": "Complete",
+    "failed": "Failed",
+    "restoring-apps-complete": "Restoring Apps Complete",
+    "batch-install-apps-complete": "Batch Install Apps Complete",
+    "connect-to-watch": "Connect to watch",
+    "connected-via-usb": "Connected via USB",
+    "connected-via-wifi": "Connected via Wifi",
+    "connected": "Connected",
+    "not-connected": "Not Connected",
+    "error-device-not-authorised": "Error - Device not authorised",
+    "not-found": "Not Found",
+    "try-again": "Try Again",
+    "connect-wifi-complete": "Connect Wifi Complete",
+    "not-authenticated": "Not Authenticated",
+    "error": "Error",
+    "remove-any-app-message": "What App do you want to remove?",
+    "removing-apps-complete": "Removing Apps Complete"
+}

+ 55 - 0
lang/es.json

@@ -0,0 +1,55 @@
+{
+    "main-menu-question": "¿Qué quieres hacer?",
+    "main-menu-item-1": "1-Click Karl0ss Klean",
+    "main-menu-item-2": "Eliminar aplicaciones Xiaomi",
+    "main-menu-item-3": "Restaurar aplicaciones Xiaomi",
+    "main-menu-item-4": "Instalar aplicaciones compatibles",
+    "main-menu-item-5": "Restaura CUALQUIER aplicación",
+    "main-menu-item-6": "Eliminar CUALQUIER aplicación",
+    "main-menu-item-7": "Aplicaciones de instalación por lotes",
+    "main-menu-item-8": "Eliminar por lotes las aplicaciones instaladas",
+    "main-menu-item-9": "Salir",
+    "connection-type-message": "¿Cómo desea conectarse?",
+    "connect-wifi-message":"¿Cuál es su MiWatch IpAdress?",
+    "restore-app-message": "¿Qué aplicaciones quieres restaurar?",
+    "install-compatible-apps-message": "¿Qué aplicaciones quieres instalar?",
+    "remove-installed-apps-message": "¿Qué aplicaciones instaladas desea eliminar?",
+    "restore-any-app-message": "¿Qué aplicación desea restaurar?",
+    "header-remove-installed-apps": "Eliminar aplicaciones instaladas",
+    "packages-recieved-from-watch": "Paquetes recibidos desde watch",
+    "device-not-authorised": "Dispositivo no autorizado",
+    "restarting-adb": "Reiniciando ADB",
+    "please-reconnect-to-watch": "Vuelve a conectarte para mirar",
+    "remove-installed-apps-failed": "Falló la eliminación de aplicaciones instaladas",
+    "removing": "Eliminando",
+    "removal-complete": "Eliminación completa",
+    "installing": "Instalando",
+    "restoring": "Restaurando",
+    "remove-selected-user-apps": "Aplicaciones de usuario seleccionadas eliminadas",
+    "install-compatible-apps-header": "Instalar aplicaciones compatibles",
+    "simple-weather-activated-on-watch": "simpleWeather activado en el reloj",
+    "morelocale-activated-on-watch": "moreLocale activado durante el reloj",
+    "alberto-locale-activated-on-watch": "Alberto Locale activado durante el reloj",
+    "compatible-apps-installed": "Aplicaciones compatibles instaladas",
+    "compatible-apps": "Aplicaciones compatibles",
+    "remove-xiaomi-apps": "Eliminar aplicaciones Xiaomi",
+    "downloading-compatible-apps": "Descarga de aplicaciones compatibles",
+    "installing-apps": "Instalar aplicaciones",
+    "downloading-latest": "Descargando la última",
+    "complete": "Completo",
+    "failed": "Falló",
+    "restoring-apps-complete": "Restauración de aplicaciones completa",
+    "batch-install-apps-complete": "Instalación por lotes de aplicaciones completa",
+    "connect-to-watch": "Conectarse al reloj",
+    "connected-via-usb": "Conectado mediante USB",
+    "connected-via-wifi": "Conectado a través de Wifi",
+    "not-connected": "No conectado",
+    "error-device-not-authorised": "Error - Dispositivo no autorizado",
+    "not-found": "No encontrado",
+    "try-again": "Inténtalo de nuevo",
+    "connect-wifi-complete": "Conectar Wifi Completo",
+    "not-authenticated": "No autenticado",
+    "error": "Error",
+    "remove-any-app-message": "¿Qué aplicación quieres eliminar?",
+    "removing-apps-complete": "Eliminación de aplicaciones completa"
+}

+ 167 - 13
lib/adb.js

@@ -1,24 +1,178 @@
 const gfin = require('get-files-in')
+const logger = require('perfect-logger');
 const shellExec = require('shell-exec')
+const Language = require("@shypes/language-translator");
+const inquirer = require('../lib/inquirer');
+const common = require('./common')
+const chalk = require('chalk');
+const globalVariables = require('../lib/globalVars');
+const { dualLog } = require('./common');
+
+if (process.platform === 'win32' || process.platform === 'win64') {
+  adbRun = 'adb'
+} else {
+  adbRun = './adb'
+}
 
 module.exports = {
-  getListOfAPk: () => {
-    this.apkListToInstall = gfin('./data/apps', matchFiletypes = ["apk"], checkSubDirectories = false)
+  installApk: async (element) => {
+    Language.setActiveLang(globalVariables.language)
+    result = await shellExec(adbRun + ' install -r ' + element).then(async function (result) {
+      if (result.stderr != '') {
+        common.dualLog('device-not-authorised' + ' ' + result.stderr, 'red')
+      }
+      common.dualLog(element + ' - ' + result.stdout)
+
+      if (element === "data\\apps\\simpleweather_base.apk") {
+        await common.downloadFile('http://kithub.cf/Karl/MiWatchKleaner-APKs/raw/master/Others/simpleweather_split_config.armeabi_v7a.apk', './data/apps/simpleweather_split_config.armeabi_v7a.apk')
+        await common.downloadFile('http://kithub.cf/Karl/MiWatchKleaner-APKs/raw/master/Others/simpleweather_split_config.xhdpi.apk', './data/apps/simpleweather_split_config.xhdpi.apk')
+        await shellExec(adbRun + ' install-multiple "data\\apps\\simpleweather_base.apk" "data\\apps\\simpleweather_split_config.armeabi_v7a.apk" "data\\apps\\simpleweather_split_config.xhdpi.apk"').then(async function (result) {
+          common.log(result)
+          common.dualLog('simple-weather-activated-on-watch')
+        })
+      }
+      if (element === "data\\apps\\MoreLocale.apk") {
+        await shellExec(adbRun + ' shell pm grant jp.co.c_lis.ccl.morelocale android.permission.CHANGE_CONFIGURATION').then(async function (result) {
+          common.log(result)
+          common.dualLog('morelocale-activated-on-watch')
+        })
+      }
+      if (element === "data\\apps\\AlbertoLocale.apk") {
+        await shellExec(adbRun + ' shell pm grant com.alberto.locale android.permission.CHANGE_CONFIGURATION && ' + adbRun + ' shell am start -n com.alberto.locale/com.alberto.locale.MainActivity && ' + adbRun + ' shell pm grant com.alberto.locale android.permission.CHANGE_CONFIGURATION').then(async function (result) {
+          common.log(result)
+          common.dualLog('alberto-locale-activated-on-watch')
+        });
+      }
+    });
   },
-  installApk: async () => {
-    await module.exports.getListOfAPk()
-    for (let element of this.apkListToInstall) {
+  removeApk: async (package) => {
+    Language.setActiveLang(globalVariables.language)
+    result = await shellExec(adbRun + ' uninstall ' + package)
+    if (result.stderr != '') {
+      common.dualLog('device-not-authorised' + ' ' + result.stderr, 'red')
+    } else {
+      common.dualLog(await Language.get('removing') + ' ' + package + ' - ' + result.stdout)
+    }
+  },
+  removeXiaomiApk: async (package) => {
+    Language.setActiveLang(globalVariables.language)
+    result = await shellExec(adbRun + ' shell pm uninstall -k --user 0 ' + package)
+    if (result.stderr != '') {
+      common.dualLog('device-not-authorised' + ' ' + result.stderr, 'red')
+    } else {
+      common.dualLog(await Language.get('removing') + ' ' + package + ' - ' + result.stdout)
+    }
+  },
+  restoreXiaomiApk: async (package) => {
+    Language.setActiveLang(globalVariables.language)
+    result = await shellExec(adbRun + ' shell cmd package install-existing ' + package)
+    if (result.stderr != '') {
+      common.dualLog('device-not-authorised' + ' ' + result.stderr, 'red')
+    } else {
+      common.dualLog(await Language.get('removing') + ' ' + package + ' - ' + result.stdout)
+    }
+  },
+  restoreAnyApk: async (package) => {
+    Language.setActiveLang(globalVariables.language)
+    result = await shellExec(adbRun + ' shell cmd package install-existing ' + package.restoreAnyApp)
+    if (result.stderr != '') {
+      common.dualLog('device-not-authorised' + ' ' + result.stderr, 'red')
+    } else if (result.stdout.includes('doesn\'t exist')) {
+      logger.info(result.stdout);
+      console.log(chalk.redBright(result.stdout));
+    } else {
+      common.dualLog(await Language.get('restoring') + ' ' + package + ' - ' + result.stdout)
+    }
+  },
+  removeAnyApk: async (package) => {
+    Language.setActiveLang(globalVariables.language)
+    result = await shellExec(adbRun + ' shell pm uninstall -k --user 0 ' + package.removeAnyApp)
+    if (result.stderr != '') {
+      common.dualLog('device-not-authorised' + ' ' + result.stderr, 'red')
+    } else if (result.stdout.includes('doesn\'t exist')) {
+      logger.info(result.stdout);
+      console.log(chalk.redBright(result.stdout));
+    } else {
+      common.dualLog(await Language.get('removing') + ' ' + package + ' - ' + result.stdout)
+    }
+  },
+  getInstalledPacakges: async () => {
+    Language.setActiveLang(globalVariables.language)
+    result = await shellExec(adbRun + ' shell pm list packages -3')
+    logger.info(await Language.get('packages-recieved-from-watch'))
+    if (result.stderr.includes('error')) {
+      logger.info(result.stderr)
+      console.log(chalk.red(await Language.get('device-not-authorised')))
+      common.pause(3000)
+      await shellExec(adbRun + ' kill-server').then(async function (result) {
+        logger.info(await Language.get('restarting-adb'))
+        logger.info(result.stdout)
+        console.log(await Language.get('please-reconnect-to-watch'))
+        common.pause(3000)
+        logger.info(await Language.get('remove-installed-apps-failed'))
+        module.exports.mainMenu()
+      })
+    } else {
       if (process.platform === 'win32' || process.platform === 'win64') {
-        await shellExec('adb install -r ' + element).then(function (result) {
-          console.log('Installing ' + element + ' - ' + result.stdout);
-        });
+        installedAppList = result.stdout.split('\r\n'); // split string on comma space
+        installedAppList.splice(-1, 1)
       } else {
-        await shellExec('./adb install -r ' + element).then(function (result) {
-          console.log('Installing ' + element + ' - ' + result.stdout);
-        });
+        installedAppList = result.stdout.split('\n'); // split string on comma space
+        installedAppList.splice(-1, 1)
       }
+      const value = await inquirer.installedApps(installedAppList);
+      return value
     }
-    // console.log(chalk.green('Removal Complete'))
   },
-
+  killAdbServer: async () => {
+    Language.setActiveLang(globalVariables.language)
+    let result = await shellExec(adbRun + ' kill-server')
+    // common.log('')
+    // common.dualLog('restarting-adb' + ' ' + result.stderr, 'red')
+  },
+  watchConnection: async (value) => {
+    Language.setActiveLang(globalVariables.language)
+    if (value.connection === "usb") {
+      await module.exports.killAdbServer()
+      result = await shellExec(adbRun + ' devices')
+      console.log(result.stdout)
+      if (result.stdout.includes('device', 15)) {
+        common.dualLog(await Language.get('connected-via-usb', 'green'))
+        await common.pause(3000)
+        globalVariables.localUSB = "X"
+        return true
+      } else {
+        common.dualLog(await Language.get('not-found', 'red'))
+        await common.pause(2000)
+        common.dualLog(await Language.get('try-again', 'white'))
+        await common.pause(1000)
+        return false
+      }
+    }
+    if (value.connection === "wifi") {
+      const value = await inquirer.connectWifi();
+      await module.exports.killAdbServer()
+      result = await shellExec(adbRun + ' connect ' + value.connectWifi)
+      logger.info("Connect Wifi Result " + result.stdout)
+      if (result.stdout.includes('already connected') || result.stdout.includes('connected to ')) {
+        common.dualLog(await Language.get('connected', 'green'))
+        globalVariables.localUSB = ""
+        globalVariables.miWatchIpaddress = value.connectWifi
+        await common.pause(3000)
+        common.dualLog(await Language.get('connect-wifi-complete', 'green'))
+        return true
+      } else {
+        if (result.stdout.includes('failed to authenticate')) {
+          common.dualLog(await Language.get('not-authenticated', 'red'))
+          return false
+        } else {
+          common.dualLog(result.stdout, 'red')
+        }
+        await common.pause(2000)
+        common.dualLog('try-again', '')
+        await common.pause(1000)
+        return false
+      }
+    }
+  }
 };

+ 47 - 9
lib/common.js

@@ -5,14 +5,17 @@ const fs = require('fs')
 var pjson = require('../package.json');
 const fetch = require('node-fetch');
 var shell = require('shelljs');
-
+const logger = require('perfect-logger');
+const Language = require("@shypes/language-translator");
 const globalVariables = require('../lib/globalVars');
+var chalkRainbow = require('chalk-rainbow')
 
 module.exports = {
-    header: (page) => {
+    header: async (page) => {
+        Language.setActiveLang(globalVariables.language)
         clear();
         console.log(
-            chalk.red(
+            chalkRainbow(
                 figlet.textSync('MiWatch Kleaner', {
                     horizontalLayout: 'full'
                 })
@@ -20,13 +23,12 @@ module.exports = {
         );
         console.log(chalk.red('                                                                                     ' + pjson.version));
         console.log();
-
         console.log(
             chalk.red(
                 '-------------------------------------------------------------------------------------------------------'
             )
         )
-        console.log(chalk.blue(page))
+        console.log(chalk.blue(await Language.get(page)))
         module.exports.connectionCheck()
         console.log(chalk.red('----------'))
     },
@@ -34,19 +36,22 @@ module.exports = {
         await new Promise(resolve => setTimeout(resolve, time));
     },
     connectionCheck: async () => {
+        Language.setActiveLang(globalVariables.language)
         if (globalVariables.localUSB === "X") {
-            console.log(chalk.white('MiWatch: ') + chalk.green('Connected via USB'))
+            console.log(chalk.white('MiWatch: ') + chalk.green(await Language.get('connected-via-usb')))
         }
         if (globalVariables.miWatchIpaddress != "") {
-            console.log(chalk.white('MiWatch: ') + chalk.green('Connected via Wifi - ' + chalk.white(globalVariables.miWatchIpaddress)))
+            console.log(chalk.white('MiWatch: ') + chalk.green(await Language.get('connected-via-wifi') + ' ' + chalk.white(globalVariables.miWatchIpaddress)))
         }
         if (globalVariables.localUSB === "" && globalVariables.miWatchIpaddress === "") {
-            console.log(chalk.white('MiWatch: ') + chalk.red('Not Connected'))
+            console.log(chalk.white('MiWatch: ') + chalk.red(await Language.get('not-connected')))
         }
     },
     downloadFile: async (url, path) => {
+        Language.setActiveLang(globalVariables.language)
         const res = await fetch(url);
-        await new Promise((resolve, reject) => {
+        // await module.exports.downloadSize(url)
+        await new Promise(async (resolve, reject) => {
             const fileStream = fs.createWriteStream(path);
             res.body.pipe(fileStream);
             res.body.on("error", (err) => {
@@ -57,6 +62,12 @@ module.exports = {
             });
         });
     },
+    downloadSize: async (url) => {
+        remote(url, function (err, o) {
+            console.log(o)
+            console.log(err)
+        })
+    },
     getCompatibleAppsList: async () => {
         let settings = { method: "Get" };
         const response = await fetch("http://kithub.cf/Karl/MiWatchKleaner-APKs/raw/master/compatibleApps.json", settings)
@@ -66,4 +77,31 @@ module.exports = {
     clearApkFolder: async () => {
         await shell.rm('-rf', './data/apps/*.apk');
     },
+    log: async (item) => {
+        logger.info(await Language.get(item, 'en'))
+    },
+    print: async (item, colour) => {
+        Language.setActiveLang(globalVariables.language)
+        switch (colour) {
+            case 'green':
+                console.log(chalk.green(await Language.get(item)))
+                break;
+            case 'red':
+                console.log(chalk.redBright(await Language.get(item)))
+                break;
+            case 'whiteBright':
+                console.log(chalk.whiteBright(await Language.get(item)))
+                break;
+            case 'rainbow':
+                console.log(chalkRainbow(await Language.get(item)))
+                break;
+            default:
+                console.log(chalk.white(await Language.get(item)))
+                break;
+        }
+    },
+    dualLog: async (item, colour) => {
+        await module.exports.log(item)
+        await module.exports.print(item, colour)
+    }
 }

+ 15 - 2
lib/files.js

@@ -1,7 +1,12 @@
 const fs = require('fs');
 const path = require('path');
 const tiny = require("@peterpanhihi/tiny");
-const { resolve } = require('path');
+const getFilesIn = require('get-files-in')
+const globalVariables = require('../lib/globalVars');
+const Language = require("@shypes/language-translator");
+
+Language.setActiveLang(globalVariables.language)
+
 
 module.exports = {
   getCurrentDirectoryBase: () => {
@@ -39,5 +44,13 @@ module.exports = {
       }
       resolve(x / y);
     }).catch(err => NaN)
-  }
+  },
+  getListOfAPk: (path) => {
+    const result = getFilesIn(path, matchFiletypes = ["apk"], checkSubDirectories = false)
+    return result
+  },
+  getLanguageFiles: () => {
+    const result = getFilesIn('./lang/', matchFiletypes = ["json"], checkSubDirectories = false)
+    return result
+  },
 }

+ 1 - 0
lib/globalVars.js

@@ -1,6 +1,7 @@
 class globalVariables {
     localUSB = "";
     miWatchIpaddress = "";
+    language = "";
     usersList=[];
  }
 

+ 58 - 28
lib/inquirer.js

@@ -1,37 +1,53 @@
 const inquirer = require("inquirer");
 const files = require("./files");
 const common = require("./common");
-
-// let compatibleApps
+const Language = require("@shypes/language-translator");
+const globalVariables = require('../lib/globalVars');
 
 module.exports = {
-  mainMenu: () => {
+  mainMenu: async () => {
+    Language.setActiveLang(globalVariables.language)
     const questions = [{
       type: "list",
       name: "mainMenu",
-      message: "What do you want to do?",
+      message: await Language.get('main-menu-question'),
       choices: [
-        // "Connect to MiWatch",
-        "1-Click Karl0ss Klean",
-        "Remove Xiaomi Apps",
-        "Restore Xiaomi Apps",
-        "Install Compatible Apps",
-        "Restore ANY app",
-        "Batch Install APKs",
-        "Batch Remove Installed Apps",
-        "Quit"
+        await Language.get('main-menu-item-1'),
+        await Language.get('main-menu-item-2'),
+        await Language.get('main-menu-item-3'),
+        await Language.get('main-menu-item-4'),
+        await Language.get('main-menu-item-5'),
+        await Language.get('main-menu-item-6'),
+        await Language.get('main-menu-item-7'),
+        await Language.get('main-menu-item-8'),
+        await Language.get('main-menu-item-9'),
       ],
       filter: function (val) {
         return val.toLowerCase();
       },
-    }, ];
+    },];
+    return inquirer.prompt(questions);
+  },
+  LanguageSelect: async () => {
+    langList = files.getLanguageFiles()
+    langList = langList.map(s => s.slice(5, -5));
+    const questions = [{
+      type: "list",
+      name: "selection",
+      message: await Language.get('Select Language'),
+      choices: langList,
+      filter: function (val) {
+        return val.toLowerCase();
+      },
+    },];
     return inquirer.prompt(questions);
   },
-  connectionType: () => {
+  connectionType: async () => {
+    Language.setActiveLang(globalVariables.language)
     const questions = [{
       type: "list",
       name: "connection",
-      message: "How do you want to connect?",
+      message: await Language.get('connection-type-message'),
       choices: [
         "USB",
         "Wifi"
@@ -39,29 +55,32 @@ module.exports = {
       filter: function (val) {
         return val.toLowerCase();
       },
-    }, ];
+    },];
     return inquirer.prompt(questions);
   },
-  connectWifi: () => {
+  connectWifi: async () => {
+    Language.setActiveLang(globalVariables.language)
     const questions = [{
       type: "input",
       name: "connectWifi",
-      message: "What is your MiWatch IpAdress?",
-    }, ];
+      message: await Language.get('connect-wifi-message'),
+    },];
     return inquirer.prompt(questions);
   },
   removeAppsList: async () => {
+    Language.setActiveLang(globalVariables.language)
     const packages = await files.loadPackageList();
 
     const questions = [{
       type: "checkbox",
       name: "removeAppsList",
-      message: "What apps do you want to restore?",
+      message: await Language.get('restore-app-message'),
       choices: packages.apps,
-    }, ];
+    },];
     return inquirer.prompt(questions);
   },
   compatibleApps: async () => {
+    Language.setActiveLang(globalVariables.language)
     const compatibleApps = await common.getCompatibleAppsList()
     const appList = []
     for (let element of compatibleApps) {
@@ -70,26 +89,37 @@ module.exports = {
     const questions = [{
       type: "checkbox",
       name: "removeAppsList",
-      message: "What apps do you want to Install?",
+      message: await Language.get('install-compatible-apps-message'),
       choices: appList,
-    }, ];
+    },];
     return inquirer.prompt(questions);
   },
   installedApps: async (installedApps) => {
+    Language.setActiveLang(globalVariables.language)
     const questions = [{
       type: "checkbox",
       name: "removeAppsList",
-      message: "What Installed apps do you want to remove?",
+      message: await Language.get('remove-installed-apps-message'),
       choices: installedApps,
-    }, ];
+    },];
     return inquirer.prompt(questions);
   },
   restoreAnyApp: async () => {
+    Language.setActiveLang(globalVariables.language)
     const questions = [{
       type: "input",
       name: "restoreAnyApp",
-      message: "What App do you want to restore?",
-    }, ];
+      message: await Language.get('restore-any-app-message'),
+    },];
+    return inquirer.prompt(questions);
+  },
+  removeAnyApp: async () => {
+    Language.setActiveLang(globalVariables.language)
+    const questions = [{
+      type: "input",
+      name: "removeAnyApp",
+      message: await Language.get('remove-any-app-message'),
+    },];
     return inquirer.prompt(questions);
   },
 };

+ 0 - 11
logger.lock

@@ -1,11 +0,0 @@
-{
-    "lastUpdatedBy": "RunTIme",
-    "FrontEndDriver": {
-        "startTime": 1588231747040,
-        "pid": 26780
-    },
-    "RunTIme": {
-        "startTime": 1592986481974,
-        "pid": 25068
-    }
-}

+ 86 - 32
package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "miwatchkleaner",
-  "version": "3.0.0",
+  "version": "3.1.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -45,6 +45,11 @@
       "resolved": "https://registry.npmjs.org/@peterpanhihi/tiny/-/tiny-2.0.0.tgz",
       "integrity": "sha512-usAoksj49559JLAsQXmrE5wOV6A055icErp8jpJDCicfojwEVPaSLk5EZ1EXhcgIuqjSNkzCOXu0gSdm3Std+w=="
     },
+    "@shypes/language-translator": {
+      "version": "2.0.15",
+      "resolved": "https://registry.npmjs.org/@shypes/language-translator/-/language-translator-2.0.15.tgz",
+      "integrity": "sha512-et4HsjzPQUH29nPKlRg3E/2Dr84lO8POJsfWezK9DnLK8nGO42b59Ug7RtwsRy28gxHWr+m1lgzY8JKsVlTlSQ=="
+    },
     "@types/color-name": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
@@ -70,9 +75,9 @@
       }
     },
     "ansi-regex": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-      "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
     },
     "ansi-styles": {
       "version": "4.2.1",
@@ -165,6 +170,38 @@
         "supports-color": "^7.1.0"
       }
     },
+    "chalk-rainbow": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/chalk-rainbow/-/chalk-rainbow-1.0.0.tgz",
+      "integrity": "sha1-kS7wiQ0NI6ZX1byInuFzb++fuPA=",
+      "requires": {
+        "chalk": "^1.1.3"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+        }
+      }
+    },
     "chardet": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
@@ -254,14 +291,6 @@
         "assert-plus": "^1.0.0"
       }
     },
-    "debug": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-      "requires": {
-        "ms": "2.0.0"
-      }
-    },
     "deep-is": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -631,6 +660,14 @@
         "har-schema": "^2.0.0"
       }
     },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
     "has-flag": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -691,6 +728,21 @@
         "string-width": "^4.1.0",
         "strip-ansi": "^6.0.0",
         "through": "^2.3.6"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+        },
+        "strip-ansi": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "requires": {
+            "ansi-regex": "^5.0.0"
+          }
+        }
       }
     },
     "interpret": {
@@ -880,11 +932,6 @@
         "minimist": "^1.2.5"
       }
     },
-    "ms": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
-    },
     "multistream": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/multistream/-/multistream-2.1.1.tgz",
@@ -1100,14 +1147,6 @@
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
       "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
     },
-    "rename": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/rename/-/rename-1.0.4.tgz",
-      "integrity": "sha1-oPJQePpBleZQ9zBQx8Esz2ifQws=",
-      "requires": {
-        "debug": "^2.5.2"
-      }
-    },
     "request": {
       "version": "2.88.2",
       "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
@@ -1261,6 +1300,21 @@
         "emoji-regex": "^8.0.0",
         "is-fullwidth-code-point": "^3.0.0",
         "strip-ansi": "^6.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+        },
+        "strip-ansi": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "requires": {
+            "ansi-regex": "^5.0.0"
+          }
+        }
       }
     },
     "string_decoder": {
@@ -1272,17 +1326,17 @@
       }
     },
     "strip-ansi": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
-      "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
       "requires": {
-        "ansi-regex": "^5.0.0"
+        "ansi-regex": "^2.0.0"
       }
     },
     "supports-color": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-      "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
       "requires": {
         "has-flag": "^4.0.0"
       }

+ 3 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "miwatchkleaner",
-  "version": "3.0.0",
+  "version": "3.1.0",
   "description": "MiWatch Cleaning Tool",
   "main": "app.js",
   "bin": "app.js",
@@ -16,7 +16,9 @@
   "license": "ISC",
   "dependencies": {
     "@peterpanhihi/tiny": "^2.0.0",
+    "@shypes/language-translator": "^2.0.15",
     "chalk": "^4.0.0",
+    "chalk-rainbow": "^1.0.0",
     "clear": "^0.1.0",
     "clui": "^0.3.6",
     "figlet": "^1.3.0",

+ 153 - 277
pages/pages.js

@@ -1,12 +1,11 @@
 const chalk = require('chalk');
 const common = require('../lib/common');
 const inquirer = require('../lib/inquirer');
-const shellExec = require('shell-exec')
 const files = require('../lib/files')
-const getFilesIn = require('get-files-in')
-let logger = require('perfect-logger');
+const logger = require('perfect-logger');
+const Language = require("@shypes/language-translator");
 const globalVariables = require('../lib/globalVars');
-
+const adb = require('../lib/adb');
 
 logger.info(process.platform + " detected")
 if (process.platform === 'win32' || process.platform === 'win64') {
@@ -22,339 +21,216 @@ logger.initialize('RunTIme', {
 });
 
 module.exports = {
-    removeCompatibleApps: async () => {
-        let installedAppList
-        common.header('Remove Installed Apps')
-        logger.info('Remove Installed Apps')
-        await shellExec(adbRun + ' shell pm list packages -3').then(async function (result) {
-            logger.info('Packages recieved from watch')
-            if (result.stderr.includes('error')) {
-                logger.info(result.stderr)
-                console.log(chalk.red('Device not authorised'))
-                common.pause(3000)
-                await shellExec(adbRun + ' kill-server').then(async function (result) {
-                    logger.info('Restarting ADB')
-                    logger.info(result.stdout)
-                    console.log('Please reconnect to watch')
-                    common.pause(3000)
-                    logger.info('Remove Installed Apps Failed')
-                    module.exports.mainMenu()
-                })
-            } else {
-                if (process.platform === 'win32' || process.platform === 'win64') {
-                    installedAppList = result.stdout.split('\r\n'); // split string on comma space
-                    installedAppList.splice(-1, 1)
-                } else {
-                    installedAppList = result.stdout.split('\n'); // split string on comma space
-                    installedAppList.splice(-1, 1)
-                }
-                const value = await inquirer.installedApps(installedAppList);
+    oneClick: async () => {
+        common.log('main-menu-item-1')
+        common.header('main-menu-item-1')
+        common.print('remove-xiaomi-apps', 'whiteBright')
+        const removalPackagesList = files.loadPackageList()
+        for (let package of removalPackagesList.apps) {
+            await adb.removeXiaomiApk(package)
+        }
+        common.print('removal-complete', 'green')
+        await common.pause(2000)
+        common.log('removal-complete')
+        common.log('compatible-apps')
 
-                for (let element of value.removeAppsList) {
-                    console.log('Removing ' + element)
-                    logger.info('Removing ' + element)
-                    const package = element.substring(8)
-                    await shellExec(adbRun + ' uninstall ' + package).then(async function (result) {
-                        console.log(element + ' - ' + result.stdout);
-                        logger.info(element + ' - ' + result.stdout);
-                    });
-                }
-                console.log(chalk.green('Removed Selected User Apps'))
-                logger.info('Removed Selected User Apps')
-                await common.pause(2000)
-                module.exports.mainMenu()
-            }
-        })
-    },
-    compatibleApps: async () => {
-        logger.info("Compatible Apps")
-        common.header('Install Compatible Apps')
+        await common.clearApkFolder()
 
         const compatibleApps = await common.getCompatibleAppsList()
-        const value = await inquirer.compatibleApps();
 
-        await common.clearApkFolder()
+        console.log(chalk.whiteBright('----------'))
+        common.print('downloading-compatible-apps', 'whiteBright')
 
-        for (let element of value.removeAppsList) {
-            for (let element2 of compatibleApps) {
-                if (element === element2.name) {
-                    newName = element.replace(/\s/g, '');
-                    await common.downloadFile(element2.url, './data/apps/' + newName + '.apk')
+        for (const package of compatibleApps) {
+            if (package.Klean === "X") {
+                try {
+                    newPacakgeName = package.name.replace(/\s/g, '');
+                    await common.downloadFile(package.url, './data/apps/' + newPacakgeName + '.apk')
+                    logger.info(await Language.get('downloading-latest', 'en') + ' ' + package.name + ' ' + chalk.green(await Language.get('complete', 'en')))
+                    console.log(await Language.get('downloading-latest') + ' ' + package.name + ' ' + await Language.get('complete'))
+                } catch (error) {
+                    logger.info(await Language.get('downloading-latest', 'en') + ' ' + package.name + ' ' + chalk.red(await Language.get('failed', 'en')))
+                    console.log(await Language.get('downloading-latest') + ' ' + package.name + ' ' + await Language.get('failed'))
                 }
             }
         }
-
-        const apkList = await getFilesIn('./data/apps', matchFiletypes = ['apk'], checkSubDirectories = false)
-
+        const apkList = await files.getListOfAPk('./data/apps')
+        console.log(chalk.whiteBright('----------'))
+        common.print('installing-apps', 'whiteBright')
         for (let element of apkList) {
-            console.log('Installing ' + element)
-            logger.info('Installing ' + element)
-            await shellExec(adbRun + ' install -r ' + element).then(async function (result) {
-                if (result.stderr != '') {
-                    logger.info('Error ' + result.stderr);
-                    console.log(chalk.redBright('Error - Device not authorised'));
-                }
-                console.log(element + ' - ' + result.stdout);
-                logger.info(element + ' - ' + result.stdout);
-
-                if (element === "data\\apps\\simpleweather_base.apk") {
-                    await common.downloadFile('http://kithub.cf/Karl/MiWatchKleaner-APKs/raw/master/Others/simpleweather_split_config.armeabi_v7a.apk', './data/apps/simpleweather_split_config.armeabi_v7a.apk')
-                    await common.downloadFile('http://kithub.cf/Karl/MiWatchKleaner-APKs/raw/master/Others/simpleweather_split_config.xhdpi.apk', './data/apps/simpleweather_split_config.xhdpi.apk')
-                    await shellExec(adbRun + ' install-multiple "data\\apps\\simpleweather_base.apk" "data\\apps\\simpleweather_split_config.armeabi_v7a.apk" "data\\apps\\simpleweather_split_config.xhdpi.apk"').then(function (result) {
-                        console.log(result)
-                        console.log('simpleWeather Activated On Watch');
-                        logger.info('simpleWeather Activated On Watch');
-                    })
-                }
-                if (element === "data\\apps\\MoreLocale.apk") {
-                    await shellExec(adbRun + ' shell pm grant jp.co.c_lis.ccl.morelocale android.permission.CHANGE_CONFIGURATION').then(function (result) {
-                        console.log('moreLocale Activated On Watch');
-                        logger.info('moreLocale Activated On Watch');
-                    })
-                }
-                if (element === "data\\apps\\com.alberto.locale.apk") {
-                    await shellExec(adbRun + ' shell pm grant com.alberto.locale android.permission.CHANGE_CONFIGURATION && ' + adbRun + ' shell am start -n com.alberto.locale/com.alberto.locale.MainActivity && ' + adbRun + ' shell pm grant com.alberto.locale android.permission.CHANGE_CONFIGURATION').then(function (result) {
-                        console.log(result)
-                        console.log('Alberto Locale Activated On Watch');
-                        logger.info('Alberto Locale Activated On Watch');
-                    });
-                }
-            });
+            await adb.installApk(element)
         }
-        console.log(chalk.green('Compatible Apps Installed'))
-        logger.info('Compatible Apps Installed')
+        common.dualLog('compatible-apps-installed', 'green')
         await common.pause(2000)
         module.exports.mainMenu()
     },
-    removeApps: async () => {
-        logger.info("Remove Apps")
-        common.header('Remove Apps')
+
+    removeXiaomiApps: async () => {
+        common.header('main-menu-item-2')
+        common.log('main-menu-item-2')
         const value = await inquirer.removeAppsList();
-        for (let element of value.removeAppsList) {
-            // await shellExec(adbRun + ' shell pm  disable-user --0 ' + element).then(function (result) {
-            await shellExec(adbRun + ' shell pm uninstall -k --user 0 ' + element).then(function (result) {
-                if (result.stderr != '') {
-                    logger.info('Error ' + result.stderr);
-                    console.log(chalk.redBright('Error - Device not authorised'));
-                } else {
-                    logger.info('Removing ' + element + ' - ' + result.stdout);
-                    console.log('Removing ' + element + ' - ' + result.stdout);
-                }
-            });
+        for (let package of value.removeAppsList) {
+            await adb.removeXiaomiApk(package)
         }
-        console.log(chalk.green('Removal Complete'))
+        common.dualLog('removal-complete', 'green')
         await common.pause(2000)
-        logger.info("Remove Complete")
         module.exports.mainMenu()
     },
-    restoreApps: async () => {
-        logger.info("Restore Apps")
-        common.header('Restore Apps')
+
+    restoreXiaomiApps: async () => {
+        common.header('main-menu-item-3')
+        common.log('main-menu-item-3')
         const value = await inquirer.removeAppsList();
-        for (let element of value.removeAppsList) {
-            await shellExec(adbRun + ' shell cmd package install-existing ' + element).then(function (result) {
-                if (result.stderr != '') {
-                    logger.info('Error ' + result.stderr);
-                    console.log(chalk.redBright('Error - Device not authorised'));
-                } else {
-                    logger.info('Restoring ' + element + ' - ' + result.stdout);
-                    console.log('Restoring ' + element + ' - ' + result.stdout);
-                }
-            });
+        for (let package of value.removeAppsList) {
+            await adb.restoreXiaomiApk(package)
         }
-        console.log(chalk.green('Restore Complete'))
+        common.dualLog('restoring-apps-complete', 'green')
         await common.pause(2000)
-        logger.info("Restore Apps Complete")
         module.exports.mainMenu()
     },
-    connectWatch: async () => {
-        logger.info("Connect to watch")
-        common.header('Connect to watch')
-        const value = await inquirer.connectionType()
-        if (value.connection === "usb") {
-            await shellExec(adbRun + ' kill-server').then(async function (result) {
-                logger.info('Restarting ADB')
-                logger.info(result.stdout)
-            })
-            await shellExec(adbRun + ' devices').then(async function (result) {
-                console.log(result.stdout)
-                if (result.stdout.includes('device', 15)) {
-                    console.log(chalk.green('MiWatch Connected via USB'))
-                    await common.pause(3000)
-                    logger.info("MiWatch connected")
-                    globalVariables.localUSB = "X"
-                    module.exports.mainMenu()
-                } else {
-                    console.log(chalk.red('MiWatch not found'))
-                    logger.info("MiWatch not found")
-                    await common.pause(2000)
-                    console.log(chalk.white('Try Again'))
-                    await common.pause(1000)
-                    module.exports.connectWatch()
-                }
-            })
-        }
-        if (value.connection === "wifi") {
-            const value = await inquirer.connectWifi();
-            await shellExec(adbRun + ' kill-server').then(async function (result) {
-                logger.info('Restarting ADB')
-                logger.info(result.stdout)
-            })
-            await shellExec(adbRun + ' connect ' + value.connectWifi).then(async function (result) {
-                logger.info("Connect Wifi Result " + result.stdout)
-                if (result.stdout.includes('already connected') || result.stdout.includes('connected to ')) {
-                    console.log(chalk.green('MiWatch Connected'))
-                    globalVariables.localUSB = ""
-                    globalVariables.miWatchIpaddress = value.connectWifi
-                    await common.pause(3000)
-                    logger.info("Connect Wifi Complete")
-                    module.exports.mainMenu()
-                } else {
-                    if (result.stdout.includes('failed to authenticate')) {
-                        console.log(chalk.redBright('MiWatch not authenticated'))
-                        logger.info('MiWatch not authenticated')
-                    } else {
-                        console.log(chalk.red(result.stdout))
-                        logger.info(result.stdout)
-                    }
-                    await common.pause(2000)
-                    console.log(chalk.white('Try Again'))
-                    await common.pause(1000)
-                    module.exports.connectWatch()
-                }
-            }).catch()
-        }
-    },
-    oneClick: async () => {
-        logger.info("1-Click Karl0ss Klean")
-        common.header('1-Click Karl0ss Klean')
-        const removalPackagesList = files.loadPackageList()
-        for (let element of removalPackagesList.apps) {
-            await shellExec(adbRun + ' shell pm uninstall -k --user 0 ' + element).then(function (result) {
-                if (result.stderr != '') {
-                    logger.info('Error ' + result.stderr);
-                    console.log(chalk.redBright('Error - Device not authorised'));
-                } else {
-                    logger.info('Removing ' + element + ' - ' + result.stdout);
-                    console.log('Removing ' + element + ' - ' + result.stdout);
-                }
-            });
-        }
-        console.log(chalk.green('Removal Complete'))
-        await common.pause(2000)
-        logger.info("Remove Complete")
-        logger.info("Compatible Apps")
-
-        await common.clearApkFolder()
 
+    installCompatibleApps: async () => {
+        common.header('main-menu-item-4')
+        common.log('main-menu-item-4')
         const compatibleApps = await common.getCompatibleAppsList()
+        const value = await inquirer.compatibleApps();
 
-        for (const element of compatibleApps) {
-            if (element.Klean === "X") {
-                try {
-                    logger.info('Downloading Latest ' + element.name + ' Complete')
-                    newName = element.name.replace(/\s/g, '');
-                    await common.downloadFile(element.url, './data/apps/' + newName + '.apk')
-                    logger.info('Downloading Latest ' + element.name + ' Complete')
-                } catch (error) {
-                    logger.info('Downloading Latest ' + element.name + ' FAILED')
+        await common.clearApkFolder()
+
+        for (let element of value.removeAppsList) {
+            for (let element2 of compatibleApps) {
+                if (element === element2.name) {
+                    newName = element.replace(/\s/g, '');
+                    await common.downloadFile(element2.url, './data/apps/' + newName + '.apk')
                 }
             }
         }
-        const apkList = await getFilesIn('./data/apps', matchFiletypes = ['apk'], checkSubDirectories = false)
 
-        for (let element of apkList) {
-            console.log('Installing ' + element)
-            logger.info('Installing ' + element)
-            await shellExec(adbRun + ' install -r ' + element).then(async function (result) {
-                if (result.stderr != '') {
-                    logger.info('Error ' + result.stderr);
-                    console.log(chalk.redBright('Error - Device not authorised'));
-                }
-                console.log(element + ' - ' + result.stdout);
-                logger.info(element + ' - ' + result.stdout);
+        const apkList = await files.getListOfAPk('./data/apps')
 
-            });
+        for (let package of apkList) {
+            common.dualLog('installing', 'whiteBright')
+            await adb.installApk(package)
         }
-        console.log(chalk.green('Compatible Apps Installed'))
-        logger.info('Compatible Apps Installed')
+        common.dualLog('compatible-apps-installed', 'green')
         await common.pause(2000)
         module.exports.mainMenu()
     },
+
     restoreAnyApp: async () => {
-        logger.info("Restore Any App")
-        common.header('Restore Any App')
+        common.header('main-menu-item-5')
+        common.log('main-menu-item-5')
         const value = await inquirer.restoreAnyApp();
-        await shellExec(adbRun + ' shell cmd package install-existing ' + value.restoreAnyApp).then(function (result) {
-            if (result.stderr != '') {
-                logger.info('Error ' + result.stderr);
-                console.log(chalk.redBright('Error - Device not authorised'));
-            } else {
-                logger.info('Restoring ' + value.restoreAnyApp + ' - ' + result.stdout);
-                console.log('Restoring ' + value.restoreAnyApp + ' - ' + result.stdout);
-            }
-        });
-        console.log(chalk.green('Restore Complete'))
+        await adb.restoreAnyApk(value)
+        common.dualLog('restoring-apps-complete', 'green')
         await common.pause(2000)
-        logger.info("App Restore Complete")
         module.exports.mainMenu()
     },
-    batchInstallApks: async () => {
-        logger.info("Batch Install Apks")
-        common.header('Batch Install Apks')
-        
-        let apkList = await getFilesIn('./my_apk/', matchFiletypes = ['apk'], checkSubDirectories = false)
 
-        await files.renameLocalApk(apkList)
+    removeAnyApp: async () => {
+        common.header('main-menu-item-6')
+        common.log('main-menu-item-6')
+        const value = await inquirer.removeAnyApp();
+        await adb.restoreAnyApk(value)
+        common.dualLog('removing-apps-complete', 'green')
+        await common.pause(2000)
+        module.exports.mainMenu()
+    },
 
-        apkList = await getFilesIn('./my_apk/', matchFiletypes = ['apk'], checkSubDirectories = false)
+    batchInstallApps: async () => {
+        common.header('main-menu-item-7')
+        common.log('main-menu-item-7')
+
+        let apkList = await files.getListOfAPk('./my-apk/')
+        await files.renameLocalApk(apkList)
+        apkList = await files.getListOfAPk('./my-apk/')
 
         for (let element of apkList) {
-            console.log('Installing ' + element)
-            logger.info('Installing ' + element)
-            await shellExec(adbRun + ' install -r ' + element).then(async function (result) {
-                if (result.stderr != '') {
-                    logger.info('Error ' + result.stderr);
-                    console.log(chalk.redBright(result.stderr));
-                }
-                console.log(element + ' - ' + result.stdout);
-                logger.info(element + ' - ' + result.stdout);
-            });
+            console.log(await Language.get('installing') + ' ' + element)
+            logger.info(await Language.get('installing') + ' ' + element)
+            await adb.installApk(element)
         }
-        console.log(chalk.green('Batch Install Apks Completed'))
-        logger.info('Batch Install Apks Completed')
+        common.dualLog('batch-install-apps-complete', 'green')
         await common.pause(2000)
         module.exports.mainMenu()
     },
+
+    batchRemoveInstalledApps: async () => {
+        common.header('main-menu-item-8')
+        common.log('main-menu-item-8')
+
+        value = await adb.getInstalledPacakges()
+
+        for (let element of value.removeAppsList) {
+            console.log(await Language.get('removing') + ' ' + element)
+            logger.info(await Language.get('removing') + ' ' + element)
+            const package = element.substring(8)
+            await adb.removeApk(package)
+        }
+        common.dualLog('remove-selected-user-apps', 'green')
+        await common.pause(2000)
+        module.exports.mainMenu()
+    },
+
+    connectWatch: async () => {
+        common.header('connect-to-watch')
+        common.log('connect-to-watch')
+        const value = await inquirer.connectionType()
+        connected = await adb.watchConnection(value)
+        if (connected != true) {
+            module.exports.connectWatch()
+        } else {
+            module.exports.mainMenu()
+        }
+    },
+
+    selectLanguage: async () => {
+        common.header('Select Language')
+        common.log('Select Language')
+        const v = await inquirer.LanguageSelect()
+        globalVariables.language = v.selection
+        module.exports.connectWatch()
+    },
+
     mainMenu: async () => {
         common.header('Main Menu')
         const mainMenuSelection = await inquirer.mainMenu();
+        menu_1 = await Language.get('main-menu-item-1')
+        menu_2 = await Language.get('main-menu-item-2')
+        menu_3 = await Language.get('main-menu-item-3')
+        menu_4 = await Language.get('main-menu-item-4')
+        menu_5 = await Language.get('main-menu-item-5')
+        menu_6 = await Language.get('main-menu-item-6')
+        menu_7 = await Language.get('main-menu-item-7')
+        menu_8 = await Language.get('main-menu-item-8')
+        menu_9 = await Language.get('main-menu-item-9')
+
         switch (mainMenuSelection.mainMenu) {
-            case 'connect to miwatch':
-                module.exports.connectWatch()
-                break;
-            case '1-click karl0ss klean':
+            case menu_1.toLowerCase():
                 module.exports.oneClick()
                 break;
-            case 'remove xiaomi apps':
-                module.exports.removeApps()
-                break;
-            case 'restore xiaomi apps':
-                module.exports.restoreApps()
+            case menu_2.toLowerCase():
+                module.exports.removeXiaomiApps()
                 break;
-            case 'install compatible apps':
-                module.exports.compatibleApps()
+            case menu_3.toLowerCase():
+                module.exports.restoreXiaomiApps()
                 break;
-            case 'batch remove installed apps':
-                module.exports.removeCompatibleApps()
+            case menu_4.toLowerCase():
+                module.exports.installCompatibleApps()
                 break;
-            case 'restore any app':
+            case menu_5.toLowerCase():
                 module.exports.restoreAnyApp()
                 break;
-            case 'batch install apks':
-                module.exports.batchInstallApks()
+            case menu_6.toLowerCase():
+                module.exports.removeAnyApp()
+                break;
+            case menu_7.toLowerCase():
+                module.exports.batchInstallApps()
+                break;
+            case menu_8.toLowerCase():
+                module.exports.batchRemoveInstalledApps()
                 break;
-            case 'quit':
+            case menu_9.toLowerCase():
                 break;
             default:
             // code block