diff --git a/package-lock.json b/package-lock.json index 6f1866e..bb038bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1306,6 +1306,60 @@ "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", "dev": true }, + "adbkit": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/adbkit/-/adbkit-2.11.1.tgz", + "integrity": "sha512-hDTiRg9NX3HQt7WoDAPCplUpvzr4ZzQa2lq7BdTTJ/iOZ6O7YNAs6UYD8sFAiBEcYHDRIyq3cm9sZP6uZnhvXw==", + "requires": { + "adbkit-logcat": "^1.1.0", + "adbkit-monkey": "~1.0.1", + "bluebird": "~2.9.24", + "commander": "^2.3.0", + "debug": "~2.6.3", + "node-forge": "^0.7.1", + "split": "~0.3.3" + }, + "dependencies": { + "bluebird": { + "version": "2.9.34", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.34.tgz", + "integrity": "sha1-L3tOyAIWMoqf3evfacjUlC/v99g=" + }, + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "adbkit-logcat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/adbkit-logcat/-/adbkit-logcat-1.1.0.tgz", + "integrity": "sha1-Adf5sM75CTowvLOwB+//MBUIli8=" + }, + "adbkit-monkey": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/adbkit-monkey/-/adbkit-monkey-1.0.1.tgz", + "integrity": "sha1-8pG+cBou/FZ6Y/x6pq/N7TFDC+E=", + "requires": { + "async": "~0.2.9" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + } + } + }, "address": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", @@ -3977,8 +4031,7 @@ "commander": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", - "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=", - "dev": true + "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" }, "common-tags": { "version": "1.8.0", @@ -7066,13 +7119,15 @@ "version": "1.0.0", "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7089,19 +7144,22 @@ "version": "1.1.0", "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -7232,7 +7290,8 @@ "version": "2.0.3", "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -7246,6 +7305,7 @@ "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7262,6 +7322,7 @@ "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7385,7 +7446,8 @@ "version": "1.0.1", "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -7536,6 +7598,7 @@ "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -10192,8 +10255,7 @@ "node-forge": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", - "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", - "dev": true + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==" }, "node-gyp": { "version": "3.8.0", @@ -16733,6 +16795,14 @@ "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=", "dev": true }, + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "requires": { + "through": "2" + } + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", diff --git a/package.json b/package.json index 02ea827..d3d58a9 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "url": "https://github.com/StarGazer1258/BeatDrop.git" }, "dependencies": { + "adbkit": "^2.11.1", "adm-zip": "^0.4.13", "electron-is-dev": "^0.3.0", "electron-log": "^2.2.17", diff --git a/src/actions/adbActions.js b/src/actions/adbActions.js new file mode 100644 index 0000000..7c6325d --- /dev/null +++ b/src/actions/adbActions.js @@ -0,0 +1,295 @@ +import AdmZip from "adm-zip"; +import { ADD_DEVICE, DISPLAY_WARNING, DOWNLOAD_TOOLS, START_ADB_SERVICE, SYNC_DEVICE, UPDATE_DEVICE } from "./types"; +import * as DEVICE from '../constants/devices' +import * as STATUS from "../constants/device_statuses"; +import os from 'os' +import path from 'path' +import fs from 'fs' +import { exec } from 'child_process' +import { DEVICE_TYPES } from "../constants/device_types"; +const adb = require('adbkit'); +const Promise = require('bluebird') + +export const syncDevice = (serial) => (dispatch, getState) => { + let localSongFolder = path.join(getState().settings.installationDirectory, 'Beat Saber_Data', 'CustomLevels') + let questSongFolder = '' + let command = `-s ${serial} push ${localSongFolder}/. ${questSongFolder} ` + // execute(command) + dispatch({ + type: SYNC_DEVICE, + payload: { + deviceId: serial, + time: new Date() + } + }) +} + +export const getDevices = () => (dispatch, getState) => { + if (!isADBStarted()(getState)){ + startAdb()(dispatch, getState) + dispatch({ type: DISPLAY_WARNING, payload: { text: 'No ADB instance started. Attempting to start...', timeout: 2500 } }) + return + } + + let adb = getState().adb.instance; + adb.listDevices().then(devices => { + if (devices.length < 1){ + dispatch({ type: DISPLAY_WARNING, payload:{ text: "No devices found", timeout: 2500 } }) + return; + } + devices.forEach(async (device) => { + if (device.type === 'device') { + if (isDeviceAdded(device)(getState)) return; + dispatch({ + type: ADD_DEVICE, + payload: await buildDevice(device.id)(getState) + }) + adb.trackDevices() + .then(function(tracker) { + console.log('Device %s was plugged in', device.id) + tracker.on('add', function(device) { + dispatch({ + type: UPDATE_DEVICE, + payload: { + deviceId: device.id, + status: STATUS.CONNECTED + } + }) + }) + tracker.on('remove', function(device) { + console.log('Device %s was unplugged', device.id) + dispatch({ + type: UPDATE_DEVICE, + payload: { + deviceId: device.id, + status: STATUS.OFFLINE + } + }) + }) + tracker.on('end', function() { + console.log('Tracking stopped') + dispatch({ + type: UPDATE_DEVICE, + payload: { + deviceId: device.id, + status: STATUS.UNKNOWN + } + }) + }) + }) + .catch(function(err) { + console.error('Something went wrong:', err.stack) + }) + } + }) + }) +} + +const downloadADBTools = () => (dispatch, getState) => { + let url = 'https://dl.google.com/android/repository/platform-tools-latest-' + let name = "windows.zip" + switch (os.platform()) { + case "win32": + name = "windows.zip" + break + case "darwin": + name = "darwin.zip" + break + case "linux": + name = "linux.zip" + break + default: + name = "windows.zip" + break; + } + let downloadLink = url + name + let downloadPath = path.join(getState().settings.installationDirectory) + let toolsPath = path.join(downloadPath, 'platform-tools'); + if (fs.existsSync(toolsPath)){ + dispatch({ + type: DOWNLOAD_TOOLS, + payload: { path: toolsPath, toolsDownloaded: true } + }) + return + } + return new Promise(async (resolve, reject) => { + await fetch(downloadLink) + .then(res => res.arrayBuffer()) + .then((data) => { + let zip = new AdmZip(new Buffer(data)) + try{ + zip.extractAllTo(downloadPath, true) + dispatch({ + type: DOWNLOAD_TOOLS, + payload: { path: toolsPath, toolsDownloaded: true } + }) + } catch (err) { + dispatch({ + type: DISPLAY_WARNING, + payload: { + text: `Error download ADB tools. Please try again` + } + }) + } + return resolve(downloadPath) + }) + }); +} + +function getAdbBinary() { + switch (os.platform()) { + case 'darwin': + case 'linux': + return 'adb'; + default: + return 'adb.exe'; + } +} + +const execute = (command) => (getState) => { + return new Promise(async (resolve, reject) => { + let adbP = path.join(getState().adb.toolsPath, getAdbBinary()) + await exec('"' + adbP + '" ' + command, (err, stdout, stderr) => { + if (err || stderr) return reject(err || stderr) + return resolve(stdout) + }) + }) +} + +const getProperty = (serial, property) => (getState) => { + return new Promise(async (resolve, reject) => { + let command = `-s ${serial} shell getprop ${property}` + return await execute(command)(getState) + .catch((error) => { + return reject(error) + }) + .then((result) => { + return resolve(result) + }) + }) +} + +const getStorage = (serial) => (getState) => { + return new Promise(async (resolve, reject) => { + let command = `-s ${serial} shell df` + return await execute(command)(getState) + .catch((error) => { + return reject(error) + }) + .then((result) => { + return resolve(result) + }) + }) +} + +const listDevices = () => (getState) => { + let command = `devices` + execute(command)(getState).then((result) => { + console.log(result) + }) +} + +const buildDevice = (serial) => (getState) => { + return new Promise(async (resolve, reject) => { + let info = { + used: 0, + avail: 0 + }; + await getProperty(serial, 'ro.product.manufacturer')(getState) + .catch((error) => { + console.log(error) + }) + .then((manufacturer) => { + info.manufacturer = manufacturer.toString().replace("\n", '') + }) + .catch((error) => { + console.log(error) + }) + .then(() => { + return getProperty(serial, 'ro.product.model')(getState) + }) + .catch((error) => { + console.log(error) + }) + .then((model) => { + info.model = model.toString().replace("\n", '') + }) + .catch((error) => { + console.log(error) + }) + .then(() => { + info.device = `${info.manufacturer} ${info.model}` + }) + + await getStorage(serial)(getState).then(async (storage) => { + let storageArr = parseStorage(storage) + storageArr.forEach((filesystem) => { + if (isNaN(filesystem.used) || isNaN(filesystem.avail)) return + let used = Number(filesystem.used) + let avail = Number(filesystem.avail) + info.used += Math.round(( used / 1000)) + info.avail += Math.round((avail / 1000)) + }) + }) + + if (info.manufacturer.includes(DEVICE_TYPES.MANUFACTURER.OCULUS)) { + if( info.model.includes(DEVICE_TYPES.MODEL.QUEST)){ + return resolve([{ + type: DEVICE.OCULUS.QUEST, + status: STATUS.CONNECTED, + storageUsed: info.used, + capacity: info.avail + info.used, + deviceId: serial, + lastSync: 'N/A' + }]) + } + } + }) +} + +const parseStorage = (str) => { + let strArr = str.split('\n') + let newArr = []; + strArr.forEach((item)=>{ + newArr.push([item.split(' ').filter((e)=>{return e})]) + }) + let arrObj = [] + newArr.forEach((innerArr)=>{ + innerArr.forEach((nextArr)=>{ + if (nextArr[3] === undefined) return + arrObj.push({ + filesystem: nextArr[0], + kblocks: nextArr[1], + used: nextArr[2], + avail: nextArr[3], + usePer: nextArr[4], + mountLoc: nextArr[5], + }) + }) + }) + return arrObj +} + +const startAdb = () => async (dispatch, getState) => { + if (!areToolsDownloaded()(getState)) await downloadADBTools()(dispatch, getState) + if (getState().adb.instance && getState().adb.instance.constructor.name === "Client") return + dispatch({ + type: START_ADB_SERVICE, + payload: { instance: adb.createClient({ bin: path.join(getState().adb.toolsPath, getAdbBinary()) }), started: true } + }) + getDevices()(dispatch, getState) +} + +const isADBStarted = () => (getState) => { + return !!getState().adb.instance && getState().adb.toolsDownloaded && fs.existsSync(getState().adb.toolsPath) && getState().adb.instance.constructor.name === "Client" +} + +const areToolsDownloaded = () => (getState) => { + return getState().adb.toolsDownloaded && getState().adb.toolsPath && fs.existsSync(getState().adb.toolsPath) +} + +const isDeviceAdded = (device) => getState => { + let found = false; + getState().devices.list.some((someDevice) => { if (someDevice.deviceId === device.id) found = true }) + return found +} \ No newline at end of file diff --git a/src/actions/types.js b/src/actions/types.js index 2d073a5..e0330fa 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -102,4 +102,15 @@ export const SET_DOWNLOADED_SONGS = 'SET_DOWNLOADED_SONGS' // Devices export const SCAN_DEVICES = 'SCAN_DEVICES' -export const SELECT_DEVICE = 'SELECT_DEVICE' \ No newline at end of file +export const SELECT_DEVICE = 'SELECT_DEVICE' +export const ADD_DEVICE = 'ADD_DEVICE' +export const UPDATE_DEVICE = 'UPDATE_DEVICE' +export const SYNC_DEVICE = 'SYNC_DEVICE' + +// ADB +export const DOWNLOAD_TOOLS = 'DOWNLOAD_TOOLS' +export const START_ADB_SERVICE = 'START_ADB_SERVICE' +export const STOP_ADB_SERVICE = 'STOP_ADB_SERVICE' +export const PULL = 'PULL' +export const PUSH = 'PUSH' +export const INSTALL = 'INSTALL' \ No newline at end of file diff --git a/src/assets/sync-f.png b/src/assets/sync-f.png new file mode 100644 index 0000000..f5cfee3 Binary files /dev/null and b/src/assets/sync-f.png differ diff --git a/src/components/App.js b/src/components/App.js index 21c4592..82f1189 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -11,7 +11,6 @@ import UpdateDialog from './UpdateDialog'; import SongScanningDialog from './SongScanningDialog'; import ReleaseNotesModal from './ReleaseNotesModal' import CrashMessage from './CrashMessage' - import { connect } from 'react-redux' import { setHasError } from '../actions/windowActions' @@ -19,8 +18,8 @@ import { downloadSong } from '../actions/queueActions' import { loadModDetails, installMod } from '../actions/modActions' import { loadDetailsFromKey } from '../actions/detailsActions' import { setView } from '../actions/viewActions' -import { fetchLocalPlaylists } from '../actions/playlistsActions' +import { fetchLocalPlaylists } from '../actions/playlistsActions' import { SONG_DETAILS, SONG_LIST, MOD_DETAILS, MODS_VIEW } from '../views' const { ipcRenderer } = window.require('electron') @@ -41,7 +40,6 @@ class App extends Component { setView(SONG_LIST)(store.dispatch, store.getState) } loadDetailsFromKey()(store.dispatch, store.getState) - } for(let i = 0; i < message.mods.details.length; i++) { if(store.getState().view.view === MOD_DETAILS && store.getState().view.previousView !== MOD_DETAILS) { diff --git a/src/components/DeviceDetails.js b/src/components/DeviceDetails.js index 0d2c2ed..dbea1f7 100644 --- a/src/components/DeviceDetails.js +++ b/src/components/DeviceDetails.js @@ -4,7 +4,8 @@ import '../css/DeviceDetails.scss' import ProgressBar from './ProgressBar' import deleteIcon from '../assets/delete-filled.png' -import addIcon from '../assets/add-filled.png' +import syncIcon from '../assets/sync-f.png' +import { syncDevice } from '../actions/adbActions' //import moreIcon from '../assets/more-filled.png' import { connect } from 'react-redux' @@ -28,9 +29,10 @@ class DeviceDetails extends Component {

