import * as authManager from "./authmanager"; import * as commandManager from "./commandmanager"; import { debugSettings } from "./debugsettings"; import { _ } from "./languagemanager"; import * as metadataManager from "./metadatamanager"; import { HomePage, InfoPageBlock, LobbyPageBlock, SeatPage, TablesPage, } from "./pages"; import { AccountStatusPopup, AddMoneyPopup, AuthPopup, ChangePasswordPopup, ChatPopup, CustomPopup, HandHistoryPopup, JoinTablePopup, MorePopup, OkCancelPopup, RulesPopup, SettingsPopup, SlowConnectionPopup, TableMenuPopup, } from "./popups"; import { SimplePopup } from "./popups/simplepopup"; import { connectionService, deviceEvents, imagePreloadService, keyboardActivationService, orientationService, pushService, reloadManager, slowInternetService, soundManager, websiteService, } from "./services"; import * as broadcastService from "./services/broadcastservice"; import { uiManager, UIManager } from "./services/uimanager"; import { settings } from "./settings"; import { TabBar } from "./tabbar"; import * as runtimeSettings from "./table/runtimesettings"; import { tableManager } from "./table/tablemanager"; import * as timeService from "./timeservice"; type PromiseOrVoid = void | Promise; export class App { public static addTabBarItemMapping(tabBarItem: string, pageName: string) { UIManager.addTabBarItemMapping(tabBarItem, pageName); } public currentPopup: string = null; public homePage: HomePage; public lobbyPageBlock: LobbyPageBlock; public tablesPage: TablesPage; public seatsPage: SeatPage; public infoPageBlock: InfoPageBlock; public authPopup: AuthPopup; public changePasswordPopup: ChangePasswordPopup; public simplePopup: SimplePopup; public okcancelPopup: OkCancelPopup; public customPopup: CustomPopup; public joinTablePopup: JoinTablePopup; public tableMenuPopup: TableMenuPopup; public addMoneyPopup: AddMoneyPopup; public slowConnectionPopup: SlowConnectionPopup; public tableChatPopup: ChatPopup; public handHistoryPopup: HandHistoryPopup; public accountStatusPopup: AccountStatusPopup; public settingsPopup: SettingsPopup; public rulesPopup: RulesPopup; public morePopup: MorePopup; public tabBar: TabBar; public mainSelector: Selector; public spinner: any; public progressSpinner: any; public processing: KnockoutObservable; public popupClosed: Signal; public loadPromises: JQueryPromise[]; public fullyInitialized: boolean; public disconnected: boolean; public suppressResume: boolean; private stopped = false; private savedPopup: string = null; constructor() { const self = this; this.loadPromises = []; // register pages. this.homePage = new HomePage(); this.infoPageBlock = new InfoPageBlock(); this.lobbyPageBlock = new LobbyPageBlock(); this.tablesPage = new TablesPage(); this.seatsPage = new SeatPage(); this.authPopup = new AuthPopup(); this.changePasswordPopup = new ChangePasswordPopup(); this.simplePopup = new SimplePopup(); this.okcancelPopup = new OkCancelPopup(); this.customPopup = new CustomPopup(); this.joinTablePopup = new JoinTablePopup(); this.settingsPopup = new SettingsPopup(); this.rulesPopup = new RulesPopup(); this.tableMenuPopup = new TableMenuPopup(); this.addMoneyPopup = new AddMoneyPopup(); this.slowConnectionPopup = new SlowConnectionPopup(); this.tableChatPopup = new ChatPopup(); this.handHistoryPopup = new HandHistoryPopup(); this.accountStatusPopup = new AccountStatusPopup(); this.morePopup = new MorePopup(); this.processing = ko.observable(false); this.bindSubPage("home", self.homePage); this.bindSubPage("tables", self.tablesPage); this.bindSubPage("seats", self.seatsPage); this.bindPopup("auth", self.authPopup); this.bindPopup("changePassword", self.changePasswordPopup); this.bindPopup("simple", self.simplePopup); this.bindPopup("okcancel", self.okcancelPopup); this.bindPopup("custom", self.customPopup); this.bindPopup("joinTable", self.joinTablePopup); this.bindPopup("settings", self.settingsPopup); this.bindPopup("rules", self.rulesPopup); this.bindPopup("tableMenu", self.tableMenuPopup); this.bindPopup("addMoney", self.addMoneyPopup); this.bindPopup("slowConnection", self.slowConnectionPopup); this.bindPopup("tableChat", self.tableChatPopup); this.bindPopup("handHistory", self.handHistoryPopup); this.bindPopup("accountStatus", self.accountStatusPopup); this.bindPageBlock("lobby", this.lobbyPageBlock); this.bindPageBlock("info", this.infoPageBlock); this.bindUIElement(".more-block", this.morePopup); this.mainSelector = new Selector(); if (typeof window !== "undefined") { const mainSelectorElement = $(".page.main .sub-page.selector")[0]; if (mainSelectorElement) { ko.applyBindings(this.mainSelector, mainSelectorElement); } } this.initializeTabbar(); this.initializeConnection(); // var progressBackgroundElement = $(".progress-background")[0]; // ko.applyBindings(this, progressBackgroundElement); if (typeof window !== "undefined") { this.processing.subscribe(function(newValue) { if (newValue) { $(".progress-background").show(); } else { $(".progress-background").hide(); } }); } // show startup page uiManager.showPage("initialization"); if (typeof window !== "undefined") { const opts = { lines: 13, // The number of lines to draw length: 4, // The length of each line width: 2, // The line thickness radius: 6, // The radius of the inner circle corners: 1, // Corner roundness (0..1) rotate: 0, // The rotation offset direction: 1, // 1: clockwise, -1: counterclockwise color: "#fff", // #rgb or #rrggbb or array of colors speed: 1, // Rounds per second trail: 60, // Afterglow percentage shadow: false, // Whether to render a shadow hwaccel: false, // Whether to use hardware acceleration className: "spinner", // The CSS class to assign to the spinner zIndex: 2e9, // The z-index (defaults to 2000000000) top: "auto", // Top position relative to parent in px left: "auto", // Left position relative to parent in px }; this.spinner = new Spinner(opts); const target = document.getElementById("spinner"); this.spinner.spin(target); const progressTarget = document.getElementById("progress-spinner"); this.progressSpinner = new Spinner(opts).spin(progressTarget); } this.popupClosed = new signals.Signal(); } // Bind Event Listeners // // Bind any events that are required on startup. Common events are: // "load", "deviceready", "offline", and "online". public bindEvents() { document.addEventListener("deviceready", this.onDeviceReady, false); if (debugSettings.ios.hasMultitasking) { document.addEventListener("resign", this.onResign, false); document.addEventListener("active", this.onActive, false); } document.addEventListener("pause", this.onPause, false); document.addEventListener("resume", this.onResume, false); deviceEvents.initialize(); } // deviceready Event Handler // // The scope of 'this' is the event. In order to call the 'receivedEvent' // function, we must explicity call 'app.receivedEvent(...);' public onDeviceReady() { const device: Device = window.device; if (device != null && device.available) { if (device.platform.toLowerCase() === "ios") { if (device.version.toString().indexOf("7.0") === 0) { StatusBar.overlaysWebView(false); /* tslint:disable:no-string-literal */ ko.bindingHandlers["image"].options.enabled = false; /* tslint:enable:no-string-literal */ runtimeSettings.setShowNewsAfterLogin(false); } } } if (platformInfo.hasMenu()) { app.setupMenu(); } // Recalculate width of the landscape mode. const currentWidth = $("body").width(); if (currentWidth === 1024) { platformInfo.isTablet = true; } app.tablesPage.calculateLandscapeWidth(); pushService.register(); tableManager.maxTablesReached.add(function(continuation) { SimplePopup.display(_("maxtables.caption"), _("maxtables.maxtablesreached")); }); tableManager.hasTurn.subscribe(function(value) { app.tabBar.notice("tables", value); }); app.popupClosed.add(function(popupName) { keyboardActivationService.forceHideKeyboard(); console.log("Popup " + popupName + " closed"); }); app.receivedEvent("deviceready"); } // Update DOM on a Received Event public async receivedEvent(id) { const self = this; timeService.start(); settings.soundEnabled.subscribe(function(value) { soundManager.enabled(value); }); settings.loadSettings(); settings.isGuest.subscribe(function(value) { if (authManager.authenticated() && !value) { app.lobbyPageBlock.lobbyPage.cashOptions.currency(1); app.lobbyPageBlock.lobbyPage.sngOptions.currency(1); app.lobbyPageBlock.lobbyPage.tournamentOptions.currency(1); } else { app.lobbyPageBlock.lobbyPage.cashOptions.currency(2); app.lobbyPageBlock.lobbyPage.sngOptions.currency(2); app.lobbyPageBlock.lobbyPage.tournamentOptions.currency(2); } }); authManager.authenticated.subscribe(function(value) { if (value && !settings.isGuest()) { app.lobbyPageBlock.lobbyPage.cashOptions.currency(1); app.lobbyPageBlock.lobbyPage.sngOptions.currency(1); app.lobbyPageBlock.lobbyPage.tournamentOptions.currency(1); } else { app.lobbyPageBlock.lobbyPage.cashOptions.currency(2); app.lobbyPageBlock.lobbyPage.sngOptions.currency(2); app.lobbyPageBlock.lobbyPage.tournamentOptions.currency(2); } }); $.when(this.loadPromises).then(function() { keyboardActivationService.setup(); self.setupTouchActivation(); }); this.setInitializationState(); let startPage = "main"; if (this.getParameterByName("restore") === "true") { const currentTime = new Date(); const timeDiff = currentTime.valueOf() - settings.lastTime(); if (timeDiff > 1000 * 60 * 20) { authToken = null; startPage = "main"; } else { authToken = settings.authToken(); startPage = settings.lastPage(); } } this.logEvent("Received Event: " + id); if (window.innerWidth > 640) { PageBlock.useDoubleView = true; AnimationSettings.platform = "tablet"; } this.setDesiredOrientation(); if (platformInfo.isTablet) { orientationService.suppressRotation(); } this.setupClosePopupOnClick(); metadataManager.setFailed(() => { slowInternetService.onConnectionSlow(); slowInternetService.onDisconnected(); self.metadataUpdateFailed(); }); metadataManager.setReady(function() { // Adjust height const toolpadHeight = platformInfo.hasTabBar() ? 49 : 15; const logoHeight = 102; let noLogoHeight = 57; const pageHeaderHeight = 58; if (platformInfo.hasTabBar()) { $(".page.main").addClass("has-toolbar"); } noLogoHeight = window.innerHeight - toolpadHeight - noLogoHeight - platformInfo.statusBarHeight(); $(".popup-container.scroll-container").css("max-height", noLogoHeight); const device: Device = window.device; let tournamentLobbyAdjustment = 57; let lobbyAdjustment = 0; if (device != null && device.available) { if (device.platform.toLowerCase() === "ios") { tournamentLobbyAdjustment = 57; } else { tournamentLobbyAdjustment = 81; lobbyAdjustment = -30; app.setupMenu(); } } if (startPage === "main") { uiManager.showPage("main"); self.showPageBlock("home"); self.showSubPage("home"); } else { app.showSubPage("tables"); self.loadTablesAndTournaments(true); } tableManager.tables.subscribe(function(newValue) { self.updateTabbar(authManager.authenticated(), newValue); }); authManager.authenticated.subscribe(function(newValue) { self.updateTabbar(newValue, tableManager.tables()); // tslint:disable-next-line:no-console console.log("Authentication changed."); setTimeout(() => { self.terminateConnection(); self.loadTablesAndTournaments(newValue); }, 100); }); }); slowInternetService.initialize(); const hasInternet = slowInternetService.hasInternet(); // tslint:disable-next-line:no-console console.log("Detecting internet status..." + hasInternet ? "connected" : "not connected"); if (hasInternet) { slowInternetService.setRetryHandler(null); self.updateMetadataOnLaunch(); self.hideSplash(); } else { slowInternetService.onOffline(); self.hideSplash(); slowInternetService.setRetryHandler(() => self.updateMetadataOnLaunch()); } } public setInitializationState() { const parentElement = document.getElementById("deviceready"); if (parentElement) { const listeningElement = parentElement.querySelector(".listening"); const receivedElement = parentElement.querySelector(".received"); listeningElement.setAttribute("style", "display:none;"); receivedElement.setAttribute("style", "display:block;"); } } public buildStartConnection() { return connectionService.buildStartConnectionAsync(); } public showSubPage(pageName: string) { this.hideMoreBlock(); uiManager.showSubPage(pageName); } public showPageBlock(pageBlockName: string) { uiManager.showPageBlock(pageBlockName); } public showSelector(selectorCaption: string, options: SelectorItem[], success: (item: SelectorItem) => void) { const successCallback = (item: SelectorItem) => { $(".page .page-block." + uiManager.currentPageBlock).css("display", "block"); $(".page .sub-page." + uiManager.currentPage).css("display", "block"); $(".page .sub-page.selector").css("display", "none"); success(item); }; const cancelCallback = () => { $(".page .page-block." + uiManager.currentPageBlock).css("display", "block"); $(".page .sub-page." + uiManager.currentPage).css("display", "block"); $(".page .sub-page.selector").css("display", "none"); }; $(".page .page-block." + uiManager.currentPageBlock).css("display", "none"); $(".page .sub-page." + uiManager.currentPage).css("display", "none"); $(".page .sub-page.selector").css("display", "block"); this.mainSelector.setParams(selectorCaption, options, successCallback, cancelCallback); } public bindPageBlock(pageBlockName: string, viewModel: PageBlock) { const self = this; commandManager.registerCommand("pageblock." + pageBlockName, function() { const requireAuthentication = viewModel.requireAuthentication; if (!requireAuthentication) { self.showPageBlock(pageBlockName); } else { app.requireAuthentication().then(function(value) { if (value) { self.showPageBlock(pageBlockName); } }); } }); for (let i = 0; i < viewModel.loadPromises.length; i++) { const item = viewModel.loadPromises[i]; this.loadPromises.push(item); } } public bindSubPage(pageName: string, viewModel: any) { const self = this; commandManager.registerCommand("page." + pageName, function() { const requireAuthentication = viewModel.requireAuthentication || false; if (!requireAuthentication) { self.showSubPage(pageName); } else { app.requireAuthentication().then(function(value) { if (value) { self.showSubPage(pageName); } }); } }); if (typeof window === "undefined") { return; } const pagejElement = $(".page .sub-page." + pageName); if (pagejElement.length === 0) { console.error("Could not bind sub page " + pageName + " since DOM element not found."); return; } if (pagejElement.length > 1) { console.warn("Page " + pageName + " has more then one element to bind."); return; } const pageElement = pagejElement[0]; if (!pageElement.hasChildNodes()) { const templateSource: string = pagejElement.data("template") as any; const pageLoadPromise = $.get(templateSource, "text/html").then(function(data: string) { pagejElement.html(data); try { ko.applyBindings(viewModel, pageElement); } catch (e) { console.log("Bind page " + pageName + " failed"); } }); this.loadPromises.push(pageLoadPromise); return; } ko.applyBindings(viewModel, pageElement); } public bindPopup(popup: string, viewModel: any): void { const self = this; commandManager.registerCommand("popup." + popup, function() { self.showPopup(popup); }); if (typeof window === "undefined") { return; } const popupjElement = $(".popup." + popup); if (popupjElement.length === 0) { console.error("Could not bind popup " + popup + " since DOM element not found."); return; } if (popupjElement.length > 1) { console.warn("Popup " + popup + " has more then one element to bind."); return; } const popupElement = popupjElement[0]; if (!popupElement.hasChildNodes()) { const templateSource: string = popupjElement.data("template") as any; $.get(templateSource, "text/html").then(function(data) { popupjElement.html(data); try { ko.applyBindings(viewModel, popupElement); } catch (e) { console.log("Bind popup " + popup + " failed"); console.log("Detailed exception: ", e); } }); return; } ko.applyBindings(viewModel, popupElement); } public bindUIElement(className: string, viewModel: any): void { if (typeof window === "undefined") { return; } const uiElement = $(className); if (uiElement.length === 0) { console.error("Could not bind UI element with class " + className + " since DOM element not found."); return; } if (uiElement.length > 1) { console.warn("UI element with class " + className + " has more then one element."); return; } const domElement = uiElement[0]; if (!domElement.hasChildNodes()) { const templateSource: string = uiElement.data("template") as any; $.get(templateSource, "text/html").then(function(data) { uiElement.html(data); try { ko.applyBindings(viewModel, domElement); } catch (e) { console.log("Bind UI element " + className + " failed"); } }); return; } ko.applyBindings(viewModel, domElement); } public async showPopup(popupName: string, ...args: any[]) { if (!popupName) { console.error("The empty popup passed"); throw new Error("The empty popup passed"); } if (this.currentPopup != null) { this.hideMoreBlock(); this.closePopup(); } this.currentPopup = popupName; console.log("Show popup " + popupName); const result = new Promise((resolve) => { this.popupClosed.addOnce(function(name: string, dialogResults?: any) { if (popupName !== name) { console.warn("Responding to popup " + name + " instead of " + popupName); } const signalData = { name, result: dialogResults, }; resolve(signalData); }, this, 1); const popupObject = this[this.currentPopup + "Popup"]; if (popupObject != null) { popupObject.shown(args); } if (typeof window !== "undefined") { const popupContainer = $(".popup." + popupName + " .popup-container"); if (popupContainer.length > 0) { popupContainer[0].scrollTop = 0; } $(".popup." + popupName).css("display", "block"); $(".popup-background").css("display", "block"); } }); return result; } public closePopup(result?: any): void { if (this.currentPopup) { console.log("Close popup " + this.currentPopup); if (typeof window !== "undefined") { $(".popup." + this.currentPopup + " .popup-container")[0].scrollTop = 0; $(".popup." + this.currentPopup).css("display", "none"); $(".popup-background").css("display", "none"); } const popupName = this.currentPopup; const popupObject = this[this.currentPopup + "Popup"]; /* tslint:disable:no-string-literal */ if (popupObject !== undefined && popupObject["visible"] !== undefined) { popupObject.visible(false); } /* tslint:enable:no-string-literal */ this.currentPopup = null; this.popupClosed.dispatch(popupName, result); } } public executeCommand(commandName: string, parameters: any[]= []) { if (commandName === "popup.auth.show") { this.showPopup("auth"); return; } if (commandName === "popup.auth.forgetPassword") { this.showPopup("forgetPassword"); return; } if (commandName === "popup.auth.registration") { this.showPopup("registration"); return; } if (commandName === "popup.auth.continueForgetPassword") { this.showPopup("continueForgetPassword"); return; } if (commandName === "popup.close") { this.closePopup(); return; } if (commandName === "legal.eula") { app.closePopup(); app.executeCommand("pageblock.info"); app.infoPageBlock.showLicenseAgreement(); return; } if (commandName === "popup.cancel") { this.closePopup("cancel"); return; } if (commandName === "more.close") { this.hideMoreBlock(); const currentTabBarItem = UIManager.getTabBarItemForPage(uiManager.currentPageBlock); app.tabBar.select(currentTabBarItem, true); return; } if (commandName === "logout") { authManager.logout(); return; } if (commandName === "app.exit") { authManager.logout(); this.reloadApplication(); return; } commandManager.executeCommand(commandName, parameters); } public reloadApplication() { /* tslint:disable:no-unused-expression no-string-literal */ window["StatusBar"] && StatusBar.show(); /* tslint:enable:no-unused-expression no-string-literal */ window.location.reload(); } public shouldRotateToOrientation(interfaceOrientation: any) { /// Checks that given orientation currently supported /// For now this is works in iOS. return ScreenOrientation.shouldRotateToOrientation(interfaceOrientation); } public requireAuthentication(): JQueryPromise { const result = $.Deferred(); if (!authManager.authenticated()) { // We don't authenticated, so display authentication popup. this.popupClosed.addOnce(function() { // Resolve with current authentication status, so // caller would know operation was successful or not. result.resolve(authManager.authenticated(), false); }, this, null); this.showPopup("auth"); } else { // We already authenticated, no need to show authentication popup. result.resolve(true, true); } return result; } public requireGuestAuthentication(): JQueryPromise { const result = $.Deferred(); if (!authManager.authenticated()) { // We don't authenticated, so display authentication popup. authManager.loginAsGuest().then(function(status) { result.resolve(authManager.authenticated(), false); }); } else { // We already authenticated, no need to show authentication popup. result.resolve(true, true); } return result; } public prompt(title: string, messages: string[], buttons: string[]= null) { if (buttons === null) { buttons = [_("common.ok"), _("common.cancel")]; } this.showPopup("okcancel"); const popupObject = this.okcancelPopup; const deferred = popupObject.deferred; popupObject.title(title); popupObject.messages(messages); popupObject.buttons(buttons); popupObject.customStyle(""); return deferred; } public promptEx(title: string, messages: string[], buttons: string[], actions: Array<() => PromiseOrVoid>) { this.showPopup("custom"); const popupObject = this.customPopup; const deferred = popupObject.deferred; popupObject.title(title); popupObject.messages(messages); popupObject.buttons(buttons); popupObject.actions(actions); return deferred; } public promptAsync(title: string, messages: string[], buttons: string[] = null) { return new Promise((resolve, reject) => { this.prompt(title, messages, buttons).then(() => resolve(true), () => resolve(false)); }); } private initializeTabbar() { this.tabBar = new TabBar(); this.tabBar.addItem("home", _("tabbar.home"), "home", function() { app.executeCommand("page.home"); app.showPageBlock("home"); }); this.tabBar.addItem("lobby", _("tabbar.lobby"), "lobby", function() { app.lobbyPageBlock.showLobby(); }); this.tabBar.addItem("tables", _("tabbar.tables"), "tables", function() { const currentTable = app.tablesPage.currentTable(); if (currentTable === null || currentTable.model === null) { console.warn("No tables opened. Could not open tables page"); SimplePopup.display(_("menu.tables"), _("tablesList.noTablesSelected")); return; } app.executeCommand("app.selectTable", [currentTable.model]); app.showSubPage("tables"); }); this.tabBar.addItem("cashier", _("tabbar.cashier"), "cashier", function() { app.executeCommand("pageblock.cashier"); // app.executeCommand("pageblock.other"); }); this.tabBar.addItem("more", _("tabbar.more"), "more", function() { const currentTabBarItem = UIManager.getTabBarItemForPage(uiManager.currentPageBlock); const isMoreSelected = app.tabBar.isSelected("more"); const isMoreOpened = $("body").hasClass("more-opened"); if (isMoreOpened) { app.tabBar.select("more", false); app.tabBar.select(currentTabBarItem, true); $(".more-block").hide(); $("body").removeClass("more-opened"); } else { app.tabBar.select(currentTabBarItem, false); app.tabBar.select("more", true); app.morePopup.update(); $(".more-block").show(); $("body").addClass("more-opened"); } app.morePopup.visible(!app.morePopup.visible()); }); this.tabBar.enable("tables", false); if (typeof window !== "undefined") { const tabBarElement = $(".toolbar-container")[0]; if (tabBarElement) { ko.applyBindings(this.tabBar, tabBarElement); } } uiManager.subPageHiding.add(function(blockHiding: string) { const name = UIManager.getTabBarItemForPage(blockHiding); app.tabBar.select(name, false); }); uiManager.subPageShowing.add(function(blockShowing: string) { const name = UIManager.getTabBarItemForPage(blockShowing); app.tabBar.select(name, true); }); uiManager.pageBlockHiding.add(function(blockHiding: string) { const name = UIManager.getTabBarItemForPage(blockHiding); app.tabBar.select(name, false); }); uiManager.pageBlockShowing.add(function(blockShowing: string) { const name = UIManager.getTabBarItemForPage(blockShowing); app.tabBar.select(name, true); }); uiManager.pageBlockHidden.add(function(pageBlock: string) { if (app.tabBar.isSelected("more")) { if (pageBlock !== "more" && !app.morePopup.visible()) { app.tabBar.select("more", false); } app.hideMoreBlock(); } }); } private onResign() { const self = app; self.logEvent("Application resign active"); // Wrap code in the timeout to prevent application from freezing. self.terminateConnection(); } private onActive() { const self = app; self.logEvent("Application active"); // Wrap code in the timeout to prevent application from freezing. self.establishConnection(); } private onPause() { const self = app; const device: Device = window.device; if (platformInfo.isTablet) { orientationService.enableRotation(); } if (platformInfo.reloadOnResume) { // Don't do anything if reloading on resume. if (uiManager.currentPage === "tables") { settings.lastPage("tables"); } else { settings.lastPage("main"); } settings.authToken(authToken); settings.lastTime(new Date().valueOf()); settings.saveSettings(); return; } if (self.suppressResume) { return; } if (debugSettings.application.deactivateOnPause) { uiManager.deactivateSubPage(uiManager.currentPage); } self.logEvent("Pause application"); // Wrap code in the timeout to prevent application from freezing. timeService.setTimeout(function() { self.logEvent("Pause application#2"); self.showSplash(); settings.saveSettings(); if (self.currentPopup === "registration") { self.savedPopup = self.currentPopup; } else { self.savedPopup = null; } self.closePopup(); timeService.printDebug(); }, 0); timeService.stop(); self.processing(false); self.spinner.stop(); self.terminateConnection(); } private onResume() { const self = app; const device: Device = window.device; if (platformInfo.reloadOnResume) { // Reload to the main page with special configuration parameter self.showSplash(); location.replace(location.protocol + "//" + location.host + location.pathname + "?restore=true"); return; } if (self.suppressResume) { self.suppressResume = false; if (self.savedPopup) { self.showPopup(self.savedPopup, true); self.savedPopup = null; } return; } self.logEvent("Resume application"); timeService.start(); self.showSplash(); const target = document.getElementById("spinner"); self.spinner.spin(target); let pageBeforeClosing = uiManager.effectivePageContainer; let pageBlockBeforeClosing = uiManager.currentPageBlock; let subPageBeforeClosing = uiManager.currentPage; if (pageBeforeClosing === "initialization" || pageBeforeClosing === null) { pageBeforeClosing = "main"; pageBlockBeforeClosing = "home"; subPageBeforeClosing = "home"; } uiManager.showPage("initialization"); settings.loadSettings(); self.setInitializationState(); orientationService.setLastOrientation(); if (platformInfo.isTablet) { orientationService.suppressRotation(); } if (slowInternetService.fatalError) { self.hideSplash(); slowInternetService.showDuplicatedConnectionPopup(); return; } if (slowInternetService.hasInternet()) { slowInternetService.closePopup(); self.updateMetadataOnResume(pageBeforeClosing, pageBlockBeforeClosing, subPageBeforeClosing); slowInternetService.setRetryHandler(null); self.hideSplash(); } else { slowInternetService.onOffline(); self.hideSplash(); slowInternetService.setRetryHandler(function() { self.updateMetadataOnResume(pageBeforeClosing, pageBlockBeforeClosing, subPageBeforeClosing); }); } } private async updateMetadataOnResume(lastPage, pageBlockBeforeClosing, subPageBeforeClosing) { const self = this; if (debugSettings.initialization.stopOnResume) { return; } console.log("Launch intialization of metadata on resume"); if (!this.fullyInitialized) { console.log("Application was never initialized, performing full initialization."); await this.updateMetadataOnLaunch(); return; } const failHandler = function() { console.log("Failed updating metadata on resume, rescheduling attempt."); slowInternetService.showReconnectFailedPopup(); slowInternetService.setRetryHandler(() => { self.updateMetadataOnResume(lastPage, pageBlockBeforeClosing, subPageBeforeClosing); }); }; if (!await this.versionCheck()) { return; } this.preloadTableImages(); try { await metadataManager.update(); tableManager.initialize(); try { await tableManager.getCurrentTablesAndTournaments(); this.spinner.stop(); const wrapper = await self.establishConnection(); if (wrapper.terminated) { return; } this.logEvent("Showing last page"); if (lastPage != null) { if (!debugSettings.application.goToLobbyAfterPause) { uiManager.showPage(lastPage); } else { uiManager.showPage("main"); if (lastPage === "table") { uiManager.showPageBlock("lobby"); uiManager.showSubPage("lobby"); } } } else { uiManager.showPage("main"); } if (debugSettings.application.deactivateOnPause) { this.logEvent("Activating subpage"); uiManager.activateSubPage(uiManager.currentPage); } if (this.savedPopup) { this.showPopup(this.savedPopup, true); this.savedPopup = null; } orientationService.setLastOrientation(); reloadManager.execute(); } catch (e) { failHandler(); } } catch (e) { failHandler(); } } private async updateMetadataOnLaunch() { const self = this; if (debugSettings.initialization.stopOnLaunch) { return; } console.log("Launch intialization of metadata first time"); const failHandler = function (e: Error) { console.error(e); console.log("Failed updating metadata for first time, rescheduling attempt."); slowInternetService.setRetryHandler(() => { self.updateMetadataOnLaunch(); }); }; if (!await this.versionCheck()) { return; } self.preloadTableImages(); try { await metadataManager.update(); self.spinner.stop(); tableManager.initialize(); try { await self.establishConnection(); await tableManager.getCurrentTablesAndTournaments(); self.fullyInitialized = true; metadataManager.setReady(null); } catch (e) { failHandler(e); } } catch (e) { failHandler(e); } } private async versionCheck() { try { await metadataManager.versionCheck(); return true; } catch (e) { // Display dialog which prompts for the update. app.promptEx(_("updater.title"), [_("updater.line1")], [_("updater.button")], [() => { websiteService.navigateUpdateApk(); }]); return false; } } private setupTouchActivation() { // This is a fix which updates binding for the knockout value binding. // This is nescessary since touchstart event start handling. $("body").on("keyup", "input", function(event) { $(this).trigger("change"); }); $("body").on("touchstart", ".button, .actionable", function(event) { $(this).addClass("pressed"); }).on("touchend", ".button, .actionable", function(event) { $(this).removeClass("pressed"); }).on("touchcancel", ".button, .actionable", function(event) { $(this).removeClass("pressed"); }); } private setupMenu() { menu.initialize([ { id: 1, order: 1, name: _("menu.home") }, { id: 2, order: 1, name: _("menu.lobby") }, { id: 3, order: 1, name: _("menu.tables") }, { id: 4, order: 1, name: _("menu.cashier") }, { id: 5, order: 1, name: _("menu.account") }, { id: 6, order: 1, name: _("menu.chat") }, { id: 7, order: 1, name: _("menu.rating") }, { id: 8, order: 1, name: _("menu.messages") }, { id: 9, order: 1, name: _("menu.information") }, ]); menu.optionItemClick = function(itemId) { if (itemId === 1) { app.executeCommand("page.home"); app.showPageBlock("home"); } if (itemId === 2) { app.lobbyPageBlock.showLobby(); } if (itemId === 3) { app.executeCommand("page.tables"); } if (itemId === 4) { app.executeCommand("pageblock.cashier"); } if (itemId === 5) { app.executeCommand("page.account"); } if (itemId === 6) { app.executeCommand("page.chat"); } if (itemId === 7) { app.executeCommand("page.rating"); } if (itemId === 8) { app.executeCommand("page.messages"); } if (itemId === 9) { app.executeCommand("page.information"); } console.log(itemId); }; } private async loadTablesAndTournaments(authenticated: boolean) { const self = this; if (authenticated) { try { await tableManager.getCurrentTablesAndTournaments(); self.establishConnection(); } catch (e) { console.log("Could not get current tables!"); slowInternetService.showReconnectFailedPopup(); } } else { tableManager.clear(); self.establishConnection(); } } private setFailedState() { const parentElement = document.getElementById("deviceready"); if (parentElement) { const listeningElement = parentElement.querySelector(".listening"); const receivedElement = parentElement.querySelector(".received"); receivedElement.setAttribute("style", "display:none;"); const failedElement = parentElement.querySelector(".failed"); failedElement.setAttribute("style", "display:block;"); } } private metadataUpdateFailed() { this.setFailedState(); console.log("Metadata retreiving failure"); } private setDesiredOrientation() { if (!PageBlock.useDoubleView) { orientationService.setOrientation("portrait"); } else { orientationService.setOrientation("landscape"); } } private initializeConnection() { const self = this; // connectionService.initializeConnection(); connectionService.recoverableError.add(function() { self.establishConnection(); }); } private terminateConnection(forceDisconnect = false) { tableManager.stopConnectingToTables(); connectionService.terminateConnection(forceDisconnect); } private async establishConnection(maxAttempts = 3) { const self = this; // This part should be moved up to the stack to remove dependency on other services // in the connection management. connectionService.initializeConnection(); const wrapper = await connectionService.establishConnectionAsync(maxAttempts); if (wrapper.terminated) { return wrapper; } self.logEvent("Setting up connection dependent services."); slowInternetService.manualDisconnect = false; tableManager.connectTables(); tableManager.connectTournaments(); const connection = wrapper.connection; try { self.logEvent("Joining lobby chat."); connection.Chat.server.join(0); } catch (error) { console.log(error); throw new Error("Could not join chat after establishingConnection"); } self.logEvent("Listening lobby chat messages."); const chatHub = connection.createHubProxy("chat"); chatHub.on("Message", function(...msg: any[]) { const messageId = msg[0]; const tableId = msg[1]; const type = msg[2]; const sender = msg[3]; const message = msg[4]; if (tableId !== 0) { return; } if (type === "B") { broadcastService.displayMessage(message); } }); return wrapper; } private hideMoreBlock() { app.morePopup.visible(false); $(".more-block").hide(); $("body").removeClass("more-opened"); app.tabBar.select("more", false); } private updateTabbar(authenticated, tables) { const self = this; if (authenticated) { const tablesEnabled = tables.length > 0; self.tabBar.enable("tables", tablesEnabled); } else { self.tabBar.enable("tables", false); } } private setupClosePopupOnClick() { $(".popup-background").on("tap", () => { if (app.currentPopup !== "slowConnection") { app.closePopup(); } }); } private preloadTableImages() { imagePreloadService.preloadResource("img/lobby/table2-empty"); imagePreloadService.preloadResource("img/lobby/table2-s1"); imagePreloadService.preloadResource("img/lobby/table2-s2"); imagePreloadService.preloadResource("img/lobby/table6-empty"); imagePreloadService.preloadResource("img/lobby/table6-s1"); imagePreloadService.preloadResource("img/lobby/table6-s2"); imagePreloadService.preloadResource("img/lobby/table6-s3"); imagePreloadService.preloadResource("img/lobby/table6-s4"); imagePreloadService.preloadResource("img/lobby/table6-s5"); imagePreloadService.preloadResource("img/lobby/table6-s6"); imagePreloadService.preloadResource("img/lobby/table10-empty"); imagePreloadService.preloadResource("img/lobby/table10-s1"); imagePreloadService.preloadResource("img/lobby/table10-s2"); imagePreloadService.preloadResource("img/lobby/table10-s3"); imagePreloadService.preloadResource("img/lobby/table10-s4"); imagePreloadService.preloadResource("img/lobby/table10-s5"); imagePreloadService.preloadResource("img/lobby/table10-s6"); imagePreloadService.preloadResource("img/lobby/table10-s7"); imagePreloadService.preloadResource("img/lobby/table10-s8"); imagePreloadService.preloadResource("img/lobby/table10-s9"); imagePreloadService.preloadResource("img/lobby/table10-s10"); imagePreloadService.preloadDeviceSpecificResource("img/images/tableImages/poker_table"); } private logEvent(message: string) { if (debugSettings.device.events) { console.log(message); } } private getParameterByName(name) { name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); const regex = new RegExp("[\\?&]" + name + "=([^&#]*)"); const results = regex.exec(location.search); return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); } private showSplash() { /* tslint:disable:no-unused-expression no-string-literal */ navigator["splashscreen"] && navigator.splashscreen.show(); /* tslint:enable:no-unused-expression no-string-literal */ } private hideSplash() { /* tslint:disable:no-unused-expression no-string-literal */ navigator["splashscreen"] && navigator.splashscreen.hide(); /* tslint:enable:no-unused-expression no-string-literal */ } } declare var app: App;