eslint re-formatting

pull/1/head
Thomas Ballmann 4 years ago
parent f47fe28388
commit 20ddc7dc3e

@ -10,6 +10,6 @@ trim_trailing_whitespace = true
# The indent size used in the `package.json` file cannot be changed # The indent size used in the `package.json` file cannot be changed
# https://github.com/npm/npm/pull/3180#issuecomment-16336516 # https://github.com/npm/npm/pull/3180#issuecomment-16336516
[{*.yml,*.yaml,package.json,.eslintrc.js}] [{*.yml,*.yaml,package.json,.eslintrc.js,vue.config.js,*.js}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

@ -1,5 +1,5 @@
module.exports = { module.exports = {
presets: [ presets: [
'@vue/cli-plugin-babel/preset' '@vue/cli-plugin-babel/preset',
] ],
} }

@ -1,135 +1,109 @@
<template> <template>
<v-app _style="background: #e2e2e2"> <v-app _style="background: #e2e2e2">
<template v-if="isLoading"> <template v-if="isLoading">
<v-overlay :absolute="true" :value="true"> <v-overlay
<v-progress-circular indeterminate size="64"></v-progress-circular> :absolute="true"
</v-overlay> :value="true"
>
<v-progress-circular
indeterminate
size="64"
/>
</v-overlay>
</template>
<template v-else>
<v-system-bar
app
dark
color="primary"
_window
_lights-out
>
<span>paperdash.io</span>
<v-spacer />
<span>{{ settings.device.name }}</span>
<v-spacer />
<template v-if="stats.wifi.connected">
<v-icon>{{ stats.wifi.rssi | wifiIcon(0) }}</v-icon>
<span>{{ stats.device.time | moment("LT") }}</span>
</template> </template>
<template v-else>
<template v-else> <v-btn
<!-- to="/setup/wifi"
<v-navigation-drawer icon
v-model="drawer" >
app <v-icon color="red">
> $signalWifiOff
</v-navigation-drawer> </v-icon>
--> </v-btn>
</template>
<v-system-bar app dark color="primary" _window _lights-out> </v-system-bar>
<span>paperdash.io</span>
<v-spacer></v-spacer> <v-main>
<span>{{ settings.device.name }}</span> <v-container
<v-spacer></v-spacer> fluid
<template v-if="stats.wifi.connected"> class="align-start fill-height"
<v-icon>{{ stats.wifi.rssi | wifiIcon(0) }}</v-icon> >
<span>{{ stats.device.time | moment("LT") }}</span> <transition-page>
</template> <router-view />
<template v-else> </transition-page>
<v-btn to="/setup/wifi" icon> </v-container>
<v-icon color="red">$signalWifiOff</v-icon> </v-main>
</v-btn> </template>
</template> </v-app>
</v-system-bar>
<!--
<v-app-bar _bottom dense app color="orange lighten-1" dark _short>
<v-app-bar-nav-icon @click="drawer = !drawer">
<v-icon>$device</v-icon>
</v-app-bar-nav-icon>
<v-toolbar-title>paperdash.io</v-toolbar-title>
<v-spacer></v-spacer>
<template v-for="(link, i) in items">
<v-btn icon :to="link.to" :key="i">
<v-icon v-text="link.icon" />
</v-btn>
</template>
</v-app-bar>
-->
<!--
<v-bottom-navigation
v-model="bottomNav"
dark
shift
app
>
<v-btn>
<span>Device</span>
<v-icon>$device</v-icon>
</v-btn>
<v-btn>
<span>Settings</span>
<v-icon>$settings</v-icon>
</v-btn>
</v-bottom-navigation>
-->
<v-content>
<v-container fluid fill-height class="align-start">
<transition-page>
<router-view></router-view>
</transition-page>
</v-container>
</v-content>
</template>
</v-app>
</template> </template>
<script> <script>
import apiDevice from './api/device' import apiDevice from './api/device'
import "@/assets/app.css" import '@/assets/app.css'
import transitionPage from "@/components/TransitionPage" import transitionPage from '@/components/TransitionPage'
export default { export default {
components: { components: {
transitionPage transitionPage,
}, },
data: () => ({ data: () => ({
isLoading: true, isLoading: true,
settings: null settings: null,
}), }),
created () { computed: {
apiDevice.getSettings(settings => { stats () {
this.settings = settings; return this.$root._data.stats
},
this.autoReloadStats(); },
}); watch: {
}, stats () {
watch: { this.isLoading = false
stats () { },
this.isLoading = false },
} created () {
}, apiDevice.getSettings(settings => {
computed: { this.settings = settings
stats () {
return this.$root._data.stats; this.autoReloadStats()
}, })
}, },
methods: { methods: {
autoReloadStats () { autoReloadStats () {
apiDevice.getStats(stats => { apiDevice.getStats(stats => {
// give esp some extra time befor fetch new data // give esp some extra time befor fetch new data
stats.playlist.remaining += 2 stats.playlist.remaining += 2
// reset old so reactive watcher can detect a change // reset old so reactive watcher can detect a change
if (this.$root._data.stats) { if (this.$root._data.stats) {
this.$root._data.stats.playlist.remaining = 0 this.$root._data.stats.playlist.remaining = 0
} }
this.$root._data.stats = stats this.$root._data.stats = stats
setTimeout(() => { setTimeout(() => {
this.autoReloadStats() this.autoReloadStats()
}, stats.playlist.remaining * 1000) }, stats.playlist.remaining * 1000)
}) })
} },
} },
}; }
</script> </script>
<style scoped> <style scoped>
</style> </style>

@ -2,149 +2,146 @@
* Mocking client-server processing * Mocking client-server processing
*/ */
// eslint-disable-next-line
import axios from 'axios'
// eslint-disable-next-line // eslint-disable-next-line
const _settings = { const _settings = {
system: { system: {
country: "AT", country: 'AT',
language: "de", language: 'de',
timezone: "", timezone: '',
utc: 0, utc: 0,
dst: 0, dst: 0,
wifi: "" wifi: '',
}, },
device: { device: {
theme: "black", theme: 'black',
name: "dummy" name: 'dummy',
}, },
playlist: { playlist: {
timer: 60 timer: 60,
}, },
weather: { weather: {
api: "", api: '',
location: 2766824, location: 2766824,
lang: "de", lang: 'de',
unit: "metric" unit: 'metric',
}, },
cloud: { cloud: {
mode: "active", mode: 'active',
url: "http://", url: 'http://',
token: "###" token: '###',
} },
} }
// eslint-disable-next-line // eslint-disable-next-line
const _stats = { const _stats = {
"wifi": { wifi: {
"ssid": "xd-design.info", ssid: 'xd-design.info',
"connected": true, connected: true,
"ip": "192.168.178.62", ip: '192.168.178.62',
"mac": "30:AE:A4:21:20:40", mac: '30:AE:A4:21:20:40',
"channel": 1, channel: 1,
"dns": "192.168.178.1", dns: '192.168.178.1',
"gateway": "192.168.178.1" gateway: '192.168.178.1',
}, },
"device": { device: {
"heap": 120496, heap: 120496,
"bootCycle": 1, bootCycle: 1,
"screen": { screen: {
"width": 640, width: 640,
"height": 384 height: 384,
}, },
"fs": { fs: {
"total": 1860161, total: 1860161,
"used": 1107663, used: 1107663,
"free": 752498 free: 752498,
} },
}, },
"playlist": { playlist: {
"current": "Calendar", current: 'Calendar',
"remaining": 22 remaining: 22,
}, },
"capability": [ capability: [
"png", 'png',
"wbmp" 'wbmp',
], ],
"cloud": { cloud: {
"sleep": 10 sleep: 10,
} },
} }
// eslint-disable-next-line // eslint-disable-next-line
const _wifiScan = [{ "rssi": -59, "ssid": "paperdash.io", "bssid": "38:10:D5:34:80:1B", "channel": 11, "secure": 3 }, { "rssi": -75, "ssid": "FRITZ!Box 7430 JI", "bssid": "38:10:D5:5D:FE:7C", "channel": 1, "secure": 3 }, { "rssi": -87, "ssid": "Vodafone Hotspot", "bssid": "AA:0E:14:BD:50:ED", "channel": 1, "secure": 0 }, { "rssi": -88, "ssid": "WLAN-548426", "bssid": "E0:60:66:55:7F:C5", "channel": 1, "secure": 3 }, { "rssi": -89, "ssid": "Familie Kalinowski", "bssid": "C8:0E:14:BD:50:ED", "channel": 1, "secure": 3 }, { "rssi": -91, "ssid": "WLAN-507287", "bssid": "E0:60:66:48:6C:6B", "channel": 1, "secure": 3 }, { "rssi": -94, "ssid": "TP-LINK_7238", "bssid": "A4:2B:B0:D8:72:38", "channel": 3, "secure": 3 }] const _wifiScan = [{ "rssi": -59, "ssid": "paperdash.io", "bssid": "38:10:D5:34:80:1B", "channel": 11, "secure": 3 }, { "rssi": -75, "ssid": "FRITZ!Box 7430 JI", "bssid": "38:10:D5:5D:FE:7C", "channel": 1, "secure": 3 }, { "rssi": -87, "ssid": "Vodafone Hotspot", "bssid": "AA:0E:14:BD:50:ED", "channel": 1, "secure": 0 }, { "rssi": -88, "ssid": "WLAN-548426", "bssid": "E0:60:66:55:7F:C5", "channel": 1, "secure": 3 }, { "rssi": -89, "ssid": "Familie Kalinowski", "bssid": "C8:0E:14:BD:50:ED", "channel": 1, "secure": 3 }, { "rssi": -91, "ssid": "WLAN-507287", "bssid": "E0:60:66:48:6C:6B", "channel": 1, "secure": 3 }, { "rssi": -94, "ssid": "TP-LINK_7238", "bssid": "A4:2B:B0:D8:72:38", "channel": 3, "secure": 3 }]
import axios from 'axios'
export default { export default {
/** /**
* @param cb * @param cb
* @returns {PromiseLike<any> | Promise<any>} * @returns {PromiseLike<any> | Promise<any>}
*/ */
getSettings(cb) { getSettings (cb) {
//return cb(_settings); // return cb(_settings);
// eslint-disable-next-line // eslint-disable-next-line
return axios return axios
.get('/api/settings') .get('/api/settings')
.then(response => cb(response.data)) .then(response => cb(response.data))
}, },
/**
/** * @returns {IDBRequest<IDBValidKey> | Promise<void>}
* @returns {IDBRequest<IDBValidKey> | Promise<void>} */
*/ putSettings (settings, cb) {
putSettings(settings, cb) { return axios
return axios .put('/api/settings', settings, {
.put('/api/settings', settings, { headers: {
headers: { 'Content-Type': 'application/json',
'Content-Type': 'application/json' },
} })
}) .then(response => cb(response.data))
.then(response => cb(response.data)) },
},
/**
* scan for wifi in range
/** * @param {*} cb
* scan for wifi in range */
* @param {*} cb wifiScan (cb) {
*/ return axios
wifiScan(cb) { .get('/api/wifi/scan')
return axios .then(response => cb(response.data))
.get('/api/wifi/scan') },
.then(response => cb(response.data))
}, /**
* connect to wifi
* @param {*} ssid
/** * @param {*} password
* connect to wifi * @param {*} cb
* @param {*} ssid */
* @param {*} password wifiConnect (ssid, password, cb) {
* @param {*} cb return axios
*/ .post('/api/wifi/connect', {
wifiConnect(ssid, password, cb) { ssid: ssid,
return axios password: password,
.post('/api/wifi/connect', { }, {
ssid: ssid, headers: {
password: password 'Content-Type': 'application/json',
}, { },
headers: { })
'Content-Type': 'application/json' .then(response => cb(response.data))
} },
})
.then(response => cb(response.data)) /**
},
/**
* @param cb * @param cb
* @returns {PromiseLike<any> | Promise<any>} * @returns {PromiseLike<any> | Promise<any>}
*/ */
getStats(cb) { getStats (cb) {
//return cb(_stats); // return cb(_stats);
// eslint-disable-next-line // eslint-disable-next-line
return axios return axios
.get('/stats') .get('/stats')
.then(response => cb(response.data)) .then(response => cb(response.data))
} },
} }

@ -2,195 +2,196 @@
* Mocking client-server processing * Mocking client-server processing
*/ */
// eslint-disable-next-line
import axios from 'axios'
// eslint-disable-next-line // eslint-disable-next-line
const _weather = { const _weather = {
coord: { lon: 13.04, lat: 47.8 }, coord: { lon: 13.04, lat: 47.8 },
weather: [ weather: [
{ id: 800, main: "Clear", description: "Klarer Himmel", icon: "01d" } { id: 800, main: 'Clear', description: 'Klarer Himmel', icon: '01d' },
], ],
base: "stations", base: 'stations',
main: { main: {
temp: 2.75, temp: 2.75,
feels_like: 0.09, feels_like: 0.09,
temp_min: 0, temp_min: 0,
temp_max: 6.11, temp_max: 6.11,
pressure: 1023, pressure: 1023,
humidity: 69 humidity: 69,
}, },
visibility: 10000, visibility: 10000,
wind: { speed: 0.5 }, wind: { speed: 0.5 },
clouds: { all: 9 }, clouds: { all: 9 },
dt: 1584260150, dt: 1584260150,
sys: { sys: {
type: 1, type: 1,
id: 6877, id: 6877,
country: "AT", country: 'AT',
sunrise: 1584249628, sunrise: 1584249628,
sunset: 1584292379 sunset: 1584292379,
}, },
timezone: 3600, timezone: 3600,
id: 2766824, id: 2766824,
name: "Salzburg", name: 'Salzburg',
cod: 200 cod: 200,
} }
// eslint-disable-next-line // eslint-disable-next-line
const _forecast = { const _forecast = {
city: { city: {
id: 2766824, id: 2766824,
name: "Salzburg", name: 'Salzburg',
coord: { lon: 13.044, lat: 47.7994 }, coord: { lon: 13.044, lat: 47.7994 },
country: "AT", country: 'AT',
population: 0, population: 0,
timezone: 3600 timezone: 3600,
}, },
cod: "200", cod: '200',
message: 0.0878612, message: 0.0878612,
cnt: 4, cnt: 4,
list: [ list: [
{ {
dt: 1584270000, dt: 1584270000,
sunrise: 1584249627, sunrise: 1584249627,
sunset: 1584292378, sunset: 1584292378,
temp: { temp: {
day: 14.02, day: 14.02,
min: 1.59, min: 1.59,
max: 14.02, max: 14.02,
night: 1.59, night: 1.59,
eve: 6.4, eve: 6.4,
morn: 2.88 morn: 2.88,
}, },
feels_like: { day: 9.75, night: -2.31, eve: 2.85, morn: -0.11 }, feels_like: { day: 9.75, night: -2.31, eve: 2.85, morn: -0.11 },
pressure: 1021, pressure: 1021,
humidity: 42, humidity: 42,
weather: [ weather: [
{ {
id: 801, id: 801,
main: "Clouds", main: 'Clouds',
description: "Ein paar Wolken", description: 'Ein paar Wolken',
icon: "02d" icon: '02d',
} },
], ],
speed: 3.55, speed: 3.55,
deg: 105, deg: 105,
clouds: 15 clouds: 15,
}, },
{ {
dt: 1584356400, dt: 1584356400,
sunrise: 1584335904, sunrise: 1584335904,
sunset: 1584378865, sunset: 1584378865,
temp: { temp: {
day: 13.15, day: 13.15,
min: 0.88, min: 0.88,
max: 13.15, max: 13.15,
night: 4.3, night: 4.3,
eve: 6.25, eve: 6.25,
morn: 0.88 morn: 0.88,
}, },
feels_like: { day: 10.56, night: 1.77, eve: 4.16, morn: -2.11 }, feels_like: { day: 10.56, night: 1.77, eve: 4.16, morn: -2.11 },
pressure: 1022, pressure: 1022,
humidity: 46, humidity: 46,
weather: [ weather: [
{ {
id: 800, id: 800,
main: "Clear", main: 'Clear',
description: "Klarer Himmel", description: 'Klarer Himmel',
icon: "01d" icon: '01d',
} },
], ],
speed: 1.26, speed: 1.26,
deg: 349, deg: 349,
clouds: 0 clouds: 0,
}, },
{ {
dt: 1584442800, dt: 1584442800,
sunrise: 1584422182, sunrise: 1584422182,
sunset: 1584465351, sunset: 1584465351,
temp: { temp: {
day: 13.8, day: 13.8,
min: 3.73, min: 3.73,
max: 14.05, max: 14.05,
night: 9.64, night: 9.64,
eve: 9.75, eve: 9.75,
morn: 3.73 morn: 3.73,
}, },
feels_like: { day: 11.71, night: 7.26, eve: 7.47, morn: 1.33 }, feels_like: { day: 11.71, night: 7.26, eve: 7.47, morn: 1.33 },
pressure: 1029, pressure: 1029,
humidity: 53, humidity: 53,
weather: [ weather: [
{ id: 804, main: "Clouds", description: "Bedeckt", icon: "04d" } { id: 804, main: 'Clouds', description: 'Bedeckt', icon: '04d' },
], ],
speed: 1.21, speed: 1.21,
deg: 331, deg: 331,
clouds: 100 clouds: 100,
}, },
{ {
dt: 1584529200, dt: 1584529200,
sunrise: 1584508459, sunrise: 1584508459,
sunset: 1584551838, sunset: 1584551838,
temp: { temp: {
day: 16.55, day: 16.55,
min: 6.35, min: 6.35,
max: 16.55, max: 16.55,
night: 7.1, night: 7.1,
eve: 9.94, eve: 9.94,
morn: 6.35 morn: 6.35,
}, },
feels_like: { day: 14.61, night: 5.37, eve: 8.03, morn: 4.56 }, feels_like: { day: 14.61, night: 5.37, eve: 8.03, morn: 4.56 },
pressure: 1028, pressure: 1028,
humidity: 52, humidity: 52,
weather: [ weather: [
{ {
id: 800, id: 800,
main: "Clear", main: 'Clear',
description: "Klarer Himmel", description: 'Klarer Himmel',
icon: "01d" icon: '01d',
} },
], ],
speed: 1.67, speed: 1.67,
deg: 39, deg: 39,
clouds: 7 clouds: 7,
} },
] ],
} }
import axios from 'axios'
export default { export default {
/** /**
* @param cb * @param cb
* @returns {PromiseLike<any> | Promise<any>} * @returns {PromiseLike<any> | Promise<any>}
*/ */
getCurrent(cb) { getCurrent (cb) {
//return cb(_weather); // return cb(_weather);
// eslint-disable-next-line // eslint-disable-next-line
return axios return axios
.get('/fs/weatherCurrent.json') .get('/fs/weatherCurrent.json')
.then(response => cb(response.data)) .then(response => cb(response.data))
}, },
/** /**
* @param cb * @param cb
* @returns {PromiseLike<any> | Promise<any>} * @returns {PromiseLike<any> | Promise<any>}
*/ */
getForecast(cb) { getForecast (cb) {
//return cb(_forecast); // return cb(_forecast);
// eslint-disable-next-line // eslint-disable-next-line
return axios return axios
.get('/fs/weatherForecast.json') .get('/fs/weatherForecast.json')
.then(response => cb(response.data)) .then(response => cb(response.data))
}, },
/** /**
* @param cb * @param cb
* @returns {PromiseLike<any> | Promise<any>} * @returns {PromiseLike<any> | Promise<any>}
*/ */
updateWeather(cb) { updateWeather (cb) {
return axios return axios
.get('/api/update?weather=1') .get('/api/update?weather=1')
.then(response => cb(response.data)) .then(response => cb(response.data))
}, },
} }

@ -8,19 +8,27 @@
<v-list-item-title>{{ stats.wifi.ssid }}</v-list-item-title> <v-list-item-title>{{ stats.wifi.ssid }}</v-list-item-title>
</v-list-item-content> </v-list-item-content>
<v-list-item-avatar> <v-list-item-avatar>
<v-avatar color="secondary lighten-3" size="24"> <v-avatar
color="secondary lighten-3"
size="24"
>
<span class="white--text headline caption">{{ stats.wifi.channel }}</span> <span class="white--text headline caption">{{ stats.wifi.channel }}</span>
</v-avatar> </v-avatar>
</v-list-item-avatar> </v-list-item-avatar>
</v-list-item> </v-list-item>
<v-divider class="mx-4"></v-divider> <v-divider class="mx-4" />
<v-list dense> <v-list dense>
<v-list-item v-for="key in wifiStats" :key="key"> <v-list-item
v-for="key in wifiStats"
:key="key"
>
<v-list-item-title>{{ key }}</v-list-item-title> <v-list-item-title>{{ key }}</v-list-item-title>
<v-list-item-subtitle class="text-right">{{ stats.wifi[key] }}</v-list-item-subtitle> <v-list-item-subtitle class="text-right">
{{ stats.wifi[key] }}
</v-list-item-subtitle>
</v-list-item> </v-list-item>
</v-list> </v-list>
@ -32,43 +40,56 @@
<v-list-item-title>i8n:Storage</v-list-item-title> <v-list-item-title>i8n:Storage</v-list-item-title>
</v-list-item-content> </v-list-item-content>
<v-list-item-avatar> <v-list-item-avatar>
<v-progress-circular :rotate="-90" :value="fsUsage" class="caption">{{ fsUsage }}</v-progress-circular> <v-progress-circular
:rotate="-90"
:value="fsUsage"
class="caption"
>
{{ fsUsage }}
</v-progress-circular>
</v-list-item-avatar> </v-list-item-avatar>
</v-list-item> </v-list-item>
<v-divider class="mx-4"></v-divider> <v-divider class="mx-4" />
<v-list dense class="pb-0"> <v-list
dense
class="pb-0"
>
<v-list-item> <v-list-item>
<v-list-item-title>Total</v-list-item-title> <v-list-item-title>Total</v-list-item-title>
<v-list-item-subtitle class="text-right">{{ fs.total | prettyBytes }}</v-list-item-subtitle> <v-list-item-subtitle class="text-right">
{{ fs.total | prettyBytes }}
</v-list-item-subtitle>
</v-list-item> </v-list-item>
<v-list-item> <v-list-item>
<v-list-item-title>Free</v-list-item-title> <v-list-item-title>Free</v-list-item-title>
<v-list-item-subtitle class="text-right">{{ fs.free | prettyBytes }}</v-list-item-subtitle> <v-list-item-subtitle class="text-right">
{{ fs.free | prettyBytes }}
</v-list-item-subtitle>
</v-list-item> </v-list-item>
</v-list> </v-list>
</v-card> </v-card>
</template> </template>
<script> <script>
export default { export default {
data: () => ({ data: () => ({
wifiStats: ["ip", "gateway", "dns", "mac"] wifiStats: ['ip', 'gateway', 'dns', 'mac'],
}), }),
computed: { computed: {
stats() { stats () {
return this.$root._data.stats; return this.$root._data.stats
},
fsUsage () {
return Math.round(
(100 / this.stats.device.fs.total) * this.stats.device.fs.used,
)
},
fs () {
return this.stats.device.fs
},
}, },
fsUsage() {
return Math.round(
(100 / this.stats.device.fs.total) * this.stats.device.fs.used
);
},
fs() {
return this.stats.device.fs;
}
} }
};
</script> </script>

@ -1,10 +1,37 @@
<template> <template>
<v-card color="grey lighten-4" _outlined> <v-card
<v-img :aspect-ratio="16/9" :src="device_screen_src"></v-img> color="grey lighten-4"
_outlined
>
<v-img
:aspect-ratio="16/9"
:src="device_screen_src"
>
<template #placeholder>
<v-row
class="fill-height ma-0 grey"
align="center"
justify="center"
>
<v-progress-circular
indeterminate
color="grey lighten-5"
/>
</v-row>
</template>
</v-img>
<v-card-actions style="position: relative"> <v-card-actions style="position: relative">
<router-link to="/settings"> <router-link to="/settings">
<v-btn color="orange" dark absolute top right fab elevation="2"> <v-btn
color="orange"
dark
absolute
top
right
fab
elevation="2"
>
<v-icon>$settings</v-icon> <v-icon>$settings</v-icon>
</v-btn> </v-btn>
</router-link> </router-link>
@ -14,46 +41,48 @@
:size="50" :size="50"
:width="5" :width="5"
:value="playlistProgress" :value="playlistProgress"
>{{ playlistRemainingCountdown }}</v-progress-circular> >
{{ playlistRemainingCountdown }}
</v-progress-circular>
<span class="headline pl-3">{{ playlistCurrent }}</span> <span class="headline pl-3">{{ playlistCurrent }}</span>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</template> </template>
<script> <script>
export default { export default {
data: () => ({ data: () => ({
device_screen_src: null, device_screen_src: null,
playlistRemainingCountdown: 0 playlistRemainingCountdown: 0,
}), }),
created() { computed: {
this.playlistRemainingCountdown = this.playlistRemaining; playlistProgress () {
this.device_screen_src = "/current-image2?q=10&" + Date.now(); return parseInt((100 / 60) * this.playlistRemainingCountdown)
},
setInterval(() => { playlistRemaining () {
if (this.playlistRemainingCountdown > 0) { return this.$root._data.stats.playlist.remaining
this.playlistRemainingCountdown--; },
} playlistCurrent () {
}, 1000); return this.$root._data.stats.playlist.current
}, },
computed: { },
playlistProgress() { watch: {
return parseInt((100 / 60) * this.playlistRemainingCountdown); playlistRemaining (val) {
if (val > 0) {
this.playlistRemainingCountdown = val
this.device_screen_src = '/current-image3?' + Date.now()
}
},
}, },
playlistRemaining() { created () {
return this.$root._data.stats.playlist.remaining; this.playlistRemainingCountdown = this.playlistRemaining
this.device_screen_src = '/current-image3?' + Date.now()
setInterval(() => {
if (this.playlistRemainingCountdown > 0) {
this.playlistRemainingCountdown--
}
}, 1000)
}, },
playlistCurrent() {
return this.$root._data.stats.playlist.current;
}
},
watch: {
playlistRemaining(val) {
if (val > 0) {
this.playlistRemainingCountdown = val;
this.device_screen_src = "/current-image2?q=10&" + Date.now();
}
}
} }
};
</script> </script>

@ -2,46 +2,46 @@
<v-card flat> <v-card flat>
<v-card-text> <v-card-text>
<v-text-field <v-text-field
label="i8n:OpenWeatherMap API key"
v-model="settings.weather.api" v-model="settings.weather.api"
label="i8n:OpenWeatherMap API key"
placeholder="###" placeholder="###"
></v-text-field> />
<weather-find-location <weather-find-location
:api="settings.weather.api" :api="settings.weather.api"
:location.sync="settings.weather.location" :location.sync="settings.weather.location"
:lang="lang" :lang="lang"
:unit="unit" :unit="unit"
></weather-find-location> />
</v-card-text> </v-card-text>
</v-card> </v-card>
</template> </template>
<script> <script>
import weatherFindLocation from "@/components/WeatherFindLocation"; import weatherFindLocation from '@/components/WeatherFindLocation'
export default { export default {
props: { components: {
settings: { weatherFindLocation,
type: Object, },
required: true props: {
} settings: {
}, type: Object,
components: { required: true,
weatherFindLocation },
}, },
data: () => ({ data: () => ({
}), }),
computed: { computed: {
lang() { lang () {
return this.settings.language || "EN"; return this.settings.language || 'EN'
},
unit () {
return this.settings.language === 'EN' ? '' : 'metric'
},
},
methods: {
commit () {},
}, },
unit() {
return this.settings.language === "EN" ? "" : "metric";
}
},
methods: {
commit() {}
} }
};
</script> </script>

@ -1,10 +1,19 @@
<template> <template>
<v-card flat> <v-card flat>
<v-toolbar dark color="primary"> <v-toolbar
<v-btn icon dark @click="$emit('cancel')"> dark
color="primary"
>
<v-btn
icon
dark
@click="$emit('cancel')"
>
<v-icon>$close</v-icon> <v-icon>$close</v-icon>
</v-btn> </v-btn>
<v-toolbar-title class="pl-0">Enter the password for "{{ ssid }}"</v-toolbar-title> <v-toolbar-title class="pl-0">
Enter the password for "{{ ssid }}"
</v-toolbar-title>
<v-progress-linear <v-progress-linear
:active="isConnecting" :active="isConnecting"
@ -12,7 +21,7 @@
absolute absolute
bottom bottom
color="deep-orange accent-4" color="deep-orange accent-4"
></v-progress-linear> />
</v-toolbar> </v-toolbar>
<v-card-text class="pa-5"> <v-card-text class="pa-5">
@ -22,37 +31,39 @@
:type="show1 ? 'text' : 'password'" :type="show1 ? 'text' : 'password'"
label="i8n:Password" label="i8n:Password"
@click:append="show1 = !show1" @click:append="show1 = !show1"
></v-text-field> />
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer />
<v-btn <v-btn
depressed depressed
:disabled="password === ''" :disabled="password === ''"
color="primary" color="primary"
@click="onConnect(ssid, password)" @click="onConnect(ssid, password)"
>i8n:Join</v-btn> >
i8n:Join
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
ssid: { ssid: {
type: String, type: String,
required: true required: true,
},
onConnect: {
type: Function,
required: true,
},
}, },
onConnect: { data: () => ({
type: Function, isConnecting: false,
required: true password: '',
} show1: false,
}, }),
data: () => ({ }
isConnecting: false,
password: "",
show1: false
})
};
</script> </script>

