Working: initial setup tool, app list, using Apps

Framework7
Skylar Ittner 6 years ago
parent d248aa5934
commit 0b85c8a7f6

3
.gitignore vendored

@ -1,4 +1,5 @@
nbproject/private
platforms
plugins
node_modules
node_modules
/www/old/

@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.netsyms.BusinessMobile" version="1.7" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>Business</name>
<widget id="com.netsyms.BusinessMobile.f7" version="1.7" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>Business F7</name>
<description>
Mobile client for the Netsyms Business Apps.
</description>
@ -66,13 +66,13 @@
<splash density="land-xxxhdpi" src="res/screen/android/splash-land-xxxhdpi.png" />
</platform>
<preference name="AutoHideSplashScreen" value="false" />
<plugin name="cordova-plugin-add-swift-support" spec="^1.7.1" />
<plugin name="cordova-plugin-whitelist" spec="^1.3.2" />
<plugin name="cordova-plugin-headercolor" spec="^1.0.0" />
<plugin name="cordova-plugin-app-version" spec="^0.1.9" />
<plugin name="cordova-plugin-file" spec="^6.0.1" />
<plugin name="cordova-plugin-headercolor" spec="^1.0.0" />
<plugin name="cordova-plugin-statusbar" spec="^2.4.1" />
<plugin name="cordova-plugin-whitelist" spec="^1.3.2" />
<plugin name="cordova-plugin-add-swift-support" spec="^1.7.1" />
<plugin name="cordova-plugin-zeroconf" spec="^1.3.1" />
<plugin name="cordova-plugin-statusbar" spec="^2.4.1" />
<plugin name="phonegap-plugin-barcodescanner" spec="^7.1.0">
<variable name="ANDROID_SUPPORT_V4_VERSION" value="27.+" />
</plugin>
@ -85,4 +85,5 @@
<plugin name="cordova-plugin-background-fetch" spec="^5.4.1" />
<plugin name="cordova-plugin-local-notification" spec="^0.9.0-beta.2" />
<engine name="android" spec="^7.1.1" />
<engine name="browser" spec="^5.0.4" />
</widget>

@ -8,6 +8,7 @@
"license": "MPL-2.0",
"dependencies": {
"cordova-android": "^7.1.1",
"cordova-browser": "^5.0.4",
"cordova-plugin-add-swift-support": "^1.7.1",
"cordova-plugin-app-version": "^0.1.9",
"cordova-plugin-background-fetch": "^5.4.1",
@ -49,7 +50,8 @@
"cordova-plugin-local-notification": {}
},
"platforms": [
"android"
"android",
"browser"
]
}
}

@ -0,0 +1,119 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.mobile-app-hide {
display: none;
visibility: hidden;
}
.mobile-app-show {
visibility: visible;
}
.mobile-app-display {
display: initial;
}
@media screen and (max-width: 767px) {
#navbar-collapse {
display: none;
}
}
#swipe-nav {
display: none;
visibility: visible;
overflow-y: scroll;
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 60%;
z-index: 9999999;
max-width: 300px;
min-width: 200px;
background-color: #fafafa;
box-shadow: 5px 0px 15px 0px rgba(0,0,0,0.5);
}
#swipe-nav #swipe-header {
height: 150px;
background-color: #eeeeee;
position: relative;
}
#swipe-nav #swipe-header #swipe-username {
position: absolute;
bottom: 0;
padding-left: 10px;
padding-bottom: 10px;
font-size: 110%;
}
#swipe-nav #swipe-header #swipe-appicon {
position: absolute;
top: 0;
padding-left: 20px;
padding-top: 20px;
height: 80px;
}
#swipe-nav #swipe-header #swipe-username .fa {
font-size: 120%;
}
#swipe-nav #swipe-pages {
padding-bottom: 10px;
border-bottom: 1px solid #eeeeee;
}
#swipe-shader {
position: fixed;
display: none;
visibility: visible;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
z-index: 9999998;
}
#swipe-nav .swipe-list {
margin-top: 5px;
margin-bottom: 10px;
padding-left: 0px;
list-style-type: none;
padding: 3px;
}
#swipe-nav .swipe-list .nav-item {
color: #424242;
padding-top: 5px;
padding-bottom: 5px;
}
#swipe-nav .swipe-list .nav-item a:focus,a:active {
background-color: #e0e0e0;
}
#swipe-nav .swipe-list .nav-item i.fa {
font-size: 120%;
margin-right: 10px;
margin-left: 5px;
}
#swipe-nav .swipe-list .nav-item a {
display: inline-block;
color: #424242;
font-size: 110%;
text-decoration: none;
width: 100%;
padding-top: 15px;
padding-bottom: 15px;
}
#swipe-nav .swipe-list .nav-item a:hover {
text-decoration: none;
}

@ -1,148 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
html, body {
height: 100%;
}
.app-dock-container {
display: flex;
height: 100%;
}
.app-dock {
margin: 0 auto 10px auto;
display: flex;
justify-content: space-evenly;
flex-wrap: wrap;
align-items: center;
justify-content: center;
height: 100%;
}
.app-icon {
border: 1px solid grey;
border-radius: 20%;
}
.app-dock-item {
padding: 0px 10px 2px 10px;
min-width: 100px;
max-width: 50%;
width: 120px;
margin: 15px;
}
.app-dock-item p {
margin-bottom: 0px;
font-size: 120%;
color: #555;
}
.app-dock-item p img {
width: 80px;
height: 80px;
display: block;
background: url(../img/app-icon-bg.svg) no-repeat;
background-size: 90%;
background-position: 50%;
margin: 0 auto;
}
.app-dock-item p span {
display: block;
text-align: center;
}
/* https://stackoverflow.com/a/23536146 */
.navbar-collapse.collapse {
display: block!important;
}
.navbar-nav>li, .navbar-nav {
float: left !important;
}
.navbar-nav.navbar-right:last-child {
margin-right: -15px !important;
}
.navbar-right {
float: right!important;
}
/* /stackoverflow */
.nav {
color: white;
margin-right: 0px;
height: 30px;
margin-top: -4px;
font-size: 20px;
margin-left: 5px;
}
.navbar-right span {
color: white;
font-size: 18px;
margin-top: -4px;
}
.navbar-brand img {
margin-right: 15px;
height: 30px;
margin-top: -4px;
margin-left: -10px;
display: inline-block;
}
.navbar-right li a img {
height: 30px;
margin-top: 6px;
display: inline-block;
}
@media (min-width: 768px) {
.navbar-right {
margin-top: -6px;
}
.navbar-right li a img {
margin-top: -1px;
}
}
#manual_setup {
margin-top: 15px;
}
#navbar {
min-height: 56px;
}
.loading-text {
font-size: 18px;
}
.circle-btn {
display: flex;
align-items: center;
justify-content: center;
align-content: center;
border-radius: 50%;
height: 5rem;
width: 5rem;
position: fixed;
bottom: 0;
right: 0;
margin: 2rem;
z-index: 99999;
}
.circle-btn img {
height: 3rem;
width: 3rem;
}

@ -0,0 +1,31 @@
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(./MaterialIcons-Regular.woff2) format('woff2'),
url(./MaterialIcons-Regular.woff) format('woff');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
}

