Implemented AssistedInject for details screen
This commit is contained in:
parent
08da2cbbe0
commit
aab5f5e0de
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
Pixabay
|
6
.idea/compiler.xml
generated
Normal file
6
.idea/compiler.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<bytecodeTargetLevel target="17" />
|
||||||
|
</component>
|
||||||
|
</project>
|
18
.idea/deploymentTargetSelector.xml
generated
Normal file
18
.idea/deploymentTargetSelector.xml
generated
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="deploymentTargetSelector">
|
||||||
|
<selectionStates>
|
||||||
|
<SelectionState runConfigName="app">
|
||||||
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
|
<DropdownSelection timestamp="2024-07-26T12:17:16.367108Z">
|
||||||
|
<Target type="DEFAULT_BOOT">
|
||||||
|
<handle>
|
||||||
|
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/adriankuta/.android/avd/Pixel_8_API_34.avd" />
|
||||||
|
</handle>
|
||||||
|
</Target>
|
||||||
|
</DropdownSelection>
|
||||||
|
<DialogSelection />
|
||||||
|
</SelectionState>
|
||||||
|
</selectionStates>
|
||||||
|
</component>
|
||||||
|
</project>
|
39
.idea/gradle.xml
generated
Normal file
39
.idea/gradle.xml
generated
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||||
|
<component name="GradleSettings">
|
||||||
|
<option name="linkedExternalProjectsSettings">
|
||||||
|
<GradleProjectSettings>
|
||||||
|
<compositeConfiguration>
|
||||||
|
<compositeBuild compositeDefinitionSource="SCRIPT">
|
||||||
|
<builds>
|
||||||
|
<build path="$PROJECT_DIR$/build-logic" name="build-logic">
|
||||||
|
<projects>
|
||||||
|
<project path="$PROJECT_DIR$/build-logic" />
|
||||||
|
<project path="$PROJECT_DIR$/build-logic/convention" />
|
||||||
|
</projects>
|
||||||
|
</build>
|
||||||
|
</builds>
|
||||||
|
</compositeBuild>
|
||||||
|
</compositeConfiguration>
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
||||||
|
<option name="modules">
|
||||||
|
<set>
|
||||||
|
<option value="$PROJECT_DIR$" />
|
||||||
|
<option value="$PROJECT_DIR$/app" />
|
||||||
|
<option value="$PROJECT_DIR$/build-logic" />
|
||||||
|
<option value="$PROJECT_DIR$/build-logic/convention" />
|
||||||
|
<option value="$PROJECT_DIR$/core" />
|
||||||
|
<option value="$PROJECT_DIR$/core/ui" />
|
||||||
|
<option value="$PROJECT_DIR$/data" />
|
||||||
|
<option value="$PROJECT_DIR$/feature" />
|
||||||
|
<option value="$PROJECT_DIR$/feature/details" />
|
||||||
|
<option value="$PROJECT_DIR$/feature/search" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
<option name="resolveExternalAnnotations" value="false" />
|
||||||
|
</GradleProjectSettings>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
53
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
53
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="ComposePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ComposePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ComposePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ComposePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
6
.idea/kotlinc.xml
generated
Normal file
6
.idea/kotlinc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="KotlinJpsPluginSettings">
|
||||||
|
<option name="version" value="1.9.24" />
|
||||||
|
</component>
|
||||||
|
</project>
|
10
.idea/migrations.xml
generated
Normal file
10
.idea/migrations.xml
generated
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectMigrations">
|
||||||
|
<option name="MigrateToGradleLocalJavaHome">
|
||||||
|
<set>
|
||||||
|
<option value="$PROJECT_DIR$" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
10
.idea/misc.xml
generated
Normal file
10
.idea/misc.xml
generated
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectType">
|
||||||
|
<option name="id" value="Android" />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
1
build-logic/.gitignore
vendored
Normal file
1
build-logic/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.gradle/
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,2 +0,0 @@
|
|||||||
#Wed Jul 24 13:11:02 CEST 2024
|
|
||||||
gradle.version=8.7
|
|
Binary file not shown.
Binary file not shown.
@ -23,6 +23,7 @@ fun SearchField(
|
|||||||
value = query,
|
value = query,
|
||||||
onValueChange = onQueryChange,
|
onValueChange = onQueryChange,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
maxLines = 1,
|
||||||
placeholder = {
|
placeholder = {
|
||||||
if (hint != null) {
|
if (hint != null) {
|
||||||
Text(text = hint)
|
Text(text = hint)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import java.util.Properties
|
||||||
|
|
||||||
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
|
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.convention.android.library)
|
alias(libs.plugins.convention.android.library)
|
||||||
@ -9,10 +11,15 @@ android {
|
|||||||
buildFeatures {
|
buildFeatures {
|
||||||
buildConfig = true
|
buildConfig = true
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
buildConfigField("String", "PIXABAY_API_KEY", "\"<REPLACE_WITH_PIXABAY_API_KEY>\"")
|
val localPropertiesFile = project.rootProject.file("local.properties")
|
||||||
|
val properties = Properties()
|
||||||
|
properties.load(localPropertiesFile.inputStream())
|
||||||
|
|
||||||
|
val apiKey = properties.getProperty("PIXABAY_API_KEY") ?: ""
|
||||||
|
buildConfigField("String", "PIXABAY_API_KEY", "\"$apiKey\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -9,10 +9,13 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import dev.adriankuta.pixabay.data.room.AppDatabase
|
import dev.adriankuta.pixabay.data.room.AppDatabase
|
||||||
import dev.adriankuta.pixabay.data.room.dao.PixabayImagesDao
|
import dev.adriankuta.pixabay.data.room.dao.PixabayImagesDao
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
@Module
|
@Module
|
||||||
internal class PersistanceModule {
|
internal class PersistanceModule {
|
||||||
|
|
||||||
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideRoomDb(@ApplicationContext context: Context): AppDatabase {
|
fun provideRoomDb(@ApplicationContext context: Context): AppDatabase {
|
||||||
return Room.databaseBuilder(
|
return Room.databaseBuilder(
|
||||||
|
@ -75,6 +75,6 @@ internal class PixabayImageRepository @Inject constructor(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val NETWORK_PAGE_SIZE = 30
|
const val NETWORK_PAGE_SIZE = 30
|
||||||
const val USE_CACHE_PAGER = false
|
const val USE_CACHE_PAGER = true
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,7 +14,6 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@ -34,6 +33,7 @@ import dev.adriankuta.pixabay.core.ui.R.drawable
|
|||||||
import dev.adriankuta.pixabay.core.ui.R.string
|
import dev.adriankuta.pixabay.core.ui.R.string
|
||||||
import dev.adriankuta.pixabay.core.ui.StatsItem
|
import dev.adriankuta.pixabay.core.ui.StatsItem
|
||||||
import dev.adriankuta.pixabay.data.model.PixabayImage
|
import dev.adriankuta.pixabay.data.model.PixabayImage
|
||||||
|
import dev.adriankuta.pixabay.feature.details.di.PhotoDetailsViewModelFactory
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -41,15 +41,15 @@ fun PhotoDetailRoute(
|
|||||||
photoId: Int,
|
photoId: Int,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: PhotoDetailViewModel = hiltViewModel()
|
viewModel: PhotoDetailViewModel = hiltViewModel(
|
||||||
|
creationCallback = { factory: PhotoDetailsViewModelFactory ->
|
||||||
|
factory.create(photoId)
|
||||||
|
}
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val uiState by viewModel.uiState.collectAsState()
|
val uiState by viewModel.uiState.collectAsState()
|
||||||
|
|
||||||
LaunchedEffect(photoId) {
|
|
||||||
viewModel.loadImage(photoId)
|
|
||||||
}
|
|
||||||
|
|
||||||
PhotoDetailScreen(
|
PhotoDetailScreen(
|
||||||
state = uiState,
|
state = uiState,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
@ -1,30 +1,25 @@
|
|||||||
@file:OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
|
|
||||||
package dev.adriankuta.pixabay.feature.details
|
package dev.adriankuta.pixabay.feature.details
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dev.adriankuta.pixabay.data.repository.ImageRepository
|
import dev.adriankuta.pixabay.data.repository.ImageRepository
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import dev.adriankuta.pixabay.feature.details.di.PhotoDetailsViewModelFactory
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel(assistedFactory = PhotoDetailsViewModelFactory::class)
|
||||||
class PhotoDetailViewModel @Inject constructor(
|
class PhotoDetailViewModel @AssistedInject constructor(
|
||||||
private val imageRepository: ImageRepository
|
private val imageRepository: ImageRepository,
|
||||||
|
@Assisted private val imageId: Int
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _idToLoad = MutableStateFlow<Int?>(null)
|
private val loadedData = flow {
|
||||||
|
emit(imageRepository.searchImageById(imageId))
|
||||||
private val loadedData = _idToLoad
|
|
||||||
.filterNotNull()
|
|
||||||
.map { id ->
|
|
||||||
imageRepository.searchImageById(id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val uiState = loadedData
|
val uiState = loadedData
|
||||||
@ -34,9 +29,4 @@ class PhotoDetailViewModel @Inject constructor(
|
|||||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5000),
|
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5000),
|
||||||
initialValue = PhotoDetailUiState.Loading
|
initialValue = PhotoDetailUiState.Loading
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
fun loadImage(id: Int) {
|
|
||||||
_idToLoad.value = id
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package dev.adriankuta.pixabay.feature.details.di
|
||||||
|
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dev.adriankuta.pixabay.feature.details.PhotoDetailViewModel
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
internal interface PhotoDetailsViewModelFactory {
|
||||||
|
fun create(imageId: Int): PhotoDetailViewModel
|
||||||
|
}
|
@ -1,13 +1,13 @@
|
|||||||
[versions]
|
[versions]
|
||||||
androidxNavigation = "2.7.7"
|
androidxNavigation = "2.7.7"
|
||||||
androidGradlePlugin = "8.1.4"
|
androidGradlePlugin = "8.1.4"
|
||||||
agp = "8.6.0-beta01"
|
agp = "8.6.0-beta02"
|
||||||
coilCompose = "2.6.0"
|
coilCompose = "2.6.0"
|
||||||
composeCompiler = "1.5.14"
|
composeCompiler = "1.5.14"
|
||||||
kotlin = "1.9.24"
|
kotlin = "1.9.24"
|
||||||
kotlinSerialization = "2.0.0"
|
kotlinSerialization = "2.0.0"
|
||||||
coreKtx = "1.13.1"
|
coreKtx = "1.13.1"
|
||||||
androidxHilt = "1.0.0"
|
androidxHilt = "1.2.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.2.1"
|
junitVersion = "1.2.1"
|
||||||
espressoCore = "3.6.1"
|
espressoCore = "3.6.1"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user