@ -12,71 +12,71 @@
</template> </template>
<script> <script>
const DEFAULT_TRANSITION = `fade`; const DEFAULT_TRANSITION = 'fade'
const DEFAULT_TRANSITION_MODE = `out-in`; const DEFAULT_TRANSITION_MODE = 'out-in'
export default { export default {
name: `TransitionPage`, name: 'TransitionPage',
data() { data () {
return { return {
prevHeight: 0, prevHeight: 0,
transitionName: DEFAULT_TRANSITION, transitionName: DEFAULT_TRANSITION,
transitionMode: DEFAULT_TRANSITION_MODE, transitionMode: DEFAULT_TRANSITION_MODE,
transitionEnterActiveClass: `` transitionEnterActiveClass: '',
};
},
created() {
this.$router.beforeEach((to, from, next) => {
let transitionName =
to.meta.transitionName ||
from.meta.transitionName ||
DEFAULT_TRANSITION;
if (transitionName === `slide`) {
const toDepth = to.path.split(`/`).length;
const fromDepth = from.path.split(`/`).length;
transitionName = toDepth < fromDepth ? `slide-right` : `slide-left`;
} }
this.transitionMode = DEFAULT_TRANSITION_MODE;
this.transitionEnterActiveClass = `${transitionName}-enter-active`;
if (to.meta.transitionName === `zoom`) {
this.transitionMode = `in-out`;
this.transitionEnterActiveClass = `zoom-enter-active`;
document.body.style.overflow = `hidden`;
}
if (from.meta.transitionName === `zoom`) {
this.transitionMode = null;
this.transitionEnterActiveClass = null;
document.body.style.overflow = null;
}
this.transitionName = transitionName;
next();
});
},
methods: {
beforeLeave(element) {
this.prevHeight = getComputedStyle(element).height;
}, },
enter(element) { created () {
const { height } = getComputedStyle(element); this.$router.beforeEach((to, from, next) => {
let transitionName =
// eslint-disable-next-line no-param-reassign to.meta.transitionName ||
element.style.height = this.prevHeight; from.meta.transitionName ||
DEFAULT_TRANSITION
if (transitionName === 'slide') {
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
}
this.transitionMode = DEFAULT_TRANSITION_MODE
this.transitionEnterActiveClass = `${transitionName}-enter-active`
if (to.meta.transitionName === 'zoom') {
this.transitionMode = 'in-out'
this.transitionEnterActiveClass = 'zoom-enter-active'
document.body.style.overflow = 'hidden'
}
if (from.meta.transitionName === 'zoom') {
this.transitionMode = null
this.transitionEnterActiveClass = null
document.body.style.overflow = null
}
this.transitionName = transitionName
next()
})
},
methods: {
beforeLeave (element) {
this.prevHeight = getComputedStyle(element).height
},
enter (element) {
const { height } = getComputedStyle(element)
setTimeout(() => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
element.style.height = height; element.style.height = this.prevHeight
});
setTimeout(() => {
// eslint-disable-next-line no-param-reassign
element.style.height = height
})
},
afterEnter (element) {
// eslint-disable-next-line no-param-reassign
element.style.height = 'auto'
},
}, },
afterEnter(element) {
// eslint-disable-next-line no-param-reassign
element.style.height = `auto`;
}
} }
};
</script> </script>
<style lang="scss"> <style lang="scss">
@ -136,4 +136,4 @@ export default {
opacity: 1; opacity: 1;
} }
} }
</style> </style>

