From ada963441ab217ddac564c19bb3b96db780a7b69 Mon Sep 17 00:00:00 2001 From: b4tchkn Date: Sat, 2 Mar 2024 18:05:41 +0900 Subject: [PATCH 1/3] feat: AssistedInjection HiltViewModel --- app/src/main/kotlin/KonnpassApp.kt | 16 ++++--- .../konnpass/state/AsyncStateViewModel.kt | 6 +++ .../state/event/EventStateViewModel.kt | 20 +++----- .../state/event/EventStateViewModelFactory.kt | 8 ++++ .../konnpass/ui/screen/EventDetailScreen.kt | 46 +++++++++++++++++-- .../b4tchkn/konnpass/ui/screen/HomeScreen.kt | 8 +++- 6 files changed, 80 insertions(+), 24 deletions(-) create mode 100644 app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModelFactory.kt diff --git a/app/src/main/kotlin/KonnpassApp.kt b/app/src/main/kotlin/KonnpassApp.kt index beb6787..f928b8c 100644 --- a/app/src/main/kotlin/KonnpassApp.kt +++ b/app/src/main/kotlin/KonnpassApp.kt @@ -7,6 +7,9 @@ import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument import io.github.b4tchkn.konnpass.ui.screen.EventDetailScreen import io.github.b4tchkn.konnpass.ui.screen.HomeScreen +import io.github.b4tchkn.konnpass.ui.screen.eventDetailScreenParamId +import io.github.b4tchkn.konnpass.ui.screen.eventDetailScreenRoute +import io.github.b4tchkn.konnpass.ui.screen.navigateToEventDetailScreen @Composable fun KonnpassApp() { @@ -21,20 +24,21 @@ fun KonnpassNavHost( NavHost(navController = navController, startDestination = "home") { composable("home") { HomeScreen( - onEventPressed = { - navController.navigate("event_detail/${it.title}") - }, + onEventPressed = navController::navigateToEventDetailScreen, ) } composable( - "event_detail/{data}", + eventDetailScreenRoute, arguments = listOf( - navArgument("data") { + navArgument(eventDetailScreenParamId) { type = NavType.StringType }, ), ) { - EventDetailScreen(it.arguments?.getString("data")) + EventDetailScreen( + eventId = it.arguments?.getString(eventDetailScreenParamId), + onBackPressed = navController::popBackStack, + ) } } } diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/AsyncStateViewModel.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/AsyncStateViewModel.kt index faef168..ccd4330 100644 --- a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/AsyncStateViewModel.kt +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/AsyncStateViewModel.kt @@ -13,6 +13,12 @@ abstract class AsyncStateViewModel : ViewModel() { val state: StateFlow> get() = _state + init { + viewModelScope.launch { + refresh() + } + } + abstract suspend fun fetch(): T suspend fun refresh(loading: LoadingStatus = LoadingStatus.Loading) = runAsync(loading) { diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt index 9b2598c..897d7d9 100644 --- a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt @@ -1,28 +1,20 @@ package io.github.b4tchkn.konnpass.state.event -import androidx.lifecycle.viewModelScope +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject import dagger.hilt.android.lifecycle.HiltViewModel import io.github.b4tchkn.konnpass.model.EventResponseModel import io.github.b4tchkn.konnpass.state.AsyncStateViewModel import io.github.b4tchkn.konnpass.usecase.GetEventsUseCase -import kotlinx.coroutines.launch import javax.inject.Inject -@HiltViewModel -class EventStateViewModel @Inject constructor( +@HiltViewModel(assistedFactory = EventStateViewModelFactory::class) +class EventStateViewModel @AssistedInject constructor( private val useCase: GetEventsUseCase, + @Assisted private val param: EventStateViewModelParam, ) : AsyncStateViewModel() { - init { - viewModelScope.launch { - refresh() - } - } - override suspend fun fetch(): EventResponseModel { - val param = EventStateViewModelParam( - count = LIMIT_LOAD_COUNT, - ) return useCase( eventId = param.eventId, keyword = param.keyword, @@ -33,7 +25,7 @@ class EventStateViewModel @Inject constructor( seriesId = param.seriesId, start = param.start, order = param.order, - count = param.count, + count = param.count ?: LIMIT_LOAD_COUNT, ) } diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModelFactory.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModelFactory.kt new file mode 100644 index 0000000..9d88cc4 --- /dev/null +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModelFactory.kt @@ -0,0 +1,8 @@ +package io.github.b4tchkn.konnpass.state.event + +import dagger.assisted.AssistedFactory + +@AssistedFactory +interface EventStateViewModelFactory { + fun create(param: EventStateViewModelParam): EventStateViewModel +} \ No newline at end of file diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/EventDetailScreen.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/EventDetailScreen.kt index 2e12b61..5c5da71 100644 --- a/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/EventDetailScreen.kt +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/EventDetailScreen.kt @@ -1,17 +1,57 @@ package io.github.b4tchkn.konnpass.ui.screen import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.navigation.NavController +import io.github.b4tchkn.konnpass.model.EventModel +const val eventDetailScreenParamId = "eventId" +const val eventDetailScreenRoute = "event_detail/{$eventDetailScreenParamId}" + +fun NavController.navigateToEventDetailScreen( + event: EventModel, +) { + navigate( + eventDetailScreenRoute.replace( + "{$eventDetailScreenParamId}", + event.eventId.toString(), + ), + ) +} + +@OptIn(ExperimentalMaterial3Api::class) @Composable -fun EventDetailScreen(data: String?) { - Scaffold { +fun EventDetailScreen( + eventId: String?, + onBackPressed: () -> Unit, +) { + Scaffold( + topBar = { + TopAppBar( + title = { Text(text = eventId ?: "") }, + navigationIcon = { + IconButton(onClick = onBackPressed) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "もどる", + ) + } + }, + ) + }, + ) { Text( modifier = Modifier.padding(it), - text = data ?: "None", + text = eventId ?: "None", ) } } diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/HomeScreen.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/HomeScreen.kt index 13c25e8..f58327b 100644 --- a/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/HomeScreen.kt +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/HomeScreen.kt @@ -15,10 +15,16 @@ import androidx.hilt.navigation.compose.hiltViewModel import io.github.b4tchkn.konnpass.model.EventModel import io.github.b4tchkn.konnpass.state.LoadingStatus import io.github.b4tchkn.konnpass.state.event.EventStateViewModel +import io.github.b4tchkn.konnpass.state.event.EventStateViewModelFactory +import io.github.b4tchkn.konnpass.state.event.EventStateViewModelParam @Composable fun HomeScreen( - eventStateViewModel: EventStateViewModel = hiltViewModel(), + eventStateViewModel: EventStateViewModel = hiltViewModel( + creationCallback = { factory: EventStateViewModelFactory -> + factory.create(EventStateViewModelParam()) + } + ), onEventPressed: (event: EventModel) -> Unit, ) { val eventState by eventStateViewModel.state.collectAsState() From 9ea3d36221d0b943d3fd670f730ea34d20b3a26f Mon Sep 17 00:00:00 2001 From: b4tchkn Date: Sat, 2 Mar 2024 18:06:45 +0900 Subject: [PATCH 2/3] refactor: run ktlintFormat --- .../github/b4tchkn/konnpass/state/event/EventStateViewModel.kt | 1 - .../b4tchkn/konnpass/state/event/EventStateViewModelFactory.kt | 2 +- .../kotlin/io/github/b4tchkn/konnpass/ui/screen/HomeScreen.kt | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt index 897d7d9..e5ea068 100644 --- a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt @@ -6,7 +6,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel import io.github.b4tchkn.konnpass.model.EventResponseModel import io.github.b4tchkn.konnpass.state.AsyncStateViewModel import io.github.b4tchkn.konnpass.usecase.GetEventsUseCase -import javax.inject.Inject @HiltViewModel(assistedFactory = EventStateViewModelFactory::class) class EventStateViewModel @AssistedInject constructor( diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModelFactory.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModelFactory.kt index 9d88cc4..f45dd2f 100644 --- a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModelFactory.kt +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModelFactory.kt @@ -5,4 +5,4 @@ import dagger.assisted.AssistedFactory @AssistedFactory interface EventStateViewModelFactory { fun create(param: EventStateViewModelParam): EventStateViewModel -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/HomeScreen.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/HomeScreen.kt index f58327b..5cbaff1 100644 --- a/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/HomeScreen.kt +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/ui/screen/HomeScreen.kt @@ -23,7 +23,7 @@ fun HomeScreen( eventStateViewModel: EventStateViewModel = hiltViewModel( creationCallback = { factory: EventStateViewModelFactory -> factory.create(EventStateViewModelParam()) - } + }, ), onEventPressed: (event: EventModel) -> Unit, ) { From 138dffc15ba2539946398e2d4924ca08a3808a4a Mon Sep 17 00:00:00 2001 From: b4tchkn Date: Sat, 2 Mar 2024 18:11:37 +0900 Subject: [PATCH 3/3] fix: move viewmodel init --- .../github/b4tchkn/konnpass/state/AsyncStateViewModel.kt | 6 ------ .../b4tchkn/konnpass/state/event/EventStateViewModel.kt | 8 ++++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/AsyncStateViewModel.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/AsyncStateViewModel.kt index ccd4330..faef168 100644 --- a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/AsyncStateViewModel.kt +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/AsyncStateViewModel.kt @@ -13,12 +13,6 @@ abstract class AsyncStateViewModel : ViewModel() { val state: StateFlow> get() = _state - init { - viewModelScope.launch { - refresh() - } - } - abstract suspend fun fetch(): T suspend fun refresh(loading: LoadingStatus = LoadingStatus.Loading) = runAsync(loading) { diff --git a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt index e5ea068..4390dd3 100644 --- a/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt +++ b/app/src/main/kotlin/io/github/b4tchkn/konnpass/state/event/EventStateViewModel.kt @@ -1,11 +1,13 @@ package io.github.b4tchkn.konnpass.state.event +import androidx.lifecycle.viewModelScope import dagger.assisted.Assisted import dagger.assisted.AssistedInject import dagger.hilt.android.lifecycle.HiltViewModel import io.github.b4tchkn.konnpass.model.EventResponseModel import io.github.b4tchkn.konnpass.state.AsyncStateViewModel import io.github.b4tchkn.konnpass.usecase.GetEventsUseCase +import kotlinx.coroutines.launch @HiltViewModel(assistedFactory = EventStateViewModelFactory::class) class EventStateViewModel @AssistedInject constructor( @@ -13,6 +15,12 @@ class EventStateViewModel @AssistedInject constructor( @Assisted private val param: EventStateViewModelParam, ) : AsyncStateViewModel() { + init { + viewModelScope.launch { + refresh() + } + } + override suspend fun fetch(): EventResponseModel { return useCase( eventId = param.eventId,