Skip to content

Commit

Permalink
Merge pull request #191 from DroidKaigi/takahirom/add-contributor-vie…
Browse files Browse the repository at this point in the history
…wmodel/2023-06-14

Add contributor ViewModel
  • Loading branch information
takahirom authored Jun 15, 2023
2 parents d3f922a + 14b0710 commit c9dffde
Show file tree
Hide file tree
Showing 19 changed files with 144 additions and 41 deletions.
1 change: 1 addition & 0 deletions app-android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ dependencies {
implementation(projects.core.data)
implementation(projects.core.designsystem)
implementation(libs.composeNavigation)
implementation(libs.composeHiltNavigtation)
testImplementation(projects.core.testing)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import dagger.hilt.android.AndroidEntryPoint
import io.github.droidkaigi.confsched2023.contributors.ContributorsScreen
import io.github.droidkaigi.confsched2023.contributors.ContributorsViewModel
import io.github.droidkaigi.confsched2023.designsystem.theme.KaigiTheme
import io.github.droidkaigi.confsched2023.sessions.TimetableScreen

Expand All @@ -36,7 +38,7 @@ class MainActivity : ComponentActivity() {
)
}
composable("contributors") {
ContributorsScreen()
ContributorsScreen(hiltViewModel<ContributorsViewModel>())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class AndroidKotlinPlugin : Plugin<Project> {
}
dependencies {
implementation(libs.findLibrary("kotlinxCoroutinesCore"))
// Fix https://youtrack.jetbrains.com/issue/KT-41821
implementation(libs.findLibrary("kotlinxAtomicfu"))
}
}
Expand Down
15 changes: 15 additions & 0 deletions core/designsystem/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
import io.github.droidkaigi.confsched2023.primitive.implementation
import io.github.droidkaigi.confsched2023.primitive.libs

plugins {
id("droidkaigi.primitive.kmp")
id("droidkaigi.primitive.kmp.android")
id("droidkaigi.primitive.kmp.ios")
id("droidkaigi.primitive.kmp.compose")
id("droidkaigi.primitive.kmp.android.hilt")
id("droidkaigi.primitive.spotless")
}

android.namespace = "io.github.droidkaigi.confsched2023.core.designsystem"

kotlin {
sourceSets {
commonMain {
dependencies {
// Fix https://youtrack.jetbrains.com/issue/KT-41821
implementation(libs.findLibrary("kotlinxAtomicfu").get())
}
}
}
}