@ -6,7 +6,9 @@
> >
<v-list-item two-line> <v-list-item two-line>
<v-list-item-content v-if="weather"> <v-list-item-content v-if="weather">
<v-list-item-title class="headline">{{ weather.name }}</v-list-item-title> <v-list-item-title class="headline">
{{ weather.name }}
</v-list-item-title>
<v-list-item-subtitle>{{ weather.dt | moment("ddd, h A") }}, {{ weather.weather[0].description }}</v-list-item-subtitle> <v-list-item-subtitle>{{ weather.dt | moment("ddd, h A") }}, {{ weather.weather[0].description }}</v-list-item-subtitle>
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
@ -14,9 +16,18 @@
<template v-if="weather"> <template v-if="weather">
<v-card-text> <v-card-text>
<v-row align="center"> <v-row align="center">
<v-col class="display-3" cols="6">{{ currentTemp }} &deg;C</v-col> <v-col
class="display-3"
cols="6"
>
{{ currentTemp }} &deg;C
</v-col>
<v-col cols="6"> <v-col cols="6">
<v-img :src="currentConditionIcon" alt width="92"></v-img> <v-img
:src="currentConditionIcon"
alt
width="92"
/>
</v-col> </v-col>
</v-row> </v-row>
</v-card-text> </v-card-text>
@ -35,87 +46,98 @@
<v-list-item-subtitle>{{ weather.main.humidity }}%</v-list-item-subtitle> <v-list-item-subtitle>{{ weather.main.humidity }}%</v-list-item-subtitle>
</v-list-item> </v-list-item>
<v-divider class="mx-4"></v-divider> <v-divider class="mx-4" />
<template v-if="forecast"> <template v-if="forecast">
<v-list class="transparent"> <v-list class="transparent">
<v-list-item v-for="item in forecast.list" :key="item.dt"> <v-list-item
v-for="item in forecast.list"
:key="item.dt"
>
<v-list-item-title>{{ item.dt | moment("dddd") }}</v-list-item-title> <v-list-item-title>{{ item.dt | moment("dddd") }}</v-list-item-title>
<v-list-item-icon class="ma-0"> <v-list-item-icon class="ma-0">
<v-img :src="getConditionIcon(item.weather[0].icon)"></v-img> <v-img :src="getConditionIcon(item.weather[0].icon)" />
</v-list-item-icon> </v-list-item-icon>
<v-list-item-subtitle <v-list-item-subtitle
class="text-right" class="text-right"
>{{ item.temp.max | round }}&deg; / {{ item.temp.min | round }}&deg;</v-list-item-subtitle> >
{{ item.temp.max | round }}&deg; / {{ item.temp.min | round }}&deg;
</v-list-item-subtitle>
</v-list-item> </v-list-item>
</v-list> </v-list>
</template> </template>
</template> </template>
<v-divider></v-divider> <v-divider />
<v-card-actions> <v-card-actions>
<v-btn :loading="isUpdatingData" @click="updateData" text>i8n:update weather data</v-btn> <v-btn
:loading="isUpdatingData"
text
@click="updateData"
>
i8n:update weather data
</v-btn>
</v-card-actions> </v-card-actions>
</v-skeleton-loader> </v-skeleton-loader>
</v-card> </v-card>
</template> </template>
<script> <script>
import weatherApi from "@/api/weather"; import weatherApi from '@/api/weather'
export default { export default {
data: () => ({ data: () => ({
isLoading: true, isLoading: true,
isUpdatingData: false, isUpdatingData: false,
weather: null, weather: null,
forecast: null forecast: null,
}), }),
created() {
this.loadData(); computed: {
}, currentTemp () {
return Math.round(this.weather.main.temp)
computed: { },
currentTemp() { currentConditionIcon () {
return Math.round(this.weather.main.temp); return (
'http://openweathermap.org/img/wn/' +
this.weather.weather[0].icon +
'@2x.png'
)
},
}, },
currentConditionIcon() { created () {
return ( this.loadData()
"http://openweathermap.org/img/wn/" +
this.weather.weather[0].icon +
"@2x.png"
);
}
},
methods: {
getConditionIcon(code) {
return "http://openweathermap.org/img/wn/" + code + "@2x.png";
}, },
loadData() { methods: {
this.isLoading = true; getConditionIcon (code) {
weatherApi.getCurrent(weather => { return 'http://openweathermap.org/img/wn/' + code + '@2x.png'
this.weather = weather; },
loadData () {
weatherApi.getForecast(forecast => { this.isLoading = true
this.forecast = forecast; weatherApi.getCurrent(weather => {
this.weather = weather
this.isLoading = false;
}); weatherApi.getForecast(forecast => {
}); this.forecast = forecast
this.isLoading = false
})
})
},
updateData () {
this.isUpdatingData = true
weatherApi.updateWeather(() => {
// TODO reload json
this.isUpdatingData = false
this.loadData()
})
},
}, },
updateData() {
this.isUpdatingData = true;
weatherApi.updateWeather(() => {
// TODO reload json
this.isUpdatingData = false;
this.loadData();
});
}
} }
};
</script> </script>

@ -1,7 +1,7 @@
<template> <template>
<v-autocomplete <v-autocomplete
:disabled="!api"
v-model="model" v-model="model"
:disabled="!api"
:items="entries" :items="entries"
:loading="isLoading" :loading="isLoading"
:search-input.sync="search" :search-input.sync="search"
@ -13,95 +13,106 @@
placeholder="i8n:Start typing to Search" placeholder="i8n:Start typing to Search"
_return-object _return-object
> >
<template v-slot:item="{ item }"> <template #item="{ item }">
<v-list-item two-line class="pa-0"> <v-list-item
two-line
class="pa-0"
>
<v-list-item-icon class="ma-0"> <v-list-item-icon class="ma-0">
<img width="64" :src="getConditionIcon(item.weather[0].icon)" /> <img
width="64"
:src="getConditionIcon(item.weather[0].icon)"
>
</v-list-item-icon> </v-list-item-icon>
<v-list-item-content> <v-list-item-content>
<v-list-item-title> <v-list-item-title>
{{ item.name }}, {{ item.sys.country }} {{ item.name }}, {{ item.sys.country }}
<img :src="getCountryFlag(item.sys.country)" /> <img :src="getCountryFlag(item.sys.country)">
<strong>{{ item.weather[0].description }}</strong> <strong>{{ item.weather[0].description }}</strong>
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> <v-list-item-subtitle>
<v-chip class="font-weight-bold" small>{{ item.main.temp }}°С</v-chip> <v-chip
class="font-weight-bold"
small
>
{{ item.main.temp }}°С
</v-chip>
</v-list-item-subtitle> </v-list-item-subtitle>
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
<v-list-item></v-list-item> <v-list-item />
</template> </template>
</v-autocomplete> </v-autocomplete>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
location: { location: {
type: Number, type: Number,
required: false required: false,
}, },
api: { api: {
type: String, type: String,
required: true required: true,
},
lang: {
type: String,
required: true,
},
unit: {
type: String,
required: true,
},
}, },
lang: {
type: String,
required: true
},
unit: {
type: String,
required: true
}
},
data: () => ({ data: () => ({
entries: [], entries: [],
isLoading: false, isLoading: false,
model: null, model: null,
search: null search: null,
}), }),
watch: { watch: {
model(val) { model (val) {
this.$emit("update:location", val); this.$emit('update:location', val)
}, },
search(val) { search (val) {
if (!val || val.length < 3) return; if (!val || val.length < 3) return
// Items have already been requested // Items have already been requested
if (this.isLoading) return; if (this.isLoading) return
this.isLoading = true; this.isLoading = true
// search // search
let url = "https://api.openweathermap.org/data/2.5/find?appid="; let url = 'https://api.openweathermap.org/data/2.5/find?appid='
url += this.api; url += this.api
url += "&lang=" + this.lang; url += '&lang=' + this.lang
url += "&units=" + this.unit; url += '&units=' + this.unit
url += "&type=like&sort=population&cnt=10"; url += '&type=like&sort=population&cnt=10'
url += "&q=" + val; url += '&q=' + val
fetch(url) fetch(url)
.then(res => res.json()) .then(res => res.json())
.then(res => { .then(res => {
this.count = res.count; this.count = res.count
this.entries = res.list; this.entries = res.list
}) })
.catch(err => { .catch(err => {
console.log(err); console.log(err)
}) })
.finally(() => (this.isLoading = false)); .finally(() => (this.isLoading = false))
} },
}, },
methods: { methods: {
getCountryFlag(code) { getCountryFlag (code) {
return ( return (
"http://openweathermap.org/images/flags/" + code.toLowerCase() + ".png" 'http://openweathermap.org/images/flags/' + code.toLowerCase() + '.png'
); )
},
getConditionIcon (code) {
return 'http://openweathermap.org/img/wn/' + code + '@2x.png'
},
}, },
getConditionIcon(code) {
return "http://openweathermap.org/img/wn/" + code + "@2x.png";
}
} }
}; </script>
</script>

@ -5,13 +5,13 @@ import vuetify from './plugins/vuetify'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.use(require('vue-moment')); Vue.use(require('vue-moment'))
new Vue({ new Vue({
vuetify, vuetify,
router, router,
data: { data: {
stats: null stats: null,
}, },
render: h => h(App) render: h => h(App),
}).$mount('#app') }).$mount('#app')

@ -6,101 +6,100 @@ import Vuetify from 'vuetify/lib'
// @see https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/services/icons/presets/mdi-svg.ts // @see https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/services/icons/presets/mdi-svg.ts
const MY_ICONS = { const MY_ICONS = {
// system icons // system icons
//complete: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check/baseline.svg')}, // complete: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check/baseline.svg')},
//cancel: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/cancel/baseline.svg')}, // cancel: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/cancel/baseline.svg')},
close: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/close/baseline.svg')}, close: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/close/baseline.svg') },
//delete: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/delete/baseline.svg')}, // delete: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/delete/baseline.svg')},
//clear: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/clear/baseline.svg')}, // clear: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/clear/baseline.svg')},
//success: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check_circle/baseline.svg')}, // success: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check_circle/baseline.svg')},
//info: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/info/baseline.svg')}, // info: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/info/baseline.svg')},
//warning: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/priority_high/baseline.svg')}, // warning: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/priority_high/baseline.svg')},
//error: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/warning/baseline.svg')}, // error: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/warning/baseline.svg')},
prev: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/chevron_left/baseline.svg')}, prev: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/chevron_left/baseline.svg') },
next: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/chevron_right/baseline.svg')}, next: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/chevron_right/baseline.svg') },
//checkboxOn: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check_box/baseline.svg')}, // checkboxOn: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check_box/baseline.svg')},
//checkboxOff: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check_box_outline_blank/baseline.svg')}, // checkboxOff: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check_box_outline_blank/baseline.svg')},
//checkboxIndeterminate: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/indeterminate_check_box/baseline.svg')}, // checkboxIndeterminate: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/indeterminate_check_box/baseline.svg')},
//delimiter: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/fiber_manual_record/baseline.svg')}, // for carousel // delimiter: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/fiber_manual_record/baseline.svg')}, // for carousel
//sort: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/arrow_upward/baseline.svg')}, // sort: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/arrow_upward/baseline.svg')},
//expand: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/keyboard_arrow_down/baseline.svg')}, // expand: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/keyboard_arrow_down/baseline.svg')},
//menu: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/menu/baseline.svg')}, // menu: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/menu/baseline.svg')},
//subgroup: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/arrow_drop_down/baseline.svg')}, // subgroup: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/arrow_drop_down/baseline.svg')},
dropdown: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/arrow_drop_down/baseline.svg')}, dropdown: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/arrow_drop_down/baseline.svg') },
radioOn: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/radio_button_checked/baseline.svg')}, radioOn: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/radio_button_checked/baseline.svg') },
radioOff: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/radio_button_unchecked/baseline.svg')}, radioOff: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/radio_button_unchecked/baseline.svg') },
//edit: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/edit/baseline.svg')}, // edit: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/edit/baseline.svg')},
//ratingEmpty: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/star_border/baseline.svg')}, // ratingEmpty: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/star_border/baseline.svg')},
//ratingFull: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/star/baseline.svg')}, // ratingFull: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/star/baseline.svg')},
//ratingHalf: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/star_half/baseline.svg')}, // ratingHalf: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/star_half/baseline.svg')},
//loading: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/cached/baseline.svg')}, // loading: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/cached/baseline.svg')},
//first: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/first_page/baseline.svg')}, // first: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/first_page/baseline.svg')},
//last: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/last_page/baseline.svg')}, // last: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/last_page/baseline.svg')},
//unfold: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/unfold_more/baseline.svg')}, // unfold: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/unfold_more/baseline.svg')},
//file: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/attach_file/baseline.svg')}, // file: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/attach_file/baseline.svg')},
//plus: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/add/baseline.svg')}, // plus: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/add/baseline.svg')},
//minus: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/remove/baseline.svg')}, // minus: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/remove/baseline.svg')},
// app icons // app icons
//save: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/save/baseline.svg')}, // save: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/save/baseline.svg')},
//more_vert: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/more_vert/baseline.svg')}, // more_vert: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/more_vert/baseline.svg')},
//reorder: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/reorder/baseline.svg')}, // reorder: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/reorder/baseline.svg')},
//preview: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/remove_red_eye/baseline.svg')}, // preview: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/remove_red_eye/baseline.svg')},
//search: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/search/baseline.svg')}, // search: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/search/baseline.svg')},
memory: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/memory/baseline.svg')}, memory: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/memory/baseline.svg') },
lock: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/lock/baseline.svg')}, lock: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/lock/baseline.svg') },
settings: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/settings/baseline.svg')}, settings: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/settings/baseline.svg') },
// wifi // wifi
signalWifiOff: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_off/baseline.svg')}, signalWifiOff: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_off/baseline.svg') },
signalWifi0: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_0_bar/baseline.svg')}, signalWifi0: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_0_bar/baseline.svg') },
signalWifi1: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar/baseline.svg')}, signalWifi1: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar/baseline.svg') },
signalWifi1Lock: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar_lock/baseline.svg')}, signalWifi1Lock: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar_lock/baseline.svg') },
signalWifi2: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar/baseline.svg')}, signalWifi2: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar/baseline.svg') },
signalWifi2Lock: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar_lock/baseline.svg')}, signalWifi2Lock: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar_lock/baseline.svg') },
signalWifi3: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar/baseline.svg')}, signalWifi3: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar/baseline.svg') },
signalWifi3Lock: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar_lock/baseline.svg')}, signalWifi3Lock: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar_lock/baseline.svg') },
signalWifi4: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar/baseline.svg')}, signalWifi4: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar/baseline.svg') },
signalWifi4Lock: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar_lock/baseline.svg')}, signalWifi4Lock: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar_lock/baseline.svg') },
// setup // setup
wb_sunny: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/wb_sunny/baseline.svg')}, wb_sunny: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/wb_sunny/baseline.svg') },
open_in_new: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/open_in_new/baseline.svg')}, open_in_new: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/open_in_new/baseline.svg') },
face: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/face/baseline.svg')}, face: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/face/baseline.svg') },
autorenew: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/autorenew/baseline.svg')}, autorenew: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/autorenew/baseline.svg') },
check: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check/baseline.svg')}, check: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/check/baseline.svg') },
visibility: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/visibility/baseline.svg')}, visibility: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/visibility/baseline.svg') },
visibility_off: {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/visibility_off/baseline.svg')} visibility_off: { component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/visibility_off/baseline.svg') },
} }
Vue.use(Vuetify) Vue.use(Vuetify)
// usage: {{ file.size | prettyBytes }} // usage: {{ file.size | prettyBytes }}
Vue.filter('prettyBytes', function (num) { Vue.filter('prettyBytes', function (num) {
// jacked from: https://github.com/sindresorhus/pretty-bytes // jacked from: https://github.com/sindresorhus/pretty-bytes
if (typeof num !== 'number' || isNaN(num)) { if (typeof num !== 'number' || isNaN(num)) {
throw new TypeError('Expected a number'); throw new TypeError('Expected a number')
} }
var exponent; var exponent
var unit; var unit
var neg = num < 0; var neg = num < 0
var units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; var units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
if (neg) { if (neg) {
num = -num; num = -num
} }
if (num < 1) { if (num < 1) {
return (neg ? '-' : '') + num + ' B'; return (neg ? '-' : '') + num + ' B'
} }
exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1); exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1)
num = (num / Math.pow(1000, exponent)).toFixed(2) * 1; num = (num / Math.pow(1000, exponent)).toFixed(2) * 1
unit = units[exponent]; unit = units[exponent]
return (neg ? '-' : '') + num + ' ' + unit; return (neg ? '-' : '') + num + ' ' + unit
}); })
/** /**
* Vue filter to round the decimal to the given place. * Vue filter to round the decimal to the given place.
@ -110,18 +109,17 @@ Vue.filter('prettyBytes', function (num) {
* @param {Number} decimals The number of decimal places. * @param {Number} decimals The number of decimal places.
*/ */
Vue.filter('round', function (value, decimals) { Vue.filter('round', function (value, decimals) {
if (!value) { if (!value) {
value = 0; value = 0
} }
if (!decimals) {
decimals = 0;
}
value = Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals); if (!decimals) {
return value; decimals = 0
}); }
value = Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals)
return value
})
/** /**
* usage: {{ wifi.rssi | wifiIcon(wifi.secure) }} * usage: {{ wifi.rssi | wifiIcon(wifi.secure) }}
@ -129,38 +127,34 @@ Vue.filter('round', function (value, decimals) {
* @param {Boolean} secure Is wifi protected * @param {Boolean} secure Is wifi protected
*/ */
Vue.filter('wifiIcon', function (rssi, secure) { Vue.filter('wifiIcon', function (rssi, secure) {
let icon = '$signalWifi' let icon = '$signalWifi'
// strength // strength
if (rssi >= -67) { if (rssi >= -67) {
icon += 4 icon += 4
} } else if (rssi >= -70) {
else if (rssi >= -70) { icon += 3
icon += 3 } else if (rssi >= -80) {
} icon += 2
else if (rssi >= -80) { } else if (rssi >= -90) {
icon += 2 icon += 1
} } else {
else if (rssi >= -90) { icon += 0
icon += 1 }
}
else { // secure
icon += 0 if (secure !== 0 && rssi >= -90) {
} icon += 'Lock'
}
// secure
if (secure !== 0 && rssi >= -90) { return icon
icon += 'Lock' })
}
return icon
});
const opts = { const opts = {
icons: { icons: {
iconfont: '', iconfont: '',
values: MY_ICONS values: MY_ICONS,
} },
} }
export default new Vuetify(opts) export default new Vuetify(opts)

