From 4167b69757b023e76ab3e58d777d3df86449022f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 18:27:10 +0000 Subject: [PATCH 01/92] Initial plan From 5b14f7f8621ca6948ffeef98703399255096297c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 18:32:49 +0000 Subject: [PATCH 02/92] Add settings panel HTML and JavaScript state management Co-authored-by: MrAlders0n <55921894+MrAlders0n@users.noreply.github.com> --- content/wardrive.js | 125 +++++++++++++++++++++ index.html | 263 ++++++++++++++++++++++++-------------------- 2 files changed, 266 insertions(+), 122 deletions(-) diff --git a/content/wardrive.js b/content/wardrive.js index 9aee5e6..391203a 100644 --- a/content/wardrive.js +++ b/content/wardrive.js @@ -102,6 +102,17 @@ const gpsAccEl = document.getElementById("gpsAcc"); const distanceInfoEl = document.getElementById("distanceInfo"); // Distance from last ping const sessionPingsEl = document.getElementById("sessionPings"); // optional const coverageFrameEl = document.getElementById("coverageFrame"); + +// NEW: selectors for settings panel and controls +const settingsPanel = $("settingsPanel"); +const settingsCloseBtn = $("settingsCloseBtn"); +const settingsGearBtn = $("settingsGearBtn"); +const connectHelperText = $("connectHelperText"); +const pingControls = $("pingControls"); +const disconnectBtn = $("disconnectBtn"); +const permBluetooth = $("permBluetooth"); +const permLocation = $("permLocation"); + setConnectButton(false); // NEW: selectors @@ -135,6 +146,8 @@ const state = { disconnectReason: null, // Tracks the reason for disconnection (e.g., "app_down", "capacity_full", "public_key_error", "channel_setup_error", "ble_disconnect_error", "normal") channelSetupErrorMessage: null, // Error message from channel setup failure bleDisconnectErrorMessage: null, // Error message from BLE disconnect failure + radioPowerSelected: false, // Track if user has selected radio power + settingsOpen: true, // Track if settings panel is open repeaterTracking: { isListening: false, // Whether we're currently listening for echoes sentTimestamp: null, // Timestamp when the ping was sent @@ -519,6 +532,17 @@ function scheduleCoverageRefresh(lat, lon, delayMs = 0) { } function setConnectButton(connected) { if (!connectBtn) return; + + // Show/hide ping controls based on connection state + if (pingControls) { + pingControls.classList.toggle("hidden", !connected); + } + + // Show/hide disconnect button based on connection state + if (disconnectBtn) { + disconnectBtn.classList.toggle("hidden", !connected); + } + if (connected) { connectBtn.textContent = "Disconnect"; connectBtn.classList.remove( @@ -529,6 +553,10 @@ function setConnectButton(connected) { "bg-red-600", "hover:bg-red-500" ); + // Hide helper text when connected + if (connectHelperText) { + connectHelperText.classList.add("hidden"); + } } else { connectBtn.textContent = "Connect"; connectBtn.classList.remove( @@ -539,11 +567,83 @@ function setConnectButton(connected) { "bg-emerald-600", "hover:bg-emerald-500" ); + // Update connect button state (may show helper text) + updateConnectButtonState(); + } +} + +/** + * Update Connect button state based on radio power selection + */ +function updateConnectButtonState() { + const powerSelected = getCurrentPowerSetting() !== ""; + state.radioPowerSelected = powerSelected; + + // Enable/disable Connect button + connectBtn.disabled = !powerSelected && !state.connection; + + // Show/hide helper text + if (connectHelperText) { + connectHelperText.classList.toggle("hidden", powerSelected || state.connection); + } + + // Show/hide settings close button + if (settingsCloseBtn) { + settingsCloseBtn.classList.toggle("hidden", !powerSelected); + } + + debugLog(`Connect button state updated: powerSelected=${powerSelected}, disabled=${connectBtn.disabled}`); +} + +/** + * Toggle settings panel visibility + * @param {boolean} open - Whether to open or close the panel + */ +function toggleSettingsPanel(open) { + state.settingsOpen = open; + + if (settingsPanel) { + settingsPanel.classList.toggle("hidden", !open); + } + + if (settingsGearBtn) { + settingsGearBtn.classList.toggle("hidden", open); + } + + debugLog(`Settings panel toggled: open=${open}`); +} + +/** + * Update permission status indicators + */ +async function updatePermissionStatus() { + // Check Bluetooth permission + if (permBluetooth) { + const hasBluetooth = "bluetooth" in navigator; + permBluetooth.textContent = hasBluetooth ? "✓ Available" : "✗ Unavailable"; + permBluetooth.classList.toggle("text-emerald-400", hasBluetooth); + permBluetooth.classList.toggle("text-red-400", !hasBluetooth); + } + + // Check Location permission + if (permLocation) { + try { + const permission = await navigator.permissions.query({ name: "geolocation" }); + const granted = permission.state === "granted"; + const prompt = permission.state === "prompt"; + permLocation.textContent = granted ? "✓ Granted" : (prompt ? "○ Not requested" : "✗ Denied"); + permLocation.classList.toggle("text-emerald-400", granted); + permLocation.classList.toggle("text-amber-400", prompt); + permLocation.classList.toggle("text-red-400", !granted && !prompt); + } catch { + permLocation.textContent = "? Unknown"; + } } } + // ---- Wake Lock helpers ---- async function acquireWakeLock() { debugLog("Attempting to acquire wake lock"); @@ -2327,6 +2427,31 @@ export async function onLoad() { } }); + // Radio power selection listener + document.querySelectorAll('input[name="power"]').forEach(radio => { + radio.addEventListener("change", () => { + updateConnectButtonState(); + debugLog(`Radio power changed: ${getCurrentPowerSetting()}`); + }); + }); + + // Settings panel toggle listeners + if (settingsCloseBtn) { + settingsCloseBtn.addEventListener("click", () => { + toggleSettingsPanel(false); + }); + } + + if (settingsGearBtn) { + settingsGearBtn.addEventListener("click", () => { + toggleSettingsPanel(true); + }); + } + + // Initialize states + updateConnectButtonState(); + updatePermissionStatus(); + // Prompt location permission early (optional) debugLog("Requesting initial location permission"); try { diff --git a/index.html b/index.html index 0a6b374..e82ab77 100644 --- a/index.html +++ b/index.html @@ -35,116 +35,145 @@
-
-

