Skip to content

Commit

Permalink
feat(mobile-app): Updated files after merging from main branch
Browse files Browse the repository at this point in the history
  • Loading branch information
marlonlom committed Mar 21, 2024
2 parents 6c6ed56 + 2fc8e22 commit 5a8a6a2
Show file tree
Hide file tree
Showing 47 changed files with 1,618 additions and 114 deletions.
2 changes: 1 addition & 1 deletion apps/mobile-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ android {

}
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.kotlin.compose.compiler.get()
kotlinCompilerExtensionVersion = libs.versions.kotlinComposeCompiler.get()
}
packaging {
resources {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import dev.marlonlom.apps.cappajv.core.database.datasource.LocalDataSourceImpl
import dev.marlonlom.apps.cappajv.core.preferences.UserPreferencesRepository
import dev.marlonlom.apps.cappajv.dataStore
import dev.marlonlom.apps.cappajv.features.catalog_list.CatalogListRepository
import dev.marlonlom.apps.cappajv.features.catalog_search.CatalogSearchRepository
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module
import java.util.Locale
Expand All @@ -22,7 +23,8 @@ val dataModule = module {
LocalDataSourceImpl(
catalogItemsDao = db.catalogProductsDao(),
catalogPunctuationsDao = db.catalogPunctuationsDao(),
catalogFavoriteItemsDao = db.catalogFavoriteItemsDao()
catalogFavoriteItemsDao = db.catalogFavoriteItemsDao(),
catalogSearchDao = db.catalogSearchDao(),
)
}
}
Expand All @@ -35,6 +37,11 @@ val dataModule = module {
catalogDataService = get(),
)
}
single<CatalogSearchRepository> {
CatalogSearchRepository(
localDataSource = get(),
)
}
single {
UserPreferencesRepository(androidContext().dataStore)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ package dev.marlonlom.apps.cappajv.di

import dev.marlonlom.apps.cappajv.features.catalog_detail.CatalogDetailViewModel
import dev.marlonlom.apps.cappajv.features.catalog_list.CatalogListViewModel
import dev.marlonlom.apps.cappajv.features.catalog_search.CatalogSearchViewModel
import dev.marlonlom.apps.cappajv.features.settings.SettingsViewModel
import org.koin.androidx.viewmodel.dsl.viewModelOf
import org.koin.dsl.module

val viewModelsModule = module {
includes(dataModule)
viewModelOf(::CatalogListViewModel)
viewModelOf(::CatalogSearchViewModel)
viewModelOf(::CatalogDetailViewModel)
viewModelOf(::SettingsViewModel)
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ fun CatalogListContent(
onCatalogItemSelected: (Long) -> Unit,
) {
when {

(appState.devicePosture is DevicePosture.Separating.Book).and(appState.isCompactHeight.not())
.and(appState.isLandscape.not()) -> {

}

appState.isLandscape.and(appState.devicePosture == DevicePosture.Normal).and(appState.isCompactHeight) -> {
LandscapeCompactCatalogListScreen(
appState = appState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import dev.marlonlom.apps.cappajv.core.database.datasource.LocalDataSource
import dev.marlonlom.apps.cappajv.core.database.entities.CatalogItem
import dev.marlonlom.apps.cappajv.core.database.entities.CatalogPunctuation
import dev.marlonlom.apps.cappajv.ui.util.slug
import dev.marlonlom.apps.cappajv.ui.util.toSentenceCase
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
Expand All @@ -28,6 +27,7 @@ import dev.marlonlom.apps.cappajv.core.catalog_source.CatalogItem as RemoteCatal
*
* @property localDataSource Local data source.
* @property catalogDataService Catalog data service.
* @property coroutineDispatcher Coroutine dispatcher for this repository.
*/
class CatalogListRepository(
private val localDataSource: LocalDataSource,
Expand Down Expand Up @@ -96,7 +96,7 @@ private val RemoteCatalogItem.toEntity: CatalogItem
id = id,
title = title,
slug = title.slug,
titleNormalized = title.toSentenceCase,
titleNormalized = title.slug.replace("-", " "),
picture = picture,
category = category,
detail = detail,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,4 @@ class CatalogListViewModel(
/** UI state object for view model */
val uiState = repository.allProducts.stateIn(viewModelScope, SharingStarted.Eagerly, Loading)

companion object {
fun factory(
repository: CatalogListRepository
): ViewModelProvider.Factory = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return CatalogListViewModel(repository) as T
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ import kotlinx.coroutines.yield
*
* @author marlonlom
*
* @param modifier
* @param appState Application ui state.
* @param modifier Modifier for this composable.
*/
@ExperimentalFoundationApi
@Composable
fun CatalogListBanner(
appState: CappajvAppState, modifier: Modifier = Modifier
appState: CappajvAppState,
modifier: Modifier = Modifier,
) {
val bannerImagesList = listOf(
painterResource(R.drawable.img_catalog_home_banner_01),
Expand Down Expand Up @@ -82,7 +84,7 @@ fun CatalogListBanner(
.fillMaxWidth()
) { page ->
BannerCard(
page = page,
pageIndex = page,
pagerState = pagerState,
bannerImage = bannerImagesList[page],
)
Expand All @@ -98,18 +100,27 @@ fun CatalogListBanner(

}

/**
* Banner card item content composable ui.
*
* @author marlonlom
*
* @param pageIndex Page index for displayed banner.
* @param pagerState Pager ui state for displayed banner.
* @param bannerImage Banner picture painter resource.
*/
@ExperimentalFoundationApi
@Composable
private fun BannerCard(
page: Int,
pageIndex: Int,
pagerState: PagerState,
bannerImage: Painter
) {
Card(
onClick = {},
shape = MaterialTheme.shapes.large,
modifier = Modifier.graphicsLayer {
val pageOffset = pagerState.currentPage.minus(page).plus(pagerState.currentPageOffsetFraction)
val pageOffset = pagerState.currentPage.minus(pageIndex).plus(pagerState.currentPageOffsetFraction)

lerp(
start = 0.85f,
Expand All @@ -136,6 +147,15 @@ private fun BannerCard(
}
}

/**
* Horizontal pager indicator composable ui.
*
* @author marlonlom
*
* @param activeColor Color that indicates the active displayed banner.
* @param pagerState Pager ui state for displayed banner.
* @param modifier Modifier for this composable.
*/
@ExperimentalFoundationApi
@Composable
fun HorizontalPagerIndicator(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2024 Marlonlom
* SPDX-License-Identifier: Apache-2.0
*/

package dev.marlonlom.apps.cappajv.features.catalog_search

import dev.marlonlom.apps.cappajv.core.database.datasource.LocalDataSource

/**
* Catalog search repository.
*
* @author marlonlom
*
* @property localDataSource Local data source.
*/
class CatalogSearchRepository(
private val localDataSource: LocalDataSource,
) {

/**
* Perform search using provided text.
*
* @param searchText Query text.
*/
fun performSearch(searchText: String) = localDataSource.searchProducts("%$searchText%")

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2024 Marlonlom
* SPDX-License-Identifier: Apache-2.0
*/

package dev.marlonlom.apps.cappajv.features.catalog_search

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import dev.marlonlom.apps.cappajv.features.catalog_search.screens.CatalogSearchRouteScreen
import dev.marlonlom.apps.cappajv.ui.main.CappajvAppState
import org.koin.androidx.compose.koinViewModel
import timber.log.Timber

/**
* Catalog search route composable ui.
*
* @author marlonlom
*
* @param appState Application ui state.
* @param viewModel Catalog search viewmodel.
*/
@ExperimentalFoundationApi
@Composable
fun CatalogSearchRoute(
appState: CappajvAppState,
viewModel: CatalogSearchViewModel = koinViewModel(),
) {
val queryText = rememberSaveable { viewModel.queryText }
val showClearIcon = remember {
derivedStateOf { viewModel.queryText.value.isNotEmpty() }
}
val searchResultState by viewModel.searchResult.collectAsStateWithLifecycle()
CatalogSearchRouteScreen(
appState = appState,
queryText = queryText,
showClearIcon = showClearIcon,
onSearchReady = viewModel::onQueryTextChanged,
searchResultUiState = searchResultState,
onSearchedItemClicked = {
Timber.d("[CatalogSearchRoute] clicked item[$it] ")
},
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2024 Marlonlom
* SPDX-License-Identifier: Apache-2.0
*/

package dev.marlonlom.apps.cappajv.features.catalog_search

import dev.marlonlom.apps.cappajv.core.database.entities.CatalogItemTuple

/**
* Catalog search ui state.
*
* @author marlonlom
*/
sealed class CatalogSearchUiState {

/**
* Default catalog search ui state.
*
* @author marlonlom
*
*/
data object None : CatalogSearchUiState()

/**
* Searching phase of catalog search ui state.
*
* @author marlonlom
*
*/
data object Searching : CatalogSearchUiState()

/**
* Empty results phase of catalog search ui state.
*
* @author marlonlom
*
*/
data object Empty : CatalogSearchUiState()

/**
* Success result phase of catalog search ui state.
*
* @author marlonlom
*
* @property results Catalog tuples result list.
*/
data class Success(
val results: List<CatalogItemTuple>
) : CatalogSearchUiState()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2024 Marlonlom
* SPDX-License-Identifier: Apache-2.0
*/

package dev.marlonlom.apps.cappajv.features.catalog_search

import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dev.marlonlom.apps.cappajv.features.catalog_search.CatalogSearchUiState.Empty
import dev.marlonlom.apps.cappajv.features.catalog_search.CatalogSearchUiState.None
import dev.marlonlom.apps.cappajv.features.catalog_search.CatalogSearchUiState.Searching
import dev.marlonlom.apps.cappajv.features.catalog_search.CatalogSearchUiState.Success
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

/**
* Catalog search viewmodel.
*
* @author marlonlom
*
* @property repository Catalog search repository.
*/
class CatalogSearchViewModel(
private val repository: CatalogSearchRepository
) : ViewModel() {
var queryText = mutableStateOf("")
private set

private val _searchResult = MutableStateFlow<CatalogSearchUiState>(None)

val searchResult = _searchResult.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = None
)

/** Handles query text value change. */
fun onQueryTextChanged() {
_searchResult.value = if (queryText.value.isNotEmpty()) Searching else None
if (_searchResult.value is None) return
viewModelScope.launch {
_searchResult.update {
val searchResults = repository.performSearch(queryText.value).first()
if (searchResults.isEmpty()) Empty else Success(searchResults)
}
}
}

}
Loading

0 comments on commit 5a8a6a2

Please sign in to comment.