diff options
Diffstat (limited to 'www')
| -rw-r--r-- | www/js/EventCtrl.js | 5 | ||||
| -rw-r--r-- | www/js/ModalCtrl.js | 3 | ||||
| -rw-r--r-- | www/js/TimelineCtrl.js | 608 |
3 files changed, 452 insertions, 164 deletions
diff --git a/www/js/EventCtrl.js b/www/js/EventCtrl.js index a2b79638..20c4f627 100644 --- a/www/js/EventCtrl.js +++ b/www/js/EventCtrl.js @@ -1237,13 +1237,14 @@ angular.module('zmApp.controllers') } - $scope.toggleGapless = function() + $scope.toggleGapless = function() { - + console.log ("GAPLESS TOGGLE"); $scope.loginData.gapless = !$scope.loginData.gapless; ZMDataModel.setLogin($scope.loginData); }; + //-------------------------------------------------------- //Navigate to next/prev event in full screen mode diff --git a/www/js/ModalCtrl.js b/www/js/ModalCtrl.js index 4aa56eb7..df2c560c 100644 --- a/www/js/ModalCtrl.js +++ b/www/js/ModalCtrl.js @@ -441,6 +441,9 @@ angular.module('zmApp.controllers').controller('ModalCtrl', ['$scope', '$rootSco ZMDataModel.zmLog("Error saving image: " + e.message); console.log("***ERROR"); } + + + //----------------------------------------------------------------------- // Saves a snapshot of the monitor image to phone storage diff --git a/www/js/TimelineCtrl.js b/www/js/TimelineCtrl.js index f2e8885b..b8321e00 100644 --- a/www/js/TimelineCtrl.js +++ b/www/js/TimelineCtrl.js @@ -9,7 +9,11 @@ // I've disabled pan and zoom and used buttons instead // also limits # of items to maxItems (currently 200) -angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPlatform', '$scope', 'zm', 'ZMDataModel', '$ionicSideMenuDelegate', '$rootScope', '$http', '$q', 'message', '$state', '$ionicLoading', '$ionicPopover', '$ionicScrollDelegate', '$ionicModal', '$timeout', '$ionicContentBanner', '$ionicHistory','$sce', function ($ionicPlatform, $scope, zm, ZMDataModel, $ionicSideMenuDelegate, $rootScope, $http, $q, message, $state, $ionicLoading, $ionicPopover, $ionicScrollDelegate, $ionicModal, $timeout, $ionicContentBanner, $ionicHistory, $sce) { + +// FIXME: too much redundant code between EventCtrl and Timeline +// Move to ModalCtrl and see if it works + +angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPlatform', '$scope', 'zm', 'ZMDataModel', '$ionicSideMenuDelegate', '$rootScope', '$http', '$q', 'message', '$state', '$ionicLoading', '$ionicPopover', '$ionicScrollDelegate', '$ionicModal', '$timeout', '$ionicContentBanner', '$ionicHistory','$sce', '$stateParams', function ($ionicPlatform, $scope, zm, ZMDataModel, $ionicSideMenuDelegate, $rootScope, $http, $q, message, $state, $ionicLoading, $ionicPopover, $ionicScrollDelegate, $ionicModal, $timeout, $ionicContentBanner, $ionicHistory, $sce,$stateParams) { console.log("Inside Timeline controller"); $scope.openMenu = function () { @@ -113,151 +117,34 @@ angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPla // To show a modal dialog with the event tapped on in timeline // FIXME : code repeat from Events //-------------------------------------------------------- - function openModal(eid, ename, edur, eframes, basepath, relativepath, evideo) { - ZMDataModel.zmDebug("TimelineCtrl: Open Modal with path " + relativepath); - $scope.eventName = ename; - $scope.eventId = eid; - $scope.eFramesNum = eframes; - $scope.eventDur = Math.round(edur); - $scope.loginData = ZMDataModel.getLogin(); - $scope.eventBasePath = basepath; - $scope.relativePath = relativepath; - $rootScope.rand = Math.floor(Math.random() * (999999 - 111111 + 1)) + 111111; - console.log ("**** defaultVideo is " + evideo); - - $scope.playbackURL = $scope.loginData.url; - /* if ($rootScope.platformOS == "desktop") { - $scope.playbackURL = zm.desktopUrl; - }*/ - - - $scope.defaultVideo = evideo; - $scope.videoObject = {}; - var videoURL = $scope.loginData.url + "/events/" + relativepath + evideo; - console.log ("Video path in openModal: " + videoURL); - $scope.videoObject.config = { - autoPlay: true, - sources: [ - { - src: $sce.trustAsResourceUrl(videoURL), - type: "video/mp4" - } - - ], - - theme: "lib/videogular-themes-default/videogular.css", - - }; - - - $scope.slider_modal_options = { - from: 1, - to: eframes, - 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; - //console.log("**Resetting range"); - $scope.slides = []; - var i; - for (i = 1; i <= eframes; i++) { - var fname = padToN(i, eventImageDigits) + "-capture.jpg"; - // console.log ("Building " + fname); - $scope.slides.push({ - id: i, - img: fname - }); - } + function openModal(event) { + ZMDataModel.setAwake(ZMDataModel.getKeepAwake()); + + currentEvent = event; - // now get event details to show alarm frames - var loginData = ZMDataModel.getLogin(); - var myurl = loginData.apiurl + '/events/' + eid + ".json"; - ZMDataModel.zmLog("*** Constructed API for detailed events: " + myurl); - $http.get(myurl) - .success(function (data) { - $scope.FrameArray = data.event.Frame; - // $scope.slider_options.scale=[]; - $scope.slider_modal_options.scale = []; - //$scope.slider_options.modelLabels={2:'X'}; - //$scope.slider_options.dimension="arjun"; - var i; - for (i = 0; i < data.event.Frame.length; i++) { - if (data.event.Frame[i].Type == "Alarm") { - - // console.log ("**ALARM AT " + i); - $scope.slider_modal_options.scale.push({ - val: i + 1, - label: ' ' - }); - } else { - //$scope.slider_options.scale.push(' '); - } + prepareModalEvent(event.Event.Id); - } + $ionicModal.fromTemplateUrl('templates/events-modal.html', { + scope: $scope, + animation: 'slide-in-up' + }) + .then(function (modal) { + $scope.modal = modal; - }) - .error(function (err) { - ZMDataModel.zmLog("Error retrieving detailed frame API " + JSON.stringify(err)); - ZMDataModel.displayBanner('error', ['error retrieving event details', 'please try again']); - }); + $ionicLoading.show({ + template: "please wait...", + noBackdrop: true, + duration: 10000 + }); - $scope.totalEventTime = Math.round(parseFloat(edur)) - 1; - $scope.currentEventTime = 0; + $scope.modal.show(); - ZMDataModel.setAwake(ZMDataModel.getKeepAwake()); + var ld = ZMDataModel.getLogin(); - $ionicModal.fromTemplateUrl('templates/events-modal.html', { - scope: $scope, - animation: 'slide-in-up' - }) - .then(function (modal) { - $scope.modal = modal; + - $ionicLoading.show({ - template: "please wait...", - noBackdrop: true, - duration: 10000 }); - $scope.modal.show(); - - var ld = ZMDataModel.getLogin(); - - }); - } //-------------------------------------------------------- @@ -274,6 +161,14 @@ angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPla } }; + + $scope.toggleGapless = function() + { + console.log ("GAPLESS TOGGLE"); + $scope.loginData.gapless = !$scope.loginData.gapless; + ZMDataModel.setLogin($scope.loginData); + + }; //------------------------------------------------------------------------- @@ -293,32 +188,413 @@ angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPla // which in turn calls openModal //-------------------------------------------------------- - function showEvent(start, mid, edur, eframes, eid, ename, evideo) { - ZMDataModel.zmDebug("TimelineCtrl/showevent called with start:" + - start + " monitorId:" + mid + " dur:" + edur + " frames:" + eframes + - " eventId:" + eid + " eventName:" + ename + "video:"+evideo); - //console.log("Event STARTED WITH " + start); - var str = start; - 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'); - var relativepath = - mid + "/" + - yy + "/" + - mm + "/" + - dd + "/" + - hh + "/" + - min + "/" + - sec + "/"; - console.log("PATH IS " + relativepath); - - openModal(eid, ename, edur, eframes, "", relativepath, evideo); + function showEvent(event) { + + + openModal(event); } + + + // 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 (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.toggleGapless = function() + { + console.log ("GAPLESS TOGGLE"); + $scope.loginData.gapless = !$scope.loginData.gapless; + ZMDataModel.setLogin($scope.loginData); + + }; + + + //-------------------------------------------------------- + //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; + } + console.log ("JUMPING"); + jumpToEvent(eid,dirn); + + }; + + $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() + { + + + $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; + } + + } + + //-------------------------------------------------------- + // 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) { + + + + 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; + + + 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; + //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: i + 1, + 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']); + }); + + + } + //------------------------------------------------- // Make sure we delete the timeline @@ -375,6 +651,8 @@ angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPla //------------------------------------------------- // Controller main //------------------------------------------------- + + var currentEvent=""; // Make sure sliding for menu is disabled so it // does not interfere with graph panning @@ -394,6 +672,11 @@ angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPla $scope.$watch('mycarousel.index', function () { $scope.ionRange.index = ($scope.mycarousel.index + 1).toString(); + + if (currentEvent && $scope.ionRange.index == parseInt(currentEvent.Event.Frames)) + { + playbackFinished(); + } }); $scope.mycarousel = { @@ -695,7 +978,8 @@ angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPla mydur: myevents[i].Event.Length, myeid: myevents[i].Event.Id, myename: myevents[i].Event.Name, - myvideo: myevents[i].Event.DefaultVideo + myvideo: myevents[i].Event.DefaultVideo, + myevent:myevents[i] }); graphIndex++; @@ -733,7 +1017,7 @@ angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPla ZMDataModel.zmDebug("TimelineCtrl/drawGraph:You clicked on item " + properties.items); var item = graphData.get(properties.items); ZMDataModel.zmDebug("TimelineCtrl/drawGraph: clicked item details:" + JSON.stringify(item)); - showEvent(item[0].start, item[0].group, item[0].mydur, item[0].myframes, item[0].myeid, item[0].myename, item[0].myvideo); + showEvent(item[0].myevent); } else { |