-
-

- MeshCore Wardrive

-
+
+

+ + MeshCore Wardrive

+
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Status:Disconnected
Device:-
Channel:-
GPS:-
Accuracy:-
Distance from last ping:-
- - -
- - - - -
- -
- Auto interval: - - - - - - + +
+ +
+ + + +
- - -
- Radio power: - - - - - -
+ +
- -
- Requires Bluetooth and Location permissions. Keep the app in the foreground with the screen on and unlocked. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Status:Disconnected
Device:-
Channel:-
GPS:-
Accuracy:-
Distance from last ping:-
+ + +
+ +

+ Select radio power to connect +

+ + + + + +
@@ -174,31 +203,21 @@

Session Pings

- - + +
+

Notes

+
    +
  • Requires Bluetooth and Location permissions
  • +
  • Keep app in foreground with screen on & unlocked
  • +
  • YOW region only
  • +
  • Sends location to #wardriving for coverage map
  • +
  • ⚠️ Not supported in Safari — Use Bluefy on iOS
  • +
+

+ Fork of kallanreed/mesh-map, + modified for meshmapper.net +

+
From f831d56ab628fc5a6bae22fa1879a0f912ed8ff3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 18:35:35 +0000 Subject: [PATCH 03/92] Fix JavaScript initialization order issue Co-authored-by: MrAlders0n <55921894+MrAlders0n@users.noreply.github.com> --- content/wardrive.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/wardrive.js b/content/wardrive.js index 391203a..7f2c9f5 100644 --- a/content/wardrive.js +++ b/content/wardrive.js @@ -113,8 +113,6 @@ const disconnectBtn = $("disconnectBtn"); const permBluetooth = $("permBluetooth"); const permLocation = $("permLocation"); -setConnectButton(false); - // NEW: selectors const intervalSelect = $("intervalSelect"); // 15 / 30 / 60 seconds const powerSelect = $("powerSelect"); // "", "0.3w", "0.6w", "1.0w" @@ -2400,6 +2398,7 @@ export async function onLoad() { setStatus("Disconnected", STATUS_COLORS.error); enableControls(false); updateAutoButton(); + setConnectButton(false); // Initialize button state connectBtn.addEventListener("click", async () => { try { From 6ff1aae85611261c25f7899cd40fbf34c29337d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 18:38:42 +0000 Subject: [PATCH 04/92] Fix button layout for connected state - separate Connect and Disconnect buttons Co-authored-by: MrAlders0n <55921894+MrAlders0n@users.noreply.github.com> --- content/wardrive.js | 34 +++++++++++++++------------------- docs/CONNECTION_WORKFLOW.md | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/content/wardrive.js b/content/wardrive.js index 7f2c9f5..5da222c 100644 --- a/content/wardrive.js +++ b/content/wardrive.js @@ -536,35 +536,18 @@ function setConnectButton(connected) { pingControls.classList.toggle("hidden", !connected); } - // Show/hide disconnect button based on connection state + // Show/hide connect vs disconnect button based on connection state if (disconnectBtn) { disconnectBtn.classList.toggle("hidden", !connected); } + connectBtn.classList.toggle("hidden", connected); if (connected) { - connectBtn.textContent = "Disconnect"; - connectBtn.classList.remove( - "bg-emerald-600", - "hover:bg-emerald-500" - ); - connectBtn.classList.add( - "bg-red-600", - "hover:bg-red-500" - ); // Hide helper text when connected if (connectHelperText) { connectHelperText.classList.add("hidden"); } } else { - connectBtn.textContent = "Connect"; - connectBtn.classList.remove( - "bg-red-600", - "hover:bg-red-500" - ); - connectBtn.classList.add( - "bg-emerald-600", - "hover:bg-emerald-500" - ); // Update connect button state (may show helper text) updateConnectButtonState(); } @@ -2412,6 +2395,19 @@ export async function onLoad() { setStatus(e.message || "Connection failed", STATUS_COLORS.error); } }); + + // Disconnect button listener (separate button for when connected) + if (disconnectBtn) { + disconnectBtn.addEventListener("click", async () => { + try { + await disconnect(); + } catch (e) { + debugError(`Disconnect button error: ${e.message}`, e); + setStatus(e.message || "Disconnect failed", STATUS_COLORS.error); + } + }); + } + sendPingBtn.addEventListener("click", () => { debugLog("Manual ping button clicked"); sendPing(true).catch(console.error); diff --git a/docs/CONNECTION_WORKFLOW.md b/docs/CONNECTION_WORKFLOW.md index 5fb424d..e1a014f 100644 --- a/docs/CONNECTION_WORKFLOW.md +++ b/docs/CONNECTION_WORKFLOW.md @@ -4,6 +4,7 @@ - [Overview](#overview) - [Connection Overview](#connection-overview) - [Disconnection Overview](#disconnection-overview) +- [Pre-Connection Requirements](#pre-connection-requirements) - [Connection Workflow](#connection-workflow) - [Disconnection Workflow](#disconnection-workflow) - [Workflow Diagrams](#workflow-diagrams) @@ -49,6 +50,26 @@ - Connection state reset - Ready to initiate a new connection +## Pre-Connection Requirements + +Before initiating a connection, the user must: + +1. **Select Radio Power** — Choose from N/A, 0.3w, 0.6w, or 1.0w + - No default is pre-selected + - Connect button remains disabled until selection is made + - Helper text "Select radio power to connect" is shown below the disabled Connect button + - Once selected, the close button (✕) appears on the settings panel + +2. **Auto Ping Interval** (Optional) — Defaults to 30s but can be changed to 15s or 60s + - Can be configured in the settings panel before or after connection + +3. **Settings Panel** + - Opens by default on page load + - Contains Radio Power selection, Auto Ping Interval, and Permissions status + - Can be closed after Radio Power is selected + - Gear icon (⚙️) appears in header when settings are closed + - Settings can be reopened by clicking the gear icon + ## Connection Workflow ### Connection Steps (High-Level) From 2eab0699d3ff9bf89df689d2c9457e5860b303f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 18:41:43 +0000 Subject: [PATCH 05/92] Simplify to single Connect/Disconnect button that changes text and appearance Co-authored-by: MrAlders0n <55921894+MrAlders0n@users.noreply.github.com> --- content/wardrive.js | 45 ++++++++++++++++++++++++--------------------- index.html | 12 ++++-------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/content/wardrive.js b/content/wardrive.js index 5da222c..da87e2e 100644 --- a/content/wardrive.js +++ b/content/wardrive.js @@ -109,7 +109,6 @@ const settingsCloseBtn = $("settingsCloseBtn"); const settingsGearBtn = $("settingsGearBtn"); const connectHelperText = $("connectHelperText"); const pingControls = $("pingControls"); -const disconnectBtn = $("disconnectBtn"); const permBluetooth = $("permBluetooth"); const permLocation = $("permLocation"); @@ -536,18 +535,32 @@ function setConnectButton(connected) { pingControls.classList.toggle("hidden", !connected); } - // Show/hide connect vs disconnect button based on connection state - if (disconnectBtn) { - disconnectBtn.classList.toggle("hidden", !connected); - } - connectBtn.classList.toggle("hidden", connected); - if (connected) { + // Change to Disconnect button + connectBtn.textContent = "Disconnect"; + connectBtn.classList.remove( + "bg-emerald-600", + "hover:bg-emerald-500" + ); + connectBtn.classList.add( + "bg-red-600", + "hover:bg-red-500" + ); // Hide helper text when connected if (connectHelperText) { connectHelperText.classList.add("hidden"); } } else { + // Change to Connect button + connectBtn.textContent = "Connect"; + connectBtn.classList.remove( + "bg-red-600", + "hover:bg-red-500" + ); + connectBtn.classList.add( + "bg-emerald-600", + "hover:bg-emerald-500" + ); // Update connect button state (may show helper text) updateConnectButtonState(); } @@ -560,8 +573,10 @@ function updateConnectButtonState() { const powerSelected = getCurrentPowerSetting() !== ""; state.radioPowerSelected = powerSelected; - // Enable/disable Connect button - connectBtn.disabled = !powerSelected && !state.connection; + // Enable/disable Connect button (only when not connected) + if (!state.connection) { + connectBtn.disabled = !powerSelected; + } // Show/hide helper text if (connectHelperText) { @@ -2396,18 +2411,6 @@ export async function onLoad() { } }); - // Disconnect button listener (separate button for when connected) - if (disconnectBtn) { - disconnectBtn.addEventListener("click", async () => { - try { - await disconnect(); - } catch (e) { - debugError(`Disconnect button error: ${e.message}`, e); - setStatus(e.message || "Disconnect failed", STATUS_COLORS.error); - } - }); - } - sendPingBtn.addEventListener("click", () => { debugLog("Manual ping button clicked"); sendPing(true).catch(console.error); diff --git a/index.html b/index.html index e82ab77..d1f1a3f 100644 --- a/index.html +++ b/index.html @@ -149,10 +149,6 @@

Settings<
-

Select radio power to connect

@@ -169,10 +165,10 @@

Settings<

- - From 18e1c9a1dafa53e221ce4d31e49eb539d0ccc85c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 18:52:24 +0000 Subject: [PATCH 06/92] Remove N/A option from Radio Power and change to 3-column layout Co-authored-by: MrAlders0n <55921894+MrAlders0n@users.noreply.github.com> --- index.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/index.html b/index.html index d1f1a3f..890e898 100644 --- a/index.html +++ b/index.html @@ -78,11 +78,7 @@

Settings< -
- +