@ -2,50 +2,37 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<html>
<head>
<title>Netsyms Business for Mobile</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/bootstrap.min.css" />
<link rel="stylesheet" href="css/font-awesome.min.css" />
<link rel="stylesheet" href="css/material-color.min.css" />
<link rel="stylesheet" href="css/app.css" />
<script src="cordova.js"></script>
<script src="js/polyfills.js"></script>
<script src="js/jquery-3.2.1.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/accounts.js"></script>
<script src="js/app.js"></script>
</head>
<body>
<div id="modal-load-box" class="container" style='z-index: 1000;'>
</div>
<nav class="navbar navbar-inverse navbar-fixed-top" id="navbar">
<div class="container-fluid">
<div class="nav navbar-nav navbar-left" id="navbar-header">
<span class="navbar-brand" id="navbar-title" style="color: white;">Business</span>
</div>
<ul class="nav navbar-nav navbar-right" id="navbar-buttons">
</ul>
</div>
</nav>
<div id="content-zone" class="container" style="margin-top: 75px;">
<div class="app-dock-container">
<div class="app-dock" id="app-dock">
<div style="margin-top: 50px;">
<img src="img/loader.gif" style="width: 65px; height: 65px;" alt=""/>
</div>
<div style="width: 100%;"></div>
<p class="loading-text">Loading...</p>
</div>
</div>
</div>
</body>
</html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#2196f3">
<link rel="stylesheet" href="vendor/css/framework7.min.css">
<link rel="stylesheet" href="fonts/material.css">
<title>Netsyms Business for Mobile</title>
<div id="app">
<div class="statusbar"></div>
<div class="view view-main"></div>
</div>
<script src="cordova.js"></script>
<script src="vendor/js/jquery-3.2.1.min.js"></script>
<script src="vendor/js/framework7.min.js"></script>
<script src="vendor/js/fontawesome/fontawesome.min.js"></script>
<script src="vendor/js/fontawesome/solid.min.js"></script>
<script src="vendor/js/fontawesome/regular.min.js"></script>
<script src="js/polyfills.js"></script>
<script src="js/material-palette.js"></script>
<script src="js/notifications.js"></script>
<script src="js/accounts.js"></script>
<script src="js/home.js"></script>
<script src="js/app.js"></script>
<script src="routes.js"></script>
<script src="js/main.js"></script>

