Skip to content

Commit edc0be0

Browse files
committed
Feat: Add like function in comic screen
1 parent 7bc84cd commit edc0be0

File tree

9 files changed

+83
-27
lines changed

9 files changed

+83
-27
lines changed

core/data/src/main/java/kr/toongether/data/model/Comic.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import kr.toongether.model.Comic
66
import kr.toongether.network.model.ComicResponse
77

88
fun ComicResponse.asModel(): Comic = Comic(
9+
id = id,
910
title = title,
1011
thumbnail = thumbnail,
1112
imageUrl = imageUrl,

core/model/src/main/java/kr/toongether/model/Comic.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package kr.toongether.model
33
import kotlinx.datetime.LocalDateTime
44

55
data class Comic(
6+
val id: Long,
67
val title: String,
78
val thumbnail: String,
89
val imageUrl: List<String>,

core/network/src/main/java/kr/toongether/network/model/ComicResponse.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import kotlinx.serialization.Serializable
66

77
@Serializable
88
data class ComicResponse(
9+
@SerialName("id")
10+
val id: Long,
911
@SerialName("title")
1012
val title: String,
1113
@SerialName("thumbnail")

core/ui/src/main/java/kr/toongether/ui/ShortsCard.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import kr.toongether.common.toRelativeDateTime
3636
import kr.toongether.designsystem.icon.ToongetherIcons
3737
import kr.toongether.designsystem.icon.icons.FilledHeart
3838
import kr.toongether.designsystem.icon.icons.OutlinedHeart
39+
import kr.toongether.designsystem.theme.Red
3940
import kr.toongether.designsystem.theme.TransparentBlack80
4041
import kr.toongether.designsystem.theme.pretendard
4142
import kr.toongether.designsystem.utils.NoRippleInteractionSource
@@ -148,7 +149,7 @@ fun ShortsCard(
148149
),
149150
imageVector = if (isLiked.not()) ToongetherIcons.OutlinedHeart else ToongetherIcons.FilledHeart,
150151
contentDescription = null,
151-
tint = Color.White
152+
tint = if (isLiked.not()) Color.White else Red
152153
)
153154

154155
Spacer(modifier = modifier.width(5.dp))

feature/comic/src/main/java/kr/toongether/comic/ComicContract.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import kr.toongether.model.Comic
77

88
data class ComicState(
99
val comic: Comic = Comic(
10+
id = 0L,
1011
title = "",
1112
thumbnail = "",
1213
imageUrl = emptyList(),
@@ -22,7 +23,9 @@ data class ComicState(
2223
liked = false
2324
),
2425
val error: Throwable? = null,
25-
val isLoading: Boolean = false
26+
val likeCount: Int = comic.likeCount,
27+
val liked: Boolean = comic.liked,
28+
val isLoading: Boolean = false,
2629
)
2730

2831
sealed class ComicSideEffect {

feature/comic/src/main/java/kr/toongether/comic/ComicScreen.kt

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.Spacer
1111
import androidx.compose.foundation.layout.defaultMinSize
1212
import androidx.compose.foundation.layout.fillMaxSize
1313
import androidx.compose.foundation.layout.fillMaxWidth
14-
import androidx.compose.foundation.layout.height
1514
import androidx.compose.foundation.layout.navigationBarsPadding
1615
import androidx.compose.foundation.layout.padding
1716
import androidx.compose.foundation.layout.size
@@ -59,16 +58,17 @@ import kr.toongether.designsystem.theme.TransparentBlack
5958
import kr.toongether.designsystem.theme.pretendard
6059
import kr.toongether.designsystem.utils.NoRippleInteractionSource
6160
import org.orbitmvi.orbit.compose.collectAsState
61+
import org.orbitmvi.orbit.compose.collectSideEffect
6262
import java.time.LocalTime
6363
import kotlin.concurrent.timer
6464

6565
@Composable
6666
internal fun ComicRoute(
67-
episodeId: Long,
67+
episodeNumber: Long,
6868
seriesId: Long,
6969
navController: NavController,
7070
modifier: Modifier = Modifier,
71-
viewModel: ComicViewModel = hiltViewModel()
71+
viewModel: ComicViewModel = hiltViewModel(),
7272
) {
7373
val comicState by viewModel.collectAsState()
7474
val lazyListState = rememberLazyListState()
@@ -99,9 +99,9 @@ internal fun ComicRoute(
9999

100100
LaunchedEffect(Unit) {
101101
if (seriesId == -1L) {
102-
viewModel.getComic(episodeId)
102+
viewModel.getComic(episodeNumber)
103103
} else {
104-
viewModel.getComic(seriesId = seriesId, episodeId = episodeId)
104+
viewModel.getComic(seriesId = seriesId, episodeId = episodeNumber)
105105
}
106106
showTabs()
107107
}
@@ -115,26 +115,40 @@ internal fun ComicRoute(
115115
isShowTabs = isShowTabs || isTopOrBottom,
116116
recomposition = {
117117
isTopOrBottom = lazyListState.layoutInfo.visibleItemsInfo.firstOrNull()?.index == 0 ||
118-
lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ==
119-
lazyListState.layoutInfo.totalItemsCount - 1
118+
lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ==
119+
lazyListState.layoutInfo.totalItemsCount - 1
120+
},
121+
onClickLike = {
122+
if (seriesId == -1L) {
123+
viewModel.likeShorts(episodeNumber)
124+
} else {
125+
viewModel.likeSeries(comicState.comic.id)
126+
}
120127
},
121-
onClickLike = { },
122128
/* onClickComment = { }, */
123-
liked = comicState.comic.liked,
124-
likeCount = comicState.comic.likeCount,
129+
liked = comicState.liked,
130+
likeCount = comicState.likeCount,
125131
/* commentCount = comicState.comic.commentCount, */
126132
onClickAfter = {
127133
navController.navigateToComic(
128134
seriesId = seriesId,
129-
episodeId = comicState.comic.nextEpisode!!,
130-
navOptions { this.popUpTo(kr.toongether.comic.navigation.ComicRoute) { inclusive = true } }
135+
episodeNumber = comicState.comic.nextEpisode!!,
136+
navOptions {
137+
this.popUpTo(kr.toongether.comic.navigation.ComicRoute) {
138+
inclusive = true
139+
}
140+
}
131141
)
132142
},
133143
onClickBefore = {
134144
navController.navigateToComic(
135145
seriesId = seriesId,
136-
episodeId = comicState.comic.beforeEpisode!!,
137-
navOptions { this.popUpTo(kr.toongether.comic.navigation.ComicRoute) { inclusive = true } }
146+
episodeNumber = comicState.comic.beforeEpisode!!,
147+
navOptions {
148+
this.popUpTo(kr.toongether.comic.navigation.ComicRoute) {
149+
inclusive = true
150+
}
151+
}
138152
)
139153
},
140154
isNext = comicState.comic.nextEpisode != null,
@@ -159,7 +173,7 @@ internal fun ComicScreen(
159173
onClickBefore: () -> Unit,
160174
onClickAfter: () -> Unit,
161175
isNext: Boolean,
162-
isBefore: Boolean
176+
isBefore: Boolean,
163177
) {
164178
val minHeight: Dp
165179
val lastHeight: Dp
@@ -371,7 +385,7 @@ internal fun ComicScreen(
371385
private fun ComicItem(
372386
modifier: Modifier = Modifier,
373387
height: Dp,
374-
imageUrl: String
388+
imageUrl: String,
375389
) {
376390
Box(
377391
modifier = modifier

feature/comic/src/main/java/kr/toongether/comic/ComicViewModel.kt

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import androidx.lifecycle.ViewModel
44
import dagger.hilt.android.lifecycle.HiltViewModel
55
import kr.toongether.domain.GetSeriesEpisodeUseCase
66
import kr.toongether.domain.GetShortsEpisodeUseCase
7+
import kr.toongether.domain.LikeSeriesUseCase
8+
import kr.toongether.domain.LikeShortsUseCase
79
import org.orbitmvi.orbit.ContainerHost
810
import org.orbitmvi.orbit.syntax.simple.intent
911
import org.orbitmvi.orbit.syntax.simple.postSideEffect
@@ -14,7 +16,9 @@ import javax.inject.Inject
1416
@HiltViewModel
1517
class ComicViewModel @Inject constructor(
1618
private val getShortsEpisodeUseCase: GetShortsEpisodeUseCase,
17-
private val getSeriesEpisodeUseCase: GetSeriesEpisodeUseCase
19+
private val getSeriesEpisodeUseCase: GetSeriesEpisodeUseCase,
20+
private val likeShortsUseCase: LikeShortsUseCase,
21+
private val likeSeriesUseCase: LikeSeriesUseCase,
1822
) : ContainerHost<ComicState, ComicSideEffect>, ViewModel() {
1923

2024
override val container = container<ComicState, ComicSideEffect>(ComicState())
@@ -28,7 +32,9 @@ class ComicViewModel @Inject constructor(
2832
reduce {
2933
state.copy(
3034
isLoading = false,
31-
comic = it
35+
comic = it,
36+
liked = it.liked,
37+
likeCount = it.likeCount
3238
)
3339
}
3440
}.onFailure {
@@ -53,7 +59,9 @@ class ComicViewModel @Inject constructor(
5359
reduce {
5460
state.copy(
5561
isLoading = false,
56-
comic = it
62+
comic = it,
63+
liked = it.liked,
64+
likeCount = it.likeCount
5765
)
5866
}
5967
}.onFailure {
@@ -66,4 +74,30 @@ class ComicViewModel @Inject constructor(
6674
}
6775
}
6876
}
77+
78+
fun likeShorts(shortsId: Long) = intent {
79+
likeShortsUseCase.invoke(shortsId)
80+
.onSuccess {
81+
if (it) {
82+
reduce { state.copy(likeCount = state.likeCount + 1, liked = true) }
83+
} else {
84+
reduce { state.copy(likeCount = state.likeCount - 1, liked = false) }
85+
}
86+
}.onFailure {
87+
postSideEffect(ComicSideEffect.Toast(it.message!!))
88+
}
89+
}
90+
91+
fun likeSeries(seriesId: Long) = intent {
92+
likeSeriesUseCase.invoke(seriesId)
93+
.onSuccess {
94+
if (it) {
95+
reduce { state.copy(likeCount = state.likeCount + 1, liked = true) }
96+
} else {
97+
reduce { state.copy(likeCount = state.likeCount - 1, liked = false) }
98+
}
99+
}.onFailure {
100+
postSideEffect(ComicSideEffect.Toast(it.message!!))
101+
}
102+
}
69103
}

feature/comic/src/main/java/kr/toongether/comic/navigation/ComicNavigation.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ import androidx.navigation.navArgument
1111
import com.google.accompanist.navigation.animation.composable
1212
import kr.toongether.comic.ComicRoute
1313

14-
const val ComicRoute = "comic_route/{seriesId}/{episodeId}"
14+
const val ComicRoute = "comic_route/{seriesId}/{episodeNumber}"
1515

1616
fun NavController.navigateToComic(shortsId: Long, navOptions: NavOptions? = null) {
1717
this.navigate("comic_route/-1/$shortsId", navOptions)
1818
}
1919

2020
fun NavController.navigateToComic(
2121
seriesId: Long,
22-
episodeId: Long,
22+
episodeNumber: Long,
2323
navOptions: NavOptions? = null
2424
) {
25-
this.navigate("comic_route/$seriesId/$episodeId", navOptions)
25+
this.navigate("comic_route/$seriesId/$episodeNumber", navOptions)
2626
}
2727

2828
@OptIn(ExperimentalAnimationApi::class)
@@ -31,7 +31,7 @@ fun NavGraphBuilder.comicScreen(navController: NavController) {
3131
route = ComicRoute,
3232
arguments = listOf(
3333
navArgument("seriesId") { type = NavType.LongType },
34-
navArgument("episodeId") { type = NavType.LongType }
34+
navArgument("episodeNumber") { type = NavType.LongType },
3535
),
3636
enterTransition = {
3737
when (initialState.destination.route) {
@@ -64,7 +64,7 @@ fun NavGraphBuilder.comicScreen(navController: NavController) {
6464
ComicRoute(
6565
navController = navController,
6666
seriesId = it.arguments?.getLong("seriesId") ?: 0L,
67-
episodeId = it.arguments?.getLong("episodeId") ?: 0L
67+
episodeNumber = it.arguments?.getLong("episodeNumber") ?: 0L,
6868
)
6969
}
7070
}

feature/episode/src/main/java/kr/toongether/episode/EpisodeScreen.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ internal fun EpisodeRoute(
5050
onItemClick = {
5151
navController.navigateToComic(
5252
seriesId = id,
53-
episodeId = it.episodeNumber.toLong()
53+
episodeNumber = it.episodeNumber.toLong(),
5454
)
5555
},
5656
onClickBack = navController::popBackStack,

0 commit comments

Comments
 (0)