From 9a265bf2272fb39c2409d9d9a0566ec6c15f1fb0 Mon Sep 17 00:00:00 2001
From: IFOKNR <253658289+ifoknr@users.noreply.github.com>
Date: Thu, 15 Oct 2026 00:15:19 +0000
Subject: [PATCH] v2.5.1: first stable release, and backups can be deleted from
the phone
- FBS_CHANNEL is stable: module.prop drops (Beta), the WebUI hides its Beta chip and
release.yml no longer forces a pre-release.
- fbs delete
-
+
${esc(T('err.generic', e.message || e))}
`; @@ -601,6 +602,7 @@ $('#backupList').addEventListener('click', async e => { const btn = e.target.closest('button'); if (!btn || btn.disabled) return; const item = btn.closest('.bitem'); + if (btn.dataset.act === 'delete') return askDelete(item.dataset.name); const meta = item.querySelector('.m'); btn.disabled = true; btn.textContent = T('backup.verifying'); @@ -622,6 +624,20 @@ $('#backupList').addEventListener('click', async e => { : `✓ ${esc(T('backup.ok', result.ok))}`; }); +function askDelete(name) { + sheet(T('backup.deleteTitle'), `${esc(T('backup.deleteBody', name))}
`, + [{ label: T('cancel') }, { label: T('backup.delete'), kind: 'danger', onClick: async () => { + closeSheet(); + try { + const r = await fbsJson('delete', name); + toast(r.ok ? T('backup.deleted') : T('err.generic', r.msg)); + } catch (e) { + toast(T('err.generic', e.message || e)); + } + loadBackups(); + } }]); +} + /* ---------------------------------------------------------------- modules */ const Mods = { data: null, busy: false }; diff --git a/module/webroot/demo.js b/module/webroot/demo.js index 9eb93de..702aef6 100644 --- a/module/webroot/demo.js +++ b/module/webroot/demo.js @@ -22,7 +22,7 @@ ]; const info = { - fbs: '2.5.0', channel: 'beta', model: 'Demo Phone', brand: 'Demo', device: 'demo', product: 'demo_mt6789', + fbs: '2.5.1', channel: 'stable', model: 'Demo Phone', brand: 'Demo', device: 'demo', product: 'demo_mt6789', android: '14', sdk: '34', patch: '2026-08-05', build: 'DEMO-14.0.1', platform: 'mt6789', soc: 'mediatek', arch: 'arm64-v8a', slot: '_a', dynamic: true, treble: true, vndk: '34', boot: { vbstate: 'orange', device_state: 'unlocked', locked: false, spoofed: true }, @@ -123,6 +123,12 @@ case 'reboot': return JSON.stringify({ ok: true }); case 'open': return JSON.stringify({ ok: true }); case 'modules': return JSON.stringify(modules); + case 'delete': { + const i = backups.findIndex(x => x.name === a1); + if (i < 0) return JSON.stringify({ ok: false, msg: 'missing' }); + backups.splice(i, 1); + return JSON.stringify({ ok: true, folder: a1 }); + } default: return ''; } } @@ -152,7 +158,7 @@ const modules = { root: '/data/adb/modules', modules: [ - m('fastboot_studio_companion', 'Fastboot Studio Companion (Beta)', 'v2.5.0', { webui: true, action: true }), + m('fastboot_studio_companion', 'Fastboot Studio Companion', 'v2.5.1', { webui: true, action: true }), m('systemless_hosts', 'Systemless Hosts', 'v1.2', { files: 1 }), m('adblock_plus', 'AdBlock Plus', 'v4.0', { files: 1, props: 2, scripts: ['service.sh'] }), m('google_sans_font', 'Google Sans Font', 'v3.1', { files: 46 }), diff --git a/module/webroot/i18n.js b/module/webroot/i18n.js index 0bd36fa..60bbc20 100644 --- a/module/webroot/i18n.js +++ b/module/webroot/i18n.js @@ -52,6 +52,8 @@ const STRINGS = { 'backup.start': 'Start backup', 'backup.running': 'Backing up…', 'backup.saved': 'Saved backups', 'backup.format': 'Same layout as Fastboot Studio on Windows: its Phone page (v2.5.0 and later) copies a backup to your PC and checks it in one click, and the Device page restores it. Or check it here with sha256sum -c.', 'backup.none': 'No backups yet.', 'backup.verify': 'Verify', 'backup.verifying': 'Checking…', + 'backup.delete': 'Delete', 'backup.deleteTitle': 'Delete this backup?', 'backup.deleted': 'Backup deleted', + 'backup.deleteBody': '{0} is removed from the phone for good. Copy it to your PC first if you still need it.', 'backup.ok': 'All {0} match', 'backup.bad': '{0} changed or missing', 'backup.files': '{0} files · {1}', 'backup.done': 'Saved {0} images', 'backup.failed': '{0} failed', 'backup.confirm': 'Full backup', 'backup.confirmBody': 'This copies {0} partitions ({1}) to {2}. It can take several minutes.', @@ -125,6 +127,8 @@ const STRINGS = { 'backup.start': 'ابدأ الباك أب', 'backup.running': 'جاري النسخ…', 'backup.saved': 'النسخ المحفوظة', 'backup.format': 'نفس صيغة Fastboot Studio في الويندوز: صفحة «الجوال» في البرنامج (v2.5.0 وأحدث) تنقل النسخة للكمبيوتر وتتحقق منها بضغطة، وتسترجعها من صفحة الجهاز. أو تحقق منها هنا بـ sha256sum -c.', 'backup.none': 'ما فيه نسخ للحين.', 'backup.verify': 'تحقق', 'backup.verifying': 'يتحقق…', + 'backup.delete': 'حذف', 'backup.deleteTitle': 'تحذف هالنسخة؟', 'backup.deleted': 'انحذفت النسخة', + 'backup.deleteBody': '{0} بتنحذف من الجوال نهائياً. انقلها للكمبيوتر أول إذا تحتاجها.', 'backup.ok': 'كلها مطابقة ({0})', 'backup.bad': '{0} متغيّر أو ناقص', 'backup.files': '{0} ملف · {1}', 'backup.done': 'انحفظت {0} صورة', 'backup.failed': '{0} فشلت', 'backup.confirm': 'باك أب كامل', 'backup.confirmBody': 'بينسخ {0} بارتشن ({1}) إلى {2}. ممكن ياخذ كم دقيقة.', diff --git a/module/webroot/style.css b/module/webroot/style.css index 728b428..0282676 100644 --- a/module/webroot/style.css +++ b/module/webroot/style.css @@ -127,6 +127,7 @@ main { padding: 1rem 1rem calc(var(--bottom) + 6rem); max-width: 1500px; margin: .fbtn.rules { margin-inline-start: auto; border-color: var(--info-line); color: var(--info); background: var(--info-soft); } .btn-s { background: var(--raised); border: 1px solid var(--line); border-radius: .7rem; padding: .55rem .9rem; cursor: pointer; font-size: .9rem; color: var(--dim); white-space: nowrap; } .btn-s[aria-pressed="true"] { color: var(--warn); border-color: var(--warn-line); background: var(--warn-soft); } +.btn-s.danger { color: var(--danger); border-color: var(--danger-line); } .seg { display: grid; grid-template-columns: 1fr 1fr; background: var(--raised); border: 1px solid var(--line); border-radius: .7rem; padding: .2rem; gap: .2rem; } .seg.three { grid-template-columns: 1fr 1fr 1fr; } .seg button { background: none; border: 0; border-radius: .55rem; padding: .5rem; font-size: .9rem; cursor: pointer; color: var(--dim); } @@ -190,11 +191,12 @@ main { padding: 1rem 1rem calc(var(--bottom) + 6rem); max-width: 1500px; margin: .prow .st.ok { color: var(--ok); } .prow .st.bad { color: var(--danger); } .blist { display: flex; flex-direction: column; gap: .8rem; } -.bitem { display: grid; grid-template-columns: 1fr auto; gap: .15rem .5rem; align-items: center; font-size: .9rem; } +.bitem { display: grid; grid-template-columns: 1fr auto auto; gap: .15rem .5rem; align-items: center; font-size: .9rem; } .bitem .p { font-family: var(--mono); font-size: .8rem; direction: ltr; unicode-bidi: isolate; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; } [dir="rtl"] .bitem .p { text-align: right; } -.bitem .m { color: var(--faint); font-size: .8rem; } -.bitem button { grid-row: span 2; } +.bitem .m { color: var(--faint); font-size: .8rem; grid-column: 1; grid-row: 2; } +.bitem .p { grid-column: 1; grid-row: 1; } +.bitem button { grid-row: 1 / span 2; } /* Links to the Windows app, the group and a private message. */ .links { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: .5rem; margin-top: .9rem; } diff --git a/tests/run.sh b/tests/run.sh index c6d1577..28f63fd 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -177,6 +177,20 @@ for SHN in $SHELLS; do out=$(fbs verify ".partial-$name") expect "verify skips unfinished backups" jqt "$out" '.event == "error"' + # ---- delete + out=$(fbs delete ../etc) + expect "delete stays inside Backups" jqt "$out" '.ok == false' + expect "delete leaves other folders alone" test -d "$WORK/data/Backups" + out=$(fbs delete ".partial-x") + expect "delete refuses hidden folders" jqt "$out" '.ok == false' + out=$(fbs delete "no-such-backup") + expect "delete reports a missing backup" jqt "$out" '.ok == false and .msg == "missing"' + out=$(fbs delete "$name") + expect "delete removes the backup" jqt "$out" '.ok == true' + expect "deleted folder is gone" test ! -e "$dir" + out=$(fbs backups) + expect "two backups left" jqt "$out" '.items | length == 2' + # ---- reboot rm -f "$R/reboot.log" fbs reboot bootloader > /dev/null diff --git a/tests/webui-smoke.sh b/tests/webui-smoke.sh index 41551dd..9ee4511 100755 --- a/tests/webui-smoke.sh +++ b/tests/webui-smoke.sh @@ -21,7 +21,8 @@ for lang in en ar; do check "super card filled" 'system_a' check "backup sets described" 'id="setCritical">[^<]' check "reboot targets listed" 'data-r="bootloader"' - check "beta badge shown" 'id="betaChip" data-i="beta">' + check "no beta badge on a stable build" 'id="betaChip" hidden' + check "backups can be deleted" 'data-act="delete"' check "links listed" 'data-url="https://t.me/IFOKNR1"' check "group link" 'data-url="https://t.me/BeNeXTBrO"' check "link to the Windows app" 'data-url="https://github.com/ifoknr/FastbootStudio/releases/latest"' diff --git a/update.json b/update.json index 1b796ed..07d3a1f 100644 --- a/update.json +++ b/update.json @@ -1,6 +1,6 @@ { - "version": "v2.5.0", - "versionCode": 250, - "zipUrl": "https://github.com/ifoknr/FastbootStudio-Companion/releases/download/v2.5.0/FastbootStudio-Companion-v2.5.0.zip", + "version": "v2.5.1", + "versionCode": 251, + "zipUrl": "https://github.com/ifoknr/FastbootStudio-Companion/releases/download/v2.5.1/FastbootStudio-Companion-v2.5.1.zip", "changelog": "https://raw.githubusercontent.com/ifoknr/FastbootStudio-Companion/main/CHANGELOG.md" }