Skip to content

Commit e3536fb

Browse files
authored
Merge pull request #39 from rbqks529/ui/#35-group_mygroup
[UI] 모임방 만들기 페이지 구현 완료
2 parents a2fbbe8 + 5bfd72d commit e3536fb

34 files changed

Lines changed: 2289 additions & 104 deletions

.idea/deviceManager.xml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package com.texthip.thip.ui.common.bottomsheet
2+
3+
4+
import androidx.compose.animation.core.Animatable
5+
import androidx.compose.animation.core.tween
6+
import androidx.compose.foundation.background
7+
import androidx.compose.foundation.clickable
8+
import androidx.compose.foundation.gestures.detectVerticalDragGestures
9+
import androidx.compose.foundation.interaction.MutableInteractionSource
10+
import androidx.compose.foundation.layout.*
11+
import androidx.compose.foundation.shape.RoundedCornerShape
12+
import androidx.compose.material3.Button
13+
import androidx.compose.material3.Text
14+
import androidx.compose.runtime.*
15+
import androidx.compose.ui.Alignment
16+
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.graphics.Color
18+
import androidx.compose.ui.input.pointer.pointerInput
19+
import androidx.compose.ui.tooling.preview.Preview
20+
import androidx.compose.ui.unit.dp
21+
import androidx.compose.ui.zIndex
22+
import com.texthip.thip.ui.theme.ThipTheme
23+
import com.texthip.thip.ui.theme.ThipTheme.colors
24+
import kotlinx.coroutines.launch
25+
26+
@Composable
27+
fun CustomBottomSheet(
28+
onDismiss: () -> Unit,
29+
content: @Composable ColumnScope.() -> Unit
30+
) {
31+
val scope = rememberCoroutineScope()
32+
val animatableOffset = remember { Animatable(300f) }
33+
var offsetY by remember { mutableFloatStateOf(0f) }
34+
var isDismissing by remember { mutableStateOf(false) }
35+
36+
// 등장 애니메이션
37+
LaunchedEffect(Unit) {
38+
animatableOffset.animateTo(
39+
targetValue = 0f,
40+
animationSpec = tween(durationMillis = 300)
41+
)
42+
}
43+
44+
// 바깥 클릭 감지
45+
Box(
46+
modifier = Modifier
47+
.fillMaxSize()
48+
.clickable(
49+
indication = null,
50+
interactionSource = remember { MutableInteractionSource() }
51+
) {
52+
if (!isDismissing) {
53+
isDismissing = true
54+
scope.launch {
55+
animatableOffset.animateTo(300f, tween(300))
56+
onDismiss()
57+
}
58+
}
59+
}
60+
.zIndex(1f)
61+
)
62+
63+
// BottomSheet 본체
64+
Box(
65+
modifier = Modifier
66+
.fillMaxSize()
67+
.zIndex(2f),
68+
contentAlignment = Alignment.BottomCenter
69+
) {
70+
Box(
71+
modifier = Modifier
72+
.fillMaxWidth()
73+
.offset(y = (offsetY + animatableOffset.value).dp)
74+
.background(
75+
color = colors.DarkGrey,
76+
shape = RoundedCornerShape(topEnd = 12.dp, topStart = 12.dp)
77+
)
78+
.pointerInput(Unit) {
79+
detectVerticalDragGestures(
80+
onVerticalDrag = { _, dragAmount ->
81+
if (dragAmount > 0) {
82+
offsetY += dragAmount / 2
83+
}
84+
},
85+
onDragEnd = {
86+
if (offsetY > 100f && !isDismissing) {
87+
isDismissing = true
88+
scope.launch {
89+
animatableOffset.animateTo(300f, tween(300))
90+
onDismiss()
91+
}
92+
} else {
93+
offsetY = 0f
94+
}
95+
}
96+
)
97+
}
98+
.clickable(enabled = true) {}
99+
) {
100+
Column(modifier = Modifier.fillMaxWidth()) {
101+
content()
102+
}
103+
}
104+
}
105+
}
106+
107+
108+
@Preview()
109+
@Composable
110+
fun PreviewCustomBottomSheet() {
111+
var showSheet by remember { mutableStateOf(true) }
112+
113+
ThipTheme {
114+
Box(Modifier.fillMaxSize()) {
115+
Text(
116+
text = "Main Content Area",
117+
color = Color.White,
118+
modifier = Modifier
119+
.align(Alignment.Center)
120+
)
121+
122+
if (showSheet) {
123+
CustomBottomSheet(
124+
onDismiss = { showSheet = false }
125+
) {
126+
Text(
127+
"바텀 시트 예시",
128+
color = Color.White,
129+
modifier = Modifier.padding(bottom = 16.dp)
130+
)
131+
Button(
132+
onClick = { showSheet = false },
133+
modifier = Modifier.fillMaxWidth()
134+
) {
135+
Text("닫기", color = Color.Black)
136+
}
137+
}
138+
}
139+
}
140+
}
141+
}

