diff --git a/dist/hass-aarlo.js b/dist/hass-aarlo.js
index 986bb5d..bcfe310 100644
--- a/dist/hass-aarlo.js
+++ b/dist/hass-aarlo.js
@@ -341,6 +341,9 @@ class AarloGlance extends LitElement {
+ { this.previousCameraImage() }}">
+
{ this.toggleCamera() }}">
@@ -393,6 +396,9 @@ class AarloGlance extends LitElement {
{ this.toggleLight(this.cc.lightId); }}">
+ { this.nextCameraImage() }}">
+
@@ -700,33 +706,51 @@ class AarloGlance extends LitElement {
get gc() {
return this._gc
}
+ set gc( value ) {
+ this._gc = value
+ }
get gs() {
return this._gs
}
+ set gs( value ) {
+ this._gs = value
+ }
get cc() {
if( !(`${this._cameraIndex}` in this._cc) ) {
this._cc[`${this._cameraIndex}`] = {}
}
return this._cc[`${this._cameraIndex}`]
}
+ set cc( value ) {
+ this._cc[`${this._cameraIndex}`] = value
+ }
get cs() {
if( !(`${this._cameraIndex}` in this._cs) ) {
this._cs[`${this._cameraIndex}`] = {}
}
return this._cs[this._cameraIndex]
}
+ set cs( value ) {
+ this._cs[this._cameraIndex] = value
+ }
get lc() {
if( !(`${this._cameraIndex}` in this._lc) ) {
this._lc[`${this._cameraIndex}`] = {}
}
return this._lc[this._cameraIndex]
}
+ set lc( value ) {
+ this._lc[this._cameraIndex] = value
+ }
get ls() {
if( !(`${this._cameraIndex}` in this._ls) ) {
this._ls[`${this._cameraIndex}`] = {}
}
return this._ls[this._cameraIndex]
}
+ set ls( value ) {
+ this._ls[this._cameraIndex] = value
+ }
_getState(_id, default_value = '') {
return this._hass !== null && _id in this._hass.states ?
@@ -741,15 +765,15 @@ class AarloGlance extends LitElement {
};
}
- updateStatuses() {
+ _updateStatuses() {
// CAMERA
const camera = this._getState(this.cc.id,'unknown');
// Set the camera name now. We have to wait untik now to ensure `_hass`
// is set and we can get to the camera state.
- if ( !this.cc.name ) {
- this.cc.name = this._config.name ? this._config.name : camera.attributes.friendly_name;
+ if ( this.cc.name === null ) {
+ this.cc.name = camera.attributes.friendly_name
}
// Image changed? See if:
@@ -891,18 +915,24 @@ class AarloGlance extends LitElement {
const bell = this._getState(this.cc.doorBellId, 'off');
const name = bell.attributes.friendly_name
const mute = bell.attributes.chimes_silenced || bell.attributes.calls_silenced
+ const muteable = !!this.cc.doorBellMuteId
if ( bell.state === 'on' ) {
this.cs.doorBellState = 'on'
this.cs.doorBellText = `${name}: ${this._i.status.doorbell_pressed}`
this.cs.doorBellIcon = 'mdi:bell-ring'
- }
- else if ( mute ) {
- this.cs.doorBellState = 'warn'
- this.cs.doorBellText = `${name}: ${this._i.status.doorbell_muted}`
- this.cs.doorBellIcon = 'mdi:bell-off'
+ } else if( muteable ) {
+ if ( mute ) {
+ this.cs.doorBellState = 'warn'
+ this.cs.doorBellText = `${name}: ${this._i.status.doorbell_muted}`
+ this.cs.doorBellIcon = 'mdi:bell-off'
+ } else {
+ this.cs.doorBellState = 'off'
+ this.cs.doorBellText = `${name}: ${this._i.status.doorbell_mute}`
+ this.cs.doorBellIcon = 'mdi:bell'
+ }
} else {
this.cs.doorBellState = 'off'
- this.cs.doorBellText = `${name}: ${mute.state === 'off' ? this._i.status.doorbell_mute : this._i.status.doorbell_idle}`
+ this.cs.doorBellText = `${name}: ${this._i.status.doorbell_idle}`
this.cs.doorBellIcon = 'mdi:bell'
}
}
@@ -911,18 +941,24 @@ class AarloGlance extends LitElement {
const bell = this._getState(this.cc.door2BellId, 'off');
const name = bell.attributes.friendly_name
const mute = bell.attributes.chimes_silenced || bell.attributes.calls_silenced
+ const muteable = !!this.cc.door2BellMuteId
if ( bell.state === 'on' ) {
this.cs.door2BellState = 'on'
this.cs.door2BellText = `${name}: ${this._i.status.doorbell_pressed}`
this.cs.door2BellIcon = 'mdi:bell-ring'
- }
- else if ( mute ) {
- this.cs.door2BellState = 'warn'
- this.cs.door2BellText = `${name}: ${this._i.status.doorbell_muted}`
- this.cs.door2BellIcon = 'mdi:bell-off'
+ } else if( muteable ) {
+ if ( mute ) {
+ this.cs.door2BellState = 'warn'
+ this.cs.door2BellText = `${name}: ${this._i.status.doorbell_muted}`
+ this.cs.door2BellIcon = 'mdi:bell-off'
+ } else {
+ this.cs.door2BellState = 'off'
+ this.cs.door2BellText = `${name}: ${this._i.status.doorbell_mute}`
+ this.cs.door2BellIcon = 'mdi:bell'
+ }
} else {
this.cs.door2BellState = 'off'
- this.cs.door2BellText = `${name}: ${mute.state === 'off' ? this._i.status.doorbell_mute : this._i.status.doorbell_idle}`
+ this.cs.door2BellText = `${name}: ${this._i.status.doorbell_idle}`
this.cs.door2BellIcon = 'mdi:bell'
}
}
@@ -936,6 +972,14 @@ class AarloGlance extends LitElement {
}
}
+ updateStatuses() {
+ const index = this._cameraIndex
+ for( this._cameraIndex = 0; this._cameraIndex < this._cameraCount; this._cameraIndex++ ) {
+ this._updateStatuses()
+ }
+ this._cameraIndex = index
+ }
+
checkConfig() {
if ( this._hass === null ) {
@@ -965,20 +1009,42 @@ class AarloGlance extends LitElement {
}
}
- getGlobalCameraConfig( config ) {
- }
+ getGlobalConfig( config ) {
- getGlobalLibraryConfig( config ) {
- }
+ return {
+ // GLOBAL config
+ // Mobile? see here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
+ isMobile: navigator.userAgent.includes("Mobi"),
+
+ // Language override?
+ lang: config.lang,
+
+ // aspect ratio
+ aspectRatio: config.aspect_ratio === 'square' ? '1x1' : '16x9',
+ aspectRatioMultiplier: config.aspect_ratio === 'square' ? 1 : 0.5625,
+
+ // logging?
+ log: config.logging ? config.logging : false,
- getCameraConfig( config ) {
+ // lovelace card size
+ cardSize: config.card_size ? parseInt(config.card_size) : 3,
+
+ // swipe threshold
+ swipeThreshold: config.swipe_threshold ? parseInt(config.swipe_threshold) : 150,
+ }
}
- getLibraryConfig( config ) {
+ getGlobalLibraryConfig( config ) {
}
- setConfig(config) {
+ _merge_config( global, local ) {
+ let merged = Object.assign( {}, global )
+ return Object.assign( merged, local )
+ }
+ getCameraConfig( global, local ) {
+ const config = this._merge_config( global, local )
+
// find camera
let camera = ""
if( config.entity ) {
@@ -1006,101 +1072,55 @@ class AarloGlance extends LitElement {
prefix = config.prefix;
}
- // save then check new config
- this._config = config
- this.checkConfig()
-
- // GLOBAL config
- // Mobile? see here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
- this.gc.isMobile = navigator.userAgent.includes("Mobi")
-
- // Language override?
- this.gc.lang = config.lang
+ let cc = {}
- // aspect ratio
- this.gc.aspectRatio = config.aspect_ratio === 'square' ? '1x1' : '16x9';
- this.gc.aspectRatioMultiplier = config.aspect_ratio === 'square' ? 1 : 0.5625
-
- // logging?
- this.gc.log = config.logging ? config.logging : false
-
- // lovelace card size
- this.gc.cardSize = config.card_size ? parseInt(config.card_size) : 3
-
- // swipe threshold
- this.gc.swipeThreshold = config.swipe_threshold ? parseInt(config.swipe_threshold) : 150
-
- // TODO use proxy for defaults... read defaults as though a camera... or just keep simple
- // and copy the defaults and add camera specifics
-
- // PER-CAMERA config
- // TODO save and restore index
- this._cameraIndex = 0
+ // Grab name if there
+ cc.name = config.name ? config.name : null
- // library config
- const library_click = config.image_click ? config.image_click : ""
- this.lc.imageClickModal = library_click.includes("modal")
- this.lc.imageClickSmart = library_click.includes("smart")
- this.lc.imageAutoPlay = library_click.includes("autoplay")
- this.lc.sizes = config.library_sizes ? config.library_sizes : [ 3 ]
- this.lc.recordings = config.max_recordings ? parseInt(config.max_recordings) : 99
- this.lc.regions = config.library_regions ? config.library_regions : this.lc.sizes
- this.lc.colors = {
- "Animal" : config.library_animal ? config.library_animal : 'orangered',
- "Vehicle" : config.library_vehicle ? config.library_vehicle : 'yellow',
- "Person" : config.library_person ? config.library_person : 'lime'
- }
- this.ls.sizeIndex = 0
- this.ls.size = -1
- this.ls.gridCount = -1
-
- // on click
- // click on image
+ // What happens when we click on image
const image_click = config.image_click ? config.image_click : ""
- this.cc.imageClickStream = image_click.includes("live") ||
+ cc.imageClickStream = image_click.includes("live") ||
image_click.includes("play") ||
image_click.includes("stream")
- this.cc.imageClickModal = image_click.includes("modal")
- this.cc.imageClickSmart = image_click.includes("smart")
- this.cc.imageAutoPlay = image_click.includes("autoplay")
+ cc.imageClickModal = image_click.includes("modal")
+ cc.imageClickSmart = image_click.includes("smart")
+ cc.imageAutoPlay = image_click.includes("autoplay")
// snapshot updates
- this.cc.snapshotTimeouts = config.snapshot_retry ? config.snapshot_retry : [ 2, 5 ]
+ cc.snapshotTimeouts = config.snapshot_retry ? config.snapshot_retry : [ 2, 5 ]
// modal window multiplier
- this.cc.modalMultiplier = config.modal_multiplier ? parseFloat(config.modal_multiplier) : 0.8;
+ cc.modalMultiplier = config.modal_multiplier ? parseFloat(config.modal_multiplier) : 0.8;
// stream directly from Arlo
- this.cc.playDirectFromArlo = config.play_direct ? config.play_direct : false;
+ cc.playDirectFromArlo = config.play_direct ? config.play_direct : false;
// auto play
- this.cc.autoPlay = config.auto_play ? config.auto_play : false
- this.cs.autoPlay = this.cc.autoPlay
- this.cs.autoPlayTimer = null
+ cc.autoPlay = config.auto_play ? config.auto_play : false
// camera and sensors
- this.cc.id = config.camera_id ? config.camera_id : 'camera.' + prefix + camera;
- this.cc.motionId = config.motion_id ? config.motion_id : 'binary_sensor.' + prefix + 'motion_' + camera;
- this.cc.soundId = config.sound_id ? config.sound_id : 'binary_sensor.' + prefix + 'sound_' + camera;
- this.cc.batteryId = config.battery_id ? config.battery_id : 'sensor.' + prefix + 'battery_level_' + camera;
- this.cc.signalId = config.signal_id ? config.signal_id : 'sensor.' + prefix + 'signal_strength_' + camera;
- this.cc.capturedTodayId = config.capture_id ? config.capture_id : 'sensor.' + prefix + 'captured_today_' + camera;
- this.cc.lastCaptureId = config.last_id ? config.last_id : 'sensor.' + prefix + 'last_' + camera;
+ cc.id = config.camera_id ? config.camera_id : 'camera.' + prefix + camera;
+ cc.motionId = config.motion_id ? config.motion_id : 'binary_sensor.' + prefix + 'motion_' + camera;
+ cc.soundId = config.sound_id ? config.sound_id : 'binary_sensor.' + prefix + 'sound_' + camera;
+ cc.batteryId = config.battery_id ? config.battery_id : 'sensor.' + prefix + 'battery_level_' + camera;
+ cc.signalId = config.signal_id ? config.signal_id : 'sensor.' + prefix + 'signal_strength_' + camera;
+ cc.capturedTodayId = config.capture_id ? config.capture_id : 'sensor.' + prefix + 'captured_today_' + camera;
+ cc.lastCaptureId = config.last_id ? config.last_id : 'sensor.' + prefix + 'last_' + camera;
// door definition
- this.cc.doorId = config.door ? config.door: null;
- this.cc.doorBellId = config.door_bell ? config.door_bell : null;
- this.cc.doorBellMuteId = config.door_bell_mute ? config.door_bell_mute : null;
- this.cc.doorLockId = config.door_lock ? config.door_lock : null;
+ cc.doorId = config.door ? config.door: null;
+ cc.doorBellId = config.door_bell ? config.door_bell : null;
+ cc.doorBellMuteId = config.door_bell_mute ? config.door_bell_mute : null;
+ cc.doorLockId = config.door_lock ? config.door_lock : null;
// door2 definition
- this.cc.door2Id = config.door2 ? config.door2: null;
- this.cc.door2BellId = config.door2_bell ? config.door2_bell : null;
- this.cc.door2BellMuteId = config.door2_bell_mute ? config.door2_bell_mute : null;
- this.cc.door2LockId = config.door2_lock ? config.door2_lock : null;
+ cc.door2Id = config.door2 ? config.door2: null;
+ cc.door2BellId = config.door2_bell ? config.door2_bell : null;
+ cc.door2BellMuteId = config.door2_bell_mute ? config.door2_bell_mute : null;
+ cc.door2LockId = config.door2_lock ? config.door2_lock : null;
// light definition
- this.cc.lightId = config.light ? config.light: null;
+ cc.lightId = config.light ? config.light: null;
// what are we hiding?
const hide = this._config.hide || [];
@@ -1109,41 +1129,115 @@ class AarloGlance extends LitElement {
const show_status = !hide.includes('status')
// ui configuration
- this.cc.showTopTitle = config.top_title ? show_title : false
- this.cc.showTopDate = config.top_date ? show_date : false
- this.cc.showTopStatus = config.top_status ? show_status : false
- this.cc.showBottomTitle = config.top_title ? false : show_title
- this.cc.showBottomDate = config.top_date ? false : show_date
- this.cc.showBottomStatus = config.top_status ? false : show_status
+ cc.showTopTitle = config.top_title ? show_title : false
+ cc.showTopDate = config.top_date ? show_date : false
+ cc.showTopStatus = config.top_status ? show_status : false
+ cc.showBottomTitle = config.top_title ? false : show_title
+ cc.showBottomDate = config.top_date ? false : show_date
+ cc.showBottomStatus = config.top_status ? false : show_status
// what are we showing?
const show = this._config.show || [];
- this.cc.showPlay = show.includes('play')
- this.cc.showSnapshot = show.includes('snapshot')
- this.cc.showCameraOnOff = show.includes('on_off')
-
- this.cc.showBattery = show.includes('battery') || show.includes('battery_level')
- this.cc.showSignal = show.includes('signal_strength')
- this.cc.showMotion = show.includes('motion')
- this.cc.showSound = show.includes('sound')
- this.cc.showCaptured = show.includes('captured') || show.includes('captured_today')
- this.cc.showImageDate = show.includes('image_date')
-
- this.cc.showDoor = !!this.cc.doorId
- this.cc.showDoorLock = !!this.cc.doorLockId
- this.cc.showDoorBell = !!this.cc.doorBellId
- this.cc.showDoor2 = !!this.cc.door2Id
- this.cc.showDoor2Lock = !!this.cc.door2LockId
- this.cc.showDoor2Bell = !!this.cc.door2BellId
-
- this.cc.showLight = !!this.cc.lightId
- this.cc.showLightLeft = config.light_left ? !!config.light_left : false;
- this.cc.showLightRight = !this.cc.showLightLeft
-
- this.cc.showOthers = ( this.cc.showDoor || this.cc.showDoorLock || this.cc.showDoorBell ||
- this.cc.showDoor2 || this.cc.showDoor2Lock || this.cc.showDoor2Bell ||
- this.cc.showLight )
+ cc.showPlay = show.includes('play')
+ cc.showSnapshot = show.includes('snapshot')
+ cc.showCameraOnOff = show.includes('on_off')
+
+ cc.showBattery = show.includes('battery') || show.includes('battery_level')
+ cc.showSignal = show.includes('signal_strength')
+ cc.showMotion = show.includes('motion')
+ cc.showSound = show.includes('sound')
+ cc.showCaptured = show.includes('captured') || show.includes('captured_today')
+ cc.showImageDate = show.includes('image_date')
+
+ cc.showDoor = !!cc.doorId
+ cc.showDoorLock = !!cc.doorLockId
+ cc.showDoorBell = !!cc.doorBellId
+ cc.showDoor2 = !!cc.door2Id
+ cc.showDoor2Lock = !!cc.door2LockId
+ cc.showDoor2Bell = !!cc.door2BellId
+
+ cc.showLight = !!cc.lightId
+ cc.showLightLeft = config.light_left ? !!config.light_left : false;
+ cc.showLightRight = !cc.showLightLeft
+
+ cc.showOthers = ( cc.showDoor || cc.showDoorLock || cc.showDoorBell ||
+ cc.showDoor2 || cc.showDoor2Lock || cc.showDoor2Bell ||
+ cc.showLight )
+
+ return cc
+ }
+
+ getCameraState( config ) {
+ return {
+ autoPlay: config.autoPlay,
+ autoPlayTimer: null,
+ }
+ }
+
+ getLibraryConfig( global, local ) {
+
+ const config = this._merge_config( global, local )
+ const library_click = config.image_click ? config.image_click : ""
+ const sizes = config.library_sizes ? config.library_sizes : [ 3 ]
+
+ return {
+ // What to when video clicked
+ imageClickModal: library_click.includes("modal"),
+ imageClickSmart: library_click.includes("smart"),
+ imageAutoPlay: library_click.includes("autoplay"),
+
+ // How many recordings to show
+ sizes: sizes,
+ recordings: config.max_recordings ? parseInt(config.max_recordings) : 99,
+
+ // Highlight motion triggers?
+ regions: config.library_regions ? config.library_regions : sizes,
+ colors: {
+ "Animal": config.library_animal ? config.library_animal : 'orangered',
+ "Vehicle": config.library_vehicle ? config.library_vehicle : 'yellow',
+ "Person": config.library_person ? config.library_person : 'lime',
+ },
+ }
+ }
+
+ getLibraryState( _config ) {
+ return {
+ size: -1,
+ sizeIndex: 0,
+ gridCount: -1,
+ }
+ }
+
+ setConfig(config) {
+
+ // save then check new config
+ this._config = config
+
+ this.gc = this.getGlobalConfig( config )
+
+ if( "entities" in this._config ) {
+ this._cameraIndex = 0
+ this._config.entities.forEach( (local_config) => {
+ this.cc = this.getCameraConfig( config, local_config )
+ this.cs = this.getCameraState( this.cc )
+ this.lc = this.getLibraryConfig( config, local_config )
+ this.ls = this.getLibraryState( this.lc )
+ this._cameraIndex++
+ })
+ this._cameraCount = this._cameraIndex
+ this._cameraIndex = 0
+ } else {
+ // Single camera. Much simpler.
+ this._cameraIndex = 0
+ this.cc = this.getCameraConfig( config, {} )
+ this.cs = this.getCameraState( this.cc )
+ this.lc = this.getLibraryConfig( config, {} )
+ this.ls = this.getLibraryState( this.lc )
+ this._cameraCount = 1
+ }
+
+ //this.checkConfig()
// web item id suffix
//this.gc.idSuffix = this.cc.id.replaceAll('.','-').replaceAll('_','-')
@@ -1212,9 +1306,10 @@ class AarloGlance extends LitElement {
this._show('bottom-bar-title', this.cc.showBottomTitle )
this._show('bottom-bar-camera', this.cs.showCameraControls )
this._show('bottom-bar-date', this.cc.showBottomDate && this.cc.showImageDate )
- this._show('bottom-bar-externals', this.cc.showOthers )
+ this._show('bottom-bar-externals', this.cc.showOthers || (!this.gc.isMobile && this._cameraCount > 1) )
this._show('bottom-bar-status', this.cc.showBottomStatus )
+ this._show('camera-previous', this._cameraCount > 1 )
this._show('camera-on-off', this.cc.showCameraOnOff )
this._show('camera-captured', this.cc.showCaptured )
this._show('camera-light-left', this.cc.showLightLeft )
@@ -1226,9 +1321,37 @@ class AarloGlance extends LitElement {
this._show("externals-door-lock-2", this.cc.showDoor2Lock )
this._show("externals-door-bell-2", this.cc.showDoor2Bell )
this._show("externals-light", this.cc.showLightRight )
+ this._show('camera-next', !this.gc.isMobile && this._cameraCount > 1 )
this._set("top-bar-title", {text: this.cc.name})
this._set("bottom-bar-title", {text: this.cc.name})
+ }
+
+ setupImageHandlers() {
+
+ const viewer = this._element("image-viewer")
+
+ if( this.gc.isMobile ) {
+ viewer.addEventListener('touchstart', (e) => {
+ this.ls.xDown = e.touches[0].clientX
+ this.ls.xUp = null
+ }, { passive: true })
+
+ viewer.addEventListener('touchmove', (e) => {
+ this.ls.xUp = e.touches[0].clientX
+ }, { passive: true })
+
+ viewer.addEventListener('touchend', () => {
+ if( this.ls.xDown && this.ls.xUp ) {
+ const xDiff = this.ls.xDown - this.ls.xUp;
+ if( xDiff > this.gc.swipeThreshold ) {
+ this.nextCameraImage()
+ } else if( xDiff < (0 - this.gc.swipeThreshold) ) {
+ this.previousCameraImage()
+ }
+ }
+ }, { passive: true })
+ }
this._element("externals-door-bell").addEventListener('click', () => {
if ( this.cc.doorBellMuteId ) {
@@ -1276,6 +1399,7 @@ class AarloGlance extends LitElement {
this._set("bottom-bar-date", {text: this.cs.imageDate})
this._set("bottom-bar-status", {text: this.cs.state})
+ this._set ("camera-previous", {title: this._i.status.previous_camera, icon: "mdi:chevron-left", state: "on"})
this._set ("camera-on-off", {title: this.cs.onOffText, icon: this.cs.onOffIcon, state: this.cs.onOffState})
this._set ("camera-motion", {title: this.cs.motionText, icon: "mdi:run-fast", state: this.cs.motionState})
this._show('camera-motion', this.cc.showMotion && this.cs.showCameraControls )
@@ -1299,6 +1423,7 @@ class AarloGlance extends LitElement {
this._set("externals-door-bell-2", {title: this.cs.door2BellText, icon: this.cs.door2BellIcon, state: this.cs.door2BellState})
this._set("externals-door-lock-2", {title: this.cs.door2LockText, icon: this.cs.door2LockIcon, state: this.cs.door2LockState})
this._set("externals-light", {title: this.cs.lightText, icon: this.cs.lightIcon, state: this.cs.lightState})
+ this._set("camera-next", {title: this._i.status.next_camera, icon: "mdi:chevron-right", state: "on"})
}
/**
@@ -1355,44 +1480,51 @@ class AarloGlance extends LitElement {
this._set("library-control-resize",{ state: "on"} )
this._set("library-control-close",{ state: "on"} )
+ // set state
+ this.ls.offset = 0
+ }
+
+ setupLibraryHandlers() {
// rudementary swipe support
- let viewer = this._element("library-viewer")
- viewer.addEventListener('touchstart', (e) => {
- this.ls.xDown = e.touches[0].clientX
- this.ls.xUp = null
- }, { passive: true })
- viewer.addEventListener('touchmove', (e) => {
- this.ls.xUp = e.touches[0].clientX
- }, { passive: true })
- viewer.addEventListener('touchend', () => {
- if( this.ls.xDown && this.ls.xUp ) {
- const xDiff = this.ls.xDown - this.ls.xUp;
- if( xDiff > this.gc.swipeThreshold ) {
- this.nextLibraryPage()
- } else if( xDiff < (0 - this.gc.swipeThreshold) ) {
- this.previousLibraryPage()
+ const viewer = this._element("library-viewer")
+
+ if( this.gc.isMobile ) {
+ viewer.addEventListener('touchstart', (e) => {
+ this.ls.xDown = e.touches[0].clientX
+ this.ls.xUp = null
+ }, { passive: true })
+
+ viewer.addEventListener('touchmove', (e) => {
+ this.ls.xUp = e.touches[0].clientX
+ }, { passive: true })
+
+ viewer.addEventListener('touchend', () => {
+ if( this.ls.xDown && this.ls.xUp ) {
+ const xDiff = this.ls.xDown - this.ls.xUp;
+ if( xDiff > this.gc.swipeThreshold ) {
+ this.nextLibraryPage()
+ } else if( xDiff < (0 - this.gc.swipeThreshold) ) {
+ this.previousLibraryPage()
+ }
}
- }
- }, { passive: true })
-
- // set state
- this.ls.offset = -1
+ }, { passive: true })
+ }
}
_updateLibraryHTML() {
// update library state to reflect the new layout
- this.ls.size = this.lc.sizes[this.ls.sizeIndex]
- this.ls.gridCount = this.ls.size * this.ls.size
+ this.gs.librarySize = this.lc.sizes[this.ls.sizeIndex]
+ this.ls.gridCount = this.gs.librarySize * this.gs.librarySize
let grid = document.createElement("div")
grid.style.display = "grid"
- grid.style['grid-template-columns'] = `repeat(${this.ls.size},1fr)`
- grid.style['grid-template-rows'] = `repeat(${this.ls.size},1fr)`
+ grid.style['grid-template-columns'] = `repeat(${this.gs.librarySize},1fr)`
+ grid.style['grid-template-rows'] = `repeat(${this.gs.librarySize},1fr)`
grid.style['grid-gap'] = '1px'
grid.style.padding= '2px'
- for( let i = 0; i < this.ls.size * this.ls.size; ++i ) {
+ for( let i = 0; i < this.gs.librarySize * this.gs.librarySize; ++i ) {
let img = document.createElement("img")
img.id = this._id(`library-${i}`)
@@ -1409,8 +1541,8 @@ class AarloGlance extends LitElement {
box.style.top = "0"
img.addEventListener("click", () => { this.playLibraryVideo(i) } )
- const column = Math.floor((i % this.ls.size) + 1)
- const row = Math.floor((i / this.ls.size) + 1)
+ const column = Math.floor((i % this.gs.librarySize) + 1)
+ const row = Math.floor((i / this.gs.librarySize) + 1)
let div = document.createElement("div")
div.style.position= 'relative'
div.style.gridColumn = `${column}`
@@ -1437,7 +1569,7 @@ class AarloGlance extends LitElement {
let i = 0;
let j= this.ls.offset;
- const show_triggers = this.lc.regions.includes(this.ls.size)
+ const show_triggers = this.lc.regions.includes(this.gs.librarySize)
const last = Math.min(j + this.ls.gridCount, this.ls.videos.length)
for( ; j < last; i++, j++ ) {
const id = `library-${i}`
@@ -1512,7 +1644,7 @@ class AarloGlance extends LitElement {
}
// Resized? Rebuild grid and force reload of images.
- if ( this.ls.size !== this.lc.sizes[this.ls.sizeIndex] ) {
+ if ( this.gs.librarySize !== this.lc.sizes[this.ls.sizeIndex] ) {
this._updateLibraryHTML()
this.ls.lastOffset = -1
}
@@ -1767,6 +1899,9 @@ class AarloGlance extends LitElement {
this.setupVideoView()
this.setupStreamView()
+ this.setupImageHandlers()
+ this.setupLibraryHandlers()
+
// And go...
this.updateImageView()
this.updateLibraryView()
@@ -1989,6 +2124,20 @@ class AarloGlance extends LitElement {
}
}
+ nextCameraImage() {
+ this._cameraIndex = this._cameraIndex === (this._cameraCount - 1) ? 0 : (this._cameraIndex + 1)
+ this.setupImageView()
+ this.setupLibraryView()
+ this.updateImageView()
+ }
+
+ previousCameraImage() {
+ this._cameraIndex = this._cameraIndex === 0 ? (this._cameraCount - 1) : (this._cameraIndex - 1)
+ this.setupImageView()
+ this.setupLibraryView()
+ this.updateImageView()
+ }
+
clickVideo() {
if ( this._misHidden("video-controls") ) {
this.showVideoControls(2)
diff --git a/lang/en-gb.js b/lang/en-gb.js
new file mode 120000
index 0000000..78e6f7f
--- /dev/null
+++ b/lang/en-gb.js
@@ -0,0 +1 @@
+en.js
\ No newline at end of file
diff --git a/lang/en-us.js b/lang/en-us.js
new file mode 120000
index 0000000..78e6f7f
--- /dev/null
+++ b/lang/en-us.js
@@ -0,0 +1 @@
+en.js
\ No newline at end of file
diff --git a/lang/en.js b/lang/en.js
index 6444eb1..ccaee92 100644
--- a/lang/en.js
+++ b/lang/en.js
@@ -58,6 +58,8 @@ export var messages = {
doorbell_muted: 'muted (click to unmute)',
light_on: 'on',
light_off: 'off',
+ next_camera: 'next camera',
+ previous_camera: 'previous camera',
},
// known triggers
diff --git a/lang/fr-ca.js b/lang/fr-ca.js
deleted file mode 100644
index 01558ff..0000000
--- a/lang/fr-ca.js
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-export var messages = {
-
- // image viewer
- image: {
- turn_camera_on: 'allume la caméra',
- turn_camera_off: 'éteins la caméra',
- take_a_snapshot: 'prends une photo',
- start_stream: 'visionne le livestream',
- stop_stream: 'arrête le livestream',
- automatic_capture: 'capturée automatiquement à',
- snapshot_capture: 'image instantanée capturée à',
- },
-
- // library viewer
- library: {
- first_page: 'première page',
- previous_page: 'page précédente',
- next_size: 'prochaine taille de grille',
- close: 'ferme la bibliothèque',
- next_page: 'prochaine page',
- last_page: 'dernière page',
- captured: 'capturée',
- },
-
- // video/stream viewer
- video: {
- stop: 'arrête',
- play: 'joue',
- pause: 'pause',
- fullscreen: 'plein écran',
- },
-
- // device statuses
- status: {
- battery_strength: 'puissance batterie',
- detected: 'détecté',
- door_closed: 'fermée',
- door_open: 'ouverte',
- captured: 'capturée',
- captured_nothing: 'rien aujourd’hui',
- captured_something: 'clips d’aujourd’hui, capturés à',
- clear: 'sans mouvement',
- plugged_in: 'branchée',
- signal_strength: 'intensité du signal',
- motion: 'mouvement',
- sound: 'son',
- lock_locked: 'verrouillée. appuyez pour déverrouiller',
- lock_unlocked: 'déverrouillée. appuyer pour verrouiller',
- doorbell_pressed: 'Dring-dring!',
- doorbell_idle: 'en attente',
- doorbell_mute: 'click to mute',
- doorbell_muted: 'muted, click to unmute',
- light_on: 'allumé',
- light_off: 'éteint',
- },
-
- // known triggers
- trigger : {
- animal: 'animal',
- vehicle: 'véhicule',
- person: 'personne',
- parcel: 'colis',
- },
-}
diff --git a/lang/fr-ca.js b/lang/fr-ca.js
new file mode 120000
index 0000000..b0fd9cf
--- /dev/null
+++ b/lang/fr-ca.js
@@ -0,0 +1 @@
+fr.js
\ No newline at end of file
diff --git a/lang/fr.js b/lang/fr.js
index 01558ff..b7e2f38 100644
--- a/lang/fr.js
+++ b/lang/fr.js
@@ -54,6 +54,8 @@ export var messages = {
doorbell_muted: 'muted, click to unmute',
light_on: 'allumé',
light_off: 'éteint',
+ next_camera: 'prochaine caméra',
+ previous_camera: 'caméra précédente',
},
// known triggers