folderlauncher: add a way to move apps between folders from web interface

Web interface still can not do everything settings on phone can, still
it is very useful to sort applications between folders.
pull/3241/head
Pavel Machek 2024-02-24 00:17:12 +01:00
parent 79444702de
commit 7e4a83f928
4 changed files with 243 additions and 3 deletions

View File

@ -1,3 +1,4 @@
0.01: New app! 0.01: New app!
0.02: Handle files potentially not existing 0.02: Handle files potentially not existing
0.03: Add setting to disable vibration 0.03: Add setting to disable vibration
0.04: Add glue to allow moving applications from web interface

View File

@ -33,4 +33,8 @@ Swiping up and down will scroll. Swiping from the left, using the back button, o
* Move app here: Display a list of apps. Selecting one moves it into the folder. * Move app here: Display a list of apps. Selecting one moves it into the folder.
* One menu entry for each subfolder, which opens the folder management menu for that subfolder. * One menu entry for each subfolder, which opens the folder management menu for that subfolder.
* View apps: Only present if this folder contains apps, Display a menu of all apps in the folder. This is for information only, tapping the apps does nothing. * View apps: Only present if this folder contains apps, Display a menu of all apps in the folder. This is for information only, tapping the apps does nothing.
* Delete folder: Only present if not viewing the root folder. Delete the current folder and move all apps into the parent folder. * Delete folder: Only present if not viewing the root folder. Delete the current folder and move all apps into the parent folder.
## Web interface
Limited editing is possible from the web interface. You can add folders and move applications between folders.

View File

