Skip to content

Commit 50a10b3

Browse files
authored
Merge pull request #54 from YAPP-Github/feat/#47-goal-editor-screen
목표 생성, 편집 화면 구현
2 parents 5b518ac + c9e510a commit 50a10b3

File tree

45 files changed

+2274
-12
lines changed

Some content is hidden

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

45 files changed

+2274
-12
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ dependencies {
3636
implementation(projects.feature.login)
3737
implementation(projects.feature.main)
3838
implementation(projects.feature.taskCertification)
39+
implementation(projects.feature.goalEditor)
3940

4041
// Firebase
4142
implementation(platform(libs.google.firebase.bom))

app/src/main/java/com/yapp/twix/di/FeatureModules.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.yapp.twix.di
22

3+
import com.twix.goal_editor.di.goalEditorModule
34
import com.twix.home.di.homeModule
45
import com.twix.login.di.loginModule
56
import com.twix.main.di.mainModule
@@ -12,4 +13,5 @@ val featureModules: List<Module> =
1213
mainModule,
1314
homeModule,
1415
taskCertificationModule,
16+
goalEditorModule,
1517
)

core/design-system/src/main/java/com/twix/designsystem/components/bottomsheet/CommonBottomSheet.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fun CommonBottomSheet(
7777

7878
if (!rendering) return
7979

80-
BackHandler { onDismissRequest() }
80+
BackHandler(enabled = internalVisible) { onDismissRequest() }
8181

8282
BoxWithConstraints(
8383
modifier =
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.twix.designsystem.components.common
2+
3+
import androidx.compose.animation.core.animateFloatAsState
4+
import androidx.compose.animation.core.tween
5+
import androidx.compose.foundation.background
6+
import androidx.compose.foundation.border
7+
import androidx.compose.foundation.clickable
8+
import androidx.compose.foundation.layout.Box
9+
import androidx.compose.foundation.layout.offset
10+
import androidx.compose.foundation.layout.padding
11+
import androidx.compose.foundation.layout.size
12+
import androidx.compose.foundation.shape.CircleShape
13+
import androidx.compose.foundation.shape.RoundedCornerShape
14+
import androidx.compose.runtime.Composable
15+
import androidx.compose.runtime.getValue
16+
import androidx.compose.ui.Alignment
17+
import androidx.compose.ui.Modifier
18+
import androidx.compose.ui.draw.clip
19+
import androidx.compose.ui.platform.LocalDensity
20+
import androidx.compose.ui.unit.IntOffset
21+
import androidx.compose.ui.unit.dp
22+
import com.twix.designsystem.theme.CommonColor
23+
import com.twix.designsystem.theme.GrayColor
24+
import kotlin.math.roundToInt
25+
26+
@Composable
27+
fun CommonSwitch(
28+
modifier: Modifier = Modifier,
29+
checked: Boolean,
30+
onClick: (Boolean) -> Unit,
31+
) {
32+
val density = LocalDensity.current
33+
val minBound = with(density) { 0.dp.toPx() }
34+
val maxBound = with(density) { 18.dp.toPx() }
35+
val state by animateFloatAsState(
36+
targetValue = if (checked) maxBound else minBound,
37+
animationSpec = tween(durationMillis = 500),
38+
label = "common switch",
39+
)
40+
41+
Box(
42+
modifier =
43+
modifier
44+
.size(width = 48.dp, height = 30.dp)
45+
.clip(RoundedCornerShape(999.dp))
46+
.background(if (checked) GrayColor.C500 else CommonColor.White)
47+
.border(1.dp, GrayColor.C500, RoundedCornerShape(999.dp))
48+
.clickable(onClick = { onClick(!checked) }),
49+
contentAlignment = Alignment.CenterStart,
50+
) {
51+
Box(
52+
modifier =
53+
Modifier
54+
.offset { IntOffset(state.roundToInt(), 0) }
55+
.padding(4.dp)
56+
.size(22.dp)
57+
.clip(CircleShape)
58+
.background(if (checked) CommonColor.White else GrayColor.C500),
59+
)
60+
}
61+
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
package com.twix.designsystem.components.dialog
2+
3+
import androidx.activity.compose.BackHandler
4+
import androidx.compose.animation.AnimatedVisibility
5+
import androidx.compose.animation.core.tween
6+
import androidx.compose.animation.fadeIn
7+
import androidx.compose.animation.fadeOut
8+
import androidx.compose.foundation.BorderStroke
9+
import androidx.compose.foundation.background
10+
import androidx.compose.foundation.layout.Box
11+
import androidx.compose.foundation.layout.Column
12+
import androidx.compose.foundation.layout.ColumnScope
13+
import androidx.compose.foundation.layout.Row
14+
import androidx.compose.foundation.layout.Spacer
15+
import androidx.compose.foundation.layout.fillMaxSize
16+
import androidx.compose.foundation.layout.fillMaxWidth
17+
import androidx.compose.foundation.layout.height
18+
import androidx.compose.foundation.layout.padding
19+
import androidx.compose.foundation.layout.width
20+
import androidx.compose.foundation.shape.RoundedCornerShape
21+
import androidx.compose.material3.Surface
22+
import androidx.compose.runtime.Composable
23+
import androidx.compose.ui.Alignment
24+
import androidx.compose.ui.Modifier
25+
import androidx.compose.ui.tooling.preview.Preview
26+
import androidx.compose.ui.unit.dp
27+
import com.twix.designsystem.components.button.AppButton
28+
import com.twix.designsystem.components.text.AppText
29+
import com.twix.designsystem.theme.CommonColor
30+
import com.twix.designsystem.theme.DimmedColor
31+
import com.twix.designsystem.theme.GrayColor
32+
import com.twix.designsystem.theme.TwixTheme
33+
import com.twix.domain.model.enums.AppTextStyle
34+
import com.twix.ui.extension.noRippleClickable
35+
36+
@Composable
37+
fun CommonDialog(
38+
modifier: Modifier = Modifier,
39+
visible: Boolean,
40+
confirmText: String,
41+
dismissText: String? = null,
42+
onDismissRequest: () -> Unit,
43+
content: @Composable ColumnScope.() -> Unit,
44+
onConfirm: () -> Unit,
45+
onDismiss: (() -> Unit)? = null,
46+
) {
47+
BackHandler(enabled = visible) { onDismissRequest() }
48+
49+
Box(
50+
modifier =
51+
Modifier
52+
.fillMaxSize()
53+
.then(modifier),
54+
contentAlignment = Alignment.Center,
55+
) {
56+
DialogScrim(visible = visible, onDismissRequest = onDismissRequest)
57+
58+
DialogContent(
59+
modifier =
60+
Modifier
61+
.padding(horizontal = 20.dp)
62+
.fillMaxWidth(),
63+
visible = visible,
64+
confirmText = confirmText,
65+
dismissText = dismissText,
66+
content = content,
67+
onConfirm = onConfirm,
68+
onDismiss = onDismiss,
69+
)
70+
}
71+
}
72+
73+
@Composable
74+
private fun DialogScrim(
75+
visible: Boolean,
76+
onDismissRequest: () -> Unit,
77+
) {
78+
val fadeDuration = 160
79+
80+
AnimatedVisibility(
81+
visible = visible,
82+
enter = fadeIn(animationSpec = tween(fadeDuration)),
83+
exit = fadeOut(animationSpec = tween(fadeDuration)),
84+
modifier = Modifier.fillMaxSize(),
85+
) {
86+
Box(
87+
modifier =
88+
Modifier
89+
.fillMaxSize()
90+
.background(DimmedColor.D070)
91+
.noRippleClickable(onClick = onDismissRequest),
92+
)
93+
}
94+
}
95+
96+
@Composable
97+
private fun DialogContent(
98+
modifier: Modifier,
99+
visible: Boolean,
100+
confirmText: String,
101+
dismissText: String? = null,
102+
content: @Composable ColumnScope.() -> Unit,
103+
onConfirm: () -> Unit,
104+
onDismiss: (() -> Unit)? = null,
105+
) {
106+
val fadeDuration = 160
107+
108+
AnimatedVisibility(
109+
visible = visible,
110+
enter = fadeIn(animationSpec = tween(fadeDuration)),
111+
exit = fadeOut(animationSpec = tween(fadeDuration)),
112+
) {
113+
Surface(
114+
shape = RoundedCornerShape(20.dp),
115+
color = CommonColor.White,
116+
modifier = modifier,
117+
) {
118+
Column(
119+
modifier =
120+
Modifier
121+
.padding(horizontal = 20.dp)
122+
.padding(top = 24.dp, bottom = 20.dp),
123+
horizontalAlignment = Alignment.CenterHorizontally,
124+
) {
125+
content()
126+
127+
Spacer(Modifier.height(24.dp))
128+
129+
Row(
130+
modifier =
131+
Modifier
132+
.fillMaxWidth()
133+
.padding(vertical = 8.dp),
134+
) {
135+
if (dismissText != null && onDismiss != null) {
136+
AppButton(
137+
modifier = Modifier.weight(1f),
138+
text = dismissText,
139+
textColor = GrayColor.C500,
140+
backgroundColor = CommonColor.White,
141+
border = BorderStroke(1.dp, GrayColor.C500),
142+
onClick = onDismiss,
143+
)
144+
145+
Spacer(Modifier.width(8.dp))
146+
}
147+
148+
AppButton(
149+
modifier = Modifier.weight(1f),
150+
text = confirmText,
151+
onClick = onConfirm,
152+
)
153+
}
154+
}
155+
}
156+
}
157+
}
158+
159+
@Preview(showBackground = true, showSystemUi = true)
160+
@Composable
161+
private fun Preview() {
162+
TwixTheme {
163+
CommonDialog(
164+
visible = true,
165+
confirmText = "확인",
166+
dismissText = "취소",
167+
onDismissRequest = {},
168+
onConfirm = {},
169+
onDismiss = {},
170+
content = {
171+
AppText(
172+
text = "타이틀 텍스트",
173+
style = AppTextStyle.T1,
174+
color = GrayColor.C500,
175+
)
176+
177+
Spacer(Modifier.height(8.dp))
178+
179+
AppText(
180+
text = "내용 텍스트",
181+
style = AppTextStyle.B2,
182+
color = GrayColor.C400,
183+
)
184+
},
185+
)
186+
}
187+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.twix.designsystem.components.text_field
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Box
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.Spacer
8+
import androidx.compose.foundation.layout.fillMaxWidth
9+
import androidx.compose.foundation.layout.height
10+
import androidx.compose.foundation.layout.padding
11+
import androidx.compose.foundation.text.BasicTextField
12+
import androidx.compose.foundation.text.KeyboardActions
13+
import androidx.compose.foundation.text.KeyboardOptions
14+
import androidx.compose.material3.HorizontalDivider
15+
import androidx.compose.runtime.Composable
16+
import androidx.compose.ui.Alignment
17+
import androidx.compose.ui.Modifier
18+
import androidx.compose.ui.unit.dp
19+
import com.twix.designsystem.components.text.AppText
20+
import com.twix.designsystem.theme.GrayColor
21+
import com.twix.designsystem.theme.LocalAppTypography
22+
import com.twix.designsystem.theme.toTextStyle
23+
import com.twix.domain.model.enums.AppTextStyle
24+
25+
@Composable
26+
fun UnderlineTextField(
27+
modifier: Modifier = Modifier,
28+
value: String,
29+
placeHolder: String = "",
30+
textStyle: AppTextStyle = AppTextStyle.T2,
31+
enabled: Boolean = true,
32+
readOnly: Boolean = false,
33+
singleLine: Boolean = true,
34+
showTrailing: Boolean = false,
35+
maxLines: Int = 1,
36+
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
37+
keyboardActions: KeyboardActions = KeyboardActions.Default,
38+
trailing: (@Composable () -> Unit)? = null,
39+
onValueChange: (String) -> Unit,
40+
) {
41+
val typo = LocalAppTypography.current
42+
43+
Column(
44+
modifier =
45+
Modifier
46+
.height(52.dp),
47+
horizontalAlignment = Alignment.Start,
48+
verticalArrangement = Arrangement.Center,
49+
) {
50+
Spacer(Modifier.height(4.dp))
51+
52+
Box(
53+
modifier =
54+
modifier
55+
.padding(horizontal = 8.dp, vertical = 10.dp),
56+
contentAlignment = Alignment.CenterStart,
57+
) {
58+
val shouldShowTrailing = trailing != null && showTrailing && value.isNotBlank()
59+
60+
if (value.isBlank()) {
61+
AppText(
62+
text = placeHolder,
63+
style = textStyle,
64+
color = GrayColor.C200,
65+
modifier =
66+
Modifier
67+
.align(Alignment.CenterStart),
68+
)
69+
}
70+
71+
Row(
72+
modifier =
73+
Modifier
74+
.fillMaxWidth(),
75+
verticalAlignment = Alignment.CenterVertically,
76+
) {
77+
BasicTextField(
78+
value = value,
79+
textStyle = textStyle.toTextStyle(typo).copy(color = GrayColor.C500),
80+
onValueChange = onValueChange,
81+
enabled = enabled,
82+
readOnly = readOnly,
83+
singleLine = singleLine,
84+
maxLines = maxLines,
85+
keyboardOptions = keyboardOptions,
86+
keyboardActions = keyboardActions,
87+
)
88+
89+
if (shouldShowTrailing) {
90+
Box(
91+
modifier =
92+
Modifier
93+
.padding(start = 10.dp),
94+
contentAlignment = Alignment.Center,
95+
) {
96+
trailing.invoke()
97+
}
98+
}
99+
}
100+
}
101+
102+
Spacer(Modifier.height(4.dp))
103+
104+
HorizontalDivider(thickness = 1.dp, color = GrayColor.C500, modifier = modifier)
105+
}
106+
}

0 commit comments

Comments
 (0)