"use strict"; /* eslint-disable indent */ // // Example Vue App // // Created by Milad Nazeri on 2018-10-11 // Modified from AppUi.js by Howard Stearns on 2 Nov 2016 // Copyright 2016 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // /* globals Tablet, Script, HMD, Controller, AccountServices, Menu */ (function () { // BEGIN LOCAL_SCOPE // Dependencies // ///////////////////////////////////////////////////////////////////////// var AppUi = Script.require('./appUi.js?v123'); var UNLOAD_DATE = new Date("November 24, 2018 17:05:00"); var VOTE_APP_NAME = "voteApp.js"; // need UTC TIME FOR FINAL // Consts // ///////////////////////////////////////////////////////////////////////// var URL = Script.resolvePath("./html/Tablet.html"), BUTTON_NAME = "VOTEAPP", EVENT_BRIDGE_OPEN_MESSAGE = "eventBridgeOpen"; var GOOGLE_SCRIPTS_URL = "https://script.google.com/macros/s/AKfycbyCnTK2w8gAuPmNzLUnAE4dMJNRtUarjlHFrjKPFBRRQsiy5Q/exec"; var EVENT_NAME = "robin palooza"; var DOMAIN = "domain"; var AVATAR = "avatar"; var setupNotLoggedIn = false; // DATA MANAGEMENT var domainsInfo = {}; // will use Object.keys to get array var avatarsInfo = {}; // array for now var firstLoad = true; var VOTE_APP_SETTINGS_NAME = "robinTest"; // types var VOTE_AVATARS_GOOGLE = "voteAvatars"; var VOTE_DOMAINS_GOOGLE = "voteDomains"; var GET_INFO_GOOGLE = "getInfo"; // JSON.stringify(Settings.setValue("robinTest", [])); // JSON.stringify(Settings.getValue("robinTest")); // Init // ///////////////////////////////////////////////////////////////////////// var ui; var dataStore = { isLoggedIn: true, voted: { domain: false, avatar: false }, openPolls: { avatar: false, domain: false }, visitedAllDomains: false, domains: [], avatars: [] }; // Constructors // ///////////////////////////////////////////////////////////////////////// // Collections // ///////////////////////////////////////////////////////////////////////// // GOOGLE SHEET FUNCTIONS function getGoogleData() { // REQUEST list of domains var params = encodeURLParams({ type: GET_INFO_GOOGLE }); var onComplete = function (request) { print("recieved google info"); // print ("GOOGLE INFO IS :", JSON.stringify(request)); try { var gInfo = JSON.parse(request.responseText); } catch (e) { console.error("Error parsing request in sendDomainInfoRequest"); } print ("GOOGLE INFO IS :", JSON.stringify(gInfo)); compareGoogleData(gInfo); }; var onError = function () { print("Error in VoteApp.js: Issue in getGoogleData()"); }; sendRequest(GOOGLE_SCRIPTS_URL, params, onComplete, onError); } function hasUserVoted(type) { var voted = false; var entryArray = type === DOMAIN ? dataStore.domains : dataStore.avatars; entryArray.forEach(function (entry) { if (entry.voted === true) { // voted for this entry voted = true; } }); return voted; } function sendAvatarVote(name) { avatarsInfo[name.toLowerCase()].voted = true; dataStore.voted.avatar = true; ui.updateUI(dataStore); var params = encodeURLParams({ type: VOTE_AVATARS_GOOGLE, date: Date.now(), uuid: MyAvatar.sessionUUID, username: AccountServices.username, avatar: name, event: EVENT_NAME }); var onComplete = function (request) { // TODO *** voted // var avatarName = name.toLowerCase(); // avatarsInfo[avatarName].voted = true; // dataStore.voted.avatar = true; // ui.updateUI(dataStore); }; var onError = function () { print("Error in VoteApp.js: Issue in sendAvatarVote()"); avatarsInfo[name.toLowerCase()].voted = false; dataStore.voted.avatar = false; ui.updateUI(dataStore); }; sendRequest(GOOGLE_SCRIPTS_URL, params, onComplete, onError); } function sendDomainVote(name) { domainsInfo[name.toLowerCase()].voted = true; dataStore.voted.domain = true; ui.updateUI(dataStore); var params = encodeURLParams({ type: VOTE_DOMAINS_GOOGLE, date: Date.now(), uuid: MyAvatar.sessionUUID, username: AccountServices.username, domain: name, event: EVENT_NAME }); var onComplete = function (request) { // TODO *** voted // if not vote or request failed // var domainName = name.toLowerCase(); // domainsInfo[domainName].voted = true; // dataStore.voted.domain = true; // ui.updateUI(dataStore); }; var onError = function () { print("Error in VoteApp.js: Issue in sendDomainVote()"); domainsInfo[name.toLowerCase()].voted = false; dataStore.voted.domain = false; ui.updateUI(dataStore); }; sendRequest(GOOGLE_SCRIPTS_URL, params, onComplete, onError); } // Helper Functions // ///////////////////////////////////////////////////////////////////////// function onHostChanged(host) { print("Host changed to: " + host); print("location is visitable: ", host, isLocationVisitable(host)); var domainName = host.toLowerCase(); if (domainsInfo[domainName]) { domainsInfo[domainName].visited = true; // set value in settings to save it var clientVisitedList = Settings.getValue(VOTE_APP_SETTINGS_NAME); if (!clientVisitedList) { clientVisitedList = []; } clientVisitedList.push(domainName); Settings.setValue(VOTE_APP_SETTINGS_NAME, clientVisitedList); dataStore.visitedAllDomains = checkVisitedAllDomains(clientVisitedList); ui.updateUI(dataStore); } } function compareGoogleData(gData) { // { // openPolls: { // avatar: true, // domain: true // }, // domains: [ "TheSpot", "Studio" ], // avatars: [ // { name: "Robin", image: "hello" } // ] // }; print("CHANGED GOOGLE DATA"); var changedPolls = setPollsOpen(gData.openPolls); var changedDomains = setDomains(gData.domains); var changedAvatars = setAvatars(gData.avatars); var clientVisitedList = Settings.getValue(VOTE_APP_SETTINGS_NAME, []); dataStore.visitedAllDomains = checkVisitedAllDomains(clientVisitedList); var needsUpdateUI = changedPolls && changedAvatars && changedDomains; if (firstLoad) { firstLoad = false; } if (needsUpdateUI) { ui.updateUI(dataStore); } } function setPollsOpen(gPolls) { // { // avatar: true, // domain: true // }, print("polls are ", gPolls.avatar, gPolls.domain); var changed = false; if (dataStore.openPolls.avatar !== gPolls.avatar || dataStore.openPolls.domain !== gPolls.domain) { changed = true; dataStore.openPolls.avatar = gPolls.avatar; dataStore.openPolls.domain = gPolls.domain; } return changed; } function setDomains(gDomains) { // [ "TheSpot", "Studio" ], // add domains to the location array print("voting 3"); var changed = false; var existingDomains = Object.keys(domainsInfo); print("EXISTING ", JSON.stringify(existingDomains)); print("NEW GOOGLE ", JSON.stringify(gDomains)); gDomains.forEach(function (domainName) { var lowercase = domainName.toLowerCase(); var existingIndex = existingDomains.indexOf(lowercase); if (existingIndex !== -1) { existingDomains.splice(existingIndex, 1); print("INDEX EXISTING ", JSON.stringify(existingDomains), JSON.stringify(existingIndex)); } if (firstLoad || !domainsInfo[lowercase]) { // need to get all domain info because of first load // or new domain encountered changed = true; domainsInfo[lowercase] = { name: domainName, image: "", visited: false, index: -1, voted: false }; sendDomainInfoRequest(lowercase); } }); print(" EXISTING LENGTH", JSON.stringify(existingDomains.length)); if (existingDomains.length > 0) { print("INSIDE DELETE 1"); // found domains to delete removeItems (existingDomains, DOMAIN); } Script.setTimeout(function () { setDataStoreDomainsInfo(); ui.updateUI(dataStore); }, 500); return changed; } function sendDomainInfoRequest(domainName) { // domainName is lowercase print("voting 4"); var url = "https://metaverse.highfidelity.com/api/v1/places/" + domainName; var paramString = ""; var onComplete = function (request) { print("voting 5"); try { var response = JSON.parse(request.responseText); } catch (e) { console.error("Error parsing request in sendDomainInfoRequest"); } var image = response.data.place.previews ? response.data.place.previews.thumbnail : "http://img.youtube.com/vi/kEJDqO7WrKY/hqdefault.jpg"; // url to image domainsInfo[domainName].image = image; ui.updateUI(dataStore); print(JSON.stringify(image)); }; var onError = function () { print("Error in VoteApp.js: Issue in sendDomainInfoRequest()"); }; sendRequest(url, paramString, onComplete, onError); } function setDataStoreDomainsInfo() { print("voting 6"); var domains = []; var domainKeys = Object.keys(domainsInfo); domainKeys.forEach(function (domainKey, index) { domainsInfo[domainKey].index = index; domainsInfo[domainKey].visited = hasUserVisitedDomain(domainKey); domains.push(domainsInfo[domainKey]); }); dataStore.domains = domains; } function hasUserVisitedDomain(domainName) { print("voting 7"); // domainName is lowercase var visitedDomainList = Settings.getValue(VOTE_APP_SETTINGS_NAME, []); var visited = visitedDomainList.indexOf(domainName) !== -1; return visited; } function setAvatars(gAvatars) { // { name: "Robin", image: "hello" } // update avatar images if necessary var changed = false; var existingAvatars = Object.keys(avatarsInfo); gAvatars.forEach(function (avatar, index) { print("Avatar ", index, JSON.stringify(avatar)); var lowercase = avatar.name.toLowerCase(); var existingIndex = existingAvatars.indexOf(lowercase); if (existingIndex !== -1) { existingAvatars.splice(existingIndex, 1); } if (firstLoad || !avatarsInfo[lowercase]) { // need to get all domain info because of first load // or new domain encountered changed = true; avatarsInfo[lowercase] = { name: avatar.name, image: avatar.image, index: dataStore.avatars.length - 1, // not using this yet voted: false }; dataStore.avatars.push(avatarsInfo[lowercase]); } else if (avatarsInfo[lowercase].image !== avatar.image) { // image changed, update to new image avatarsInfo[lowercase].image = avatar.image; } }); if (existingAvatars.length > 0) { // found avatars to delete removeItems(existingAvatars, AVATAR); } Script.setTimeout(function () { ui.updateUI(dataStore); }, 500); return changed; } function removeItems(listToDelete, type) { print("REMOVE ITEM", type, JSON.stringify(listToDelete)); var list = type === DOMAIN ? dataStore.domains : dataStore.avatars; var infoStore = type === DOMAIN ? domainsInfo : avatarsInfo; print("INSIDE DELETE 2", JSON.stringify(list)); listToDelete.forEach(function (nameToDelete) { // for every avatar to delete var deleteIndex = -1; for (var i = 0; i < list.length; i++) { // search var current = list[i]; var lowercase = current.name.toLowerCase(); print("COMPARE ", nameToDelete, lowercase); if (nameToDelete === lowercase) { // found deleteIndex = i; print("INSIDE DELETE 3", JSON.stringify(deleteIndex)); break; } } if (deleteIndex !== -1) { print("INSIDE DELETE 4", JSON.stringify(deleteIndex)); // remove from dataStore list and the avatar object itself list.splice(deleteIndex, 1); delete infoStore[nameToDelete]; } }); ui.updateUI(dataStore); } function checkVisitedAllDomains(clientVisitedList) { print("voting 8"); print("Domain info: ", JSON.stringify(domainsInfo)); print("ClientVisitedList info: ", JSON.stringify(clientVisitedList)); var visitedAllDomains = Object.keys(domainsInfo).reduce(function (visitedAll, domainName) { var wasVisited = clientVisitedList.indexOf(domainName) !== -1; return visitedAll && wasVisited; }, true); return visitedAllDomains; } function isLocationVisitable(host) { var domainName = host.toLowerCase(); var isCurrentLocationVisitable = Object.keys(domainsInfo).indexOf(domainName) !== -1; // currentLocation is on list return isCurrentLocationVisitable; } function encodeURLParams(params) { var paramPairs = []; for (var key in params) { paramPairs.push(key + "=" + params[key]); } return paramPairs.join("&"); } function sendRequest(url, paramString, onComplete, onError) { print("voting _1"); var request = new XMLHttpRequest(); var requestURL = paramString ? url + "?" + paramString : url; request.open('GET', requestURL); request.timeout = 10000; request.ontimeout = onError; request.onreadystatechange = function () { // called after load when readyState = 4 if (request.readyState === 4) { if (onComplete) { onComplete(request); } } }; request.send(); } // Tablet // ///////////////////////////////////////////////////////////////////////// function startup() { ui = new AppUi({ buttonName: BUTTON_NAME, home: URL, onMessage: onMessage, graphicsDirectory: Script.resolvePath("./icons/"), onOpened: onOpened }); location.hostChanged.connect(onHostChanged); checkDateToUnload(); // onOpened(); } function onOpened() { checkDateToUnload(); var isLoggedIn = AccountServices.loggedIn; if (isLoggedIn) { if (firstLoad) { dataStore.isLoggedIn = true; } getGoogleData(); // asynchronous and will call compareGoogleData(gData) once complete } else { // is not logged in handleNotLoggedInStatus(); } } function handleNotLoggedInStatus() { if (!setupNotLoggedIn) { dataStore.isLoggedIn = false; AccountServices.loggedInChanged.connect(loggedIn); setupNotLoggedIn = true; } function loggedIn() { AccountServices.loggedInChanged.disconnect(loggedIn); setupNotLoggedIn = false; dataStore.isLoggedIn = true; } } function unload() { print("WATCH OUT!"); location.hostChanged.disconnect(onHostChanged); } function checkDateToUnload() { print("CHECK DATE"); var now = new Date(); if (now > UNLOAD_DATE) { var scriptList = ScriptDiscoveryService.getRunning(); var url; scriptList.forEach(function (scriptInfo) { if (scriptInfo.name === VOTE_APP_NAME ) { url = scriptInfo.url; } }); print("UNLOAD DATE"); ScriptDiscoveryService.stopScript(url); } } // *** web event actions var GOTO = "goto", VOTE_AVATAR = "vote_avatar", VOTE_DOMAIN = "vote_domain"; function onMessage(data) { // EventBridge message from HTML script. switch (data.type) { case EVENT_BRIDGE_OPEN_MESSAGE: ui.updateUI(dataStore); break; case GOTO: Window.location = "hifi://" + data.value; break; case VOTE_AVATAR: if (hasUserVoted(AVATAR) === false) { sendAvatarVote(data.value); } break; case VOTE_DOMAIN: if (hasUserVoted(DOMAIN) === false) { sendDomainVote(data.value); } break; default: } } // Main // ///////////////////////////////////////////////////////////////////////// startup(); Script.scriptEnding.connect(unload); }()); // END LOCAL_SCOPE