Skip to content

Commit 0a49bed

Browse files
authored
Merge pull request #21 from Nexters/feat/#15-upload-ui
Feat/#15 ν”Όλ“œ μ—…λ‘œλ“œ ν™”λ©΄ UI κ΅¬ν˜„
2 parents 57e80e6 + 61a9682 commit 0a49bed

15 files changed

Lines changed: 689 additions & 106 deletions

File tree

β€Žapp/src/main/AndroidManifest.xmlβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
android:label="@string/app_name"
1212
android:roundIcon="@mipmap/ic_launcher_round"
1313
android:supportsRtl="true"
14+
android:windowSoftInputMode="adjustResize"
1415
android:theme="@style/Theme.BuyOrNot">
1516
<activity
1617
android:name=".MainActivity"

β€Žapp/src/main/java/com/sseotdabwa/buyornot/navigation/BuyOrNotNavHost.ktβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ fun BuyOrNotNavHost(
4848

4949
// 메인 ν™”λ©΄λ“€
5050
homeScreen()
51-
uploadScreen()
51+
uploadScreen(
52+
onNavigateBack = { navController.popBackStack() },
53+
)
5254
myPageScreen()
5355
}
5456
}

β€Žapp/src/main/java/com/sseotdabwa/buyornot/ui/BuyOrNotApp.ktβ€Ž

Lines changed: 7 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,18 @@
11
package com.sseotdabwa.buyornot.ui
22

33
import androidx.compose.foundation.layout.PaddingValues
4+
import androidx.compose.foundation.layout.consumeWindowInsets
45
import androidx.compose.foundation.layout.padding
5-
import androidx.compose.material.icons.Icons
6-
import androidx.compose.material.icons.filled.AccountCircle
7-
import androidx.compose.material.icons.filled.Home
8-
import androidx.compose.material.icons.filled.UploadFile
9-
import androidx.compose.material3.Icon
10-
import androidx.compose.material3.NavigationBar
11-
import androidx.compose.material3.NavigationBarItem
126
import androidx.compose.material3.Scaffold
13-
import androidx.compose.material3.Text
147
import androidx.compose.runtime.Composable
158
import androidx.compose.runtime.getValue
169
import androidx.compose.ui.Modifier
17-
import androidx.compose.ui.graphics.vector.ImageVector
1810
import androidx.navigation.NavDestination
19-
import androidx.navigation.NavDestination.Companion.hierarchy
20-
import androidx.navigation.NavGraph.Companion.findStartDestination
21-
import androidx.navigation.NavHostController
2211
import androidx.navigation.compose.currentBackStackEntryAsState
2312
import androidx.navigation.compose.rememberNavController
13+
import com.sseotdabwa.buyornot.core.designsystem.theme.BuyOrNotTheme
2414
import com.sseotdabwa.buyornot.feature.auth.navigation.AUTH_ROUTE
2515
import com.sseotdabwa.buyornot.feature.auth.navigation.SPLASH_ROUTE
26-
import com.sseotdabwa.buyornot.feature.home.navigation.HOME_ROUTE
27-
import com.sseotdabwa.buyornot.feature.mypage.navigation.MYPAGE_ROUTE
28-
import com.sseotdabwa.buyornot.feature.upload.navigation.UPLOAD_ROUTE
2916
import com.sseotdabwa.buyornot.navigation.BuyOrNotNavHost
3017

