diff --git a/core/src/main/java/com/terning/core/designsystem/textfield/NameTextField.kt b/core/src/main/java/com/terning/core/designsystem/textfield/NameTextField.kt new file mode 100644 index 000000000..6b5a9ec9a --- /dev/null +++ b/core/src/main/java/com/terning/core/designsystem/textfield/NameTextField.kt @@ -0,0 +1,37 @@ +package com.terning.core.designsystem.textfield + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import com.terning.core.designsystem.theme.Black +import com.terning.core.designsystem.theme.Grey300 +import com.terning.core.designsystem.theme.Grey400 +import com.terning.core.designsystem.theme.Grey500 +import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.TerningTheme + +@Composable +fun NameTextField( + text: String, + onValueChange: (String) -> Unit, + hint: String, + helperMessage: String, + helperIcon: Int? = null, + helperColor: Color = TerningMain, +) { + TerningBasicTextField( + value = text, + onValueChange = onValueChange, + textStyle = TerningTheme.typography.detail1, + textColor = Black, + drawLineColor = Grey500, + cursorBrush = SolidColor(Grey400), + hint = hint, + hintColor = Grey300, + showTextLength = true, + maxTextLength = 12, + helperMessage = helperMessage, + helperIcon = helperIcon, + helperColor = helperColor, + ) +} \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/textfield/SearchTextField.kt b/core/src/main/java/com/terning/core/designsystem/textfield/SearchTextField.kt new file mode 100644 index 000000000..aad31e85d --- /dev/null +++ b/core/src/main/java/com/terning/core/designsystem/textfield/SearchTextField.kt @@ -0,0 +1,29 @@ +package com.terning.core.designsystem.textfield + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.SolidColor +import com.terning.core.designsystem.theme.Grey300 +import com.terning.core.designsystem.theme.Grey400 +import com.terning.core.designsystem.theme.TerningTheme + +@Composable +fun SearchTextField( + text: String, + onValueChange: (String) -> Unit, + hint: String, + leftIcon: Int, +) { + TerningBasicTextField( + value = text, + onValueChange = onValueChange, + textStyle = TerningTheme.typography.button3, + textColor = Grey400, + cursorBrush = SolidColor(Grey300), + drawLineColor = Grey300, + strokeWidth = 2f, + hint = hint, + hintColor = Grey300, + leftIcon = leftIcon, + leftIconColor = Grey400, + ) +} \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/textfield/TerningBasicTextField.kt b/core/src/main/java/com/terning/core/designsystem/textfield/TerningBasicTextField.kt new file mode 100644 index 000000000..d100f999f --- /dev/null +++ b/core/src/main/java/com/terning/core/designsystem/textfield/TerningBasicTextField.kt @@ -0,0 +1,134 @@ +package com.terning.core.designsystem.textfield + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Grey300 +import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White + +@Composable +fun TerningBasicTextField( + value: String, + onValueChange: (String) -> Unit, + textStyle: TextStyle, + textColor: Color, + hintColor: Color, + drawLineColor: Color, + helperColor: Color, + cursorBrush: Brush, + strokeWidth: Float = 1f, + leftIcon: Int? = null, + leftIconColor: Color = TerningMain, + maxTextLength: Int? = null, + showTextLength: Boolean = false, + hint: String = "", + helperMessage: String = "", + helperIcon: Int? = null, +) { + val keyboardController = LocalSoftwareKeyboardController.current + val focusManager = LocalFocusManager.current + + BasicTextField(value = value, + onValueChange = onValueChange, + singleLine = true, + maxLines = 1, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions(onDone = { + keyboardController?.hide() + focusManager.clearFocus() + }), + + modifier = Modifier + .fillMaxWidth() + .background(White) + .drawWithContent { + val canvasWidth = size.width + val canvasHeight = size.height + + drawContent() + drawLine( + color = drawLineColor, + start = Offset(x = 0f, y = canvasHeight), + end = Offset(x = canvasWidth, y = canvasHeight), + strokeWidth = strokeWidth.dp.toPx(), + ) + }, + + textStyle = textStyle.copy(color = textColor), + cursorBrush = cursorBrush, + + decorationBox = { innerTextField -> + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp), + modifier = Modifier.padding(vertical = 8.dp) + ) { + leftIcon?.let { + Icon( + painter = painterResource(id = it), + contentDescription = null, + tint = leftIconColor, + ) + } + Box(modifier = Modifier.weight(1f)) { + if (value.isEmpty()) { + Text( + text = hint, + style = textStyle, + color = hintColor + ) + } + innerTextField() + } + if (showTextLength && maxTextLength != null) { + Text( + text = "${value.length}/$maxTextLength", + style = TerningTheme.typography.button3, + color = Grey300, + ) + } + } + }) + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier.padding(vertical = 8.dp) + ) { + helperIcon?.let { + Icon( + painter = painterResource(id = it), + contentDescription = null, + tint = helperColor, + ) + } + Text( + text = helperMessage, + style = TerningTheme.typography.detail3, + color = helperColor, + ) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/topappbar/BackButtonTopAppBar.kt b/core/src/main/java/com/terning/core/designsystem/topappbar/BackButtonTopAppBar.kt index aeb7f1b00..8088fcab1 100644 --- a/core/src/main/java/com/terning/core/designsystem/topappbar/BackButtonTopAppBar.kt +++ b/core/src/main/java/com/terning/core/designsystem/topappbar/BackButtonTopAppBar.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.Composable fun BackButtonTopAppBar( title: String, onBackButtonClick: (() -> Unit), ) { - TerningTopAppBar( + TerningBasicTopAppBar( title = title, showBackButton = true, onBackButtonClick = { onBackButtonClick.invoke() }, diff --git a/core/src/main/java/com/terning/core/designsystem/topappbar/LogoTopAppBar.kt b/core/src/main/java/com/terning/core/designsystem/topappbar/LogoTopAppBar.kt index a5b6e68e5..c3a799393 100644 --- a/core/src/main/java/com/terning/core/designsystem/topappbar/LogoTopAppBar.kt +++ b/core/src/main/java/com/terning/core/designsystem/topappbar/LogoTopAppBar.kt @@ -8,7 +8,7 @@ import com.terning.core.R @Composable fun LogoTopAppBar() { - TerningTopAppBar( + TerningBasicTopAppBar( showBackButton = false, actions = listOf { Icon( diff --git a/core/src/main/java/com/terning/core/designsystem/topappbar/MyPageTopAppBar.kt b/core/src/main/java/com/terning/core/designsystem/topappbar/MyPageTopAppBar.kt index 295c5aabd..4afb62bc3 100644 --- a/core/src/main/java/com/terning/core/designsystem/topappbar/MyPageTopAppBar.kt +++ b/core/src/main/java/com/terning/core/designsystem/topappbar/MyPageTopAppBar.kt @@ -10,11 +10,11 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import com.terning.core.R -import com.terning.core.designsystem.theme.TerningTypography +import com.terning.core.designsystem.theme.TerningTheme @Composable fun MyPageTopAppBar() { - TerningTopAppBar( + TerningBasicTopAppBar( showBackButton = false, actions = listOf( {}, @@ -24,7 +24,7 @@ fun MyPageTopAppBar() { ) { Text( text = stringResource(id = R.string.my_page_top_app_bar), - style = TerningTypography().button3, + style = TerningTheme.typography.button3, textAlign = TextAlign.Center ) IconButton(onClick = { diff --git a/core/src/main/java/com/terning/core/designsystem/topappbar/TerningTopAppBar.kt b/core/src/main/java/com/terning/core/designsystem/topappbar/TerningBasicTopAppBar.kt similarity index 82% rename from core/src/main/java/com/terning/core/designsystem/topappbar/TerningTopAppBar.kt rename to core/src/main/java/com/terning/core/designsystem/topappbar/TerningBasicTopAppBar.kt index 0e164edc5..e1d5708df 100644 --- a/core/src/main/java/com/terning/core/designsystem/topappbar/TerningTopAppBar.kt +++ b/core/src/main/java/com/terning/core/designsystem/topappbar/TerningBasicTopAppBar.kt @@ -1,24 +1,20 @@ package com.terning.core.designsystem.topappbar -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import com.terning.core.R -import com.terning.core.designsystem.theme.TerningTypography +import com.terning.core.designsystem.theme.TerningTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun TerningTopAppBar( +fun TerningBasicTopAppBar( title: String = "", showBackButton: Boolean = false, actions: List<@Composable () -> Unit> = emptyList(), @@ -30,7 +26,7 @@ fun TerningTopAppBar( Text( text = title, textAlign = TextAlign.Center, - style = TerningTypography().title2 + style = TerningTheme.typography.title2 ) }, diff --git a/feature/src/main/AndroidManifest.xml b/feature/src/main/AndroidManifest.xml index 1e31d319a..f136894fe 100644 --- a/feature/src/main/AndroidManifest.xml +++ b/feature/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ android:exported="true" android:label="@string/app_name" android:screenOrientation="portrait" + android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.TerningAndroid"> diff --git a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt index beb7b7920..68d33fb38 100644 --- a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt +++ b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt @@ -13,6 +13,7 @@ import com.terning.feature.calendar.navigation.navigateCalendar import com.terning.feature.home.navigation.navigateHome import com.terning.feature.mypage.navigation.navigateMyPage import com.terning.feature.onboarding.signin.navigation.SignIn +import com.terning.feature.search.navigation.Search import com.terning.feature.search.navigation.navigateSearch class MainNavigator( diff --git a/feature/src/main/java/com/terning/feature/main/MainScreen.kt b/feature/src/main/java/com/terning/feature/main/MainScreen.kt index 9d51ef625..38cdf8283 100644 --- a/feature/src/main/java/com/terning/feature/main/MainScreen.kt +++ b/feature/src/main/java/com/terning/feature/main/MainScreen.kt @@ -21,10 +21,9 @@ import androidx.navigation.compose.NavHost import com.terning.core.designsystem.theme.Grey300 import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.White -import com.terning.core.designsystem.topappbar.BackButtonTopAppBar import com.terning.core.designsystem.topappbar.LogoTopAppBar import com.terning.core.designsystem.topappbar.MyPageTopAppBar -import com.terning.core.designsystem.topappbar.TerningTopAppBar +import com.terning.core.designsystem.topappbar.TerningBasicTopAppBar import com.terning.feature.calendar.navigation.calendarNavGraph import com.terning.feature.home.navigation.homeNavGraph import com.terning.feature.mypage.navigation.myPageNavGraph @@ -42,13 +41,10 @@ fun MainScreen( topBar = { when (navigator.currentTab) { MainTab.HOME -> LogoTopAppBar() - MainTab.CALENDAR -> BackButtonTopAppBar( - title = "dkssud", - onBackButtonClick = { navigator.navigateUp() }) - + MainTab.CALENDAR -> TerningBasicTopAppBar() MainTab.SEARCH -> LogoTopAppBar() MainTab.MY_PAGE -> MyPageTopAppBar() - null -> TerningTopAppBar() + null -> TerningBasicTopAppBar() } }, bottomBar = { @@ -80,6 +76,21 @@ fun MainScreen( } } + + +@Composable +private fun MainTopBar( + isVisible: Boolean, + tabs: List, + currentTab: MainTab?, + onTabSelected: (MainTab) -> Unit, +) { + AnimatedVisibility( + visible = isVisible, + ) { + } +} + @Composable private fun MainBottomBar( isVisible: Boolean, diff --git a/feature/src/main/java/com/terning/feature/search/SearchRoute.kt b/feature/src/main/java/com/terning/feature/search/SearchRoute.kt index 3ba7af3d4..734ea415d 100644 --- a/feature/src/main/java/com/terning/feature/search/SearchRoute.kt +++ b/feature/src/main/java/com/terning/feature/search/SearchRoute.kt @@ -1,13 +1,25 @@ package com.terning.feature.search +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Scaffold -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.setValue import androidx.compose.ui.Modifier -import com.terning.core.designsystem.topappbar.LogoTopAppBar +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.textfield.NameTextField +import com.terning.core.designsystem.textfield.SearchTextField +import com.terning.core.designsystem.theme.Grey400 +import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.WarningRed +import com.terning.feature.R @Composable fun SearchRoute() { @@ -15,11 +27,63 @@ fun SearchRoute() { } @Composable -fun SearchScreen(modifier: Modifier = Modifier) { +fun SearchScreen() { + var text by remember { mutableStateOf("") } + + // TODO 프로필 스크린 TextField로, 삭제될 코드입니다 + var helperMessage by remember { mutableStateOf(R.string.profile_text_field_helper) } + var helperIcon by remember { mutableStateOf(null) } + var helperColor by remember { mutableStateOf(Grey400) } + val specialCharacterPattern = Regex("[!@#\$%^&*(),.?\":{}|<>\\[\\]\\\\/]") + + // TODO 프로필 스크린 TextField로, 삭제될 코드입니다 + fun updateHelper(text: String) { + helperMessage = when { + text.isEmpty() -> R.string.profile_text_field_helper + specialCharacterPattern.containsMatchIn(text) -> R.string.profile_text_field_warning + text.length <= 12 -> R.string.profile_text_field_check + else -> R.string.profile_text_field_helper + } + helperIcon = when { + text.isEmpty() -> null + specialCharacterPattern.containsMatchIn(text) -> R.drawable.ic_warning + text.length <= 12 -> R.drawable.ic_check + else -> null + } + helperColor = when { + text.isEmpty() -> Grey400 + specialCharacterPattern.containsMatchIn(text) -> WarningRed + text.length <= 12 -> TerningMain + else -> Grey400 + } + } + Column( modifier = Modifier .fillMaxWidth() + .padding(horizontal = 16.dp) ) { - Text(text = "탐색 스크린") + + SearchTextField( + text = text, + onValueChange = { newText -> + text = newText + }, + hint = stringResource(R.string.search_text_field_hint), + leftIcon = R.drawable.ic_nav_search + ) + + // TODO 프로필 스크린 TextField로, 삭제될 코드입니다 + NameTextField( + text = text, + onValueChange = { newText -> + text = newText + updateHelper(newText) + }, + hint = stringResource(R.string.profile_text_field_hint), + helperMessage = stringResource(helperMessage), + helperIcon = helperIcon, + helperColor = helperColor + ) } } diff --git a/feature/src/main/res/drawable/ic_check.xml b/feature/src/main/res/drawable/ic_check.xml new file mode 100644 index 000000000..3982b4d78 --- /dev/null +++ b/feature/src/main/res/drawable/ic_check.xml @@ -0,0 +1,18 @@ + + + + diff --git a/feature/src/main/res/drawable/ic_warning.xml b/feature/src/main/res/drawable/ic_warning.xml new file mode 100644 index 000000000..04eb2ddbe --- /dev/null +++ b/feature/src/main/res/drawable/ic_warning.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/feature/src/main/res/values/strings.xml b/feature/src/main/res/values/strings.xml index aa04f6af3..2247cdd3a 100644 --- a/feature/src/main/res/values/strings.xml +++ b/feature/src/main/res/values/strings.xml @@ -15,6 +15,16 @@ 카카오톡 로그인에 실패했습니다 로그인을 취소하였습니다 + + 이름을 입력해주세요 + 12자리 이내, 문자/숫자 가능, 특수문자/기호 입력불가 + 이름에 특수문자는 입력할 수 없어요 + 이용 가능한 이름이에요 + + + 관심있는 인턴 공고 키워드를 검색해보세요 + +