Update site structure, update global js to add domain warning, update SpiderADB
|
@ -1,6 +1,3 @@
|
||||||
*.bak
|
*.bak
|
||||||
node_modules/
|
node_modules/
|
||||||
/public/a/
|
/public/
|
||||||
/public/s/
|
|
||||||
/public/SpiderADB/
|
|
||||||
/public/WuppiMini/
|
|
||||||
|
|
18
Build.sh
|
@ -1,12 +1,24 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
for App in SpiderADB WuppiMini
|
SourceApps="SpiderADB WuppiMini"
|
||||||
|
HubSdkApps="$(SourceApps) Ecoji MatrixStickerHelper"
|
||||||
|
|
||||||
|
rm -vrf ./public || true
|
||||||
|
cp -vr ./static ./public
|
||||||
|
cp -vr ./shared ./public/shared
|
||||||
|
|
||||||
|
for App in $(SourceApps)
|
||||||
do
|
do
|
||||||
mkdir -p ./public/${App}
|
mkdir -p ./public/${App}
|
||||||
cd ./src/${App}
|
cd ./source/${App}
|
||||||
sh ./Requirements.sh
|
sh ./Requirements.sh
|
||||||
cp -r $(sh ./Build.sh) ../../public/${App}/
|
cp -r $(sh ./Build.sh) ../../public/${App}/
|
||||||
cd ../..
|
cd ../..
|
||||||
done
|
done
|
||||||
cp -r ./shared ./public/shared
|
|
||||||
cd ./public
|
cd ./public
|
||||||
node ../WriteRedirectPages.js
|
node ../WriteRedirectPages.js
|
||||||
|
|
||||||
|
for App in $(HubSdkApps)
|
||||||
|
do
|
||||||
|
echo # TODO write manifest.json files
|
||||||
|
done
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
window.addEventListener('load', (function(){
|
||||||
|
|
||||||
|
if (!['', 'hub.octt.eu.org'].includes(location.host)) {
|
||||||
|
var noticeElem = document.createElement('p');
|
||||||
|
noticeElem.style = `
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1000;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
color: black;
|
||||||
|
background-color: thistle;
|
||||||
|
font-size: initial;
|
||||||
|
font-size: smaller;
|
||||||
|
text-align: center;
|
||||||
|
`;
|
||||||
|
noticeElem.innerHTML = `You are viewing this page on the secondary/backup domain. <a style="color: darkblue;" href="https://hub.octt.eu.org${location.pathname}">Open it on hub.octt.eu.org</a>.
|
||||||
|
<button style="
|
||||||
|
float: right;
|
||||||
|
height: 1.25em;
|
||||||
|
margin: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
" onclick="this.parentElement.remove()">X</button>`;
|
||||||
|
document.body.appendChild(noticeElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
}));
|
|
@ -1,48 +1,54 @@
|
||||||
import * as Adb from '@yume-chan/adb';
|
import * as Adb from '@yume-chan/adb';
|
||||||
import * as AdbDaemonWebUsb from '@yume-chan/adb-daemon-webusb';
|
import * as AdbDaemonWebUsb from '@yume-chan/adb-daemon-webusb';
|
||||||
import AdbWebCredentialStore from '@yume-chan/adb-credential-web';
|
import AdbWebCredentialStore from '@yume-chan/adb-credential-web';
|
||||||
import { DecodeUtf8Stream } from '@yume-chan/stream-extra';
|
import { DecodeUtf8Stream, WrapReadableStream, WrapConsumableStream } from '@yume-chan/stream-extra';
|
||||||
|
import { PackageManager } from '@yume-chan/android-bin';
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// * warning on fail to claim USB interface (it may be because of other tabs, or a local adb server)
|
// * warning on fail to claim USB interface (it may be because of other tabs, or a local adb server)
|
||||||
// * warn or gracefully handle debug permission not granted
|
// * warn or gracefully handle debug permission not granted
|
||||||
// * package manager with install/uninstall/dump, debloat tool with default list and import/export
|
// * package manager with install/uninstall/dump, debloat tool with default list and import/export
|
||||||
// * fastboot shell and tools? possible?
|
// * fastboot shell and tools? possible?
|
||||||
|
// * logs for Packages section?
|
||||||
|
|
||||||
(async function(){
|
(async function(){
|
||||||
|
|
||||||
const deviceSelect = $('select$deviceSelect$');
|
const deviceSelect = $('select$deviceSelect$');
|
||||||
const deviceConnect = $('button$deviceConnect$');
|
|
||||||
const terminalOutput = $('textarea$terminalOutput$');
|
const terminalOutput = $('textarea$terminalOutput$');
|
||||||
|
|
||||||
function resizeTerminal () {
|
$('button$apkInstall$').onclick = (async function(){
|
||||||
terminalOutput.style.height = `${window.innerHeight - ((48 + 8) * 4)}px`;
|
// TODO show info popup before actually installing, also allow installing via drag&drop on packages section
|
||||||
}
|
const fileInput = $('button$apkInstall$').querySelector('input');
|
||||||
resizeTerminal();
|
fileInput.onchange = (function(event){
|
||||||
|
const count = event.target.files.length;
|
||||||
window.addEventListener('resize', (function(){
|
if (!count > 0) {
|
||||||
resizeTerminal();
|
return;
|
||||||
}));
|
}
|
||||||
|
alert(`Installing ${count} package(s)...`);
|
||||||
$('input$terminalInput$').addEventListener('keydown', (async function(event){
|
const pm = new PackageManager(Device.adb);
|
||||||
if (event.keyCode == 13) { // Enter
|
Array.from(event.target.files).forEach(async function(file, index){
|
||||||
const cmd = $('input$terminalInput$').value;
|
try {
|
||||||
terminalOutput.textContent += (cmd + '\n');
|
await pm.installStream(file.size, (new WrapReadableStream(file.stream())).pipeThrough(new WrapConsumableStream()));
|
||||||
const process = await Device.adb.subprocess.spawn(cmd);
|
alert(`Successfully installed package ${index + 1} of ${count}.`);
|
||||||
await process.stdout.pipeThrough(new DecodeUtf8Stream()).pipeTo(
|
refreshPackagesList();
|
||||||
new WritableStream({ write(chunk) {
|
} catch (err) {
|
||||||
terminalOutput.textContent += chunk;
|
alert(err);
|
||||||
terminalOutput.scrollTop = terminalOutput.scrollHeight;
|
}
|
||||||
} }),
|
});
|
||||||
);
|
});
|
||||||
terminalOutput.textContent += '\n> ';
|
fileInput.click();
|
||||||
$('input$terminalInput$').value = null;
|
});
|
||||||
};
|
|
||||||
}));
|
|
||||||
|
|
||||||
let Device = {};
|
let Device = {};
|
||||||
const CredentialStore = new AdbWebCredentialStore();
|
const CredentialStore = new AdbWebCredentialStore();
|
||||||
|
|
||||||
|
function resizeTerminal () {
|
||||||
|
const divider = (Device.adb ? 2 : 3);
|
||||||
|
terminalOutput.style.height = `${window.innerHeight - ((48 + 8) * divider)}px`;
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', resizeTerminal);
|
||||||
|
resizeTerminal();
|
||||||
|
|
||||||
const UsbManager = AdbDaemonWebUsb.AdbDaemonWebUsbDeviceManager.BROWSER;
|
const UsbManager = AdbDaemonWebUsb.AdbDaemonWebUsbDeviceManager.BROWSER;
|
||||||
if (!UsbManager) {
|
if (!UsbManager) {
|
||||||
$('div$browserWarning$').innerHTML = `<p>
|
$('div$browserWarning$').innerHTML = `<p>
|
||||||
|
@ -79,8 +85,10 @@ async function connectAuthorizeDevice () {
|
||||||
Device.transport = await Adb.AdbDaemonTransport.authenticate({ connection: Device.connection, credentialStore: CredentialStore });
|
Device.transport = await Adb.AdbDaemonTransport.authenticate({ connection: Device.connection, credentialStore: CredentialStore });
|
||||||
Device.adb = new Adb.Adb(Device.transport);
|
Device.adb = new Adb.Adb(Device.transport);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
$('[name="deviceStatus"]').innerHTML = 'An error occurred while trying to establish a device connection. Please ensure that no other processes or browser tabs on this system are currently using the device, then retry.';
|
$('p$deviceStatus$').textContent = 'An error occurred while trying to establish a device connection. Please ensure that no other processes or browser tabs on this system are currently using the device, then retry.';
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$('p$deviceStatus$').textContent = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,15 +111,18 @@ async function refreshDeviceSelect () {
|
||||||
deviceSelect.innerHTML = null;
|
deviceSelect.innerHTML = null;
|
||||||
const devices = await UsbManager.getDevices();
|
const devices = await UsbManager.getDevices();
|
||||||
if (devices.length) {
|
if (devices.length) {
|
||||||
|
$('p$deviceStatus$').textContent = null;
|
||||||
deviceSelect.innerHTML = '<option>[📲️ Select a connected device]</option>';
|
deviceSelect.innerHTML = '<option>[📲️ Select a connected device]</option>';
|
||||||
devices.forEach(function(device, index){
|
devices.forEach(function(device, index){
|
||||||
var deviceOption = document.createElement('option');
|
const deviceOption = document.createElement('option');
|
||||||
deviceOption.textContent = `${device.raw.productName} [${device.raw.serialNumber}]`;
|
deviceOption.textContent = `${device.raw.productName} [${device.raw.serialNumber}]`;
|
||||||
deviceSelect.appendChild(deviceOption);
|
deviceSelect.appendChild(deviceOption);
|
||||||
});
|
});
|
||||||
deviceSelect.onchange = onSwitchDevice;
|
deviceSelect.onchange = onSwitchDevice;
|
||||||
deviceSelect.disabled = false;
|
deviceSelect.disabled = false;
|
||||||
} else {
|
} else {
|
||||||
|
// TODO probably put this warning elsewhere? because it seems like the browser can see even Androids with ADB disabled, obviously they won't be able to connect
|
||||||
|
$('p$deviceStatus$').innerHTML = 'Connect a debuggable Android device via USB to continue. (Read "<a target="_blank" href="https://www.lifewire.com/enable-usb-debugging-android-4690927#toc-how-to-enable-usb-debugging-on-android">How to Enable USB Debugging on Android</a>" for help).';
|
||||||
deviceSelect.innerHTML = '<option>[📵️ No connected devices]</option>';
|
deviceSelect.innerHTML = '<option>[📵️ No connected devices]</option>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +134,8 @@ async function onSwitchDevice () {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshDeviceInfo () {
|
async function refreshDeviceInfo () {
|
||||||
if (deviceSelect.selectedIndex > 0) {
|
let onDevice = (deviceSelect.selectedIndex > 0);
|
||||||
|
if (onDevice) {
|
||||||
const device = await getDevice();
|
const device = await getDevice();
|
||||||
$('$deviceOem$').innerHTML = `<b>Brand</b>: ${device.raw.manufacturerName}`;
|
$('$deviceOem$').innerHTML = `<b>Brand</b>: ${device.raw.manufacturerName}`;
|
||||||
$('$deviceModel$').innerHTML = `<b>Model</b>: ${device.raw.productName}`;
|
$('$deviceModel$').innerHTML = `<b>Model</b>: ${device.raw.productName}`;
|
||||||
|
@ -133,29 +145,38 @@ async function refreshDeviceInfo () {
|
||||||
if (Device.adb) {
|
if (Device.adb) {
|
||||||
$('$deviceStatus$').innerHTML = null;
|
$('$deviceStatus$').innerHTML = null;
|
||||||
// $('$devicePropDump$').innerHTML = null;
|
// $('$devicePropDump$').innerHTML = null;
|
||||||
|
$('$deviceCpuAbis$').innerHTML = `<b>CPU ABIs</b>: ${await Device.adb.getProp('ro.system.product.cpu.abilist')}`;
|
||||||
$('$androidVersion$').innerHTML = `<b>Android version</b>: ${await Device.adb.getProp('ro.build.version.release')}`;
|
$('$androidVersion$').innerHTML = `<b>Android version</b>: ${await Device.adb.getProp('ro.build.version.release')}`;
|
||||||
$('$androidApi$').innerHTML = `<b>API version</b>: ${await Device.adb.getProp('ro.build.version.sdk')}`;
|
$('$androidApi$').innerHTML = `<b>SDK API version</b>: ${await Device.adb.getProp('ro.build.version.sdk')}`;
|
||||||
|
//$('$androidNickname$').innerHTML = `<b>Device name</b>: ${await Device.adb.getProp('persist.sys.device_name')}`;
|
||||||
|
$('$androidBuildDate$').innerHTML = `<b>Build date</b>: ${await Device.adb.getProp('ro.vendor.build.date')}`;
|
||||||
|
$('$androidBuildFingerprint$').innerHTML = `<b>Build fingerprint</b>: ${await Device.adb.getProp('ro.vendor.build.fingerprint')}`;
|
||||||
$('$androidInfo$').hidden = false;
|
$('$androidInfo$').hidden = false;
|
||||||
$('$connectReminder$').hidden = true;
|
$('$connectReminder$').hidden = true;
|
||||||
terminalOutput.disabled = false;
|
terminalOutput.disabled = false;
|
||||||
terminalOutput.textContent += '> ';
|
terminalOutput.textContent += (terminalOutput.textContent ? '\n> ' : '> ');
|
||||||
$('input$terminalInput$').disabled = false;
|
$('button$clearTerminal$').disabled = false;
|
||||||
/* for (const line of (await Device.adb.getProp()).split('\n')) {
|
/* for (const line of (await Device.adb.getProp()).split('\n')) {
|
||||||
const elem = document.createElement('li');
|
const elem = document.createElement('li');
|
||||||
elem.textContent = line;
|
elem.textContent = line;
|
||||||
$('$devicePropDump$').appendChild(elem);
|
$('$devicePropDump$').appendChild(elem);
|
||||||
} */
|
} */
|
||||||
} else {
|
} else {
|
||||||
$('$deviceInfo$').hidden = true;
|
onDevice = false;
|
||||||
}
|
}
|
||||||
$('$deviceInfo$').hidden = false;
|
|
||||||
} else {
|
} else {
|
||||||
$('$deviceStatus$').innerHTML = null;
|
//$('$deviceStatus$').innerHTML = null;
|
||||||
$('$connectReminder$').hidden = false;
|
$('$connectReminder$').hidden = false;
|
||||||
terminalOutput.disabled = true;
|
terminalOutput.disabled = true;
|
||||||
$('input$terminalInput$').disabled = true;
|
|
||||||
$('$deviceInfo$').hidden = true;
|
|
||||||
}
|
}
|
||||||
|
toggleDeviceElems(onDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleDeviceElems (enabled) {
|
||||||
|
$('$deviceInfo$').hidden = !enabled;
|
||||||
|
$('button$apkInstall$').disabled = !enabled;
|
||||||
|
$('input$terminalInput$').disabled = !enabled;
|
||||||
|
resizeTerminal();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshDeviceSection () {
|
async function refreshDeviceSection () {
|
||||||
|
@ -164,7 +185,7 @@ async function refreshDeviceSection () {
|
||||||
}
|
}
|
||||||
refreshDeviceSection();
|
refreshDeviceSection();
|
||||||
|
|
||||||
deviceConnect.onclick = (async function(){
|
$('button$deviceConnect$').onclick = (async function(){
|
||||||
const device = await UsbManager.requestDevice();
|
const device = await UsbManager.requestDevice();
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return;
|
return;
|
||||||
|
@ -174,6 +195,60 @@ deviceConnect.onclick = (async function(){
|
||||||
deviceSelect.selectedIndex = (deviceSelect.children.length - 1);
|
deviceSelect.selectedIndex = (deviceSelect.children.length - 1);
|
||||||
deviceSelect.onchange();
|
deviceSelect.onchange();
|
||||||
});
|
});
|
||||||
deviceConnect.disabled = false;
|
$('button$deviceConnect$').disabled = false;
|
||||||
|
|
||||||
|
$('input$terminalInput$').addEventListener('keydown', (async function(event){
|
||||||
|
if (event.keyCode == 13) { // Enter
|
||||||
|
const cmd = $('input$terminalInput$').value;
|
||||||
|
if (!terminalOutput.textContent) {
|
||||||
|
terminalOutput.textContent += '> ';
|
||||||
|
}
|
||||||
|
terminalOutput.textContent += (cmd + '\n');
|
||||||
|
const process = await Device.adb.subprocess.spawn(cmd);
|
||||||
|
const processWriteToTerminal = () => new WritableStream({ write(chunk) {
|
||||||
|
terminalOutput.textContent += chunk;
|
||||||
|
terminalOutput.scrollTop = terminalOutput.scrollHeight;
|
||||||
|
$('button$clearTerminal$').disabled = false;
|
||||||
|
} });
|
||||||
|
await process.stdout.pipeThrough(new DecodeUtf8Stream()).pipeTo(processWriteToTerminal());
|
||||||
|
await process.stderr.pipeThrough(new DecodeUtf8Stream()).pipeTo(processWriteToTerminal());
|
||||||
|
terminalOutput.textContent += '\n> ';
|
||||||
|
terminalOutput.scrollTop = terminalOutput.scrollHeight;
|
||||||
|
$('input$terminalInput$').value = null;
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
$('button$clearTerminal$').onclick = (function(){
|
||||||
|
terminalOutput.textContent = '';
|
||||||
|
$('button$clearTerminal$').disabled = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
$('button$wrapTerminal$').onclick = (function(){
|
||||||
|
terminalOutput.style.textWrap = (terminalOutput.style.textWrap ? '' : 'nowrap');
|
||||||
|
terminalOutput.scrollTop = terminalOutput.scrollHeight;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function refreshPackagesList () {
|
||||||
|
$('ul$packageList$').innerHTML = null;
|
||||||
|
const pm = new PackageManager(Device.adb);
|
||||||
|
const list = await pm.listPackages();
|
||||||
|
let result = await list.next();
|
||||||
|
while (!result.done) {
|
||||||
|
var packageElem = document.createElement('li');
|
||||||
|
packageElem.innerHTML = `${result.value.packageName}<!-- <input type="checkbox" class="floatRight"/>-->`;
|
||||||
|
/* packageElem.querySelector('input').onclick = (function(){
|
||||||
|
// TODO: hide or show action buttons that do actions on selected elements if there is none or at least one
|
||||||
|
}); */
|
||||||
|
$('ul$packageList$').appendChild(packageElem);
|
||||||
|
result = await list.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('hashchange', (async function(){
|
||||||
|
const sectionHash = location.hash.slice(2).split('/')[0];
|
||||||
|
if (Device.adb && sectionHash === 'packages' /* && !$('ul$packageList$').innerHTML */) {
|
||||||
|
refreshPackagesList();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
})();
|
})();
|
|
@ -27,7 +27,7 @@ a[data-action-section] {
|
||||||
/* width: 60%; */
|
/* width: 60%; */
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
background: rgba(0, 0, 0, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.holo-sidebar[data-open="open"], .holo-sideBar[data-open="open"] {
|
.holo-sidebar[data-open="open"], .holo-sideBar[data-open="open"] {
|
||||||
|
@ -37,7 +37,7 @@ a[data-action-section] {
|
||||||
.holo-sidebar .holo-list, .holo-sideBar .holo-list {
|
.holo-sidebar .holo-list, .holo-sideBar .holo-list {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: black;
|
background: rgba(0, 0, 0, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actionBar .holo-title.holo-menu, .holo-actionBar .holo-title.holo-menu {
|
.actionBar .holo-title.holo-menu, .holo-actionBar .holo-title.holo-menu {
|
|
@ -1,13 +1,17 @@
|
||||||
window.addEventListener('load', (function() {
|
window.addEventListener('load', (function() {
|
||||||
|
|
||||||
|
var initialSectionName = $('[data-section][data-open]').dataset.section;
|
||||||
|
|
||||||
$('::[data-action-sidebar]').forEach(function(actionSidebarElem){
|
$('::[data-action-sidebar]').forEach(function(actionSidebarElem){
|
||||||
var sidebarElem = $('[data-sidebar="' + actionSidebarElem.dataset.actionSidebar + '"]');
|
var sidebarElem = $('[data-sidebar="' + actionSidebarElem.dataset.actionSidebar + '"]');
|
||||||
actionSidebarElem.onclick = sidebarElem.onclick = (function(){
|
function toggleSidebar () {
|
||||||
sidebarElem.dataset.open = (sidebarElem.dataset.open !== 'open' ? 'open' : false);
|
sidebarElem.dataset.open = (sidebarElem.dataset.open !== 'open' ? 'open' : false);
|
||||||
});
|
}
|
||||||
sidebarElem.querySelector('.holo-list').onclick = (function(event){
|
actionSidebarElem.addEventListener('click', toggleSidebar);
|
||||||
|
sidebarElem.addEventListener('click', toggleSidebar);
|
||||||
|
sidebarElem.querySelector('.holo-list').addEventListener('click', (function(event){
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
});
|
}));
|
||||||
arrayFrom(sidebarElem.querySelectorAll('.holo-list li button, .holo-list li [role="button"]')).forEach(function(buttonElem){
|
arrayFrom(sidebarElem.querySelectorAll('.holo-list li button, .holo-list li [role="button"]')).forEach(function(buttonElem){
|
||||||
buttonElem.addEventListener('click', (function(){
|
buttonElem.addEventListener('click', (function(){
|
||||||
sidebarElem.dataset.open = false;
|
sidebarElem.dataset.open = false;
|
||||||
|
@ -40,9 +44,11 @@ function refreshDisplaySections (sectionTargetName) {
|
||||||
}
|
}
|
||||||
refreshDisplaySections();
|
refreshDisplaySections();
|
||||||
|
|
||||||
var sectionHash = location.hash.slice(2).split('/')[0];
|
function hashChange () {
|
||||||
if (sectionHash) {
|
var sectionHash = location.hash.slice(2).split('/')[0];
|
||||||
$(`[data-action-section="${sectionHash}"]`).click();
|
$(`[data-action-section="${sectionHash || initialSectionName}"]`).click();
|
||||||
}
|
}
|
||||||
|
window.addEventListener('hashchange', hashChange);
|
||||||
|
hashChange();
|
||||||
|
|
||||||
}));
|
}));
|
Before Width: | Height: | Size: 98 B After Width: | Height: | Size: 98 B |
|
@ -14,8 +14,16 @@
|
||||||
<script src="./holo-web/holo-touch.js"></script>
|
<script src="./holo-web/holo-touch.js"></script>
|
||||||
<script src="../../shared/OctoHub-Global.js"></script>
|
<script src="../../shared/OctoHub-Global.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body { overflow-x: hidden; }
|
|
||||||
.floatRight { float: right; }
|
.floatRight { float: right; }
|
||||||
|
body { overflow-x: hidden; padding-bottom: 0; }
|
||||||
|
ul.holo-list li input[type="checkbox"].floatRight { margin-top: 0; }
|
||||||
|
section.holo-sideBar > ul.holo-list { overflow-y: auto; }
|
||||||
|
[name="terminalInput"], [name="terminalOutput"] {
|
||||||
|
width: 100% !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -26,6 +34,16 @@
|
||||||
<!-- <button class="floatRight" data-display-sections="terminal">
|
<!-- <button class="floatRight" data-display-sections="terminal">
|
||||||
Tabs
|
Tabs
|
||||||
</button> -->
|
</button> -->
|
||||||
|
<button class="floatRight" data-display-sections="terminal" name="clearTerminal" disabled="true">
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
|
<button class="floatRight" data-display-sections="terminal" name="wrapTerminal">
|
||||||
|
Wrap
|
||||||
|
</button>
|
||||||
|
<button class="floatRight" data-display-sections="packages" name="apkInstall">
|
||||||
|
<input type="file" hidden="true" multiple="true" accept=".apk, application/vnd.android.package-archive"/>
|
||||||
|
Install APK(s)
|
||||||
|
</button>
|
||||||
</header>
|
</header>
|
||||||
<section class="holo-sideBar" data-sidebar="sidebar">
|
<section class="holo-sideBar" data-sidebar="sidebar">
|
||||||
<ul class="holo-list">
|
<ul class="holo-list">
|
||||||
|
@ -38,9 +56,9 @@
|
||||||
<!-- <li><button data-action-section="files">
|
<!-- <li><button data-action-section="files">
|
||||||
📄 Files
|
📄 Files
|
||||||
</button></li> -->
|
</button></li> -->
|
||||||
<!-- <li><button data-action-section="packages">
|
<li><button data-action-section="packages">
|
||||||
📦 Packages
|
📦 Packages <small>(WIP)</small>
|
||||||
</button></li> -->
|
</button></li>
|
||||||
<li><button data-action-section="about">
|
<li><button data-action-section="about">
|
||||||
❓️ About
|
❓️ About
|
||||||
</button></li>
|
</button></li>
|
||||||
|
@ -54,15 +72,31 @@
|
||||||
You must <a data-action-section="devices">connect and authorize a device</a> first.
|
You must <a data-action-section="devices">connect and authorize a device</a> first.
|
||||||
</p>
|
</p>
|
||||||
<section class="holo-section" data-section="about">
|
<section class="holo-section" data-section="about">
|
||||||
<p>SpiderADB is an user-friendly webapp for connecting to devices via the Android Debug Bridge, straight from a browser. More infos coming soon.</p>
|
<p>SpiderADB is an user-friendly webapp for connecting to devices via the Android Debug Bridge, straight from a browser.</p>
|
||||||
|
<!-- TODO features -->
|
||||||
|
<p>Here are some additional tips and tricks you might find useful to make the most out of this app:</p><ul>
|
||||||
|
<li><a target="_blank" href="https://dev.to/larsonzhong/most-complete-adb-commands-4pcg">Most complete ADB command manual</a></li>
|
||||||
|
</ul>
|
||||||
|
<h3>Open Source and Credits</h3>
|
||||||
|
<p>
|
||||||
|
This app is open-source and made with mostly-vanilla web technologies. You can find the full source code on my Git repo: <a href="https://gitlab.com/octospacc/octospacc.gitlab.io/-/tree/master/source/SpiderADB/">https://gitlab.com/octospacc/octospacc.gitlab.io/-/tree/master/source/SpiderADB/</a>.
|
||||||
|
<p>Also, this app wouldn't have been possible without these third-party components, of which the license is specified in brackets:</p><ul>
|
||||||
|
<li><a target="_blank" href="https://github.com/yume-chan/ya-webadb">Tango</a> [MIT]: ADB port for the web</li>
|
||||||
|
<li><a target="_blank" href="https://github.com/tango-adb/old-demo">Tango Demo (Old)</a> [MIT]: the previous official Tango demo webapp, helpful for writing my app since the Tango documentation is pretty lacking</li>
|
||||||
|
<li><a target="_blank" href="https://github.com/zmyaro/holo-web">Holo Web</a> [MIT]: stylesheets for recreating the Android Holo theme on the web</li>
|
||||||
|
</ul>
|
||||||
<h3>Changelog</h3>
|
<h3>Changelog</h3>
|
||||||
|
<h4>2024-04-18</h4><ul>
|
||||||
|
<li>Improve Terminal logic, which now also shows stdout, scaling, and add a Clear feature.</li>
|
||||||
|
<li>Introduce Packages menu, listing all installed packages' names, and allow installing (multiple) APKs files.</li>
|
||||||
|
</ul>
|
||||||
<h4>2024-04-16</h4><ul>
|
<h4>2024-04-16</h4><ul>
|
||||||
<li>Introduced the basic Terminal.</li>
|
<li>Introduce the basic Terminal.</li>
|
||||||
<li>Slight improvements to the user experience with better error handling.</li>
|
<li>Slight improvements to the user experience with better error handling.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h4>2024-04-14</h4><ul>
|
<h4>2024-04-14</h4><ul>
|
||||||
<li>First WIP version, with Android ICS Holo UI, allows simply connecting to devices and shows basic info.</li>
|
<li>First WIP version, with Android ICS Holo UI, allows simply connecting to devices and shows basic info.</li>
|
||||||
<li>Introduced sections: Devices, About.</li>
|
<li>Introduce sections: Devices, About.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section class="holo-section" data-section="devices" data-open="open">
|
<section class="holo-section" data-section="devices" data-open="open">
|
||||||
|
@ -81,6 +115,10 @@
|
||||||
<div name="androidInfo" hidden="true">
|
<div name="androidInfo" hidden="true">
|
||||||
<li name="androidVersion"></li>
|
<li name="androidVersion"></li>
|
||||||
<li name="androidApi"></li>
|
<li name="androidApi"></li>
|
||||||
|
<!-- <li name="androidNickname"></li> -->
|
||||||
|
<li name="androidBuildDate"></li>
|
||||||
|
<li name="androidBuildFingerprint"></li>
|
||||||
|
<li name="deviceCpuAbis"></li>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
<!-- <details>
|
<!-- <details>
|
||||||
|
@ -90,14 +128,12 @@
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section class="holo-section" data-section="terminal">
|
<section class="holo-section" data-section="terminal">
|
||||||
<textarea name="terminalOutput" readonly="true" disabled="true" placeholder="Terminal output will be displayed here." style="width: 100%; margin-left: 0; margin-right: 0;"></textarea>
|
<textarea name="terminalOutput" readonly="true" disabled="true" placeholder="Terminal output will be displayed here."></textarea>
|
||||||
<input name="terminalInput" type="text" disabled="true" placeholder="> Input any command..." style="width: 100%; margin-left: 0; margin-right: 0;"/>
|
<input name="terminalInput" type="text" disabled="true" placeholder="> Input any command..."/>
|
||||||
</section>
|
</section>
|
||||||
<section class="holo-section" data-section="packages">
|
<section class="holo-section" data-section="packages">
|
||||||
<!-- TODO buttons -->
|
<!-- TODO buttons -->
|
||||||
<ul class="holo-list" name="packageList">
|
<ul class="holo-list" name="packageList"></ul><!--<li>Test <input type="checkbox" class="floatRight"/></li><!--<label><li>Test <input type="checkbox"/></li></label>-->
|
||||||
<li>Test <input type="checkbox"/></li>
|
|
||||||
</ul>
|
|
||||||
<section class="holo-subsection" name="packageInfo">
|
<section class="holo-subsection" name="packageInfo">
|
||||||
|
|
||||||
</section>
|
</section>
|
|
@ -8,6 +8,7 @@
|
||||||
"@yume-chan/adb": "^0.0.23",
|
"@yume-chan/adb": "^0.0.23",
|
||||||
"@yume-chan/adb-credential-web": "^0.0.23",
|
"@yume-chan/adb-credential-web": "^0.0.23",
|
||||||
"@yume-chan/adb-daemon-webusb": "^0.0.23",
|
"@yume-chan/adb-daemon-webusb": "^0.0.23",
|
||||||
|
"@yume-chan/android-bin": "^0.0.23",
|
||||||
"@yume-chan/stream-extra": "^0.0.23"
|
"@yume-chan/stream-extra": "^0.0.23"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -50,6 +51,17 @@
|
||||||
"tslib": "^2.6.2"
|
"tslib": "^2.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@yume-chan/android-bin": {
|
||||||
|
"version": "0.0.23",
|
||||||
|
"resolved": "https://registry.npmjs.org/@yume-chan/android-bin/-/android-bin-0.0.23.tgz",
|
||||||
|
"integrity": "sha512-yOhErwfD7oe8piG/kboHbYGLQJU/eJE81yUzQFJbXtI0guR8j9baeyVYuTHzSVyvFTlBqsd5cd68bYGT6o3yAw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@yume-chan/adb": "^0.0.23",
|
||||||
|
"@yume-chan/stream-extra": "^0.0.23",
|
||||||
|
"@yume-chan/struct": "^0.0.23",
|
||||||
|
"tslib": "^2.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@yume-chan/async": {
|
"node_modules/@yume-chan/async": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@yume-chan/async/-/async-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@yume-chan/async/-/async-2.2.0.tgz",
|
|
@ -3,6 +3,7 @@
|
||||||
"@yume-chan/adb": "^0.0.23",
|
"@yume-chan/adb": "^0.0.23",
|
||||||
"@yume-chan/adb-credential-web": "^0.0.23",
|
"@yume-chan/adb-credential-web": "^0.0.23",
|
||||||
"@yume-chan/adb-daemon-webusb": "^0.0.23",
|
"@yume-chan/adb-daemon-webusb": "^0.0.23",
|
||||||
|
"@yume-chan/android-bin": "^0.0.23",
|
||||||
"@yume-chan/stream-extra": "^0.0.23"
|
"@yume-chan/stream-extra": "^0.0.23"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -260,6 +260,7 @@ const endpointInfo = [ (ctx) => (ctx.urlSections[0] === 'info' && ctx.request.me
|
||||||
${isEnvServer ? `You can obtain the full source code and assets by downloading the following files:
|
${isEnvServer ? `You can obtain the full source code and assets by downloading the following files:
|
||||||
${resFiles.map((file) => ` • <a href="/res/${file}">${file}</a>`).join('')}.
|
${resFiles.map((file) => ` • <a href="/res/${file}">${file}</a>`).join('')}.
|
||||||
` : 'To get the original, unminified source code, visit this same page on the server-side version (refer to the Versions section above).'}
|
` : 'To get the original, unminified source code, visit this same page on the server-side version (refer to the Versions section above).'}
|
||||||
|
Alternatively, you can also find the source code on my shared Git repo: ${A('https://gitlab.com/octospacc/octospacc.gitlab.io/-/tree/master/source/WuppiMini/')}.
|
||||||
</p>
|
</p>
|
||||||
${isEnvServer ? `<h3>Terms of Use and Privacy Policy</h3>${appTerms}` : ''}
|
${isEnvServer ? `<h3>Terms of Use and Privacy Policy</h3>${appTerms}` : ''}
|
||||||
<h3>Changelog</h3>
|
<h3>Changelog</h3>
|
Before Width: | Height: | Size: 226 KiB After Width: | Height: | Size: 226 KiB |
Before Width: | Height: | Size: 354 KiB After Width: | Height: | Size: 354 KiB |
Before Width: | Height: | Size: 581 KiB After Width: | Height: | Size: 581 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
@ -48,27 +48,31 @@
|
||||||
--><a href="./HashyMagnet/">🧲 HashyMagnet</a>
|
--><a href="./HashyMagnet/">🧲 HashyMagnet</a>
|
||||||
<small>(BitTorrent Hash to Magnet)</small><!--
|
<small>(BitTorrent Hash to Magnet)</small><!--
|
||||||
--></h4>
|
--></h4>
|
||||||
<h4><!--
|
|
||||||
--><a href="./Ecoji/">🦜 Ecoji v1</a>
|
|
||||||
<small>(webapp fork)</small><!--
|
|
||||||
--></h4>
|
|
||||||
<h4><!--
|
<h4><!--
|
||||||
--><a href="./FramesBrowser/">🪟️ Frames Browser</a>
|
--><a href="./FramesBrowser/">🪟️ Frames Browser</a>
|
||||||
<small>(<i>yo dawg, i heard you...</i>)</small><!--
|
<small>(<i>yo dawg, i heard you...</i>)</small><!--
|
||||||
--></h4>
|
--></h4>
|
||||||
<h4><a href="./MatrixStickerHelper/">🃏️ [Matrix] Sticker Helper</a></h4>
|
<h4><a href="./MatrixStickerHelper/">🃏️ [Matrix] Sticker Helper</a></h4>
|
||||||
<h4><!--
|
<h4><!--
|
||||||
--><a href="./MBViewer/">👁️🗨️️ MBViewer</a>
|
--><a href="./SpiderADB/">🕷️ SpiderADB</a>
|
||||||
<small>(WordPress/RSS/... chat-like UI)</small><!--
|
<small>(Android debugging for Web)</small><!--
|
||||||
--></h4>
|
--></h4>
|
||||||
<h4><!--
|
<h4><!--
|
||||||
--><a href="./WuppiMini/">☘️ WuppìMini</a>
|
--><a href="./WuppiMini/">☘️ WuppìMini</a>
|
||||||
<small>(basic-HTML posting client)</small><!--
|
<small>(basic-HTML posting client)</small><!--
|
||||||
--></h4>
|
--></h4>
|
||||||
|
<h4><!--
|
||||||
|
--><a href="./MBViewer/">👁️🗨️️ MBViewer</a>
|
||||||
|
<small>(WordPress/RSS/... chat-like UI)</small><!--
|
||||||
|
--></h4>
|
||||||
|
<h4><!--
|
||||||
|
--><a href="./Ecoji/">🦜 Ecoji v1</a>
|
||||||
|
<small>(webapp fork)</small><!--
|
||||||
|
--></h4>
|
||||||
<br/>
|
<br/>
|
||||||
<h4><a href="https://octospacc.gitlab.io/FumoPrisms">🔺️ Fumo Prisms (!)</a></h4>
|
<h4><a href="https://octospacc.gitlab.io/FumoPrisms/">🔺️ Fumo Prisms (!)</a></h4>
|
||||||
<h4><a href="./Collections/">🎀 My Collections</a> <small>(of posts/pages)</small></h4>
|
<h4><a href="./Collections/">🎀 My Collections</a> <small>(of posts/pages)</small></h4>
|
||||||
<h4><a href="./Userscripts/">⚙️ My Userscripts</a></h4>
|
<h4><a href="./Userscripts/">⚙️ My Userscripts</a> <small>for a nicer web</small></h4>
|
||||||
<h4>Nice <a href="https://addons.mozilla.org/firefox/collections/18049170/octollection/">🦊 Firefox Add-ons</a>
|
<h4>Nice <a href="https://addons.mozilla.org/firefox/collections/18049170/octollection/">🦊 Firefox Add-ons</a>
|
||||||
<small>(<a href="https://addons.mozilla.org/firefox/user/18049170/">mine</a> + suggestions)</small></h4>
|
<small>(<a href="https://addons.mozilla.org/firefox/user/18049170/">mine</a> + suggestions)</small></h4>
|
||||||
</div></div>
|
</div></div>
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |