diff options
Diffstat (limited to 'www')
| -rw-r--r-- | www/index.html | 3 | ||||
| -rw-r--r-- | www/js/DataModel.js | 7 | ||||
| -rw-r--r-- | www/js/EventCtrl.js | 13 | ||||
| -rw-r--r-- | www/js/EventModalCtrl.js | 1240 | ||||
| -rw-r--r-- | www/js/MonitorModalCtrl.js (renamed from www/js/ModalCtrl.js) | 129 | ||||
| -rw-r--r-- | www/js/MontageCtrl.js | 4 | ||||
| -rw-r--r-- | www/js/app.js | 109 | ||||
| -rw-r--r-- | www/templates/devoptions.html | 8 | ||||
| -rw-r--r-- | www/templates/events-modal.html | 40 | ||||
| -rw-r--r-- | www/templates/events.html | 4 | ||||
| -rw-r--r-- | www/templates/monitors-modal.html | 2 |
11 files changed, 1530 insertions, 29 deletions
diff --git a/www/index.html b/www/index.html index 214c2cf8..85f6e828 100644 --- a/www/index.html +++ b/www/index.html @@ -81,7 +81,8 @@ <script src="js/controllers.js"></script> <script src="js/DataModel.js"></script> <script src="js/LoginCtrl.js"></script> - <script src="js/ModalCtrl.js"></script> + <script src="js/MonitorModalCtrl.js"></script> + <script src="js/EventModalCtrl.js"></script> <script src="js/MontageCtrl.js"></script> <script src="js/EventCtrl.js"></script> <script src="js/EventsGraphsCtrl.js"></script> diff --git a/www/js/DataModel.js b/www/js/DataModel.js index eeae0784..d6331681 100644 --- a/www/js/DataModel.js +++ b/www/js/DataModel.js @@ -62,6 +62,7 @@ angular.module('zmApp.controllers') 'minAlarmCount':'1', 'montageSize':'3', 'useNphZms':true, + 'useNphZmsForEvents':false, 'packMontage':true, 'exitOnSleep':false, 'forceNetworkStop':false, @@ -240,6 +241,12 @@ angular.module('zmApp.controllers') loginData.useNphZms = true; } + if (typeof loginData.useNphZmsForEvents == 'undefined') + { + zmDebug ("useNphZmsForEvents does not exist. Setting to false"); + loginData.useNphZmsForEvents = false; + } + if (typeof loginData.packMontage == 'undefined') { zmDebug ("packMontage does not exist. Setting to true"); diff --git a/www/js/EventCtrl.js b/www/js/EventCtrl.js index cbe6d399..c46a830b 100644 --- a/www/js/EventCtrl.js +++ b/www/js/EventCtrl.js @@ -7,7 +7,7 @@ // and whether the new API has a better mechanism angular.module('zmApp.controllers') - .controller('zmApp.EventCtrl', ['$scope', '$rootScope', 'zm', 'ZMDataModel', 'message', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$ionicPlatform', '$ionicSlideBoxDelegate', '$ionicPosition', '$ionicPopover', '$ionicPopup', 'EventServer', '$sce', '$cordovaBadge', '$cordovaLocalNotification', '$q', function ($scope, $rootScope, zm, ZMDataModel, message, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $stateParams, $ionicHistory, $ionicScrollDelegate, $ionicPlatform, $ionicSlideBoxDelegate, $ionicPosition, $ionicPopover, $ionicPopup, EventServer, $sce, $cordovaBadge, $cordovaLocalNotification, $q) { + .controller('zmApp.EventCtrl', ['$scope', '$rootScope', 'zm', 'ZMDataModel', 'message', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$ionicPlatform', '$ionicSlideBoxDelegate', '$ionicPosition', '$ionicPopover', '$ionicPopup', 'EventServer', '$sce', '$cordovaBadge', '$cordovaLocalNotification', '$q', 'appModalService', function ($scope, $rootScope, zm, ZMDataModel, message, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $stateParams, $ionicHistory, $ionicScrollDelegate, $ionicPlatform, $ionicSlideBoxDelegate, $ionicPosition, $ionicPopover, $ionicPopup, EventServer, $sce, $cordovaBadge, $cordovaLocalNotification, $q, appModalService) { // events in last 5 minutes // TODO https://server/zm/api/events/consoleEvents/5%20minute.json @@ -84,7 +84,7 @@ angular.module('zmApp.controllers') document.addEventListener("pause", onPause, false); //console.log("I got STATE PARAM " + $stateParams.id); $scope.id = parseInt($stateParams.id, 10); - $scope.connKey = Math.floor(Math.random() * (999999 - 111111 + 1)) + 111111; + // $scope.connKey = Math.floor(Math.random() * (999999 - 111111 + 1)) + 111111; @@ -1268,6 +1268,7 @@ angular.module('zmApp.controllers') //ZMDataModel.zmDebug("EventCtrl: Open Modal with Base path " + relativepath); $scope.event = event; + ZMDataModel.setAwake(ZMDataModel.getKeepAwake()); $scope.currentEvent = event; @@ -1275,6 +1276,14 @@ angular.module('zmApp.controllers') // prepareModalEvent(event.Event.Id); + + /* appModalService.show('templates/events-modal.html', 'EventModalCtrl') + .then(function(result) { + // result from modal controller: $scope.closeModal(result) or <as name here>.closeModal(result) [Only on template] + }, function(err) { + // error + });*/ + $ionicModal.fromTemplateUrl('templates/events-modal.html', { scope: $scope, diff --git a/www/js/EventModalCtrl.js b/www/js/EventModalCtrl.js new file mode 100644 index 00000000..7376f858 --- /dev/null +++ b/www/js/EventModalCtrl.js @@ -0,0 +1,1240 @@ +// Common Controller for the montage view +/* jshint -W041 */ +/* jslint browser: true*/ +/* global saveAs, cordova,StatusBar,angular,console,ionic, moment */ + + +/* FIXME for nph events +a) timers +b) sliders +c) photo save +d) gapless + +*/ + +angular.module('zmApp.controllers').controller('EventModalCtrl', ['$scope', '$rootScope', 'zm', 'ZMDataModel', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$q', '$sce', 'carouselUtils', '$ionicPopup', function ($scope, $rootScope, zm, ZMDataModel, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $stateParams, $ionicHistory, $ionicScrollDelegate, $q, $sce, carouselUtils, $ionicPopup) { + + + // from parent scope + var currentEvent = $scope.currentEvent; + var nphTimer; + var eventQueryHandle; + $scope.loginData = ZMDataModel.getLogin(); + + + // $scope.currentEventLength = parseFloat($scope.currentEvent.Event.Length); + //console.log ("Current event duration is " + $scope.currentEventLength); + + + //$scope.currentEventLength = $scope.event.Event.Length; + + + var eventImageDigits = 5; // failsafe + $scope.currentProgress = 0; + ZMDataModel.getKeyConfigParams(0) + .then(function (data) { + //console.log ("***GETKEY: " + JSON.stringify(data)); + eventImageDigits = parseInt(data); + ZMDataModel.zmLog("Image padding digits reported as " + eventImageDigits); + }); + + $scope.animationInProgress = false; + $scope.imageFit = true; + // FIXME: This is a hack - for some reason + // the custom slider view is messed up till the image loads + // in modal view + $scope.showModalRangeSider = false; + $scope.isModalActive = true; + + + $timeout(function () { + $scope.showModalRangeSider = true; + + }, 2000); + + document.addEventListener("pause", onPause, false); + document.addEventListener("resume", onResume, false); + + $rootScope.authSession = "undefined"; + $ionicLoading.show({ + template: 'negotiating stream authentication...', + animation: 'fade-in', + showBackdrop: true, + duration: zm.loadingTimeout, + maxWidth: 300, + showDelay: 0 + }); + var ld = ZMDataModel.getLogin(); + + $scope.streamMode = ld.useNphZms ? "jpeg" : "single"; + $scope.currentStreamMode = 'single'; + ZMDataModel.zmLog("Using stream mode " + $scope.currentStreamMode); + + ZMDataModel.zmDebug ("EventModalCtrl called from " + $ionicHistory.currentStateName()); + // This is not needed for event mode + + + + + ZMDataModel.zmDebug("Setting playback to " + $scope.streamMode); + + + $rootScope.validMonitorId = $scope.monitors[0].Monitor.Id; + ZMDataModel.getAuthKey($rootScope.validMonitorId,(Math.floor((Math.random() * 999999) + 1)).toString()) + .then(function (success) { + $ionicLoading.hide(); + $rootScope.authSession = success; + ZMDataModel.zmLog("Modal: Stream authentication construction: " + $rootScope.authSession); + + }, + function (error) { + + $ionicLoading.hide(); + ZMDataModel.zmDebug("ModalCtrl: Error details of stream auth:" + error); + //$rootScope.authSession=""; + ZMDataModel.zmLog("Modal: Error returned Stream authentication construction. Retaining old value of: " + $rootScope.authSession); + }); + + + + $rootScope.$on("auth-success", function () { + + ZMDataModel.zmDebug("EventModalCtrl: Re-login detected, resetting everything & re-generating connkey"); + window.stop(); + $scope.connKey = (Math.floor((Math.random() * 999999) + 1)).toString(); + $timeout( function () { sendCommand('14',$scope.connKey, '&offset='+$scope.currentProgress);},500); + $timeout.cancel(eventQueryHandle); + eventQueryHandle = $timeout (function(){checkEvent();}, zm.eventPlaybackQuery); + + + + }); + + + $scope.togglePTZ = function () { + + //console.log("PTZ"); + + if ($scope.isControllable == '1') { + //console.log ("iscontrollable is true"); + $scope.showPTZ = !$scope.showPTZ; + } else { + $ionicLoading.show({ + template: "PTZ not configured for this monitor", + noBackdrop: true, + duration: 3000, + }); + } + + + + }; + + + + + function checkEvent() + { + console.log ("Event timer"); + processEvent('99',$scope.connKey); + } + + + function sendCommand(cmd,connkey,extras,rq) + { + var d = $q.defer(); + var loginData = ZMDataModel.getLogin(); + var rqtoken = rq? rq:"stream"; + var myauthtoken = $rootScope.authSession.replace("&auth=",""); + //&auth= + $http({ + method: 'POST', + /*timeout: 15000,*/ + url: loginData.url + '/index.php', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + //'Accept': '*/*', + }, + transformRequest: function (obj) { + var str = []; + for (var p in obj) + str.push(encodeURIComponent(p) + "=" + + encodeURIComponent(obj[p])); + var foo = str.join("&"); + if (extras) + { + foo = foo + extras; + //console.log("EXTRAS****SUB RETURNING " + foo); + } + return foo; + + }, + + data: { + view: "request", + request: rqtoken, + connkey: connkey, + command: cmd, + auth: myauthtoken, + // user: loginData.username, + // pass: loginData.password + } + }) + .then (function (resp) { + // ZMDataModel.zmDebug ("sendCmd response:"+JSON.stringify(resp)); + d.resolve(resp); + return (d.promise); + + + }, + function (resp) { + ZMDataModel.zmDebug ("sendCmd error:"+JSON.stringify(resp)); + d.reject (resp); + return (d.promise); + }); + + return (d.promise); + } + + + function processEvent(cmd,connkey) + { + var loginData = ZMDataModel.getLogin(); + var myauthtoken = $rootScope.authSession.replace("&auth=",""); + //&auth= + var req = $http({ + method: 'POST', + /*timeout: 15000,*/ + url: loginData.url + '/index.php', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + //'Accept': '*/*', + }, + transformRequest: function (obj) { + var str = []; + for (var p in obj) + str.push(encodeURIComponent(p) + "=" + + encodeURIComponent(obj[p])); + var foo = str.join("&"); + //console.log("****SUB RETURNING " + foo); + return foo; + }, + + data: { + view: "request", + request: "stream", + connkey: connkey, + command: cmd, + auth: myauthtoken, + // user: loginData.username, + // pass: loginData.password + } + }); + + req.success (function (resp) { + ZMDataModel.zmDebug ("processEvent success:"+JSON.stringify(resp)); + + if (resp.result=="Ok") + { + + $scope.currentProgress = resp.status.progress; + $scope.eventId = resp.status.event; + + + if ($scope.currentProgress > $scope.currentEventDuration) $scope.currentProgress = $scope.currentEventDuration; + $scope.progressText = "At " + $scope.currentProgress + "s of " + $scope.currentEventDuration+"s"; + + if (Math.floor(resp.status.progress) >=$scope.currentEventDuration) + { + ZMDataModel.zmLog ("Reached end of event " + $scope.eventId); + + + + if (loginData.gapless) + { + ZMDataModel.zmLog ("STEP 1: Moving to nextevent as gapless is on"); + sendCommand ('13',connkey) // next + .then (function (resp) // 13 + { + + sendCommand('99',connkey) // query + .then (function (resp) //99 + { + console.log ("Output of next move afer query is " + JSON.stringify(resp)); + + // now get duration; + // $scope.currentEventDuration = Math.floor($scope.currentEvent.Event.Length); + var apiurl = loginData.apiurl + "/events/" + resp.data.status.event + ".json"; + ZMDataModel.zmLog ("STEP 2:Getting details for " + apiurl); + $http.get(apiurl) + .then (function (data) + { + $scope.currentEventDuration = Math.floor(data.data.event.Event.Length); + + if (resp.data.status.event != $scope.eventId) + $scope.currentProgress = 0; // if = then we are at end + + $scope.eventId = resp.data.status.event; + + ZMDataModel.zmDebug ("STEP 3: New eid " + $scope.eventId + " duration " + $scope.currentEventDuration); + eventQueryHandle = $timeout (function(){checkEvent();}, zm.eventPlaybackQuery); + }, + function (err) //api + { + console.log ("Error " + JSON.stringify(err)); + eventQueryHandle = $timeout (function(){checkEvent();}, zm.eventPlaybackQuery); + + }); + + }, + function (err) // 99 + { + eventQueryHandle = $timeout (function(){checkEvent();}, zm.eventPlaybackQuery); + + }); + }, + function(error) { //13 + console.log ("Error of next move is " + JSON.stringify(resp)); + eventQueryHandle = $timeout (function(){checkEvent();}, zm.eventPlaybackQuery); + } ); + + $scope.currentProgress = 0; + + + } + else // not gapless + { + // keep timer on if its switched to gapless + eventQueryHandle = $timeout (function(){checkEvent();}, zm.eventPlaybackQuery); + } + + } + else // not at end of playback + { + console.log ("all good, scheduling next iteration after " + zm.eventPlaybackQuery); + //$timeout (checkEvent(), zm.eventPlaybackQuery); + eventQueryHandle = $timeout (function(){checkEvent();}, zm.eventPlaybackQuery); + } + + /* if ((resp.status.paused==1) && ($scope.currentProgress < $scope.currentEventDuration ) && !$scope.isPaused) + { + + //wtf? why? + + //No such file or directory + + ZMDataModel.zmDebug ("ZMS mysteriously paused at " + $scope.currentProgress+ "of " +$scope.currentEventDuration+"seconds , force resuming"); + sendCommand (2,connkey); + // $timeout( function () { sendCommand('14',$scope.connKey, '&offset='+$scope.currentProgress);},500); + }*/ + } + else + + { + ZMDataModel.zmDebug("Hmm I found an error " + JSON.stringify(resp) + +"so I can't tell if the playback ended"); + $scope.connKey = (Math.floor((Math.random() * 999999) + 1)).toString(); + $timeout( function () { sendCommand('14',$scope.connKey, '&offset='+$scope.currentProgress);},500); + ZMDataModel.zmDebug ("so I'm regenerating Connkey to " + $scope.connKey); + } + }); + + + req.error (function (resp) { + ZMDataModel.zmDebug ("processEvent error:"+JSON.stringify(resp)); + + }); + + } + + + + function onPause() { + + // $interval.cancel(modalIntervalHandle); + + // FIXME: Do I need to setAwake(false) here? + } + + + function onResume() { + ZMDataModel.zmDebug("EventModalCtrl: Modal resume called"); + + + $rootScope.modalRand = Math.floor((Math.random() * 100000) + 1); + + } + + + + + + + + + $scope.finishedLoadingImage = function () { + // console.log("***Monitor image FINISHED Loading***"); + $ionicLoading.hide(); + + }; + + + + + + + + + //----------------------------------------------------------------------- + // Sucess/Error handlers for saving a snapshot of the + // monitor image to phone storage + //----------------------------------------------------------------------- + + function SaveSuccess() { + $ionicLoading.show({ + template: "done!", + noBackdrop: true, + duration: 1000 + }); + ZMDataModel.zmDebug("ModalCtrl:Photo saved successfuly"); + } + + function SaveError(e) { + $ionicLoading.show({ + template: "error - could not save", + noBackdrop: true, + duration: 2000 + }); + ZMDataModel.zmLog("Error saving image: " + e.message); + //console.log("***ERROR"); + } + + + + + + + //----------------------------------------------------------------------- + // Saves a snapshot of the monitor image to phone storage + //----------------------------------------------------------------------- + + $scope.saveEventImageToPhone = function () { + + + var curState = carouselUtils.getStop(); + carouselUtils.setStop(true); + + //console.log("Your index is " + $scope.mycarousel.index); + //console.log("Associated image is " + $scope.slides[$scope.mycarousel.index].img); + + ZMDataModel.zmDebug("ModalCtrl: SaveEventImageToPhone called"); + var canvas, context, imageDataUrl, imageData; + var loginData = ZMDataModel.getLogin(); + + var url = $scope.playbackURL + '/index.php?view=image&rand=' + $rootScope.rand + "&path=" + $scope.relativePath + $scope.slides[$scope.mycarousel.index].img; + + + $scope.selectEventUrl = url; + $scope.slideIndex = $scope.mycarousel.index; + $scope.slideLastIndex = $scope.slides.length - 1; + + + + + $rootScope.zmPopup = $ionicPopup.show({ + template: '<center>Frame: {{slideIndex+1}} of {{slideLastIndex+1}}</center><br/><img src="{{selectEventUrl}}" width="100%" />', + title: 'Select frame to save', + subTitle: 'use left and right arrows to change', + scope: $scope, + cssClass: 'popup80', + buttons: [ + { + // left 1 + text: '', + type: 'button-small button-energized ion-chevron-left', + onTap: function (e) { + if ($scope.slideIndex > 0) $scope.slideIndex--; + $scope.selectEventUrl = $scope.playbackURL + '/index.php?view=image&rand=' + $rootScope.rand + "&path=" + $scope.relativePath + $scope.slides[$scope.slideIndex].img; + //ZMDataModel.zmLog("selected frame is " + $scope.slideIndex); + + e.preventDefault(); + } + }, + { + // right 1 + text: '', + type: 'button-small button-energized ion-chevron-right', + onTap: function (e) { + if ($scope.slideIndex < $scope.slideLastIndex) $scope.slideIndex++; + $scope.selectEventUrl = $scope.playbackURL + '/index.php?view=image&rand=' + $rootScope.rand + "&path=" + $scope.relativePath + $scope.slides[$scope.slideIndex].img; + //ZMDataModel.zmLog("selected frame is " + $scope.slideIndex); + e.preventDefault(); + } + }, + { + // left 10 + text: '', + type: 'button-small button-energized ion-skip-backward', + onTap: function (e) { + var tempVar = $scope.slideIndex; + tempVar -= 10; + if (tempVar < 0) tempVar = 0; + $scope.slideIndex = tempVar; + + $scope.selectEventUrl = $scope.playbackURL + '/index.php?view=image&rand=' + $rootScope.rand + "&path=" + $scope.relativePath + $scope.slides[$scope.slideIndex].img; + //ZMDataModel.zmLog("selected frame is " + $scope.slideIndex); + + e.preventDefault(); + } + }, + { + // right 10 + text: '', + type: 'button-small button-energized ion-skip-forward', + onTap: function (e) { + var tempVar = $scope.slideIndex; + tempVar += 10; + if (tempVar > $scope.slideLastIndex) tempVar = $scope.slideLastIndex; + $scope.slideIndex = tempVar; + if ($scope.slideIndex < $scope.slideLastIndex) $scope.slideIndex++; + $scope.selectEventUrl = $scope.playbackURL + '/index.php?view=image&rand=' + $rootScope.rand + "&path=" + $scope.relativePath + $scope.slides[$scope.slideIndex].img; + //ZMDataModel.zmLog("selected frame is " + $scope.slideIndex); + e.preventDefault(); + } + }, + + { + text: '', + type: 'button-assertive button-small ion-close-round' + }, + { + text: '', + type: 'button-positive button-small ion-checkmark-round', + onTap: function (e) { + saveNow(); + + } + }] + }); + + function saveNow() + { + $ionicLoading.show({ + template: "saving snapshot...", + noBackdrop: true, + duration: zm.httpTimeout + }); + var url = $scope.selectEventUrl; + ZMDataModel.zmLog ("saveNow: File path to grab is " + url); + + var img = new Image(); + img.onload = function () { + // console.log("********* ONLOAD"); + canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + context = canvas.getContext('2d'); + context.drawImage(img, 0, 0); + + imageDataUrl = canvas.toDataURL('image/jpeg', 1.0); + imageData = imageDataUrl.replace(/data:image\/jpeg;base64,/, ''); + + if ($rootScope.platformOS != "desktop") { + try { + + cordova.exec( + SaveSuccess, + SaveError, + 'Canvas2ImagePlugin', + 'saveImageDataToLibrary', [imageData] + ); + // carouselUtils.setStop(curState); + } catch (e) { + + SaveError(e.message); + // carouselUtils.setStop(curState); + } + } else { + + + var fname = $scope.relativePath+$scope.slides[$scope.slideIndex].img + ".png"; + fname = fname.replace(/\//,"-"); + fname = fname.replace(/\.jpg/,''); + + canvas.toBlob(function (blob) { + saveAs(blob, fname); + SaveSuccess(); + }); + } + }; + try { + img.src = url; + // console.log ("SAVING IMAGE SOURCE"); + } catch (e) { + SaveError(e.message); + } + } + }; + + + + + + $scope.reloadView = function () { + ZMDataModel.zmLog("Reloading view for modal view, recomputing rand"); + $rootScope.modalRand = Math.floor((Math.random() * 100000) + 1); + $scope.isModalActive = true; + }; + + $scope.scaleImage = function () { + + $scope.imageFit = !$scope.imageFit; + // console.log("Switching image style to " + $scope.imageFit); + }; + + $scope.$on('$ionicView.enter', function () { + + + + }); + + $scope.$on('modal.shown', function () { + + var ld = ZMDataModel.getLogin(); + $scope.loginData = ZMDataModel.getLogin(); + + + + currentEvent = $scope.currentEvent; + + console.log ("Current Event " + JSON.stringify(currentEvent)); + $scope.connKey = (Math.floor((Math.random() * 999999) + 1)).toString(); + console.log ("************* GENERATED CONNKEY " + $scope.connKey); + + $scope.currentFrame = 1; + $scope.isPaused = false; + //console.log ("CURRENT EVENT " + JSON.stringify($scope.currentEvent)); + $scope.currentEventDuration = Math.floor($scope.currentEvent.Event.Length); + //console.log ($scope.event.Event.Frames); + if (currentEvent && currentEvent.Event) + { + console.log ("************ CALLING PREPARE MODAL ***********"); + prepareModalEvent(currentEvent.Event.Id); + if (ld.useNphZmsForEvents) + { + + ZMDataModel.zmLog ("Starting checkAllEvents timer"); + + eventQueryHandle = $timeout (checkEvent(), zm.eventPlaybackQuery); + /*eventQueryHandle = $interval(function () { + checkEvent(); + // console.log ("Refreshing Image..."); + }.bind(this),zm.eventPlaybackQuery);*/ + } + + } + + + + + + + }); + + + $scope.$on('modal.removed', function () { + $scope.isModalActive = false; + //console.log("**MODAL REMOVED: Stopping modal timer"); + //$interval.cancel(eventQueryHandle); + $timeout.cancel(eventQueryHandle); + ZMDataModel.zmDebug ("Modal removed - killing connkey"); + sendCommand(17,$scope.connKey); + + + // Execute action + }); + + + // Playback speed adjuster + $scope.adjustSpeed = function (val) { + switch (val) { + + case "super": + $scope.eventSpeed = 20 / $scope.event.Event.Frames; + carouselUtils.setDuration($scope.eventSpeed); + break; + case "normal": + $scope.eventSpeed = $scope.event.Event.Length / $scope.event.Event.Frames; + //$scope.eventSpeed = 5; + carouselUtils.setDuration($scope.eventSpeed); + + break; + case "faster": + $scope.eventSpeed = $scope.eventSpeed / 2; + if ($scope.eventSpeed < 20 / $scope.event.Event.Frames) + $scope.eventSpeed = 10 / $scope.event.Event.Frames; + carouselUtils.setDuration($scope.eventSpeed); + break; + case "slower": + $scope.eventSpeed = $scope.eventSpeed * 2; + carouselUtils.setDuration($scope.eventSpeed); + + break; + default: + + + } + ZMDataModel.zmDebug("Set playback speed to " + $scope.eventSpeed); + + $ionicLoading.show({ + template: 'playback interval: ' + $scope.eventSpeed.toFixed(3) + "ms", + animation: 'fade-in', + showBackdrop: false, + duration: 1500, + maxWidth: 300, + showDelay: 0 + }); + + + }; + + + $scope.toggleGapless = function () { + // console.log(">>>>>>>>>>>>>>GAPLESS TOGGLE INSIDE MODAL"); + $scope.loginData.gapless = !$scope.loginData.gapless; + ZMDataModel.setLogin($scope.loginData); + + }; + + + // This function returns neighbor events if applicable + function neighborEvents(eid) { + var d = $q.defer(); + // now get event details to show alarm frames + var loginData = ZMDataModel.getLogin(); + var myurl = loginData.apiurl + '/events/' + eid + ".json"; + var neighbors = { + prev: "", + next: "" + }; + $http.get(myurl) + .success(function (data) { + + // In Timeline view, gapless should stick to the same monitor + if ($scope.followSameMonitor == "1") // we are viewing only one monitor + { + ZMDataModel.zmDebug("Getting next event for same monitor Id "); + neighbors.prev = data.event.Event.PrevOfMonitor ? data.event.Event.PrevOfMonitor : ""; + neighbors.next = data.event.Event.NextOfMonitor ? data.event.Event.NextOfMonitor : ""; + } else { + neighbors.prev = data.event.Event.Prev ? data.event.Event.Prev : ""; + neighbors.next = data.event.Event.Next ? data.event.Event.Next : ""; + } + ZMDataModel.zmDebug("Neighbor events of " + eid + "are Prev:" + + neighbors.prev + " and Next:" + neighbors.next); + + + d.resolve(neighbors); + return (d.promise); + }) + .error(function (err) { + ZMDataModel.zmLog("Error retrieving neighbors" + JSON.stringify(err)); + d.reject(neighbors); + return (d.promise); + + + }); + return (d.promise); + + } + + + $scope.zoomImage = function (val) + { + var zl = parseInt($ionicScrollDelegate.$getByHandle("imgscroll").getScrollPosition().zoom); + if (zl == 1 && val == -1) + { + ZMDataModel.zmDebug ("Already zoomed out max"); + return; + } + + + zl+=val; + ZMDataModel.zmDebug ("Zoom level is " + zl); $ionicScrollDelegate.$getByHandle("imgscroll").zoomTo(zl,true); + + }; + + + //-------------------------------------------------------- + //Navigate to next/prev event in full screen mode + //-------------------------------------------------------- + + $scope.onSwipeEvent = function (eid, dirn) { + //console.log("HERE"); + var ld = ZMDataModel.getLogin(); + if (!ld.canSwipeMonitors) return; + + if ($ionicScrollDelegate.$getByHandle("imgscroll").getScrollPosition().zoom != 1) { + //console.log("Image is zoomed in - not honoring swipe"); + return; + } + + if (ld.useNphZmsForEvents) + { + ZMDataModel.zmLog("using zms to move "); + jumpToEventZms($scope.connKey, dirn); + // sendCommand ( dirn==1?'13':'12',$scope.connKey); + + } + else + { + jumpToEvent(eid, dirn); + } + + //console.log("JUMPING"); + + + }; + + $scope.jumpToEvent = function (eid, dirn) { + // console.log("jumptoevent"); + + jumpToEvent(eid, dirn); + + }; + + function jumpToEvent(eid, dirn) { + ZMDataModel.zmLog("Event jump called with:" + eid); + if (eid == "") { + $ionicLoading.show({ + template: "no more events", + noBackdrop: true, + duration: 2000 + }); + + return; + } + + var slidein; + var slideout; + if (dirn == 1) { + slideout = "animated slideOutLeft"; + slidein = "animated slideInRight"; + } else { + slideout = "animated slideOutRight"; + slidein = "animated slideInLeft"; + } + var element = angular.element(document.getElementById("full-screen-event")); + element.addClass(slideout).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', outWithOld); + + + + function outWithOld() { + + ZMDataModel.zmLog("ModalCtrl:Stopping network pull..."); + window.stop(); + $scope.animationInProgress = true; + // give digest time for image to swap + // 100 should be enough + $timeout(function () { + element.removeClass(slideout); + element.addClass(slidein) + .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', inWithNew); + prepareModalEvent(eid); + }, 200); + } + + function inWithNew() { + element.removeClass(slidein); + $scope.animationInProgress = false; + carouselUtils.setStop(false); + } + + } + + + + function jumpToEventZms(connkey, dirn) { + + var cmd = dirn==1?'13':'12'; + + ZMDataModel.zmDebug ("Sending " + cmd + " to " + connkey); + + $ionicLoading.show({ + template: "switching events..", + noBackdrop: true, + duration: zm.httpTimeout + }); + + sendCommand ( cmd,connkey) + .then (function (success) {$ionicLoading.hide();}, function (error) {$ionicLoading.hide();}); + var slidein; + var slideout; + if (dirn == 1) { + slideout = "animated slideOutLeft"; + slidein = "animated slideInRight"; + } else { + slideout = "animated slideOutRight"; + slidein = "animated slideInLeft"; + } + var element = angular.element(document.getElementById("full-screen-event")); + element.addClass(slideout).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', outWithOld); + + + + function outWithOld() { + + + + $timeout(function () { + element.removeClass(slideout); + element.addClass(slidein) + .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', inWithNew); + + }, 200); + } + + function inWithNew() { + element.removeClass(slidein); + + + } + + } + + + //-------------------------------------------------------- + // utility function + //-------------------------------------------------------- + + function computeRelativePath(event) { + var relativePath = ""; + var loginData = ZMDataModel.getLogin(); + var str = event.Event.StartTime; + var yy = moment(str).format('YY'); + var mm = moment(str).format('MM'); + var dd = moment(str).format('DD'); + var hh = moment(str).format('HH'); + var min = moment(str).format('mm'); + var sec = moment(str).format('ss'); + relativePath = event.Event.MonitorId + "/" + + yy + "/" + + mm + "/" + + dd + "/" + + hh + "/" + + min + "/" + + sec + "/"; + return relativePath; + + } + + //-------------------------------------------------------- + // utility function + //-------------------------------------------------------- + + function computeBasePath(event) { + var basePath = ""; + var loginData = ZMDataModel.getLogin(); + var str = event.Event.StartTime; + var yy = moment(str).format('YY'); + var mm = moment(str).format('MM'); + var dd = moment(str).format('DD'); + var hh = moment(str).format('HH'); + var min = moment(str).format('mm'); + var sec = moment(str).format('ss'); + + basePath = loginData.url + "/events/" + + event.Event.MonitorId + "/" + + yy + "/" + + mm + "/" + + dd + "/" + + hh + "/" + + min + "/" + + sec + "/"; + return basePath; + } + + + //------------------------------------------------------------------------- + // Called when rncarousel or video player finished playing event + //------------------------------------------------------------------------- + + $scope.playbackFinished = function () { + playbackFinished(); + }; + + function playbackFinished() { + // currentEvent is updated with the currently playing event in prepareModalEvent() + ZMDataModel.zmLog("Playback of event " + currentEvent.Event.Id + " is finished"); + + if ($scope.loginData.gapless) { + + neighborEvents(currentEvent.Event.Id) + .then(function (success) { + + // lets give a second before gapless transition to the next event + $timeout(function () { + $scope.nextId = success.next; + $scope.prevId = success.prev; + ZMDataModel.zmDebug("Gapless move to event " + $scope.nextId); + jumpToEvent($scope.nextId, 1); + }, 1000); + }, + function (error) { + ZMDataModel.zmDebug("Error in neighbor call " + + JSON.stringify(error)); + }); + } else { + ZMDataModel.zmDebug("not going to next event, gapless is off"); + } + } + + + //-------------------------------------------------------- + // Called by openModal as well as jump to event + // what it basically does is get a detailed event API + // for an event ID and constructs required playback + // parameters + // Note that openModal is called with the top level event + // API. Some parameters are repeated across both + //-------------------------------------------------------- + + + function prepareModalEvent(eid) { + + // Lets get the detailed event API + var loginData = ZMDataModel.getLogin(); + var myurl = loginData.apiurl + '/events/' + eid + ".json"; + ZMDataModel.zmLog("*** Constructed API for detailed events: " + myurl); + $http.get(myurl) + .then(function (success) { + + + // console.log ("DUCCESS::"+JSON.stringify(success)); + var event = success.data.event; + currentEvent = event; + + event.Event.BasePath = computeBasePath(event); + event.Event.relativePath = computeRelativePath(event); + + + //console.log (JSON.stringify( success)); + $scope.eventName = event.Event.Name; + $scope.eventId = event.Event.Id; + $scope.eFramesNum = event.Event.Frames; + $scope.eventDur = Math.round(event.Event.Length); + $scope.loginData = ZMDataModel.getLogin(); + + //console.log("**** VIDEO STATE IS " + event.Event.DefaultVideo); + if (typeof event.Event.DefaultVideo === 'undefined') + event.Event.DefaultVideo = ""; + + $scope.defaultVideo = event.Event.DefaultVideo; + + console.log ("loginData is " + JSON.stringify($scope.loginData)); + console.log ("Event ID is " + $scope.eventId); + console.log ("video is " + $scope.defaultVideo); + + + neighborEvents(event.Event.Id) + .then(function (success) { + $scope.nextId = success.next; + $scope.prevId = success.prev; + }, + function (error) { + //console.log(JSON.stringify(error)); + }); + + $scope.nextId = "..."; + $scope.prevId = "..."; + + + + + event.Event.video = {}; + var videoURL = $scope.loginData.url + "/events/" + event.Event.relativePath + event.Event.DefaultVideo; + + //console.log("************** VIDEO IS " + videoURL); + event.Event.video.config = { + autoPlay: true, + sources: [ + { + src: $sce.trustAsResourceUrl(videoURL), + type: "video/mp4" + } + + ], + + theme: "lib/videogular-themes-default/videogular.css", + + }; + + $scope.videoObject = event.Event.video; + + $scope.playbackURL = $scope.loginData.url; + + /* we don't need this for electron + if ($rootScope.platformOS == "desktop") { + $scope.playbackURL = zm.desktopUrl; + } */ + + $scope.eventBasePath = event.Event.BasePath; + $scope.relativePath = event.Event.relativePath; + $rootScope.rand = Math.floor(Math.random() * (999999 - 111111 + 1)) + 111111; + + $scope.slider_modal_options = { + from: 1, + to: event.Event.Frames, + realtime: true, + step: 1, + className: "mySliderClass", + callback: function (value, released) { + //console.log("CALLBACK"+value+released); + $ionicScrollDelegate.freezeScroll(!released); + + + }, + //modelLabels:function(val) {return "";}, + smooth: false, + css: { + background: { + "background-color": "silver" + }, + before: { + "background-color": "purple" + }, + default: { + "background-color": "white" + }, // default value: 1px + after: { + "background-color": "green" + }, // zone after default value + pointer: { + "background-color": "red" + }, // circle pointer + range: { + "background-color": "red" + } // use it if double value + }, + scale: [] + + }; + + + $scope.mycarousel.index = 0; + $scope.ionRange.index = 1; + $scope.eventSpeed = $scope.event.Event.Length / $scope.event.Event.Frames; + + //console.log("**Resetting range"); + $scope.slides = []; + var i; + for (i = 1; i <= event.Event.Frames; i++) { + var fname = padToN(i, eventImageDigits) + "-capture.jpg"; + // console.log ("Building " + fname); + $scope.slides.push({ + id: i, + img: fname + }); + } + + + // now get event details to show alarm frames + + $scope.FrameArray = event.Frame; + // $scope.slider_options.scale=[]; + $scope.slider_modal_options.scale = []; + + + for (i = 0; i < event.Frame.length; i++) { + + if (event.Frame[i].Type == "Alarm") { + + $scope.slider_modal_options.scale.push({ + val: event.Frame[i].FrameId, + label: ' ' + }); + } else { + //$scope.slider_options.scale.push(' '); + } + + + } + $scope.totalEventTime = Math.round(parseFloat(event.Event.Length)) - 1; + $scope.currentEventTime = 0; + }, + function (err) { + ZMDataModel.zmLog("Error retrieving detailed frame API " + JSON.stringify(err)); + ZMDataModel.displayBanner('error', ['could not retrieve frame details', 'please try again']); + }); + + + } + + + if (typeof $scope.ionRange !== 'undefined') { + $scope.$watch('ionRange.index', function () { + // + $scope.mycarousel.index = parseInt($scope.ionRange.index) - 1; + + if (carouselUtils.getStop() == true) + return; + + + // console.log ("***ION RANGE CHANGED TO " + $scope.mycarousel.index); + }); + } + + if (typeof $scope.mycarousel !== 'undefined') { + $scope.$watch('mycarousel.index', function () { + + + + //console.log ("***ION MYCAROUSEL CHANGED"); + + if (currentEvent && $scope.ionRange.index == parseInt(currentEvent.Event.Frames)) { + playbackFinished(); + } + // end of playback from quick scrub + // so ignore gapless + + + + if ($scope.event && $scope.ionRange.index == parseInt($scope.event.Event.Frames) - 1) { + if (!$scope.modal || $scope.modal.isShown() == false) { + // console.log("quick scrub playback over"); + carouselUtils.setStop(true); + $scope.ionRange.index = 0; + $scope.mycarousel.index = 1; + } + + } + if (carouselUtils.getStop() == true) + return; + $scope.ionRange.index = ($scope.mycarousel.index + 1).toString(); + // console.log ("***IONRANGE RANGE CHANGED TO " + $scope.ionRange.index); + + + }); + } + + function padToN(number, digits) { + + var i; + var stringMax = ""; + var stringLeading = ""; + for (i = 1; i <= digits; i++) { + stringMax = stringMax + "9"; + if (i != digits) stringLeading = stringLeading + "0"; + } + var numMax = parseInt(stringMax); + + if (number <= numMax) { + number = (stringLeading + number).slice(-digits); + } + //console.log ("PADTON: returning " + number); + return number; + } + + + +}]);
\ No newline at end of file diff --git a/www/js/ModalCtrl.js b/www/js/MonitorModalCtrl.js index 1deffdbb..dc34372a 100644 --- a/www/js/ModalCtrl.js +++ b/www/js/MonitorModalCtrl.js @@ -4,12 +4,28 @@ /* global saveAs, cordova,StatusBar,angular,console,ionic, moment */ -angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootScope', 'zm', 'ZMDataModel', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$q', '$sce', 'carouselUtils', '$ionicPopup', function ($scope, $rootScope, zm, ZMDataModel, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $stateParams, $ionicHistory, $ionicScrollDelegate, $q, $sce, carouselUtils, $ionicPopup) { +/* FIXME for nph events +a) timers +b) sliders +c) photo save +d) gapless + +*/ + +angular.module('zmApp.controllers').controller('MonitorModalCtrl', ['$scope', '$rootScope', 'zm', 'ZMDataModel', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$q', '$sce', 'carouselUtils', '$ionicPopup', function ($scope, $rootScope, zm, ZMDataModel, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $stateParams, $ionicHistory, $ionicScrollDelegate, $q, $sce, carouselUtils, $ionicPopup) { // from parent scope var currentEvent = $scope.currentEvent; var nphTimer; + var eventQueryHandle; + + + // $scope.currentEventLength = parseFloat($scope.currentEvent.Event.Length); + //console.log ("Current event duration is " + $scope.currentEventLength); + + + //$scope.currentEventLength = $scope.event.Event.Length; var eventImageDigits = 5; // failsafe @@ -52,7 +68,12 @@ angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootSco $scope.currentStreamMode = 'single'; ZMDataModel.zmLog("Using stream mode " + $scope.currentStreamMode); - if (ld.useNphZms == true) { + ZMDataModel.zmDebug ("ModalCtrl called from " + $ionicHistory.currentStateName()); + // This is not needed for event mode + + if (ld.useNphZms == true && + $ionicHistory.currentStateName() != 'events' && + $ionicHistory.currentStateName() != 'timeline' ) { ZMDataModel.zmLog("Setting timer to play nph-zms mode"); // first 5 seconds, load a snapshot, then switch to real FPS display // this is to avoid initial image load delay @@ -84,6 +105,16 @@ angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootSco //$rootScope.authSession=""; ZMDataModel.zmLog("Modal: Error returned Stream authentication construction. Retaining old value of: " + $rootScope.authSession); }); + + + $rootScope.$on("auth-success", function () { + + ZMDataModel.zmDebug("MonitorModalCtrl: Re-login detected, resetting everything & re-generating connkey"); + window.stop(); + $scope.connKey = (Math.floor((Math.random() * 999999) + 1)).toString(); + + + }); $scope.togglePTZ = function () { @@ -219,7 +250,8 @@ angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootSco $interval.cancel(intervalModalHandle); - if (ld.useNphZms == false) { + if (ld.useNphZms == false && $ionicHistory.currentStateName() != 'events' && + $ionicHistory.currentStateName() != 'timeline') { intervalModalHandle = $interval(function () { loadModalNotifications(); // console.log ("Refreshing Image..."); @@ -227,9 +259,67 @@ angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootSco loadModalNotifications(); } else { - ZMDataModel.zmLog("Using nph-zms, no timer needed"); + ZMDataModel.zmLog("Using nph-zms or not live view, no timer needed"); + + } + + + function checkEvent() + { + subControlStream('99',$scope.connKey); + } + + + function subControlStream(cmd,connkey) + { + var loginData = ZMDataModel.getLogin(); + var myauthtoken = $rootScope.authSession.replace("&auth=",""); + //&auth= + var req = $http({ + method: 'POST', + /*timeout: 15000,*/ + url: loginData.url + '/index.php', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + //'Accept': '*/*', + }, + transformRequest: function (obj) { + var str = []; + for (var p in obj) + str.push(encodeURIComponent(p) + "=" + + encodeURIComponent(obj[p])); + var foo = str.join("&"); + //console.log("****SUB RETURNING " + foo); + return foo; + }, + + data: { + view: "request", + request: "stream", + connkey: connkey, + command: cmd, + auth: myauthtoken, + // user: loginData.username, + // pass: loginData.password + } + }); + + req.success (function (resp) { + ZMDataModel.zmDebug ("subControl success:"+JSON.stringify(resp)); + if (parseFloat(resp.status.progress) >=$scope.currentEventDuration) + { + console.lof ("********** END OF EVENT PLAYBACK"); + } + }); + + + req.error (function (resp) { + ZMDataModel.zmDebug ("subControl error:"+JSON.stringify(resp)); + }); + + } @@ -250,14 +340,17 @@ angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootSco $interval.cancel(intervalModalHandle); var ld = ZMDataModel.getLogin(); - if (ld.useNphZms == false) { + if (ld.useNphZms == false && $ionicHistory.currentStateName() != 'events' && + $ionicHistory.currentStateName() != 'timeline') { intervalModalHandle = $interval(function () { loadModalNotifications(); // console.log ("Refreshing Image..."); }.bind(this), ld.refreshSec * 1000); } else { - ZMDataModel.zmLog("using nph - no timers needed"); + ZMDataModel.zmLog("using nph or not live view - no timers needed"); } + + $rootScope.modalRand = Math.floor((Math.random() * 100000) + 1); @@ -1019,6 +1112,7 @@ angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootSco $scope.isModalActive = false; //console.log("**MODAL REMOVED: Stopping modal timer"); $interval.cancel(intervalModalHandle); + $interval.cancel(eventQueryHandle); ZMDataModel.zmDebug ("Modal removed - killing connkey"); controlStream(17,"",$scope.connKey,-1); @@ -1540,9 +1634,32 @@ angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootSco } $scope.$on('modal.shown', function () { + + var ld = ZMDataModel.getLogin(); currentEvent = $scope.currentEvent; + $scope.connKey = (Math.floor((Math.random() * 999999) + 1)).toString(); + console.log ("************* GENERATED CONNKEY " + $scope.connKey); + $scope.currentFrame = 1; + console.log ("CURRENT EVENT " + JSON.stringify($scope.currentEvent)); + $scope.currentEventDuration = parseFloat($scope.currentEvent.Event.Length); + //console.log ($scope.event.Event.Frames); if (currentEvent && currentEvent.Event) prepareModalEvent(currentEvent.Event.Id); + + if (ld.useNphZmsForEvents && ( $ionicHistory.currentStateName() == 'events' || + $ionicHistory.currentStateName() == 'timeline')) + { + checkEvent(); + ZMDataModel.zmLog ("Starting checkAllEvents timer"); + eventQueryHandle = $interval(function () { + checkEvent(); + // console.log ("Refreshing Image..."); + }.bind(this),zm.eventPlaybackQuery); + } + + + + }); }]);
\ No newline at end of file diff --git a/www/js/MontageCtrl.js b/www/js/MontageCtrl.js index 5c7e519f..5102068e 100644 --- a/www/js/MontageCtrl.js +++ b/www/js/MontageCtrl.js @@ -194,7 +194,7 @@ angular.module('zmApp.controllers').controller('zmApp.MontageCtrl', ['$scope', ' //console.log ("MONITORS " + JSON.stringify($scope.monitors)); $rootScope.validMonitorId = $scope.monitors[0].Monitor.Id; - ZMDataModel.getAuthKey($rootScope.validMonitorId, $scope.monitors[0].Monitor.connKey) + ZMDataModel.getAuthKey($rootScope.validMonitorId, (Math.floor((Math.random() * 999999) + 1)).toString()) .then(function (success) { $ionicLoading.hide(); //console.log(success); @@ -592,7 +592,7 @@ angular.module('zmApp.controllers').controller('zmApp.MontageCtrl', ['$scope', ' $scope.ptzMoveCommand = ""; $scope.ptzStopCommand = ""; $scope.presetOn = false; - $scope.connKey = connKey; + $scope.connKey = (Math.floor((Math.random() * 999999) + 1)).toString(); // This is a modal to show the monitor footage // We need to switch to always awake if set so the feed doesn't get interrupted diff --git a/www/js/app.js b/www/js/app.js index b699d627..f4c2f819 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -41,7 +41,7 @@ angular.module('zmApp', [ authoremail: 'pliablepixels+zmNinja@gmail.com', logFileMaxSize: 20000, // after this limit log gets reset loginInterval: 300000, //5m*60s*1000 - ZM auto login after 5 mins - //loginInterval: 60000, + //loginInterval: 30000, updateCheckInterval: 86400000, // 24 hrs loadingTimeout: 15000, safeMontageLimit: 10, @@ -71,6 +71,7 @@ angular.module('zmApp', [ blogUrl:"http://pliablepixels.github.io/feed.json", nphSwitchTimer:6000, eventHistoryTimer:10000, + eventPlaybackQuery:3000, }) @@ -168,6 +169,112 @@ angular.module('zmApp', [ }; }) +//------------------------------------------------------- +// Ability to share controllers with modals +// Credit: http://codepen.io/julianpaulozzi/pen/wBgpjM +//------------------------------------------------------- + +.factory('appModalService', +['$ionicModal', '$rootScope', '$q', '$injector', '$controller', function($ionicModal, $rootScope, $q, $injector, $controller) { + + return { + show: show + }; + + function show(templateUrl, controller, parameters, options) { + // Grab the injector and create a new scope + var deferred = $q.defer(), + ctrlInstance, + modalScope = $rootScope.$new(), + thisScopeId = modalScope.$id, + defaultOptions = { + animation: 'slide-in-up', + focusFirstInput: false, + backdropClickToClose: true, + hardwareBackButtonClose: true, + modalCallback: null + }; + + options = angular.extend({}, defaultOptions, options); + + $ionicModal.fromTemplateUrl(templateUrl, { + scope: modalScope, + animation: options.animation, + focusFirstInput: options.focusFirstInput, + backdropClickToClose: options.backdropClickToClose, + hardwareBackButtonClose: options.hardwareBackButtonClose + }).then(function (modal) { + modalScope.modal = modal; + + modalScope.openModal = function () { + modalScope.modal.show(); + }; + modalScope.closeModal = function (result) { + deferred.resolve(result); + modalScope.modal.hide(); + }; + modalScope.$on('modal.hidden', function (thisModal) { + if (thisModal.currentScope) { + var modalScopeId = thisModal.currentScope.$id; + if (thisScopeId === modalScopeId) { + deferred.resolve(null); + _cleanup(thisModal.currentScope); + } + } + }); + + // Invoke the controller + var locals = { '$scope': modalScope, 'parameters': parameters }; + var ctrlEval = _evalController(controller); + ctrlInstance = $controller(controller, locals); + if (ctrlEval.isControllerAs) { + ctrlInstance.openModal = modalScope.openModal; + ctrlInstance.closeModal = modalScope.closeModal; + } + + modalScope.modal.show() + .then(function () { + modalScope.$broadcast('modal.afterShow', modalScope.modal); + }); + + if (angular.isFunction(options.modalCallback)) { + options.modalCallback(modal); + } + + }, function (err) { + deferred.reject(err); + }); + + return deferred.promise; + } + + function _cleanup(scope) { + scope.$destroy(); + if (scope.modal) { + scope.modal.remove(); + } + } + + function _evalController(ctrlName) { + var result = { + isControllerAs: false, + controllerName: '', + propName: '' + }; + var fragments = (ctrlName || '').trim().split(/\s+/); + result.isControllerAs = fragments.length === 3 && (fragments[1] || '').toLowerCase() === 'as'; + if (result.isControllerAs) { + result.controllerName = fragments[0]; + result.propName = fragments[2]; + } else { + result.controllerName = ctrlName; + } + + return result; + } + +}]) + //------------------------------------------------------------------ // this directive will be called any time an image completes loading // via img tags where this directive is added (I am using this in diff --git a/www/templates/devoptions.html b/www/templates/devoptions.html index 27c5fe23..2ae803fb 100644 --- a/www/templates/devoptions.html +++ b/www/templates/devoptions.html @@ -35,7 +35,13 @@ <label> <ion-toggle ng-model="loginData.useNphZms" ng-checked="{{loginData.useNphZms}}" - toggle-class="toggle-calm">use ZMS for single stream</ion-toggle> + toggle-class="toggle-calm">use ZMS for single live view</ion-toggle> + </label> + + <label> + <ion-toggle ng-model="loginData.useNphZmsForEvents" + ng-checked="{{loginData.useNphZmsForEvents}}" + toggle-class="toggle-calm">use ZMS for events footage</ion-toggle> </label> <div class="item item-input-inset"> diff --git a/www/templates/events-modal.html b/www/templates/events-modal.html index f51ec86e..df2e3cbe 100644 --- a/www/templates/events-modal.html +++ b/www/templates/events-modal.html @@ -1,4 +1,4 @@ -<div ng-controller="ModalCtrl" ng-cloak> + <div ng-controller="EventModalCtrl"> <!-- style="width: 90%; height: 90%; top: 5%; left: 5%; right: 5%; bottom: 5%;"--> <ion-modal-view cache-view="false"> <ion-content style="background-color:#444444" ng-cloak> @@ -8,19 +8,16 @@ <div id="full-screen-event" style="height: 100vh;"> - <div ng-if="defaultVideo=='' || loginData.enableh264==false"> + <div ng-if="(defaultVideo=='' || loginData.enableh264==false) && !loginData.useNphZmsForEvents"> - <!--<ul rn-carousel rn-carousel-buffered rn-carousel-transition="none" rn-swipe-disabled="true" rn-carousel-index="mycarousel.index" rn-carousel-auto-slide="{{event.Event.Length/event.Event.Frames}}" rn-carousel-pause-on-hover rn-platform="{{$root.platformOS}}">--> - - -<!--Speed:{{eventSpeed}}--> -<ul rn-carousel rn-carousel-transition="none" rn-swipe-disabled="true" rn-carousel-index="mycarousel.index" rn-carousel-auto-slide="{{eventSpeed}}" rn-carousel-pause-on-hover rn-platform="{{$root.platformOS}}" rn-carousel-buffered > - + + <ul rn-carousel rn-carousel-transition="none" rn-swipe-disabled="true" rn-carousel-index="mycarousel.index" rn-carousel-auto-slide="{{eventSpeed}}" rn-carousel-pause-on-hover rn-platform="{{$root.platformOS}}" rn-carousel-buffered > + <li ng-repeat="slide in slides"> <div ng-if="!animationInProgress"> <img style="width:100vw; height:100vh" imageonload="finishedLoadingImage($index)" - image-spinner-src="{{playbackURL}}/index.php?view=image&rand={{$root.rand}}&path={{relativePath}}{{slide.img}}&scale={{loginData.singleImageQuality}}" + image-spinner-src="{{playbackURL}}/index.php?view=image&rand={{$root.rand}}&path={{relativePath}}{{slide.img}}&scale={{loginData.singleImageQuality}}{{$root.authSession}}" image-spinner-loader="lines" ng-class="{'object-fit_cover':imageFit==false, 'object-fit_contain':imageFit==true}" @@ -39,8 +36,20 @@ </li> </ul> </div> + + <!-- route via ZMS --> + + <div ng-if="( (defaultVideo=='') || (loginData.enableh264==false)) && (loginData.useNphZmsForEvents==true)"> + + <div style="color:white">connkey:{{connKey}}</div> + <div style="width:100vw; height:100vh" > + <img image-spinner-src="{{loginData.streamingurl}}/nph-zms?source=event&mode=jpeg&event={{eventId}}&frame=1&replay=single&rate=100&connkey={{connKey}}&scale={{loginData.singleImageQuality}}{{$root.authSession}}" ng-class="{'object-fit_cover':imageFit==false, 'object-fit_contain':imageFit==true}"/> + + </div> + </div> + <!-- no default video --> - +<!-- <div ng-if="defaultVideo!==undefined && defaultVideo!='' && loginData.enableh264 == true"> <div> <videogular vg-theme="videoObject.config.theme" vg-complete="playbackFinished()"> @@ -62,7 +71,7 @@ </div> - +--> </div> <!-- 100vh --> </ion-scroll> @@ -102,7 +111,7 @@ </nav> -<div class="events-range-modal" ng-if="defaultVideo==''"> +<div class="events-range-modal" ng-if="(defaultVideo=='' )&& (!loginData.useNphZmsForEvents)"> <div style="width:90%"> <input ng-model="ionRange.index" type="text" id="mySlider2" slider options="slider_modal_options" /> @@ -110,6 +119,11 @@ </div> + +<div class="events-range-modal" ng-if="(defaultVideo=='' )&& (loginData.useNphZmsForEvents)" style="color:white"> + <!-- Progress: Event: {{eventId}} - {{progressText}}--> + <progress max="{{currentEventDuration}}" value="{{currentProgress}}"></progress> +</div> <div class="events-range-modal-text" >showing event: {{eventId}}</div> @@ -154,4 +168,4 @@ <progress max="{{totalEventTime}}" value="{{currentEventTime}}" class="eventprogress"></progress> --> - </div>
\ No newline at end of file +</div>
\ No newline at end of file diff --git a/www/templates/events.html b/www/templates/events.html index 02254bce..41e29ee4 100644 --- a/www/templates/events.html +++ b/www/templates/events.html @@ -1,4 +1,4 @@ -<div ng-controller="ModalCtrl"> +<!--<div ng-controller="EventModalCtrl">--> <ion-view cache-view="false"> <ion-nav-title>{{scrollPosition();}}</ion-nav-title> <ion-nav-buttons side="left"> @@ -327,4 +327,4 @@ </ion-view> -</div>
\ No newline at end of file +<!--</div>-->
\ No newline at end of file diff --git a/www/templates/monitors-modal.html b/www/templates/monitors-modal.html index cadd856c..92330d15 100644 --- a/www/templates/monitors-modal.html +++ b/www/templates/monitors-modal.html @@ -1,4 +1,4 @@ -<div ng-controller="ModalCtrl" ng-cloak> +<div ng-controller="MonitorModalCtrl" ng-cloak> <!--style="background-color:#444444;width: 90%; height: 90%; top: 5%; left: 5%; right: 5%; bottom: 5%;"--> |
