// 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', 'NVRDataModel', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$ionicPopup', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$ionicPlatform', 'zm', '$ionicPopover', '$controller', 'imageLoadingDataShare', '$window', '$localstorage', '$translate', 'SecuredPopups', 'EventServer', function ($scope, $rootScope, NVRDataModel, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $ionicPopup, $stateParams, $ionicHistory, $ionicScrollDelegate, $ionicPlatform, zm, $ionicPopover, $controller, imageLoadingDataShare, $window, $localstorage, $translate, SecuredPopups, EventServer) { //--------------------------------------------------------------------- // Controller main //--------------------------------------------------------------------- var intervalHandleMontage; // image re-load handler var intervalHandleAlarmStatus; // status of each alarm state var intervalHandleMontageCycle; var intervalHandleReloadPage; 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 streamState = { SNAPSHOT:1, ACTIVE:2, STOPPED:3 }; var currentStreamState = streamState.SNAPSHOT; // 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 () { // do nothing, we are reloading here anyway? /* if ($scope.singleMonitorModalOpen) { NVRDataModel.debug("Montage: Not creating streams, as modal is open"); return; } NVRDataModel.debug("Montage Re-auth handler"); //streamState = true; $timeout(function () { // after render if (simulStreaming) { NVRDataModel.debug("Re-creating all stream connkeys in montage ..."); NVRDataModel.regenConnKeys(); $scope.monitors = NVRDataModel.getMonitorsNow(); $scope.MontageMonitors = angular.copy($scope.monitors); $timeout(function () // after render { initPackery(); }, zm.packeryTimer); } }); broadcastHandles.push(as); //console.log (">>>>>>>>>>>>>>>>>>>>>>>>>>>AS="+as); */ }); //-------------------------------------------------------------------------------------- // 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 NVRDataModel.debug("Got network change:" + data); var ds; if (data == 'lowbw') { ds = $translate.instant('kLowBWDisplay'); } else { ds = $translate.instant('kHighBWDisplay'); } NVRDataModel.displayBanner('net', [ds]); var ld = NVRDataModel.getLogin(); refreshSec = (NVRDataModel.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), NVRDataModel.getLogin().cycleMontageInterval * 1000); intervalHandleReloadPage = $interval(function () { forceReloadPage(); }.bind(this), reloadPage); if (NVRDataModel.getBandwidth() == 'lowbw') { NVRDataModel.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 NVRDataModel.debug("Modal is open, closing it"); NVRDataModel.setAwake(false); cleanupOnCloseModal(); } else { NVRDataModel.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 forceReloadPage() { if ($scope.isDragabillyOn) { NVRDataModel.debug("not reloading, edit in progress"); return; } var ld = NVRDataModel.getLogin(); ld.reloadInMontage = true; NVRDataModel.log("Reloading view to keep memory in check..."); NVRDataModel.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' }); /* $state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: true });*/ }); /*$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; $scope.areImagesLoading = true; var progressCalled = false; if (draggies) { draggies.forEach(function (drag) { drag.destroy(); }); } draggies = []; var layouttype = true; var ld = NVRDataModel.getLogin(); var positionsStr = ld.packeryPositions; var positions = {}; if (positionsStr == '' || positionsStr == undefined) { NVRDataModel.log("Did NOT find a packery layout"); layouttype = true; } else { //console.log ("POSITION STR IS " + positionsStr); positions = JSON.parse(positionsStr); NVRDataModel.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++; }); NVRDataModel.log("Monitors that are active and not DOM hidden: " + cnt + " while grid has " + positions.length); if (cnt > NVRDataModel.getLogin().maxMontage) { cnt = NVRDataModel.getLogin().maxMontage; NVRDataModel.log("restricting monitor count to " + cnt + " due to max-montage setting"); } if (cnt != positions.length) { NVRDataModel.log("Whoops!! Monitors have changed. I'm resetting layouts, sorry!"); layouttype = true; positions = {}; } var elem = angular.element(document.getElementById("mygrid")); //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 }); imagesLoaded(elem).on('progress', function (instance, img) { var result = img.isLoaded ? 'loaded' : 'broken'; // NVRDataModel.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(); }, 100); progressCalled = true; // if (layouttype) $timeout (function(){layout(pckry);},100); }); imagesLoaded(elem).on('always', function () { //console.log ("******** ALL IMAGES LOADED"); // $scope.$digest(); NVRDataModel.debug("All images loaded, switching to snapshot..."); $scope.areImagesLoading = false; currentStreamState = streamState.SNAPSHOT; if (simulStreaming) { $timeout (function() { NVRDataModel.debug ("Switching mode to active..."); currentStreamState = streamState.ACTIVE; },100); } $ionicLoading.hide(); if (!progressCalled) { NVRDataModel.log("*** PROGRESS WAS NOT CALLED"); // pckry.reloadItems(); } $timeout(function () { 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)) { NVRDataModel.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; $scope.MontageMonitors[i].Monitor.gridScale = positions[j].size; $scope.MontageMonitors[i].Monitor.listDisplay = positions[j].display; // NVRDataModel.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); } } NVRDataModel.debug("All images loaded, doing image layout"); } $timeout(function () { //NVRDataModel.log("Force calling resize"); ///pckry.reloadItems(); ///positions is defined only if layouttype was false console.log(">>> Positions is " + JSON.stringify(positions)); if (!layouttype && positions) pckry.initShiftLayout(positions, "data-item-id"); // now do a jiggle $timeout(function () { NVRDataModel.debug("doing the jiggle and dance..."); pckry.resize(true); }, 300); }, 100); //pckry.onresize(); }, 20); }); function itemDragged(item) { NVRDataModel.debug("drag complete"); $timeout(function () { pckry.shiftLayout(); }, 20); pckry.once('layoutComplete', function () { var positions = pckry.getShiftPositions('data-item-id'); //console.log ("POSITIONS MAP " + JSON.stringify(positions)); var ld = NVRDataModel.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'); NVRDataModel.setLogin(ld); NVRDataModel.debug("saved new positions"); }); //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