app/src/main/java/com/texthip/thip/ui/group/myroom/component/GenreChipRow.kt renamed to app/src/main/java/com/texthip/thip/ui/common/buttons/GenreChipRow.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
1-
package com.texthip.thip.ui.group.myroom.component
1+
package com.texthip.thip.ui.common.buttons
22

3-
import androidx.compose.foundation.layout.Arrangement
4-
import androidx.compose.foundation.layout.Row
5-
import androidx.compose.foundation.layout.fillMaxWidth
3+
import androidx.compose.foundation.layout.*
64
import androidx.compose.runtime.Composable
75
import androidx.compose.ui.Modifier
86
import androidx.compose.ui.tooling.preview.Preview
9-
import com.texthip.thip.ui.common.buttons.OptionChipButton
7+
import androidx.compose.ui.unit.dp
108

119
@Composable
1210
fun GenreChipRow(
11+
modifier: Modifier = Modifier.width(4.dp),
1312
genres: List<String>,
1413
selectedIndex: Int,
1514
onSelect: (Int) -> Unit
1615
) {
1716
Row(
18-
Modifier.fillMaxWidth(),
19-
horizontalArrangement = Arrangement.SpaceEvenly
17+
modifier = Modifier.fillMaxWidth(),
18+
horizontalArrangement = Arrangement.Center
2019
) {
2120
genres.forEachIndexed { idx, genre ->
2221
OptionChipButton(
@@ -25,6 +24,9 @@ fun GenreChipRow(
2524
isSelected = selectedIndex == idx,
2625
onClick = { onSelect(idx) }
2726
)
27+
if (idx < genres.size - 1) {
28+
Spacer(modifier = modifier)
29+
}
2830
}
2931
}
3032
}
@@ -37,4 +39,4 @@ fun PreviewGenreChipRow() {
3739
selectedIndex = 0,
3840
onSelect = {}
3941
)
40-
}
42+
}

