Initial commit

This commit is contained in:
weishaupt
2026-09-01 12:32:15 -04:00
commit defdefdb28
33 changed files with 3540 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
package data
/** A configured IRC server/network connection. */
data class ServerConfig(
val id: String, // stable key, e.g. "rizon"
val label: String, // display name, e.g. "Rizon"
val host: String,
val port: Int = 6667,
val useTls: Boolean = false,
val nick: String,
val autoJoinChannels: List<String> = emptyList(),
val saslUser: String? = null,
val saslPass: String? = null,
// Raw IRC commands sent right after registration (001), before auto-join channels.
// e.g. "PRIVMSG NickServ :IDENTIFY hunter2" or "NS IDENTIFY hunter2".
// This is the "on join perform" list — saved to disk and replayed every connect.
val onConnectCommands: List<String> = emptyList()
)
/** True for channel-style targets ('#', '&', '+', '!' prefixes per the IRC spec). */
fun isChannelName(name: String): Boolean =
name.isNotEmpty() && name[0] in "#&+!"
enum class MessageKind { CHAT, ACTION, JOIN, PART, QUIT, KICK, MODE, NOTICE, NICK, TOPIC, SYSTEM }
// Process-wide, so every IrcMessage ever constructed while the app is running gets a
// genuinely unique seq, regardless of which buffer/server it belongs to.
private val nextMessageSeq = java.util.concurrent.atomic.AtomicLong(0)
data class IrcMessage(
val timestampMillis: Long,
val kind: MessageKind,
val sender: String?, // nick, or null for system/server lines
val rawText: String, // still contains mIRC control codes; parsed at render time
val target: String? = null, // e.g. for KICK, the nick that got kicked
// Monotonically increasing, guaranteed-unique identity for this message - used as the
// LazyColumn item key in ChannelScreen (see there). The old key there was
// "${timestampMillis}_${sender}_${rawText.hashCode()}" - in a genuinely busy channel,
// two messages sharing the same millisecond, sender, and text (not rare for short
// repeated lines - "lol", a single emoji, etc.) would produce the exact same key, and
// Compose requires unique keys per item. Not persisted to disk - history reloaded on
// restart just gets fresh seq values in load order, which is fine since uniqueness only
// needs to hold within a single running session, not across restarts.
val seq: Long = nextMessageSeq.getAndIncrement()
)
/** Buffer key: server id + channel/query name (channel names include '#'). */
data class BufferKey(val serverId: String, val name: String)
data class ChannelUser(
val nick: String,
val isOp: Boolean = false,
val isVoice: Boolean = false
)
data class ChannelBuffer(
val key: BufferKey,
val messages: List<IrcMessage> = emptyList(),
val users: List<ChannelUser> = emptyList(),
val topic: String = ""
)