@ -12,22 +12,22 @@ const SetupName = () => import('../views/Setup/Name')
const SetupAppearance = () => import('../views/Setup/Appearance') const SetupAppearance = () => import('../views/Setup/Appearance')
const SetupDone = () => import('../views/Setup/Done') const SetupDone = () => import('../views/Setup/Done')
Vue.use(VueRouter); Vue.use(VueRouter)
export default new VueRouter({ export default new VueRouter({
routes: [ routes: [
{ path: '/', component: Dashboard }, { path: '/', component: Dashboard },
{ path: '/settings', component: Settings, meta: { transitionName: 'slide' } }, { path: '/settings', component: Settings, meta: { transitionName: 'slide' } },
// setup wizard // setup wizard
{ path: '/setup/start', component: SetupStart, meta: { transitionName: 'slide' } }, { path: '/setup/start', component: SetupStart, meta: { transitionName: 'slide' } },
{ path: '/setup/country', component: SetupCountry, meta: { transitionName: 'slide' } }, { path: '/setup/country', component: SetupCountry, meta: { transitionName: 'slide' } },
{ path: '/setup/wifi', component: SetupWifi, meta: { transitionName: 'slide' } }, { path: '/setup/wifi', component: SetupWifi, meta: { transitionName: 'slide' } },
{ path: '/setup/weather', component: SetupWeather, meta: { transitionName: 'slide' } }, { path: '/setup/weather', component: SetupWeather, meta: { transitionName: 'slide' } },
{ path: '/setup/name', component: SetupName, meta: { transitionName: 'slide' } }, { path: '/setup/name', component: SetupName, meta: { transitionName: 'slide' } },
{ path: '/setup/appearance', component: SetupAppearance, meta: { transitionName: 'slide' } }, { path: '/setup/appearance', component: SetupAppearance, meta: { transitionName: 'slide' } },
{ path: '/setup/done', component: SetupDone, meta: { transitionName: 'slide' } }, { path: '/setup/done', component: SetupDone, meta: { transitionName: 'slide' } },
{ path: '*', redirect: '/' } { path: '*', redirect: '/' },
], ],
}); })

@ -1,33 +1,43 @@
<template> <template>
<v-container fluid _grid-list-md _pa-2> <v-container
class="_grid-list-md _pa-2"
fluid
>
<v-row> <v-row>
<v-col cols="12" md="6"> <v-col
<screen-card></screen-card> cols="12"
md="6"
>
<screen-card />
</v-col> </v-col>
<v-col cols="12" sm="6" md="4"> <v-col
<weather-card></weather-card> cols="12"
<device-card class="mt-5"></device-card> sm="6"
md="4"
>
<weather-card />
<device-card class="mt-5" />
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
</template> </template>
<script> <script>
import screenCard from "@/components/ScreenCard"; import screenCard from '@/components/ScreenCard'
import weatherCard from "@/components/WeatherCard"; import weatherCard from '@/components/WeatherCard'
import deviceCard from "@/components/DeviceCard"; import deviceCard from '@/components/DeviceCard'
export default { export default {
components: { components: {
screenCard, screenCard,
weatherCard, weatherCard,
deviceCard deviceCard,
}, },
data: () => ({ data: () => ({
isLoading: false isLoading: false,
}) }),
}; }
</script> </script>
<style scoped> <style scoped>
</style> </style>

@ -1,15 +1,31 @@
<template> <template>
<v-layout fluid fill-height> <v-row class="fluid fill-height">
<template v-if="isLoading"> <template v-if="isLoading">
<v-overlay :absolute="true" :value="true"> <v-overlay
<v-progress-circular indeterminate size="64"></v-progress-circular> :absolute="true"
:value="true"
>
<v-progress-circular
indeterminate
size="64"
/>
</v-overlay> </v-overlay>
</template> </template>
<v-container> <v-container>
<v-snackbar v-model="isSnackbar" :timeout="3000" color="success">i8n:saved</v-snackbar> <v-snackbar
v-model="isSnackbar"
<v-tabs v-model="tab" centered icons-and-text> :timeout="3000"
color="success"
>
i8n:saved
</v-snackbar>
<v-tabs
v-model="tab"
centered
icons-and-text
>
<v-tab> <v-tab>
Device Device
<v-icon>$tv</v-icon> <v-icon>$tv</v-icon>
@ -30,69 +46,88 @@
--> -->
</v-tabs> </v-tabs>
<v-card v-if="settings" class="mx-auto" width="400"> <v-card
v-if="settings"
class="mx-auto"
width="400"
>
<v-tabs-items v-model="tab"> <v-tabs-items v-model="tab">
<v-tab-item> <v-tab-item>
<v-card-text> <v-card-text>
<v-select <v-select
:items="deviceOrientation"
v-model="settings.device.angle" v-model="settings.device.angle"
:items="deviceOrientation"
label="i8n:Orientation" label="i8n:Orientation"
placeholder placeholder
></v-select> />
<v-select <v-select
:items="deviceTheme"
v-model="settings.device.theme" v-model="settings.device.theme"
:items="deviceTheme"
label="i8n:Theme" label="i8n:Theme"
placeholder placeholder
></v-select> />
<v-dialog v-model="dialogSystemUpdate" max-width="400"> <v-dialog
<template v-slot:activator="{ on }"> v-model="dialogSystemUpdate"
<v-btn class="my-5" block small outlined color="warning" v-on="on">System update</v-btn> max-width="400"
>
<template #activator="{ on }">
<v-btn
class="my-5"
block
small
outlined
color="warning"
v-on="on"
>
System update
</v-btn>
</template> </template>
<v-card :loading="system.updateProgress > 0"> <v-card :loading="system.updateProgress > 0">
<template v-slot:progress> <template #progress>
<v-progress-linear <v-progress-linear
v-model="system.updateProgress" v-model="system.updateProgress"
:indeterminate="system.updateProgress === 100" :indeterminate="system.updateProgress === 100"
height="10" height="10"
></v-progress-linear> />
</template> </template>
<v-card-title class="headline">System update</v-card-title> <v-card-title class="headline">
System update
</v-card-title>
<v-card-text> <v-card-text>
<!--
<v-alert border="left" type="warning" outlined>
Sed in libero ut nibh placerat accumsan. Phasellus leo dolor, tempus non, auctor et
</v-alert>
-->
<v-file-input <v-file-input
v-model="system.firmware" v-model="system.firmware"
show-size show-size
accept="application/octet-stream" accept="application/octet-stream"
label="Firmware" label="Firmware"
></v-file-input> />
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-btn text href="https://github.com/paperdash" target="_blank">Get firmware</v-btn>
<v-spacer></v-spacer>
<v-btn <v-btn
text
href="https://github.com/paperdash"
target="_blank"
>
Get firmware
</v-btn>
<v-spacer />
<v-btn
ref="firmware"
outlined outlined
color="warning" color="warning"
ref="firmware"
@click="onSystemUpdate()" @click="onSystemUpdate()"
>Update system</v-btn> >
Update system
<!-- </v-btn>
<v-btn color="green darken-1" text @click="dialogSystemUpdate = false">Disagree</v-btn>
<v-btn color="green darken-1" text @click="dialogSystemUpdate = false">Agree</v-btn>
-->
</v-card-actions> </v-card-actions>
</v-card> </v-card>
<v-dialog :value="system.updateResult !== null" persistent max-width="400"> <v-dialog
:value="system.updateResult !== null"
persistent
max-width="400"
>
<v-card> <v-card>
<v-card-title class="headline"> <v-card-title class="headline">
update result... update result...
@ -100,8 +135,13 @@
</v-card-title> </v-card-title>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer />
<v-btn text @click="onUpdateDone()">OK</v-btn> <v-btn
text
@click="onUpdateDone()"
>
OK
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
@ -111,11 +151,17 @@
<v-tab-item> <v-tab-item>
<v-card-text class="pb-0"> <v-card-text class="pb-0">
<v-row> <v-row>
<v-col cols="3" class="text-center mt-2 pb-0"> <v-col
cols="3"
class="text-center mt-2 pb-0"
>
<v-icon>$wb_sunny</v-icon> <v-icon>$wb_sunny</v-icon>
<br />Forecast <br>Forecast
</v-col> </v-col>
<v-col cols="6" class="text-center pb-0"> <v-col
cols="6"
class="text-center pb-0"
>
<v-text-field <v-text-field
v-model="settings.playlist.timer" v-model="settings.playlist.timer"
label="Switch every" label="Switch every"
@ -125,15 +171,21 @@
filled filled
suffix="seconds" suffix="seconds"
class="text-right" class="text-right"
></v-text-field> />
</v-col> </v-col>
<v-col cols="3" class="text-center mt-2 pb-0"> <v-col
cols="3"
class="text-center mt-2 pb-0"
>
<v-icon>$calendar_today</v-icon> <v-icon>$calendar_today</v-icon>
<br />Calendar <br>Calendar
</v-col> </v-col>
</v-row> </v-row>
<ul class="mt-5" v-if="0"> <ul
v-if="0"
class="mt-5"
>
<li>calendar</li> <li>calendar</li>
<li>weather forecast</li> <li>weather forecast</li>
<li>unsplash.com</li> <li>unsplash.com</li>
@ -143,30 +195,30 @@
<v-tab-item> <v-tab-item>
<v-card-text> <v-card-text>
<v-text-field <v-text-field
label="i8n:OpenWeatherMap API key"
v-model="settings.weather.api" v-model="settings.weather.api"
label="i8n:OpenWeatherMap API key"
placeholder="###" placeholder="###"
></v-text-field> />
<weather-find-location <weather-find-location
:api="settings.weather.api" :api="settings.weather.api"
:location.sync="settings.weather.location" :location.sync="settings.weather.location"
:lang="settings.weather.lang" :lang="settings.weather.lang"
:unit="settings.weather.unit" :unit="settings.weather.unit"
></weather-find-location> />
<v-select <v-select
:items="weatherLang"
v-model="settings.weather.lang" v-model="settings.weather.lang"
:items="weatherLang"
label="i8n:Lang" label="i8n:Lang"
placeholder placeholder
></v-select> />
<v-select <v-select
:items="weatherUnit"
v-model="settings.weather.unit" v-model="settings.weather.unit"
:items="weatherUnit"
label="i8n:Units" label="i8n:Units"
placeholder placeholder
></v-select> />
</v-card-text> </v-card-text>
</v-tab-item> </v-tab-item>
<!-- <!--
@ -196,192 +248,203 @@
</v-tabs-items> </v-tabs-items>
<v-card-actions> <v-card-actions>
<v-btn text to="/">i8n:cancel</v-btn> <v-btn
text
<v-spacer></v-spacer> to="/"
>
<v-btn text color="primary" @click="onSave()">i8n:Save</v-btn> i8n:cancel
</v-btn>
<v-spacer />
<v-btn
text
color="primary"
@click="onSave()"
>
i8n:Save
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-container> </v-container>
</v-layout> </v-row>
</template> </template>
<script> <script>
import apiDevice from "../api/device"; import apiDevice from '../api/device'
import weatherFindLocation from "./../components/WeatherFindLocation"; import weatherFindLocation from './../components/WeatherFindLocation'
import axios from "axios"; import axios from 'axios'
export default { export default {
name: "Settings", name: 'Settings',
components: { components: {
weatherFindLocation weatherFindLocation,
},
data: () => ({
isLoading: true,
isSnackbar: false,
tab: 0,
settings: null,
// 0 thru 3 corresponding to 4 cardinal rotations
deviceOrientation: [
{ text: "Nord", value: 0 },
{ text: "East", value: 1 },
{ text: "South", value: 2 },
{ text: "West", value: 3 }
],
deviceTheme: [
{ text: "Black", value: "black" },
{ text: "White", value: "white" }
],
deviceMode: [
{ text: "Active", value: "active" },
{ text: "Passive", value: "passive" }
],
// @see https://openweathermap.org/current#multi
weatherLang: [
{ text: "English", value: "en" },
{ text: "Deutsch", value: "de" }
],
weatherUnit: [
{ text: "Imperial", value: "" },
{ text: "Metrisch", value: "metric" }
],
dialogSystemUpdate: false,
system: {
firmware: null,
updateProgress: 0,
updateResult: null
}
}),
created() {
this.$vuetify.icons.values.tv = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/tv/baseline.svg"
)
};
this.$vuetify.icons.values.playlist = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/live_tv/baseline.svg"
)
}; // slideshow | playlist_play | live_tv | queue_play_next
this.$vuetify.icons.values.keys = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/insert_link/baseline.svg"
)
};
this.$vuetify.icons.values.cloud = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/cloud/baseline.svg"
)
};
this.$vuetify.icons.values.calendar_today = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/calendar_today/baseline.svg"
)
};
this.$vuetify.icons.values.wb_sunny = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/wb_sunny/baseline.svg"
)
};
this.$vuetify.icons.values.system_update = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/system_update_alt/baseline.svg"
)
};
this.$vuetify.icons.values.file = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/attach_file/baseline.svg"
)
};
this.$vuetify.icons.values.warning = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/warning/baseline.svg"
)
};
this.$vuetify.icons.values.clear = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/clear/baseline.svg"
)
};
apiDevice.getSettings(settings => {
this.settings = settings;
this.isLoading = false;
});
},
methods: {
onSave() {
this.isLoading = true;
apiDevice.putSettings(this.settings, data => {
console.log(data);
this.isLoading = false;
this.isSnackbar = true;
this.$router.push("/");
});
}, },
data: () => ({
isLoading: true,
isSnackbar: false,
tab: 0,
settings: null,
// 0 thru 3 corresponding to 4 cardinal rotations
deviceOrientation: [
{ text: 'Nord', value: 0 },
{ text: 'East', value: 1 },
{ text: 'South', value: 2 },
{ text: 'West', value: 3 },
],
deviceTheme: [
{ text: 'Black', value: 'black' },
{ text: 'White', value: 'white' },
],
deviceMode: [
{ text: 'Active', value: 'active' },
{ text: 'Passive', value: 'passive' },
],
// @see https://openweathermap.org/current#multi
weatherLang: [
{ text: 'English', value: 'en' },
{ text: 'Deutsch', value: 'de' },
],
weatherUnit: [
{ text: 'Imperial', value: '' },
{ text: 'Metrisch', value: 'metric' },
],
dialogSystemUpdate: false,
system: {
firmware: null,
updateProgress: 0,
updateResult: null,
},
}),
created () {
this.$vuetify.icons.values.tv = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/tv/baseline.svg'
),
}
this.$vuetify.icons.values.playlist = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/live_tv/baseline.svg'
),
} // slideshow | playlist_play | live_tv | queue_play_next
this.$vuetify.icons.values.keys = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/insert_link/baseline.svg'
),
}
this.$vuetify.icons.values.cloud = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/cloud/baseline.svg'
),
}
this.$vuetify.icons.values.calendar_today = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/calendar_today/baseline.svg'
),
}
this.$vuetify.icons.values.wb_sunny = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/wb_sunny/baseline.svg'
),
}
this.$vuetify.icons.values.system_update = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/system_update_alt/baseline.svg'
),
}
this.$vuetify.icons.values.file = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/attach_file/baseline.svg'
),
}
this.$vuetify.icons.values.warning = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/warning/baseline.svg'
),
}
this.$vuetify.icons.values.clear = {
component: () =>
import(
/* webpackChunkName: "icons" */ '!vue-svg-loader!@material-icons/svg/svg/clear/baseline.svg'
),
}
onSystemUpdate() { apiDevice.getSettings(settings => {
let self = this; this.settings = settings
self.system.updateProgress = 0;
const config = { this.isLoading = false
onUploadProgress: function(progressEvent) { })
let percentCompleted = Math.round( },
(progressEvent.loaded * 100) / progressEvent.total methods: {
); onSave () {
this.isLoading = true
self.system.updateProgress = percentCompleted; apiDevice.putSettings(this.settings, data => {
} console.log(data)
}; this.isLoading = false
this.isSnackbar = true
let formData = new FormData(); this.$router.push('/')
formData.append("update", this.system.firmware); })
},
axios onSystemUpdate () {
.post("/update", formData, config) const self = this
.then(response => { self.system.updateProgress = 0
console.log(response.data);
self.system.updateProgress = null; const config = {
self.system.updateResult = response.data.success; onUploadProgress: function (progressEvent) {
}) const percentCompleted = Math.round(
.catch(response => { (progressEvent.loaded * 100) / progressEvent.total,
console.log(response); )
self.system.updateProgress = null; self.system.updateProgress = percentCompleted
self.system.updateResult = false; },
}); }
},
onUpdateDone() { const formData = new FormData()
if (this.system.updateResult === true) { formData.append('update', this.system.firmware)
window.location = "/";
} else { axios
this.system.firmware = null; .post('/update', formData, config)
this.system.updateProgress = 0; .then(response => {
this.system.updateResult = null; console.log(response.data)
}
} self.system.updateProgress = null
self.system.updateResult = response.data.success
})
.catch(response => {
console.log(response)
self.system.updateProgress = null
self.system.updateResult = false
})
},
onUpdateDone () {
if (this.system.updateResult === true) {
window.location = '/'
} else {
this.system.firmware = null
this.system.updateProgress = 0
this.system.updateResult = null
}
},
},
} }
};
</script> </script>
<style scoped> <style scoped>

