Skip to content

Commit 61b1b47

Browse files
Add Database for wishlist IDs, and flows to get and set them III
1 parent 6796cc1 commit 61b1b47

24 files changed

Lines changed: 245 additions & 110 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package au.com.alfie.ecomm.data.database
2+
3+
import androidx.room.Database
4+
import androidx.room.RoomDatabase
5+
import au.com.alfie.ecomm.data.database.wishlist.WishlistDao
6+
import au.com.alfie.ecomm.data.database.wishlist.model.WishlistEntity
7+
8+
@Database(
9+
entities = [WishlistEntity::class],
10+
version = 1,
11+
exportSchema = true
12+
)
13+
internal abstract class WishlistDatabase : RoomDatabase() {
14+
15+
abstract fun wishlistDao(): WishlistDao
16+
}

data/database/src/main/java/au/com/alfie/ecomm/data/database/di/DatabaseModule.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import androidx.room.Room
55
import au.com.alfie.ecomm.data.database.FeatureToggleDatabase
66
import au.com.alfie.ecomm.data.database.InMemoryDatabase
77
import au.com.alfie.ecomm.data.database.PersistentDatabase
8+
import au.com.alfie.ecomm.data.database.WishlistDatabase
89
import au.com.alfie.ecomm.data.database.navigation.NavigationEntryDao
910
import au.com.alfie.ecomm.data.database.search.FeatureToggleDao
1011
import au.com.alfie.ecomm.data.database.search.RecentSearchDao
12+
import au.com.alfie.ecomm.data.database.wishlist.WishlistDao
1113
import dagger.Module
1214
import dagger.Provides
1315
import dagger.hilt.InstallIn
@@ -47,6 +49,15 @@ internal object DatabaseModule {
4749
name = "feature-toggle-database"
4850
).build()
4951

52+
@Provides
53+
@Singleton
54+
fun provideWishlistDatabase(@ApplicationContext context: Context): WishlistDatabase =
55+
Room.databaseBuilder(
56+
context = context,
57+
klass = WishlistDatabase::class.java,
58+
name = "wishlist-database"
59+
).build()
60+
5061
@Provides
5162
fun provideRecentSearchDao(database: PersistentDatabase): RecentSearchDao = database.recentSearchDao()
5263

