Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/mz 203 vote list api #101

Merged
merged 10 commits into from
Jan 27, 2024
23 changes: 20 additions & 3 deletions core/model/src/main/java/com/susu/core/model/Vote.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
package com.susu.core.model

import androidx.compose.runtime.Stable
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.toKotlinLocalDateTime
import kotlinx.serialization.Serializable

@Stable
@Serializable
data class Vote(
val id: Long = 0,
val uid: Long = 0,
val category: String = "",
val content: String = "",
val count: Int = 0,
val isModified: Boolean = false,
val createdAt: LocalDateTime = java.time.LocalDateTime.now().toKotlinLocalDateTime(),
val optionList: List<VoteOption> = emptyList(),
)

@Stable
@Serializable
data class VoteOption(
val id: Long,
val category: String,
val content: String,
val isModified: Boolean,
val optionList: List<String>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import androidx.compose.runtime.snapshotFlow
fun LazyListState.OnBottomReached(
// tells how many items before we reach the bottom of the list
// to call onLoadMore function
buffer: Int = 3,
buffer: Int = 0,
minItemsCount: Int = 0,
onLoadMore: () -> Unit,
) {
// Buffer must be positive.
Expand All @@ -22,6 +23,7 @@ fun LazyListState.OnBottomReached(
val shouldLoadMore = remember {
derivedStateOf {
val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull() ?: return@derivedStateOf false
if (lastVisibleItem.index < minItemsCount) return@derivedStateOf false

lastVisibleItem.index >= layoutInfo.totalItemsCount - 1 - buffer
}
Expand Down
4 changes: 4 additions & 0 deletions core/ui/src/main/java/com/susu/core/ui/util/Date.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ fun getSafeLocalDateTime(year: Int, month: Int, day: Int): LocalDateTime = try {
Log.e("DateTimeError", "Invalid date provided: $year-$month-$day", e)
LocalDateTime.of(year, month, 1, 0, 0)
}

fun isBetween(target: LocalDateTime, start: LocalDateTime, end: LocalDateTime): Boolean {
return !target.isBefore(start) && !target.isAfter(end)
}
1 change: 1 addition & 0 deletions core/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@
<string name="word_register">등록</string>
<string name="word_free">자유</string>
<string name="content_description_report_button">신고 버튼</string>
<string name="word_all">전체</string>
</resources>
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.susu.data.data.repository

import com.susu.core.model.Category
import com.susu.core.model.Vote
import com.susu.data.local.model.toModel
import com.susu.data.remote.api.VoteService
Expand Down Expand Up @@ -28,4 +29,26 @@ class VoteRepositoryImpl @Inject constructor(
categoryId = categoryId,
),
).getOrThrow().toModel()

override suspend fun getVoteList(
content: String?,
mine: Boolean?,
sortType: String?,
categoryId: Int?,
page: Int?,
size: Int?,
sort: String?,
): List<Vote> = api.getVoteList(
content = content,
mine = mine,
sortType = sortType,
categoryId = categoryId,
page = page,
size = size,
sort = sort,
).getOrThrow().toModel()

override suspend fun getPopularVoteList(): List<Vote> = api.getPopularVoteList().getOrThrow().map { it.toModel() }

override suspend fun getPostCategoryConfig(): List<Category> = api.getPostCategoryConfig().getOrThrow().map { it.toModel() }
}
24 changes: 23 additions & 1 deletion data/src/main/java/com/susu/data/remote/api/VoteService.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,37 @@
package com.susu.data.remote.api

import com.susu.data.remote.model.request.CreateVoteRequest
import com.susu.data.remote.model.response.PopularVoteResponse
import com.susu.data.remote.model.response.PostCategoryConfig
import com.susu.data.remote.model.response.VoteListResponse
import com.susu.data.remote.model.response.VoteResponse
import com.susu.data.remote.retrofit.ApiResult
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query

interface VoteService {

@POST("/api/v1/votes")
@POST("votes")
suspend fun createVote(
@Body createVoteRequest: CreateVoteRequest,
): ApiResult<VoteResponse>

@GET("votes")
suspend fun getVoteList(
@Query("content") content: String?,
@Query("mine") mine: Boolean?,
@Query("sortType") sortType: String?,
@Query("categoryId") categoryId: Int?,
@Query("page") page: Int?,
@Query("size") size: Int?,
@Query("sort") sort: String?,
): ApiResult<VoteListResponse>

@GET("votes/popular")
suspend fun getPopularVoteList(): ApiResult<List<PopularVoteResponse>>

@GET("posts/configs/create-post")
suspend fun getPostCategoryConfig(): ApiResult<List<PostCategoryConfig>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ data class CreateVoteRequest(

@Serializable
data class VoteOption(
val id: Long? = null,
val content: String,
val seq: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.susu.data.remote.model.response

import com.susu.core.model.Vote
import kotlinx.datetime.toKotlinLocalDateTime
import kotlinx.serialization.Serializable
import java.time.LocalDateTime

@Serializable
data class PopularVoteResponse(
val id: Long,
val category: String,
val content: String,
val count: Int,
val isModified: Boolean,
)

internal fun PopularVoteResponse.toModel() = Vote(
id = id,
uid = 0,
category = category,
content = content,
isModified = isModified,
count = count,
createdAt = LocalDateTime.now().toKotlinLocalDateTime(),
optionList = listOf(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.susu.data.remote.model.response

import com.susu.core.model.Category
import kotlinx.serialization.Serializable

@Serializable
data class PostCategoryConfig(
val id: Int,
val name: String,
)

internal fun PostCategoryConfig.toModel() = Category(
id = id,
name = name,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.susu.data.remote.model.response

import kotlinx.serialization.Serializable

@Serializable
data class VoteListResponse(
val data: List<VoteResponse> = emptyList(),
)

internal fun VoteListResponse.toModel() = data.map { it.toModel() }
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,34 @@ package com.susu.data.remote.model.response

import com.susu.core.model.Vote
import com.susu.data.remote.model.request.VoteOption
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.toKotlinLocalDateTime
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class VoteResponse(
val id: Long,
val uid: Long = 0,
val category: String,
val content: String,
val isModified: Boolean,
val createdAt: LocalDateTime = java.time.LocalDateTime.now().toKotlinLocalDateTime(),
@SerialName("options")
val optionList: List<VoteOption>,
)

internal fun VoteResponse.toModel() = Vote(
id = id,
uid = uid,
category = category,
content = content,
isModified = isModified,
optionList = optionList.sortedBy { it.seq }.map { it.content },
createdAt = createdAt,
optionList = optionList.sortedBy { it.seq }.map {
com.susu.core.model.VoteOption(
id = it.id ?: 0L,
content = it.content,
)
},
)
15 changes: 15 additions & 0 deletions domain/src/main/java/com/susu/domain/repository/VoteRepository.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.susu.domain.repository

import com.susu.core.model.Category
import com.susu.core.model.Vote

interface VoteRepository {
Expand All @@ -8,4 +9,18 @@ interface VoteRepository {
optionList: List<String>,
categoryId: Int,
): Vote

suspend fun getVoteList(
content: String?,
mine: Boolean?,
sortType: String?,
categoryId: Int?,
page: Int?,
size: Int?,
sort: String?,
): List<Vote>

suspend fun getPopularVoteList(): List<Vote>

suspend fun getPostCategoryConfig(): List<Category>
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class GetLedgerListUseCase @Inject constructor(
ledgerRepository.getLedgerList(
title = title,
categoryIdList = categoryIdList,
fromStartAt = fromStartAt ?: LocalDateTime.now().minusYears(10),
toEndAt = toEndAt ?: LocalDateTime.now().plusYears(10),
fromStartAt = fromStartAt ?: LocalDateTime.now().minusYears(100),
toEndAt = toEndAt ?: LocalDateTime.now().plusYears(100),
page = page,
sort = sort,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.susu.domain.usecase.vote

import com.susu.core.common.runCatchingIgnoreCancelled
import com.susu.domain.repository.VoteRepository
import javax.inject.Inject

class GetPopularVoteListUseCase @Inject constructor(
private val voteRepository: VoteRepository,
) {
suspend operator fun invoke() = runCatchingIgnoreCancelled {
voteRepository.getPopularVoteList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.susu.domain.usecase.vote

import com.susu.core.common.runCatchingIgnoreCancelled
import com.susu.domain.repository.VoteRepository
import javax.inject.Inject

class GetPostCategoryConfigUseCase @Inject constructor(
private val voteRepository: VoteRepository,
) {
suspend operator fun invoke() = runCatchingIgnoreCancelled {
voteRepository.getPostCategoryConfig()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.susu.domain.usecase.vote

import com.susu.core.common.runCatchingIgnoreCancelled
import com.susu.domain.repository.VoteRepository
import javax.inject.Inject

class GetVoteListUseCase @Inject constructor(
private val voteRepository: VoteRepository,
) {
suspend operator fun invoke(param: Param) = runCatchingIgnoreCancelled {
with(param) {
voteRepository.getVoteList(
content = content,
mine = mine,
sortType = sortType,
categoryId = categoryId,
page = page,
size = size,
sort = sort,
)
}
}

data class Param(
val content: String?,
val mine: Boolean?,
val sortType: String?,
val categoryId: Int?,
val page: Int?,
val size: Int? = null,
val sort: String?,
)
}
5 changes: 5 additions & 0 deletions feature/community/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.susu.android.feature.compose)
alias(libs.plugins.kotlin.serialization)
}

android {
namespace = "com.susu.feature.community"
}

dependencies {
implementation(libs.kotlinx.serialization.json)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.susu.feature.community.community

import com.susu.core.model.Category
import com.susu.core.model.Vote
import com.susu.core.ui.base.SideEffect
import com.susu.core.ui.base.UiState
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf

data class CommunityState(
val categoryConfigList: PersistentList<Category> = persistentListOf(),
val selectedCategory: Category? = null,
val popularVoteList: PersistentList<Vote> = persistentListOf(),
val voteList: PersistentList<Vote> = persistentListOf(),
val isCheckedVotePopular: Boolean = false,
val isCheckShowMine: Boolean = false,
val isLoading: Boolean = false,
) : UiState

sealed interface CommunitySideEffect : SideEffect {
data class HandleException(val throwable: Throwable, val retry: () -> Unit) : CommunitySideEffect
}
Loading
Loading