Handle connecting/disconnecting states

This commit is contained in:
nemunaire 2026-01-01 17:58:06 +07:00
commit 02b93a3ef0
6 changed files with 176 additions and 41 deletions

View file

@ -9,6 +9,7 @@ const appState = {
wifiReconnectAttempts: 0,
maxReconnectAttempts: 5,
connectedSSID: null,
connectionState: 'disconnected',
networks: [],
uptime: 0,
uptimeInterval: null
@ -104,10 +105,11 @@ async function connectToWifi() {
const password = document.getElementById('wifiPassword').value;
if (appState.selectedWifi.security !== 'Open' && !password) {
showToast('warning', 'Attention', 'Mot de passe requis pour ce réseau');
return;
}
// Password requirement disabled
// if (appState.selectedWifi.security !== 'Open' && !password) {
// showToast('warning', 'Attention', 'Mot de passe requis pour ce réseau');
// return;
// }
showLoading(true);
@ -250,12 +252,32 @@ function updateStatusDisplay(status) {
const wifiDot = wifiStatus.querySelector('.status-dot');
const wifiText = wifiStatus.querySelector('.status-text');
if (status.connected) {
wifiDot.className = 'status-dot active';
wifiText.textContent = `Connecté: ${status.connectedSSID}`;
} else {
wifiDot.className = 'status-dot offline';
wifiText.textContent = 'Déconnecté';
// Use connectionState for more detailed status
const state = status.connectionState || (status.connected ? 'connected' : 'disconnected');
appState.connectionState = state;
switch (state) {
case 'connected':
wifiDot.className = 'status-dot active';
wifiText.textContent = `Connecté: ${status.connectedSSID}`;
break;
case 'connecting':
wifiDot.className = 'status-dot connecting';
wifiText.textContent = status.connectedSSID ? `Connexion à ${status.connectedSSID}...` : 'Connexion...';
break;
case 'disconnecting':
wifiDot.className = 'status-dot disconnecting';
wifiText.textContent = 'Déconnexion...';
break;
case 'roaming':
wifiDot.className = 'status-dot active';
wifiText.textContent = `Roaming: ${status.connectedSSID}`;
break;
case 'disconnected':
default:
wifiDot.className = 'status-dot offline';
wifiText.textContent = 'Déconnecté';
break;
}
// Update hotspot status badge
@ -282,11 +304,14 @@ function updateStatusDisplay(status) {
// Update hotspot details if available
updateHotspotDetails(status.hotspotStatus);
// Check if connectedSSID changed and refresh WiFi list if needed
const connectedSSIDChanged = appState.connectedSSID !== status.connectedSSID;
// Check if connectedSSID or state changed and refresh WiFi list if needed
const prevSSID = appState.connectedSSID;
const prevState = appState.connectionState;
appState.connectedSSID = status.connectedSSID;
if (connectedSSIDChanged && appState.networks.length > 0) {
const connectedChanged = prevSSID !== status.connectedSSID || prevState !== state;
if (connectedChanged && appState.networks.length > 0) {
displayWifiNetworks(appState.networks);
}
@ -314,9 +339,20 @@ function displayWifiNetworks(networks) {
const wifiItem = document.createElement('div');
wifiItem.className = 'wifi-item';
// Mark the currently connected network
// Mark the network based on connection state
if (appState.connectedSSID && network.ssid === appState.connectedSSID) {
wifiItem.classList.add('connected');
switch (appState.connectionState) {
case 'connected':
case 'roaming':
wifiItem.classList.add('connected');
break;
case 'connecting':
wifiItem.classList.add('connecting');
break;
case 'disconnecting':
wifiItem.classList.add('disconnecting');
break;
}
}
wifiItem.onclick = () => selectWifi(network, wifiItem);
@ -576,27 +612,61 @@ function handleStateChange(data) {
const wifiDot = wifiStatus.querySelector('.status-dot');
const wifiText = wifiStatus.querySelector('.status-text');
if (data.state === 'connected') {
wifiDot.className = 'status-dot active';
wifiText.textContent = `Connecté: ${data.ssid}`;
appState.connectedSSID = data.ssid;
// Update state in appState
appState.connectionState = data.state;
// Refresh network list to show connected network
if (appState.networks.length > 0) {
displayWifiNetworks(appState.networks);
}
} else if (data.state === 'disconnected') {
wifiDot.className = 'status-dot offline';
wifiText.textContent = 'Déconnecté';
appState.connectedSSID = null;
switch (data.state) {
case 'connected':
wifiDot.className = 'status-dot active';
wifiText.textContent = `Connecté: ${data.ssid}`;
appState.connectedSSID = data.ssid;
// Refresh network list to remove connected highlighting
if (appState.networks.length > 0) {
displayWifiNetworks(appState.networks);
}
} else if (data.state === 'connecting') {
wifiDot.className = 'status-dot';
wifiText.textContent = `Connexion à ${data.ssid}...`;
// Refresh network list to show connected network
if (appState.networks.length > 0) {
displayWifiNetworks(appState.networks);
}
break;
case 'connecting':
wifiDot.className = 'status-dot connecting';
wifiText.textContent = data.ssid ? `Connexion à ${data.ssid}...` : 'Connexion...';
// Refresh network list to show connecting state
if (appState.networks.length > 0) {
displayWifiNetworks(appState.networks);
}
break;
case 'disconnecting':
wifiDot.className = 'status-dot disconnecting';
wifiText.textContent = 'Déconnexion...';
// Refresh network list to show disconnecting state
if (appState.networks.length > 0) {
displayWifiNetworks(appState.networks);
}
break;
case 'roaming':
wifiDot.className = 'status-dot active';
wifiText.textContent = `Roaming: ${data.ssid}`;
appState.connectedSSID = data.ssid;
break;
case 'disconnected':
wifiDot.className = 'status-dot offline';
wifiText.textContent = 'Déconnecté';
appState.connectedSSID = null;
// Refresh network list to remove connected highlighting
if (appState.networks.length > 0) {
displayWifiNetworks(appState.networks);
}
break;
default:
console.warn('Unknown WiFi state:', data.state);
break;
}
console.log(`WiFi state changed: ${data.previous_state}${data.state}`, data.ssid);

View file

@ -107,11 +107,26 @@ body {
animation: none;
}
.status-dot.connecting {
background: var(--warning-color);
animation: blink 1s ease-in-out infinite;
}
.status-dot.disconnecting {
background: var(--warning-color);
animation: blink 1s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
/* Stats Grid */
.stats-grid {
display: grid;
@ -428,6 +443,33 @@ body {
font-weight: 700;
}
.wifi-item.connecting {
background: #fef3c7;
border-left-color: var(--warning-color) !important;
animation: pulse-item 1.5s ease-in-out infinite;
}
.wifi-item.connecting .wifi-ssid {
color: var(--warning-color);
font-weight: 700;
}
.wifi-item.disconnecting {
background: #fee2e2;
border-left-color: #dc2626 !important;
animation: pulse-item 1.5s ease-in-out infinite;
}
.wifi-item.disconnecting .wifi-ssid {
color: #dc2626;
font-weight: 700;
}
@keyframes pulse-item {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.wifi-item.loading {
justify-content: center;
color: var(--text-secondary);

View file

@ -31,12 +31,13 @@ type App struct {
func New(assets embed.FS) *App {
return &App{
Status: models.SystemStatus{
Connected: false,
ConnectedSSID: "",
HotspotStatus: nil,
ConnectedCount: 0,
DataUsage: 0.0,
Uptime: 0,
Connected: false,
ConnectionState: "disconnected",
ConnectedSSID: "",
HotspotStatus: nil,
ConnectedCount: 0,
DataUsage: 0.0,
Uptime: 0,
},
StartTime: time.Now(),
Assets: assets,
@ -136,6 +137,7 @@ func (a *App) periodicStatusUpdate() {
for range ticker.C {
a.StatusMutex.Lock()
a.Status.Connected = wifi.IsConnected()
a.Status.ConnectionState = wifi.GetConnectionState()
a.Status.ConnectedSSID = wifi.GetConnectedSSID()
a.Status.Uptime = getSystemUptime()

View file

@ -41,6 +41,7 @@ type HotspotStatus struct {
// SystemStatus represents overall system status
type SystemStatus struct {
Connected bool `json:"connected"`
ConnectionState string `json:"connectionState"` // Connection state: connected, disconnected, connecting, disconnecting, roaming
ConnectedSSID string `json:"connectedSSID"`
HotspotStatus *HotspotStatus `json:"hotspotStatus,omitempty"` // Detailed hotspot status
ConnectedCount int `json:"connectedCount"`

View file

@ -241,6 +241,15 @@ func GetConnectedSSID() string {
return props.Name
}
// GetConnectionState returns the current WiFi connection state
func GetConnectionState() string {
state, err := station.GetState()
if err != nil {
return string(iwd.StateDisconnected)
}
return string(state)
}
// StartEventMonitoring initializes D-Bus signal monitoring and WebSocket broadcasting
func StartEventMonitoring() error {
// Initialize broadcaster

View file

@ -454,6 +454,16 @@ components:
type: boolean
description: Whether router is connected to upstream WiFi
example: true
connectionState:
type: string
description: Current WiFi connection state
enum:
- connected
- disconnected
- connecting
- disconnecting
- roaming
example: "connected"
connectedSSID:
type: string
description: SSID of connected upstream network (empty if not connected)
@ -485,6 +495,7 @@ components:
$ref: '#/components/schemas/ConnectedDevice'
required:
- connected
- connectionState
- connectedSSID
- connectedCount
- dataUsage