dependencies {
}
2 changes: 2 additions & 0 deletions core/ui/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id("droidkaigi.primitive.kmp")
id("droidkaigi.primitive.kmp.android")
id("droidkaigi.primitive.kmp.ios")
id("droidkaigi.primitive.kmp.compose")
id("droidkaigi.primitive.kmp.android.hilt")
id("droidkaigi.primitive.spotless")
Expand All @@ -13,6 +14,7 @@ kotlin{
commonMain {
dependencies {
implementation(project(":core:designsystem"))
implementation(project(":core:data"))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.github.droidkaigi.confsched2023.ui

import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

actual typealias KmpHiltViewModel = HiltViewModel
actual typealias KmpInject = Inject
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.github.droidkaigi.confsched2023.ui

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch

fun <T> Flow<T>.handleErrorAndRetryAction(
actionLabel: String,
userMessageStateHolder: UserMessageStateHolder,
retryAction: suspend ((Throwable) -> Unit),
) = catch { throwable ->
val messageResult = userMessageStateHolder.showMessage(
message = throwable.toApplicationErrorMessage(),
actionLabel = actionLabel,
)

if (messageResult == UserMessageResult.ActionPerformed) {
retryAction(throwable)
}
}.catch { /* Do nothing if the user dose not retry. */ }
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,3 @@ fun <T> Flow<T>.handleErrorAndRetry(

retryPerformed
}.catch { /* Do nothing if the user dose not retry. */ }

fun <T> Flow<T>.handleErrorAndRetryAction(
actionLabel: String,
userMessageStateHolder: UserMessageStateHolder,
retryAction: suspend ((Throwable) -> Unit),
) = catch { throwable ->
val messageResult = userMessageStateHolder.showMessage(
message = throwable.toApplicationErrorMessage(),
actionLabel = actionLabel,
)

if (messageResult == UserMessageResult.ActionPerformed) {
retryAction(throwable)
}
}.catch { /* Do nothing if the user dose not retry. */ }
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.github.droidkaigi.confsched2023.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineScope

actual typealias KmpViewModel = ViewModel

actual val KmpViewModel.viewModelScope: CoroutineScope
get() = this.viewModelScope
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.github.droidkaigi.confsched2023.ui

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@Module
@InstallIn(SingletonComponent::class)
class MessageStateHolderModule {
@Provides
fun provideMessageStateHolder(): UserMessageStateHolder {
return UserMessageStateHolderImpl()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
Expand Down Expand Up @@ -54,16 +50,6 @@ data class UserMessage(
data class MessageUiState(
val userMessages: List<UserMessage> = emptyList(),
)

@Module
@InstallIn(SingletonComponent::class)
class MessageStateHolderModule {
@Provides
fun provideMessageStateHolder(): UserMessageStateHolder {
return UserMessageStateHolderImpl()
}
}

class UserMessageStateHolderImpl : UserMessageStateHolder {
private var _messageUiState by mutableStateOf(MessageUiState())
override val messageUiState get() = _messageUiState
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.github.droidkaigi.confsched2023.ui

expect annotation class KmpHiltViewModel()
expect annotation class KmpInject()
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.github.droidkaigi.confsched2023.ui

import kotlinx.coroutines.CoroutineScope

expect abstract class KmpViewModel()

expect val KmpViewModel.viewModelScope: CoroutineScope
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.github.droidkaigi.confsched2023.ui

actual annotation class KmpHiltViewModel()
actual annotation class KmpInject()
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.github.droidkaigi.confsched2023.ui

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope

actual abstract class KmpViewModel
actual val KmpViewModel.viewModelScope: CoroutineScope
// TODO: Cancel scope
get() = MainScope()
1 change: 1 addition & 0 deletions feature/contributors/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ kotlin {
commonMain {
dependencies {
implementation(projects.core.model)
implementation(projects.core.ui)
implementation(libs.kotlinxCoroutinesCore)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
package io.github.droidkaigi.confsched2023.contributors

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import io.github.droidkaigi.confsched2023.contributors.Contributors
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue

@Composable
fun ContributorsScreen() {
fun ContributorsScreen(viewModel: ContributorsViewModel) {
val contributors = Contributors()
Text(text = contributors.greet())
val sessions by viewModel.sessions.collectAsState()
Column {
sessions.timetableItems.forEach {
Text(
text = it.title.currentLangTitle,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.droidkaigi.confsched2023.contributors

import io.github.droidkaigi.confsched2023.model.SessionsRepository
import io.github.droidkaigi.confsched2023.model.Timetable
import io.github.droidkaigi.confsched2023.ui.KmpHiltViewModel
import io.github.droidkaigi.confsched2023.ui.KmpInject
import io.github.droidkaigi.confsched2023.ui.KmpViewModel
import io.github.droidkaigi.confsched2023.ui.viewModelScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn

@KmpHiltViewModel
class ContributorsViewModel @KmpInject constructor(val sessionRepository: SessionsRepository) :
KmpViewModel() {
// FIXME
val sessions = sessionRepository.getSessionsStream()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), Timetable())

fun greet(): String {
return "Hello, ${Contributors().greet()}"
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package io.github.droidkaigi.confsched2023.contributors

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.interop.LocalUIViewController
import androidx.compose.ui.window.ComposeUIViewController
import io.github.droidkaigi.confsched2023.data.DefaultSessionsRepository
import io.github.droidkaigi.confsched2023.data.FakeSessionsApi
import platform.UIKit.UIViewController

@Suppress("UNUSED")
fun viewController(): UIViewController = ComposeUIViewController {
Column(
modifier = Modifier
.fillMaxSize()
) {
Text("Hello")
val viewModel = ContributorsViewModel(DefaultSessionsRepository(FakeSessionsApi()))
val uiViewController = LocalUIViewController.current
LaunchedEffect(uiViewController) {
// uiViewController
// TODO: How to know the destroy event of the ViewController?
// viewModel.viewModelScope.cancel()
}

ContributorsScreen(viewModel)
}

0 comments on commit c9dffde

Please sign in to comment.