@ -0,0 +1,234 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../../css/spectre.min.css">
<link rel="stylesheet" href="../../css/spectre-icons.min.css">
<link rel="stylesheet" href="../../css/spectre-icons.min.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css">
<script type="module">
import vcf from 'https://cdn.jsdelivr.net/npm/vcf@2.1.1/+esm'
window.vcf = vcf;
</script>
<style type="text/css">
html, body { height: 100% }
.flex-col { display:flex; flex-direction:column; height:100% }
#map { width:100%; height:100% }
#tab-list { width:100%; height:100% }
/* https://stackoverflow.com/a/58686215 */
.arrow-icon {
width: 14px;
height: 14px;
}
.arrow-icon > div {
margin-left: -1px;
margin-top: -3px;
transform-origin: center center;
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<h1>Folder Launcher v0.04</h1>
<div class="flex-col">
<div id="statusarea">
<button id="download" class="btn btn-error">Reload</button> <button id="upload" class="btn btn-primary">Upload</button>
<span id="status"></span>
<span id="routestatus"></span>
</div>
<div style="flex: 1">
<div id="tab-list">
<table class="table">
<thead>
<tr>
<th>App</th>
<th>Folder</th>
<th>Move to</th>
</tr>
</thead>
<tbody id="list">
</tbody>
</table>
<br>
<h4>Add a new folder</h4>
<form id="add_folder_form">
<div class="columns">
<div class="column col-3 col-xs-8">
<input class="form-input input-sm" type="text" id="add_folder_name" placeholder="Name">
</div>
</div>
<div class="columns">
<div class="column col-3 col-xs-8">
<button id="add_folder_button" class="btn btn-primary btn-sm">Add Folder</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script src="../../core/lib/interface.js"></script>
<script>
var json = [];
var folders = [];
// ==========================================================================
/*** status ***/
function clean() {
$('#status').html('<i class="icon icon-check"></i> No pending changes.');
}
function dirty() {
$('#status').html('<b><i class="icon icon-edit"></i> Changes have not been sent to the watch.</b>');
}
/*** util ***/
// https://stackoverflow.com/a/22706073
function escapeHTML(str){
return new Option(str).innerHTML;
}
/*** Bangle.js ***/
function gotStored(pts) {
json = pts;
renderAllApps();
}
// ========================================================================== LIST
var $name = document.getElementById('add_folder_name')
var $form = document.getElementById('add_folder_form')
var $add_folder_button = document.getElementById('add_folder_button')
var $list = document.getElementById('list')
$add_folder_button.addEventListener('click', event => {
event.preventDefault()
var name = $name.value.trim()
if(!name) return;
let n = {};
n.folders = {};
n.apps = [];
json.rootFolder.folders[name] = n;
renderAllApps()
$name.value = ''
dirty();
});
function moveTo(appId, dst){
let config = json;
let path = [];
path.push(dst);
console.log(`Move ${appId} to ${dst}`);
var folder = config.rootFolder;
for (var _i = 0, _a = config.apps[appId].folder; _i < _a.length; _i++) {
var folderName = _a[_i];
folder = folder.folders[folderName];
}
console.log(`Move ${appId} from ${folder}`);
folder.apps = folder.apps.filter(function (item) { return item != appId; });
config.apps[appId].folder = path.slice();
folder = config.rootFolder;
for (var _b = 0, path_2 = path; _b < path_2.length; _b++) {
var folderName = path_2[_b];
folder = folder.folders[folderName];
}
folder.apps.push(appId);
console.log(`Move done?`);
renderAllApps();
dirty();
}
function renderAppsList(){
folders = [];
$list.innerHTML = '';
Object.entries(json.rootFolder.folders).forEach(([name, params]) => {
console.log('Folders:', name);
folders.push(name);
});
Object.entries(json.apps).forEach(([name, params]) => {
let $contact = document.createElement('tr')
let folder = params.folder;
console.log('Foreach', name, folder);
if (folder != '') {
$contact.innerHTML = `<td>${name}</td><td>${folder}</td>`;
} else {
$contact.innerHTML = `<td>${name}</td><td>/</td>`;
}
let buttons = "";
for (let f of folders) {
buttons += `<button class="btn" onclick="moveTo('${name}', '${f}')">${f}</button>`;
}
$contact.innerHTML += `<td>${buttons}</td>`;
$list.appendChild($contact)
});
}
function renderApps() {
renderAppsList();
}
function renderAllApps() {
renderAppsList();
}
// ========================================================================== UPLOAD/DOWNLOAD
function downloadJSONfile(fileid, callback) {
// TODO: use interface.js-provided stuff?
Puck.write(`\x10(function() {
var pts = require("Storage").readJSON("${fileid}")||[{name:"NONE"}];
Bluetooth.print(JSON.stringify(pts));
})()\n`, contents => {
if (contents=='[{name:"NONE"}]') contents="[]";
var storedpts = JSON.parse(contents);
callback(storedpts);
clean();
});
}
function uploadFile(fileid, contents) {
// TODO: use interface.js-provided stuff?
Puck.write(`\x10(function() {
require("Storage").write("${fileid}",'${contents}');
Bluetooth.print("OK");
})()\n`, ret => {
console.log("uploadFile", ret);
if (ret == "OK")
clean();
});
}
function onInit() {
downloadJSONfile("folderlaunch.json", gotStored);
}
$('#download').on('click', function() {
downloadJSONfile("folderlaunch.json", gotStored);
});
$('#upload').click(function() {
var data = JSON.stringify(json);
uploadFile("folderlaunch.json",data);
});
// ========================================================================== FINALLY...
clean();
renderAllApps();
</script>
</body>
</html>

View File

@ -1,7 +1,7 @@
{ {
"id": "folderlaunch", "id": "folderlaunch",
"name": "Folder launcher", "name": "Folder launcher",
"version": "0.03", "version": "0.04",
"description": "Launcher that allows you to put your apps into folders", "description": "Launcher that allows you to put your apps into folders",
"icon": "icon.png", "icon": "icon.png",
"type": "launch", "type": "launch",
@ -10,6 +10,7 @@
"BANGLEJS2" "BANGLEJS2"
], ],
"readme": "README.md", "readme": "README.md",
"interface": "interface.html",
"storage": [ "storage": [
{ {
"name": "folderlaunch.app.js", "name": "folderlaunch.app.js",