@ -1,15 +1,30 @@
<template> <template>
<v-container fluid _fill-height> <v-container
<v-btn v-if="currentStep > 0" text color="primary" class="pl-0" @click="currentStep--"> class="_fill-height"
fluid
>
<v-btn
v-if="currentStep > 0"
text
color="primary"
class="pl-0"
@click="currentStep--"
>
<v-icon>$prev</v-icon>Back <v-icon>$prev</v-icon>Back
</v-btn> </v-btn>
<template v-if="currentStep === 0"> <template v-if="currentStep === 0">
<!-- 1. hello --> <!-- 1. hello -->
<v-card flat class="mx-auto" width="520"> <v-card
<v-card-title class="display-2 mt-12 justify-center text-center">Hello paperdash</v-card-title> flat
class="mx-auto"
width="520"
>
<v-card-title class="display-2 mt-12 justify-center text-center">
Hello paperdash
</v-card-title>
<Case <case
v-if="0" v-if="0"
id="device_" id="device_"
:class="[device.theme, device.case, device.front, 'case_orange', 'my-12']" :class="[device.theme, device.case, device.front, 'case_orange', 'my-12']"
@ -37,12 +52,19 @@
</defs> </defs>
--> -->
<g id="border" fill="#262626" stroke="none"> <g
id="border"
fill="#262626"
stroke="none"
>
<path <path
d="M442 5110 c-227 -86 -417 -161 -422 -166 -4 -5 -12 -1063 -16 -2350 -7 -2292 -6 -2342 12 -2352 31 -16 817 -242 844 -242 14 0 1086 158 2383 352 l2358 353 6 25 c9 35 -66 3683 -76 3693 -4 4 -1049 194 -2322 422 -1273 228 -2323 416 -2334 419 -11 2 -206 -67 -433 -154z" d="M442 5110 c-227 -86 -417 -161 -422 -166 -4 -5 -12 -1063 -16 -2350 -7 -2292 -6 -2342 12 -2352 31 -16 817 -242 844 -242 14 0 1086 158 2383 352 l2358 353 6 25 c9 35 -66 3683 -76 3693 -4 4 -1049 194 -2322 422 -1273 228 -2323 416 -2334 419 -11 2 -206 -67 -433 -154z"
/> />
</g> </g>
<g fill="#f3f3f3" stroke="none"> <g
fill="#f3f3f3"
stroke="none"
>
<path <path
id="front" id="front"
d="M860 2630 l0 -2611 33 6 c17 3 1080 163 2360 355 1281 191 2330 350 2332 352 6 6 -70 3666 -76 3672 -4 4 -4627 836 -4645 836 -2 0 -4 -1175 -4 -2610z m2378 1721 c1217 -175 2214 -320 2216 -322 7 -6 69 -3179 63 -3185 -8 -9 -4489 -624 -4499 -618 -10 6 -11 4444 0 4444 4 0 1003 -144 2220 -319z m2249 2 c-4 -3 -7 0 -7 7 0 7 3 10 7 7 3 -4 3 -10 0 -14z m60 -2890 c-4 -3 -7 0 -7 7 0 7 3 10 7 7 3 -4 3 -10 0 -14z" d="M860 2630 l0 -2611 33 6 c17 3 1080 163 2360 355 1281 191 2330 350 2332 352 6 6 -70 3666 -76 3672 -4 4 -4627 836 -4645 836 -2 0 -4 -1175 -4 -2610z m2378 1721 c1217 -175 2214 -320 2216 -322 7 -6 69 -3179 63 -3185 -8 -9 -4489 -624 -4499 -618 -10 6 -11 4444 0 4444 4 0 1003 -144 2220 -319z m2249 2 c-4 -3 -7 0 -7 7 0 7 3 10 7 7 3 -4 3 -10 0 -14z m60 -2890 c-4 -3 -7 0 -7 7 0 7 3 10 7 7 3 -4 3 -10 0 -14z"
@ -59,24 +81,40 @@
</svg> </svg>
<v-card-actions> <v-card-actions>
<v-btn depressed block color="primary" @click="currentStep = 1">Continue</v-btn> <v-btn
depressed
block
color="primary"
@click="currentStep = 1"
>
Continue
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</template> </template>
<template v-else-if="currentStep === 1"> <template v-else-if="currentStep === 1">
<!-- country --> <!-- country -->
<v-card flat class="mx-auto" width="520"> <v-card
flat
class="mx-auto"
width="520"
>
<v-card-title <v-card-title
class="display-2 mb-12 justify-center text-center" class="display-2 mb-12 justify-center text-center"
>Select Your Country or Region</v-card-title> >
Select Your Country or Region
</v-card-title>
<v-list class="ml-5 pa-0"> <v-list class="ml-5 pa-0">
<template v-for="(country, code) in countries"> <template v-for="(country, code) in countries">
<div :key="code"> <div :key="code">
<v-divider></v-divider> <v-divider />
<v-list-item class="pl-1" @click="commitCountry(code, country)"> <v-list-item
class="pl-1"
@click="commitCountry(code, country)"
>
<!--<v-list-item-icon>{{ country.emoji }}</v-list-item-icon>--> <!--<v-list-item-icon>{{ country.emoji }}</v-list-item-icon>-->
<v-list-item-content>{{ country.native }}</v-list-item-content> <v-list-item-content>{{ country.native }}</v-list-item-content>
@ -92,15 +130,24 @@
<template v-else-if="currentStep === 2"> <template v-else-if="currentStep === 2">
<!-- timezone if needed --> <!-- timezone if needed -->
<v-card flat class="mx-auto" width="520"> <v-card
<v-card-title class="display-2 mb-12 justify-center text-center">Select Your Timezone</v-card-title> flat
class="mx-auto"
width="520"
>
<v-card-title class="display-2 mb-12 justify-center text-center">
Select Your Timezone
</v-card-title>
<v-list class="ml-5 pa-0"> <v-list class="ml-5 pa-0">
<template v-for="(zone, i) in timeZones"> <template v-for="(zone, i) in timeZones">
<div :key="i"> <div :key="i">
<v-divider></v-divider> <v-divider />
<v-list-item class="pl-1" @click="commitTimezone(zone)"> <v-list-item
class="pl-1"
@click="commitTimezone(zone)"
>
<v-list-item-content>{{ zone }}</v-list-item-content> <v-list-item-content>{{ zone }}</v-list-item-content>
<v-list-item-action> <v-list-item-action>
@ -109,96 +156,177 @@
</v-list-item> </v-list-item>
</div> </div>
</template> </template>
<v-divider></v-divider> <v-divider />
</v-list> </v-list>
</v-card> </v-card>
</template> </template>
<template v-else-if="currentStep === 3"> <template v-else-if="currentStep === 3">
<!-- wifi select & reboot --> <!-- wifi select & reboot -->
<v-card flat class="mx-auto" width="520"> <v-card
flat
class="mx-auto"
width="520"
>
<v-card-title class="display-2 mb-12 justify-center text-center"> <v-card-title class="display-2 mb-12 justify-center text-center">
Choose a Wi-Fi Choose a Wi-Fi
<br />Network <br>Network
</v-card-title> </v-card-title>
<v-list class="_ml-5 pa-0"> <v-list class="_ml-5 pa-0">
<v-list-item-group v-model="settings.wifi"> <v-list-item-group v-model="settings.wifi">
<template v-for="(wifi, i) in wifiAvailable"> <template v-for="(wifi, i) in wifiAvailable">
<div :key="i"> <div :key="i">
<v-divider v-if="i > 0"></v-divider> <v-divider v-if="i > 0" />
<v-list-item class="px-1" :value="wifi.ssid" @click.stop="wifiConnectModal = true"> <v-list-item
class="px-1"
:value="wifi.ssid"
@click.stop="wifiConnectModal = true"
>
<v-list-item-content> <v-list-item-content>
<v-list-item-title v-text="wifi.ssid"></v-list-item-title> <v-list-item-title v-text="wifi.ssid" />
<v-list-item-subtitle v-text="wifi.bssid"></v-list-item-subtitle> <v-list-item-subtitle v-text="wifi.bssid" />
</v-list-item-content> </v-list-item-content>
<v-list-item-icon> <v-list-item-icon>
<v-icon class="mx-2" v-if="wifi.secure">$lock</v-icon> <v-icon
<v-icon class="mx-2">{{ wifi.rssi | wifiIcon(0) }}</v-icon> v-if="wifi.secure"
<v-icon class="ml-3">$next</v-icon> class="mx-2"
>
$lock
</v-icon>
<v-icon class="mx-2">
{{ wifi.rssi | wifiIcon(0) }}
</v-icon>
<v-icon class="ml-3">
$next
</v-icon>
</v-list-item-icon> </v-list-item-icon>
</v-list-item> </v-list-item>
</div> </div>
</template> </template>
</v-list-item-group> </v-list-item-group>
<v-divider></v-divider> <v-divider />
<v-btn text color="primary" class="px-0 my-2">Choose Another Network</v-btn> <v-btn
text
color="primary"
class="px-0 my-2"
>
Choose Another Network
</v-btn>
</v-list> </v-list>
<v-dialog v-model="wifiConnectModal" max-width="400"> <v-dialog
v-model="wifiConnectModal"
max-width="400"
>
<setup-wifi-connect <setup-wifi-connect
:ssid="settings.wifi" :ssid="settings.wifi"
@connected="commitWifi()" @connected="commitWifi()"
@cancel="wifiConnectModal = false" @cancel="wifiConnectModal = false"
></setup-wifi-connect> />
</v-dialog> </v-dialog>
<v-divider></v-divider> <v-divider />
</v-card> </v-card>
</template> </template>
<template v-else-if="currentStep === 4"> <template v-else-if="currentStep === 4">
<!-- appearance --> <!-- appearance -->
<v-card flat class="mx-auto" width="520"> <v-card
<v-card-title class="display-2 mb-12 justify-center text-center">Appearance</v-card-title> flat
class="mx-auto"
width="520"
>
<v-card-title class="display-2 mb-12 justify-center text-center">
Appearance
</v-card-title>
<v-radio-group v-model="settings.theme" row> <v-radio-group
<v-radio label="Light" value="white"></v-radio> v-model="settings.theme"
<v-radio label="Dark" value="black"></v-radio> row
>
<v-radio
label="Light"
value="white"
/>
<v-radio
label="Dark"
value="black"
/>
</v-radio-group> </v-radio-group>
<v-card-actions> <v-card-actions>
<v-btn depressed block color="primary" @click="currentStep++">Continue</v-btn> <v-btn
depressed
block
color="primary"
@click="currentStep++"
>
Continue
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</template> </template>
<template v-else-if="currentStep === 5"> <template v-else-if="currentStep === 5">
<!-- weather --> <!-- weather -->
<v-card flat class="mx-auto" width="520"> <v-card
<v-card-title class="display-2 mb-12 justify-center text-center">Weather</v-card-title> flat
class="mx-auto"
width="520"
>
<v-card-title class="display-2 mb-12 justify-center text-center">
Weather
</v-card-title>
<setup-weather :settings="settings"></setup-weather> <setup-weather :settings="settings" />
<v-card-actions class="flex-column"> <v-card-actions class="flex-column">
<v-btn depressed block color="primary" @click="currentStep++">Continue</v-btn> <v-btn
<v-btn class="ma-0 mt-3" text block color="primary">Set Up Later in Settings</v-btn> depressed
block
color="primary"
@click="currentStep++"
>
Continue
</v-btn>
<v-btn
class="ma-0 mt-3"
text
block
color="primary"
>
Set Up Later in Settings
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</template> </template>
<template v-else-if="currentStep === 6"> <template v-else-if="currentStep === 6">
<!-- completed --> <!-- completed -->
<v-card flat class="mx-auto mt-12" width="600"> <v-card
flat
class="mx-auto mt-12"
width="600"
>
<!--<v-card-title class="display-2 mb-12 justify-center text-center">This is Your <br/> paperdash</v-card-title>--> <!--<v-card-title class="display-2 mb-12 justify-center text-center">This is Your <br/> paperdash</v-card-title>-->
<v-card-title class="display-2 mb-12 justify-center text-center">Welcome to paperdash</v-card-title> <v-card-title class="display-2 mb-12 justify-center text-center">
Welcome to paperdash
</v-card-title>
<v-card-actions> <v-card-actions>
<v-btn depressed block color="primary" to="/">Get Started</v-btn> <v-btn
depressed
block
color="primary"
to="/"
>
Get Started
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</template> </template>
@ -206,82 +334,82 @@
</template> </template>
<script> <script>
import apiDevice from "@/api/device"; import apiDevice from '@/api/device'
import { countries } from "countries-list"; import { countries } from 'countries-list'
import timezones from "countries-and-timezones"; import timezones from 'countries-and-timezones'
import setupWifiConnect from "@/components/SetupWifiConnect"; import setupWifiConnect from '@/components/SetupWifiConnect'
import setupWeather from "@/components/SetupWeather"; import setupWeather from '@/components/SetupWeather'
import Case from "!vue-svg-loader!@/assets/case.svg"; import Case from '!vue-svg-loader!@/assets/case.svg'
export default { export default {
components: { components: {
Case, Case,
setupWifiConnect, setupWifiConnect,
setupWeather setupWeather,
},
data: () => ({
// weather + ggf. image pool
currentStep: 5,
settings: {
country: "DE",
language: "en", // (alpha-2 codes)
timezone: "Europe/Berlin",
wifi: null,
theme: null,
weather: {
api: '883b3c87223430d6f3a399645f8ba12b',
location: null,
lang: null,
unit: null
}
}, },
data: () => ({
device: { // weather + ggf. image pool
theme: "theme_w", currentStep: 5,
case: "case_whitey", settings: {
front: "front_whitey" country: 'DE',
language: 'en', // (alpha-2 codes)
timezone: 'Europe/Berlin',
wifi: null,
theme: null,
weather: {
api: '883b3c87223430d6f3a399645f8ba12b',
location: null,
lang: null,
unit: null,
},
},
device: {
theme: 'theme_w',
case: 'case_whitey',
front: 'front_whitey',
},
countries: countries,
timeZones: [],
wifi: {
available: [],
connectSSID: null,
},
wifiAvailable: [],
wifiConnectModal: false,
}),
created () {
apiDevice.wifiScan(list => {
this.wifiAvailable = list
this.isLoading = false
})
}, },
methods: {
countries: countries, commitCountry (code, country) {
timeZones: [], this.settings.country = code
this.settings.language = country.languages[0]
wifi: {
available: [], // get also timezone
connectSSID: null const zone = timezones.getCountry(code)
}, if (zone.timezones.length > 1) {
wifiAvailable: [], this.timeZones = zone.timezones
wifiConnectModal: false this.currentStep++
}), } else {
created() { this.settings.timezone = zone.timezones[0]
apiDevice.wifiScan(list => { this.currentStep += 2
this.wifiAvailable = list; }
},
this.isLoading = false;
}); commitTimezone (zone) {
}, this.settings.timezone = zone
methods: { this.currentStep++
commitCountry(code, country) { },
this.settings.country = code; commitWifi () {},
this.settings.language = country.languages[0];
// get also timezone
let zone = timezones.getCountry(code);
if (zone.timezones.length > 1) {
this.timeZones = zone.timezones;
this.currentStep++;
} else {
this.settings.timezone = zone.timezones[0];
this.currentStep += 2;
}
},
commitTimezone(zone) {
this.settings.timezone = zone;
this.currentStep++;
}, },
commitWifi() {}
} }
};
</script> </script>
<style scoped> <style scoped>

