Skip to content

Commit 51b4328

Browse files
authored
Merge pull request #208 from cerdeuk/feat/IPLC-27-댓글-API-연결
Feat/iplc 27 댓글 api 연결
2 parents 00e1c9d + d6dbb3c commit 51b4328

56 files changed

Lines changed: 1440 additions & 260 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ dependencies {
129129
// calendar
130130
implementation(libs.kizitonwose.calendar)
131131

132+
// Paging
133+
implementation(libs.androidx.room.paging)
134+
implementation(libs.androidx.paging.runtime.android)
135+
implementation(libs.androidx.paging.runtime)
136+
132137
// Google
133138
implementation(libs.androidx.credentials)
134139
implementation(libs.androidx.credentials.play.services.auth)

app/src/main/java/org/sopt/certi/core/component/bottomsheet/RegisterTestInfoBottomSheet.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,9 @@ fun RegisterTestInfoBottomSheet(
306306
}
307307
.padding(horizontal = screenWidthDp(12.dp))
308308
.noRippleClickable {
309-
showPlaceP1List = true
309+
if (!showPlaceP2List) {
310+
showPlaceP1List = true
311+
}
310312
},
311313
verticalAlignment = Alignment.CenterVertically
312314
) {
@@ -336,7 +338,7 @@ fun RegisterTestInfoBottomSheet(
336338
.clip(RoundedCornerShape(4.dp))
337339
.padding(horizontal = screenWidthDp(12.dp))
338340
.noRippleClickable {
339-
if (cityText.isNotEmpty()) {
341+
if (cityText.isNotEmpty() && !showPlaceP1List) {
340342
showPlaceP2List = true
341343
}
342344
},
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package org.sopt.certi.core.component.dialog
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.IntrinsicSize
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.Spacer
8+
import androidx.compose.foundation.layout.height
9+
import androidx.compose.foundation.layout.padding
10+
import androidx.compose.foundation.shape.RoundedCornerShape
11+
import androidx.compose.material3.HorizontalDivider
12+
import androidx.compose.material3.Text
13+
import androidx.compose.material3.VerticalDivider
14+
import androidx.compose.runtime.Composable
15+
import androidx.compose.ui.Alignment
16+
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.draw.clip
18+
import androidx.compose.ui.res.stringResource
19+
import androidx.compose.ui.text.style.TextAlign
20+
import androidx.compose.ui.tooling.preview.Preview
21+
import androidx.compose.ui.unit.dp
22+
import androidx.compose.ui.window.Dialog
23+
import org.sopt.certi.R
24+
import org.sopt.certi.core.util.heightForScreenPercentage
25+
import org.sopt.certi.core.util.screenHeightDp
26+
import org.sopt.certi.core.util.screenWidthDp
27+
import org.sopt.certi.ui.theme.CertiTheme
28+
29+
@Composable
30+
fun CertiContentDialog(
31+
titleText: String,
32+
contentText: String,
33+
onConfirmClick: () -> Unit,
34+
onDismissClick: () -> Unit
35+
) {
36+
Dialog(onDismissRequest = onDismissClick) {
37+
Column(
38+
modifier = Modifier
39+
.clip(RoundedCornerShape(12.dp))
40+
.background(CertiTheme.colors.white)
41+
.padding(top = screenHeightDp(30.dp)),
42+
horizontalAlignment = Alignment.CenterHorizontally
43+
) {
44+
Text(
45+
text = titleText,
46+
style = CertiTheme.typography.body.semibold_16,
47+
color = CertiTheme.colors.gray600,
48+
modifier = Modifier.padding(horizontal = screenWidthDp(16.dp)),
49+
textAlign = TextAlign.Center
50+
)
51+
Spacer(modifier = Modifier.heightForScreenPercentage(16.dp))
52+
53+
Text(
54+
text = contentText,
55+
style = CertiTheme.typography.caption.regular_14,
56+
color = CertiTheme.colors.gray600,
57+
modifier = Modifier.padding(horizontal = screenWidthDp(16.dp)),
58+
textAlign = TextAlign.Center
59+
)
60+
61+
Spacer(modifier = Modifier.heightForScreenPercentage(26.dp))
62+
63+
HorizontalDivider(
64+
thickness = 1.dp,
65+
color = CertiTheme.colors.gray100
66+
)
67+
68+
Row(modifier = Modifier.height(IntrinsicSize.Max)) {
69+
DialogButton(
70+
text = stringResource(R.string.delete_dialog_cancel),
71+
textColor = CertiTheme.colors.black,
72+
onClick = onDismissClick,
73+
modifier = Modifier.weight(1f)
74+
)
75+
VerticalDivider(
76+
thickness = 1.dp,
77+
color = CertiTheme.colors.gray100
78+
)
79+
DialogButton(
80+
text = stringResource(R.string.delete_dialog_confirm),
81+
textColor = CertiTheme.colors.purpleBlue,
82+
onClick = onConfirmClick,
83+
modifier = Modifier.weight(1f)
84+
)
85+
}
86+
}
87+
}
88+
}
89+
90+
@Preview
91+
@Composable
92+
private fun PreviewCertiContentDialog() {
93+
CertiContentDialog(
94+
titleText = "프리뷰 프리뷰",
95+
contentText = "콘텐트 콘텐트",
96+
onConfirmClick = {},
97+
onDismissClick = {}
98+
)
99+
}

app/src/main/java/org/sopt/certi/core/component/dialog/CertiDialog.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier
1717
import androidx.compose.ui.draw.clip
1818
import androidx.compose.ui.res.stringResource
1919
import androidx.compose.ui.text.style.TextAlign
20+
import androidx.compose.ui.tooling.preview.Preview
2021
import androidx.compose.ui.unit.dp
2122
import androidx.compose.ui.window.Dialog
2223
import org.sopt.certi.R
@@ -74,3 +75,13 @@ fun CertiDialog(
7475
}
7576
}
7677
}
78+
79+
@Preview
80+
@Composable
81+
private fun PreviewCertiDialog() {
82+
CertiDialog(
83+
text = "프리뷰 프리뷰",
84+
onConfirmClick = {},
85+
onDismissClick = {}
86+
)
87+
}

app/src/main/java/org/sopt/certi/core/network/TokenManager.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ class TokenManager @Inject constructor(
7676
return sharedPreferences.getString("NICKNAME", "").orEmpty()
7777
}
7878

79+
fun saveUserId(userId: Long) {
80+
sharedPreferences.edit().putLong("USERID", userId).apply()
81+
}
82+
83+
fun getUserId(): Long {
84+
return sharedPreferences.getLong("USERID", 0L)
85+
}
86+
7987
fun nicknameFlow(): Flow<String> = callbackFlow {
8088
trySend(getNickName())
8189

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.sopt.certi.data.mapper.todomain.comment
2+
3+
import org.sopt.certi.data.remote.dto.response.comment.CommentItemResponseDto
4+
import org.sopt.certi.data.remote.dto.response.comment.GetCommentListResponseDto
5+
import org.sopt.certi.domain.model.comment.CommentData
6+
import org.sopt.certi.domain.model.comment.CommentItemData
7+
import org.sopt.certi.domain.type.CertStateType
8+
9+
fun GetCommentListResponseDto.toDomain(): CommentData {
10+
return CommentData(
11+
content = content.map { it.toDomain() },
12+
totalPages = totalPages,
13+
totalElements = totalElements,
14+
isLast = isLast
15+
)
16+
}
17+
18+
fun CommentItemResponseDto.toDomain(): CommentItemData {
19+
return CommentItemData(
20+
commentId = commentId,
21+
userId = userId,
22+
nickName = nickName,
23+
content = content,
24+
userMajor = userMajor,
25+
userJob = userJob,
26+
state = CertStateType.fromStateName(state),
27+
createdTime = createdTime,
28+
lastModifiedTime = lastModifiedTime,
29+
isLike = isLike,
30+
likeCount = likeCount
31+
)
32+
}

app/src/main/java/org/sopt/certi/data/mapper/todomain/user/UserInfoResponseDtoMapper.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import org.sopt.certi.data.remote.dto.response.UserInfoResponseDto
44
import org.sopt.certi.domain.model.user.UserInfoData
55

66
fun UserInfoResponseDto.toDomain() = UserInfoData(
7+
userId = userId,
78
nickname = nickname,
89
name = name,
910
university = university,
1011
major = major,
12+
job = job,
1113
profileImageUrl = profileImage,
1214
birthday = birthDate
1315
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.sopt.certi.data.mapper.todto.comment
2+
3+
import org.sopt.certi.data.remote.dto.request.comment.CommentListPageableRequestDto
4+
import org.sopt.certi.data.remote.dto.request.comment.RegisterCommentRequestDto
5+
import org.sopt.certi.domain.model.comment.CommentListPageableRequest
6+
import org.sopt.certi.domain.model.comment.RegisterCommentRequest
7+
8+
fun RegisterCommentRequest.toDto(): RegisterCommentRequestDto {
9+
return RegisterCommentRequestDto(
10+
content = content,
11+
certificationId = certificationId
12+
)
13+
}
14+
15+
fun CommentListPageableRequest.toDto(): CommentListPageableRequestDto {
16+
return CommentListPageableRequestDto(
17+
page = page,
18+
size = size,
19+
sort = sort
20+
)
21+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.sopt.certi.data.mapper.todto.report
2+
3+
import org.sopt.certi.data.remote.dto.request.report.ReportCommentRequestDto
4+
import org.sopt.certi.domain.model.report.ReportCommentRequest
5+
6+
fun ReportCommentRequest.toDto(): ReportCommentRequestDto {
7+
return ReportCommentRequestDto(
8+
content = this.content,
9+
shouldBlockUser = this.shouldBlockUser
10+
)
11+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.sopt.certi.data.pagingsource
2+
3+
import androidx.paging.Pager
4+
import androidx.paging.PagingConfig
5+
import androidx.paging.PagingSource
6+
import androidx.paging.PagingState
7+
8+
class CertiPagingSource<T : Any>(
9+
private val pageSize: Int,
10+
private val getList: suspend (Int) -> List<T>
11+
) : PagingSource<Int, T>() {
12+
override fun getRefreshKey(state: PagingState<Int, T>): Int? {
13+
val anchor = state.anchorPosition ?: return null
14+
val page = state.closestPageToPosition(anchor) ?: return null
15+
return page.prevKey?.plus(1) ?: page.nextKey?.minus(1)
16+
}
17+
18+
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, T> {
19+
val currentPage = params.key ?: 0
20+
return try {
21+
val list = getList(currentPage)
22+
LoadResult.Page(
23+
data = list,
24+
prevKey = if (currentPage == 0) null else currentPage - 1,
25+
nextKey = if (list.size < pageSize) null else currentPage + 1
26+
)
27+
} catch (e: Exception) {
28+
LoadResult.Error(e)
29+
}
30+
}
31+
}
32+
33+
fun <T : Any> createPager(
34+
limit: Int = 10,
35+
initialLoadSize: Int = 20,
36+
q: List<String>? = null,
37+
startPage: Int? = null,
38+
pagingSourceFactory: suspend (page: Int, limit: Int, sort: List<String>?) -> List<T>
39+
): Pager<Int, T> {
40+
return Pager(
41+
config = PagingConfig(
42+
pageSize = limit,
43+
initialLoadSize = initialLoadSize,
44+
prefetchDistance = 1,
45+
enablePlaceholders = false
46+
),
47+
initialKey = startPage ?: 0,
48+
pagingSourceFactory = {
49+
CertiPagingSource<T>(pageSize = limit) { page ->
50+
pagingSourceFactory(page, limit, q)
51+
}
52+
}
53+
)
54+
}

0 commit comments

Comments
 (0)