3118
/**
@@ -44,86 +31,21 @@ import com.sseotdabwa.buyornot.navigation.BuyOrNotNavHost
4431
fun BuyOrNotApp() {
4532
val navController = rememberNavController()
4633
val navBackStackEntry by navController.currentBackStackEntryAsState()
47-
val currentRoute = navBackStackEntry?.destination?.route
4834
val currentDestination = navBackStackEntry?.destination
4935

50-
// ν•˜λ‹¨ λ°”λ₯Ό 숨길 ν™”λ©΄ λͺ©λ‘
51-
val routesWithoutBottomBar = setOf(SPLASH_ROUTE, AUTH_ROUTE)
52-
val showBottomBar = currentRoute !in routesWithoutBottomBar
53-
54-
val destinations =
55-
listOf(
56-
TopLevelDestination(route = HOME_ROUTE, label = "ν™ˆ", icon = Icons.Filled.Home),
57-
TopLevelDestination(route = UPLOAD_ROUTE, label = "μ—…λ‘œλ“œ", icon = Icons.Filled.UploadFile),
58-
TopLevelDestination(route = MYPAGE_ROUTE, label = "λ§ˆμ΄νŽ˜μ΄μ§€", icon = Icons.Filled.AccountCircle),
59-
)
60-
6136
Scaffold(
62-
bottomBar = {
63-
if (showBottomBar) {
64-
BuyOrNotBottomBar(navController = navController, destinations = destinations)
65-
}
66-
},
37+
containerColor = BuyOrNotTheme.colors.gray0,
6738
) { innerPadding ->
6839
BuyOrNotNavHost(
6940
navController = navController,
70-
modifier = Modifier.bottomBarPadding(currentDestination, innerPadding),
41+
modifier =
42+
Modifier
43+
.consumeWindowInsets(innerPadding)
44+
.bottomBarPadding(currentDestination, innerPadding),
7145
)
7246
}
7347
}
7448

75-
/**
76-
* ν•˜λ‹¨ λ„€λΉ„κ²Œμ΄μ…˜ λ°” μ»΄ν¬λ„ŒνŠΈ
77-
*
78-
* 메인 ν™”λ©΄λ“€(ν™ˆ, μ—…λ‘œλ“œ, λ§ˆμ΄νŽ˜μ΄μ§€) κ°„ 이동을 μœ„ν•œ λ„€λΉ„κ²Œμ΄μ…˜ λ°”μž…λ‹ˆλ‹€.
79-
*
80-
* @param navController λ„€λΉ„κ²Œμ΄μ…˜ 컨트둀러
81-
* @param destinations λ„€λΉ„κ²Œμ΄μ…˜ 바에 ν‘œμ‹œλ  λͺ©μ μ§€ λͺ©λ‘
82-
*/
83-
@Composable
84-
private fun BuyOrNotBottomBar(
85-
navController: NavHostController,
86-
destinations: List<TopLevelDestination>,
87-
) {
88-
val navBackStackEntry by navController.currentBackStackEntryAsState()
89-
val currentDestination = navBackStackEntry?.destination
90-
91-
NavigationBar {
92-
destinations.forEach { destination ->
93-
val selected = currentDestination?.hierarchy?.any { it.route == destination.route } == true
94-
NavigationBarItem(
95-
selected = selected,
96-
onClick = {
97-
navController.navigate(destination.route) {
98-
popUpTo(navController.graph.findStartDestination().id) {
99-
saveState = true
100-
}
101-
launchSingleTop = true
102-
restoreState = true
103-
}
104-
},
105-
icon = {
106-
Icon(imageVector = destination.icon, contentDescription = destination.label)
107-
},
108-
label = { Text(text = destination.label) },
109-
)
110-
}
111-
}
112-
}
113-
114-
/**
115-
* ν•˜λ‹¨ λ„€λΉ„κ²Œμ΄μ…˜ λ°”μ˜ λͺ©μ μ§€ 정보λ₯Ό λ‹΄λŠ” 데이터 클래슀
116-
*
117-
* @property route λ„€λΉ„κ²Œμ΄μ…˜ 라우트
118-
* @property label 화면에 ν‘œμ‹œλ  λ ˆμ΄λΈ”
119-
* @property icon λ„€λΉ„κ²Œμ΄μ…˜ μ•„μ΄ν…œ μ•„μ΄μ½˜
120-
*/
121-
private data class TopLevelDestination(
122-
val route: String,
123-
val label: String,
124-
val icon: ImageVector,
125-
)
126-
12749
/**
12850
* νŠΉμ • ν™”λ©΄(μŠ€ν”Œλž˜μ‹œ, 둜그인)μ—μ„œλŠ” μ‹œμŠ€ν…œ νŒ¨λ”©μ„ μ œκ±°ν•˜λŠ” ν™•μž₯ ν•¨μˆ˜
12951
*

β€Žcore/designsystem/src/main/java/com/sseotdabwa/buyornot/core/designsystem/components/AlertDialog.ktβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fun BuyOrNotAlertDialog(
4343
Column(
4444
modifier =
4545
Modifier
46-
.padding(horizontal = 28.dp)
46+
.padding(horizontal = 18.dp)
4747
.padding(top = 26.dp, bottom = 16.dp),
4848
) {
4949
Column(
@@ -60,7 +60,7 @@ fun BuyOrNotAlertDialog(
6060
Text(
6161
text = subText,
6262
style = BuyOrNotTheme.typography.bodyB3Medium,
63-
color = BuyOrNotTheme.colors.gray500, // μ‹œμ•ˆμ˜ νλ¦Ών•œ ν…μŠ€νŠΈ 색상
63+
color = BuyOrNotTheme.colors.gray700,
6464
)
6565
}
6666

β€Žcore/designsystem/src/main/java/com/sseotdabwa/buyornot/core/designsystem/components/BottomSheet.ktβ€Ž

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import androidx.compose.runtime.setValue
3131
import androidx.compose.ui.Alignment
3232
import androidx.compose.ui.Modifier
3333
import androidx.compose.ui.graphics.Color
34+
import androidx.compose.ui.graphics.Shape
3435
import androidx.compose.ui.platform.LocalDensity
3536
import androidx.compose.ui.platform.LocalWindowInfo
3637
import androidx.compose.ui.tooling.preview.Preview
@@ -61,6 +62,7 @@ import kotlinx.coroutines.launch
6162
fun BuyOrNotBottomSheet(
6263
onDismissRequest: () -> Unit,
6364
isHalfExpandedOnly: Boolean = false,
65+
sheetShape: Shape = RoundedCornerShape(26.dp),
6466
sheetState: SheetState =
6567
rememberModalBottomSheetState(
6668
skipPartiallyExpanded = true,
@@ -86,9 +88,10 @@ fun BuyOrNotBottomSheet(
8688
modifier =
8789
Modifier
8890
.padding(horizontal = 14.dp),
91+
// κΈ°μ‘΄ ν•˜λ‹¨ νŒ¨λ”© 제거?
8992
sheetState = sheetState,
90-
shape = RoundedCornerShape(26.dp),
91-
containerColor = Color.Transparent,
93+
shape = sheetShape,
94+
containerColor = Color.Transparent, // λ°°κ²½ 투λͺ…ν•˜κ²Œ -> Spacer
9295
tonalElevation = 0.dp,
9396
scrimColor = BuyOrNotTheme.colors.gray1000.copy(alpha = 0.5f),
9497
dragHandle = null,
@@ -103,7 +106,7 @@ fun BuyOrNotBottomSheet(
103106
.fillMaxWidth()
104107
.background(
105108
color = BuyOrNotTheme.colors.gray0,
106-
shape = RoundedCornerShape(26.dp),
109+
shape = sheetShape,
107110
).then(
108111
if (isHalfExpandedOnly) {
109112
Modifier.heightIn(max = screenHeight / 2f)
@@ -139,6 +142,7 @@ fun BuyOrNotBottomSheet(
139142
Spacer(
140143
modifier =
141144
Modifier
145+
.fillMaxWidth()
142146
.navigationBarsPadding() // μ‹œμŠ€ν…œ λ„€λΉ„κ²Œμ΄μ…˜ λ°” λŒ€μ‘
143147
.height(20.dp), // ν•˜λ‹¨μ—μ„œ λ„μš°κ³  싢은 만큼 높이 μ„€μ •
144148
)

β€Žcore/designsystem/src/main/java/com/sseotdabwa/buyornot/core/designsystem/components/ExpandableFab.ktβ€Ž

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import androidx.compose.runtime.remember
2828
import androidx.compose.runtime.setValue
2929
import androidx.compose.ui.Alignment
3030
import androidx.compose.ui.Modifier
31-
import androidx.compose.ui.draw.rotate
3231
import androidx.compose.ui.graphics.Color
32+
import androidx.compose.ui.graphics.graphicsLayer
3333
import androidx.compose.ui.graphics.vector.ImageVector
3434
import androidx.compose.ui.tooling.preview.Preview
3535
import androidx.compose.ui.unit.dp
@@ -93,7 +93,9 @@ fun ExpandableFloatingActionButton(
9393
modifier =
9494
Modifier
9595
.size(24.dp)
96-
.rotate(rotationAngle),
96+
.graphicsLayer {
97+
rotationZ = rotationAngle
98+
},
9799
)
98100
}
99101
}

β€Žcore/designsystem/src/main/java/com/sseotdabwa/buyornot/core/designsystem/components/OptionSheet.ktβ€Ž

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
1212
import androidx.compose.foundation.layout.height
1313
import androidx.compose.foundation.layout.padding
1414
import androidx.compose.foundation.lazy.LazyColumn
15+
import androidx.compose.foundation.shape.RoundedCornerShape
1516
import androidx.compose.material3.ExperimentalMaterial3Api
1617
import androidx.compose.material3.Icon
1718
import androidx.compose.material3.Text
@@ -22,8 +23,10 @@ import androidx.compose.runtime.remember
2223
import androidx.compose.runtime.setValue
2324
import androidx.compose.ui.Alignment
2425
import androidx.compose.ui.Modifier
26+
import androidx.compose.ui.draw.clip
2527
import androidx.compose.ui.graphics.Brush
2628
import androidx.compose.ui.graphics.Color
29+
import androidx.compose.ui.graphics.Shape
2730
import androidx.compose.ui.tooling.preview.Preview
2831
import androidx.compose.ui.unit.dp
2932
import com.sseotdabwa.buyornot.core.designsystem.icon.BuyOrNotIcons
@@ -44,14 +47,18 @@ fun OptionSheet(
4447
title: String,
4548
options: List<String>,
4649
selectedOption: String? = null,
50+
sheetShape: Shape = RoundedCornerShape(26.dp),
4751
onOptionClick: (String) -> Unit,
4852
onDismissRequest: () -> Unit,
4953
) {
5054
BuyOrNotBottomSheet(
5155
onDismissRequest = onDismissRequest,
5256
isHalfExpandedOnly = true,
57+
sheetShape = sheetShape,
5358
) { hideSheet ->
54-
Box {
59+
Box(
60+
modifier = Modifier.clip(sheetShape),
61+
) {
5562
Column(
5663
modifier =
5764
Modifier
@@ -104,7 +111,7 @@ fun OptionSheet(
104111
colors =
105112
listOf(
106113
Color.Transparent, // μ‹œμž‘μ  (μœ„): 투λͺ…
107-
Color.White, // 끝점 (μ•„λž˜): 흰색
114+
BuyOrNotTheme.colors.gray0, // 끝점 (μ•„λž˜): 배경색
108115
),
109116
),
110117
),

β€Žcore/designsystem/src/main/java/com/sseotdabwa/buyornot/core/designsystem/icon/BuyOrNotIcons.ktβ€Ž

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,15 @@ object BuyOrNotIcons {
4040

4141
// κΈ°λŠ₯ μ•„μ΄μ½˜
4242
val CheckCircle = IconResource(R.drawable.ic_check_circle)
43+
val Camera = IconResource(R.drawable.ic_camera)
4344
val Vote = IconResource(R.drawable.ic_vote)
4445
val VoteDone = IconResource(R.drawable.ic_vote_done)
4546
val Bag = IconResource(R.drawable.ic_bag)
4647
val Profile = IconResource(R.drawable.ic_profile)
4748
val Notification = IconResource(R.drawable.ic_notification)
4849
val NotificationFilled = IconResource(R.drawable.ic_notification_filled)
50+
51+
val Won = IconResource(R.drawable.ic_won)
4952
}
5053

5154
/**
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.sseotdabwa.buyornot.core.designsystem.shape
2+
3+
import androidx.compose.ui.geometry.CornerRadius
4+
import androidx.compose.ui.geometry.Rect
5+
import androidx.compose.ui.geometry.RoundRect
6+
import androidx.compose.ui.geometry.Size
7+
import androidx.compose.ui.graphics.Outline
8+
import androidx.compose.ui.graphics.Path
9+
import androidx.compose.ui.graphics.Shape
10+
import androidx.compose.ui.unit.Density
11+
import androidx.compose.ui.unit.Dp
12+
import androidx.compose.ui.unit.LayoutDirection
13+
14+
class BubbleShape(
15+
private val cornerRadius: Dp,
16+
private val arrowWidth: Dp,
17+
private val arrowHeight: Dp,
18+
) : Shape {
19+
override fun createOutline(
20+
size: Size,
21+
layoutDirection: LayoutDirection,
22+
density: Density,
23+
): Outline =
24+
Outline.Generic(
25+
Path().apply {
26+
val cornerRadiusPx = with(density) { cornerRadius.toPx() }
27+
val arrowWidthPx = with(density) { arrowWidth.toPx() }
28+
val arrowHeightPx = with(density) { arrowHeight.toPx() }
29+
30+
// 말풍선 본체 μ‚¬κ°ν˜• (였λ₯Έμͺ½ ν™”μ‚΄ν‘œ μ˜μ—­ μ œμ™Έ)
31+
addRoundRect(
32+
RoundRect(
33+
rect = Rect(0f, 0f, size.width - arrowWidthPx, size.height),
34+
cornerRadius = CornerRadius(cornerRadiusPx),
35+
),
36+
)
37+
38+
// 였λ₯Έμͺ½ 쀑앙에 μ‚Όκ°ν˜• 꼬리 μΆ”κ°€
39+
moveTo(size.width - arrowWidthPx, size.height / 2 - arrowHeightPx / 2)
40+
lineTo(size.width, size.height / 2)
41+
lineTo(size.width - arrowWidthPx, size.height / 2 + arrowHeightPx / 2)
42+
close()
43+
},
44+
)
45+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="20dp"
3+
android:height="20dp"
4+
android:viewportWidth="20"
5+
android:viewportHeight="20">
6+
<path
7+
android:pathData="M12.295,1.231C12.672,1.231 12.862,1.231 13.019,1.256C13.871,1.393 14.539,2.062 14.676,2.914C14.701,3.071 14.702,3.26 14.702,3.637C14.702,3.71 14.76,3.769 14.833,3.769C16.928,3.77 18.003,3.789 18.764,4.342C19.018,4.527 19.242,4.751 19.427,5.005C20,5.794 20,6.92 20,9.169V13.369C20,15.618 20,16.744 19.427,17.533C19.242,17.787 19.018,18.011 18.764,18.196C17.975,18.769 16.849,18.769 14.6,18.769H5.4C3.151,18.769 2.025,18.769 1.236,18.196C0.982,18.011 0.758,17.787 0.573,17.533C0,16.744 0,15.618 0,13.369V9.169C0,6.92 0,5.794 0.573,5.005C0.758,4.751 0.982,4.527 1.236,4.342C1.997,3.79 3.072,3.77 5.166,3.769C5.239,3.769 5.299,3.71 5.299,3.637C5.299,3.26 5.299,3.071 5.324,2.914C5.461,2.062 6.129,1.393 6.98,1.256C7.138,1.231 7.328,1.231 7.705,1.231H12.295ZM10,7.418C7.791,7.418 6,9.209 6,11.418C6,13.628 7.791,15.418 10,15.418C12.209,15.418 14,13.628 14,11.418C14,9.209 12.209,7.418 10,7.418ZM10,9.418C11.104,9.418 12,10.314 12,11.418C12,12.523 11.105,13.418 10,13.418C8.895,13.418 8,12.523 8,11.418C8,10.314 8.896,9.418 10,9.418ZM14.25,6.489C13.755,6.489 13.354,6.891 13.354,7.386C13.354,7.881 13.755,8.282 14.25,8.283C14.745,8.283 15.147,7.882 15.148,7.386C15.148,6.891 14.745,6.489 14.25,6.489Z"
8+
android:fillColor="#2A3038"/>
9+
</vector>

0 commit comments

Comments
Β (0)