@ -1,17 +1,45 @@
<template> <template>
<v-container fluid _fill-height> <v-container
<v-row no-gutters justify="center"> class="_fill-height"
<v-col lg="5" md="6" sm="8"> fluid
>
<v-row
no-gutters
justify="center"
>
<v-col
lg="5"
md="6"
sm="8"
>
<v-card flat> <v-card flat>
<v-card-title class="display-2 mb-12 justify-center text-center">Appearance</v-card-title> <v-card-title class="display-2 mb-12 justify-center text-center">
Appearance
</v-card-title>
<v-radio-group v-model="settings.device.theme" row> <v-radio-group
<v-radio label="Light" value="white"></v-radio> v-model="settings.device.theme"
<v-radio label="Dark" value="black"></v-radio> row
>
<v-radio
label="Light"
value="white"
/>
<v-radio
label="Dark"
value="black"
/>
</v-radio-group> </v-radio-group>
<v-card-actions> <v-card-actions>
<v-btn depressed block color="primary" @click="commitStep()">Continue</v-btn> <v-btn
depressed
block
color="primary"
@click="commitStep()"
>
Continue
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-col> </v-col>
@ -20,34 +48,34 @@
</template> </template>
<script> <script>
import apiDevice from "@/api/device"; import apiDevice from '@/api/device'
export default { export default {
data: () => ({ data: () => ({
isLoading: true, isLoading: true,
isSaving: false, isSaving: false,
settings: null settings: null,
}), }),
created() { created () {
apiDevice.getSettings(settings => { apiDevice.getSettings(settings => {
this.settings = settings; this.settings = settings
this.isLoading = false; this.isLoading = false
}); })
}, },
methods: { methods: {
commitStep() { commitStep () {
this.isSaving = true; this.isSaving = true
apiDevice.putSettings({ device: this.settings.device }, () => { apiDevice.putSettings({ device: this.settings.device }, () => {
this.isSaving = false; this.isSaving = false
this.nextStep(); this.nextStep()
}); })
},
nextStep () {
this.$router.push('/setup/done')
},
}, },
nextStep() {
this.$router.push("/setup/done");
}
} }
}; </script>
</script>

@ -1,20 +1,35 @@
<template> <template>
<v-container fluid _fill-height> <v-container
<v-row no-gutters justify="center"> class="_fill-height"
<v-col lg="5" md="6" sm="8"> fluid
>
<v-row
no-gutters
justify="center"
>
<v-col
lg="5"
md="6"
sm="8"
>
<template v-if="currentStep === 0"> <template v-if="currentStep === 0">
<!-- country --> <!-- country -->
<v-card flat> <v-card flat>
<v-card-title <v-card-title
class="display-2 mb-12 justify-center text-center" class="display-2 mb-12 justify-center text-center"
>Select Your Country or Region</v-card-title> >
Select Your Country or Region
</v-card-title>
<v-list class="ml-5 pa-0"> <v-list class="ml-5 pa-0">
<template v-for="(country, code) in availableCountries"> <template v-for="(country, code) in availableCountries">
<div :key="code"> <div :key="code">
<v-divider></v-divider> <v-divider />
<v-list-item class="pl-1" @click="commitCountry(code, country)"> <v-list-item
class="pl-1"
@click="commitCountry(code, country)"
>
<!--<v-list-item-icon>{{ country.emoji }}</v-list-item-icon>--> <!--<v-list-item-icon>{{ country.emoji }}</v-list-item-icon>-->
<v-list-item-content>{{ country.native }}</v-list-item-content> <v-list-item-content>{{ country.native }}</v-list-item-content>
@ -31,14 +46,19 @@
<template v-else-if="currentStep === 1"> <template v-else-if="currentStep === 1">
<!-- timezone if needed --> <!-- timezone if needed -->
<v-card flat> <v-card flat>
<v-card-title class="display-2 mb-12 justify-center text-center">Select Your Timezone</v-card-title> <v-card-title class="display-2 mb-12 justify-center text-center">
Select Your Timezone
</v-card-title>
<v-list class="ml-5 pa-0"> <v-list class="ml-5 pa-0">
<template v-for="(zone, i) in availableTimeZones"> <template v-for="(zone, i) in availableTimeZones">
<div :key="i"> <div :key="i">
<v-divider></v-divider> <v-divider />
<v-list-item class="pl-1" @click="commitTimezone(zone)"> <v-list-item
class="pl-1"
@click="commitTimezone(zone)"
>
<v-list-item-content>{{ zone }}</v-list-item-content> <v-list-item-content>{{ zone }}</v-list-item-content>
<v-list-item-action> <v-list-item-action>
@ -47,7 +67,7 @@
</v-list-item> </v-list-item>
</div> </div>
</template> </template>
<v-divider></v-divider> <v-divider />
</v-list> </v-list>
</v-card> </v-card>
</template> </template>
@ -57,64 +77,64 @@
</template> </template>
<script> <script>
import apiDevice from "@/api/device"; import apiDevice from '@/api/device'
import { countries } from "countries-list"; import { countries } from 'countries-list'
import timezones from "countries-and-timezones"; import timezones from 'countries-and-timezones'
export default { export default {
data: () => ({ data: () => ({
currentStep: 0, currentStep: 0,
isLoading: true, isLoading: true,
isSaving: true, isSaving: true,
settings: null, settings: null,
availableCountries: countries, availableCountries: countries,
availableTimeZones: [] availableTimeZones: [],
}), }),
created() { created () {
apiDevice.getSettings(settings => { apiDevice.getSettings(settings => {
this.settings = settings; this.settings = settings
this.isLoading = false; this.isLoading = false
}); })
},
methods: {
commitCountry(code, country) {
this.settings.system.country = code;
this.settings.system.language = country.languages[0];
// get also timezone
const zone = timezones.getCountry(code);
if (zone.timezones.length > 1) {
this.availableTimeZones = zone.timezones;
this.currentStep = 1;
} else {
this.commitTimezone(zone.timezones[0]);
}
}, },
methods: {
commitTimezone(zone) { commitCountry (code, country) {
this.settings.system.timezone = zone; this.settings.system.country = code
this.settings.system.language = country.languages[0]
const timezone = timezones.getTimezone(zone);
this.settings.system.utc = timezone.utcOffset * 60; // get also timezone
this.settings.system.dst = timezone.dstOffset * 60; const zone = timezones.getCountry(code)
if (zone.timezones.length > 1) {
this.commitStep(); this.availableTimeZones = zone.timezones
this.currentStep = 1
} else {
this.commitTimezone(zone.timezones[0])
}
},
commitTimezone (zone) {
this.settings.system.timezone = zone
const timezone = timezones.getTimezone(zone)
this.settings.system.utc = timezone.utcOffset * 60
this.settings.system.dst = timezone.dstOffset * 60
this.commitStep()
},
commitStep () {
this.isSaving = true
apiDevice.putSettings({ system: this.settings.system }, () => {
this.isSaving = false
this.$router.push('/setup/wifi')
})
},
}, },
commitStep() {
this.isSaving = true;
apiDevice.putSettings({ system: this.settings.system }, () => {
this.isSaving = false;
this.$router.push("/setup/wifi");
});
}
} }
};
</script> </script>
<style scoped> <style scoped>
@ -123,4 +143,4 @@ export default {
.v-card__title { .v-card__title {
word-break: normal; word-break: normal;
} }
</style> </style>

@ -1,36 +1,52 @@
<template> <template>
<v-container fluid _fill-height> <v-container
<v-card flat class="mx-auto" width="540"> class="_fill-height"
fluid
>
<v-card
flat
class="mx-auto"
width="540"
>
<!--<v-card-title class="display-2 mb-12 justify-center text-center">Welcome to paperdash</v-card-title>--> <!--<v-card-title class="display-2 mb-12 justify-center text-center">Welcome to paperdash</v-card-title>-->
<v-card-title class="display-2 mb-12 justify-center text-center">Hello {{ settings.device.name }}</v-card-title> <v-card-title class="display-2 mb-12 justify-center text-center">
Hello {{ settings.device.name }}
</v-card-title>
<v-card-actions> <v-card-actions>
<v-btn outlined block color="primary" @click="onStart">Let's start</v-btn> <v-btn
outlined
block
color="primary"
@click="onStart"
>
Let's start
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-container> </v-container>
</template> </template>
<script> <script>
import apiDevice from "@/api/device"; import apiDevice from '@/api/device'
export default { export default {
data: () => ({ data: () => ({
isLoading: true, isLoading: true,
isSaving: false, isSaving: false,
settings: null settings: null,
}), }),
created() { created () {
apiDevice.getSettings(settings => { apiDevice.getSettings(settings => {
this.settings = settings; this.settings = settings
this.isLoading = false; this.isLoading = false
}); })
}, },
methods: { methods: {
onStart() { onStart () {
this.$router.push("/"); this.$router.push('/')
} },
},
} }
}; </script>
</script>

@ -1,28 +1,56 @@
<template> <template>
<v-container fluid _fill-height> <v-container
<v-row no-gutters justify="center"> class="_fill-height"
<v-col lg="5" md="6" sm="8"> fluid
>
<v-row
no-gutters
justify="center"
>
<v-col
lg="5"
md="6"
sm="8"
>
<v-card flat> <v-card flat>
<div class="justify-center text-center"> <div class="justify-center text-center">
<v-icon viewBox="0 0 24 24" style="width: 64px; height: 64px; fill: #FF9800">$face</v-icon> <v-icon
view-box="0 0 24 24"
style="width: 64px; height: 64px; fill: #FF9800"
>
$face
</v-icon>
</div> </div>
<v-card-title class="display-2 mb-12 justify-center text-center">Give it a name</v-card-title> <v-card-title class="display-2 mb-12 justify-center text-center">
Give it a name
</v-card-title>
<p <p
class="text-center" class="text-center"
>TODO:Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam</p> >
TODO:Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam
</p>
<v-skeleton-loader v-if="isLoading" type="list-item-two-line" class="mx-auto"></v-skeleton-loader> <v-skeleton-loader
v-if="isLoading"
type="list-item-two-line"
class="mx-auto"
/>
<template v-else> <template v-else>
<v-card-text> <v-card-text>
<v-text-field label="i8n:My paperdash name" v-model="settings.device.name"> <v-text-field
<template v-slot:append-outer> v-model="settings.device.name"
label="i8n:My paperdash name"
>
<template #append-outer>
<v-icon <v-icon
viewBox="0 0 24 24" view-box="0 0 24 24"
style="width: 48px; height: 48px;" style="width: 48px; height: 48px;"
@click="setRandomeName()" @click="setRandomeName()"
>$autorenew</v-icon> >
$autorenew
</v-icon>
</template> </template>
</v-text-field> </v-text-field>
</v-card-text> </v-card-text>
@ -35,7 +63,9 @@
block block
color="primary" color="primary"
@click="commitStep()" @click="commitStep()"
>Continue</v-btn> >
Continue
</v-btn>
</v-card-actions> </v-card-actions>
</template> </template>
</v-card> </v-card>
@ -45,53 +75,53 @@
</template> </template>
<script> <script>
import apiDevice from "@/api/device"; import apiDevice from '@/api/device'
import randomNames from "@/assets/fantasyNames.json"; import randomNames from '@/assets/fantasyNames.json'
export default { export default {
data: () => ({ data: () => ({
isLoading: true, isLoading: true,
isSaving: false, isSaving: false,
settings: null settings: null,
}), }),
created() { computed: {
apiDevice.getSettings(settings => { isStepValid () {
this.settings = settings; return (
this.settings.device.name !== undefined &&
this.settings.device.name !== ''
)
},
},
created () {
apiDevice.getSettings(settings => {
this.settings = settings
if (!this.isStepValid) { if (!this.isStepValid) {
this.setRandomeName(); this.setRandomeName()
} }
this.isLoading = false; this.isLoading = false
}); })
}, },
computed: { methods: {
isStepValid() { commitStep () {
return ( this.isSaving = true
this.settings.device.name != undefined &&
this.settings.device.name !== ""
);
}
},
methods: {
commitStep() {
this.isSaving = true;
apiDevice.putSettings({ device: this.settings.device }, () => { apiDevice.putSettings({ device: this.settings.device }, () => {
this.isSaving = false; this.isSaving = false
this.nextStep(); this.nextStep()
}); })
}, },
nextStep() { nextStep () {
this.$router.push("/setup/appearance"); this.$router.push('/setup/appearance')
},
setRandomeName () {
this.settings.device.name =
randomNames[Math.floor(Math.random() * randomNames.length)]
},
}, },
setRandomeName() {
this.settings.device.name =
randomNames[Math.floor(Math.random() * randomNames.length)];
}
} }
};
</script> </script>
<style scoped> <style scoped>
@ -99,4 +129,4 @@ export default {
font-size: 2.2em; font-size: 2.2em;
max-height: inherit; max-height: inherit;
} }
</style> </style>