@ -100,7 +100,6 @@ function rmaccount(id) {
* succeeds.
*/
function getuserinfo(callback) {
$(".loading-text").text("Loading account...");
if (localStorage.getItem("username") === null
|| localStorage.getItem("password") === null
|| localStorage.getItem("syncurl") === null
@ -114,7 +113,6 @@ function getuserinfo(callback) {
action: "user_info"
}, function (data) {
if (data.status === 'OK') {
$(".loading-text").text("Loading...");
userinfo = data.info;
if (typeof callback == 'function') {
callback();

@ -27,7 +27,6 @@ $.cssHooks.backgroundColor = {
}
}
function openmenu() {
if ($('#swipe-nav').css('display') == 'none') {
$('#swipe-shader').show("fade", {}, 300);
@ -50,9 +49,8 @@ function togglemenu() {
}
}
$(document).ready(function () {
$.fx.off = __JQUERYFXOFF__;
var bootstrap_version = $.fn.tooltip.Constructor.VERSION;
if (typeof navbar_breakpoint != "undefined") {
var nav_breakpoint = navbar_breakpoint;
} else {
@ -66,15 +64,11 @@ $(document).ready(function () {
var logo = "__LOGO__";
parent.postMessage("setcolor " + menucolor, "*");
parent.postMessage('load_bs_version ' + bootstrap_version + ' ' + nav_breakpoint, '*');
parent.postMessage("load_css " + nav_breakpoint, "*");
if (bootstrap_version.startsWith("4")) {
pages = pages.replace(/\s?py-[a-z]{2}-0/g, ""); // Issue #12
$('#navbar-right').html("<span class='nav-item py-" + nav_breakpoint + "-0'><a class='nav-link py-" + nav_breakpoint + "-0' onclick='quitapp()'><i class='fas fa-sign-out-alt fa-fw'></i> Back to Menu</a></span>");
body.append("<div id='swipe-nav'><div id='swipe-header' style='background-color: " + menucolor + "; color: " + textcolor + "'><a href='./app.php'><img id='swipe-appicon' src='" + logo + "' /></a> <div id='swipe-username'><i class='fa fa-user fa-fw'></i> " + username + "</div></div>\n<div id='swipe-pages' class='swipe-list'>" + pages + "</div><div class='swipe-list'><span class='nav-item'><a class='nav-link' onclick='quitapp()'><i class='fas fa-sign-out-alt fa-fw'></i> Back to Menu</a></span></div></div>");
} else {
body.append("<div id='swipe-nav'><div id='swipe-header' style='background-color: " + menucolor + "; color: " + textcolor + "'><a href='./app.php'><img id='swipe-appicon' src='" + logo + "' /></a> <div id='swipe-username'><i class='fa fa-user fa-fw'></i> " + username + "</div></div>\n<ul id='swipe-pages'>" + pages + "</ul><ul><li><a onclick='quitapp()'><i class='fa fa-sign-out fa-fw'></i> Back to Menu</a></li></ul></div>");
}
pages = pages.replace(/\s?py-[a-z]{2}-0/g, ""); // Issue #12
$('#navbar-right').html("<span class='nav-item py-" + nav_breakpoint + "-0'><a class='nav-link py-" + nav_breakpoint + "-0' onclick='quitapp()'><i class='fas fa-sign-out-alt fa-fw'></i> Back to Menu</a></span>");
body.append("<div id='swipe-nav'><div id='swipe-header' style='background-color: " + menucolor + "; color: " + textcolor + "'><a href='./app.php'><img id='swipe-appicon' src='" + logo + "' /></a> <div id='swipe-username'><i class='fa fa-user fa-fw'></i> " + username + "</div></div>\n<div id='swipe-pages' class='swipe-list'>" + pages + "</div><div class='swipe-list'><span class='nav-item'><a class='nav-link' onclick='quitapp()'><i class='fas fa-sign-out-alt fa-fw'></i> Back to Menu</a></span></div></div>");
body.append("<div id='swipe-shader'></div>");
$(".navbar-brand").attr("href", "#");
@ -97,6 +91,7 @@ $(document).ready(function () {
closemenu();
});
window.addEventListener('message', function (event) {
if (event.data.startsWith("coderesult~|~")) {
var data = event.data.split("~|~");
@ -118,6 +113,8 @@ $(document).ready(function () {
console.log("app: keepalive ping " + d.status);
});
}, 1000 * 60);
parent.postMessage('done_loading', '*');
});
function quitapp() {

@ -1,332 +1,154 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var shown_notifications = [];
/**
* Switches the app to the given screen.
* @param {String} screenname The name of the screen to show.
* @param {String} effect FADE, SLIDE, or nothing
* @returns {undefined}
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function openscreen(screenname, effect) {
if (effect === 'FADE') {
$('#content-zone').fadeOut(300, function () {
$('#content-zone').load("views/" + screenname + ".html", function () {
$('#content-zone').fadeIn(300);
});
});
} else if (effect === 'SLIDE') {
$('#content-zone').slideToggle('400', function () {
$('#content-zone').load("views/" + screenname + ".html", function () {
$('#content-zone').slideToggle('400');
});
});
} else {
$('#content-zone').load("views/" + screenname + ".html");
}
currentscreen = screenname;
}
function openfragment(fragment, target, effect) {
if (effect === 'FADE') {
$(target).fadeOut('slow', function () {
$(target).load("views/" + fragment + ".html", function () {
$(target).fadeIn('slow');
});
});
} else if (effect === 'SLIDE') {
$(target).slideToggle('400', function () {
$(target).load("views/" + fragment + ".html", function () {
$(target).slideToggle('400');
});
});
} else {
$(target).load("views/" + fragment + ".html");
}
}
var historyctr = -1;
/**
* Add button to the top navbar.
* @param String screenid openscreen(screenid)
* @param String icon The filename of the icon to show: <img src="icons/icon"...
* @param String title Text to show next to the icon on large screens.
* @returns {undefined}
*/
function addnavbarbtn(screenid, icon, title) {
$('#navbar-buttons').append('<li><a onclick="openscreen(\'' + screenid + '\', \'FADE\')"><img src="icons/' + icon + '" alt="" /> <span class="hidden-xs">' + title + '</span></a></li>');
}
/**
* Set the navbar options.
*
* @param String title Text to display
* @param boolean showarrow True if the back arrow should be visible
* @param Stringn backscreen The screen to open when the title is pressed, false or null for none
* @returns {undefined}
*/
function setnavbartitle(title, showarrow, backscreen) {
var arrow = "";
if (showarrow === true) {
arrow = '<img src="icons/ic_arrow-back.svg" />';
}
var onclick = "";
if (backscreen !== null && backscreen !== false) {
onclick = ' onclick=\'openscreen("' + backscreen + '", "FADE");\'';
}
$("#navbar-header").html('<span class="navbar-brand" id="navbar-title" style="color: white;"' + onclick + '>' + arrow + title + '</span>');
}
/**
* Set the navbar.
* @param {String,boolean} type false if no navbar, "home" for the home screen,
* "settings" for settings, "app" for a custom title, or anything else for
* a simple one.
* @param {String} screentitle The title to show if type == "app"
* @param {String} returnscreen Where to go back to. Defaults to "home".
* @returns {undefined}
*/
function setnavbar(type, screentitle, returnscreen) {
var navbar = $('#navbar-header');
var btns = $('#navbar-buttons');
if (type == false) {
$('#navbar').css('display', 'none');
$('#content-zone').css('margin-top', '0px');
} else {
if (cordova.platformId == 'android') {
StatusBar.backgroundColorByHexString("#1976d2");
window.plugins.headerColor.tint("#2196f3");
} else {
StatusBar.backgroundColorByHexString("#2196f3");
}
$('#navbar').css('display', 'initial');
$('#content-zone').css('margin-top', '75px');
if (returnscreen === undefined) {
returnscreen = "home";
_returnscreen = null;
} else {
_returnscreen = returnscreen;
}
btns.html("");
switch (type) {
case "home":
setnavbartitle("Business", false, false);
addnavbarbtn("mobilecode", "ic_desktop_windows.svg", "Code Login");
addnavbarbtn("otp", "ic_vpn_key.svg", "2-factor Auth");
addnavbarbtn("settings", "ic_settings.svg", "Settings");
break;
case "setup":
setnavbartitle("Business", false, false);
addnavbarbtn("otp", "ic_vpn_key.svg", "2-factor Auth");
addnavbarbtn("settings", "ic_settings.svg", "Settings");
break;
case "settings":
setnavbartitle("Settings", true, "home");
break;
case "otp":
setnavbartitle("Auth Keys", true, "home");
break;
case "app":
setnavbartitle(screentitle, true, returnscreen);
break;
default:
setnavbartitle("Business", false, false);
break;
}
}
}
/**
* Thanks to https://stackoverflow.com/a/13542669
* @param {type} color
* @param {type} percent
* @returns {String}
*/
function shadeColor2(color, percent) {
var f = parseInt(color.slice(1), 16), t = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = f >> 16, G = f >> 8 & 0x00FF, B = f & 0x0000FF;
return "#" + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1);
}
/**
* Load the app.html view and open an app with native Android UI elements
* @param String id Application ID
* Open an app with native Android UI elements
* @param String api Path to the mobile API
* @param String url Base URL of the app
* @param String icon URL to the app icon
* @param String title Friendly app name
* @param boolean injectcode (optional, default true) Whether or not to inject UI modification code into the app
* @param boolean shownavbar (optional, default false) Whether or not to show the navbar at the top of the screen.
* @returns {undefined}
*/
function openapp(id, api, url, icon, title, injectcode, shownavbar) {
$('#content-zone').fadeOut(300, function () {
$('#content-zone').load("views/app.html", function () {
$('#content-zone').fadeIn(300, function () {
launchapp(id, api, url, icon, title, injectcode, shownavbar);
});
});
});
}
function launchapp(api, url, icon, title) {
app.dialog.progress("Loading...").setText(title);
/**
* Opens a modal dialog over the top of everything else.
* @param {String} filename views/[filename].html
* @param {String} modalselector [#id-of-the-modal]
* @returns {undefined}
*/
function openmodal(filename, modalselector) {
$('#modal-load-box').load("views/" + filename + ".html", null, function (x) {
$(modalselector).css('z-index', 9999999);
$(modalselector).modal('show');
router.navigate({
name: 'app'
});
}
/**
* Close a modal (see openmodal)
* @param {String} modalselector
* @returns {undefined}
*/
function closemodal(modalselector) {
$(modalselector).modal('hide');
}
function restartApplication() {
navigator.splashscreen.show();
// We're doing the timeout so we don't run afoul of server-side rate limiting
setTimeout(function () {
window.location = "index.html";
}, 3000);
}
function displayNotifications(callback) {
$.post(localStorage.getItem("syncurl"), {
$.post(url + api, {
username: localStorage.getItem("username"),
key: localStorage.getItem("key"),
action: "checknotifications"
password: localStorage.getItem("password"),
action: "start_session"
}, function (data) {
if (data.status === 'OK') {
for (var i = 0; i < data.notifications.length; i++) {
var n = data.notifications[i];
if (n.seen || shown_notifications.includes(n.id)) {
continue;
}
cordova.plugins.notification.local.schedule([{
title: n.title,
text: n.content,
actions: [
{id: 'mark_read', title: "Mark Read"}
],
id: n.id,
lockscreen: !n.sensitive
}]);
shown_notifications.push(n.id);
}
}
if (typeof callback == 'function') {
callback();
$('#appframe').on("load", function () {
app.dialog.close();
historyctr++;
// Do this right away so it's a bit harder to glitch
$('#appframe').contents().find('.navbar-right').html("<li><a onclick='quitapp()'><i class='fas fa-sign-out-alt fa-fw'></i> Back to Menu</a></li>");
$.get("js/polyfills.js", function (script) {
$('#appframe').contents().find('body').append("<script>" + script + "<\/script>");
$.get("vendor/js/jquery-ui.min.js", function (script) {
$('#appframe').contents().find('body').append("<script>" + script + "<\/script>");
$.get("vendor/js/hammer.min.js", function (script) {
$('#appframe').contents().find('body').append("<script>" + script + "<\/script>");
$.get("js/app-inject.js", function (script) {
script = script.replace("__USERNAME__", userinfo.realname);
script = script.replace("__LOGO__", icon);
$('#appframe').contents().find('body').append("<script>" + script + "<\/script>");
});
});
});
});
});
$('#appframe').attr('src', url);
} else {
navigator.notification.alert(data.msg, null, "Error", 'Dismiss');
router.back();
}
}, "json").fail(function () {
if (typeof callback == 'function') {
callback();
}
navigator.notification.alert("Could not connect to the server. Try again later.", null, "Error", 'Dismiss');
router.back();
});
}
// Handle back button to close things
document.addEventListener("backbutton", function (event) {
if (isconfigvalid()) {
if ($("#appframe").length && historyctr > 0) {
console.log("going back");
var iframe = document.getElementById("appframe");
iframe.contentWindow.postMessage("goback", "*");
historyctr--;
} else if (_returnscreen != null) {
openscreen(_returnscreen, "FADE");
_returnscreen = null;
} else {
openscreen("home", "FADE");
}
} else {
if (_returnscreen != null) {
openscreen(_returnscreen, "FADE");
_returnscreen = null;
}
}
}, false);
function navigateApp(src) {
$('#appframe').attr('src', './' + src);
}
document.addEventListener("deviceready", function () {
if (cordova.platformId == 'android') {
StatusBar.backgroundColorByHexString("#1976d2");
var scanningactive = false;
var dedup = [];
window.addEventListener('message', function (event) {
console.log("app event: " + event.data);
setTimeout(function () {
dedup = [];
}, 500);
if (dedup.includes(event.data)) {
return;
}
cordova.plugins.notification.local.setDefaults({
led: true,
color: '#2196F3',
vibrate: true,
smallIcon: "res://ic_notification"
});
cordova.plugins.notification.local.on("mark_read", function (notification) {
$.post(localStorage.getItem("syncurl"), {
username: localStorage.getItem("username"),
key: localStorage.getItem("key"),
password: localStorage.getItem("password"),
action: "readnotification",
id: notification.id
});
});
// Enable/disable jQuery animations depending on user preference
$.fx.off = !(localStorage.getItem("animations") === null || localStorage.getItem("animations") === "true");
/* Fade out alerts */
$(".alert .close").click(function (e) {
$(this).parent().fadeOut("slow");
});
if (isconfigvalid()) {
getuserinfo(function () {
openscreen("home");
setInterval(displayNotifications, 30 * 1000);
if (typeof cordova.plugins.notification.local.launchDetails === 'undefined') {
displayNotifications();
dedup.push(event.data);
if (event.data == "quit") {
router.back();
if (cordova.platformId == 'android') {
StatusBar.backgroundColorByHexString("#1976d2");
} else {
StatusBar.backgroundColorByHexString("#2196f3");
}
} else if (event.data == "done_loading") {
app.dialog.close();
} else if (event.data == "goneback") {
historyctr -= 1;
} else if (event.data.startsWith("load_css ")) {
var nav_breakpoint = event.data.split(" ", 2)[1];
$.get("css/app-inject.css", function (style) {
var break_px = "767";
switch (nav_breakpoint) {
case "sm":
break_px = "575";
break;
case "md":
break_px = "767";
break;
case "lg":
break_px = "991";
break;
case "xl":
break_px = "1199";
break;
}
var BackgroundFetch = window.BackgroundFetch;
// Your background-fetch handler.
var fetchCallback = function () {
console.log('[js] BackgroundFetch event received');
displayNotifications(function () {
BackgroundFetch.finish();
});
};
var failureCallback = function (error) {
console.log('- BackgroundFetch failed', error);
};
BackgroundFetch.configure(fetchCallback, failureCallback, {
minimumFetchInterval: 1,
stopOnTerminate: false,
startOnBoot: true,
forceReload: false,
enableHeadless: true
});
style = style.replace("max-width: 767px", "max-width: " + break_px + "px");
$('#appframe').contents().find('head').append("<style>" + style + "</style>");
});
} else {
// Try to recover data from NativeStorage back to localStorage
recoveraccounts(function (ok) {
if (ok) {
restartApplication();
} else {
openscreen("setup1");
} else if (event.data.startsWith("setcolor ")) {
var color = event.data.split(" ", 2)[1];
if (cordova.platformId == 'android') {
window.plugins.headerColor.tint(color);
for (var swatch in _PALETTE) {
if (color == _PALETTE[swatch]["shade_500"]) {
StatusBar.backgroundColorByHexString(_PALETTE[swatch]["shade_700"]);
return;
}
}
StatusBar.backgroundColorByHexString(shadeColor2(color, -0.1));
} else {
StatusBar.backgroundColorByHexString(color);
}
} else if (event.data.startsWith("scancode ")) {
var callbackcode = event.data.split(" ").slice(1).join(" ");
console.log("got scancode " + callbackcode);
try {
if (scanningactive) {
console.log("Scanner already active, ignoring request.");
return;
}
})
scanningactive = true;
cordova.plugins.barcodeScanner.scan(
function (result) {
scanningactive = false;
if (!result.cancelled) {
var iframe = document.getElementById("appframe");
iframe.contentWindow.postMessage("coderesult~|~" + callbackcode + "~|~" + result.text, "*");
}
},
function (error) {
scanningactive = false;
navigator.notification.alert("Scanning failed: " + error, null, "Error", 'Dismiss');
},
{
"showFlipCameraButton": true,
"prompt": "Scan Code"
}
);
} catch (ex) {
scanningactive = false;
navigator.notification.alert(ex.message, null, "Error", 'Dismiss');
}
}
setTimeout(navigator.splashscreen.hide, 500);
}, false);

File diff suppressed because one or more lines are too long

@ -0,0 +1,59 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function loadHomePage() {
$.post(localStorage.getItem("syncurl"), {
username: localStorage.getItem("username"),
key: localStorage.getItem("key"),
action: "listapps"
}, function (data) {
if (data.status === 'OK') {
loadingProgressDialog.setProgress(80);
var appcards = [];
Object.keys(data.apps).forEach(function (k) {
var app = data.apps[k];
var iconurl = app.icon;
if (!app.icon.startsWith("http")) {
iconurl = app.url + app.icon;
}
if (!app.card) {
return;
}
appcards.push({
api: app.mobileapi,
url: app.url,
icon: iconurl,
title: app.title,
text: app.card.string,
color: app.card.color
});
});
loadingProgressDialog.setProgress(90);
router.navigate("/home", {
context: {
appcards: appcards
}
});
$(".view-main").on("click", "#applist .applist-item", function () {
launchapp($(this).data("api"), $(this).data("url"), $(this).data("icon"), $(this).data("title"));
});
loadingProgressDialog.setProgress(100);
loadingProgressDialog.close();
} else {
loadingProgressDialog.close();
app.dialog.alert(data.msg, "Error", function () {
restartApplication();
});
}
}, "json").fail(function () {
loadingProgressDialog.close();
app.dialog.alert("Could not connect to the server. Try again later.", "Error", function () {
restartApplication();
});
});
}

@ -0,0 +1,127 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var shown_notifications = [];
var app = new Framework7({
root: "#app",
name: "Business",
id: "com.netsyms.BusinessMobile",
routes: routes,
dialog: {
buttonOK: "Dismiss"
}
});
var router = app.router;
var mainView = app.views.create('.view-main', {
url: "/"
});
var loadingProgressDialog;
/**
* Thanks to https://stackoverflow.com/a/13542669
* @param {type} color
* @param {type} percent
* @returns {String}
*/
function shadeColor2(color, percent) {
var f = parseInt(color.slice(1), 16), t = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = f >> 16, G = f >> 8 & 0x00FF, B = f & 0x0000FF;
return "#" + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1);
}
/**
* Load the app.html view and open an app with nativeish Android UI elements
* @param String id Application ID
* @param String api Path to the mobile API
* @param String url Base URL of the app
* @param String icon URL to the app icon
* @param String title Friendly app name
* @param boolean injectcode (optional, default true) Whether or not to inject UI modification code into the app
* @param boolean shownavbar (optional, default false) Whether or not to show the navbar at the top of the screen.
* @returns {undefined}
*/
function openapp(id, api, url, icon, title, injectcode, shownavbar) {
$('#content-zone').fadeOut(300, function () {
$('#content-zone').load("views/app.html", function () {
$('#content-zone').fadeIn(300, function () {
launchapp(id, api, url, icon, title, injectcode, shownavbar);
});
});
});
}
function restartApplication() {
navigator.splashscreen.show();
// We're doing the timeout so we don't run afoul of server-side rate limiting
setTimeout(function () {
window.location = "index.html";
}, 3000);
}
// Handle back button to close things
document.addEventListener("backbutton", function (event) {
if (isconfigvalid()) {
if ($("#appframe").length && historyctr > 0) {
console.log("going back");
var iframe = document.getElementById("appframe");
iframe.contentWindow.postMessage("goback", "*");
historyctr--;
} else if (_returnscreen != null) {
openscreen(_returnscreen, "FADE");
_returnscreen = null;
} else {
openscreen("home", "FADE");
}
} else {
if (_returnscreen != null) {
openscreen(_returnscreen, "FADE");
_returnscreen = null;
}
}
}, false);
document.addEventListener("deviceready", function () {
loadingProgressDialog = app.dialog.progress('Loading...', 0);
loadingProgressDialog.setText('');
if (cordova.platformId == 'android') {
StatusBar.backgroundColorByHexString("#1976d2");
}
// Enable/disable jQuery animations depending on user preference
$.fx.off = !(localStorage.getItem("animations") === null || localStorage.getItem("animations") === "true");
if (isconfigvalid()) {
loadingProgressDialog.setProgress(20);
loadingProgressDialog.setText('Account');
getuserinfo(function () {
loadingProgressDialog.setProgress(50);
loadingProgressDialog.setText('Notifications');
// Setup notification sync
initNotifications();
loadingProgressDialog.setProgress(60);
// Load homepage/dashboard
loadingProgressDialog.setText('Apps');
loadHomePage();
});
} else {
// Try to recover data from NativeStorage back to localStorage
recoveraccounts(function (ok) {
if (ok) {
// Success, restart app to reload from localStorage
restartApplication();
} else {
// No account data found, open setup
router.navigate({
name: 'setup1'
});
}
})
}
setTimeout(navigator.splashscreen.hide, 500);
}, false);

@ -0,0 +1,94 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function displayNotifications(callback) {
$.post(localStorage.getItem("syncurl"), {
username: localStorage.getItem("username"),
key: localStorage.getItem("key"),
action: "checknotifications"
}, function (data) {
if (data.status === 'OK') {
for (var i = 0; i < data.notifications.length; i++) {
var n = data.notifications[i];
if (n.seen || shown_notifications.includes(n.id)) {
continue;
}
cordova.plugins.notification.local.schedule([{
title: n.title,
text: n.content,
actions: [
{id: 'mark_read', title: "Mark Read"}
],
id: n.id,
lockscreen: !n.sensitive
}]);
shown_notifications.push(n.id);
}
}
if (typeof callback == 'function') {
callback();
}
}, "json").fail(function () {
if (typeof callback == 'function') {
callback();
}
});
}
function initForegroundNotifications() {
cordova.plugins.notification.local.setDefaults({
led: true,
color: '#2196F3',
vibrate: true,
smallIcon: "res://ic_notification"
});
cordova.plugins.notification.local.on("mark_read", function (notification) {
$.post(localStorage.getItem("syncurl"), {
username: localStorage.getItem("username"),
key: localStorage.getItem("key"),
password: localStorage.getItem("password"),
action: "readnotification",
id: notification.id
});
});
setInterval(displayNotifications, 30 * 1000);
if (typeof cordova.plugins.notification.local.launchDetails === 'undefined') {
displayNotifications();
}
}
function initBackgroundNotifications() {
var BackgroundFetch = window.BackgroundFetch;
// Your background-fetch handler.
var fetchCallback = function () {
console.log('[js] BackgroundFetch event received');
displayNotifications(function () {
BackgroundFetch.finish();
});
};
var failureCallback = function (error) {
console.log('- BackgroundFetch failed', error);
};
BackgroundFetch.configure(fetchCallback, failureCallback, {
minimumFetchInterval: 1,
stopOnTerminate: false,
startOnBoot: true,
forceReload: false,
enableHeadless: true
});
}
function initNotifications() {
initForegroundNotifications();
initBackgroundNotifications();
}

@ -0,0 +1,126 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
setupusername = "";
setuppassword = "";
setupsynckey = "";
setupsyncurl = "";
if (localStorage.getItem("firstrun") === null) {
$("#setuptitle").text("Setup");
$(".firstrun-only").css("display", "");
}
$('#use-security').click(function () {
if (this.checked) {
$('#protocol-select').text("https://");
} else {
$('#protocol-select').text("http://");
}
});
/* Detect if the user typed "http[s]://" into the URL box and correct for it */
$("#syncurl").blur(function () {
if ($('#syncurl').val().toLowerCase().startsWith("https://")) {
$('#syncurl').val($('#syncurl').val().replace(/https\:\/\//ig, ""));
$('#protocol-select').text("https://");
$('#use-security').prop('checked', true);
} else if ($('#syncurl').val().toLowerCase().startsWith("http://")) {
$('#syncurl').val($('#syncurl').val().replace(/http\:\/\//ig, ""));
$('#protocol-select').text("http://");
$('#use-security').prop('checked', false);
}
});
$("#key").on("keyup", function () {
if (window.getSelection().toString() !== '') {
return;
}
var text = $('#key').val().replace(/\s+/g, '');
var formatted = "";
for (var i = 1; i <= text.length; i++) {
formatted = formatted + text[i - 1];
if (i % 5 == 0 && i > 1 && i < text.length) {
// add a space every 5 characters,
// unless it's the first character
// or the last character
formatted = formatted + " ";
}
}
$('#key').val(formatted.toUpperCase());
});
$('#username').on("keyup", function () {
$('#username').val($('#username').val().toLowerCase());
});
function manualsetup() {
if ($('#syncurl').val().toLowerCase().startsWith("http")) {
var syncurl = $('#syncurl').val();
} else {
var syncurl = $('#protocol-select').text() + $('#syncurl').val();
}
var username = $('#username').val();
var key = $('#key').val().replace(/\s+/g, '');
checkAndSave(syncurl, username, key);
}
function manualshow() {
$('#manual_setup').css('display', 'block');
}
function checkAndSave(syncurl, username, key) {
$.post(syncurl, {
username: username,
key: key,
action: "check_key"
}, function (data) {
if (data.status === 'OK') {
setupusername = username;
setupsyncurl = syncurl;
setupsynckey = key;
router.navigate({
name: 'setup2'
});
} else {
navigator.notification.alert(data.msg, null, "Error", 'Dismiss');
}
}, "json").fail(function () {
navigator.notification.alert("Could not connect to the server. Try again.", null, "Error", 'Dismiss');
});
}
function scanCode() {
try {
cordova.plugins.barcodeScanner.scan(
function (result) {
if (!result.cancelled) {
if (!result.text.startsWith("bizsync://")) {
navigator.notification.alert("Invalid sync code. Try again.", null, "Error", 'Dismiss');
return;
}
var url = result.text.replace("bizsync://", "");
var parts = url.split("/");
var syncurl = parts[0].replace(/\\/g, "/");
var username = parts[1];
var key = parts[2];
checkAndSave(syncurl, username, key);
}
},
function (error) {
navigator.notification.alert("Scanning failed: " + error, null, "Error", 'Dismiss');
},
{
"showFlipCameraButton": false,
"prompt": "Scan mobile sync QR code."
}
);
} catch (ex) {
navigator.notification.alert(ex.message, null, "Error", 'Dismiss');
}
}

@ -0,0 +1,9 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.app-icon {
border: 1px solid grey;
border-radius: 20%;
}

Before

Width:  |  Height:  |  Size: 199 B

After

Width:  |  Height:  |  Size: 199 B

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 274 B

Before

Width:  |  Height:  |  Size: 389 B

After

Width:  |  Height:  |  Size: 389 B

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 320 B

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

@ -0,0 +1,320 @@
/*
Based on the file
https://github.com/srekanui/google-material-color-palette-json/blob/master/lib/palette.json
MIT License
Copyright (c) 2016 Sravan Kumar Rekandar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
_PALETTE = {
"red": {
"shade_50": "#ffebee",
"shade_100": "#ffcdd2",
"shade_200": "#ef9a9a",
"shade_300": "#e57373",
"shade_400": "#ef5350",
"shade_500": "#f44336",
"shade_600": "#e53935",
"shade_700": "#d32f2f",
"shade_800": "#c62828",
"shade_900": "#b71c1c",
"shade_A100": "#ff8a80",
"shade_A200": "#ff5252",
"shade_A400": "#ff1744",
"shade_A700": "#d50000"
},
"pink": {
"shade_50": "#fce4ec",
"shade_100": "#f8bbd0",
"shade_200": "#f48fb1",
"shade_300": "#f06292",
"shade_400": "#ec407a",
"shade_500": "#e91e63",
"shade_600": "#d81b60",
"shade_700": "#c2185b",
"shade_800": "#ad1457",
"shade_900": "#880e4f",
"shade_A100": "#ff80ab",
"shade_A200": "#ff4081",
"shade_A400": "#f50057",
"shade_A700": "#c51162"
},
"purple": {
"shade_50": "#f3e5f5",
"shade_100": "#e1bee7",
"shade_200": "#ce93d8",
"shade_300": "#ba68c8",
"shade_400": "#ab47bc",
"shade_500": "#9c27b0",
"shade_600": "#8e24aa",
"shade_700": "#7b1fa2",
"shade_800": "#6a1b9a",
"shade_900": "#4a148c",
"shade_A100": "#ea80fc",
"shade_A200": "#e040fb",
"shade_A400": "#d500f9",
"shade_A700": "#aa00ff"
},
"deepPurple": {
"shade_50": "#ede7f6",
"shade_100": "#d1c4e9",
"shade_200": "#b39ddb",
"shade_300": "#9575cd",
"shade_400": "#7e57c2",
"shade_500": "#673ab7",
"shade_600": "#5e35b1",
"shade_700": "#512da8",
"shade_800": "#4527a0",
"shade_900": "#311b92",
"shade_A100": "#b388ff",
"shade_A200": "#7c4dff",
"shade_A400": "#651fff",
"shade_A700": "#6200ea"
},
"indigo": {
"shade_50": "#e8eaf6",
"shade_100": "#c5cae9",
"shade_200": "#9fa8da",
"shade_300": "#7986cb",
"shade_400": "#5c6bc0",
"shade_500": "#3f51b5",
"shade_600": "#3949ab",
"shade_700": "#303f9f",
"shade_800": "#283593",
"shade_900": "#1a237e",
"shade_A100": "#8c9eff",
"shade_A200": "#536dfe",
"shade_A400": "#3d5afe",
"shade_A700": "#304ffe"
},
"blue": {
"shade_50": "#e3f2fd",
"shade_100": "#bbdefb",
"shade_200": "#90caf9",
"shade_300": "#64b5f6",
"shade_400": "#42a5f5",
"shade_500": "#2196f3",
"shade_600": "#1e88e5",
"shade_700": "#1976d2",
"shade_800": "#1565c0",
"shade_900": "#0d47a1",
"shade_A100": "#82b1ff",
"shade_A200": "#448aff",
"shade_A400": "#2979ff",
"shade_A700": "#2962ff"
},
"lightBlue": {
"shade_50": "#e1f5fe",
"shade_100": "#b3e5fc",
"shade_200": "#81d4fa",
"shade_300": "#4fc3f7",
"shade_400": "#29b6f6",
"shade_500": "#03a9f4",
"shade_600": "#039be5",
"shade_700": "#0288d1",
"shade_800": "#0277bd",
"shade_900": "#01579b",
"shade_A100": "#80d8ff",
"shade_A200": "#40c4ff",
"shade_A400": "#00b0ff",
"shade_A700": "#0091ea"
},
"cyan": {
"shade_50": "#e0f7fa",
"shade_100": "#b2ebf2",
"shade_200": "#80deea",
"shade_300": "#4dd0e1",
"shade_400": "#26c6da",
"shade_500": "#00bcd4",
"shade_600": "#00acc1",
"shade_700": "#0097a7",
"shade_800": "#00838f",
"shade_900": "#006064",
"shade_A100": "#84ffff",
"shade_A200": "#18ffff",
"shade_A400": "#00e5ff",
"shade_A700": "#00b8d4"
},
"teal": {
"shade_50": "#e0f2f1",
"shade_100": "#b2dfdb",
"shade_200": "#80cbc4",
"shade_300": "#4db6ac",
"shade_400": "#26a69a",
"shade_500": "#009688",
"shade_600": "#00897b",
"shade_700": "#00796b",
"shade_800": "#00695c",
"shade_900": "#004d40",
"shade_A100": "#a7ffeb",
"shade_A200": "#64ffda",
"shade_A400": "#1de9b6",
"shade_A700": "#00bfa5"
},
"green": {
"shade_50": "#e8f5e9",
"shade_100": "#c8e6c9",
"shade_200": "#a5d6a7",
"shade_300": "#81c784",
"shade_400": "#66bb6a",
"shade_500": "#4caf50",
"shade_600": "#43a047",
"shade_700": "#388e3c",
"shade_800": "#2e7d32",
"shade_900": "#1b5e20",
"shade_A100": "#b9f6ca",
"shade_A200": "#69f0ae",
"shade_A400": "#00e676",
"shade_A700": "#00c853"
},
"lightGreen": {
"shade_50": "#f1f8e9",
"shade_100": "#dcedc8",
"shade_200": "#c5e1a5",
"shade_300": "#aed581",
"shade_400": "#9ccc65",
"shade_500": "#8bc34a",
"shade_600": "#7cb342",
"shade_700": "#689f38",
"shade_800": "#558b2f",
"shade_900": "#33691e",
"shade_A100": "#ccff90",
"shade_A200": "#b2ff59",
"shade_A400": "#76ff03",
"shade_A700": "#64dd17"
},
"lime": {
"shade_50": "#f9fbe7",
"shade_100": "#f0f4c3",
"shade_200": "#e6ee9c",
"shade_300": "#dce775",
"shade_400": "#d4e157",
"shade_500": "#cddc39",
"shade_600": "#c0ca33",
"shade_700": "#afb42b",
"shade_800": "#9e9d24",
"shade_900": "#827717",
"shade_A100": "#f4ff81",
"shade_A200": "#eeff41",
"shade_A400": "#c6ff00",
"shade_A700": "#aeea00"
},
"yellow": {
"shade_50": "#fffde7",
"shade_100": "#fff9c4",
"shade_200": "#fff59d",
"shade_300": "#fff176",
"shade_400": "#ffee58",
"shade_500": "#ffeb3b",
"shade_600": "#fdd835",
"shade_700": "#fbc02d",
"shade_800": "#f9a825",
"shade_900": "#f57f17",
"shade_A100": "#ffff8d",
"shade_A200": "#ffff00",
"shade_A400": "#ffea00",
"shade_A700": "#ffd600"
},
"amber": {
"shade_50": "#fff8e1",
"shade_100": "#ffecb3",
"shade_200": "#ffe082",
"shade_300": "#ffd54f",
"shade_400": "#ffca28",
"shade_500": "#ffc107",
"shade_600": "#ffb300",
"shade_700": "#ffa000",
"shade_800": "#ff8f00",
"shade_900": "#ff6f00",
"shade_A100": "#ffe57f",
"shade_A200": "#ffd740",
"shade_A400": "#ffc400",
"shade_A700": "#ffab00"
},
"orange": {
"shade_50": "#fff3e0",
"shade_100": "#ffe0b2",
"shade_200": "#ffcc80",
"shade_300": "#ffb74d",
"shade_400": "#ffa726",
"shade_500": "#ff9800",
"shade_600": "#fb8c00",
"shade_700": "#f57c00",
"shade_800": "#ef6c00",
"shade_900": "#e65100",
"shade_A100": "#ffd180",
"shade_A200": "#ffab40",
"shade_A400": "#ff9100",
"shade_A700": "#ff6d00"
},
"deepOrange": {
"shade_50": "#fbe9e7",
"shade_100": "#ffccbc",
"shade_200": "#ffab91",
"shade_300": "#ff8a65",
"shade_400": "#ff7043",
"shade_500": "#ff5722",
"shade_600": "#f4511e",
"shade_700": "#e64a19",
"shade_800": "#d84315",
"shade_900": "#bf360c",
"shade_A100": "#ff9e80",
"shade_A200": "#ff6e40",
"shade_A400": "#ff3d00",
"shade_A700": "#dd2c00"
},
"brown": {
"shade_50": "#efebe9",
"shade_100": "#d7ccc8",
"shade_200": "#bcaaa4",
"shade_300": "#a1887f",
"shade_400": "#8d6e63",
"shade_500": "#795548",
"shade_600": "#6d4c41",
"shade_700": "#5d4037",
"shade_800": "#4e342e",
"shade_900": "#3e2723"
},
"grey": {
"shade_50": "#fafafa",
"shade_100": "#f5f5f5",
"shade_200": "#eeeeee",
"shade_300": "#e0e0e0",
"shade_400": "#bdbdbd",
"shade_500": "#9e9e9e",
"shade_600": "#757575",
"shade_700": "#616161",
"shade_800": "#424242",
"shade_900": "#212121"
},
"blueGrey": {
"shade_50": "#eceff1",
"shade_100": "#cfd8dc",
"shade_200": "#b0bec5",
"shade_300": "#90a4ae",
"shade_400": "#78909c",
"shade_500": "#607d8b",
"shade_600": "#546e7a",
"shade_700": "#455a64",
"shade_800": "#37474f",
"shade_900": "#263238"
}
}

@ -0,0 +1,6 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="app">
<iframe id="appframe" src="" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0px;"></iframe>
</div>

@ -0,0 +1,42 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="home">
<div class="navbar">
<div class="navbar-inner">
<div class="title">Business</div>
</div>
</div>
<!--<div class="toolbar">
<div class="toolbar-inner">
<a href="#" class="link">Link 1</a>
<a href="#" class="link">Link 2</a>
</div>
</div>-->
<div class="page-content">
<div class="card">
<div class="card-header">Apps</div>
<div class="card-content">
<div class="list media-list">
<ul id="applist">
{{#each appcards}}
<li class="item-content applist-item" data-api="{{api}}" data-url="{{url}}" data-icon="{{icon}}" data-title="{{title}}" >
<div class="item-media"><img src="{{icon}}" width="44"/></div>
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">{{title}}</div>
</div>
<div class="item-subtitle">{{text}}</div>
</div>
</li>
{{/each}}
</ul>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,78 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="setup1">
<div class="navbar">
<div class="navbar-inner">
<div class="title">Link Account</div>
</div>
</div>
<div class="page-content">
<div class="block">
<p>Open AccountHub on another device and go to Sync settings. Generate a mobile sync code, then press the button below to scan it.</p>
<div class="row">
<button class="col button button-fill" onclick="scanCode()" id="scancodebtn">Scan Code</button>
<button class="col button" onclick="manualshow()" id="manualsetupbtn">Manual Setup</button>
</div>
</div>
<div id="manual_setup" class="block" style="display: none;">
<div class="list">
<ul>
<li class="item-content item-input">
<div class="item-inner">
<div class="item-input-wrap">
<input type="text" id="username" placeholder="Username" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input">
<div class="item-inner">
<div class="item-input-wrap">
<input type="text" id="key" class="form-control" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li class="item-content item-input">
<div class="item-inner">
<div class="item-title item-floating-label" id="protocol-select">https://</div>
<div class="item-input-wrap">
<input type="url" id="syncurl" placeholder="URL" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
<span class="input-clear-button"></span>
</div>
</div>
</li>
<li>
<label class="item-checkbox item-content">
<input type="checkbox" id="use-security" checked="checked" />
<i class="icon icon-checkbox"></i>
<span class="item-inner">
<span class="item-title">Use secure connection</span>
</span>
</label>
</li>
</ul>
</div>
<div class="button button-fill" onclick="manualsetup()">
Continue
</div>
</div>
</div>
<script src="js/setup1.js"></script>
</div>

@ -0,0 +1,61 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="setup2">
<div class="navbar">
<div class="navbar-inner">
<div class="title">Link Account</div>
</div>
</div>
<div class="page-content">
<div class="block">
<p>Enter your password, then tap Finish.</p>
<div class="list">
<ul>
<li class="item-content item-input">
<div class="item-media"><i class="fas fa-key"></i></div>
<div class="item-inner">
<div class="item-input-wrap">
<input type="password" id="passbox" placeholder="Password">
<span class="input-clear-button"></span>
</div>
</div>
</li>
</ul>
</div>
<button class="button button-fill" onclick="savePassword()">Finish</button>
</div>
</div>
<script>
function savePassword() {
$.post(setupsyncurl, {
username: setupusername,
key: setupsynckey,
password: $('#passbox').val(),
action: "check_password"
}, function (data) {
if (data.status === 'OK') {
setuppassword = $('#passbox').val();
var accid = addaccount(setupusername, setuppassword, setupsyncurl, setupsynckey);
switchaccount(accid);
localStorage.setItem("firstrun", "1");
navigator.notification.alert("Account connected!", null, "Success", 'Continue');
restartApplication();
} else {
navigator.notification.alert(data.msg, null, "Error", 'Dismiss');
}
}, "json").fail(function () {
navigator.notification.alert("Could not connect to the server. Try again later.", null, "Error", 'Dismiss');
});
}
</script>
</div>

@ -0,0 +1,29 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
var routes = [
{
path: '/home',
templateUrl: './pages/home.html',
name: 'home'
},
{
path: '/setup/1',
url: './pages/setup1.html',
name: 'setup1'
},
{
path: '/setup/2',
url: './pages/setup2.html',
name: 'setup2'
},
{
path: '/app',
url: './pages/app.html',
name: 'app'
}
];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,174 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<iframe id="appframe" src="" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0px;"></iframe>
<iframe id="loadframe" src="views/appspinner.html" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0px; z-index: 999999;"></iframe>
<script src="js/material-palette.js"></script>
<script>
var historyctr = -1;
/**
* Open an app with native Android UI elements
* @param String id Application ID
* @param String api Path to the mobile API
* @param String url Base URL of the app
* @param String icon URL to the app icon
* @param String title Friendly app name
* @param boolean injectcode (optional, default true) Whether or not to inject UI modification code into the app
* @param boolean shownavbar (optional, default false) Whether or not to show the navbar at the top of the screen.
* @returns {undefined}
*/
function launchapp(id, api, url, icon, title, injectcode, shownavbar) {
if (typeof shownavbar === 'undefined' || shownavbar === false) {
setnavbar(false);
} else {
setnavbar("app", title);
$('#appframe').css('top', '75px');
}
$.post(url + api, {
username: localStorage.getItem("username"),
key: localStorage.getItem("key"),
password: localStorage.getItem("password"),
action: "start_session"
}, function (data) {
if (data.status === 'OK') {
document.getElementById("loadframe").contentWindow.postMessage("loginok", "*");
if (typeof injectcode === 'undefined' || injectcode === true) {
$('#appframe').on("load", function () {
$("#loadframe").fadeOut(300);
historyctr++;
// Do this right away so it's a bit harder to glitch
$('#appframe').contents().find('.navbar-right').html("<li><a onclick='quitapp()'><i class='fa fa-sign-out fa-fw'></i> Back to Menu</a></li>");
// Moved BS4 code to sidemenu.js
$.get("css/sidemenu.css", function (style) {
$('#appframe').contents().find('head').append("<style>" + style + "</style>");
$.get("js/polyfills.js", function (script) {
$('#appframe').contents().find('body').append("<script>" + script + "<\/script>");
$.get("js/jquery-ui.min.js", function (script) {
$('#appframe').contents().find('body').append("<script>" + script + "<\/script>");
$.get("js/hammer.min.js", function (script) {
$('#appframe').contents().find('body').append("<script>" + script + "<\/script>");
$.get("js/sidemenu.js", function (script) {
script = script.replace("__JQUERYFXOFF__", !(localStorage.getItem("animations") === null || localStorage.getItem("animations") === "true"));
script = script.replace("__USERNAME__", userinfo.realname);
script = script.replace("__LOGO__", icon);
$('#appframe').contents().find('body').append("<script>" + script + "<\/script>");
});
});
});
});
});
});
} else {
// Only inject minimal CSS
$('#appframe').on("load", function () {
$.get("css/inject_mini.css", function (style) {
$('#appframe').contents().find('head').append("<style>" + style + "</style>");
});
});
}
$('#appframe').attr('src', url);
} else {
navigator.notification.alert(data.msg, null, "Error", 'Dismiss');
openscreen("home");
}
}, "json").fail(function () {
navigator.notification.alert("Could not connect to the server. Try again later.", null, "Error", 'Dismiss');
openscreen("home");
});
}
var scanningactive = false;
var dedup = [];
window.addEventListener('message', function (event) {
console.log("app event: " + event.data);
setTimeout(function () {
dedup = [];
}, 500);
if (dedup.includes(event.data)) {
return;
}
dedup.push(event.data);
if (event.data == "quit") {
openscreen("home");
} else if (event.data == "goneback") {
historyctr -= 1;
} else if (event.data.startsWith("load_bs_version ")) {
var bootstrap_version = event.data.split(" ")[1];
var nav_breakpoint = event.data.split(" ")[2];
var bs_file = "bs3";
if (bootstrap_version.startsWith("4")) {
bs_file = "bs4";
}
$.get("css/sidemenu-" + bs_file + ".css", function (style) {
if (bs_file == "bs4") {
var break_px = "767";
switch (nav_breakpoint) {
case "sm":
break_px = "575";
break;
case "md":
break_px = "767";
break;
case "lg":
break_px = "991";
break;
case "xl":
break_px = "1199";
break;
}
style = style.replace("max-width: 767px", "max-width: " + break_px + "px");
}
$('#appframe').contents().find('head').append("<style>" + style + "</style>");
});
} else if (event.data.startsWith("setcolor ")) {
var color = event.data.split(" ", 2)[1];
if (cordova.platformId == 'android') {
window.plugins.headerColor.tint(color);
for (var swatch in _PALETTE) {
if (color == _PALETTE[swatch]["shade_500"]) {
StatusBar.backgroundColorByHexString(_PALETTE[swatch]["shade_700"]);
return;
}
}
StatusBar.backgroundColorByHexString(shadeColor2(color, -0.1));
} else {
StatusBar.backgroundColorByHexString(color);
}
} else if (event.data.startsWith("scancode ")) {
var callbackcode = event.data.split(" ").slice(1).join(" ");
console.log("got scancode " + callbackcode);
try {
if (scanningactive) {
console.log("Scanner already active, ignoring request.");
return;
}
scanningactive = true;
cordova.plugins.barcodeScanner.scan(
function (result) {
scanningactive = false;
if (!result.cancelled) {
var iframe = document.getElementById("appframe");
iframe.contentWindow.postMessage("coderesult~|~" + callbackcode + "~|~" + result.text, "*");
}
},
function (error) {
scanningactive = false;
navigator.notification.alert("Scanning failed: " + error, null, "Error", 'Dismiss');
},
{
"showFlipCameraButton": true,
"prompt": "Scan Code"
}
);
} catch (ex) {
scanningactive = false;
navigator.notification.alert(ex.message, null, "Error", 'Dismiss');
}
}
}, false);
if (userinfo == null) {
getuserinfo();
}
</script>

@ -1,76 +0,0 @@
<!DOCTYPE html>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<title>Loading</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
html, body {
height: 100%;
background-color: white;
font-family: "Roboto","Helvetica Neue",Helvetica,Arial,sans-serif;
}
body {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
#statustext {
text-align: center;
}
#giveup {
display: none;
margin-top: 5px;
border: none;
border-radius: 3px;
box-shadow: 1px 1px 4px rgba(0,0,0,0.4);
padding: 6px 16px;
font-size: 13px;
line-height: 1.846;
color: #fff;
background-color: #2196f3;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
white-space: nowrap;
text-decoration: none;
box-sizing: border-box;
text-transform: uppercase;
position: relative;
}
</style>
<img src="cdvfile://localhost/assets/www/img/loader.gif" style="width: 65px; height: 65px;" alt="" onerror="this.onerror=null;this.src='cdvfile://localhost/bundle/www/img/loader.gif';"/>
<p id="statustext">Logging in...</p>
<br />
<div id="giveup" onclick="parent.postMessage('quit', '*');">Give up</div>
<script>
window.addEventListener('message', function (event) {
if (event.data == "loginok") {
document.getElementById("statustext").innerHTML = "Loading...";
setTimeout(function () {
document.getElementById("statustext").innerHTML = "Still loading...";
}, 5000);
setTimeout(function () {
document.getElementById("statustext").innerHTML = "Just a moment...";
document.getElementById("giveup").style.display = "inline-block";
}, 10000);
setTimeout(function () {
document.getElementById("statustext").innerHTML = "Well this is awkward.";
}, 20000);
setTimeout(function () {
document.getElementById("statustext").innerHTML = "[fidgets nervously]";
}, 25000);
setTimeout(function () {
document.getElementById("statustext").innerHTML = "Either something is broken or your connection is too slow.";
}, 30000);
}
});
</script>

@ -1,49 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="app-dock-container">
<div class="app-dock" id="app-dock">
<div style="margin-top: 50px;">
<img src="img/loader.gif" style="width: 65px; height: 65px;" alt=""/>
</div>
<div style="width: 100%;"></div>
<p class="loading-text">Loading...</p>
</div>
</div>
<script>
function loadapps() {
$(".loading-text").html("Loading Apps...");
$.post(localStorage.getItem("syncurl"), {
username: localStorage.getItem("username"),
key: localStorage.getItem("key"),
action: "listapps"
}, function (data) {
if (data.status === 'OK') {
$("#loading-text").text("One moment...");
$('#app-dock').html("");
Object.keys(data.apps).forEach(function (k) {
var app = data.apps[k];
var iconurl = app.icon;
if (!app.icon.startsWith("http")) {
iconurl = app.url + app.icon;
}
$("<div class=\"app-dock-item\" onclick=\"openapp('" + k + "', '" + app.mobileapi + "', '" + app.url + "', '" + iconurl + "', '" + app.title + "')\"><p><img src=\"" + iconurl + "\" class=\"img-responsive app-icon\" /><span>" + app.title + "</span></p></div>").hide().appendTo("#app-dock").fadeIn(200);
});
} else {
navigator.notification.alert(data.msg, null, "Error", 'Dismiss');
openscreen("homeloaderror");
}
}, "json").fail(function () {
navigator.notification.alert("Could not connect to the server. Try again later.", null, "Error", 'Dismiss');
openscreen("homeloaderror");
});
}
if (isconfigvalid()) {
setnavbar("home");
loadapps();
} else {
openscreen("setup1");
}
</script>

@ -1,163 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<br />
<div class="panel panel-blue">
<div class="panel-heading">
<h3 class="panel-title" id="setuptitle">Add Account</h3>
</div>
<div class="panel-body">
<p>
<span class="firstrun-only" style="display: none;">
Welcome! There's a few things we need to do to get everything ready.
<br /><br />
</span>
Open AccountHub on another device and go to Sync settings. Generate a mobile sync code, then press the button below to scan it.
</p>
<span class="btn btn-primary" onclick="scanCode()" id="scancodebtn">
<i class="fa fa-qrcode"></i> Scan Code
</span>
<span class="btn btn-link" onclick="manualshow()" id="manualsetupbtn">
Manual Setup
</span>
<div id="manual_setup" class="well" style="display: none;">
<input type="text" id="username" class="form-control" placeholder="Username" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" /> <br />
<input type="text" id="key" class="form-control" placeholder="Sync key" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" /> <br />
<div class="input-group" style="margin-left: -20px;">
<span class="input-group-addon" id="protocol-select">https://</span>
<input type="text" id="syncurl" class="form-control" placeholder="URL" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
</div> <br />
<div class="checkbox">
<label>
<input type="checkbox" id="use-security" checked > Use secure connection
</label>
</div>
<br />
<div class="btn btn-primary" onclick="manualsetup()">
Continue
</div>
</div>
</div>
</div>
<script>
setupusername = "";
setuppassword = "";
setupsynckey = "";
setupsyncurl = "";
if (localStorage.getItem("firstrun") === null) {
$("#setuptitle").text("Setup");
$(".firstrun-only").css("display", "");
}
$('#use-security').click(function () {
if (this.checked) {
$('#protocol-select').text("https://");
} else {
$('#protocol-select').text("http://");
}
});
/* Detect if the user typed "http[s]://" into the URL box and correct for it */
$("#syncurl").blur(function () {
if ($('#syncurl').val().toLowerCase().startsWith("https://")) {
$('#syncurl').val($('#syncurl').val().replace(/https\:\/\//ig, ""));
$('#protocol-select').text("https://");
$('#use-security').prop('checked', true);
} else if ($('#syncurl').val().toLowerCase().startsWith("http://")) {
$('#syncurl').val($('#syncurl').val().replace(/http\:\/\//ig, ""));
$('#protocol-select').text("http://");
$('#use-security').prop('checked', false);
}
});
$("#key").on("keyup", function () {
if (window.getSelection().toString() !== '') {
return;
}
var text = $('#key').val().replace(/\s+/g, '');
var formatted = "";
for (var i = 1; i <= text.length; i++) {
formatted = formatted + text[i - 1];
if (i % 5 == 0 && i > 1 && i < text.length) {
// add a space every 5 characters,
// unless it's the first character
// or the last character
formatted = formatted + " ";
}
}
$('#key').val(formatted.toUpperCase());
});
$('#username').on("keyup", function () {
$('#username').val($('#username').val().toLowerCase());
});
function manualsetup() {
if ($('#syncurl').val().toLowerCase().startsWith("http")) {
var syncurl = $('#syncurl').val();
} else {
var syncurl = $('#protocol-select').text() + $('#syncurl').val();
}
var username = $('#username').val();
var key = $('#key').val().replace(/\s+/g, '');
checkAndSave(syncurl, username, key);
}
function manualshow() {
$('#manual_setup').css('display', 'block');
}
function checkAndSave(syncurl, username, key) {
$.post(syncurl, {
username: username,
key: key,
action: "check_key"
}, function (data) {
if (data.status === 'OK') {
setupusername = username;
setupsyncurl = syncurl;
setupsynckey = key;
openscreen("setup2");
} else {
navigator.notification.alert(data.msg, null, "Error", 'Dismiss');
}
}, "json").fail(function () {
navigator.notification.alert("Could not connect to the server. Try again.", null, "Error", 'Dismiss');
});
}
function scanCode() {
try {
cordova.plugins.barcodeScanner.scan(
function (result) {
if (!result.cancelled) {
if (!result.text.startsWith("bizsync://")) {
navigator.notification.alert("Invalid sync code. Try again.", null, "Error", 'Dismiss');
return;
}
var url = result.text.replace("bizsync://", "");
var parts = url.split("/");
var syncurl = parts[0].replace(/\\/g, "/");
var username = parts[1];
var key = parts[2];
checkAndSave(syncurl, username, key);
}
},
function (error) {
navigator.notification.alert("Scanning failed: " + error, null, "Error", 'Dismiss');
},
{
"showFlipCameraButton": false,
"prompt": "Scan mobile sync QR code."
}
);
} catch (ex) {
navigator.notification.alert(ex.message, null, "Error", 'Dismiss');
}
}
setnavbar("setup");
</script>
Loading…
Cancel
Save