diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..882ab2a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + +
+ + + + xmlns:android + ^$ + + + +
+
+ + + + xmlns:.* + ^$ + + + BY_NAME + +
+
+ + + + .*:id + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + ^$ + + + +
+
+ + + + style + ^$ + + + +
+
+ + + + .* + ^$ + + + BY_NAME + +
+
+ + + + .* + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + .* + + + BY_NAME + +
+
+
+
+ + +
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index 71c4a7c..ea20fc2 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -1,26 +1,17 @@ - - + - + - - + + - - - - - - - - - - + + \ No newline at end of file diff --git a/.idea/kotlinScripting.xml b/.idea/kotlinScripting.xml new file mode 100644 index 0000000..ea39e51 --- /dev/null +++ b/.idea/kotlinScripting.xml @@ -0,0 +1,9 @@ + + + + + 2147483647 + true + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 7bb6b40..b9847bb 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -6,6 +6,7 @@ + diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/DSL.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/DSL.kt new file mode 100644 index 0000000..ade695b --- /dev/null +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/DSL.kt @@ -0,0 +1,53 @@ +package io.github.mohamedisoliman.pixapay + +import io.github.mohamedisoliman.pixapay.data.entities.ImageModel + + +@DslMarker +annotation class ImageDSL + + +fun image(block: ImageBuilder.() -> Unit): ImageModel = ImageBuilder().apply(block).build() + +@ImageDSL +class ImageBuilder { + var imageId: Long = -1 + var userName: String = "" + var url: String = "" + var likes: String = "" + var downloads: String = "" + var comments: String = "" + private var tags: MutableList = mutableListOf() + var largeImageURL: String? = "" + + fun tag(block: ImageBuilder.() -> String) { + tags.add(block()) + } + + fun build(): ImageModel = ImageModel( + imageId = imageId, + userName = userName, + url = url, + likes = likes, + downloads = downloads, + comments = comments, + tags = tags, + largeImageURL = largeImageURL + ) +} + +fun main() { + val image = image { + comments = "20" + downloads = "30" + tag { "Nature" } + tag { "People" } + tag { + comments = "40" + "Travel" + + } + } + + print(image) +} \ No newline at end of file diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/MVI.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/MVI.kt new file mode 100644 index 0000000..d422e0a --- /dev/null +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/MVI.kt @@ -0,0 +1,5 @@ +package io.github.mohamedisoliman.pixapay + +interface UiEvent + +interface UiState \ No newline at end of file diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/data/ImagesRepository.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/data/ImagesRepository.kt index 58e49e0..26695f4 100644 --- a/app/src/main/java/io/github/mohamedisoliman/pixapay/data/ImagesRepository.kt +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/data/ImagesRepository.kt @@ -3,6 +3,7 @@ package io.github.mohamedisoliman.pixapay.data import io.github.mohamedisoliman.pixapay.data.entities.PixabayImage import io.github.mohamedisoliman.pixapay.data.local.LocalPixabayStoreContract import io.github.mohamedisoliman.pixapay.data.remote.RemotePixabayContract +import io.github.mohamedisoliman.pixapay.domain.search.ImagesRepositoryContract import kotlinx.coroutines.flow.* import timber.log.Timber import javax.inject.Inject diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/data/entities/ImageModel.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/data/entities/ImageModel.kt index 31ff0d7..25e1ceb 100644 --- a/app/src/main/java/io/github/mohamedisoliman/pixapay/data/entities/ImageModel.kt +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/data/entities/ImageModel.kt @@ -2,11 +2,11 @@ package io.github.mohamedisoliman.pixapay.data.entities data class ImageModel( val imageId: Long = -1, - val userName: String, - val url: String, - val likes: String, - val downloads: String, - val comments: String, - val tags: List, - val largeImageURL: String?, + val userName: String = "", + val url: String = "", + val likes: String = "", + val downloads: String = "", + val comments: String = "", + val tags: List = emptyList(), + val largeImageURL: String? = "", ) \ No newline at end of file diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/di/AppModule.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/di/AppModule.kt index 91c1d7b..182f039 100644 --- a/app/src/main/java/io/github/mohamedisoliman/pixapay/di/AppModule.kt +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/di/AppModule.kt @@ -7,7 +7,7 @@ import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import io.github.mohamedisoliman.pixapay.data.ImagesRepository -import io.github.mohamedisoliman.pixapay.data.ImagesRepositoryContract +import io.github.mohamedisoliman.pixapay.domain.search.ImagesRepositoryContract import io.github.mohamedisoliman.pixapay.data.local.* import io.github.mohamedisoliman.pixapay.data.remote.RemotePixabayContract import io.github.mohamedisoliman.pixapay.data.remote.pixabayApi diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/di/SearchViewModelDi.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/di/SearchViewModelDi.kt new file mode 100644 index 0000000..c4aeb03 --- /dev/null +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/di/SearchViewModelDi.kt @@ -0,0 +1,26 @@ +package io.github.mohamedisoliman.pixapay.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ViewModelComponent +import dagger.hilt.android.scopes.ViewModelScoped +import io.github.mohamedisoliman.pixapay.domain.search.SearchState +import io.github.mohamedisoliman.pixapay.ui.search.SearchScreenEvent +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow + + +@Module +@InstallIn(ViewModelComponent::class) +internal object ViewModelSearchModule { + + @Provides + @ViewModelScoped + fun providesEventsFlow(): MutableSharedFlow = MutableSharedFlow() + + + @Provides + @ViewModelScoped + fun providesStatesFlow(): MutableStateFlow = MutableStateFlow(SearchState.IDLE()) +} \ No newline at end of file diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/SearchUsecase.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/SearchUsecase.kt deleted file mode 100644 index 34aa301..0000000 --- a/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/SearchUsecase.kt +++ /dev/null @@ -1,28 +0,0 @@ -package io.github.mohamedisoliman.pixapay.domain - -import io.github.mohamedisoliman.pixapay.data.ImagesRepositoryContract -import io.github.mohamedisoliman.pixapay.data.entities.toImageModel -import io.github.mohamedisoliman.pixapay.data.entities.ImageModel -import kotlinx.coroutines.flow.* -import javax.inject.Inject - -class SearchUsecase @Inject constructor( - private val imagesRepository: ImagesRepositoryContract, -) { - - operator fun invoke(query: String): Flow { - return imagesRepository.search(query) - .map { list -> list.map { it.toImageModel() } } - .map { if (it.isEmpty()) SearchState.Empty else SearchState.Success(it) } - .onStart { emit(SearchState.Loading) } - .catch { emit(SearchState.Error(it)) } - } - -} - -sealed class SearchState { - object Empty : SearchState() - class Success(val images: List) : SearchState() - class Error(val throwable: Throwable) : SearchState() - object Loading : SearchState() -} \ No newline at end of file diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/data/ImagesRepositoryContract.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/search/ImagesRepositoryContract.kt similarity index 78% rename from app/src/main/java/io/github/mohamedisoliman/pixapay/data/ImagesRepositoryContract.kt rename to app/src/main/java/io/github/mohamedisoliman/pixapay/domain/search/ImagesRepositoryContract.kt index 879062d..00208e4 100644 --- a/app/src/main/java/io/github/mohamedisoliman/pixapay/data/ImagesRepositoryContract.kt +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/search/ImagesRepositoryContract.kt @@ -1,4 +1,4 @@ -package io.github.mohamedisoliman.pixapay.data +package io.github.mohamedisoliman.pixapay.domain.search import io.github.mohamedisoliman.pixapay.data.entities.PixabayImage import kotlinx.coroutines.flow.Flow diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/search/SearchState.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/search/SearchState.kt new file mode 100644 index 0000000..01e9e5e --- /dev/null +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/search/SearchState.kt @@ -0,0 +1,29 @@ +package io.github.mohamedisoliman.pixapay.domain.search + +import io.github.mohamedisoliman.pixapay.UiState +import io.github.mohamedisoliman.pixapay.data.entities.ImageModel + +sealed class SearchState( + val isLoading: Boolean = false, + val result: List? = null, + val searchText: String? = null, + val throwable: Throwable? = null, +) : UiState { + + class IDLE(searchText: String? = "") : SearchState(searchText = searchText) + + class EmptyResult(searchText: String?) : SearchState(searchText = searchText) + + class Loading(searchText: String?) : SearchState(searchText = searchText, isLoading = true) + + class Success( + result: List?, + searchText: String?, + ) : SearchState(result = result, searchText = searchText) + + class Error( + searchText: String? = null, + throwable: Throwable? = null, + ) : SearchState(searchText = searchText, throwable = throwable) + +} \ No newline at end of file diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/search/SearchUsecase.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/search/SearchUsecase.kt new file mode 100644 index 0000000..b24a078 --- /dev/null +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/domain/search/SearchUsecase.kt @@ -0,0 +1,27 @@ +package io.github.mohamedisoliman.pixapay.domain.search + +import io.github.mohamedisoliman.pixapay.data.entities.toImageModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart +import javax.inject.Inject + +class SearchUsecase @Inject constructor( + private val imagesRepository: ImagesRepositoryContract, +) { + + operator fun invoke(query: String): Flow { + return imagesRepository.search(query) + .map { list -> list.map { it.toImageModel() } } + .map { + if (it.isEmpty()) + SearchState.EmptyResult(query) + else + SearchState.Success(searchText = query, result = it) + }.onStart { emit(SearchState.Loading(query)) } + .catch { emit(SearchState.Error(searchText = query, it)) } + } + +} + diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/navigation.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/navigation.kt index ecf6990..b581c5e 100644 --- a/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/navigation.kt +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/navigation.kt @@ -14,8 +14,10 @@ import io.github.mohamedisoliman.pixapay.R import io.github.mohamedisoliman.pixapay.ui.image_details.ImageDetailsScreen import io.github.mohamedisoliman.pixapay.ui.search.SearchImagesViewModel import io.github.mohamedisoliman.pixapay.ui.search.SearchScreen +import kotlinx.coroutines.ExperimentalCoroutinesApi +@OptIn(ExperimentalCoroutinesApi::class) @Composable fun AppNavigation( modifier: Modifier = Modifier, @@ -23,6 +25,9 @@ fun AppNavigation( ) { val viewModel: SearchImagesViewModel = hiltViewModel() + viewModel.navigateToDetails = { + navController.navigate("${Screen.ImageDetails.route}/${it}") + } NavHost( navController = navController, @@ -31,9 +36,7 @@ fun AppNavigation( ) { composable(Screen.Search.route) { - SearchScreen(viewModel) { - navController.navigate("${Screen.ImageDetails.route}/${it}") - } + SearchScreen(viewModel) } composable( diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchImagesViewModel.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchImagesViewModel.kt index eb3785e..9810bde 100644 --- a/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchImagesViewModel.kt +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchImagesViewModel.kt @@ -3,47 +3,75 @@ package io.github.mohamedisoliman.pixapay.ui.search import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import io.github.mohamedisoliman.pixapay.domain.SearchState -import io.github.mohamedisoliman.pixapay.domain.SearchState.* -import io.github.mohamedisoliman.pixapay.domain.SearchUsecase import io.github.mohamedisoliman.pixapay.data.entities.ImageModel +import io.github.mohamedisoliman.pixapay.domain.search.SearchState +import io.github.mohamedisoliman.pixapay.domain.search.SearchUsecase import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class SearchImagesViewModel @Inject constructor( - val searchUsecase: SearchUsecase, + private val searchUsecase: SearchUsecase, + private val _states: MutableStateFlow, ) : ViewModel() { - private var _searchViewState = MutableStateFlow(Empty) - val searchViewState: StateFlow = _searchViewState - - private var _searchQueryState = MutableStateFlow("fruits") - val searchQueryState: StateFlow = _searchQueryState + val states = _states.asStateFlow() + private val _queryState = MutableStateFlow("fruits") + val query by lazy { _queryState.asStateFlow() } + private val _searchClick = MutableSharedFlow() + lateinit var navigateToDetails: (Long) -> Unit init { + subscribeToEvents() onSearchClicked() } - fun search(query: String) { - searchUsecase(query = query) - .onEach { _searchViewState.value = it } + + private fun subscribeToEvents() { + merge( + searchCurrentQuery(), + searchWhileTyping(), + updateUiSearchText() + ) + .flatMapMerge { it.toUsecase() } + .onEach { _states.value = it } .launchIn(viewModelScope) + } - fun onSearchChange(searchText: String) { - _searchQueryState.value = searchText + fun onSearchClicked() { + viewModelScope.launch { _searchClick.emit(_queryState.value) } } - fun findImage(id: Long): ImageModel? = - (_searchViewState.value as? Success)?.images?.find { it.imageId == id } + fun onSearchQueryChange(query: String) { + viewModelScope.launch { _queryState.emit(query) } + } + + fun findImage(id: Long): ImageModel? = _states.value.result?.find { it.imageId == id } - fun onSearchClicked() { - search(_searchQueryState.value) + private fun SearchScreenEvent.toUsecase(): Flow = when (this) { + is SearchClicked -> searchUsecase(this.query) + is SearchQueryChanged -> searchUsecase(this.query) + is SearchQueryUpdated -> flowOf(SearchState.IDLE(searchText = this.query)) } + private fun updateUiSearchText() = + _queryState.asSharedFlow() + .map { SearchQueryUpdated(it) } + + private fun searchWhileTyping() = + _queryState.asSharedFlow() + .map { SearchQueryChanged(it) } + .debounce(700) + + private fun searchCurrentQuery() = + _searchClick.asSharedFlow() + .map { SearchClicked(it) } + .onStart { SearchClicked("fruits") } + } diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchScreen.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchScreen.kt index 814c7d0..f04ce87 100644 --- a/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchScreen.kt +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchScreen.kt @@ -29,41 +29,79 @@ import androidx.compose.ui.unit.dp import coil.annotation.ExperimentalCoilApi import coil.compose.rememberImagePainter import io.github.mohamedisoliman.pixapay.R -import io.github.mohamedisoliman.pixapay.domain.SearchState -import io.github.mohamedisoliman.pixapay.domain.SearchState.* +import io.github.mohamedisoliman.pixapay.UiState +import io.github.mohamedisoliman.pixapay.data.entities.ImageModel +import io.github.mohamedisoliman.pixapay.domain.search.SearchState import io.github.mohamedisoliman.pixapay.ui.common.ImageChips import io.github.mohamedisoliman.pixapay.ui.common.isPortrait import io.github.mohamedisoliman.pixapay.ui.common.toUiModel -import io.github.mohamedisoliman.pixapay.data.entities.ImageModel +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview @Preview @Composable fun PreviewSearch() { - SearchScreenContent(searchState = Empty) + SearchScreenContent() } +@OptIn(FlowPreview::class) +@ExperimentalCoroutinesApi @Composable -fun SearchScreen(viewModel: SearchImagesViewModel, onNavigateClicked: (Long) -> Unit = { }) { - val viewState by viewModel.searchViewState.collectAsState() - val query by viewModel.searchQueryState.collectAsState() +fun SearchScreen(viewModel: SearchImagesViewModel) { + val viewState by viewModel.states.collectAsState() + var showDialog by remember { mutableStateOf(false) } + var imageId by remember { mutableStateOf(-1L) } SearchScreenContent( - onImageClicked = onNavigateClicked, - searchText = query, - searchState = viewState, - onSearchChange = { viewModel.onSearchChange(it) }, - onSearchClicked = { viewModel.onSearchClicked() } + searchText = viewModel.query.value, + searchMainView = { + viewState.StateToMainView(showDialog = { + showDialog = it + }, imageId = { + imageId = it + }) + + }, + onSearchChange = { viewModel.onSearchQueryChange(it) }, + onSearchClicked = { viewModel.onSearchClicked() }, + isLoading = viewState.isLoading ) + + ConfirmationDialog(showDialog = showDialog, onConfirm = { + showDialog = false + viewModel.navigateToDetails(imageId) + }) { + showDialog = false + } +} + +@Composable +private fun UiState.StateToMainView( + imageId: (Long) -> Unit, + showDialog: (Boolean) -> Unit, +) { + when (this) { + is SearchState.EmptyResult -> EmptyView() + is SearchState.Error -> this.throwable?.let { ErrorView(it) } + is SearchState.Success -> this.result?.let { list -> + ImageListView(list) { + imageId(it) + showDialog(true) + } + } + else -> { + } + } } @Composable fun ConfirmationDialog( - showDialog: Boolean, + showDialog: Boolean = false, onConfirm: () -> Unit, onDismiss: () -> Unit, ) { - if (showDialog) { + if (showDialog) AlertDialog( modifier = Modifier.fillMaxWidth(), title = { Text(stringResource(R.string.dialog_title_open_image_details)) }, @@ -86,55 +124,37 @@ fun ConfirmationDialog( } } ) - } } @OptIn(ExperimentalComposeUiApi::class) @Composable private fun SearchScreenContent( searchText: String = "", + isLoading: Boolean = false, onSearchChange: (String) -> Unit = {}, onSearchClicked: () -> Unit = {}, - searchState: SearchState = Empty, - onImageClicked: (Long) -> Unit = {}, + searchMainView: @Composable () -> Unit = {}, ) { - var showDialog by remember { mutableStateOf(false) } - var imageId by remember { mutableStateOf(-1L) } - Box( modifier = Modifier.padding(top = 8.dp, start = 8.dp, end = 8.dp), contentAlignment = Alignment.TopCenter ) { - when (searchState) { - is Success -> ImageListView(searchState.images) { - imageId = it - showDialog = true - } - is Empty -> EmptyView(modifier = Modifier.align(Alignment.Center)) - is Error -> ErrorView(searchState.throwable) - } + searchMainView() SearchTopbar( searchText = searchText, onSearchChange = onSearchChange, onSearchClicked = onSearchClicked, - isLoading = searchState is Loading, + isLoading = isLoading, ) } - ConfirmationDialog(showDialog = showDialog, onConfirm = { - showDialog = false - onImageClicked(imageId) - }) { - showDialog = false - } - } @Composable -private fun EmptyView(modifier: Modifier) { +fun EmptyView(modifier: Modifier = Modifier) { PlaceHolderView( modifier = modifier, icon = Icons.Outlined.Pets, @@ -188,7 +208,7 @@ fun ErrorView( @OptIn(ExperimentalFoundationApi::class) @Composable -private fun ImageListView( +fun ImageListView( images: List, onImageClicked: (Long) -> Unit, ) { diff --git a/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchScreenEvent.kt b/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchScreenEvent.kt new file mode 100644 index 0000000..1fa7735 --- /dev/null +++ b/app/src/main/java/io/github/mohamedisoliman/pixapay/ui/search/SearchScreenEvent.kt @@ -0,0 +1,15 @@ +package io.github.mohamedisoliman.pixapay.ui.search + +import io.github.mohamedisoliman.pixapay.UiEvent + + +sealed class SearchScreenEvent : UiEvent + +data class SearchClicked(val query: String) : SearchScreenEvent() + +data class SearchQueryChanged(val query: String) : SearchScreenEvent() + +data class SearchQueryUpdated(val query: String) : SearchScreenEvent() + + + diff --git a/app/src/test/java/io/github/mohamedisoliman/pixapay/domain/SearchUsecaseTest.kt b/app/src/test/java/io/github/mohamedisoliman/pixapay/domain/SearchUsecaseTest.kt index b877e69..7c73f23 100644 --- a/app/src/test/java/io/github/mohamedisoliman/pixapay/domain/SearchUsecaseTest.kt +++ b/app/src/test/java/io/github/mohamedisoliman/pixapay/domain/SearchUsecaseTest.kt @@ -1,7 +1,9 @@ package io.github.mohamedisoliman.pixapay.domain -import io.github.mohamedisoliman.pixapay.data.ImagesRepositoryContract +import io.github.mohamedisoliman.pixapay.domain.search.ImagesRepositoryContract import io.github.mohamedisoliman.pixapay.data.entities.PixabayImage +import io.github.mohamedisoliman.pixapay.domain.search.SearchState +import io.github.mohamedisoliman.pixapay.domain.search.SearchUsecase import io.mockk.mockk import kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking @@ -12,13 +14,13 @@ class SearchUsecaseTest { @Test - fun `search() Then start Loading`() = runBlocking { + fun `search() THEN start with Loading state`() = runBlocking { val hit = mockk() val repository = mockRepository(flowOf(listOf(hit, hit, hit))) val result = SearchUsecase(repository).invoke("flowers").first() - assert((result is SearchState.Loading)) + assert(result is SearchState.Loading) } @Test @@ -39,7 +41,7 @@ class SearchUsecaseTest { val result = SearchUsecase(repository).invoke("flowers").last() - assert((result is SearchState.Empty)) + assert((result is SearchState.EmptyResult)) } @Test @@ -51,7 +53,7 @@ class SearchUsecaseTest { val result = SearchUsecase(repository).invoke("flowers").last() - assert((result is SearchState.Success) && result.images.size == 3) + assert((result is SearchState.Success) && result.result?.size == 3) }