fix: correct connect/disconnect button state on connection lifecycle

- Enable disconnect button immediately when connect is clicked, so the
  user can cancel without waiting for the StateConnecting IPC event.
- Disable disconnect button on all error paths in the connect goroutine
  to restore the default disconnected button state.
- Capture ipcClient once at eventLoop start instead of re-reading every
  iteration, preventing a second onConnect call from making the old
  event loop jump to the new client and consume events concurrently.
- In eventLoop recv error recovery, only reset button states if the
  current ipcClient still matches the captured one, so a stale
  disconnection does not clobber the state of a newer session.
- Disable connect button in StateReconnecting case (was missing).
- Remove WriteOK from daemon startSession: the StateConnecting event
  already serves as the implicit acknowledgment; the OK response was
  being read by eventLoop as a no-op event, adding unnecessary noise.
This commit is contained in:
2026-07-06 19:34:29 +08:00
parent b0aa386ee2
commit 04d2e6e429
2 changed files with 24 additions and 14 deletions
-1
View File
@@ -155,7 +155,6 @@ func (d *daemon) startSession(conn net.Conn, req ipc.Request) {
d.session = nil
return
}
_ = ipc.WriteOK(conn)
}
func (d *daemon) stopSession() {
+24 -13
View File
@@ -75,6 +75,7 @@ func (a *App) onConnect() {
}
a.connectBtn.Disable()
a.disconnectBtn.Enable()
a.stateLabel.SetText(i18n.T("StateConnecting"))
go func() {
@@ -85,6 +86,7 @@ func (a *App) onConnect() {
showError(i18n.T("DlgDaemonError"), err.Error(), a.window)
a.stateLabel.SetText(i18n.T("StateDisconnected"))
a.connectBtn.Enable()
a.disconnectBtn.Disable()
})
return
}
@@ -102,6 +104,7 @@ func (a *App) onConnect() {
a.window)
a.stateLabel.SetText(i18n.T("StateDisconnected"))
a.connectBtn.Enable()
a.disconnectBtn.Disable()
})
return
}
@@ -121,6 +124,7 @@ func (a *App) onConnect() {
showError(i18n.T("DlgIPCError"), err.Error(), a.window)
a.stateLabel.SetText(i18n.T("StateDisconnected"))
a.connectBtn.Enable()
a.disconnectBtn.Disable()
})
return
}
@@ -146,23 +150,29 @@ func (a *App) onDisconnect() {
// eventLoop reads IPC events from the daemon and updates the UI.
func (a *App) eventLoop() {
a.mu.Lock()
client := a.ipcClient
a.mu.Unlock()
if client == nil {
return
}
for {
a.mu.Lock()
client := a.ipcClient
a.mu.Unlock()
if client == nil {
return
}
ev, err := client.Recv()
if err != nil {
fyne.Do(func() {
a.stateLabel.SetText(i18n.T("StateDisconnected"))
a.ipLabel.SetText(i18n.T("IpNone"))
a.uptimeLabel.SetText(i18n.T("UptimeNone"))
a.rxLabel.SetText(i18n.T("RxZero"))
a.txLabel.SetText(i18n.T("TxZero"))
a.connectBtn.Enable()
a.disconnectBtn.Disable()
a.mu.Lock()
current := a.ipcClient
a.mu.Unlock()
if current == client {
a.stateLabel.SetText(i18n.T("StateDisconnected"))
a.ipLabel.SetText(i18n.T("IpNone"))
a.uptimeLabel.SetText(i18n.T("UptimeNone"))
a.rxLabel.SetText(i18n.T("RxZero"))
a.txLabel.SetText(i18n.T("TxZero"))
a.connectBtn.Enable()
a.disconnectBtn.Disable()
}
})
return
}
@@ -201,6 +211,7 @@ func (a *App) applyState(state string) {
a.disconnectBtn.Enable()
case stats.StateReconnecting:
a.stateLabel.SetText(i18n.T("StateReconnecting"))
a.connectBtn.Disable()
a.disconnectBtn.Enable()
case stats.StateDisconnected:
a.stateLabel.SetText(i18n.T("StateDisconnected"))