{ `${this.props.device.type.vendorName} ${this.props.device.type.deviceName}` }

{ this.props.device.status }

- { this.props.device.type.identifier === DEVICE.OCULUS.QUEST.identifier ? {} }>ADD SONGS : null } + { this.props.device.type.identifier === DEVICE.OCULUS.QUEST.identifier ? { this.props.syncDevice(this.props.device.deviceId) } }>SYNC SONGS : null } {} }>REMOVE DEVICE
+
Last sync: { this.props.device.lastSync }

Storage

{ this.props.device.capacity ? : null }
{ this.props.device.capacity ? `${Math.trunc(this.props.device.storageUsed / this.props.device.capacity * 100)}% (${this.props.device.storageUsed / 1000}GB / ${this.props.device.capacity / 1000}GB)` : 'N/A' }
@@ -44,8 +46,9 @@ class DeviceDetails extends Component { } const mapStateToProps = state => ({ + deviceId: state.devices.selectedDevice, device: state.devices.list[state.devices.selectedDevice], previousView: state.view.previousView }) -export default connect(mapStateToProps, { setView })(DeviceDetails) \ No newline at end of file +export default connect(mapStateToProps, { setView, syncDevice })(DeviceDetails) \ No newline at end of file diff --git a/src/components/DevicesView.js b/src/components/DevicesView.js index ff8aa55..5076d8b 100644 --- a/src/components/DevicesView.js +++ b/src/components/DevicesView.js @@ -4,48 +4,40 @@ import '../css/DevicesView.scss' import { connect } from 'react-redux' import { selectDevice } from '../actions/deviceActions' +import { getDevices } from "../actions/adbActions"; import { setView } from '../actions/viewActions' import { DEVICE_DETAILS } from '../views' -import * as DEVICE from '../constants/devices' -import * as STATUS from '../constants/device_statuses' - const { remote } = window.require('electron') const path = remote.require('path') -let devices = [ - { - type: DEVICE.OCULUS.QUEST, - status: STATUS.CONNECTED, - storageUsed: 15400, - capacity: 32000 - }, - { - type: DEVICE.HTC.VIVE, - status: STATUS.CONNECTED, - }, - { - type: DEVICE.HTC.VIVE_PRO, - status: STATUS.OFFLINE - }, - { - type: DEVICE.OCULUS.RIFT, - status: STATUS.OFFLINE - }, - { - type: DEVICE.OCULUS.RIFT_S, - status: STATUS.OFFLINE - }, - { - type: DEVICE.PIMAX.EIGHT_K, - status: STATUS.OFFLINE - } -] - class DevicesView extends Component { + componentWillMount(){ + this.props.getDevices() + } + render() { + if (!this.props.devices || this.props.devices.length === 0) { return ( +
+

Devices

+ + + + + + { +
  • + No devices found. Click to scan for more. +
  • + } + +
    Device NameStatusStorage
    +
    + ) + } else { + return (

    Devices

    @@ -54,7 +46,7 @@ class DevicesView extends Component { { - devices.map((device, i) => { + this.props.devices.map((device, i) => { return ( { this.props.selectDevice(i); this.props.setView(DEVICE_DETAILS) } }> @@ -69,11 +61,13 @@ class DevicesView extends Component {
    {
    ) + } } } const mapStateToProps = state => ({ - + devices: state.devices.list, + adb: state.adb }) -export default connect(mapStateToProps, { selectDevice, setView })(DevicesView) \ No newline at end of file +export default connect(mapStateToProps, { selectDevice, setView, getDevices })(DevicesView) \ No newline at end of file diff --git a/src/constants/device_types.js b/src/constants/device_types.js new file mode 100644 index 0000000..bc6675f --- /dev/null +++ b/src/constants/device_types.js @@ -0,0 +1,13 @@ +export const DEVICE_TYPES = { + MANUFACTURER: { + OCULUS: 'Oculus', + HTC: "HTC" + }, + MODEL: { + QUEST: 'Quest', + RIFT: 'Rift', + RIFT_S: 'Rift S', + GO: 'Go', + VIVE: 'Vive' + } +} \ No newline at end of file diff --git a/src/constants/devices.js b/src/constants/devices.js index c1901b6..e03ffc6 100644 --- a/src/constants/devices.js +++ b/src/constants/devices.js @@ -12,16 +12,14 @@ export const OCULUS = { vendorName: 'Oculus', deviceName: 'Rift S', identifier: 'OCULUS_RIFT_S', - vendorId: 0x2833, - deviceId: null + vendorId: 0x2833 }, QUEST: { image: 'src/assets/quest.png', vendorName: 'Oculus', deviceName: 'Quest', identifier: 'OCULUS_QUEST', - vendorId: 0x2833, - deviceId: null + vendorId: 0x2833 } } @@ -31,16 +29,14 @@ export const HTC = { vendorName: 'HTC', deviceName: 'Vive', identifier: 'HTC_VIVE', - vendorId: null, - deviceId: null + vendorId: null }, VIVE_PRO: { image: 'src/assets/vive-pro.png', vendorName: 'HTC', deviceName: 'Vive Pro', identifier: 'HTC_VIVE_PRO', - vendorId: null, - deviceId: null + vendorId: null } } @@ -50,8 +46,7 @@ export const VALVE = { vendorName: 'Valve', deviceName: 'Index', identifier: 'INDEX', - vendorId: 0x28de, - deviceId: null + vendorId: 0x28de } } @@ -61,7 +56,6 @@ export const PIMAX = { vendorName: 'Pimax', deviceName: '8K', identifier: 'PIMAX_EIGHT_K', - vendorId: null, - deviceId: null + vendorId: null } } \ No newline at end of file diff --git a/src/reducers/adbReducer.js b/src/reducers/adbReducer.js new file mode 100644 index 0000000..58b4867 --- /dev/null +++ b/src/reducers/adbReducer.js @@ -0,0 +1,27 @@ +import { START_ADB_SERVICE, DOWNLOAD_TOOLS } from "../actions/types"; + +const initialState = { + instance: null, + started: false, + toolsDownloaded: false, + toolsPath: '' +} + +export default (state = initialState, action) => { + switch (action.type) { + case START_ADB_SERVICE: + return { + ...state, + instance: action.payload.instance, + started: action.payload.started + } + case DOWNLOAD_TOOLS: + return { + ...state, + toolsPath: action.payload.path, + toolsDownloaded: action.payload.toolsDownloaded + } + default: + return state + } +} diff --git a/src/reducers/deviceReducer.js b/src/reducers/deviceReducer.js index 7eb53ff..96d2e0a 100644 --- a/src/reducers/deviceReducer.js +++ b/src/reducers/deviceReducer.js @@ -1,37 +1,7 @@ -import { SELECT_DEVICE } from '../actions/types' - -import * as DEVICE from '../constants/devices' -import * as STATUS from '../constants/device_statuses' +import { ADD_DEVICE, SELECT_DEVICE, SYNC_DEVICE, UPDATE_DEVICE } from "../actions/types"; const initialState = { - list: [ - { - type: DEVICE.OCULUS.QUEST, - status: STATUS.CONNECTED, - storageUsed: 15400, - capacity: 32000 - }, - { - type: DEVICE.HTC.VIVE, - status: STATUS.CONNECTED, - }, - { - type: DEVICE.HTC.VIVE_PRO, - status: STATUS.OFFLINE - }, - { - type: DEVICE.OCULUS.RIFT, - status: STATUS.OFFLINE - }, - { - type: DEVICE.OCULUS.RIFT_S, - status: STATUS.OFFLINE - }, - { - type: DEVICE.PIMAX.EIGHT_K, - status: STATUS.OFFLINE - } - ], + list: [], selectedDevice: 0 } @@ -42,6 +12,27 @@ export default function(state = initialState, action) { ...state, selectedDevice: action.payload } + case ADD_DEVICE: + return { + ...state, + list: [...state.list, ...action.payload] + } + case UPDATE_DEVICE: + let deviceId = action.payload.deviceId; + let status = action.payload.status; + return { + ...state, + list: state.list.map(device => device.deviceId === deviceId ? { ...device, status: status } : device) + } + case SYNC_DEVICE: + let time = action.payload.time; + let date = `${time.getFullYear()}-${time.getMonth() + 1}-${time.getDate()}` + let timeInHours = `${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}` + let dateTime = `${date} ${timeInHours}` + return { + ...state, + list: state.list.map(device => device.deviceId === action.payload.deviceId ? { ...device, lastSync: dateTime } : device) + } default: return state } diff --git a/src/reducers/index.js b/src/reducers/index.js index 698bf00..07fe38c 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -14,6 +14,7 @@ import playlistsReducer from './playlistsReducer' import searchReducer from './searchReducer' import modReducer from './modReducer' import deviceReducer from './deviceReducer' +import adbReducer from "./adbReducer"; export default combineReducers({ songs: songListReducer, @@ -30,5 +31,6 @@ export default combineReducers({ queue: queueReducer, warnings: warningsReducer, search: searchReducer, - devices: deviceReducer + devices: deviceReducer, + adb: adbReducer, }) \ No newline at end of file