diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 7061a0d6..82d900ed 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -57,5 +57,6 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/texthip/thip/ui/common/modal/DialogPopup.kt b/app/src/main/java/com/texthip/thip/ui/common/modal/DialogPopup.kt
index 37229e1d..315930c2 100644
--- a/app/src/main/java/com/texthip/thip/ui/common/modal/DialogPopup.kt
+++ b/app/src/main/java/com/texthip/thip/ui/common/modal/DialogPopup.kt
@@ -4,9 +4,11 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -14,6 +16,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
import com.texthip.thip.R
import com.texthip.thip.ui.common.buttons.ActionMediumButton
import com.texthip.thip.ui.theme.ThipTheme.colors
@@ -24,43 +27,47 @@ fun DialogPopup(
modifier: Modifier = Modifier,
title: String,
description: String,
+ confirmText: String = stringResource(R.string.yes),
+ cancelText: String = stringResource(R.string.no),
onConfirm: () -> Unit,
onCancel: () -> Unit
) {
Column(
modifier = modifier
- .size(width = 320.dp, height = 182.dp)
+ .width(320.dp)
.background(
color = colors.DarkGrey,
shape = RoundedCornerShape(12.dp)
)
- .padding(20.dp),
- verticalArrangement = Arrangement.SpaceBetween,
+ .padding(20.dp)
) {
Text(
text = title,
color = colors.White,
style = typography.smalltitle_m500_s18_h24,
)
+ Spacer(modifier = Modifier.height(20.dp))
Text(
text = description,
color = colors.White,
style = typography.copy_r400_s14,
+ lineHeight = 22.sp
)
+ Spacer(modifier = Modifier.height(20.dp))
Row(
horizontalArrangement = Arrangement.spacedBy(20.dp),
modifier = Modifier.fillMaxWidth()
) {
ActionMediumButton(
- text = stringResource(R.string.no),
+ text = cancelText,
contentColor = colors.White,
backgroundColor = colors.Grey02,
modifier = Modifier.weight(1f),
onClick = onCancel,
)
ActionMediumButton(
- text = stringResource(R.string.yes),
+ text = confirmText,
contentColor = colors.White,
backgroundColor = colors.Purple,
modifier = Modifier.weight(1f),
diff --git a/app/src/main/java/com/texthip/thip/ui/common/modal/ScrollbarUtil.kt b/app/src/main/java/com/texthip/thip/ui/common/modal/ScrollbarUtil.kt
index 40a7978a..713ceb3c 100644
--- a/app/src/main/java/com/texthip/thip/ui/common/modal/ScrollbarUtil.kt
+++ b/app/src/main/java/com/texthip/thip/ui/common/modal/ScrollbarUtil.kt
@@ -1,14 +1,13 @@
package com.texthip.thip.ui.common.modal
import androidx.compose.foundation.ScrollState
-import androidx.compose.runtime.Composable
+import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -26,6 +25,62 @@ fun Modifier.drawVerticalScrollbar(
val scrollProgress = scrollState.value.toFloat() / scrollState.maxValue
val scrollbarOffsetY = (size.height - scrollbarHeight) * scrollProgress
+ //전체 고정 바
+ drawRoundRect(
+ color = trackColor,
+ topLeft = Offset(x = size.width - trackThickness.toPx(), y = 0f),
+ size = Size(trackThickness.toPx(), size.height),
+ cornerRadius = CornerRadius(trackThickness.toPx() / 2)
+ )
+ //핸들 바
+ drawRoundRect(
+ color = thumbColor,
+ topLeft = Offset(x = size.width - thumbThickness.toPx(), y = scrollbarOffsetY),
+ size = Size(thumbThickness.toPx(), scrollbarHeight),
+ cornerRadius = CornerRadius(thumbThickness.toPx() / 2)
+ )
+ }
+)
+
+fun Modifier.drawVerticalScrollbar(
+ lazyListState: LazyListState,
+ trackThickness: Dp = 1.dp,
+ thumbThickness: Dp = 3.dp,
+ trackColor: Color = Color.White.copy(alpha = 0.2f),
+ thumbColor: Color = Color.White.copy(alpha = 0.8f),
+): Modifier = this.then(
+ Modifier.drawBehind {
+ val layoutInfo = lazyListState.layoutInfo
+ val totalItemsCount = layoutInfo.totalItemsCount
+ val viewportHeight = layoutInfo.viewportEndOffset - layoutInfo.viewportStartOffset
+
+ // 스크롤이 필요 없으면 스크롤바 표시 안 함
+ if (totalItemsCount == 0) return@drawBehind
+ if (!lazyListState.canScrollForward && !lazyListState.canScrollBackward) return@drawBehind
+
+ val scrollbarHeight = size.height / 8f
+
+ // 전체 컨텐츠 높이 추정
+ val averageItemHeight = if (layoutInfo.visibleItemsInfo.isNotEmpty()) {
+ layoutInfo.visibleItemsInfo.map { it.size }.average().toFloat()
+ } else {
+ 100f
+ }
+ val estimatedTotalHeight = averageItemHeight * totalItemsCount
+
+ // 스크롤 진행률 계산
+ val firstVisibleIndex = lazyListState.firstVisibleItemIndex.toFloat()
+ val firstVisibleOffset = lazyListState.firstVisibleItemScrollOffset.toFloat()
+
+ val scrollProgress = if (estimatedTotalHeight > 0) {
+ ((firstVisibleIndex * averageItemHeight + firstVisibleOffset) / estimatedTotalHeight)
+ .coerceIn(0f, 1f)
+ } else {
+ 0f
+ }
+
+ val scrollbarOffsetY = (size.height - scrollbarHeight) * scrollProgress
+
//전체 고정 바
drawRoundRect(
color = trackColor,
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookListWithScrollbar.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookListWithScrollbar.kt
index bcf37098..6aa8d21f 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookListWithScrollbar.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookListWithScrollbar.kt
@@ -4,13 +4,13 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
@@ -36,7 +36,7 @@ fun GroupBookListWithScrollbar(
onLoadMore: () -> Unit = {}
) {
val listState = rememberLazyListState()
-
+
val shouldLoadMore = remember {
derivedStateOf {
val layoutInfo = listState.layoutInfo
@@ -48,7 +48,7 @@ fun GroupBookListWithScrollbar(
}
LaunchedEffect(shouldLoadMore.value, hasMore, isLoadingMore) {
- if (shouldLoadMore.value && hasMore && !isLoadingMore && books.isNotEmpty()) {
+ if (shouldLoadMore.value && hasMore && !isLoadingMore) {
onLoadMore()
}
}
@@ -57,7 +57,8 @@ fun GroupBookListWithScrollbar(
state = listState,
modifier = Modifier
.fillMaxWidth()
- .drawVerticalScrollbar(rememberScrollState())
+ .fillMaxHeight()
+ .drawVerticalScrollbar(listState)
) {
items(books) { book ->
CardBookSearch(
@@ -75,7 +76,7 @@ fun GroupBookListWithScrollbar(
)
Spacer(modifier = Modifier.height(12.dp))
}
-
+
if (isLoadingMore) {
item {
Box(
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookSearchBottomSheet.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookSearchBottomSheet.kt
index d6d14f5b..d2645e38 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookSearchBottomSheet.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupBookSearchBottomSheet.kt
@@ -28,6 +28,7 @@ import com.texthip.thip.ui.group.makeroom.mock.BookData
import com.texthip.thip.ui.group.makeroom.mock.dummyGroupBooks
import com.texthip.thip.ui.group.makeroom.mock.dummySavedBooks
import com.texthip.thip.ui.theme.ThipTheme
+import com.texthip.thip.ui.theme.ThipTheme.colors
import com.texthip.thip.utils.rooms.advancedImePadding
@Composable
@@ -49,16 +50,22 @@ fun GroupBookSearchBottomSheet(
onSearch: (String) -> Unit = {},
onLoadMoreSaved: () -> Unit = {},
onLoadMoreGroup: () -> Unit = {},
- onLoadMoreSearch: () -> Unit = {}
+ onLoadMoreSearch: () -> Unit = {},
+ showGroupBooksTab: Boolean = true
) {
var selectedTab by rememberSaveable { mutableIntStateOf(0) }
- val tabs = listOf(
- stringResource(R.string.group_saved_book), stringResource(R.string.group_book)
- )
+ val tabs = if (showGroupBooksTab) {
+ listOf(
+ stringResource(R.string.group_saved_book),
+ stringResource(R.string.group_book)
+ )
+ } else {
+ listOf(stringResource(R.string.group_saved_book))
+ }
var searchText by rememberSaveable { mutableStateOf("") }
- val currentBooks = if (selectedTab == 0) savedBooks else groupBooks
+ val currentBooks = if (showGroupBooksTab && selectedTab == 1) groupBooks else savedBooks
// 검색어가 있으면 검색 결과 사용, 없으면 탭별 도서 목록 사용
val displayBooks = if (searchText.isNotEmpty()) {
@@ -115,12 +122,18 @@ fun GroupBookSearchBottomSheet(
.align(Alignment.CenterHorizontally),
contentAlignment = Alignment.Center
) {
- CircularProgressIndicator()
+ CircularProgressIndicator(
+ color = colors.White
+ )
}
}
else -> {
- Column(Modifier.padding(horizontal = 20.dp)) {
+ Column(
+ Modifier
+ .weight(1f)
+ .padding(horizontal = 20.dp)
+ ) {
when {
searchText.isNotEmpty() -> {
GroupBookListWithScrollbar(
@@ -131,7 +144,8 @@ fun GroupBookSearchBottomSheet(
onLoadMore = onLoadMoreSearch
)
}
- selectedTab == 0 -> {
+
+ !showGroupBooksTab || selectedTab == 0 -> {
GroupBookListWithScrollbar(
books = displayBooks,
onBookClick = onBookSelect,
@@ -140,6 +154,7 @@ fun GroupBookSearchBottomSheet(
onLoadMore = onLoadMoreSaved
)
}
+
else -> {
GroupBookListWithScrollbar(
books = displayBooks,
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupDatePicker.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupDatePicker.kt
index dae96fa1..d9578d6c 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupDatePicker.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupDatePicker.kt
@@ -6,14 +6,13 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -39,13 +38,13 @@ fun GroupDatePicker(
val month = selectedDate.monthValue
val day = selectedDate.dayOfMonth
- // 유효한 범위 계산 - 날짜 변경 시 안정성을 위해 remember 사용
- val years = remember(minDate.year, maxDate.year) {
- (minDate.year..maxDate.year).toList()
+ // 유효한 범위 계산 - 단순하게 전체 범위 사용
+ val years = remember(minDate.year, maxDate.year) {
+ (minDate.year..maxDate.year).toList()
}
val months = remember { (1..12).toList() }
- val days = remember(year, month) {
- (1..LocalDate.of(year, month, 1).lengthOfMonth()).toList()
+ val days = remember(year, month) {
+ (1..LocalDate.of(year, month, 1).lengthOfMonth()).toList()
}
Row(
@@ -62,7 +61,8 @@ fun GroupDatePicker(
val newDate = try {
LocalDate.of(newYear, month, day)
} catch (e: Exception) {
- LocalDate.of(newYear, month, 1)
+ val lastDay = LocalDate.of(newYear, month, 1).lengthOfMonth()
+ LocalDate.of(newYear, month, lastDay)
}
onDateSelected(newDate)
},
@@ -88,7 +88,8 @@ fun GroupDatePicker(
val newDate = try {
LocalDate.of(year, newMonth, day)
} catch (e: Exception) {
- LocalDate.of(year, newMonth, 1)
+ val lastDay = LocalDate.of(year, newMonth, 1).lengthOfMonth()
+ LocalDate.of(year, newMonth, lastDay)
}
onDateSelected(newDate)
},
@@ -109,10 +110,9 @@ fun GroupDatePicker(
GroupWheelPicker(
modifier = Modifier.width(32.dp),
items = days,
- selectedItem = day.coerceAtMost(days.max()),
+ selectedItem = day.coerceAtMost(days.maxOrNull() ?: 1),
onItemSelected = { newDay ->
- val newDate = LocalDate.of(year, month, newDay)
- onDateSelected(newDate)
+ onDateSelected(LocalDate.of(year, month, newDay))
},
displayText = { it.toString() }
)
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupMemberLimitPicker.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupMemberLimitPicker.kt
index 7b6437c8..cbca8943 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupMemberLimitPicker.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupMemberLimitPicker.kt
@@ -28,7 +28,7 @@ fun GroupMemberLimitPicker(
selectedCount: Int = 30,
onCountSelected: (Int) -> Unit = { }
) {
- val memberCounts = remember { (1..30).toList() }
+ val memberCounts = remember { (2..30).toList() }
Column(
modifier = modifier.fillMaxWidth()
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt
index ff2b2376..c08e9df4 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt
@@ -21,11 +21,13 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.texthip.thip.R
+import com.texthip.thip.ui.group.makeroom.util.WheelPickerUtils
import com.texthip.thip.ui.theme.ThipTheme
import com.texthip.thip.ui.theme.ThipTheme.colors
import com.texthip.thip.ui.theme.ThipTheme.typography
import java.time.LocalDate
import java.time.temporal.ChronoUnit
+import kotlinx.coroutines.delay
@Composable
fun GroupRoomDurationPicker(
@@ -40,6 +42,7 @@ fun GroupRoomDurationPicker(
var startDate by rememberSaveable { mutableStateOf(tomorrow) }
var endDate by rememberSaveable { mutableStateOf(tomorrow.plusDays(1)) }
var isPickerTouched by rememberSaveable { mutableStateOf(false) }
+ var debouncedRecruitmentDays by rememberSaveable { mutableStateOf(null) }
// 첫 시작 시에만 모든 날짜를 내일 기준으로 초기화
LaunchedEffect(Unit) {
@@ -47,50 +50,51 @@ fun GroupRoomDurationPicker(
startDate = tomorrow
endDate = tomorrow.plusDays(1)
isInitialized = true
+ // picker 업데이트 완료 대기 후 상태 리셋
+ delay(100)
+ isPickerTouched = false
+ debouncedRecruitmentDays = null
}
}
- // 날짜 범위 계산
- val daysBetween = ChronoUnit.DAYS.between(startDate, endDate)
- val isOverLimit = daysBetween > 91
-
- // 날짜 선택 콜백
- LaunchedEffect(startDate, endDate) {
- if (endDate.isAfter(startDate)) {
- onDateRangeSelected(startDate, endDate)
+ // 모집 기간 계산
+ LaunchedEffect(startDate, isPickerTouched) {
+ if (isPickerTouched) {
+ delay(100)
+ debouncedRecruitmentDays = ChronoUnit.DAYS.between(today, startDate).toInt()
}
}
- // 날짜 유효성 검사 및 자동 조정
- LaunchedEffect(startDate) {
- val adjustedStartDate = when {
- startDate.isBefore(tomorrow) -> tomorrow
- startDate.isAfter(maxDate) -> maxDate
- else -> startDate
- }
-
- if (adjustedStartDate != startDate) {
- startDate = adjustedStartDate
- }
+ // 날짜 유효성 검사 및 자동 조정 (통합)
+ LaunchedEffect(startDate, endDate) {
+ val (validatedStart, validatedEnd) = WheelPickerUtils.validateDateRange(
+ startDate = startDate,
+ endDate = endDate,
+ minDate = tomorrow,
+ maxDate = maxDate
+ )
- // 끝 날짜가 시작 날짜보다 빠르면 조정
- if (endDate.isBefore(startDate.plusDays(1))) {
- endDate = startDate.plusDays(1)
+ // 날짜가 조정되었으면 업데이트
+ var needsUpdate = false
+ if (validatedStart != startDate) {
+ startDate = validatedStart
+ needsUpdate = true
}
- }
-
- LaunchedEffect(endDate) {
- val adjustedEndDate = when {
- endDate.isAfter(maxDate) -> maxDate
- endDate.isBefore(startDate.plusDays(1)) -> startDate.plusDays(1)
- else -> endDate
+ if (validatedEnd != endDate) {
+ endDate = validatedEnd
+ needsUpdate = true
}
- if (adjustedEndDate != endDate) {
- endDate = adjustedEndDate
+ // 유효한 범위이고 조정이 없었으면 콜백 호출
+ if (!needsUpdate && validatedEnd.isAfter(validatedStart)) {
+ onDateRangeSelected(validatedStart, validatedEnd)
}
}
+ // 날짜 범위 계산
+ val daysBetween = ChronoUnit.DAYS.between(startDate, endDate)
+ val isOverLimit = daysBetween > 91
+
Column(modifier = modifier.fillMaxWidth()) {
Text(
text = stringResource(R.string.group_room_duration_title),
@@ -111,6 +115,7 @@ fun GroupRoomDurationPicker(
minDate = tomorrow,
maxDate = maxDate,
onDateSelected = { newDate ->
+ isPickerTouched = true
startDate = newDate
},
modifier = Modifier
@@ -132,9 +137,10 @@ fun GroupRoomDurationPicker(
// 끝 날짜 Picker
GroupDatePicker(
selectedDate = endDate,
- minDate = tomorrow,
+ minDate = startDate.plusDays(1),
maxDate = maxDate,
onDateSelected = { newDate ->
+ isPickerTouched = true
endDate = newDate
},
modifier = Modifier
@@ -151,6 +157,8 @@ fun GroupRoomDurationPicker(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
) {
+ val recruitmentDays = debouncedRecruitmentDays
+
when {
isOverLimit -> {
Text(
@@ -161,6 +169,7 @@ fun GroupRoomDurationPicker(
modifier = Modifier.padding(top = 12.dp)
)
}
+
!isPickerTouched -> {
Text(
text = stringResource(R.string.group_room_duration_initial_comment),
@@ -170,6 +179,20 @@ fun GroupRoomDurationPicker(
modifier = Modifier.padding(top = 12.dp)
)
}
+
+ isPickerTouched && recruitmentDays != null -> {
+ Text(
+ text = stringResource(
+ R.string.group_room_duration_recruitment_period,
+ recruitmentDays
+ ),
+ style = typography.info_r400_s12,
+ color = colors.NeonGreen,
+ textAlign = TextAlign.End,
+ modifier = Modifier.padding(top = 12.dp)
+ )
+ }
+
else -> {
Text(
text = stringResource(
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupWheelPicker.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupWheelPicker.kt
index fdf71339..294e3690 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupWheelPicker.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupWheelPicker.kt
@@ -68,17 +68,23 @@ fun GroupWheelPicker(
val spacingPx = remember(density) { with(density) { 9.dp.toPx() } }
val itemSpacing = remember(itemHeightPx, spacingPx) { itemHeightPx + spacingPx }
- val getCircularIndex = remember(items.size) { { index: Int ->
- WheelPickerUtils.getCircularIndex(index, items.size)
- } }
+ val getCircularIndex = remember(items.size) {
+ { index: Int ->
+ WheelPickerUtils.getCircularIndex(index, items.size)
+ }
+ }
- val normalizeOffset = remember(itemSpacing, items.size, circular) { { offset: Float ->
- WheelPickerUtils.normalizeOffset(offset, itemSpacing, items.size, circular)
- } }
+ val normalizeOffset = remember(itemSpacing, items.size, circular) {
+ { offset: Float ->
+ WheelPickerUtils.normalizeOffset(offset, itemSpacing, items.size, circular)
+ }
+ }
- val offsetToIndex = remember(itemSpacing, items.size, circular) { { offset: Float ->
- WheelPickerUtils.offsetToIndex(offset, itemSpacing, items.size, circular)
- } }
+ val offsetToIndex = remember(itemSpacing, items.size, circular) {
+ { offset: Float ->
+ WheelPickerUtils.offsetToIndex(offset, itemSpacing, items.size, circular)
+ }
+ }
// 선택 아이템이 바뀌면 중앙에 오도록 offset 이동
LaunchedEffect(selectedItem) {
@@ -104,7 +110,7 @@ fun GroupWheelPicker(
val containerHeight = remember(itemHeight) { (itemHeight * 3 + 36).dp }
val textStyle = typography.info_r400_s12
-
+
Box(
modifier = modifier.height(containerHeight)
) {
@@ -203,7 +209,6 @@ fun GroupWheelPicker(
}
}
- // 중앙 + 위 아래 한 개만 보이도록!
val visibleRange = remember(isScrollEnabled) { if (isScrollEnabled) -1..1 else 0..0 }
visibleRange.forEach { relIdx ->
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/mock/GroupMakeRoomRequest.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/mock/GroupMakeRoomRequest.kt
deleted file mode 100644
index b41d0b8b..00000000
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/mock/GroupMakeRoomRequest.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.texthip.thip.ui.group.makeroom.mock
-
-import java.time.LocalDate
-
-data class GroupMakeRoomRequest(
- val selectedBook: BookData?,
- val genreIndex: Int,
- val roomTitle: String,
- val roomDescription: String,
- val meetingStartDate: LocalDate,
- val meetingEndDate: LocalDate,
- val memberLimit: Int,
- val isPrivate: Boolean,
- val password: String = ""
-)
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/screen/GroupMakeRoomScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/screen/GroupMakeRoomScreen.kt
index 60202284..9eed363a 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/screen/GroupMakeRoomScreen.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/screen/GroupMakeRoomScreen.kt
@@ -1,5 +1,6 @@
package com.texthip.thip.ui.group.makeroom.screen
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -12,6 +13,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -20,7 +22,9 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.window.Dialog
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -30,6 +34,7 @@ import com.texthip.thip.data.manager.Genre
import com.texthip.thip.ui.common.buttons.GenreChipRow
import com.texthip.thip.ui.common.buttons.ToggleSwitchButton
import com.texthip.thip.ui.common.forms.WarningTextField
+import com.texthip.thip.ui.common.modal.DialogPopup
import com.texthip.thip.ui.common.topappbar.InputTopAppBar
import com.texthip.thip.ui.group.makeroom.component.GroupBookSearchBottomSheet
import com.texthip.thip.ui.group.makeroom.component.GroupInputField
@@ -45,7 +50,9 @@ import com.texthip.thip.ui.theme.ThipTheme.colors
import com.texthip.thip.ui.theme.ThipTheme.typography
import com.texthip.thip.utils.rooms.advancedImePadding
import com.texthip.thip.utils.rooms.toDisplayStrings
+import java.time.format.DateTimeFormatter
+private val DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd")
@Composable
fun GroupMakeRoomScreen(
@@ -66,7 +73,7 @@ fun GroupMakeRoomScreen(
GroupMakeRoomContent(
uiState = uiState,
onNavigateBack = onNavigateBack,
- onCreateGroup = {
+ onCreateGroup = {
viewModel.createGroup(
onSuccess = { roomId ->
onGroupCreated(roomId)
@@ -74,6 +81,7 @@ fun GroupMakeRoomScreen(
onError = { }
)
},
+ onToggleConfirmDialog = viewModel::toggleConfirmDialog,
onSelectBook = viewModel::selectBook,
onToggleBookSearchSheet = viewModel::toggleBookSearchSheet,
onSelectGenre = viewModel::selectGenre,
@@ -85,7 +93,6 @@ fun GroupMakeRoomScreen(
onUpdatePassword = viewModel::updatePassword,
onSearchBooks = viewModel::searchBooks,
onLoadMoreSavedBooks = viewModel::loadMoreSavedBooks,
- onLoadMoreGroupBooks = viewModel::loadMoreGroupBooks,
onLoadMoreSearchResults = viewModel::loadMoreSearchResults,
modifier = modifier
)
@@ -97,6 +104,7 @@ fun GroupMakeRoomContent(
uiState: GroupMakeRoomUiState,
onNavigateBack: () -> Unit = {},
onCreateGroup: () -> Unit = {},
+ onToggleConfirmDialog: (Boolean) -> Unit = {},
onSelectBook: (BookData) -> Unit = {},
onToggleBookSearchSheet: (Boolean) -> Unit = {},
onSelectGenre: (Int) -> Unit = {},
@@ -108,7 +116,6 @@ fun GroupMakeRoomContent(
onUpdatePassword: (String) -> Unit = {},
onSearchBooks: (String) -> Unit = {},
onLoadMoreSavedBooks: () -> Unit = {},
- onLoadMoreGroupBooks: () -> Unit = {},
onLoadMoreSearchResults: () -> Unit = {}
) {
val scrollState = rememberScrollState()
@@ -117,7 +124,11 @@ fun GroupMakeRoomContent(
Column(
modifier = modifier
.fillMaxSize()
- .then(if (uiState.showBookSearchSheet) Modifier.blur(5.dp) else Modifier),
+ .then(
+ if (uiState.showBookSearchSheet || uiState.showConfirmDialog || uiState.isLoading) Modifier.blur(
+ 5.dp
+ ) else Modifier
+ ),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -125,7 +136,7 @@ fun GroupMakeRoomContent(
title = stringResource(R.string.group_making_group),
isRightButtonEnabled = uiState.isFormValid && !uiState.isLoading,
onLeftClick = onNavigateBack,
- onRightClick = onCreateGroup
+ onRightClick = { onToggleConfirmDialog(true) }
)
Column(
@@ -157,7 +168,7 @@ fun GroupMakeRoomContent(
genres = uiState.genres.toDisplayStrings(),
selectedIndex = uiState.selectedGenreIndex,
onSelect = onSelectGenre,
- horizontalArrangement = Arrangement.Start
+ horizontalArrangement = Arrangement.Center
)
Spacer(modifier = Modifier.height(12.dp))
@@ -260,22 +271,60 @@ fun GroupMakeRoomContent(
onToggleBookSearchSheet(false)
},
savedBooks = uiState.savedBooks,
- groupBooks = uiState.groupBooks,
+ groupBooks = emptyList(),
searchResults = uiState.searchResults,
isLoading = uiState.isLoadingBooks,
isSearching = uiState.isSearching,
isLoadingMoreSaved = uiState.isLoadingMoreSavedBooks,
- isLoadingMoreGroup = uiState.isLoadingMoreGroupBooks,
+ isLoadingMoreGroup = false,
isLoadingMoreSearch = uiState.isLoadingMoreSearchResults,
hasMoreSaved = !uiState.isLastSavedBooks,
- hasMoreGroup = !uiState.isLastGroupBooks,
+ hasMoreGroup = false,
hasMoreSearch = !uiState.isLastSearchPage,
onSearch = onSearchBooks,
onLoadMoreSaved = onLoadMoreSavedBooks,
- onLoadMoreGroup = onLoadMoreGroupBooks,
- onLoadMoreSearch = onLoadMoreSearchResults
+ onLoadMoreGroup = {},
+ onLoadMoreSearch = onLoadMoreSearchResults,
+ showGroupBooksTab = false
)
}
+
+ if (uiState.showConfirmDialog) {
+ Dialog(
+ onDismissRequest = { onToggleConfirmDialog(false) }
+ ) {
+ DialogPopup(
+ title = stringResource(R.string.group_create_confirm_title),
+ description = stringResource(
+ R.string.group_create_confirm_message,
+ java.time.LocalDate.now().format(DATE_FORMATTER),
+ uiState.meetingStartDate.format(DATE_FORMATTER),
+ uiState.meetingStartDate.format(DATE_FORMATTER),
+ uiState.meetingEndDate.format(DATE_FORMATTER)
+ ),
+ confirmText = stringResource(R.string.confirm),
+ cancelText = stringResource(R.string.cancel),
+ onConfirm = {
+ onToggleConfirmDialog(false)
+ onCreateGroup()
+ },
+ onCancel = {
+ onToggleConfirmDialog(false)
+ }
+ )
+ }
+ }
+
+ if (uiState.isLoading) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color.Black.copy(alpha = 0.5f)),
+ contentAlignment = Alignment.Center
+ ) {
+ CircularProgressIndicator(color = colors.NeonGreen)
+ }
+ }
}
}
@@ -312,20 +361,6 @@ private fun GroupMakeRoomScreenPreview() {
author = "유발 하라리",
isbn = "9788934972464"
)
- ),
- groupBooks = listOf(
- BookData(
- title = "1984",
- imageUrl = "https://picsum.photos/300/400?4",
- author = "조지 오웰",
- isbn = "9788937460777"
- ),
- BookData(
- title = "어린왕자",
- imageUrl = "https://picsum.photos/300/400?5",
- author = "생텍쥐페리",
- isbn = "9788932917245"
- )
)
)
)
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/util/WheelPickerDisplayUtils.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/util/WheelPickerDisplayUtils.kt
index 9a355d52..0bbd85f3 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/util/WheelPickerDisplayUtils.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/util/WheelPickerDisplayUtils.kt
@@ -1,5 +1,6 @@
package com.texthip.thip.ui.group.makeroom.util
+import java.time.LocalDate
import kotlin.math.roundToInt
object WheelPickerUtils {
@@ -27,4 +28,29 @@ object WheelPickerUtils {
return if (circular) getCircularIndex(centerIndex, size)
else centerIndex.coerceIn(0, size - 1)
}
+
+ @JvmStatic
+ fun validateDateRange(
+ startDate: LocalDate,
+ endDate: LocalDate,
+ minDate: LocalDate,
+ maxDate: LocalDate
+ ): Pair {
+ // 시작 날짜 유효성 검사
+ val validatedStart = when {
+ startDate.isBefore(minDate) -> minDate
+ startDate.isAfter(maxDate) -> maxDate
+ else -> startDate
+ }
+
+ // 종료 날짜 유효성 검사
+ val minEndDate = validatedStart.plusDays(1)
+ val validatedEnd = when {
+ endDate.isAfter(maxDate) -> maxDate
+ endDate.isBefore(minEndDate) -> minEndDate
+ else -> endDate
+ }
+
+ return validatedStart to validatedEnd
+ }
}
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/viewmodel/GroupMakeRoomUiState.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/viewmodel/GroupMakeRoomUiState.kt
index f3fa81a9..c62c5171 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/viewmodel/GroupMakeRoomUiState.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/viewmodel/GroupMakeRoomUiState.kt
@@ -2,7 +2,6 @@ package com.texthip.thip.ui.group.makeroom.viewmodel
import com.texthip.thip.data.manager.Genre
import com.texthip.thip.ui.group.makeroom.mock.BookData
-import com.texthip.thip.ui.group.makeroom.mock.GroupMakeRoomRequest
import java.time.LocalDate
import java.time.temporal.ChronoUnit
@@ -12,20 +11,17 @@ data class GroupMakeRoomUiState(
val selectedGenreIndex: Int = -1,
val roomTitle: String = "",
val roomDescription: String = "",
- val meetingStartDate: LocalDate = LocalDate.now(),
- val meetingEndDate: LocalDate = LocalDate.now().plusDays(1),
+ val meetingStartDate: LocalDate = LocalDate.now().plusDays(1),
+ val meetingEndDate: LocalDate = LocalDate.now().plusDays(2),
val memberLimit: Int = 30,
val isPrivate: Boolean = false,
val password: String = "",
val isLoading: Boolean = false,
val errorMessage: String? = null,
val savedBooks: List = emptyList(),
- val groupBooks: List = emptyList(),
val isLoadingBooks: Boolean = false,
val isLoadingMoreSavedBooks: Boolean = false,
- val isLoadingMoreGroupBooks: Boolean = false,
val isLastSavedBooks: Boolean = false,
- val isLastGroupBooks: Boolean = false,
val searchResults: List = emptyList(),
val isSearching: Boolean = false,
val isLoadingMoreSearchResults: Boolean = false,
@@ -33,13 +29,16 @@ data class GroupMakeRoomUiState(
val isLastSearchPage: Boolean = false,
val currentSearchQuery: String = "",
val genres: List = emptyList(),
- val isBookPreselected: Boolean = false
+ val isBookPreselected: Boolean = false,
+ val showConfirmDialog: Boolean = false
) {
// 유효성 검사 로직
val isDurationValid: Boolean
get() {
+ val today = LocalDate.now()
+ val tomorrow = today.plusDays(1)
val daysBetween = ChronoUnit.DAYS.between(meetingStartDate, meetingEndDate)
- return daysBetween in 1..90
+ return !meetingStartDate.isBefore(tomorrow) && daysBetween in 1..91
}
val isCountValid: Boolean
@@ -57,18 +56,4 @@ data class GroupMakeRoomUiState(
isCountValid &&
isPasswordValid
- // 서버 전송용 데이터로 변환
- fun toRequest(): GroupMakeRoomRequest {
- return GroupMakeRoomRequest(
- selectedBook = selectedBook,
- genreIndex = selectedGenreIndex,
- roomTitle = roomTitle.trim(),
- roomDescription = roomDescription.trim(),
- meetingStartDate = meetingStartDate,
- meetingEndDate = meetingEndDate,
- memberLimit = memberLimit,
- isPrivate = isPrivate,
- password = if (isPrivate) password else ""
- )
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/viewmodel/GroupMakeRoomViewModel.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/viewmodel/GroupMakeRoomViewModel.kt
index 9c1320e4..eb616863 100644
--- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/viewmodel/GroupMakeRoomViewModel.kt
+++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/viewmodel/GroupMakeRoomViewModel.kt
@@ -3,11 +3,10 @@ package com.texthip.thip.ui.group.makeroom.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.texthip.thip.R
+import com.texthip.thip.data.manager.Genre
import com.texthip.thip.data.model.book.response.BookSavedResponse
import com.texthip.thip.data.model.book.response.BookSearchItem
-import com.texthip.thip.data.model.book.response.BookUserSaveList
import com.texthip.thip.data.model.rooms.request.CreateRoomRequest
-import com.texthip.thip.data.manager.Genre
import com.texthip.thip.data.provider.StringResourceProvider
import com.texthip.thip.data.repository.BookRepository
import com.texthip.thip.data.repository.RoomsRepository
@@ -36,9 +35,6 @@ class GroupMakeRoomViewModel @Inject constructor(
private var searchJob: Job? = null
private var loadMoreSearchJob: Job? = null
private var savedBooksCursor: String? = null
- private var groupBooksCursor: String? = null
- private var isLoadingSavedBooks = false
- private var isLoadingGroupBooks = false
companion object {
private val DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd")
@@ -88,21 +84,25 @@ class GroupMakeRoomViewModel @Inject constructor(
}
private fun loadBooks() {
- updateState { it.copy(isLoadingBooks = true) }
loadSavedBooks(isInitial = true)
- loadGroupBooks(isInitial = true)
+ // 모임 생성 화면에서는 저장된 책만 표시
}
fun loadSavedBooks(isInitial: Boolean = false) {
- if (isLoadingSavedBooks) return
- if (!isInitial && _uiState.value.isLastSavedBooks) return
+ val currentState = _uiState.value
+ if (currentState.isLoadingBooks || currentState.isLoadingMoreSavedBooks) return
+ if (!isInitial && currentState.isLastSavedBooks) return
viewModelScope.launch {
try {
- isLoadingSavedBooks = true
-
if (isInitial) {
- updateState { it.copy(savedBooks = emptyList(), isLastSavedBooks = false) }
+ updateState {
+ it.copy(
+ savedBooks = emptyList(),
+ isLastSavedBooks = false,
+ isLoadingBooks = true
+ )
+ }
savedBooksCursor = null
} else {
updateState { it.copy(isLoadingMoreSavedBooks = true) }
@@ -113,7 +113,8 @@ class GroupMakeRoomViewModel @Inject constructor(
bookRepository.getBooks("SAVED", cursor)
.onSuccess { response ->
if (response != null) {
- val currentList = if (isInitial) emptyList() else _uiState.value.savedBooks
+ val currentList =
+ if (isInitial) emptyList() else _uiState.value.savedBooks
val newBooks = response.bookList.map { it.toBookData() }
updateState {
it.copy(
@@ -132,62 +133,11 @@ class GroupMakeRoomViewModel @Inject constructor(
}
}
} finally {
- isLoadingSavedBooks = false
- updateState {
+ updateState {
it.copy(
- isLoadingBooks = if (isInitial && !isLoadingGroupBooks) false else it.isLoadingBooks,
+ isLoadingBooks = false,
isLoadingMoreSavedBooks = false
- )
- }
- }
- }
- }
-
- fun loadGroupBooks(isInitial: Boolean = false) {
- if (isLoadingGroupBooks) return
- if (!isInitial && _uiState.value.isLastGroupBooks) return
-
- viewModelScope.launch {
- try {
- isLoadingGroupBooks = true
-
- if (isInitial) {
- updateState { it.copy(groupBooks = emptyList(), isLastGroupBooks = false) }
- groupBooksCursor = null
- } else {
- updateState { it.copy(isLoadingMoreGroupBooks = true) }
- }
-
- val cursor = if (isInitial) null else groupBooksCursor
-
- bookRepository.getBooks("JOINING", cursor)
- .onSuccess { response ->
- if (response != null) {
- val currentList = if (isInitial) emptyList() else _uiState.value.groupBooks
- val newBooks = response.bookList.map { it.toBookData() }
- updateState {
- it.copy(
- groupBooks = currentList + newBooks,
- isLastGroupBooks = response.isLast
- )
- }
- groupBooksCursor = response.nextCursor
- } else {
- updateState { it.copy(isLastGroupBooks = true) }
- }
- }
- .onFailure { exception ->
- if (isInitial) {
- updateState { it.copy(groupBooks = emptyList()) }
- }
- }
- } finally {
- isLoadingGroupBooks = false
- updateState {
- it.copy(
- isLoadingBooks = if (isInitial && !isLoadingSavedBooks) false else it.isLoadingBooks,
- isLoadingMoreGroupBooks = false
- )
+ )
}
}
}
@@ -197,10 +147,6 @@ class GroupMakeRoomViewModel @Inject constructor(
loadSavedBooks(isInitial = false)
}
- fun loadMoreGroupBooks() {
- loadGroupBooks(isInitial = false)
- }
-
private fun BookSavedResponse.toBookData(): BookData {
return BookData(
title = this.bookTitle,
@@ -224,28 +170,28 @@ class GroupMakeRoomViewModel @Inject constructor(
loadMoreSearchJob?.cancel()
if (query.isBlank()) {
- updateState {
+ updateState {
it.copy(
- searchResults = emptyList(),
+ searchResults = emptyList(),
isSearching = false,
searchPage = 1,
isLastSearchPage = false,
currentSearchQuery = ""
- )
+ )
}
return
}
searchJob = viewModelScope.launch {
delay(300) // 디바운싱
- updateState {
+ updateState {
it.copy(
isSearching = true,
searchResults = emptyList(),
searchPage = 1,
isLastSearchPage = false,
currentSearchQuery = query
- )
+ )
}
try {
@@ -291,23 +237,24 @@ class GroupMakeRoomViewModel @Inject constructor(
fun loadMoreSearchResults() {
val currentState = _uiState.value
- if (currentState.isLoadingMoreSearchResults ||
+ if (currentState.isLoadingMoreSearchResults ||
currentState.isSearching ||
- currentState.isLastSearchPage ||
+ currentState.isLastSearchPage ||
currentState.searchResults.isEmpty() ||
- currentState.currentSearchQuery.isBlank()) {
+ currentState.currentSearchQuery.isBlank()
+ ) {
return
}
loadMoreSearchJob?.cancel()
loadMoreSearchJob = viewModelScope.launch {
updateState { it.copy(isLoadingMoreSearchResults = true) }
-
+
try {
val nextPage = currentState.searchPage + 1
val result = bookRepository.searchBooks(
currentState.currentSearchQuery,
- page = nextPage,
+ page = nextPage,
isFinalized = false
)
result.onSuccess { response ->
@@ -380,6 +327,10 @@ class GroupMakeRoomViewModel @Inject constructor(
updateState { it.copy(password = password) }
}
+ fun toggleConfirmDialog(show: Boolean = true) {
+ updateState { it.copy(showConfirmDialog = show) }
+ }
+
fun createGroup(onSuccess: (Int) -> Unit, onError: (String) -> Unit) {
val currentState = _uiState.value
diff --git a/app/src/main/java/com/texthip/thip/utils/auth/AuthInterceptor.kt b/app/src/main/java/com/texthip/thip/utils/auth/AuthInterceptor.kt
index 8d5865e4..5cb37e51 100644
--- a/app/src/main/java/com/texthip/thip/utils/auth/AuthInterceptor.kt
+++ b/app/src/main/java/com/texthip/thip/utils/auth/AuthInterceptor.kt
@@ -28,9 +28,12 @@ class AuthInterceptor @Inject constructor(
}.build()
val response = chain.proceed(newRequest)
-
- // 401 응답 처리
- if (response.code == 401) {
+
+ // 401 또는 인증 관련 500 에러 처리
+ val shouldClearAuth = response.code == 401 ||
+ (response.code == 500 && isAuthError(response))
+
+ if (shouldClearAuth) {
runBlocking {
tokenManager.clearTokens()
authStateManager.triggerTokenExpired()
@@ -39,4 +42,14 @@ class AuthInterceptor @Inject constructor(
return response
}
+
+ private fun isAuthError(response: Response): Boolean {
+ return try {
+ val body = response.peekBody(Long.MAX_VALUE).string()
+ // 에러 코드 40108 (인증 처리 중 서버 오류) 확인
+ body.contains("40108")
+ } catch (e: Exception) {
+ false
+ }
+ }
}
diff --git a/app/src/main/java/com/texthip/thip/utils/permission/NotificationPermissionUtils.kt b/app/src/main/java/com/texthip/thip/utils/permission/NotificationPermissionUtils.kt
index 6548c4a8..db8b0ee6 100644
--- a/app/src/main/java/com/texthip/thip/utils/permission/NotificationPermissionUtils.kt
+++ b/app/src/main/java/com/texthip/thip/utils/permission/NotificationPermissionUtils.kt
@@ -7,13 +7,13 @@ import android.os.Build
import androidx.core.content.ContextCompat
object NotificationPermissionUtils {
-
+
// POST_NOTIFICATIONS 권한이 필요한지 확인
fun isNotificationPermissionRequired(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
}
-
+
// 알림 권한이 허용되었는지 확인
fun isNotificationPermissionGranted(context: Context): Boolean {
@@ -27,7 +27,7 @@ object NotificationPermissionUtils {
true
}
}
-
+
// 알림 권한 요청이 필요한지 확인
fun shouldRequestNotificationPermission(context: Context): Boolean {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e23ee58a..1085d124 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -31,6 +31,8 @@
내 피드에 추가
예
아니오
+ 취소
+ 확인
글 등록
팔로우
책 변경
@@ -304,7 +306,10 @@
%1$d월 %2$d일 자정에 자동으로 모집 마감되고 활동이 가능합니다.
검색해서 찾기
모임방 활동이 시작되면, 독서메이트 모집이 자동으로 종료돼요.
+ 활동 시작 전 독서메이트 모집 기간 : %d일
%1$d / %2$d
+ 모임 만들기
+ - 모집기간 : %1$s ~ %2$s\n- 활동기간 : %3$s ~ %4$s\n\n모집기간은 독서메이트 신청을 받는 기간, 활동기간은 실제 모임이 진행되는 기간이에요.\n독서메이트 모집은 조기 마감이 가능하며, 즉시 활동을 시작할 수 있어요.\n\n이 모임을 생성할까요?
띱!