// Controller for the montage view /* jshint -W041 */ /* jslint browser: true*/ /* global cordova,StatusBar,angular,console,ionic,Packery, Draggabilly, imagesLoaded, ConnectSDK, moment */ angular.module('zmApp.controllers') .controller('zmApp.MontageCtrl', ['$scope', '$rootScope', 'NVR', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$ionicPopup', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$ionicPlatform', 'zm', '$ionicPopover', '$controller', 'imageLoadingDataShare', '$window', '$localstorage', '$translate', 'SecuredPopups', 'EventServer', function ($scope, $rootScope, NVR, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $ionicPopup, $stateParams, $ionicHistory, $ionicScrollDelegate, $ionicPlatform, zm, $ionicPopover, $controller, imageLoadingDataShare, $window, $localstorage, $translate, SecuredPopups, EventServer) { //--------------------------------------------------------------------- // Controller main //--------------------------------------------------------------------- var timeInMontage = new Date(); var intervalHandleMontage; // image re-load handler var intervalHandleAlarmStatus; // status of each alarm state var intervalHandleMontageCycle; var intervalHandleReloadPage; var intervalHandleEventStatus; var gridcontainer; var pckry, draggie; var draggies; var loginData; var timestamp; var sizeInProgress; var modalIntervalHandle; var ld; var refreshSec; var reloadPage = zm.forceMontageReloadDelay; var viewCleaned = false; var randToAvoidCacheMem; var beforeReorderPositions=[]; var streamState = { SNAPSHOT: 1, SNAPSHOT_LOWQUALITY:2, ACTIVE: 3, STOPPED: 4, PAUSED: 5 }; var currentStreamState = streamState.SNAPSHOT_LOWQUALITY; // first load snapshot $scope.isModalStreamPaused = false; // used in Monitor Modal //var reloadPage = 30; var simulStreaming = false; // will be true if you multiport var broadcastHandles = []; var as = $scope.$on("auth-success", function () { NVR.debug ("Auth success, recomputing rand value..."); randEachTime(); }); //-------------------------------------------------------------------------------------- // Handles bandwidth change, if required // //-------------------------------------------------------------------------------------- var bc = $scope.$on("bandwidth-change", function (e, data) { // not called for offline, I'm only interested in BW switches NVR.debug("Got network change:" + data); var ds; if (data == 'lowbw') { ds = $translate.instant('kLowBWDisplay'); } else { ds = $translate.instant('kHighBWDisplay'); } NVR.displayBanner('net', [ds]); var ld = NVR.getLogin(); refreshSec = (NVR.getBandwidth() == 'lowbw') ? ld.refreshSecLowBW : ld.refreshSec; $interval.cancel(intervalHandleMontage); $interval.cancel(intervalHandleMontageCycle); $interval.cancel(intervalHandleReloadPage); intervalHandleMontage = $interval(function () { loadNotifications(); }.bind(this), refreshSec * 1000); intervalHandleMontageCycle = $interval(function () { cycleMontageProfiles(); }.bind(this), NVR.getLogin().cycleMontageInterval * 1000); intervalHandleReloadPage = $interval(function () { forceReloadPage(); }.bind(this), reloadPage); if (NVR.getBandwidth() == 'lowbw') { NVR.debug("Enabling low bandwidth parameters"); $scope.LoginData.montageQuality = zm.montageQualityLowBW; $scope.LoginData.singleImageQuality = zm.eventSingleImageQualityLowBW; $scope.LoginData.montageHistoryQuality = zm.montageQualityLowBW; } }); broadcastHandles.push(bc); // -------------------------------------------------------- // Handling of back button in case modal is open should // close the modal // -------------------------------------------------------- $ionicPlatform.registerBackButtonAction(function (e) { e.preventDefault(); if ($scope.modal != undefined && $scope.modal.isShown()) { // switch off awake, as liveview is finished NVR.debug("Modal is open, closing it"); NVR.setAwake(false); cleanupOnCloseModal(); } else { NVR.debug("Modal is closed, so toggling or exiting"); if (!$ionicSideMenuDelegate.isOpenLeft()) { $ionicSideMenuDelegate.toggleLeft(); } else { navigator.app.exitApp(); } } }, 1000); /*$scope.toggleHide = function(mon) { if (mon.Monitor.listDisplay == 'noshow') mon.Monitor.listDisplay = 'show'; else mon.Monitor.listDisplay = 'noshow'; };*/ function jiggleMontage() { if ($scope.reOrderActive) return; NVR.debug ('window resized'); //initPackery(); } function forceReloadPage() { //return; if ($scope.isDragabillyOn) { NVR.debug("not reloading, edit in progress"); return; } var ld = NVR.getLogin(); ld.reloadInMontage = true; NVR.log("Reloading view to keep memory in check..."); NVR.setLogin(ld) .then(function () { //window.location.reload(true); //location.reload(); //$ionicHistory.clearCache(); //$state.go('app.montage'); /*$ionicHistory.clearCache([$state.current.name]).then(function() { $state.go('app.montage', $stateParams, {reload:true, inherit:false}); });*/ $ionicHistory.nextViewOptions({ disableAnimate: true, disableBack: true }); $state.go('app.refresh', { "view": 'app.montage' }); }); /*$ionicHistory.nextViewOptions( { disableAnimate: true, disableBack: true }); $state.go("app.montage", { minimal: $scope.minimal, isRefresh: true });*/ } // called by afterEnter to load Packery function initPackery() { /* $ionicLoading.show( { template: $translate.instant('kArrangingImages'), noBackdrop: true, duration: zm.loadingTimeout });*/ currentStreamState = streamState.SNAPSHOT_LOWQUALITY; $scope.areImagesLoading = true; var progressCalled = false; if (draggies) { draggies.forEach(function (drag) { drag.destroy(); }); } draggies = []; var layouttype = true; var ld = NVR.getLogin(); var positionsStr = ld.packeryPositions; var positions = {}; if (positionsStr == '' || positionsStr == undefined) { NVR.log("Did NOT find a packery layout"); layouttype = true; } else { //console.log ("POSITION STR IS " + positionsStr); try { positions = JSON.parse(positionsStr); } catch (e) { NVR.debug ("error parsing profile"); } NVR.log("found a packery layout"); layouttype = false; } var cnt = 0; $scope.MontageMonitors.forEach(function (elem) { if ((elem.Monitor.Enabled != '0') && (elem.Monitor.Function != 'None')) cnt++; }); NVR.log("Monitors that are active and not DOM hidden: " + cnt + " while grid has " + positions.length); if (cnt > NVR.getLogin().maxMontage) { cnt = NVR.getLogin().maxMontage; NVR.log("restricting monitor count to " + cnt + " due to max-montage setting"); } if (cnt != positions.length) { NVR.log("Whoops!! Monitors have changed. I'm resetting layouts, sorry!"); layouttype = true; positions = {}; } var elem = angular.element(document.getElementById("mygrid")); var loadCount = 0; //console.log ("**** mygrid is " + JSON.stringify(elem)); if (pckry) pckry.destroy(); pckry = new Packery('.grid', { itemSelector: '.grid-item', percentPosition: true, //columnWidth: '.grid-sizer', gutter: 0, initLayout: layouttype, shiftPercentResize: true, transitionDuration: 0 }); imagesLoaded(elem).on('progress', function (instance, img) { var result = img.isLoaded ? 'loaded' : 'broken'; // NVR.debug('~~loaded image is ' + result + ' for ' + img.img.src); // lay out every image if a pre-arranged position has not been found $timeout(function () { if (layouttype) { pckry.layout(); } else { pckry.shiftLayout(); } }, 100); progressCalled = true; loadCount++; // console.log ("loaded "+loadCount+" of "+positions.length); // if (layouttype) $timeout (function(){layout(pckry);},100); }); $timeout(function () { if ($scope.areImagesLoading) { NVR.debug("Images still loading after 15secs?"); allImagesLoadedOrFailed(); } }, 15000); imagesLoaded(elem).on('always', function () { //console.log ("******** ALL IMAGES LOADED"); // $scope.$digest(); NVR.debug("All images loaded, switching to snapshot..."); allImagesLoadedOrFailed(); }); imagesLoaded(elem).on('fail', function () { NVR.debug("All images loaded, but some broke, switching to snapshot..."); //console.log ("******** ALL IMAGES LOADED"); // $scope.$digest(); $timeout (function () { allImagesLoadedOrFailed(); },100); }); function allImagesLoadedOrFailed() { $scope.areImagesLoading = false; currentStreamState = streamState.SNAPSHOT; if (simulStreaming) { $timeout (function () { NVR.debug("Switching mode to streaming as multi-port on..."); //NVR.regenConnKeys(); //randEachTime(); currentStreamState = streamState.ACTIVE; },300); } $ionicLoading.hide(); pckry.getItemElements().forEach(function (itemElem) { draggie = new Draggabilly(itemElem); pckry.bindDraggabillyEvents(draggie); draggies.push(draggie); draggie.disable(); draggie.unbindHandles(); }); pckry.on('dragItemPositioned', itemDragged); if (!isEmpty(positions)) { NVR.log("Arranging as per packery grid"); for (var i = 0; i < $scope.MontageMonitors.length; i++) { for (var j = 0; j < positions.length; j++) { if ($scope.MontageMonitors[i].Monitor.Id == positions[j].attr) { if (isNaN(positions[j].size)) positions[j].size = 20; if (positions[j].size == 0) positions[j].size = 20; $scope.MontageMonitors[i].Monitor.gridScale = positions[j].size; $scope.MontageMonitors[i].Monitor.listDisplay = positions[j].display; // NVR.debug("Setting monitor ID: " + $scope.MontageMonitors[i].Monitor.Id + " to size: " + positions[j].size + " and display:" + positions[j].display); } //console.log ("Index:"+positions[j].attr+ " with size: " + positions[j].size); } } NVR.debug("All images loaded, doing image layout"); $timeout(function () { //NVR.log("Force calling resize"); ///pckry.reloadItems(); ///positions is defined only if layouttype was false //(">>> Positions is " + JSON.stringify(positions)); if (!layouttype && positions) pckry.initShiftLayout(positions, "data-item-id"); // now do a jiggle $timeout(function () { NVR.debug("inside drag items:doing the jiggle and dance..."); pckry.shiftLayout(); //$scope.squeezeMonitors(); }, 500); }, 100); } //pckry.onresize(); } function itemDragged(item) { NVR.debug("drag complete"); /* $timeout(function () { pckry.shiftLayout(); }, 20);*/ $timeout (function () { var positions = pckry.getShiftPositions('data-item-id'); //console.log ("POSITIONS MAP " + JSON.stringify(positions)); var ld = NVR.getLogin(); ld.packeryPositions = JSON.stringify(positions); // console.log ("Saving " + ld.packeryPositions); // console.log ("FULL OBJECT "+ JSON.stringify(ld)); ld.currentMontageProfile = ""; $scope.currentProfileName = $translate.instant('kMontage'); NVR.setLogin(ld); NVR.debug("saved new positions: " + ld.packeryPositions); //pckry.reloadItems(); },300); //pckry.getItemElements().forEach(function (itemElem) { //console.log (itemElem.attributes['data-item-id'].value+" size "+itemElem.attributes['data-item-size'].value ); // }); } } function isEmpty(obj) { for (var prop in obj) { return false; } return true; } //----------------------------------------------------------------------- // color for monitor state in montage //----------------------------------------------------------------------- $scope.stateColor = function () { //console.log ("***MONSTATUS**"+$scope.monStatus+"**"); var attr = ""; switch ($scope.monStatus) { case "": attr = "color:rgba(0, 0, 0, 0)"; break; case "idle": attr = "color:rgba(0, 0, 0, 0)"; break; case "pre-alarm": attr = "color:#e67e22"; break; case "alarmed": attr = "color:#D91E18"; break; case "alert": attr = "color:#e67e22"; break; case "record": attr = "color:#26A65B"; break; } return attr; }; function findNext(key, obj) { // console.log (" key is: "+ key); // console.log ("array is " + JSON.stringify (obj)); var keys = Object.keys(obj); var len = keys.length; var curindex = keys.indexOf(key); var modulus = (curindex + 1) % len; //console.log ("*********** len="+len+" curr="+curindex+" next="+modulus); //console.log ("Keys array "+ JSON.stringify(keys)); //console.log ("Current index: "+ keys.indexOf(key) ); //console.log ("returning index of " + (keys.indexOf(key) + 1) % (keys.length)); // console.log ("keys length is "+ keys.length); return keys[modulus]; /* var size = Object.keys(obj).length; var i; for (i=0; i