@ -1,87 +1,102 @@
<template> <template>
<v-container fluid _fill-height> <v-container
<v-row no-gutters justify="center"> class="_fill-height"
<v-col lg="5" md="6" sm="8"> fluid
<v-card flat> >
<v-card-title class="display-2 mt-12 justify-center text-center">Hello paperdash</v-card-title> <v-row
no-gutters
justify="center"
>
<v-col
lg="5"
md="6"
sm="8"
>
<v-card flat>
<v-card-title class="display-2 mt-12 justify-center text-center">
Hello paperdash
</v-card-title>
<Case <Case
v-if="0" v-if="0"
id="device_" id="device_"
:class="[device.theme, device.case, device.front, 'case_orange', 'my-12']" :class="[device.theme, device.case, device.front, 'case_orange', 'my-12']"
/> />
<svg <svg
id="device" id="device"
:class="[device.theme, device.case, device.front, 'case_orange front_orange', 'my-12 mx-auto']" :class="[device.theme, device.case, device.front, 'case_orange front_orange', 'my-12 mx-auto']"
version="1.0" version="1.0"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
_width="561px" _width="561px"
_height="527px" _height="527px"
viewBox="0 0 5610 5270" viewBox="0 0 5610 5270"
preserveAspectRatio="xMidYMid meet" preserveAspectRatio="xMidYMid meet"
width="400" width="400"
> >
<!--
<defs>
<pattern id="pattern_b" width="100%" height="100%">
<image x="0" y="0" height="84%" href="/face-weather-b.png"/>
</pattern>
<pattern id="pattern_w" width="100%" height="100%">
<image x="0" y="0" height="84%" href="/face-weather-w.png"/>
</pattern>
</defs>
-->
<g id="border" fill="#262626" stroke="none"> <g
<path id="border"
d="M442 5110 c-227 -86 -417 -161 -422 -166 -4 -5 -12 -1063 -16 -2350 -7 -2292 -6 -2342 12 -2352 31 -16 817 -242 844 -242 14 0 1086 158 2383 352 l2358 353 6 25 c9 35 -66 3683 -76 3693 -4 4 -1049 194 -2322 422 -1273 228 -2323 416 -2334 419 -11 2 -206 -67 -433 -154z" fill="#262626"
/> stroke="none"
</g> >
<g fill="#f3f3f3" stroke="none"> <path
<path d="M442 5110 c-227 -86 -417 -161 -422 -166 -4 -5 -12 -1063 -16 -2350 -7 -2292 -6 -2342 12 -2352 31 -16 817 -242 844 -242 14 0 1086 158 2383 352 l2358 353 6 25 c9 35 -66 3683 -76 3693 -4 4 -1049 194 -2322 422 -1273 228 -2323 416 -2334 419 -11 2 -206 -67 -433 -154z"
id="front" />
d="M860 2630 l0 -2611 33 6 c17 3 1080 163 2360 355 1281 191 2330 350 2332 352 6 6 -70 3666 -76 3672 -4 4 -4627 836 -4645 836 -2 0 -4 -1175 -4 -2610z m2378 1721 c1217 -175 2214 -320 2216 -322 7 -6 69 -3179 63 -3185 -8 -9 -4489 -624 -4499 -618 -10 6 -11 4444 0 4444 4 0 1003 -144 2220 -319z m2249 2 c-4 -3 -7 0 -7 7 0 7 3 10 7 7 3 -4 3 -10 0 -14z m60 -2890 c-4 -3 -7 0 -7 7 0 7 3 10 7 7 3 -4 3 -10 0 -14z" </g>
/> <g
<path fill="#f3f3f3"
id="image" stroke="none"
d="M1022 4642 c-7 -19 5 -4393 13 -4400 5 -5 4465 605 4472 611 4 4 -59 3161 -63 3166 -3 3 -3200 465 -4387 634 -19 2 -31 -1 -35 -11z" >
/> <path
<path id="front"
id="case" d="M860 2630 l0 -2611 33 6 c17 3 1080 163 2360 355 1281 191 2330 350 2332 352 6 6 -70 3666 -76 3672 -4 4 -4627 836 -4645 836 -2 0 -4 -1175 -4 -2610z m2378 1721 c1217 -175 2214 -320 2216 -322 7 -6 69 -3179 63 -3185 -8 -9 -4489 -624 -4499 -618 -10 6 -11 4444 0 4444 4 0 1003 -144 2220 -319z m2249 2 c-4 -3 -7 0 -7 7 0 7 3 10 7 7 3 -4 3 -10 0 -14z m60 -2890 c-4 -3 -7 0 -7 7 0 7 3 10 7 7 3 -4 3 -10 0 -14z"
d="M438 5081 c-214 -81 -390 -150 -393 -153 -7 -6 -28 -4658 -22 -4664 2 -2 182 -56 400 -119 218 -64 403 -118 412 -121 13 -6 15 259 15 2600 0 2078 -3 2606 -12 2605 -7 0 -187 -67 -400 -148z" />
/> <path
</g> id="image"
</svg> d="M1022 4642 c-7 -19 5 -4393 13 -4400 5 -5 4465 605 4472 611 4 4 -59 3161 -63 3166 -3 3 -3200 465 -4387 634 -19 2 -31 -1 -35 -11z"
/>
<path
id="case"
d="M438 5081 c-214 -81 -390 -150 -393 -153 -7 -6 -28 -4658 -22 -4664 2 -2 182 -56 400 -119 218 -64 403 -118 412 -121 13 -6 15 259 15 2600 0 2078 -3 2606 -12 2605 -7 0 -187 -67 -400 -148z"
/>
</g>
</svg>
<v-card-actions> <v-card-actions>
<v-btn depressed block color="primary" @click="commitStep()">Continue</v-btn> <v-btn
</v-card-actions> depressed
</v-card> block
</v-col> color="primary"
</v-row> @click="commitStep()"
>
Continue
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container> </v-container>
</template> </template>
<script> <script>
export default { export default {
data: () => ({ data: () => ({
device: { device: {
theme: "theme_w", theme: 'theme_w',
case: "case_whitey", case: 'case_whitey',
front: "front_whitey" front: 'front_whitey',
} },
}), }),
methods: { methods: {
commitStep() { commitStep () {
// TODO sav // TODO sav
this.$router.push("/setup/country"); this.$router.push('/setup/country')
} },
},
} }
};
</script> </script>
<style scoped> <style scoped>
#device #border, #device #border,
#device > path { #device > path {

@ -1,24 +1,46 @@
<template> <template>
<v-container fluid _fill-height> <v-container
<v-row no-gutters justify="center"> class="_fill-height"
<v-col lg="5" md="6" sm="8"> fluid
>
<v-row
no-gutters
justify="center"
>
<v-col
lg="5"
md="6"
sm="8"
>
<v-card flat> <v-card flat>
<div class="justify-center text-center"> <div class="justify-center text-center">
<v-icon viewBox="0 0 24 24" style="width: 64px; height: 64px; fill: #FF9800">$wb_sunny</v-icon> <v-icon
view-box="0 0 24 24"
style="width: 64px; height: 64px; fill: #FF9800"
>
$wb_sunny
</v-icon>
</div> </div>
<v-card-title class="display-2 mb-12 justify-center text-center">Weather</v-card-title> <v-card-title class="display-2 mb-12 justify-center text-center">
Weather
</v-card-title>
<v-skeleton-loader <v-skeleton-loader
v-if="isLoading" v-if="isLoading"
type="list-item-two-line,list-item-two-line" type="list-item-two-line,list-item-two-line"
class="mx-auto" class="mx-auto"
></v-skeleton-loader> />
<template v-else> <template v-else>
<v-card-text> <v-card-text>
<v-text-field label="i8n:OpenWeatherMap API key" v-model="settings.weather.api"> <v-text-field
<template v-slot:append-outer> v-model="settings.weather.api"
<v-icon @click="registerApiKey()">$open_in_new</v-icon> label="i8n:OpenWeatherMap API key"
>
<template #append-outer>
<v-icon @click="registerApiKey()">
$open_in_new
</v-icon>
</template> </template>
</v-text-field> </v-text-field>
@ -27,7 +49,7 @@
:location.sync="settings.weather.location" :location.sync="settings.weather.location"
:lang="lang" :lang="lang"
:unit="unit" :unit="unit"
></weather-find-location> />
</v-card-text> </v-card-text>
<v-card-actions class="flex-column"> <v-card-actions class="flex-column">
@ -37,14 +59,18 @@
block block
color="primary" color="primary"
@click="commitStep()" @click="commitStep()"
>Continue</v-btn> >
Continue
</v-btn>
<v-btn <v-btn
class="ma-0 mt-3" class="ma-0 mt-3"
text text
block block
color="primary" color="primary"
@click="nextStep()" @click="nextStep()"
>Set Up Later in Settings</v-btn> >
Set Up Later in Settings
</v-btn>
</v-card-actions> </v-card-actions>
</template> </template>
</v-card> </v-card>
@ -54,48 +80,48 @@
</template> </template>
<script> <script>
import apiDevice from "@/api/device"; import apiDevice from '@/api/device'
import weatherFindLocation from "@/components/WeatherFindLocation"; import weatherFindLocation from '@/components/WeatherFindLocation'
export default { export default {
components: { components: {
weatherFindLocation weatherFindLocation,
},
data: () => ({
isLoading: true,
settings: null
}),
created() {
apiDevice.getSettings(settings => {
this.settings = settings;
this.isLoading = false;
});
},
computed: {
lang() {
return this.settings.language || "EN";
}, },
unit() { data: () => ({
return this.settings.language === "EN" ? "" : "metric"; isLoading: true,
settings: null,
}),
computed: {
lang () {
return this.settings.language || 'EN'
},
unit () {
return this.settings.language === 'EN' ? '' : 'metric'
},
isLocationValid () {
return this.settings.weather.location > 0
},
}, },
isLocationValid() { created () {
return this.settings.weather.location > 0; apiDevice.getSettings(settings => {
} this.settings = settings
},
methods: {
commitStep() {
// TODO sav
this.nextStep(); this.isLoading = false
})
}, },
nextStep() {
this.$router.push("/setup/name"); methods: {
commitStep () {
// TODO sav
this.nextStep()
},
nextStep () {
this.$router.push('/setup/name')
},
registerApiKey () {
window.open('http://openweathermap.org/')
},
}, },
registerApiKey() {
window.open("http://openweathermap.org/");
}
} }
}; </script>
</script>

