Skip to content

Commit

Permalink
Merge pull request #190 from DeKaN/product-list-compose
Browse files Browse the repository at this point in the history
Migrate product list to Jetpack Compose
  • Loading branch information
hieuwu authored Oct 5, 2023
2 parents c8e8fd9 + 7fd31bd commit 162d271
Show file tree
Hide file tree
Showing 27 changed files with 530 additions and 218 deletions.
6 changes: 4 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ plugins {
apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 33
compileSdk 34
buildToolsVersion "31.0.0"

defaultConfig {
Expand Down Expand Up @@ -88,6 +88,8 @@ dependencies {
implementation libs.gson
implementation libs.moshi
implementation libs.kotlin.coroutines.play.services
implementation(libs.kotlinx.immutable)
implementation(libs.glide.compose)

implementation platform(libs.firebase.bom)
implementation libs.bundles.firebase
Expand All @@ -101,7 +103,7 @@ dependencies {
implementation "io.ktor:ktor-client-logging-jvm:1.6.0"
implementation("io.ktor:ktor-client-core:2.2.4")

def composeBom = platform('androidx.compose:compose-bom:2023.05.00')
def composeBom = platform('androidx.compose:compose-bom:2023.09.02')
implementation(composeBom)
androidTestImplementation(composeBom)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package com.hieuwu.groceriesstore.domain.usecases

import com.hieuwu.groceriesstore.data.database.entities.LineItem

interface AddToCartUseCase: UseCase<AddToCartUseCase.Input, AddToCartUseCase.Output> {
interface AddToCartUseCase: SuspendUseCase<AddToCartUseCase.Input, AddToCartUseCase.Output> {
class Input (val lineItem: LineItem)

class Output
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package com.hieuwu.groceriesstore.domain.usecases
import com.hieuwu.groceriesstore.data.database.entities.Order

interface CreateNewOrderUseCase :
UseCase<CreateNewOrderUseCase.Input, CreateNewOrderUseCase.Output> {
SuspendUseCase<CreateNewOrderUseCase.Input, CreateNewOrderUseCase.Output> {
class Input(val order: Order)

class Output(result: Unit)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import com.hieuwu.groceriesstore.domain.models.CategoryModel
import kotlinx.coroutines.flow.Flow

interface GetCategoriesListUseCase :
UseCase<GetCategoriesListUseCase.Input, GetCategoriesListUseCase.Output> {
SuspendUseCase<GetCategoriesListUseCase.Input, GetCategoriesListUseCase.Output> {
class Input

class Output(val result: Flow<List<CategoryModel>>)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.hieuwu.groceriesstore.domain.models.OrderModel
import kotlinx.coroutines.flow.Flow

interface GetCurrentCartUseCase :
UseCase<GetCurrentCartUseCase.Input, GetCurrentCartUseCase.Output> {
SuspendUseCase<GetCurrentCartUseCase.Input, GetCurrentCartUseCase.Output> {
class Input
data class Output(val result: Flow<OrderModel?>)
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.hieuwu.groceriesstore.domain.usecases

import com.hieuwu.groceriesstore.domain.models.OrderModel
import kotlinx.coroutines.flow.Flow

interface GetOrderListUseCase : UseCase<GetOrderListUseCase.Input, GetOrderListUseCase.Output> {
interface GetOrderListUseCase : SuspendUseCase<GetOrderListUseCase.Input, GetOrderListUseCase.Output> {
class Input
sealed class Output {
class Success(val data: List<OrderModel>) : Output()
object Failure : Output()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ import kotlinx.coroutines.flow.Flow
interface GetProductsListUseCase: UseCase<GetProductsListUseCase.Input, GetProductsListUseCase.Output> {
class Input
class Output(val result: Flow<List<ProductModel>>)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.hieuwu.groceriesstore.domain.usecases
import com.hieuwu.groceriesstore.domain.models.UserModel
import kotlinx.coroutines.flow.Flow

interface GetProfileUseCase:UseCase<GetProfileUseCase.Input, GetProfileUseCase.Output> {
interface GetProfileUseCase:SuspendUseCase<GetProfileUseCase.Input, GetProfileUseCase.Output> {
class Input
open class Output(val result: Flow<UserModel?>)
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package com.hieuwu.groceriesstore.domain.usecases

interface RefreshAppDataUseCase : UseCase<Unit, Unit>
interface RefreshAppDataUseCase : SuspendUseCase<Unit, Unit>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.hieuwu.groceriesstore.domain.usecases
import com.hieuwu.groceriesstore.domain.models.ProductModel
import kotlinx.coroutines.flow.Flow

interface SearchProductUseCase : UseCase<SearchProductUseCase.Input, SearchProductUseCase.Output> {
interface SearchProductUseCase : SuspendUseCase<SearchProductUseCase.Input, SearchProductUseCase.Output> {
class Input(val name: String? = null)
class Output(val result: Flow<List<ProductModel>>)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.hieuwu.groceriesstore.domain.usecases

interface SignInUseCase : UseCase<SignInUseCase.Input, SignInUseCase.Output> {
interface SignInUseCase : SuspendUseCase<SignInUseCase.Input, SignInUseCase.Output> {
data class Input(val email: String, val password: String)
open class Output(val result: Boolean) {
sealed class Error : Output(false)
object AccountNotExistedError : Output(false)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.hieuwu.groceriesstore.domain.usecases

interface SignOutUseCase : UseCase<SignOutUseCase.Input, SignOutUseCase.Output> {
interface SignOutUseCase : SuspendUseCase<SignOutUseCase.Input, SignOutUseCase.Output> {
class Input
class Output
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.hieuwu.groceriesstore.domain.usecases

import com.hieuwu.groceriesstore.domain.models.OrderModel

interface SubmitOrderUseCase : UseCase<SubmitOrderUseCase.Input, SubmitOrderUseCase.Output> {
interface SubmitOrderUseCase : SuspendUseCase<SubmitOrderUseCase.Input, SubmitOrderUseCase.Output> {
class Input(val order: OrderModel)
data class Output(val result: Boolean)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.hieuwu.groceriesstore.domain.usecases

interface UpdateProfileUseCase : UseCase<UpdateProfileUseCase.Input, UpdateProfileUseCase.Output> {
interface UpdateProfileUseCase : SuspendUseCase<UpdateProfileUseCase.Input, UpdateProfileUseCase.Output> {
data class Input(
val userId: String,
val name: String,
Expand All @@ -9,4 +9,4 @@ interface UpdateProfileUseCase : UseCase<UpdateProfileUseCase.Input, UpdateProfi
val address: String
)
class Output
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.hieuwu.groceriesstore.domain.usecases

interface UseCase<Input, Output> {
interface SuspendUseCase<Input, Output> {
suspend fun execute(input: Input): Output
}
}

interface UseCase<Input, Output> {
fun execute(input: Input): Output
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.hieuwu.groceriesstore.domain.usecases

interface UserSettingsUseCase : UseCase<UserSettingsUseCase.Input, UserSettingsUseCase.Output> {
interface UserSettingsUseCase : SuspendUseCase<UserSettingsUseCase.Input, UserSettingsUseCase.Output> {
class Input(
val id: String,
val isOrderCreatedEnabled: Boolean,
Expand All @@ -9,4 +9,4 @@ interface UserSettingsUseCase : UseCase<UserSettingsUseCase.Input, UserSettingsU
)

class Output
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ import javax.inject.Inject

class GetProductsByCategoryUseCaseImpl @Inject constructor(private val productRepository: ProductRepository) :
GetProductsByCategoryUseCase {
override suspend fun execute(input: GetProductsByCategoryUseCase.Input): GetProductsByCategoryUseCase.Output {
return withContext(Dispatchers.IO) {
val result = productRepository.getAllProductsByCategory(input.categoryId)
GetProductsByCategoryUseCase.Output(result)
}
override fun execute(input: GetProductsByCategoryUseCase.Input): GetProductsByCategoryUseCase.Output {
val result = productRepository.getAllProductsByCategory(input.categoryId)
return GetProductsByCategoryUseCase.Output(result)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import javax.inject.Inject

class GetProductsListUseCaseImpl @Inject constructor(private val productRepository: ProductRepository) :
GetProductsListUseCase {
override suspend fun execute(input: GetProductsListUseCase.Input): GetProductsListUseCase.Output {
override fun execute(input: GetProductsListUseCase.Input): GetProductsListUseCase.Output {
val result = productRepository.products
return GetProductsListUseCase.Output(result)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.hieuwu.groceriesstore.presentation.core.widgets

import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.hieuwu.groceriesstore.R

@Composable
fun PrimaryIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = IconButtonDefaults.filledShape,
content: @Composable () -> Unit
) {
FilledIconButton(
onClick = onClick,
modifier = modifier.defaultMinSize(minWidth = 48.dp, minHeight = 48.dp),
enabled = enabled,
shape = shape,
colors = IconButtonDefaults.filledIconButtonColors(
containerColor = colorResource(id = R.color.colorPrimary),
disabledContainerColor = colorResource(id = R.color.light_gray),
contentColor = Color.White,
),
content = content
)
}

@Composable
fun PrimarySquareIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
content: @Composable () -> Unit
) = PrimaryIconButton(
onClick = onClick,
modifier = modifier,
enabled = enabled,
shape = RoundedCornerShape(8.dp),
content = content
)

@Preview
@Composable
private fun PrimaryIconButtonPreview() {
PrimaryIconButton(onClick = {}) {
Icon(imageVector = Icons.Default.Search, contentDescription = "")
}
}

@Preview
@Composable
private fun PrimarySquareIconButtonPreview() {
PrimarySquareIconButton(onClick = {}) {
Icon(imageVector = Icons.Default.Search, contentDescription = "")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.hieuwu.groceriesstore.presentation.core.widgets

import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
import com.bumptech.glide.integration.compose.GlideImage
import com.bumptech.glide.integration.compose.placeholder
import com.hieuwu.groceriesstore.R

@OptIn(ExperimentalGlideComposeApi::class)
@Composable
fun WebImage(
model: Any?,
contentDescription: String?,
modifier: Modifier = Modifier,
alignment: Alignment = Alignment.Center,
contentScale: ContentScale = ContentScale.Fit,
) = GlideImage(
model = model,
contentDescription = contentDescription,
modifier = modifier,
alignment = alignment,
contentScale = contentScale,
loading = placeholder(R.drawable.loading_animation),
failure = placeholder(R.drawable.ic_broken_image)
)
Loading

0 comments on commit 162d271

Please sign in to comment.