app/src/main/java/com/texthip/thip/ui/common/cards/CardBookSearch.kt

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,16 @@ import com.texthip.thip.ui.theme.ThipTheme.typography
2828
@Composable
2929
fun CardBookSearch(
3030
modifier: Modifier = Modifier,
31-
number: Int,
3231
title: String,
3332
imageRes: Int? = R.drawable.bookcover_sample, // 기본 이미지 리소스
3433
onClick: () -> Unit = {}
3534
) {
3635
Row(
3736
modifier = modifier
3837
.fillMaxWidth()
39-
.clickable { onClick() }
40-
.padding(vertical = 8.dp),
38+
.clickable { onClick() },
4139
verticalAlignment = Alignment.CenterVertically
4240
) {
43-
// 넘버
44-
Text(
45-
text = "$number.",
46-
style = typography.menu_m500_s16_h24,
47-
color = colors.White,
48-
modifier = Modifier.padding(end = 12.dp)
49-
)
50-
5141
// 이미지
5242
Box(
5343
modifier = Modifier
@@ -84,7 +74,6 @@ fun CardBookSearchPreview() {
8474
verticalArrangement = Arrangement.spacedBy(8.dp)
8575
) {
8676
CardBookSearch(
87-
number = 1,
8877
title = "단 한번의 삶"
8978
)
9079
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package com.texthip.thip.ui.common.forms
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Box
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.Spacer
8+
import androidx.compose.foundation.layout.fillMaxSize
9+
import androidx.compose.foundation.layout.fillMaxWidth
10+
import androidx.compose.foundation.layout.height
11+
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.layout.size
13+
import androidx.compose.foundation.layout.width
14+
import androidx.compose.foundation.shape.RoundedCornerShape
15+
import androidx.compose.material3.Icon
16+
import androidx.compose.material3.OutlinedTextField
17+
import androidx.compose.material3.Text
18+
import androidx.compose.material3.TextFieldDefaults
19+
import androidx.compose.runtime.Composable
20+
import androidx.compose.runtime.getValue
21+
import androidx.compose.runtime.mutableStateOf
22+
import androidx.compose.runtime.saveable.rememberSaveable
23+
import androidx.compose.runtime.setValue
24+
import androidx.compose.ui.Alignment
25+
import androidx.compose.ui.Modifier
26+
import androidx.compose.ui.graphics.Color
27+
import androidx.compose.ui.res.painterResource
28+
import androidx.compose.ui.tooling.preview.Preview
29+
import androidx.compose.ui.unit.dp
30+
import androidx.compose.ui.unit.sp
31+
import com.texthip.thip.R
32+
import com.texthip.thip.ui.theme.ThipTheme.colors
33+
import com.texthip.thip.ui.theme.ThipTheme.typography
34+
35+
@Composable
36+
fun SearchBookTextField(
37+
modifier: Modifier = Modifier,
38+
hint: String,
39+
onSearch: (String) -> Unit = {}
40+
) {
41+
var text by rememberSaveable { mutableStateOf("") }
42+
val myStyle = typography.menu_r400_s14_h24.copy(lineHeight = 14.sp)
43+
44+
Box(
45+
modifier = modifier.height(48.dp)
46+
) {
47+
OutlinedTextField(
48+
value = text,
49+
onValueChange = {
50+
text = it
51+
},
52+
placeholder = {
53+
Text(
54+
text = hint,
55+
color = colors.Grey02,
56+
style = myStyle
57+
)
58+
},
59+
textStyle = myStyle,
60+
modifier = Modifier.fillMaxSize(),
61+
shape = RoundedCornerShape(12.dp),
62+
colors = TextFieldDefaults.colors(
63+
focusedTextColor = colors.White,
64+
focusedIndicatorColor = Color.Transparent,
65+
unfocusedIndicatorColor = Color.Transparent,
66+
focusedContainerColor = colors.DarkGrey02,
67+
unfocusedContainerColor = colors.DarkGrey02,
68+
cursorColor = colors.NeonGreen
69+
),
70+
trailingIcon = {
71+
Row(
72+
horizontalArrangement = Arrangement.Center
73+
) {
74+
Icon(
75+
painter = painterResource(id = R.drawable.ic_x_circle_grey),
76+
contentDescription = "Clear text",
77+
modifier = Modifier
78+
.clickable { text = "" },
79+
tint = Color.Unspecified
80+
)
81+
82+
Spacer(Modifier.width(20.dp))
83+
Icon(
84+
painter = painterResource(id = R.drawable.ic_search),
85+
contentDescription = "Search",
86+
modifier = Modifier
87+
.clickable { onSearch(text) },
88+
tint = colors.White
89+
)
90+
Spacer(Modifier.width(8.dp))
91+
}
92+
},
93+
singleLine = true
94+
)
95+
}
96+
}
97+
98+
@Preview()
99+
@Composable
100+
private fun SearchBookTextFieldPreview() {
101+
SearchBookTextField(
102+
hint = "책 제목, 저자검색",
103+
onSearch = { /* 검색 실행 */ }
104+
)
105+
}

0 commit comments

Comments
 (0)