Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/main/kotlin/chatroom/sendmessages/SendMessagePresenter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import arch.Presenter
import arch.RokyDispatchers
import chatroom.sendmessages.SendMessageEvent.SendMessage
import chatroom.sendmessages.SendMessageViewState.Clear
import chatserver.MessagesRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class SendMessagePresenter(
private val windowScope: CoroutineScope,
private val send: MessagesRepository.Write,
private val send: (String) -> Unit = ::println,
dispatchers: RokyDispatchers,
) : Presenter<SendMessagesView>(dispatchers) {
override fun onAttach(view: SendMessagesView) {
Expand All @@ -25,7 +24,7 @@ class SendMessagePresenter(
fun onEvent(event: SendMessageEvent) {
if (event is SendMessage) {
windowScope.launch(dispatchers.io) {
send.send(event.message)
send(event.message)
withContext(dispatchers.main) {
withView { it.show(Clear) }
}
Expand Down
1 change: 0 additions & 1 deletion src/main/kotlin/chatroom/sendmessages/SendMessages.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ val sendMessagesModule =
scoped {
SendMessagePresenter(
dispatchers = get(),
send = get(),
windowScope = get<ChatroomWindow>().windowScope,
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/chatroom/users/UsersListUseCase.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package chatroom.users

import chatroom.viewmessages.ViewMessagesUseCase
import chatserver.messages.LocalChatMessages
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlin.random.Random
import kotlin.time.Duration.Companion.seconds

class UsersListUseCase(
private val users: List<String> = ViewMessagesUseCase.sampleUsers,
private val users: List<String> = LocalChatMessages.sampleUsers,
private val rndInt: () -> Int = { Random.nextInt(4, users.size - 1) },
private val rndUser: (List<String>) -> String = { it.random() },
) {
Expand Down
5 changes: 3 additions & 2 deletions src/main/kotlin/chatroom/viewmessages/ViewMessages.kt
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package chatroom.viewmessages

import chatroom.ChatroomWindow
import chatserver.ChatRepositories
import org.koin.dsl.module

val viewMessagesModule =
module {
scope<ChatroomWindow> {
scoped { ViewMessagesPanel(get()) }
scoped { ViewMessagesUseCase(read = get()) }
scoped {
ViewMessagesPresenter(
windowScope = get<ChatroomWindow>().windowScope,
dispatchers = get(),
messages = get(),
read = get<ChatRepositories>().readMessages(),
channel = get<ChatRepositories>().subscribeMessages(),
)
}
}
Expand Down
22 changes: 16 additions & 6 deletions src/main/kotlin/chatroom/viewmessages/ViewMessagesPresenter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,38 @@ import arch.Presenter
import arch.RokyDispatchers
import chatroom.viewmessages.ViewMessagesViewState.Messages
import chatroom.viewmessages.ViewMessagesViewState.NoMessages
import chatserver.ChatMessageResult
import chatserver.ReadChatRepository
import chatserver.SubscribeChatRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class ViewMessagesPresenter(
private val windowScope: CoroutineScope,
private val messages: ViewMessagesUseCase,
private val read: ReadChatRepository<ChatMessageResult>,
private val channel: SubscribeChatRepository,
dispatchers: RokyDispatchers,
) : Presenter<ViewMessagesView>(dispatchers) {
override fun onAttach(view: ViewMessagesView) {
view.show(NoMessages)
windowScope.launch(dispatchers.io) {
messages().map { Messages(it) }.collect { message ->
withContext(dispatchers.main) {
withView { it.show(message) }
read.observe()
.filter { it.isOk }
.map { it.item }
.map(::Messages)
.collect { message ->
withContext(dispatchers.main) {
withView { it.show(message) }
}
}
}
}
channel.subscribe()
}

override fun onDetach(view: ViewMessagesView) {
// deliberately empty to please the auto-formatter
channel.unsubscribe()
}
}
66 changes: 0 additions & 66 deletions src/main/kotlin/chatroom/viewmessages/ViewMessagesUseCase.kt

This file was deleted.

16 changes: 16 additions & 0 deletions src/main/kotlin/chatserver/ChatMessageResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package chatserver

import chatserver.ReadChatRepository.ReadResult

data class ChatMessageResult(
override val isOk: Boolean,
override val item: String,
override val error: Exception?,
) :
ReadResult<String> {
companion object {
fun ok(item: String): ChatMessageResult = ChatMessageResult(true, item, null)

fun fail(e: Exception? = null): ChatMessageResult = ChatMessageResult(false, "", e)
}
}
6 changes: 6 additions & 0 deletions src/main/kotlin/chatserver/ChatRepositories.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package chatserver

import chatserver.messages.LocalChatMessages
import chatserver.profiles.LocalProfilesRepository

class ChatRepositories(
private val profiles: LocalProfilesRepository,
private val messages: LocalChatMessages,
) {
fun writeProfiles(): WriteChatRepository<String> = profiles

fun readProfiles(): ReadChatRepository<ProfileResult> = profiles

fun subscribeProfiles(): SubscribeChatRepository = profiles

fun readMessages(): ReadChatRepository<ChatMessageResult> = messages

fun subscribeMessages(): SubscribeChatRepository = messages
}
7 changes: 2 additions & 5 deletions src/main/kotlin/chatserver/ChatServer.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package chatserver

import chatserver.MessagesRepository.Read
import chatserver.MessagesRepository.Write
import chatserver.messages.chatServerMessagesModule
import chatserver.profiles.chatServerProfilesModule
import org.koin.core.module.dsl.factoryOf
import org.koin.dsl.binds
import org.koin.dsl.module

val chatServerModule =
module {
includes(chatServerProfilesModule)
factory { MockMessages } binds arrayOf(Read::class, Write::class)
includes(chatServerProfilesModule, chatServerMessagesModule)
factoryOf(::ChatRepositories)
}
13 changes: 0 additions & 13 deletions src/main/kotlin/chatserver/MessagesRepository.kt

This file was deleted.

20 changes: 0 additions & 20 deletions src/main/kotlin/chatserver/MockMessages.kt

This file was deleted.

8 changes: 8 additions & 0 deletions src/main/kotlin/chatserver/messages/ChatServerMessages.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package chatserver.messages

import org.koin.dsl.module

val chatServerMessagesModule =
module {
single { LocalChatMessages(get()) }
}
92 changes: 92 additions & 0 deletions src/main/kotlin/chatserver/messages/LocalChatMessages.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package chatserver.messages

import arch.RokyDispatchers
import chatserver.ChatMessageResult
import chatserver.ReadChatRepository
import chatserver.SubscribeChatRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlin.time.Duration.Companion.seconds

class LocalChatMessages(
private val dispatchers: RokyDispatchers,
private val scope: CoroutineScope = CoroutineScope(dispatchers.default + Job()),
private val source: () -> Flow<String> = { emitEveryThreeSeconds(sampleUsers, sampleMessages) },
) : ReadChatRepository<ChatMessageResult>, SubscribeChatRepository {
private var samples: Job? = null
private val _events = MutableStateFlow("")
private val events = _events.asStateFlow()

override fun latest(): ChatMessageResult = events.toResult()

override fun observe(): Flow<ChatMessageResult> = events.map { ChatMessageResult.ok(it) }

override fun subscribe() {
samples =
scope.launch {
source().cancellable().collect {
_events.value = it
}
}
}

override fun unsubscribe() {
samples?.cancel()
}

companion object {
private fun StateFlow<String>.toResult(): ChatMessageResult = ChatMessageResult.ok(value)

private val sampleMessages =
listOf(
"This is a coup!",
"What time's Roky Coding tonight?",
"Look at the calendar...",
"Charizard",
"Remind me to get my washing at 4 PM",
"ASMR....",
"BRAIN...praise me",
"Biggleswade is naff",
"Biggleswade is amazing /s",
"I love Biggleswade!!!",
"AHHHHHHHHHHHHHHHHHH",
"Wordle: 4/6",
"Wordle: 1/6",
"Wordle: 2/6",
"I AM SO HUNGRY RN",
"I am feeling quiet today",
":thumbs_up:",
"I just have a bit of a cold rn",
"I just think it's something going around",
"Don't just type out what I'm saying Mike",
":breathing_noises:",
)

val sampleUsers =
listOf(
"Martine",
"Ed",
"Kai",
"Terry",
"Robert",
"Tom",
"Brian",
"Dunia",
"Stefano",
"Mike",
)

private fun emitEveryThreeSeconds(
users: List<String>,
messages: List<String>,
) = flow {
while (true) {
delay(3.seconds)
emit("${users.random()}: ${messages.random()}")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package chatserver.profiles

import arch.RokyDispatchers
import chatroom.viewmessages.ViewMessagesUseCase
import chatserver.ProfileResult
import chatserver.ProfileResult.Companion.ok
import chatserver.ReadChatRepository
import chatserver.SubscribeChatRepository
import chatserver.WriteChatRepository
import chatserver.messages.LocalChatMessages
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
Expand All @@ -32,7 +32,7 @@ class LocalProfilesRepository(
override fun subscribe() {
scope.launch(dispatchers.default) {
while (true) {
val users = ViewMessagesUseCase.sampleUsers.shuffled()
val users = LocalChatMessages.sampleUsers.shuffled()
state.value = users.associateWith { it }.let(ProfileResult::ok)
delay(5.seconds)
}
Expand Down
Loading
Loading