@@ -1283,88 +1071,109 @@
// the container which contains the toasts is also always the same
const toastContainer = $('#toaster');
- // return the actual function
- return (msg, colorClass) => {
- // check, if the same message is already showing
- if ($('div[data-msg="' + msg + '"]', toastContainer).length <= 0) {
-
- const toast = toastTemplate.clone();
- toast.find('.toast-body').html(msg);
- toast.attr('id', "");
- // storing the message in a data attribute to easier find it afterwards
- toast.attr('data-msg', msg);
- // set the correct class for the background color
- toast.addClass(colorClass || 'text-bg-primary');
- // when clicked or tapped onto, close it
- toast.click(() => toast.remove());
-
- toastContainer.append(toast);
-
- const toastBoostrap = bootstrap.Toast.getOrCreateInstance(toast);
- toastBoostrap.show();
-
- setTimeout(() => toast.remove(), 5500);
- }
+ // return the actual function
+ return (msg, colorClass) => {
+ // check, if the same message is already showing
+ if ($('div[data-msg="' + msg + '"]', toastContainer).length <= 0) {
+
+ const toast = toastTemplate.clone();
+ toast.find('.toast-body').html(msg);
+ toast.attr('id',"");
+ // storing the message in a data attribute to easier find it afterwards
+ toast.attr('data-msg', msg);
+ // set the correct class for the background color
+ toast.addClass(colorClass || 'text-bg-primary');
+ // when clicked or tapped onto, close it
+ toast.click(() => toast.remove());
+
+ toastContainer.append(toast);
+
+ const toastBoostrap = bootstrap.Toast.getOrCreateInstance(toast);
+ toastBoostrap.show();
+
+ setTimeout(() => toast.remove(), 5500);
}
- })(),
-
- // predefined color classes for easier usage
- info: msg => toaster.toast(msg),
- success: msg => toaster.toast(msg, 'text-bg-success'),
- warning: msg => toaster.toast(msg, 'text-bg-warning'),
- error: msg => toaster.toast(msg, 'text-bg-danger')
- }
-
- i18next.use(i18nextHttpBackend).init({
- backend: {
- loadPath: "http://" + host + "/locales/{{lng}}.json"
- },
- load: 'languageOnly',
- debug: true,
- fallbackLng: 'en',
- returnObjects: true,
- }, (err, t) => {
- localize = locI18next.init(i18next);
- localize('body');
- toaster.clear();
- // change the language if we found it in the local storage
- const lang = localStorage.getItem("language");
- if (lang === null) {
- i18next.changeLanguage(language.split("-")[0]);
- } else {
- i18next.changeLanguage(lang);
}
- });
- i18next.on('languageChanged', (lng) => {
- document.querySelector('#langSel').value = lng;
+ })(),
+
+ // predefined color classes for easier usage
+ info: msg => toaster.toast(msg),
+ success: msg => toaster.toast(msg, 'text-bg-success'),
+ warning: msg => toaster.toast(msg, 'text-bg-warning'),
+ error: msg => toaster.toast(msg, 'text-bg-danger')
+ }
+
+ function initI18N() {
+ // function to call for translating elements
+ let localize;
+ // check for language in local storage. if none is present, choose navigator language or userLanguage.
+ const startupLanguage = localStorage.getItem("language") || navigator.language || navigator.userLanguage;
+
+ // function to wrap the localize call into a reusable code block
+ function localization() {
if (localize) {
- localize('body');
+ if (i18next.resolvedLanguage) {
+ localize('body');
+ console.info('language changed to', i18next.resolvedLanguage);
+ // (re)initialize all popover buttons to get correct translations in the popovers
+ document.querySelectorAll('[data-bs-toggle="popover"]')
+ .forEach(popoverButton => {
+ new bootstrap.Popover(popoverButton, {html: true, trigger: 'focus'})
+ });
+ } else {
+ console.error("Language couldn't be loaded. Check your setup, maybe the translation files are misplaced or the remote server is not available.");
+ toaster.error("Language couldn't be loaded");
+ }
+ $('#splash').hide();
}
- document.querySelector('#menu').classList.remove("show") // Hide the menu again
+ }
+
+ i18next.use(i18nextHttpBackend)
+ .init({
+ backend: {
+ loadPath: "http://" + host + "/locales/{{lng}}.json"
+ },
+ load: 'languageOnly',
+ // debug: true,
+ lng: startupLanguage,
+ fallbackLng: 'en',
+ returnObjects: true,
+ }, (err, t) => {
+ localize = locI18next.init(i18next);
+ localization();
+ });
+ i18next.on('languageChanged', () => {
+ $('#langSel').val(i18next.resolvedLanguage); // set for the resolved language, which will be without locale
+ $('#navMenu').removeClass("show"); // Hide the menu again
+ console.info('language changes to', i18next.resolvedLanguage);
+ localization();
});
- document.querySelector('#langSel').addEventListener('change', (e) => {
- const lang = e.target.value;
- console.log(lang);
- if (lang !== i18next.language) {
+ $('#langSel').on('change', (e) => {
+ const lng = e.target.value;
+ if(lng !== i18next.language) {
+ $('#splash').show();
toaster.clear();
- localStorage.setItem("language", lang);
- i18next.changeLanguage(lang);
+ localStorage.setItem("language", lng);
+ i18next.changeLanguage(lng);
}
});
- document.getElementById('trackProgressDiv').addEventListener('click', function (e) {
- var bounds = this.getBoundingClientRect();
- var max = bounds.width;
- var pos = e.pageX - bounds.left;
- var percent = Math.round(pos / max * 100);
- console.log('track progress percentage:', percent);
- var myObj = {
- "trackProgress": {
- posPercent: percent
- }
- };
- var myJSON = JSON.stringify(myObj);
- socket.send(myJSON);
- });
+ }
+ initI18N();
+
+ document.getElementById('trackProgressDiv').addEventListener('click', function(e) {
+ var bounds = this.getBoundingClientRect();
+ var max = bounds.width;
+ var pos = e.pageX - bounds.left;
+ var percent = Math.round(pos / max * 100);
+ console.log('track progress percentage:', percent);
+ var myObj = {
+ "trackProgress": {
+ posPercent: percent
+ }
+ };
+ var myJSON = JSON.stringify(myObj);
+ socket.send(myJSON);
+ });
function postRendering(event, data) {
Object.keys(data.instance._model.data).forEach(function (key, index) {
@@ -1424,268 +1233,280 @@
}
});
- function doRest(path, callback, obj) {
- obj.url = path;
- obj.dataType = "json";
- obj.contentType = "application/json;charset=IBM437",
- obj.scriptCharset = "IBM437",
- obj.success = function (data, textStatus, jqXHR) {
- if (callback) {
- callback(data);
- }
- };
- obj.error = function (jqXHR, textStatus, errorThrown) {
- console.log("AJAX error: " + textStatus + ", " + errorThrown + ": " + obj.url);
- /*debugger; */
+ function doRest(path, callback, obj) {
+ obj.url = path;
+ obj.dataType = "json";
+ obj.contentType = "application/json;charset=IBM437",
+ obj.scriptCharset = "IBM437",
+ obj.success = function(data, textStatus, jqXHR) {
+ if(callback) {
+ callback(data);
+ }
};
- jQuery.ajax(obj);
- } /* doRest */
- function getData(path, callback) {
- doRest(path, callback, {
- method: "GET"
- });
- } /* getData */
- function deleteData(path, callback, _data) {
- doRest(path, callback, {
- method: "DELETE",
- data: _data
- });
- } /* deleteData */
- function patchData(path, callback, _data) {
- doRest(path, callback, {
- method: "PATCH",
- data: _data
- });
- } /* patchData */
- function postData(path, callback, _data) {
- doRest(path, callback, {
- method: "POST",
- data: _data
- });
- } /* postData */
- function putData(path, callback, _data) {
- doRest(path, callback, {
- method: "PUT",
- data: _data
- });
- } /* putData */
- async function restartDevice() {
- console.log("restart..");
- await fetch("http://" + host + "/restart", {
- method: "POST"
- });
+ obj.error = function(jqXHR, textStatus, errorThrown) {
+ console.log("AJAX error: " + textStatus + ", " + errorThrown + ": " + obj.url);
+ /*debugger; */
+ };
+ jQuery.ajax(obj);
+ } /* doRest */
+ function getData(path, callback) {
+ doRest(path, callback, {
+ method: "GET"
+ });
+ } /* getData */
+ function deleteData(path, callback, _data) {
+ doRest(path, callback, {
+ method: "DELETE",
+ data: _data
+ });
+ } /* deleteData */
+ function patchData(path, callback, _data) {
+ doRest(path, callback, {
+ method: "PATCH",
+ data: _data
+ });
+ } /* patchData */
+ function postData(path, callback, _data) {
+ doRest(path, callback, {
+ method: "POST",
+ data: _data
+ });
+ } /* postData */
+ function putData(path, callback, _data) {
+ doRest(path, callback, {
+ method: "PUT",
+ data: _data
+ });
+ } /* putData */
+ async function restartDevice() {
+ console.log("restart..");
+ await fetch("http://" + host + "/restart", {
+ method: "POST"
+ });
+ tryRedirect();
+ $('.modal-title').text(i18next.t("restart"));
+ $('.modal-body').html(i18next.t("restartinfo"));
+ $(".modal-body").removeAttr("style");
+ new bootstrap.Modal(document.getElementById('modalInfo')).toggle();
+ } /* restart */
+ async function shutdownDevice() {
+ console.log("shutdown..");
+ await fetch("http://" + host + "/shutdown", {
+ method: "POST"
+ });
+ $('.modal-title').text(i18next.t("shutdown"));
+ $('.modal-body').html(i18next.t("shutdowninfo"));
+ $(".modal-body").removeAttr("style");
+ new bootstrap.Modal(document.getElementById('modalInfo')).toggle();
+ setTimeout(function() {
tryRedirect();
- $('.modal-title').text(i18next.t("restart"));
- $('.modal-body').html(i18next.t("restartinfo"));
- $(".modal-body").removeAttr("style");
- new bootstrap.Modal(document.getElementById('modalInfo')).toggle();
- } /* restart */
- async function shutdownDevice() {
- console.log("shutdown..");
- await fetch("http://" + host + "/shutdown", {
- method: "POST"
- });
- $('.modal-title').text(i18next.t("shutdown"));
- $('.modal-body').html(i18next.t("shutdowninfo"));
- $(".modal-body").removeAttr("style");
- new bootstrap.Modal(document.getElementById('modalInfo')).toggle();
- setTimeout(function () {
- tryRedirect();
- }, 2000);
- } /* restart */
- /* Firmware Upload (OTA) */
- $('#firmwareUploadForm').submit(function (e) {
- e.preventDefault();
- if (!document.getElementById('firmwareUpload').files.length > 0) {
- alert(i18next.t("files.upload.selectFile"));
- return false;
- }
- console.log("firmware upload!");
- var data = new FormData(this);
- const startTime = new Date().getTime();
- let bytesTotal = 0;
- $.ajax({
- url: '/update',
- type: 'POST',
- data: data,
- contentType: false,
- processData: false,
- xhr: function () {
- var xhr = new window.XMLHttpRequest();
- xhr.upload.addEventListener("progress", function (evt) {
- if (evt.lengthComputable) {
- const now = new Date().getTime();
- const percent = parseInt(evt.loaded * 100 / evt.total);
- const elapsed = (now - startTime) / 1000;
- bytesTotal = evt.total;
- let progressText = i18next.t("files.upload.timeCalc");
- if (elapsed) {
- const bps = evt.loaded / elapsed;
- const kbps = bps / 1024;
- const remaining = Math.round((evt.total - evt.loaded) / bps);
- const data = {
- percent: percent,
- remaining: {
- unit: (remaining > 60) ? i18next.t("files.upload.minutes", {
- count: Math.round(remaining / 60)
- }) : i18next.t("files.upload.seconds"),
- value: (remaining > 60) ? Math.round(remaining / 60) : ((remaining > 2) ? remaining : i18next.t("files.upload.fewSec"))
- },
- speed: kbps.toFixed(2)
- }
- progressText = i18next.t("files.upload.progress", data);
- console.log("Percent: " + percent + "%% " + kbps.toFixed(2) + " KB/s");
+ }, 2000);
+ } /* restart */
+ /* Firmware Upload (OTA) */
+ $('#firmwareUploadForm').submit(function(e) {
+ e.preventDefault();
+ if(!document.getElementById('firmwareUpload').files.length > 0) {
+ alert(i18next.t("files.upload.selectFile"));
+ return false;
+ }
+ console.log("firmware upload!");
+ var data = new FormData(this);
+ const startTime = new Date().getTime();
+ let bytesTotal = 0;
+ const fup = $('#firmwareUploadProgress');
+ $.ajax({
+ url: '/update',
+ type: 'POST',
+ data: data,
+ contentType: false,
+ processData: false,
+ xhr: function() {
+ var xhr = new window.XMLHttpRequest();
+ xhr.upload.addEventListener("progress", function(evt) {
+ if(evt.lengthComputable) {
+ const now = new Date().getTime();
+ const percent = parseInt(evt.loaded * 100 / evt.total);
+ const elapsed = (now - startTime) / 1000;
+ bytesTotal = evt.total;
+ let progressText = i18next.t("files.upload.timeCalc");
+ if(elapsed) {
+ const bps = evt.loaded / elapsed;
+ const kbps = bps / 1024;
+ const remaining = Math.round((evt.total - evt.loaded) / bps);
+ const data = {
+ percent: percent,
+ remaining: {
+ unit: (remaining > 60) ? i18next.t("files.upload.minutes", {
+ count: Math.round(remaining / 60)
+ }) : i18next.t("files.upload.seconds"),
+ value: (remaining > 60) ? Math.round(remaining / 60) : ((remaining > 2) ? remaining : i18next.t("files.upload.fewSec"))
+ },
+ speed: kbps.toFixed(2)
}
- $("#firmwareUploadProgress").css('width', percent + "%").text(progressText);
+ progressText = i18next.t("files.upload.progress", data);
+ console.log("Percent: " + percent + "%% " + kbps.toFixed(2) + " KB/s");
}
- }, false);
- return xhr;
- },
- success: function (data, textStatus, jqXHR) {
- const now = new Date().getTime();
- const elapsed = (now - startTime) / 1000;
- let transData = {
- elapsed: "00:00",
- speed: "0,00"
- };
- if (elapsed) {
- const bps = bytesTotal / elapsed;
- const kbps = bps / 1024;
- const date = new Date(null);
- date.setSeconds(elapsed);
- const timeText = date.toISOString().substr(11, 8);
- transData = {
- elapsed: timeText,
- speed: kbps.toFixed(2)
- };
+ $(".progress-bar", fup).css('width', percent + "%");
+ $(".label", fup).text(progressText);
}
- console.log("Firmware upload success (" + transData.elapsed + ", " + transData.speed + " KB/s): " + textStatus);
- const progressText = i18next.t("files.upload.success", transData);
- $("#firmwareUploadProgress").text(progressText);
- document.getElementById('uploaded_file').value = '';
- document.getElementById('uploaded_file_text').innerHTML = '';
- restartDevice();
- },
- error: function (xhr, status, error) {
- console.log("Firmware upload ERROR: " + xhr.responseText);
- $("#firmwareUploadProgress").html(" " + i18next.t("files.upload.error") + ": " + xhr.responseText + " ");
- toaster.error(i18next.t("files.upload.error") + ": " + xhr.responseText);
+ }, false);
+ fup.addClass('bg-primary bg-opacity-75');
+ $('.progress-bar', fup).removeClass('bg-danger');
+ return xhr;
+ },
+ success: function(data, textStatus, jqXHR) {
+ const now = new Date().getTime();
+ const elapsed = (now - startTime) / 1000;
+ let transData = {
+ elapsed: "00:00",
+ speed: "0,00"
+ };
+ if(elapsed) {
+ const bps = bytesTotal / elapsed;
+ const kbps = bps / 1024;
+ const date = new Date(null);
+ date.setSeconds(elapsed);
+ const timeText = date.toISOString().substr(11, 8);
+ transData = {
+ elapsed: timeText,
+ speed: kbps.toFixed(2)
+ };
}
- });
- });
- /* File Upload */
- $('#explorerUploadForm').submit(function (e) {
- e.preventDefault();
- console.log("Upload!");
- var data = new FormData(this);
- var ref = $('#explorerTree').jstree(true),
- sel = ref.get_selected(),
- path = "/";
- if (!sel.length) {
- alert(i18next.t("files.upload.selectFolder"));
- return false;
- }
- if (!document.getElementById('uploaded_file').files.length > 0) {
- alert(i18next.t("files.upload.selectFile"));
- return false;
- }
- sel = sel[0];
- selectedNode = ref.get_node(sel);
- if (selectedNode.data.directory) {
- path = selectedNode.data.path
- console.log("Directory: " + path);
- } else {
- /* remap sel to parent folder */
- sel = ref.get_node(ref.get_parent(sel));
- path = parentNode.data.path;
- console.log("Parent path: " + path);
+ console.log("Firmware upload success (" + transData.elapsed + ", " + transData.speed + " KB/s): " + textStatus);
+ const progressText = i18next.t("files.upload.success", transData);
+ $(".label", fup).text(progressText);
+ document.getElementById('uploaded_file').value = '';
+ document.getElementById('uploaded_file_text').innerHTML = '';
+ restartDevice();
+ },
+ error: function(request, status, error) {
+ console.log("Firmware upload ERROR!", request);
+ fup.removeClass('bg-primary bg-opacity-75');
+ $('.progress-bar', fup).addClass('bg-danger');
+ $(".label", fup).text(i18next.t("files.upload.error") + ": " + request.statusText);
+ toaster.error(i18next.t("files.upload.error") + ': '+ request.statusText);
}
- const startTime = new Date().getTime();
- let bytesTotal = 0;
- $.ajax({
- url: '/explorer?path=' + encodeURIComponent(path),
- type: 'POST',
- data: data,
- contentType: false,
- processData: false,
- xhr: function () {
- var xhr = new window.XMLHttpRequest();
- xhr.upload.addEventListener("progress", function (evt) {
- if (evt.lengthComputable) {
- const now = new Date().getTime();
- const percent = parseInt(evt.loaded * 100 / evt.total);
- const elapsed = (now - startTime) / 1000;
- bytesTotal = evt.total;
- let progressText = i18next.t("files.upload.timeCalc");
- if (elapsed) {
- const bps = evt.loaded / elapsed;
- const kbps = bps / 1024;
- const remaining = Math.round((evt.total - evt.loaded) / bps);
- const data = {
- percent: percent,
- remaining: {
- unit: (remaining > 60) ? i18next.t("files.upload.minutes", {
- count: Math.round(remaining / 60)
- }) : i18next.t("files.upload.seconds"),
- value: (remaining > 60) ? Math.round(remaining / 60) : ((remaining > 2) ? remaining : i18next.t("files.upload.fewSec"))
- },
- speed: kbps.toFixed(2)
- }
- progressText = i18next.t("files.upload.progress", data);
- console.log("Percent: " + percent + "%% " + kbps.toFixed(2) + " KB/s");
+ });
+ });
+ /* File Upload */
+ $('#explorerUploadForm').submit(function(e) {
+ e.preventDefault();
+ console.log("Upload!");
+ var data = new FormData(this);
+ var ref = $('#explorerTree').jstree(true),
+ sel = ref.get_selected(),
+ path = "/";
+ if(!sel.length) {
+ alert(i18next.t("files.upload.selectFolder"));
+ return false;
+ }
+ if(!document.getElementById('uploaded_file').files.length > 0) {
+ alert(i18next.t("files.upload.selectFile"));
+ return false;
+ }
+ sel = sel[0];
+ selectedNode = ref.get_node(sel);
+ if(selectedNode.data.directory) {
+ path = selectedNode.data.path
+ console.log("Directory: " + path);
+ } else {
+ /* remap sel to parent folder */
+ sel = ref.get_node(ref.get_parent(sel));
+ path = parentNode.data.path;
+ console.log("Parent path: " + path);
+ }
+ const startTime = new Date().getTime();
+ let bytesTotal = 0;
+ const eup = $("#explorerUploadProgress");
+ $.ajax({
+ url: '/explorer?path=' + encodeURIComponent(path),
+ type: 'POST',
+ data: data,
+ contentType: false,
+ processData: false,
+ xhr: function() {
+ var xhr = new window.XMLHttpRequest();
+ xhr.upload.addEventListener("progress", function(evt) {
+ if(evt.lengthComputable) {
+ const now = new Date().getTime();
+ const percent = parseInt(evt.loaded * 100 / evt.total);
+ const elapsed = (now - startTime) / 1000;
+ bytesTotal = evt.total;
+ let progressText = i18next.t("files.upload.timeCalc");
+ if(elapsed) {
+ const bps = evt.loaded / elapsed;
+ const kbps = bps / 1024;
+ const remaining = Math.round((evt.total - evt.loaded) / bps);
+ const data = {
+ percent: percent,
+ remaining: {
+ unit: (remaining > 60) ? i18next.t("files.upload.minutes", {
+ count: Math.round(remaining / 60)
+ }) : i18next.t("files.upload.seconds"),
+ value: (remaining > 60) ? Math.round(remaining / 60) : ((remaining > 2) ? remaining : i18next.t("files.upload.fewSec"))
+ },
+ speed: kbps.toFixed(2)
}
- $("#explorerUploadProgress").css('width', percent + "%").text(progressText);
+ progressText = i18next.t("files.upload.progress", data);
+ console.log("Percent: " + percent + "%% " + kbps.toFixed(2) + " KB/s");
}
- }, false);
- return xhr;
- },
- success: function (data, textStatus, jqXHR) {
- const now = new Date().getTime();
- const elapsed = (now - startTime) / 1000;
- let transData = {
- elapsed: "00:00",
- speed: "0,00"
- };
- if (elapsed) {
- const bps = bytesTotal / elapsed;
- const kbps = bps / 1024;
- const date = new Date(null);
- date.setSeconds(elapsed);
- const timeText = date.toISOString().substr(11, 8);
- transData = {
- elapsed: timeText,
- speed: kbps.toFixed(2)
- };
+ $('.progress-bar', eup).css('width', percent + "%");
+ $('.label', eup).text(progressText);
}
- console.log("Upload success (" + transData.elapsed + ", " + transData.speed + " KB/s): " + textStatus);
- const progressText = i18next.t("files.upload.success", transData);
- $("#explorerUploadProgress").text(progressText);
- document.getElementById('uploaded_file').value = '';
- document.getElementById('uploaded_file_text').innerHTML = '';
- getData("http://" + host + "/explorer?path=" + path, function (data) {
- /* We now have data! */
- deleteChildrenNodes(sel);
- addFileDirectory(sel, data);
- ref.open_node(sel);
- });
- },
- error: function (request, status, error) {
- console.log("Upload ERROR!");
- $("#explorerUploadProgress").html(" " + i18next.t("files.upload.error") + ": " + status + " ");
- toaster.error(i18next.t("files.upload.error") + ": " + status);
+ }, false);
+ eup.addClass('bg-primary bg-opacity-75');
+ $('.progress-bar', eup).removeClass('bg-danger');
+ return xhr;
+ },
+ success: function(data, textStatus, jqXHR) {
+ const now = new Date().getTime();
+ const elapsed = (now - startTime) / 1000;
+ let transData = {
+ elapsed: "00:00",
+ speed: "0,00"
+ };
+ if(elapsed) {
+ const bps = bytesTotal / elapsed;
+ const kbps = bps / 1024;
+ const date = new Date(null);
+ date.setSeconds(elapsed);
+ const timeText = date.toISOString().substr(11, 8);
+ transData = {
+ elapsed: timeText,
+ speed: kbps.toFixed(2)
+ };
}
- });
+ console.log("Upload success (" + transData.elapsed + ", " + transData.speed + " KB/s): " + textStatus);
+ const progressText = i18next.t("files.upload.success", transData);
+ $('.label', eup).text(progressText);
+ document.getElementById('uploaded_file').value = '';
+ document.getElementById('uploaded_file_text').innerHTML = '';
+ getData("http://" + host + "/explorer?path=" + path, function(data) {
+ /* We now have data! */
+ deleteChildrenNodes(sel);
+ addFileDirectory(sel, data);
+ ref.open_node(sel);
+ });
+ },
+ error: function(request, status, error) {
+ console.log("Upload ERROR!", request);
+ eup.removeClass('bg-primary bg-opacity-75');
+ $('.progress-bar', eup).addClass('bg-danger');
+ $('.label', eup).text(i18next.t("files.upload.error") + ": " + request.statusText);
+ toaster.error(i18next.t("files.upload.error") + ": " + request.statusText);
+ }
});
- /* File Delete */
- function handleDeleteData(nodeId) {
- var selectedNodes = $('#explorerTree').jstree("get_selected", true);
- $.each(selectedNodes, function () {
- var ref = $('#explorerTree').jstree(true);
- var node = ref.get_node(this.id);
- console.log("call delete request: " + node.data.path);
- deleteData("http://" + host + "/explorer?path=" + encodeURIComponent(node.data.path));
- });
- }
+ });
+ /* File Delete */
+ function handleDeleteData(nodeId) {
+ var selectedNodes = $('#explorerTree').jstree("get_selected", true);
+ $.each(selectedNodes, function() {
+ var ref = $('#explorerTree').jstree(true);
+ var node = ref.get_node(this.id);
+ console.log("call delete request: " + node.data.path);
+ deleteData("http://" + host + "/explorer?path=" + encodeURIComponent(node.data.path));
+ });
+ }
function sortData(data) {
var sortMode = 3; // Default: natural case-insensitive
@@ -1776,559 +1597,532 @@
return type;
}
- function addFileDirectory(parent, data) {
- sortData(data);
- var ref = $('#explorerTree').jstree(true);
- for (var i = 0; i < data.length; i++) {
- console.log("Create Node");
- ref.create_node(parent, createChild(parent, data[i]));
- }
- } /* addFileDirectory */
- function buildFileSystemTree(path, darkMode) {
- if (darkMode == true) {
- var theme = "default-dark";
- } else {
- var theme = "default";
- }
- $('#explorerTree').jstree({
- "core": {
- "check_callback": true,
- 'force_text': true,
- 'strings': {
- "Loading ...": () => i18next.t("files.loading")
- },
- "themes": {
- "name": theme,
- "stripes": true
- },
- 'data': {
- text: '/',
- state: {
- opened: true,
- selected: true
- },
- type: 'folder',
- children: [],
- data: {
- path: '/',
- directory: true
- }
- }
+ function addFileDirectory(parent, data) {
+ sortData(data);
+ var ref = $('#explorerTree').jstree(true);
+ for(var i = 0; i < data.length; i++) {
+ console.log("Create Node");
+ ref.create_node(parent, createChild(parent, data[i]));
+ }
+ } /* addFileDirectory */
+ function buildFileSystemTree(path, darkMode) {
+ if(darkMode == true) {
+ var theme = "default-dark";
+ } else {
+ var theme = "default";
+ }
+ $('#explorerTree').jstree({
+ "core": {
+ "check_callback": true,
+ 'force_text': true,
+ 'strings': {
+ "Loading ...": () => i18next.t("files.loading")
},
- 'types': {
- 'folder': {
- 'icon': "fa fa-folder"
- },
- 'file': {
- 'icon': "fa fa-file"
- },
- 'audio': {
- 'icon': "fa fa-file-audio"
- },
- 'playlist': {
- 'icon': "fa fa-file-alt"
- },
- 'image': {
- 'icon': "fa fa-file-image"
+ "themes": {
+ "name": theme,
+ "stripes": true
+ },
+ 'data': {
+ text: '/',
+ state: {
+ opened: true,
+ selected: true
},
- 'default': {
- 'icon': "fa fa-folder"
+ type: 'folder',
+ children: [],
+ data: {
+ path: '/',
+ directory: true
}
+ }
+ },
+ 'types': {
+ 'folder': {
+ 'icon': "fa fa-folder"
+ },
+ 'file': {
+ 'icon': "fa fa-file"
+ },
+ 'audio': {
+ 'icon': "fa fa-file-audio"
},
- plugins: ["contextmenu", "themes", "types", "search"],
- "search": {
- "case_sensitive": false,
- "show_only_matches": true
+ 'playlist': {
+ 'icon': "fa fa-file-alt"
},
- contextmenu: {
- items: function (nodeId) {
- var ref = $('#explorerTree').jstree(true);
- var node = ref.get_node(nodeId);
- var items = {};
- if (node.data.directory) {
- items.createDir = {
- label: () => i18next.t("files.context.newFolder"),
- icon: "fas fa-folder",
- action: function (x) {
- var childNode = ref.create_node(nodeId, {
- text: () => i18next.t("files.context.newFolder"),
- type: "folder"
+ 'image': {
+ 'icon': "fa fa-file-image"
+ },
+ 'default': {
+ 'icon': "fa fa-folder"
+ }
+ },
+ plugins: ["contextmenu", "themes", "types", "search"],
+ "search": {
+ "case_sensitive": false,
+ "show_only_matches": true
+ },
+ contextmenu: {
+ items: function(nodeId) {
+ var ref = $('#explorerTree').jstree(true);
+ var node = ref.get_node(nodeId);
+ var items = {};
+ if(node.data.directory) {
+ items.createDir = {
+ label: () => i18next.t("files.context.newFolder"),
+ icon: "fas fa-folder",
+ action: function(x) {
+ var childNode = ref.create_node(nodeId, {
+ text: () => i18next.t("files.context.newFolder"),
+ type: "folder"
+ });
+ if(childNode) {
+ ref.edit(childNode, null, function(childNode, status) {
+ putData("http://" + host + "/explorer?path=" + encodeURIComponent(node.data.path) + "/" + encodeURIComponent(childNode.text));
+ refreshNode(nodeId);
});
- if (childNode) {
- ref.edit(childNode, null, function (childNode, status) {
- putData("http://" + host + "/explorer?path=" + encodeURIComponent(node.data.path) + "/" + encodeURIComponent(childNode.text));
- refreshNode(nodeId);
- });
- }
- }
- };
- }
- /* Play */
- items.play = {
- label: () => i18next.t("files.context.play"),
- icon: "fas fa-play",
- action: function (x) {
- var playMode = 1;
- if (node.data.directory) {
- playMode = 5;
- } else {
- if ((/\.(m3u|m3u8|asx|pls)$/i).test(node.data.path)) {
- playMode = 11;
- }
}
- postData("http://" + host + "/exploreraudio?path=" + encodeURIComponent(node.data.path) + "&playmode=" + playMode);
}
};
- /* Refresh */
- items.refresh = {
- label: () => i18next.t("files.context.refresh"),
- icon: "fas fa-sync",
- action: function (x) {
- refreshNode(nodeId);
+ }
+ /* Play */
+ items.play = {
+ label: () => i18next.t("files.context.play"),
+ icon: "fas fa-play",
+ action: function(x) {
+ var playMode = 1;
+ if(node.data.directory) {
+ playMode = 5;
+ } else {
+ if((/\.(m3u|m3u8|asx|pls)$/i).test(node.data.path)) {
+ playMode = 11;
+ }
}
- };
- /* Delete */
- items.delete = {
- label: () => i18next.t("files.context.delete"),
- icon: "fas fa-trash",
- action: function (x) {
- handleDeleteData(nodeId);
+ postData("http://" + host + "/exploreraudio?path=" + encodeURIComponent(node.data.path) + "&playmode=" + playMode);
+ }
+ };
+ /* Refresh */
+ items.refresh = {
+ label: () => i18next.t("files.context.refresh"),
+ icon: "fas fa-sync",
+ action: function(x) {
+ refreshNode(nodeId);
+ }
+ };
+ /* Delete */
+ items.delete = {
+ label: () => i18next.t("files.context.delete"),
+ icon: "fas fa-trash",
+ action: function(x) {
+ handleDeleteData(nodeId);
+ refreshNode(ref.get_parent(nodeId));
+ }
+ };
+ /* Rename */
+ items.rename = {
+ label: () => i18next.t("files.context.rename"),
+ icon: "fas fa-edit",
+ action: function(x) {
+ var srcPath = node.data.path;
+ ref.edit(nodeId, null, function(node, status) {
+ node.data.path = node.data.path.substring(0, node.data.path.lastIndexOf("/") + 1) + node.text;
+ patchData("http://" + host + "/explorer?srcpath=" + encodeURIComponent(srcPath) + "&dstpath=" + encodeURIComponent(node.data.path));
refreshNode(ref.get_parent(nodeId));
+ });
+ }
+ };
+ /* Download */
+ if(!node.data.directory) {
+ items.download = {
+ label: () => i18next.t("files.context.download"),
+ icon: "fas fa-download",
+ action: function(x) {
+ uri = "http://" + host + "/explorerdownload?path=" + encodeURIComponent(node.data.path);
+ console.log("download file: " + node.data.path);
+ var anchor = document.createElement('a');
+ anchor.href = uri;
+ anchor.target = '_blank';
+ anchor.download = node.data.path;
+ anchor.click();
+ document.body.removeChild(document.body.lastElementChild);
}
- };
- /* Rename */
- items.rename = {
- label: () => i18next.t("files.context.rename"),
- icon: "fas fa-edit",
- action: function (x) {
- var srcPath = node.data.path;
- ref.edit(nodeId, null, function (node, status) {
- node.data.path = node.data.path.substring(0, node.data.path.lastIndexOf("/") + 1) + node.text;
- patchData("http://" + host + "/explorer?srcpath=" + encodeURIComponent(srcPath) + "&dstpath=" + encodeURIComponent(node.data.path));
- refreshNode(ref.get_parent(nodeId));
- });
- }
- };
- /* Download */
- if (!node.data.directory) {
- items.download = {
- label: () => i18next.t("files.context.download"),
- icon: "fas fa-download",
- action: function (x) {
- uri = "http://" + host + "/explorerdownload?path=" + encodeURIComponent(node.data.path);
- console.log("download file: " + node.data.path);
- var anchor = document.createElement('a');
- anchor.href = uri;
- anchor.target = '_blank';
- anchor.download = node.data.path;
- anchor.click();
- document.body.removeChild(document.body.lastElementChild);
- }
- }
- };
- return items;
- }
- }
- });
- if (path.length == 0) {
- return;
- }
- getData("http://" + host + "/explorer?path=/", function (data) {
- /* We now have data! */
- $('#explorerTree').jstree(true).settings.core.data.children = [];
- sortData(data);
- for (var i = 0; i < data.length; i++) {
- var newChild = {
- text: data[i].name,
- type: getType(data[i]),
- data: {
- path: "/" + data[i].name,
- directory: data[i].dir
- },
- children: []
+ }
};
- $('#explorerTree').jstree(true).settings.core.data.children.push(newChild);
+ return items;
}
- $("#explorerTree").jstree(true).refresh();
- });
- } /* buildFileSystemTree */
- /* File Explorer functions end */
- var socket = undefined;
- var tm;
- var volumeSlider = new Slider("#setVolume");
- document.getElementById('setVolume').remove();
-
- function connect() {
- socket = new WebSocket("ws://" + host + "/ws");
- socket.onopen = function () {
- setInterval(ping, 15000);
- setInterval(getTrackProgress, 1000);
- // clear old socket messages
- socket.sendBuffer = [];
- socket.send('{"settings":{"settings":"settings"}}'); // request settings
- socket.send('{"ssids":{"ssids":"ssids"}}'); // get ssids
- socket.send('{"trackinfo":{"trackinfo":"trackinfo"}}'); // get trackinfo
- socket.send('{"coverimg":{"coverimg":"coverimg"}}'); // get cover image
- };
- socket.onclose = function (e) {
- console.log('Socket is closed. Reconnect will be attempted in 5 seconds.', e.reason);
- socket = null;
- setTimeout(function () {
- connect();
- }, 5000);
- };
- socket.onerror = function (err) {
- console.error('Socket encountered error: ', err.message, 'Closing socket');
- };
- socket.onmessage = function (event) {
- console.log(event.data);
- var socketMsg = JSON.parse(event.data);
- if (socketMsg.rfidId != null) {
- document.getElementById('rfidIdMusic').value = socketMsg.rfidId;
- toaster.info(i18next.t("toast.rfidDetect", {
- rfidId: socketMsg.rfidId
- }));
- $("#rfidIdMusic").effect("highlight", {
- color: "#abf5af"
- }, 3000);
- if (toolsTabActive) {
- rebuildRFIDList();
- }
+ }
+ });
+ if(path.length == 0) {
+ return;
+ }
+ getData("http://" + host + "/explorer?path=/", function(data) {
+ /* We now have data! */
+ $('#explorerTree').jstree(true).settings.core.data.children = [];
+ sortData(data);
+ for(var i = 0; i < data.length; i++) {
+ var newChild = {
+ text: data[i].name,
+ type: getType(data[i]),
+ data: {
+ path: "/" + data[i].name,
+ directory: data[i].dir
+ },
+ children: []
+ };
+ $('#explorerTree').jstree(true).settings.core.data.children.push(newChild);
+ }
+ $("#explorerTree").jstree(true).refresh();
+ });
+ } /* buildFileSystemTree */
+ /* File Explorer functions end */
+ var socket = undefined;
+ var tm;
+ var volumeSlider = $("#setVolume");
+
+ function connect() {
+ socket = new WebSocket("ws://" + host + "/ws");
+ socket.onopen = function() {
+ setInterval(ping, 15000);
+ setInterval(getTrackProgress, 1000);
+ // clear old socket messages
+ socket.sendBuffer = [];
+ socket.send('{"settings":{"settings":"settings"}}'); // request settings
+ socket.send('{"ssids":{"ssids":"ssids"}}'); // get ssids
+ socket.send('{"trackinfo":{"trackinfo":"trackinfo"}}'); // get trackinfo
+ socket.send('{"coverimg":{"coverimg":"coverimg"}}'); // get cover image
+ };
+ socket.onclose = function(e) {
+ console.log('Socket is closed. Reconnect will be attempted in 5 seconds.', e.reason);
+ socket = null;
+ setTimeout(function() {
+ connect();
+ }, 5000);
+ };
+ socket.onerror = function(err) {
+ console.error('Socket encountered error: ', err.message, 'Closing socket');
+ };
+ socket.onmessage = function(event) {
+ var socketMsg = JSON.parse(event.data);
+ console.log(socketMsg);
+ if(socketMsg.rfidId != null) {
+ document.getElementById('rfidIdMusic').value = socketMsg.rfidId;
+ toaster.info(i18next.t("toast.rfidDetect", {
+ rfidId: socketMsg.rfidId
+ }));
+ $("#rfidIdMusic").effect("highlight", {
+ color: "#abf5af"
+ }, 3000);
+ if(toolsTabActive) {
+ rebuildRFIDList();
}
- if ("status" in socketMsg) {
- if (socketMsg.status == "ok") {
+ }
+ if("status" in socketMsg) {
+ if(socketMsg.status == "ok") {
+ // avoiding the untranslated toast on bootup
+ if (i18next.exists('toast.success')) {
toaster.success(i18next.t("toast.success"));
}
- if (socketMsg.status == "dropout") {
- toaster.warning(i18next.t("toast.dropout"));
- }
- }
- if ("pong" in socketMsg) {
- if (socketMsg.pong == 'pong') {
- pong();
- }
- }
- if ("volume" in socketMsg) {
- volumeSlider.setValue(parseInt(socketMsg.volume));
- }
- if ("trackinfo" in socketMsg) {
- document.getElementById('track').innerHTML = socketMsg.trackinfo.name;
- setTrackProgress(socketMsg.trackinfo);
- var btnTrackPlayPause = document.getElementById('nav-btn-play');
- if (socketMsg.trackinfo.pausePlay) {
- btnTrackPlayPause.innerHTML = '
';
- } else {
- btnTrackPlayPause.innerHTML = '
';
- }
- var btnTrackFirst = document.getElementById('nav-btn-first');
- var btnTrackPrev = document.getElementById('nav-btn-prev');
- if (socketMsg.trackinfo.currentTrackNumber <= 1) {
- btnTrackFirst.classList.add("disabled");
- btnTrackPrev.classList.add("disabled");
- } else {
- btnTrackFirst.classList.remove("disabled");
- btnTrackPrev.classList.remove("disabled");
- }
- var btnTrackLast = document.getElementById('nav-btn-last');
- var btnTrackNext = document.getElementById('nav-btn-next');
- if (socketMsg.trackinfo.currentTrackNumber >= socketMsg.trackinfo.numberOfTracks) {
- btnTrackLast.classList.add("disabled");
- btnTrackNext.classList.add("disabled");
- } else {
- btnTrackLast.classList.remove("disabled");
- btnTrackNext.classList.remove("disabled");
- }
}
- if ("trackProgress" in socketMsg) {
- setTrackProgress(socketMsg.trackProgress);
+ if(socketMsg.status == "dropout") {
+ toaster.warning(i18next.t("toast.dropout"));
}
- if ("coverimg" in socketMsg) {
- document.getElementById('coverimg').src = "http://" + host + "/cover?" + new Date().getTime();
- }
- if ("settings" in socketMsg) {
- fillSettings(socketMsg.settings);
- }
- };
- }
- async function fillSettings(settings) {
- if (!settings) {
- return false;
- }
- // update global settings
- window.settings = {
- ...window.settings,
- ...settings
- };
- // general
- let genSettings = settings.general;
- if (genSettings) {
- $('#initialVolume').bootstrapSlider('setValue', genSettings.initVolume);
- $('#maxVolumeSpeaker').bootstrapSlider('setValue', genSettings.maxVolumeSp);
- $('#maxVolumeHeadphone').bootstrapSlider('setValue', genSettings.maxVolumeHp);
- $('#inactivityTime').bootstrapSlider('setValue', genSettings.sleepInactivity);
- }
- // current values
- let currSettings = settings.current;
- if (currSettings) {
- document.getElementById("rfidIdMusic").value = currSettings.rfidTagId;
- volumeSlider.setValue(currSettings.volume);
- }
- // default (factory) settings
- let defSettings = settings.defaults;
- if (defSettings) {
- $('#initialVolume').bootstrapSlider('setValue', defSettings.initVolume);
- $('#maxVolumeSpeaker').bootstrapSlider('setValue', defSettings.maxVolumeSp);
- $('#maxVolumeHeadphone').bootstrapSlider('setValue', defSettings.maxVolumeHp);
- $('#inactivityTime').bootstrapSlider('setValue', defSettings.sleepInactivity);
- $('#initBrightness').bootstrapSlider('setValue', defSettings.initBrightness);
- $('#nightBrightness').bootstrapSlider('setValue', defSettings.nightBrightness);
- $('#warningLowVoltage').bootstrapSlider('setValue', defSettings.warnLowVoltage);
- $('#voltageIndicatorLow').bootstrapSlider('setValue', defSettings.indicatorLow);
- $('#voltageIndicatorHigh').bootstrapSlider('setValue', defSettings.indicatorHi);
- $('#voltageCheckInterval').bootstrapSlider('setValue', defSettings.voltageCheckInterval);
- $('#criticalVoltage').bootstrapSlider('setValue', defSettings.criticalVoltage);
- $("#playlistSortMode").val(defSettings.sortMode).change();
- $("#gainLowPass").bootstrapSlider('setValue', defSettings.gainLowPass);
- $("#gainBandPass").bootstrapSlider('setValue', defSettings.gainBandPass);
- $("#gainHighPass").bootstrapSlider('setValue', defSettings.gainHighPass);
- // If there is any better way to overwrite the bootstrap slider tooltip - please change this abdomination!
- formatDBTooltip($('#gainLowPass')[0].previousSibling, defSettings.gainLowPass);
- formatDBTooltip($('#gainBandPass')[0].previousSibling, defSettings.gainBandPass);
- formatDBTooltip($('#gainHighPass')[0].previousSibling, defSettings.gainHighPass);
- }
- let eqSettings = settings.equalizer;
- if (eqSettings) {
- $("#gainLowPass").bootstrapSlider('setValue', eqSettings.gainLowPass);
- $("#gainBandPass").bootstrapSlider('setValue', eqSettings.gainBandPass);
- $("#gainHighPass").bootstrapSlider('setValue', eqSettings.gainHighPass);
- // If there is any better way to overwrite the bootstrap slider tooltip - please change this abdomination!
- formatDBTooltip($('#gainLowPass')[0].previousSibling, eqSettings.gainLowPass);
- formatDBTooltip($('#gainBandPass')[0].previousSibling, eqSettings.gainBandPass)
- formatDBTooltip($('#gainHighPass')[0].previousSibling, eqSettings.gainHighPass);
- }
- // wifi
- let wifiSettings = settings.wifi;
- if (wifiSettings) {
- document.getElementById("hostname").value = wifiSettings.hostname;
- document.getElementById("scan_wifi_on_start").checked = wifiSettings.scanOnStart;
- // set title to hostname
- setTitle(wifiSettings.hostname);
}
- // ssids
- let ssidSettings = settings.ssids;
- if (ssidSettings) {
- rebuildSSIDList(ssidSettings);
- }
- // led
- let ledSettings = settings.led;
- if (ledSettings) {
- document.getElementById('neopixelConfig').setAttribute('data-visible', true);
- $('#initBrightness').bootstrapSlider('setValue', ledSettings.initBrightness);
- $('#nightBrightness').bootstrapSlider('setValue', ledSettings.nightBrightness);
- }
- // playlist
- let playlistSettings = settings.playlist;
- if (playlistSettings) {
- $("#playlistSortMode").val(playlistSettings.sortMode).change();
- }
- // battery
- let batSettings = settings.battery;
- if (batSettings) {
- document.getElementById('batteryConfig').setAttribute('data-visible', true);
- $('#warningLowVoltage').bootstrapSlider('setValue', batSettings.warnLowVoltage);
- $('#voltageIndicatorLow').bootstrapSlider('setValue', batSettings.indicatorLow);
- $('#voltageIndicatorHigh').bootstrapSlider('setValue', batSettings.indicatorHi);
- if (batSettings.criticalVoltage) {
- document.getElementById('criticalVoltageSection').setAttribute('data-visible', true);
- $('#criticalVoltage').bootstrapSlider('setValue', batSettings.criticalVoltage);
- } else {
- document.getElementById('criticalVoltageSection').setAttribute('data-visible', false);
+ if("pong" in socketMsg) {
+ if(socketMsg.pong == 'pong') {
+ pong();
}
- $('#voltageCheckInterval').bootstrapSlider('setValue', batSettings.voltageCheckInterval);
}
- // ftp
- let ftpSettings = settings.ftp;
- if (ftpSettings) {
- document.getElementById('nav-ftp-tab').setAttribute('data-visible', true);
- document.getElementById("ftpUser").value = ftpSettings.username;
- document.getElementById("ftpUser").setAttribute('maxlength', ftpSettings.maxUserLength);
- document.getElementById("ftpPwd").value = ftpSettings.password;
- document.getElementById("ftpPwd").setAttribute('maxlength', ftpSettings.maxPwdLength);
+ if("volume" in socketMsg) {
+ volumeSlider.val(parseInt(socketMsg.volume));
}
- // mqtt
- let mqttSettings = settings.mqtt;
- if (mqttSettings) {
- // todo: get the bootstrap sliders to work:
- document.getElementById('nav-mqtt-tab').setAttribute('data-visible', true);
- document.getElementById('mqttEnable').checked = mqttSettings.enable;
- document.getElementById('mqttClientId').value = mqttSettings.clientID;
- document.getElementById('mqttClientId').setAttribute('maxlength', mqttSettings.maxClientIdLength);
- document.getElementById('mqttServer').value = mqttSettings.server;
- document.getElementById('mqttServer').setAttribute('maxlength', mqttSettings.maxServerLength);
- document.getElementById('mqttUser').value = mqttSettings.username;
- document.getElementById('mqttUser').setAttribute('maxlength', mqttSettings.maxUserLength);
- document.getElementById('mqttPwd').value = mqttSettings.password;
- document.getElementById('mqttPwd').setAttribute('maxlength', mqttSettings.maxPwdLength);
- document.getElementById('mqttPort').value = mqttSettings.port;
- }
- // bluetooth
- let btSettings = settings.bluetooth;
- if (btSettings) {
- document.getElementById('nav-bt-tab').setAttribute('data-visible', true);
- document.getElementById('btDeviceName').value = btSettings.deviceName;
- document.getElementById('btPinCode').value = btSettings.pinCode;
- }
- }
- async function resetSettings() {
- let defaults = await (await fetch("http://" + host + "/settings?section=defaults")).json();
- fillSettings(defaults);
- }
- const wifiListSavedSSIDs = document.getElementById("wifiListSavedSSIDs");
- async function rebuildSSIDList(data) {
- var ssidList;
- var ssidActive;
- if (data) {
- ssidList = data.savedSSIDs;
- ssidActive = data.active;
- } else {
- ssidList = await (await fetch("http://" + host + "/savedSSIDs")).json();
- let ssidActiveObj = await (await fetch("http://" + host + "/activeSSID")).json();
- console.log(ssidActiveObj);
- ssidActive = ssidActiveObj.active;
- }
- wifiListSavedSSIDs.innerHTML = "";
- for (let ssid of ssidList) {
- console.log("appending ssid", ssid);
- let ssidElem = document.createElement("li");
- ssidElem.appendChild(document.createTextNode(ssid));
- ssidElem.classList.add("list-group-item");
- console.log("comparing ssid vs active:", ssidActive, ssid);
- if (ssidActive && ssidActive === ssid) {
- ssidElem.classList.add("active");
+ if("trackinfo" in socketMsg) {
+ document.getElementById('track').innerHTML = socketMsg.trackinfo.name;
+ setTrackProgress(socketMsg.trackinfo);
+ var btnTrackPlayPause = document.getElementById('nav-btn-play');
+ if(socketMsg.trackinfo.pausePlay) {
+ btnTrackPlayPause.innerHTML = '
';
} else {
- ssidElem.classList.add("bg-dark");
- ssidElem.classList.add("text-light");
- }
- let deleteSpan = document.createElement("span");
- deleteSpan.classList.add("float-end");
- deleteSpan.classList.add("button-group");
- let deleteButton = document.createElement("button");
- deleteButton.classList.add("btn");
- deleteButton.classList.add("btn-danger");
- deleteButton.classList.add("fa");
- deleteButton.classList.add("fa-trash");
- deleteButton.setAttribute("data-bs-toggle", "modal");
- deleteButton.setAttribute("data-bs-target", "#deleteSSIDModal");
- deleteButton.setAttribute("data-ssid", ssid);
- deleteSpan.appendChild(deleteButton);
- ssidElem.appendChild(deleteSpan);
- wifiListSavedSSIDs.appendChild(ssidElem);
- }
- }
- async function deleteSSID(ssid) {
- console.log("deleting", ssid);
- $('#deleteSSIDModal').modal('hide');
- await fetch("http://" + host + "/savedSSIDs/" + ssid, {
- method: "DELETE"
- });
- await rebuildSSIDList();
- }
- const rfidListSavedAssignments = document.getElementById("rfidListSavedAssignments");
- async function rebuildRFIDList() {
- var rfidList = await (await fetch("http://" + host + "/rfid")).json();
- var rfidActive = document.getElementById('rfidIdMusic').value;
- rfidListSavedAssignments.innerHTML = "";
- console.log(rfidList.length + ' nvs rfid entries received.');
- for (let rfid of rfidList) {
- if (!rfid.id) {
- console.log("empty tag id");
- break;
+ btnTrackPlayPause.innerHTML = '
';
}
- console.log("appending rfid ", rfid);
- let rfidElem = document.createElement("li");
- rfidElem.appendChild(document.createTextNode(rfid.id));
- if (rfid.playMode) {
- rfidElem.appendChild(document.createElement("div"));
- rfidElem.appendChild(document.createTextNode(i18next.t("files.rfid.playmode.mode." + rfid.playMode)));
- } else
- if (rfid.modId) {
- rfidElem.appendChild(document.createElement("div"));
- rfidElem.appendChild(document.createTextNode(i18next.t("files.rfid.mod.cmd." + rfid.modId)));
- }
- rfidElem.classList.add("list-group-item");
- console.log("comparing rfid vs active:", rfidActive, rfid.id);
- if (rfidActive && rfidActive === rfid.id) {
- rfidElem.classList.add("active");
+ var btnTrackFirst = document.getElementById('nav-btn-first');
+ var btnTrackPrev = document.getElementById('nav-btn-prev');
+ if(socketMsg.trackinfo.currentTrackNumber <= 1) {
+ btnTrackFirst.classList.add("disabled");
+ btnTrackPrev.classList.add("disabled");
+ } else {
+ btnTrackFirst.classList.remove("disabled");
+ btnTrackPrev.classList.remove("disabled");
}
- if (rfid.fileOrUrl) {
- rfidElem.appendChild(document.createElement("br"));
- rfidElem.appendChild(document.createTextNode(rfid.fileOrUrl));
+ var btnTrackLast = document.getElementById('nav-btn-last');
+ var btnTrackNext = document.getElementById('nav-btn-next');
+ if(socketMsg.trackinfo.currentTrackNumber >= socketMsg.trackinfo.numberOfTracks) {
+ btnTrackLast.classList.add("disabled");
+ btnTrackNext.classList.add("disabled");
+ } else {
+ btnTrackLast.classList.remove("disabled");
+ btnTrackNext.classList.remove("disabled");
}
- let deleteSpan = document.createElement("span");
- deleteSpan.classList.add("float-end");
- deleteSpan.classList.add("button-group");
- let deleteButton = document.createElement("button");
- deleteButton.classList.add("btn");
- deleteButton.classList.add("btn-danger");
- deleteButton.classList.add("fa");
- deleteButton.classList.add("fa-trash");
- deleteButton.setAttribute("data-bs-toggle", "modal");
- deleteButton.setAttribute("data-bs-target", "#deleteRFIDModal");
- deleteButton.setAttribute("data-rfid", rfid.id);
- deleteSpan.appendChild(deleteButton);
- rfidElem.appendChild(deleteSpan);
- rfidListSavedAssignments.appendChild(rfidElem);
}
- document.getElementById('listNvs').setAttribute('data-visible', (rfidList.length > 0));
- document.getElementById('eraseNvs').setAttribute('data-visible', (rfidList.length > 0));
- document.getElementById('exportNvs').setAttribute('data-visible', (rfidList.length > 0));
- }
- async function deleteRFID(tagId) {
- console.log("deleting", tagId);
- $('#deleteRFIDModal').modal('hide');
- var response = await fetch("http://" + host + "/rfid?id=" + encodeURIComponent(tagId), {
- method: "DELETE"
- });
- if (response.ok) {
- toaster.success(i18next.t("toast.success"));
- rebuildRFIDList();
- } else {
- toaster.error(response.statusText);
+ if("trackProgress" in socketMsg) {
+ setTrackProgress(socketMsg.trackProgress);
}
- console.log(response.statusText);
- }
- async function eraseNVSRFID() {
- console.log("erase all NVS RFIDs");
- $('#deleteNVSRFIDModal').modal('hide');
- var response = await fetch("http://" + host + "/rfidnvserase", {
- method: "POST"
- });
- if (response.ok) {
- toaster.success(i18next.t("toast.success"));
- await rebuildRFIDList();
- } else {
- toaster.error(response.statusText);
+ if("coverimg" in socketMsg) {
+ document.getElementById('coverimg').src = "http://" + host + "/cover?" + new Date().getTime();
}
- }
- async function uploadNVSRFID() {
- if (!document.getElementById('nvsUpload').files.length > 0) {
- alert(i18next.t("files.upload.selectFile"));
- return false;
- }
- console.log("upload NVS RFIDs");
- let formData = new FormData();
- formData.append("file", document.getElementById('nvsUpload').files[0]);
- var response = await fetch('/upload', {
- method: "POST",
- body: formData
- });
- if (response.ok) {
- toaster.success(i18next.t("toast.success"));
- rebuildRFIDList();
- } else {
- toaster.error(response.statusText);
+ if("settings" in socketMsg) {
+ fillSettings(socketMsg.settings);
}
+ };
+ }
+ async function fillSettings(settings) {
+ if(!settings) {
+ return false;
+ }
+ // update global settings
+ window.settings = {
+ ...window.settings,
+ ...settings
+ };
+ // general
+ let genSettings = settings.general;
+ if(genSettings) {
+ $('#initialVolume').val(genSettings.initVolume).trigger('input');
+ $('#maxVolumeSpeaker').val(genSettings.maxVolumeSp).trigger('input');
+ $('#maxVolumeHeadphone').val(genSettings.maxVolumeHp).trigger('input');
+ $('#inactivityTime').val(genSettings.sleepInactivity).trigger('input');
+ $('#playMono').prop('checked', genSettings.playMono);
+ $('#savePlayPosShutdown').prop('checked', genSettings.savePosShutdown);
+ $('#savePlayPosRfidChange').prop('checked', genSettings.savePosRfidChg);
+ $('#pauseOnMinVolume').prop('checked', genSettings.pauseOnMinVol);
+ $('#recoverVolBoot').prop('checked', genSettings.recoverVolBoot);
+ $('#volumeCurve').prop('checked', genSettings.volumeCurve > 0);
+ }
+ // current values
+ let currSettings = settings.current;
+ if(currSettings) {
+ document.getElementById("rfidIdMusic").value = currSettings.rfidTagId;
+ volumeSlider.val(currSettings.volume);
+ }
+ let eqSettings = settings.equalizer;
+ if(eqSettings) {
+ $("#gainLowPass").val(eqSettings.gainLowPass).trigger('input');
+ $("#gainBandPass").val(eqSettings.gainBandPass).trigger('input');
+ $("#gainHighPass").val(eqSettings.gainHighPass).trigger('input');
+ }
+ // wifi
+ let wifiSettings = settings.wifi;
+ if(wifiSettings) {
+ document.getElementById("hostname").value = wifiSettings.hostname;
+ document.getElementById("scan_wifi_on_start").checked = wifiSettings.scanOnStart;
+ // set title to hostname
+ setTitle(wifiSettings.hostname);
+ }
+ // ssids
+ let ssidSettings = settings.ssids;
+ if(ssidSettings) {
+ rebuildSSIDList(ssidSettings);
+ }
+ // led
+ let ledSettings = settings.led;
+ if(ledSettings) {
+ document.getElementById('neopixelConfig').setAttribute('data-visible', true);
+ $('#initBrightness').val(ledSettings.initBrightness).trigger('input');
+ $('#nightBrightness').val(ledSettings.nightBrightness).trigger('input');
+ }
+ // playlist
+ let playlistSettings = settings.playlist;
+ if(playlistSettings) {
+ $("#playlistSortMode").val(playlistSettings.sortMode).change();
+ }
+ // battery
+ let batSettings = settings.battery;
+ if(batSettings) {
+ document.getElementById('batteryConfig').setAttribute('data-visible', true);
+ $('#warningLowVoltage').val(batSettings.warnLowVoltage).trigger('input');
+ $('#voltageIndicatorLow').val(batSettings.indicatorLow).trigger('input');
+ $('#voltageIndicatorHigh').val(batSettings.indicatorHi).trigger('input');
+ $('#criticalVoltageSection').data('visible', batSettings.criticalVoltage);
+ if(batSettings.criticalVoltage) {
+ $('#criticalVoltage').val(batSettings.criticalVoltage).trigger('input');
+ }
+ $('#voltageCheckInterval').val(batSettings.voltageCheckInterval).trigger('input');
+ }
+ // ftp
+ let ftpSettings = settings.ftp;
+ if(ftpSettings) {
+ document.getElementById('nav-ftp-tab').setAttribute('data-visible', true);
+ document.getElementById("ftpUser").value = ftpSettings.username;
+ document.getElementById("ftpUser").setAttribute('maxlength', ftpSettings.maxUserLength);
+ document.getElementById("ftpPwd").value = ftpSettings.password;
+ document.getElementById("ftpPwd").setAttribute('maxlength', ftpSettings.maxPwdLength);
+ }
+ // mqtt
+ let mqttSettings = settings.mqtt;
+ if(mqttSettings) {
+ // todo: get the bootstrap sliders to work:
+ document.getElementById('nav-mqtt-tab').setAttribute('data-visible', true);
+ document.getElementById('mqttEnable').checked = mqttSettings.enable;
+ document.getElementById('mqttClientId').value = mqttSettings.clientID;
+ document.getElementById('mqttClientId').setAttribute('maxlength', mqttSettings.maxClientIdLength);
+ document.getElementById('mqttServer').value = mqttSettings.server;
+ document.getElementById('mqttServer').setAttribute('maxlength', mqttSettings.maxServerLength);
+ document.getElementById('mqttUser').value = mqttSettings.username;
+ document.getElementById('mqttUser').setAttribute('maxlength', mqttSettings.maxUserLength);
+ document.getElementById('mqttPwd').value = mqttSettings.password;
+ document.getElementById('mqttPwd').setAttribute('maxlength', mqttSettings.maxPwdLength);
+ document.getElementById('mqttPort').value = mqttSettings.port;
+ }
+ // bluetooth
+ let btSettings = settings.bluetooth;
+ if(btSettings) {
+ document.getElementById('nav-bt-tab').setAttribute('data-visible', true);
+ document.getElementById('btDeviceName').value = btSettings.deviceName;
+ document.getElementById('btPinCode').value = btSettings.pinCode;
+ }
+ }
+ async function resetSettings() {
+ let { defaults } = await (await fetch("http://" + host + "/settings?section=defaults")).json();
+ fillSettings(defaults);
+ }
+ const wifiListSavedSSIDs = document.getElementById("wifiListSavedSSIDs");
+ async function rebuildSSIDList(data) {
+ var ssidList;
+ var ssidActive;
+ if(data) {
+ ssidList = data.savedSSIDs;
+ ssidActive = data.active;
+ } else {
+ ssidList = await (await fetch("http://" + host + "/savedSSIDs")).json();
+ let ssidActiveObj = await (await fetch("http://" + host + "/activeSSID")).json();
+ console.log(ssidActiveObj);
+ ssidActive = ssidActiveObj.active;
+ }
+ wifiListSavedSSIDs.innerHTML = "";
+ for(let ssid of ssidList) {
+ console.log("appending ssid", ssid);
+ let ssidElem = document.createElement("li");
+ ssidElem.appendChild(document.createTextNode(ssid));
+ ssidElem.classList.add("list-group-item");
+ console.log("comparing ssid vs active:", ssidActive, ssid);
+ if(ssidActive && ssidActive === ssid) {
+ ssidElem.classList.add("active");
+ }
+ let deleteSpan = document.createElement("span");
+ deleteSpan.classList.add("float-end");
+ deleteSpan.classList.add("button-group");
+ let deleteButton = document.createElement("button");
+ deleteButton.classList.add("btn", "btn-danger", "fa", "fa-trash");
+ deleteButton.setAttribute("data-bs-toggle", "modal");
+ deleteButton.setAttribute("data-bs-target", "#deleteSSIDModal");
+ deleteButton.setAttribute("data-ssid", ssid);
+ deleteSpan.appendChild(deleteButton);
+ ssidElem.appendChild(deleteSpan);
+ wifiListSavedSSIDs.appendChild(ssidElem);
+ }
+ }
+ async function deleteSSID(ssid) {
+ console.log("deleting", ssid);
+ $('#deleteSSIDModal').modal('hide');
+ await fetch("http://" + host + "/savedSSIDs/" + ssid, {
+ method: "DELETE"
+ });
+ await rebuildSSIDList();
+ }
+ const rfidListSavedAssignments = document.getElementById("rfidListSavedAssignments");
+ async function rebuildRFIDList() {
+ var rfidList = await (await fetch("http://" + host + "/rfid")).json();
+ var rfidActive = document.getElementById('rfidIdMusic').value;
+ rfidListSavedAssignments.innerHTML = "";
+ console.log(rfidList.length + ' nvs rfid entries received.');
+ for(let rfid of rfidList) {
+ if(!rfid.id) {
+ console.log("empty tag id");
+ break;
+ }
+ console.log("appending rfid ", rfid);
+ let rfidElem = document.createElement("li");
+ rfidElem.appendChild(document.createTextNode(rfid.id));
+ if(rfid.playMode) {
+ rfidElem.appendChild(document.createElement("div"));
+ rfidElem.appendChild(document.createTextNode(i18next.t("files.rfid.playmode.mode." + rfid.playMode)));
+ } else
+ if(rfid.modId) {
+ rfidElem.appendChild(document.createElement("div"));
+ rfidElem.appendChild(document.createTextNode(i18next.t("files.rfid.mod.cmd." + rfid.modId)));
+ }
+ rfidElem.classList.add("list-group-item");
+ console.log("comparing rfid vs active:", rfidActive, rfid.id);
+ if(rfidActive && rfidActive === rfid.id) {
+ rfidElem.classList.add("active");
+ }
+ if(rfid.fileOrUrl) {
+ rfidElem.appendChild(document.createElement("br"));
+ rfidElem.appendChild(document.createTextNode(rfid.fileOrUrl));
+ }
+ let deleteSpan = document.createElement("span");
+ deleteSpan.classList.add("float-end");
+ deleteSpan.classList.add("button-group");
+ let deleteButton = document.createElement("button");
+ deleteButton.classList.add("btn");
+ deleteButton.classList.add("btn-danger");
+ deleteButton.classList.add("fa");
+ deleteButton.classList.add("fa-trash");
+ deleteButton.setAttribute("data-bs-toggle", "modal");
+ deleteButton.setAttribute("data-bs-target", "#deleteRFIDModal");
+ deleteButton.setAttribute("data-rfid", rfid.id);
+ deleteSpan.appendChild(deleteButton);
+ rfidElem.appendChild(deleteSpan);
+ rfidListSavedAssignments.appendChild(rfidElem);
+ }
+ document.getElementById('listNvs').setAttribute('data-visible', (rfidList.length > 0));
+ document.getElementById('eraseNvs').setAttribute('data-visible', (rfidList.length > 0));
+ document.getElementById('exportNvs').setAttribute('data-visible', (rfidList.length > 0));
+ }
+ async function deleteRFID(tagId) {
+ console.log("deleting", tagId);
+ $('#deleteRFIDModal').modal('hide');
+ var response = await fetch("http://" + host + "/rfid?id=" + encodeURIComponent(tagId), {
+ method: "DELETE"
+ });
+ if(response.ok) {
+ toaster.success(i18next.t("toast.success"));
+ rebuildRFIDList();
+ } else {
+ toaster.error(response.statusText);
+ }
+ console.log(response.statusText);
+ }
+ async function eraseNVSRFID() {
+ console.log("erase all NVS RFIDs");
+ $('#deleteNVSRFIDModal').modal('hide');
+ var response = await fetch("http://" + host + "/rfidnvserase", {
+ method: "POST"
+ });
+ if(response.ok) {
+ toaster.success(i18next.t("toast.success"));
+ await rebuildRFIDList();
+ } else {
+ toaster.error(response.statusText);
+ }
+ }
+ async function uploadNVSRFID() {
+ if(!document.getElementById('nvsUpload').files.length > 0) {
+ alert(i18next.t("files.upload.selectFile"));
+ return false;
+ }
+ console.log("upload NVS RFIDs");
+ let formData = new FormData();
+ formData.append("file", document.getElementById('nvsUpload').files[0]);
+ var response = await fetch('/upload', {
+ method: "POST",
+ body: formData
+ });
+ if(response.ok) {
+ toaster.success(i18next.t("toast.success"));
+ rebuildRFIDList();
+ } else {
+ toaster.error(response.statusText);
}
+ }
function onToolsTabOpened() {
console.log("tools tab opened!");
@@ -2398,24 +2192,30 @@
lastIdclicked = clickedId;
var myObj = {
"general": {
- initVolume: Number(document.getElementById('initialVolume').value),
- maxVolumeSp: Number(document.getElementById('maxVolumeSpeaker').value),
- maxVolumeHp: Number(document.getElementById('maxVolumeHeadphone').value),
- sleepInactivity: Number(document.getElementById('inactivityTime').value)
+ initVolume: Number($('#initialVolume').val()),
+ maxVolumeSp: Number($('#maxVolumeSpeaker').val()),
+ maxVolumeHp: Number($('#maxVolumeHeadphone').val()),
+ sleepInactivity: Number($('#inactivityTime').val()),
+ playMono: $('#playMono').prop('checked'),
+ savePosShutdown: $('#savePlayPosShutdown').prop('checked'),
+ savePosRfidChg: $('#savePlayPosRfidChange').prop('checked'),
+ pauseOnMinVol: $('#pauseOnMinVolume').prop('checked'),
+ recoverVolBoot: $('#recoverVolBoot').prop('checked'),
+ volumeCurve: $("#volumeCurve").prop('checked') ? 1 : 0
},
"led": {
- initBrightness: Number(document.getElementById('initBrightness').value),
- nightBrightness: Number(document.getElementById('nightBrightness').value)
+ initBrightness: Number($('#initBrightness').val()),
+ nightBrightness: Number($('#nightBrightness').val())
},
"battery": {
- warnLowVoltage: Number(document.getElementById('warningLowVoltage').value),
- indicatorLow: Number(document.getElementById('voltageIndicatorLow').value),
- indicatorHi: Number(document.getElementById('voltageIndicatorHigh').value),
- criticalVoltage: Number(document.getElementById('criticalVoltage').value),
- voltageCheckInterval: Number(document.getElementById('voltageCheckInterval').value)
+ warnLowVoltage: Number($('#warningLowVoltage').val()),
+ indicatorLow: Number($('#voltageIndicatorLow').val()),
+ indicatorHi: Number($('#voltageIndicatorHigh').val()),
+ criticalVoltage: Number($('#criticalVoltage').val()),
+ voltageCheckInterval: Number($('#voltageCheckInterval').val())
},
"playlist": {
- sortMode: Number(document.getElementById('playlistSortMode').value)
+ sortMode: Number($('#playlistSortMode').val())
}
};
var myJSON = JSON.stringify(myObj);
@@ -2599,15 +2399,15 @@
}
}
- function sendVolume(vol) {
+ volumeSlider.on('input', e => {
var myObj = {
"controls": {
- set_volume: vol
+ set_volume: e.target.value
}
};
var myJSON = JSON.stringify(myObj);
socket.send(myJSON);
- }
+ });
async function tryRedirect() {
try {
console.log("redirect to startpage..")
@@ -2736,271 +2536,168 @@
});
}
- function setTitle(newTitle) {
- $('title').text(newTitle);
- $('#navbar-heading').text(newTitle);
- }
-
- function formatDBTooltip(target, value) {
- target.querySelector('.tooltip-main .tooltip-inner').innerHTML = `${value}`;
- }
-
- function updateTabStyle() {
- document.querySelectorAll('.nav-item').forEach((element) => { // Toggle styles
- if (lightSwitch.checked) { // Dark mode
- if (element.classList.contains('active')) {
- element.classList.add('bg-black');
- element.classList.add('text-white');
- } else {
- element.classList.remove('bg-black');
- element.classList.remove('text-white');
- }
- } else { // Light mode
- element.classList.remove('bg-black');
- element.classList.remove('text-white');
- element.classList.remove('bg-white');
- element.classList.remove('text-dark');
+ function setTitle(newTitle) {
+ $('title').text(newTitle);
+ $('#navbar-heading').text(newTitle);
+ }
+ $(document).ready(function() {
+
+ // step through all input ranges with tooltips to configure them
+ [...$('.form-range[data-bs-toggle="tooltip"]')].map(rangeEl => {
+ const range = $(rangeEl);
+ const mask = range.data('toggle-mask');
+
+ // if there is a mask, use it, otherwise just return the value
+ const formatTooltip = () => {
+ if (mask) {
+ return mask.replace('%', range.val())
}
- });
- }
- $(document).ready(function () {
- connect();
- buildFileSystemTree("/");
- $('#deleteSSIDModal').on('show.bs.modal', function (event) {
- var ssid = $(event.relatedTarget).data('ssid')
- $(this).find('.modal-title').text(i18next.t("wifi.delete.title"));
- $(this).find('.modal-body').text(i18next.t("wifi.delete.prompt", {
- ssid: ssid
- }));
- $(this).find('.btn-ok').attr('href', "javascript:deleteSSID('" + ssid + "')");
- })
- $('#deleteRFIDModal').on('show.bs.modal', function (event) {
- var rfid = $(event.relatedTarget).data('rfid')
- $(this).find('.modal-title').text(i18next.t("tools.nvs.delete.title"));
- $(this).find('.modal-body').text(i18next.t("tools.nvs.delete.prompt", {
- rfid: rfid
- }));
- $(this).find('.btn-ok').attr('href', "javascript:deleteRFID('" + rfid + "')");
- })
- $('.openPopupInfo').on('click', function () {
- fetchInfo();
- $('.modal-title').text(i18next.t("systeminfo.title"));
- $('#modalInfoRefresh').on('click', fetchInfo);
- new bootstrap.Modal(document.getElementById('modalInfo')).toggle();
- })
- $('.openPopupLog').on('click', function () {
- fetchLog();
- $('.modal-title').text(i18next.t("log"));
- $("#modalLogContent").css("font-family", "monospace");
- $('#modalLogRefresh').on('click', fetchLog);
- new bootstrap.Modal(document.getElementById('modalLog')).toggle();
- })
- $('.openPopupRestart').on('click', function () {
- $('#modalInfoRefresh').hide();
- restartDevice();
- });
- $('.openPopupShutdown').on('click', function () {
- $('#modalInfoRefresh').hide();
- shutdownDevice();
- });
- $('.openPopupEqualizer').on('click', () => {
- $('#modalEqualizer .modal-title').text(i18next.t("general.equalizer.title"));
- new bootstrap.Modal(document.getElementById('modalEqualizer')).toggle();
- });
- // sending equalizer settings to API for
- $('#modalEqualizer .slider').on('slideStop', function ({
- target,
- value
- }) {
- formatDBTooltip(target, value);
- let myObj = {
- "equalizer": {
- gainLowPass: Number(document.getElementById("gainLowPass").value),
- gainBandPass: Number(document.getElementById("gainBandPass").value),
- gainHighPass: Number(document.getElementById("gainHighPass").value)
- }
- };
- var myJSON = JSON.stringify(myObj);
- // update global settings
- window.settings = {
- ...window.settings,
- ...myObj
- };
- socket.send(myJSON);
- });
- $('#modalEqualizer .slider').on('slide', function ({
- target,
- value
- }) {
- formatDBTooltip(target, value);
- });
- $(function () {
- $('[data-bs-toggle="tooltip"]').tooltip();
- });
- /* Darkmode Switch with persistence in local storage
- * Copyright: https://www.cssscript.com/dark-mode-switcher-bootstrap-5 */
- let lightSwitch = document.getElementById('lightSwitch');
- if (!lightSwitch) {
- return;
- }
- /**
- * @function darkmode
- * @summary: changes the theme to 'dark mode' and save settings to local storage.
- * Basically, replaces/toggles every CSS class that has '-light' class with '-dark'
- */
- function darkMode() {
- console.log("darkmode");
- $('#explorerTree').jstree("set_theme", "default-dark");
- document.querySelectorAll('.bg-light').forEach((element) => { // Toggle styles
- element.className = element.className.replace(/-light/g, '-temp');
- element.className = element.className.replace(/-dark/g, '-light');
- element.className = element.className.replace(/-temp/g, '-dark');
- });
- document.querySelectorAll('.bg-white').forEach((element) => {
- element.className = element.className.replace(/bg-white/, 'bg-black');
- });
- document.querySelectorAll('.text-dark').forEach((element) => {
- element.className = element.className.replace(/text-dark/, 'text-white');
- });
- document.querySelectorAll('.select-div').forEach((element) => {
- element.setAttribute("data-bs-theme", "dark");
- });
- document.querySelectorAll('.header-nav-element').forEach((element) => {
- element.className = element.className.replace(/text-light/, 'text-dark');
- });
- document.querySelectorAll('.ctrl-button').forEach((element) => {
- element.className = element.className.replace(/text-light/, 'text-dark');
- });
- document.querySelector('.navbar-dark').setAttribute("data-bs-theme", "dark"); // Needed for Langsel
- document.body.classList.add('bg-dark');
- if (document.body.classList.contains('text-dark')) {
- document.body.classList.replace('text-dark', 'text-light');
- } else {
- document.body.classList.add('text-light');
- }
- // Tables
- var tables = document.querySelectorAll('table');
- for (var i = 0; i < tables.length; i++) {
- // add table-dark class to each table
- tables[i].classList.add('table-dark');
- }
- // set light switch input to true
- if (!lightSwitch.checked) {
- lightSwitch.checked = true;
- }
- localStorage.setItem('lightSwitch', 'dark');
- }
- /**
- * @function lightmode
- * @summary: changes the theme to 'light mode' and save settings to local storage.
- */
- function lightMode() {
- console.log("lightmode");
- $('#explorerTree').jstree("set_theme", "default");
- document.querySelectorAll('.bg-dark').forEach((element) => { // Toggle styles
- element.className = element.className.replace(/-dark/g, '-temp');
- element.className = element.className.replace(/-light/g, '-dark');
- element.className = element.className.replace(/-temp/g, '-light');
- });
- document.querySelectorAll('.bg-black').forEach((element) => {
- element.className = element.className.replace(/bg-black/, 'bg-white');
- });
- document.querySelectorAll('.text-white').forEach((element) => {
- element.className = element.className.replace(/text-white/, 'text-dark');
- });
- document.querySelectorAll('.select-div').forEach((element) => {
- element.setAttribute("data-bs-theme", "light");
- });
- document.querySelectorAll('.header-nav-element').forEach((element) => {
- element.className = element.className.replace(/text-dark/, 'text-light');
- });
- document.querySelectorAll('.ctrl-button').forEach((element) => {
- element.className = element.className.replace(/text-light/, 'text-dark');
- });
- document.querySelector('.navbar-dark').setAttribute("data-bs-theme", "light"); // Needed for Langsel
- document.body.classList.add('bg-light');
- if (document.body.classList.contains('text-light')) {
- document.body.classList.replace('text-light', 'text-dark');
- } else {
- document.body.classList.add('text-dark');
- }
- // Tables
- var tables = document.querySelectorAll('table');
- for (var i = 0; i < tables.length; i++) {
- if (tables[i].classList.contains('table-dark')) {
- tables[i].classList.remove('table-dark');
- }
- }
- if (lightSwitch.checked) {
- lightSwitch.checked = false;
- }
- localStorage.setItem('lightSwitch', 'light');
- }
- /**
- * @function onToggleMode
- * @summary: the event handler attached to the switch. calling @darkMode or @lightMode depending on the checked state.
- */
- function onToggleMode() {
- if (lightSwitch.checked) {
- darkMode();
- } else {
- lightMode();
- }
- updateTabStyle();
- }
- /**
- * @function getSystemDefaultTheme
- * @summary: get system default theme by media query
- */
- function getSystemDefaultTheme() {
- const darkThemeMq = window.matchMedia('(prefers-color-scheme: dark)');
- if (darkThemeMq.matches) {
- return 'dark';
- }
- return 'light';
+ return range.val();
}
- function darkmodeSwitchSetup() {
- var settings = localStorage.getItem('lightSwitch');
- if (settings == null) {
- settings = getSystemDefaultTheme();
+ // setup the tooltip
+ const tt = new bootstrap.Tooltip(rangeEl,
+ {
+ animation: false,
+ trigger: 'hover',
+ title: formatTooltip()
}
- if (settings == 'dark') {
- lightSwitch.checked = true;
+ );
+
+ // update the tooltip content each time the input is changing
+ range.on('input', () => tt.setContent({ '.tooltip-inner': formatTooltip() }));
+ });
+
+ connect();
+ buildFileSystemTree("/");
+ $('#deleteSSIDModal').on('show.bs.modal', function(event) {
+ var ssid = $(event.relatedTarget).data('ssid')
+ $(this).find('.modal-title').text(i18next.t("wifi.delete.title"));
+ $(this).find('.modal-body').text(i18next.t("wifi.delete.prompt", {
+ ssid: ssid
+ }));
+ $(this).find('.btn-ok').attr('href', "javascript:deleteSSID('" + ssid + "')");
+ })
+ $('#deleteRFIDModal').on('show.bs.modal', function(event) {
+ var rfid = $(event.relatedTarget).data('rfid')
+ $(this).find('.modal-title').text(i18next.t("tools.nvs.delete.title"));
+ $(this).find('.modal-body').text(i18next.t("tools.nvs.delete.prompt", {
+ rfid: rfid
+ }));
+ $(this).find('.btn-ok').attr('href', "javascript:deleteRFID('" + rfid + "')");
+ })
+ $('.openPopupInfo').on('click', function() {
+ fetchInfo();
+ $('.modal-title').text(i18next.t("systeminfo.title"));
+ $('#modalInfoRefresh').on('click', fetchInfo);
+ new bootstrap.Modal(document.getElementById('modalInfo')).toggle();
+ })
+ $('.openPopupLog').on('click', function() {
+ fetchLog();
+ $('.modal-title').text(i18next.t("log"));
+ $("#modalLogContent").css("font-family", "monospace");
+ $('#modalLogRefresh').on('click', fetchLog);
+ new bootstrap.Modal(document.getElementById('modalLog')).toggle();
+ })
+ $('.openPopupRestart').on('click', function() {
+ $('#modalInfoRefresh').hide();
+ restartDevice();
+ });
+ $('.openPopupShutdown').on('click', function() {
+ $('#modalInfoRefresh').hide();
+ shutdownDevice();
+ });
+ $('.openPopupEqualizer').on('click', () => {
+ $('#modalEqualizer .modal-title').text(i18next.t("general.equalizer.title"));
+ new bootstrap.Modal(document.getElementById('modalEqualizer')).toggle();
+ });
+ // sending equalizer settings to API for
+ $('#modalEqualizer .form-range').on('change', function({
+ target,
+ value
+ }) {
+ let myObj = {
+ "equalizer": {
+ gainLowPass: Number(document.getElementById("gainLowPass").value),
+ gainBandPass: Number(document.getElementById("gainBandPass").value),
+ gainHighPass: Number(document.getElementById("gainHighPass").value)
}
- lightSwitch.addEventListener('change', onToggleMode);
- onToggleMode();
+ };
+ var myJSON = JSON.stringify(myObj);
+ // update global settings
+ window.settings = {
+ ...window.settings,
+ ...myObj
+ };
+ socket.send(myJSON);
+ });
+ $(function() {
+ $('[data-bs-toggle="tooltip"]').tooltip();
+ });
+
+ const lightSwitch = $('#lightSwitch');
+ /* Changes the color mode to a new one and saves the value to local storage. */
+ function newColorMode(mode) {
+ console.log('new mode', mode);
+
+ $('body').attr("data-bs-theme", mode);
+ // File explorer knows 'default' or 'default-dark' as themes
+ $('#explorerTree').jstree('set_theme', mode == 'dark' ? 'default-dark' : 'default');
+
+ localStorage.setItem('lightSwitch', mode);
+ }
+
+ /* Triggers a newColorMode(..) call with either 'dark' or 'light' as the new color mode. */
+ function onSwitchDarkMode() {
+ newColorMode(lightSwitch.prop('checked') ? 'dark' : 'light');
+ }
+ /**
+ * @function getSystemDefaultTheme
+ * @summary: get system default theme by media query
+ */
+ function getSystemDefaultTheme() {
+ const darkThemeMq = window.matchMedia('(prefers-color-scheme: dark)');
+ if(darkThemeMq.matches) {
+ return 'dark';
}
+ return 'light';
+ }
- function selectActiveTabFromLocalStorage() {
- /* Load last selected tab from local storage and set it as active*/
- ActiveTab = localStorage.getItem("active-tab");
- if (ActiveTab == null) {
- ActiveTab = "nav-rfid-tab";
- }
- console.log("ActiveTab: " + ActiveTab);
- document.querySelectorAll('.main-tab-item').forEach((element) => {
- element.classList.remove('active');
- element.setAttribute("aria-selected", false);
- if (ActiveTab == element.id) {
- element.classList.add('active');
- element.setAttribute("aria-selected", true);
- }
- });
- document.querySelectorAll('.main-tab-pane').forEach((element) => {
- console.log("element id:", element.id);
- element.classList.remove('active');
- element.classList.remove('show');
- if (ActiveTab.replace("-tab", "") == element.id) {
- element.classList.add('active');
- element.classList.add('show');
- }
- });
+ /* Fetches the settings for lightSwitch from storage or the system default theme. */
+ function darkmodeSwitchSetup() {
+ lightSwitch.prop('checked', (localStorage.getItem('lightSwitch') || getSystemDefaultTheme()) == 'dark');
+ onSwitchDarkMode();
+ lightSwitch.change(onSwitchDarkMode);
+ }
+
+ function selectActiveTabFromLocalStorage() {
+ /* Load last selected tab from local storage and set it as active*/
+ ActiveTab = localStorage.getItem("active-tab");
+ if(ActiveTab == null) {
+ ActiveTab = "nav-rfid-tab";
}
- darkmodeSwitchSetup();
- selectActiveTabFromLocalStorage();
- updateTabStyle();
- });
+ console.log("ActiveTab: " + ActiveTab);
+ document.querySelectorAll('.main-tab-item').forEach((element) => {
+ element.classList.remove('active');
+ element.setAttribute("aria-selected", false);
+ if(ActiveTab == element.id) {
+ element.classList.add('active');
+ element.setAttribute("aria-selected", true);
+ }
+ });
+ document.querySelectorAll('.main-tab-pane').forEach((element) => {
+ console.log("element id:", element.id);
+ element.classList.remove('active');
+ element.classList.remove('show');
+ if(ActiveTab.replace("-tab", "") == element.id) {
+ element.classList.add('active');
+ element.classList.add('show');
+ }
+ });
+ }
+ darkmodeSwitchSetup();
+ selectActiveTabFromLocalStorage();
+ });
diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp
index ecc6e991..b1ed6556 100644
--- a/src/AudioPlayer.cpp
+++ b/src/AudioPlayer.cpp
@@ -80,19 +80,20 @@ void AudioPlayer_Init(void) {
uint8_t playListSortModeValue = gPrefsSettings.getUChar("PLSortMode", EnumUtils::underlying_value(AudioPlayer_PlaylistSortMode));
AudioPlayer_PlaylistSortMode = EnumUtils::to_enum
(playListSortModeValue);
-#ifndef USE_LAST_VOLUME_AFTER_REBOOT
- // Get initial volume from NVS
- uint32_t nvsInitialVolume = gPrefsSettings.getUInt("initVolume", 0);
-#else
- // Get volume used at last shutdown
- uint32_t nvsInitialVolume = gPrefsSettings.getUInt("previousVolume", 999);
- if (nvsInitialVolume == 999) {
- gPrefsSettings.putUInt("previousVolume", AudioPlayer_GetInitVolume());
- nvsInitialVolume = AudioPlayer_GetInitVolume();
+ uint32_t nvsInitialVolume;
+ if (!gPrefsSettings.getBool("recoverVolBoot", false)) {
+ // Get initial volume from NVS
+ nvsInitialVolume = gPrefsSettings.getUInt("initVolume", 0);
} else {
- Log_Println(rememberLastVolume, LOGLEVEL_ERROR);
+ // Get volume used at last shutdown
+ nvsInitialVolume = gPrefsSettings.getUInt("previousVolume", 999);
+ if (nvsInitialVolume == 999) {
+ gPrefsSettings.putUInt("previousVolume", AudioPlayer_GetInitVolume());
+ nvsInitialVolume = AudioPlayer_GetInitVolume();
+ } else {
+ Log_Println(rememberLastVolume, LOGLEVEL_ERROR);
+ }
}
-#endif
if (nvsInitialVolume) {
AudioPlayer_SetInitVolume(nvsInitialVolume);
@@ -141,6 +142,8 @@ void AudioPlayer_Init(void) {
gPlayProperties.coverFilePos = 0;
AudioPlayer_StationLogoUrl = "";
gPlayProperties.playlist = new Playlist();
+ gPlayProperties.SavePlayPosRfidChange = gPrefsSettings.getBool("savePosRfidChge", false); // SAVE_PLAYPOS_WHEN_RFID_CHANGE
+ gPlayProperties.pauseOnMinVolume = gPrefsSettings.getBool("pauseOnMinVol", false); // PAUSE_ON_MIN_VOLUME
// Don't start audio-task in BT-speaker mode!
if ((System_GetOperationMode() == OPMODE_NORMAL) || (System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE)) {
@@ -161,15 +164,12 @@ void AudioPlayer_Exit(void) {
// save playtime total to NVS
playTimeSecTotal += playTimeSecSinceStart;
gPrefsSettings.putULong("playTimeTotal", playTimeSecTotal);
-// Make sure last playposition for audiobook is saved when playback is active while shutdown was initiated
-#ifdef SAVE_PLAYPOS_BEFORE_SHUTDOWN
- if (!gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) {
- AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);
+ // Make sure last playposition for audiobook is saved when playback is active while shutdown was initiated
+ if (gPrefsSettings.getBool("savePosShutdown", false) && !gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) { AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);
while (!gPlayProperties.pausePlay) { // Make sure to wait until playback is paused in order to be sure that playposition saved in NVS
vTaskDelay(portTICK_PERIOD_MS * 100u);
}
}
-#endif
}
static uint32_t lastPlayingTimestamp = 0;
@@ -283,13 +283,8 @@ void Audio_setTitle(const char *format, ...) {
// Set maxVolume depending on headphone-adjustment is enabled and headphone is/is not connected
// Enable/disable PA/HP-amps initially
void AudioPlayer_SetupVolumeAndAmps(void) {
-#ifdef PLAY_MONO_SPEAKER
- gPlayProperties.currentPlayMono = true;
- gPlayProperties.newPlayMono = true;
-#else
- gPlayProperties.currentPlayMono = false;
- gPlayProperties.newPlayMono = false;
-#endif
+ gPlayProperties.currentPlayMono = gPrefsSettings.getBool("playMono", false);
+ gPlayProperties.newPlayMono = gPrefsSettings.getBool("playMono", false);
#ifndef HEADPHONE_ADJUST_ENABLE
AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeSpeaker;
@@ -332,11 +327,7 @@ void AudioPlayer_HeadphoneVolumeManager(void) {
if (AudioPlayer_HeadphoneLastDetectionState != currentHeadPhoneDetectionState && (millis() - AudioPlayer_HeadphoneLastDetectionTimestamp >= headphoneLastDetectionDebounce)) {
if (currentHeadPhoneDetectionState) {
AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeSpeaker;
- #ifdef PLAY_MONO_SPEAKER
- gPlayProperties.newPlayMono = true;
- #else
- gPlayProperties.newPlayMono = false;
- #endif
+ gPlayProperties.newPlayMono = gPrefsSettings.getBool("playMono", false);
#ifdef GPIO_PA_EN
Port_Write(GPIO_PA_EN, true, false);
@@ -391,7 +382,7 @@ void AudioPlayer_Task(void *parameter) {
AudioPlayer_CurrentVolume = AudioPlayer_GetInitVolume();
audio->setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
audio->setVolumeSteps(AUDIOPLAYER_VOLUME_MAX);
- audio->setVolume(AudioPlayer_CurrentVolume, VOLUMECURVE);
+ audio->setVolume(AudioPlayer_CurrentVolume, gPrefsSettings.getUChar("volumeCurve", 0));
audio->forceMono(gPlayProperties.currentPlayMono);
int8_t currentEqualizer[3] = {gPrefsSettings.getChar("gainLowPass", 0), gPrefsSettings.getChar("gainBandPass", 0), gPrefsSettings.getChar("gainHighPass", 0)};
audio->setTone(currentEqualizer[0], currentEqualizer[1], currentEqualizer[2]);
@@ -412,7 +403,7 @@ void AudioPlayer_Task(void *parameter) {
*/
if (xQueueReceive(gVolumeQueue, ¤tVolume, 0) == pdPASS) {
Log_Printf(LOGLEVEL_INFO, newLoudnessReceivedQueue, currentVolume);
- audio->setVolume(currentVolume, VOLUMECURVE);
+ audio->setVolume(currentVolume, gPrefsSettings.getUChar("volumeCurve", 0));
Web_SendWebsocketData(0, WebsocketCodeType::Volume);
#ifdef MQTT_ENABLE
publishMqtt(topicLoudnessState, currentVolume, false);
@@ -973,36 +964,33 @@ void AudioPlayer_EqualizerToQueueSender(const int8_t gainLowPass, const int8_t g
// Pauses playback if playback is active and volume is changes from minVolume+1 to minVolume (usually 0)
void AudioPlayer_PauseOnMinVolume(const uint8_t oldVolume, const uint8_t newVolume) {
-#ifdef PAUSE_ON_MIN_VOLUME
- if (gPlayProperties.playMode == BUSY || gPlayProperties.playMode == NO_PLAYLIST) {
- return;
- }
+ if (gPlayProperties.pauseOnMinVolume) {
+ if(gPlayProperties.playMode == BUSY || gPlayProperties.playMode == NO_PLAYLIST) {
+ return;
+ }
- if (!gPlayProperties.pausePlay) { // Volume changes from 1 to 0
- if (oldVolume == AudioPlayer_GetMinVolume() + 1 && newVolume == AudioPlayer_GetMinVolume()) {
- Cmd_Action(CMD_PLAYPAUSE);
+ if (!gPlayProperties.pausePlay) { // Volume changes from 1 to 0
+ if (oldVolume == AudioPlayer_GetMinVolume() + 1 && newVolume == AudioPlayer_GetMinVolume()) {
+ Cmd_Action(CMD_PLAYPAUSE);
+ }
}
- }
- if (gPlayProperties.pausePlay) { // Volume changes from 0 to 1
- if (oldVolume == AudioPlayer_GetMinVolume() && newVolume > AudioPlayer_GetMinVolume()) {
- Cmd_Action(CMD_PLAYPAUSE);
+ if (gPlayProperties.pausePlay) { // Volume changes from 0 to 1
+ if (oldVolume == AudioPlayer_GetMinVolume() && newVolume > AudioPlayer_GetMinVolume()) {
+ Cmd_Action(CMD_PLAYPAUSE);
+ }
}
}
-#endif
}
// Receives de-serialized RFID-data (from NVS) and dispatches playlists for the given
// playmode to the track-queue.
void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _lastPlayPos, const uint32_t _playMode, const uint16_t _trackLastPlayed) {
-// Make sure last playposition for audiobook is saved when new RFID-tag is applied
-#ifdef SAVE_PLAYPOS_WHEN_RFID_CHANGE
- if (!gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) {
- AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);
+ // Make sure last playposition for audiobook is saved when new RFID-tag is applied
+ if (gPlayProperties.SavePlayPosRfidChange && !gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) { AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);
while (!gPlayProperties.pausePlay) { // Make sure to wait until playback is paused in order to be sure that playposition saved in NVS
vTaskDelay(portTICK_PERIOD_MS * 100u);
}
}
-#endif
gPlayProperties.startAtFilePos = _lastPlayPos;
gPlayProperties.currentTrackNumber = _trackLastPlayed;
diff --git a/src/AudioPlayer.h b/src/AudioPlayer.h
index ff4a4b19..c127df83 100644
--- a/src/AudioPlayer.h
+++ b/src/AudioPlayer.h
@@ -39,6 +39,8 @@ typedef struct { // Bit field
uint8_t tellMode : 2; // Tell mode for text to speech announcments
bool currentSpeechActive : 1; // If speech-play is active
bool lastSpeechActive : 1; // If speech-play was active
+ bool SavePlayPosRfidChange : 1; // Save last play-position
+ bool pauseOnMinVolume : 1; // When playback is active and volume is changed to zero, playback is paused automatically.
int8_t gainLowPass = 0; // Low Pass for EQ Control
int8_t gainBandPass = 0; // Band Pass for EQ Control
int8_t gainHighPass = 0; // High Pass for EQ Control
diff --git a/src/Bluetooth.cpp b/src/Bluetooth.cpp
index e4f8bcbc..ce27f1d8 100644
--- a/src/Bluetooth.cpp
+++ b/src/Bluetooth.cpp
@@ -202,9 +202,9 @@ void Bluetooth_Init(void) {
a2dp_sink->set_rssi_callback(rssi);
#endif
a2dp_sink->activate_pin_code(false);
- #ifdef PLAY_MONO_SPEAKER
- a2dp_sink->set_mono_downmix(true);
- #endif
+ if (gPrefsSettings.getBool("playMono", false)) {
+ a2dp_sink->set_mono_downmix(true);
+ }
a2dp_sink->set_auto_reconnect(true);
a2dp_sink->set_rssi_active(true);
// start bluetooth sink
diff --git a/src/System.cpp b/src/System.cpp
index e1c898e7..66393e47 100644
--- a/src/System.cpp
+++ b/src/System.cpp
@@ -193,9 +193,9 @@ void System_PreparePowerDown(void) {
Mqtt_Exit();
Led_Exit();
-#ifdef USE_LAST_VOLUME_AFTER_REBOOT
- gPrefsSettings.putUInt("previousVolume", AudioPlayer_GetCurrentVolume());
-#endif
+ if (gPrefsSettings.getBool("recoverVolBoot", false)) {
+ gPrefsSettings.putUInt("previousVolume", AudioPlayer_GetCurrentVolume());
+ }
SdCard_Exit();
Serial.flush();
diff --git a/src/Web.cpp b/src/Web.cpp
index 3f36f939..e84ed0e8 100644
--- a/src/Web.cpp
+++ b/src/Web.cpp
@@ -636,10 +636,13 @@ bool JSONToSettings(JsonObject doc) {
}
if (doc.containsKey("general")) {
// general settings
- if (gPrefsSettings.putUInt("initVolume", doc["general"]["initVolume"].as()) == 0 || gPrefsSettings.putUInt("maxVolumeSp", doc["general"]["maxVolumeSp"].as()) == 0 || gPrefsSettings.putUInt("maxVolumeHp", doc["general"]["maxVolumeHp"].as()) == 0 || gPrefsSettings.putUInt("mInactiviyT", doc["general"]["sleepInactivity"].as()) == 0) {
+ if (gPrefsSettings.putUInt("initVolume", doc["general"]["initVolume"].as()) == 0 || gPrefsSettings.putUInt("maxVolumeSp", doc["general"]["maxVolumeSp"].as()) == 0 || gPrefsSettings.putUInt("maxVolumeHp", doc["general"]["maxVolumeHp"].as()) == 0 || gPrefsSettings.putUInt("mInactiviyT", doc["general"]["sleepInactivity"].as()) == 0 || gPrefsSettings.putBool("playMono", doc["general"]["playMono"].as()) == 0 || gPrefsSettings.putBool("savePosShutdown", doc["general"]["savePosShutdown"].as()) == 0 || gPrefsSettings.putBool("savePosRfidChge", doc["general"]["savePosRfidChge"].as()) == 0 || gPrefsSettings.putBool("pauseOnMinVol", doc["general"]["pauseOnMinVol"].as()) == 0 || gPrefsSettings.putBool("recoverVolBoot", doc["general"]["recoverVolBoot"].as()) == 0 || gPrefsSettings.putUChar("volumeCurve", doc["general"]["volumeCurve"].as()) == 0) {
Log_Printf(LOGLEVEL_ERROR, webSaveSettingsError, "general");
return false;
}
+ gPlayProperties.newPlayMono = doc["general"]["playMono"].as();
+ gPlayProperties.SavePlayPosRfidChange = doc["general"]["savePosRfidChg"].as();
+ gPlayProperties.pauseOnMinVolume = doc["general"]["pauseOnMinVol"].as();
}
if (doc.containsKey("equalizer")) {
int8_t _gainLowPass = doc["equalizer"]["gainLowPass"].as();
@@ -824,6 +827,12 @@ static void settingsToJSON(JsonObject obj, const String section) {
generalObj["maxVolumeSp"].set(gPrefsSettings.getUInt("maxVolumeSp", 0));
generalObj["maxVolumeHp"].set(gPrefsSettings.getUInt("maxVolumeHp", 0));
generalObj["sleepInactivity"].set(gPrefsSettings.getUInt("mInactiviyT", 0));
+ generalObj["playMono"].set(gPrefsSettings.getBool("playMono", false));
+ generalObj["savePosShutdown"].set(gPrefsSettings.getBool("savePosShutdown", false)); // SAVE_PLAYPOS_BEFORE_SHUTDOWN
+ generalObj["savePosRfidChge"].set(gPrefsSettings.getBool("savePosRfidChge", false)); // SAVE_PLAYPOS_WHEN_RFID_CHANGE
+ generalObj["pauseOnMinVol"].set(gPrefsSettings.getBool("pauseOnMinVol", false)); // PAUSE_ON_MIN_VOLUME
+ generalObj["recoverVolBoot"].set(gPrefsSettings.getBool("recoverVolBoot", false)); // USE_LAST_VOLUME_AFTER_REBOOT
+ generalObj["volumeCurve"].set(gPrefsSettings.getUChar("volumeCurve", 0)); // VOLUMECURVE
}
if ((section == "") || (section == "equalizer")) {
// equalizer settings
@@ -881,30 +890,41 @@ static void settingsToJSON(JsonObject obj, const String section) {
}
#endif
if (section == "defaults") {
- // default factory settings
+ // default factory settings NOTE: maintain the settings section structure as above to make it easier for clients to use
JsonObject defaultsObj = obj.createNestedObject("defaults");
- defaultsObj["initVolume"].set(3u); // AUDIOPLAYER_VOLUME_INIT
- defaultsObj["maxVolumeSp"].set(21u); // AUDIOPLAYER_VOLUME_MAX
- defaultsObj["maxVolumeHp"].set(18u); // gPrefsSettings.getUInt("maxVolumeHp", 0));
- defaultsObj["sleepInactivity"].set(10u); // System_MaxInactivityTime
- defaultsObj["gainHighPass"].set(0);
- defaultsObj["gainBandPass"].set(0);
- defaultsObj["gainLowPass"].set(0);
+ JsonObject genSettings = defaultsObj.createNestedObject("general");
+ genSettings["initVolume"].set(3u); // AUDIOPLAYER_VOLUME_INIT
+ genSettings["maxVolumeSp"].set(21u); // AUDIOPLAYER_VOLUME_MAX
+ genSettings["maxVolumeHp"].set(18u); // gPrefsSettings.getUInt("maxVolumeHp", 0));
+ genSettings["sleepInactivity"].set(10u); // System_MaxInactivityTime
+ genSettings["playMono"].set(false); // PLAY_MONO_SPEAKER
+ genSettings["savePosShutdown"].set(false); // SAVE_PLAYPOS_BEFORE_SHUTDOWN
+ genSettings["savePosRfidChg"].set(false); // SAVE_PLAYPOS_WHEN_RFID_CHANGE
+ genSettings["pauseOnMinVol"].set(false); // PAUSE_ON_MIN_VOLUME
+ genSettings["recoverVolBoot"].set(false); // USE_LAST_VOLUME_AFTER_REBOOT
+ genSettings["volumeCurve"].set(0u); // VOLUME_CURVE
+ JsonObject eqSettings = defaultsObj.createNestedObject("equalizer");
+ eqSettings["gainHighPass"].set(0);
+ eqSettings["gainBandPass"].set(0);
+ eqSettings["gainLowPass"].set(0);
#ifdef NEOPIXEL_ENABLE
- defaultsObj["initBrightness"].set(16u); // LED_INITIAL_BRIGHTNESS
- defaultsObj["nightBrightness"].set(2u); // LED_INITIAL_NIGHT_BRIGHTNESS
+ JsonObject ledSettings = defaultsObj.createNestedObject("led");
+ ledSettings["initBrightness"].set(16u); // LED_INITIAL_BRIGHTNESS
+ ledSettings["nightBrightness"].set(2u); // LED_INITIAL_NIGHT_BRIGHTNESS
#endif
- defaultsObj["sortMode"].set(EnumUtils::underlying_value(AUDIOPLAYER_PLAYLIST_SORT_MODE_DEFAULT));
+ JsonObject playlistSettings = defaultsObj.createNestedObject("playlist");
+ playlistSettings["sortMode"].set(EnumUtils::underlying_value(AUDIOPLAYER_PLAYLIST_SORT_MODE_DEFAULT));
#ifdef BATTERY_MEASURE_ENABLE
+ JsonObject batSettings = defaultsObj.createNestedObject("battery");
#ifdef MEASURE_BATTERY_VOLTAGE
- defaultsObj["warnLowVoltage"].set(s_warningLowVoltage);
- defaultsObj["indicatorLow"].set(s_voltageIndicatorLow);
- defaultsObj["indicatorHi"].set(s_voltageIndicatorHigh);
+ batSettings["warnLowVoltage"].set(s_warningLowVoltage);
+ batSettings["indicatorLow"].set(s_voltageIndicatorLow);
+ batSettings["indicatorHi"].set(s_voltageIndicatorHigh);
#ifdef SHUTDOWN_ON_BAT_CRITICAL
- defaultsObj["criticalVoltage"].set(s_warningCriticalVoltage);
+ batSettings["criticalVoltage"].set(s_warningCriticalVoltage);
#endif
#endif
- defaultsObj["voltageCheckInterval"].set(s_batteryCheckInterval);
+ batSettings["voltageCheckInterval"].set(s_batteryCheckInterval);
#endif
}
// FTP