@@ -55,4 +66,7 @@ internal object DatabaseModule {
5566

5667
@Provides
5768
fun provideFeatureToggleDao(database: FeatureToggleDatabase): FeatureToggleDao = database.featureToggleDao()
69+
70+
@Provides
71+
fun provideWishlistDao(database: WishlistDatabase): WishlistDao = database.wishlistDao()
5872
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package au.com.alfie.ecomm.data.database.wishlist
2+
3+
import androidx.room.Dao
4+
import androidx.room.Insert
5+
import androidx.room.OnConflictStrategy
6+
import androidx.room.Query
7+
import au.com.alfie.ecomm.data.database.wishlist.model.WishlistEntity
8+
import kotlinx.coroutines.flow.Flow
9+
10+
@Dao
11+
interface WishlistDao {
12+
13+
@Insert(onConflict = OnConflictStrategy.REPLACE)
14+
suspend fun addToWishlist(product: WishlistEntity)
15+
16+
@Query("DELETE FROM wishlist WHERE id = :productId")
17+
suspend fun removeFromWishlist(productId: String)
18+
19+
@Query("SELECT * FROM wishlist")
20+
fun getWishlistIds(): Flow<List<WishlistEntity>>
21+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package au.com.alfie.ecomm.data.database.wishlist.model
2+
3+
import androidx.room.Entity
4+
import androidx.room.PrimaryKey
5+
6+
@Entity(tableName = "wishlist")
7+
data class WishlistEntity(
8+
@PrimaryKey
9+
val id: String
10+
)
Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,35 @@
11
package au.com.alfie.ecomm.data.wishlist
22

3+
import au.com.alfie.ecomm.data.database.wishlist.WishlistDao
4+
import au.com.alfie.ecomm.data.database.wishlist.model.WishlistEntity
35
import au.com.alfie.ecomm.data.toRepositoryResult
4-
import au.com.alfie.ecomm.repository.product.model.Product
5-
import au.com.alfie.ecomm.repository.result.RepositoryResult
66
import au.com.alfie.ecomm.repository.wishlist.WishlistRepository
77
import kotlinx.coroutines.flow.Flow
8-
import kotlinx.coroutines.flow.MutableStateFlow
98
import kotlinx.coroutines.flow.map
9+
import timber.log.Timber
1010
import javax.inject.Inject
1111

12-
class WishlistRepositoryImpl @Inject constructor() : WishlistRepository {
12+
class WishlistRepositoryImpl @Inject constructor(
13+
private val wishlistDao: WishlistDao
14+
) : WishlistRepository {
1315

14-
// TODO consider removing this property when the wishlist of product is saved on database or api
15-
private val _wishlist = MutableStateFlow<List<Product>>(listOf())
16-
17-
// TODO change this implementation to a proper implementation using data base or api to save the products on wishlist
18-
override fun addToWishlist(product: Product): RepositoryResult<Boolean> {
19-
if (_wishlist.value.none { it.id == product.id }) {
20-
_wishlist.value = buildList {
21-
addAll(_wishlist.value)
22-
add(product)
23-
}
16+
override fun getWishlist(): Flow<List<String>> =
17+
wishlistDao.getWishlistIds().map { wishlist ->
18+
Timber.tag("WishlistTesting").d("Fetching wishlist: $wishlist")
19+
wishlist.map { it.id }
2420
}
25-
return RepositoryResult.Success(true)
26-
}
2721

28-
// TODO change this implementation to a proper implementation using data base or api to save the products on wishlist
29-
override fun removeFromWishlist(product: Product): RepositoryResult<Boolean> {
30-
_wishlist.value = _wishlist.value.filter { it.id != product.id }.toMutableList()
31-
return RepositoryResult.Success(true)
32-
}
22+
override suspend fun addToWishlist(productId: String) =
23+
runCatching {
24+
Timber.tag("WishlistTesting").d("Adding to wishlist: $productId")
25+
wishlistDao.addToWishlist(WishlistEntity(productId))
26+
}
27+
.toRepositoryResult()
3328

34-
// TODO change this implementation to a proper implementation using data base or api to get the wishlist
35-
override fun getWishlist(): Flow<RepositoryResult<List<Product>>> {
36-
return _wishlist.map { list ->
37-
Result.success(list).toRepositoryResult()
29+
override suspend fun removeFromWishlist(productId: String) =
30+
runCatching {
31+
Timber.tag("WishlistTesting").d("Removing from wishlist: $productId")
32+
wishlistDao.removeFromWishlist(productId)
3833
}
39-
}
34+
.toRepositoryResult()
4035
}

designsystem/src/main/java/au/com/alfie/ecomm/designsystem/component/productcard/ProductCard.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ fun ProductCard(
1616
productCardType: ProductCardType,
1717
onClick: ClickEvent,
1818
modifier: Modifier = Modifier,
19-
isLoading: Boolean = false
19+
isLoading: Boolean = false,
20+
isWishlisted: Boolean = false
2021
) {
2122
when (productCardType) {
2223
is ProductCardType.XSmall -> ProductCardXSmall(
@@ -35,13 +36,15 @@ fun ProductCard(
3536
productCard = productCardType,
3637
onClick = onClick,
3738
modifier = modifier,
38-
isLoading = isLoading
39+
isLoading = isLoading,
40+
isWishlisted = isWishlisted
3941
)
4042
is ProductCardType.Large -> ProductCardLarge(
4143
productCard = productCardType,
4244
onClick = onClick,
4345
modifier = modifier,
44-
isLoading = isLoading
46+
isLoading = isLoading,
47+
isWishlisted = isWishlisted
4548
)
4649
}
4750
}

designsystem/src/main/java/au/com/alfie/ecomm/designsystem/component/productcard/size/ProductCardLarge.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ internal fun ProductCardLarge(
4040
productCard: ProductCardType.Large,
4141
onClick: ClickEvent,
4242
modifier: Modifier = Modifier,
43-
isLoading: Boolean = false
43+
isLoading: Boolean = false,
44+
isWishlisted: Boolean = false
4445
) {
4546
Column(
4647
modifier = modifier then Modifier
@@ -49,7 +50,8 @@ internal fun ProductCardLarge(
4950
) {
5051
ProductImage(
5152
productCard = productCard,
52-
isLoading = isLoading
53+
isLoading = isLoading,
54+
isWishlisted = isWishlisted
5355
)
5456
Spacer(modifier = Modifier.size(Theme.spacing.spacing16))
5557
ProductDescription(
@@ -62,7 +64,8 @@ internal fun ProductCardLarge(
6264
@Composable
6365
private fun ProductImage(
6466
productCard: ProductCardType.Large,
65-
isLoading: Boolean
67+
isLoading: Boolean,
68+
isWishlisted: Boolean
6669
) {
6770
Box(
6871
contentAlignment = Alignment.TopEnd
@@ -80,8 +83,10 @@ private fun ProductImage(
8083
modifier = Modifier.size(Theme.iconSize.large),
8184
onClick = productCard.onFavoriteClick
8285
) {
86+
val iconRes =
87+
if (isWishlisted) R.drawable.ic_action_heart_fill else R.drawable.ic_action_heart_outline
8388
Icon(
84-
painter = painterResource(id = R.drawable.ic_action_heart_outline),
89+
painter = painterResource(iconRes),
8590
contentDescription = null,
8691
modifier = Modifier.size(Theme.iconSize.medium)
8792
)

designsystem/src/main/java/au/com/alfie/ecomm/designsystem/component/productcard/size/ProductCardMedium.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ internal fun ProductCardMedium(
4141
productCard: ProductCardType.Medium,
4242
onClick: ClickEvent,
4343
modifier: Modifier = Modifier,
44-
isLoading: Boolean = false
44+
isLoading: Boolean = false,
45+
isWishlisted: Boolean = false
4546
) {
4647
Column(
4748
modifier = modifier then Modifier
@@ -50,7 +51,8 @@ internal fun ProductCardMedium(
5051
) {
5152
ProductImage(
5253
productCard = productCard,
53-
isLoading = isLoading
54+
isLoading = isLoading,
55+
isWishlisted = isWishlisted
5456
)
5557
Spacer(modifier = Modifier.size(Theme.spacing.spacing12))
5658
ProductDescription(
@@ -63,7 +65,8 @@ internal fun ProductCardMedium(
6365
@Composable
6466
private fun ProductImage(
6567
productCard: ProductCardType.Medium,
66-
isLoading: Boolean
68+
isLoading: Boolean,
69+
isWishlisted: Boolean
6770
) {
6871
Box(
6972
contentAlignment = Alignment.TopEnd
@@ -77,10 +80,13 @@ private fun ProductImage(
7780
ratio = Ratio.RATIO3x4
7881
)
7982
if (isLoading.not()) {
83+
val iconRes =
84+
if (isWishlisted) R.drawable.ic_action_heart_fill else R.drawable.ic_action_heart_outline
85+
8086
if (productCard.onFavoriteClick != null) {
8187
ActionIconButton(
8288
productCard.onFavoriteClick,
83-
R.drawable.ic_action_heart_outline
89+
iconRes
8490
)
8591
} else if (productCard.onRemoveClick != null) {
8692
ActionIconButton(
@@ -186,7 +192,9 @@ private fun ActionIconButton(
186192
) {
187193
onClick?.let {
188194
IconButton(
189-
modifier = Modifier.padding(8.dp).size(Theme.iconSize.large),
195+
modifier = Modifier
196+
.padding(8.dp)
197+
.size(Theme.iconSize.large),
190198
onClick = it
191199
) {
192200
Icon(

domain/repository/src/main/java/au/com/alfie/ecomm/repository/result/ErrorType.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ enum class ErrorType {
1010
INVALID_REQUEST,
1111
BAD_REQUEST,
1212
UN_PROCESSABLE_ENTITY,
13-
METHOD_NOT_ALLOWED
13+
METHOD_NOT_ALLOWED,
14+
DATABASE_ERROR
1415
}
Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
package au.com.alfie.ecomm.repository.wishlist
22

3-
import au.com.alfie.ecomm.repository.product.model.Product
43
import au.com.alfie.ecomm.repository.result.RepositoryResult
54
import kotlinx.coroutines.flow.Flow
65

76
interface WishlistRepository {
8-
9-
fun addToWishlist(product: Product): RepositoryResult<Boolean>
10-
11-
fun removeFromWishlist(product: Product): RepositoryResult<Boolean>
12-
13-
fun getWishlist(): Flow<RepositoryResult<List<Product>>>
7+
fun getWishlist(): Flow<List<String>>
8+
suspend fun addToWishlist(productId: String): RepositoryResult<Unit>
9+
suspend fun removeFromWishlist(productId: String): RepositoryResult<Unit>
1410
}

0 commit comments

Comments
 (0)