@ -1,27 +1,42 @@
<template> <template>
<v-container fluid _fill-height> <v-container
<v-row no-gutters justify="center"> class="_fill-height"
<v-col lg="5" md="6" sm="8"> fluid
>
<v-row
no-gutters
justify="center"
>
<v-col
lg="5"
md="6"
sm="8"
>
<v-card flat> <v-card flat>
<v-card-title class="display-2 mb-12 justify-center text-center"> <v-card-title class="display-2 mb-12 justify-center text-center">
Choose a Choose a
<br />Wi-Fi Network <br>Wi-Fi Network
</v-card-title> </v-card-title>
<v-skeleton-loader <v-skeleton-loader
v-if="isLoading" v-if="isLoading"
type="list-item-two-line,list-item-two-line,list-item-two-line" type="list-item-two-line,list-item-two-line,list-item-two-line"
class="mx-auto" class="mx-auto"
></v-skeleton-loader> />
<v-list v-else> <v-list v-else>
<template v-for="(wifi, i) in wifiAvailable"> <template v-for="(wifi, i) in wifiAvailable">
<div :key="i"> <div :key="i">
<v-divider v-if="i > 0"></v-divider> <v-divider v-if="i > 0" />
<v-list-item class="px-1" @click="onWifiSelect(wifi)"> <v-list-item
class="px-1"
@click="onWifiSelect(wifi)"
>
<v-list-item-icon class="mr-2 ml-2"> <v-list-item-icon class="mr-2 ml-2">
<v-icon v-if="wifi.ssid === settings.system.wifi">$check</v-icon> <v-icon v-if="wifi.ssid === settings.system.wifi">
$check
</v-icon>
<v-progress-circular <v-progress-circular
v-if="wifi.ssid === connectingSSID" v-if="wifi.ssid === connectingSSID"
@ -29,34 +44,52 @@
:width="2" :width="2"
color="grey " color="grey "
indeterminate indeterminate
></v-progress-circular> />
</v-list-item-icon> </v-list-item-icon>
<v-list-item-content dark> <v-list-item-content dark>
<v-list-item-title v-text="wifi.ssid"></v-list-item-title> <v-list-item-title v-text="wifi.ssid" />
<v-list-item-subtitle v-text="wifi.bssid"></v-list-item-subtitle> <v-list-item-subtitle v-text="wifi.bssid" />
</v-list-item-content> </v-list-item-content>
<v-list-item-icon> <v-list-item-icon>
<v-icon class="mx-2" v-if="wifi.secure">$lock</v-icon> <v-icon
<v-icon class="mx-2">{{ wifi.rssi | wifiIcon(0) }}</v-icon> v-if="wifi.secure"
<v-icon class="ml-3">$next</v-icon> class="mx-2"
>
$lock
</v-icon>
<v-icon class="mx-2">
{{ wifi.rssi | wifiIcon(0) }}
</v-icon>
<v-icon class="ml-3">
$next
</v-icon>
</v-list-item-icon> </v-list-item-icon>
</v-list-item> </v-list-item>
</div> </div>
</template> </template>
<v-divider></v-divider> <v-divider />
<v-btn text color="primary" class="_px-0 my-2">Choose Another Network</v-btn> <v-btn
text
color="primary"
class="_px-0 my-2"
>
Choose Another Network
</v-btn>
</v-list> </v-list>
<v-dialog v-model="wifiPasswordModal" max-width="450"> <v-dialog
v-model="wifiPasswordModal"
max-width="450"
>
<setup-wifi-connect <setup-wifi-connect
:ssid="connectSSID" :ssid="connectSSID"
:onConnect="onWifiConnect" :on-connect="onWifiConnect"
@cancel="wifiPasswordModal = false" @cancel="wifiPasswordModal = false"
></setup-wifi-connect> />
</v-dialog> </v-dialog>
</v-card> </v-card>
</v-col> </v-col>
@ -65,49 +98,49 @@
</template> </template>
<script> <script>
import apiDevice from "@/api/device"; import apiDevice from '@/api/device'
import setupWifiConnect from "@/components/SetupWifiConnect"; import setupWifiConnect from '@/components/SetupWifiConnect'
export default {
components: {
setupWifiConnect
},
data: () => ({
isLoading: true,
settings: null,
connectSSID: null,
connectingSSID: "",
wifiAvailable: [],
wifiPasswordModal: false
}),
created() {
apiDevice.getSettings(settings => {
this.settings = settings;
apiDevice.wifiScan(list => {
this.wifiAvailable = list;
this.isLoading = false;
});
});
},
methods: {
onWifiSelect(wifi) {
if (wifi.secure) {
this.connectSSID = wifi.ssid;
this.wifiPasswordModal = true;
} else {
this.onWifiConnect(wifi.ssid, "");
}
},
onWifiConnect(ssid, password) {
this.connectingSSID = ssid;
this.wifiPasswordModal = false;
apiDevice.wifiConnect(ssid, password, () => {}); export default {
} components: {
setupWifiConnect,
},
data: () => ({
isLoading: true,
settings: null,
connectSSID: null,
connectingSSID: '',
wifiAvailable: [],
wifiPasswordModal: false,
}),
created () {
apiDevice.getSettings(settings => {
this.settings = settings
apiDevice.wifiScan(list => {
this.wifiAvailable = list
this.isLoading = false
})
})
},
methods: {
onWifiSelect (wifi) {
if (wifi.secure) {
this.connectSSID = wifi.ssid
this.wifiPasswordModal = true
} else {
this.onWifiConnect(wifi.ssid, '')
}
},
onWifiConnect (ssid, password) {
this.connectingSSID = ssid
this.wifiPasswordModal = false
apiDevice.wifiConnect(ssid, password, () => {})
},
},
} }
}; </script>
</script>

@ -1,235 +1,258 @@
<template> <template>
<v-layout fluid fill-height> <v-row
<template v-if="isLoading"> class="fluid fill-height"
<v-overlay :absolute="true" :value="true"> >
<v-progress-circular indeterminate size="64"></v-progress-circular> <template v-if="isLoading">
</v-overlay> <v-overlay
</template> :absolute="true"
:value="true"
<template v-if="true"> >
<v-container> <v-progress-circular
indeterminate
<v-snackbar size="64"
v-model="isSnackbar" />
:timeout="3000" </v-overlay>
color="success" </template>
>
i8n:saved <template v-if="true">
</v-snackbar> <v-container>
<v-snackbar
<!-- status current wifi --> v-model="isSnackbar"
<v-card :timeout="3000"
max-width="344" color="success"
class="mx-auto" >
> i8n:saved
<v-template v-if="!wifiStats.connected"> </v-snackbar>
<v-card-text>
<v-icon>$signalWifi0</v-icon> <!-- status current wifi -->
not connected <v-card
max-width="344"
<v-btn color="primary" depressed small> class="mx-auto"
i8n:scan >
</v-btn> <v-template v-if="!wifiStats.connected">
</v-card-text> <v-card-text>
</v-template> <v-icon>$signalWifi0</v-icon>
<v-template v-else> not connected
<v-toolbar flat>
<v-toolbar-title class="title font-weight-light"> <v-btn
<v-icon left>$signalWifi3Lock</v-icon> color="primary"
xd-design.info depressed
</v-toolbar-title> small
>
<v-spacer></v-spacer> i8n:scan
</v-btn>
<v-menu offset-y> </v-card-text>
<template v-slot:activator="{ on }"> </v-template>
<v-btn icon small v-on="on"> <v-template v-else>
<v-icon>mdi-dots-vertical</v-icon> <v-toolbar flat>
</v-btn> <v-toolbar-title class="title font-weight-light">
</template> <v-icon left>
<v-list> $signalWifi3Lock
<v-list-item @click="scan()"> </v-icon>
<v-list-item-title>i8n:scan</v-list-item-title> xd-design.info
</v-list-item> </v-toolbar-title>
</v-list>
</v-menu> <v-spacer />
</v-toolbar>
<v-menu offset-y>
<v-divider class="mx-4"></v-divider> <template #activator="{ on }">
<v-btn
<v-list dense> icon
<v-list-item small
v-for="(value, key) in wifiStats" v-on="on"
:key="key" >
> <v-icon>mdi-dots-vertical</v-icon>
<v-list-item-title>{{ key }}</v-list-item-title> </v-btn>
</template>
<v-list-item-subtitle class="text-right"> <v-list>
{{ value }} <v-list-item @click="scan()">
</v-list-item-subtitle> <v-list-item-title>i8n:scan</v-list-item-title>
</v-list-item> </v-list-item>
</v-list> </v-list>
</v-template> </v-menu>
</v-card> </v-toolbar>
<v-divider class="mx-4" />
<br/><br/>
<v-list dense>
<!-- connect to wifi --> <v-list-item
v-for="(value, key) in wifiStats"
<v-dialog v-model="wifiConnectModal" max-width="400"> :key="key"
<v-card> >
<v-card-title class="headline"> <v-list-item-title>{{ key }}</v-list-item-title>
{{ wifiConnectSSID }}
</v-card-title> <v-list-item-subtitle class="text-right">
{{ value }}
<v-card-text> </v-list-item-subtitle>
<v-text-field </v-list-item>
v-model="wifiConnectPassword" </v-list>
:append-icon="show1 ? 'mdi-eye' : 'mdi-eye-off'" </v-template>
:type="show1 ? 'text' : 'password'" </v-card>
label="i8n:Password"
@click:append="show1 = !show1" <br><br>
></v-text-field>
</v-card-text> <!-- connect to wifi -->
<v-card-actions> <v-dialog
<v-spacer></v-spacer> v-model="wifiConnectModal"
<v-btn text @click="wifiConnectModal = false">i8n:Cancel</v-btn> max-width="400"
<v-btn >
depressed <v-card>
:loading="isConnecting" <v-card-title class="headline">
color="primary darken-1" {{ wifiConnectSSID }}
@click="onWifiConnect()" </v-card-title>
>
i8n:Connect <v-card-text>
</v-btn> <v-text-field
</v-card-actions> v-model="wifiConnectPassword"
</v-card> :append-icon="show1 ? 'mdi-eye' : 'mdi-eye-off'"
</v-dialog> :type="show1 ? 'text' : 'password'"
label="i8n:Password"
<v-card @click:append="show1 = !show1"
class="mx-auto" />
max-width="344" </v-card-text>
tile
> <v-card-actions>
<v-list > <v-spacer />
<v-subheader>Wifi found</v-subheader> <v-btn
<v-list-item-group v-model="wifiConnectSSID" color="primary"> text
<v-list-item @click="wifiConnectModal = false"
v-for="(wifi, i) in wifiAvailable" >
:key="i" i8n:Cancel
:value="wifi.ssid" </v-btn>
@click.stop="wifiConnectModal = true" <v-btn
> depressed
<v-list-item-icon> :loading="isConnecting"
<v-icon v-text="getWifiIcon(wifi)"></v-icon> color="primary darken-1"
</v-list-item-icon> @click="onWifiConnect()"
<v-list-item-content> >
<v-list-item-title v-text="wifi.ssid"></v-list-item-title> i8n:Connect
<v-list-item-subtitle v-text="wifi.bssid"></v-list-item-subtitle> </v-btn>
</v-list-item-content> </v-card-actions>
<v-list-item-avatar> </v-card>
<v-avatar color="teal" size="24"> </v-dialog>
<span class="white--text headline caption">{{ wifi.channel }}</span>
</v-avatar> <v-card
</v-list-item-avatar> class="mx-auto"
</v-list-item> max-width="344"
</v-list-item-group> tile
</v-list> >
</v-card> <v-list>
<v-subheader>Wifi found</v-subheader>
</v-container> <v-list-item-group
v-model="wifiConnectSSID"
</template> color="primary"
</v-layout> >
<v-list-item
v-for="(wifi, i) in wifiAvailable"
:key="i"
:value="wifi.ssid"
@click.stop="wifiConnectModal = true"
>
<v-list-item-icon>
<v-icon v-text="getWifiIcon(wifi)" />
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="wifi.ssid" />
<v-list-item-subtitle v-text="wifi.bssid" />
</v-list-item-content>
<v-list-item-avatar>
<v-avatar
color="teal"
size="24"
>
<span class="white--text headline caption">{{ wifi.channel }}</span>
</v-avatar>
</v-list-item-avatar>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
</v-container>
</template>
</v-row>
</template> </template>
<script> <script>
import apiDevice from '../api/device' import apiDevice from '../api/device'
export default { export default {
name: "Wifi", name: 'Wifi',
data: () => ({ data: () => ({
isLoading: true, isLoading: true,
isSnackbar: false, isSnackbar: false,
isConnecting: false, isConnecting: false,
mode: 'AP_initial', // AP_initial, AP_lost, Default mode: 'AP_initial', // AP_initial, AP_lost, Default
// todo load // todo load
wifiStats: { wifiStats: {
connected: true, connected: true,
ip: 'xxx.xxx.xxx.xxx', ip: 'xxx.xxx.xxx.xxx',
mac: 'xxxx-xxxx-xxxx-xxxx', mac: 'xxxx-xxxx-xxxx-xxxx',
channel: 11, channel: 11,
dns: 'xxx.xxx.xxx.xxx', dns: 'xxx.xxx.xxx.xxx',
gateway: 'xxx.xxx.xxx.xxx', gateway: 'xxx.xxx.xxx.xxx',
}, },
wifiAvailable: [], wifiAvailable: [],
wifiConnectModal: false, wifiConnectModal: false,
wifiConnectSSID: null, wifiConnectSSID: null,
wifiConnectPassword: null, wifiConnectPassword: null,
show1: false, show1: false,
}), }),
created () { computed: {
//this.$vuetify.icons.values.signalWifi0 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_0_bar/baseline.svg')} },
//this.$vuetify.icons.values.signalWifi1 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar/baseline.svg')} created () {
//this.$vuetify.icons.values.signalWifi1Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar_lock/baseline.svg')} // this.$vuetify.icons.values.signalWifi0 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_0_bar/baseline.svg')}
//this.$vuetify.icons.values.signalWifi2 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar/baseline.svg')} // this.$vuetify.icons.values.signalWifi1 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar/baseline.svg')}
//this.$vuetify.icons.values.signalWifi2Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar_lock/baseline.svg')} // this.$vuetify.icons.values.signalWifi1Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_1_bar_lock/baseline.svg')}
//this.$vuetify.icons.values.signalWifi3 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar/baseline.svg')} // this.$vuetify.icons.values.signalWifi2 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar/baseline.svg')}
//this.$vuetify.icons.values.signalWifi3Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar_lock/baseline.svg')} // this.$vuetify.icons.values.signalWifi2Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_2_bar_lock/baseline.svg')}
//this.$vuetify.icons.values.signalWifi4 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar/baseline.svg')} // this.$vuetify.icons.values.signalWifi3 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar/baseline.svg')}
//this.$vuetify.icons.values.signalWifi4Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar_lock/baseline.svg')} // this.$vuetify.icons.values.signalWifi3Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_3_bar_lock/baseline.svg')}
// this.$vuetify.icons.values.signalWifi4 = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar/baseline.svg')}
// this.$vuetify.icons.values.signalWifi4Lock = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/signal_wifi_4_bar_lock/baseline.svg')}
apiDevice.wifiScan(list => {
this.wifiAvailable = list apiDevice.wifiScan(list => {
this.wifiAvailable = list
this.isLoading = false
}) this.isLoading = false
}, })
computed: { },
}, methods: {
methods: { getWifiIcon (wifi) {
getWifiIcon(wifi) { let icon = '$signalWifi'
let icon = '$signalWifi'
// strength
// strength if (wifi.rssi >= -67) {
if (wifi.rssi >= -67) { icon += 4
icon += 4 } else if (wifi.rssi >= -70) {
} icon += 3
else if (wifi.rssi >= -70) { } else if (wifi.rssi >= -80) {
icon += 3 icon += 2
} } else if (wifi.rssi >= -90) {
else if (wifi.rssi >= -80) { icon += 1
icon += 2 } else {
} icon += 0
else if (wifi.rssi >= -90) { }
icon += 1
} // secure
else { if (wifi.secure !== 0 && wifi.rssi >= -90) {
icon += 0 icon += 'Lock'
} }
// secure return icon
if (wifi.secure !== 0 && wifi.rssi >= -90) { },
icon += 'Lock'
} onWifiConnect () {
this.isConnecting = true
return icon
}, apiDevice.wifiConnect(this.wifiConnectSSID, this.wifiConnectPassword)
},
onWifiConnect() { },
this.isConnecting = true }
apiDevice.wifiConnect(this.wifiConnectSSID, this.wifiConnectPassword)
}
}
}
</script> </script>
<style scoped> <style scoped>
</style> </style>

@ -1,39 +1,39 @@
const webpack = require('webpack'); const webpack = require('webpack')
const CompressionPlugin = require('compression-webpack-plugin'); const CompressionPlugin = require('compression-webpack-plugin')
module.exports = { module.exports = {
"outputDir": "../data/dist", outputDir: '../data/dist',
"filenameHashing": false, filenameHashing: false,
"productionSourceMap": false, productionSourceMap: false,
"transpileDependencies": [ transpileDependencies: [
"vuetify" 'vuetify',
], ],
devServer: { devServer: {
proxy: { proxy: {
'^/': { '^/': {
target: 'http://192.168.178.62:80', target: 'http://paperdash-display-2:80',
ws: true, ws: true,
changeOrigin: true changeOrigin: true,
}, },
} },
}, },
configureWebpack: config => { configureWebpack: config => {
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
// optimize build for esp32 // optimize build for esp32
return { return {
plugins: [ plugins: [
// reduce total size of the app // reduce total size of the app
new webpack.optimize.LimitChunkCountPlugin({ new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1 maxChunks: 1,
}), }),
// use only pre compressed files // use only pre compressed files
new CompressionPlugin({ new CompressionPlugin({
deleteOriginalAssets: true deleteOriginalAssets: true,
}) }),
] ],
} }
} else { } else {
// mutate for development... // mutate for development...
} }
} },
} }

Loading…
Cancel
Save