Add wIRC main scrollback, route services to it, remember window bounds, bump to 0.1.7
wIRC main scrollback - The main window now has a "Server messages" scrollback using the same rendering and stick-to-bottom code as channel windows (extracted from ChannelScreen into a shared MessageScrollback composable). - MOTD, numerics, errors, connection status, user modes, INVITE, ERROR, non-ACTION CTCP requests and notices/messages from services (NickServ, ChanServ, *Serv, Global, ...) and the server go there. Its history persists like any other buffer (history/wirc-main__main.json). - Unread indicator: lines arriving while the main window is unfocused show as "N new" next to the label and in the window title/taskbar. Private messages and /whois - A PM or notice from a real user opens its query window, and reopens it if it was closed. Services and the server no longer open windows. - /whois <nick> sends WHOIS and shows the formatted reply in the window it was typed in, or in wIRC main if that window has since closed. - /me now sends a proper CTCP ACTION (the \x01 wrapper was missing). Window position and size - Main, channel and PM windows remember position and size in window_prefs.json under the existing "<serverId>__<name>" key (main uses "wirc-main__main"). The new windowX/windowY/windowWidth/ windowHeight fields are optional, so older files still load. - A saved position is only used if the window's title strip is on a connected monitor; otherwise, and for windows with no saved position, windows cascade from the primary screen's top-left with a 32dp offset. - window_prefs.json is now written via a temp file + atomic move. Cleanup - Remove the TEMP DEBUG aliasDebug tracing, ServerRepository.upsert printlns and connmgr-debug printlns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
242d7a7c42
commit
807903fe0f
+30
-5
@@ -2,6 +2,7 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -9,16 +10,20 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.application
|
||||
import androidx.compose.ui.window.rememberWindowState
|
||||
import data.AliasRepository
|
||||
import data.BufferKey
|
||||
import data.MAIN_BUFFER_KEY
|
||||
import data.ServerRepository
|
||||
import data.WindowPrefsRepository
|
||||
import data.storageId
|
||||
import irc.ConnectionManager
|
||||
import ui.ChannelWindow
|
||||
import ui.MainScreen
|
||||
import ui.rememberPersistentWindowState
|
||||
import java.io.File
|
||||
|
||||
// Material 3's darkColorScheme() defaults to a purple accent; this keeps everything
|
||||
@@ -51,6 +56,13 @@ fun main() = application {
|
||||
val prefsRepo = remember { WindowPrefsRepository(appRoot) }
|
||||
|
||||
var openBuffers by remember { mutableStateOf(setOf<BufferKey>()) }
|
||||
var mainUnread by remember { mutableStateOf(0) }
|
||||
|
||||
// ConnectionManager routes WHOIS replies to the window that asked only while that
|
||||
// window is still open, so it needs to know which ones are.
|
||||
LaunchedEffect(openBuffers) {
|
||||
ConnectionManager.openWindows = openBuffers
|
||||
}
|
||||
|
||||
// Full shutdown: same steps /quit (bare, no args) already runs from a channel window -
|
||||
// disconnect every server, then end the process. Shared here so the "Exit wIRC" button
|
||||
@@ -65,31 +77,44 @@ fun main() = application {
|
||||
// ConnectionManager's sockets just live for as long as this process runs, and this
|
||||
// listener (which the Android foreground service used to own) can live directly at
|
||||
// the application level instead.
|
||||
//
|
||||
// Fires for every private message to or from a real user, so a query window the user
|
||||
// closed reopens when that person messages again. Adding a key that's already open is
|
||||
// a no-op (openBuffers is a set).
|
||||
LaunchedEffect(Unit) {
|
||||
ConnectionManager.newQueryBuffers.collect { key ->
|
||||
ConnectionManager.queryWindowRequests.collect { key ->
|
||||
openBuffers = openBuffers + key
|
||||
}
|
||||
}
|
||||
|
||||
// Restored from / saved to window_prefs.json under MAIN_BUFFER_KEY's storage id
|
||||
// ("wirc-main__main"), same as every channel and PM window - see WindowPlacement.kt.
|
||||
val mainWindowState = rememberPersistentWindowState(prefsRepo, MAIN_BUFFER_KEY.storageId(), DpSize(800.dp, 700.dp))
|
||||
val mainDisplaySettings by prefsRepo.settingsFor(MAIN_BUFFER_KEY.storageId()).collectAsState()
|
||||
|
||||
// There's no persistent tray/notification surface on this build, so closing the main
|
||||
// server-list window quits the whole app (and every channel window with it) - the
|
||||
// same "closing the primary window ends the session" convention most desktop chat
|
||||
// apps without a tray icon follow.
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
title = "wIRC - Main",
|
||||
// The unread count shows in the taskbar too, so new server messages are visible
|
||||
// even when the main window is behind other windows.
|
||||
title = if (mainUnread > 0) "wIRC - Main ($mainUnread new)" else "wIRC - Main",
|
||||
icon = painterResource("icon.png"),
|
||||
state = rememberWindowState()
|
||||
state = mainWindowState
|
||||
) {
|
||||
MaterialTheme(colorScheme = neutralDarkScheme) {
|
||||
Surface {
|
||||
MainScreen(
|
||||
repo = repo,
|
||||
colorScheme = neutralDarkScheme,
|
||||
displaySettings = mainDisplaySettings,
|
||||
onOpenChannel = { serverId, channelName ->
|
||||
openBuffers = openBuffers + BufferKey(serverId, channelName)
|
||||
},
|
||||
onExitApp = shutdownApp
|
||||
onExitApp = shutdownApp,
|
||||
onUnreadChange = { mainUnread = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user