Skip to content

Commit

Permalink
Merge pull request #39 from mash-up-kr/feature/save_link
Browse files Browse the repository at this point in the history
[#28 feature] 텍스트 필드 추가
  • Loading branch information
Ahn-seokjoo authored Jun 29, 2024
2 parents f5559ec + 8c0544f commit 11c74f1
Show file tree
Hide file tree
Showing 22 changed files with 474 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
run: ./gradlew assembleDebug
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package com.mashup.dorabangs.core.designsystem.component.textfield

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
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.fillMaxHeight
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.text.BasicTextField
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.mashup.dorabangs.core.designsystem.R
import com.mashup.dorabangs.core.designsystem.component.snackbar.doraiconclose.CloseCircle
import com.mashup.dorabangs.core.designsystem.component.snackbar.doraiconclose.DoraIconClose
import com.mashup.dorabangs.core.designsystem.theme.DoraRoundTokens
import com.mashup.dorabangs.core.designsystem.theme.DoraTypoTokens
import com.mashup.dorabangs.core.designsystem.theme.TextFieldColorTokens

@Composable
fun DoraTextField(
text: String,
hintText: String,
labelText: String,
modifier: Modifier = Modifier,
errorText: String = "",
) {
var textFieldValue by remember {
mutableStateOf(
TextFieldValue(
text = text,
selection = TextRange(text.length),
),
)
}
val focusRequester = remember { FocusRequester() }
LaunchedEffect(key1 = Unit) {
focusRequester.requestFocus()
}

Column(
modifier = modifier.padding(horizontal = 20.dp),
) {
DoraTextFieldLabel(labelText = labelText)
Spacer(modifier = Modifier.height(height = 8.dp))
Column(
modifier = Modifier
.size(width = 350.dp, height = 48.dp)
.clip(DoraRoundTokens.Round8)
.background(TextFieldColorTokens.BackGroundColor),
) {
BasicTextField(
modifier = Modifier
.focusRequester(focusRequester)
.fillMaxHeight()
.padding(horizontal = 12.dp, vertical = 13.dp),
value = textFieldValue,
singleLine = true,
textStyle = DoraTypoTokens.caption1Medium,
onValueChange = {
textFieldValue = it
},
decorationBox = { innerTextField ->
Box(
modifier = Modifier.width(326.dp),
contentAlignment = Alignment.CenterStart,
) {
if (textFieldValue.text.isBlank()) {
Text(
modifier = Modifier.fillMaxWidth(),
text = hintText,
maxLines = 1,
color = TextFieldColorTokens.HintTextColor,
style = DoraTypoTokens.caption1Medium,
textAlign = TextAlign.Start,
)
} else {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween, // 양끝 배치
) {
Box(
modifier = Modifier.weight(1f), // innerTextField가 가로로 확장되지 않도록 설정
) {
innerTextField()
}
Spacer(modifier = Modifier.width(width = 4.dp))
IconButton(
modifier = Modifier.size(size = 24.dp),
onClick = { textFieldValue = TextFieldValue("") },
) {
Icon(
imageVector = DoraIconClose.CloseCircle,
contentDescription = stringResource(id = R.string.text_field_url_text_clear),
tint = TextFieldColorTokens.ClearButtonColor,
)
}
}
}
}
},
)
}
Spacer(modifier = Modifier.height(height = 8.dp))
if (errorText.isNotBlank()) {
DoraTextFieldErrorLabel(errorText = errorText)
}
}
}

@Composable
@Preview
fun DoraTextFieldLongPreview() {
DoraTextField(
text = "테스트용 이다 어쩔래 ? ? ? asogihasio gasiofhgaioshgioashgaosighoasihg",
hintText = "URL을 입력해주세요.",
labelText = "바보",
errorText = "유효한 링크를 입력해주세요.",
)
}

@Composable
@Preview
fun DoraTextFieldShortPreview() {
DoraTextField(
text = "테스트용 이다 어쩔래 ? ? ?",
hintText = "URL을 입력해주세요.",
labelText = "바보",
errorText = "유효한 링크를 입력해주세요.",
)
}

@Composable
@Preview
fun DoraTextFieldPreviewWithHint() {
DoraTextField(
text = "",
hintText = "URL을 입력해주세요.",
labelText = "링크",
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.mashup.dorabangs.core.designsystem.component.textfield

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.mashup.dorabangs.core.designsystem.theme.DoraTypoTokens
import com.mashup.dorabangs.core.designsystem.theme.TextFieldErrorLabelColorTokens

@Composable
fun DoraTextFieldErrorLabel(
errorText: String,
modifier: Modifier = Modifier,
) {
Text(
modifier = modifier,
text = errorText,
color = TextFieldErrorLabelColorTokens.LabelColor,
style = DoraTypoTokens.SMedium,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.mashup.dorabangs.core.designsystem.component.textfield

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.mashup.dorabangs.core.designsystem.theme.DoraTypoTokens
import com.mashup.dorabangs.core.designsystem.theme.TextFieldLabelColorTokens

@Composable
fun DoraTextFieldLabel(
labelText: String,
modifier: Modifier = Modifier,
) {
Text(
modifier = modifier,
text = labelText,
style = DoraTypoTokens.caption1Medium,
color = TextFieldLabelColorTokens.LabelColor,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ object ClipBoardColorTokens {
val ArrowColor = DoraColorTokens.G3
}

object TextFieldColorTokens {
val BackGroundColor = DoraColorTokens.G1
val HintTextColor = DoraColorTokens.G4
val ClearButtonColor = DoraColorTokens.G4
}

object TextFieldLabelColorTokens {
val LabelColor = DoraColorTokens.G9
}

object TextFieldErrorLabelColorTokens {
val LabelColor = DoraColorTokens.Alert
}

object TopBarColorTokens {
val ContainerColor = DoraColorTokens.White
val OnContainerColor = DoraColorTokens.G9
Expand Down
1 change: 1 addition & 0 deletions core/designsystem/src/main/res/values/string.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
<string name="home_empty_feed">테스트 테스트 테스트 테스트</string>
<string name="snack_bar_title">클립보드에 복사한 링크 저장</string>
<string name="snack_bar_cancel_description">스낵바 취소</string>
<string name="text_field_url_text_clear">url 모두 지우기</string>
</resources>
1 change: 1 addition & 0 deletions feature/save/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
78 changes: 78 additions & 0 deletions feature/save/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.com.android.library)
alias(libs.plugins.org.jetbrains.kotlin.android)
alias(libs.plugins.hilt)
alias(libs.plugins.kotlin.kapt)
}

android {
namespace = "com.dorabangs.feature.save"
compileSdk = 34

defaultConfig {
minSdk = 24

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_18
targetCompatibility = JavaVersion.VERSION_18
}
kotlinOptions {
jvmTarget = "18"
}
}

dependencies {
implementation(project(":domain"))
implementation(project(":core:coroutine"))
implementation(project(":core:designsystem"))
implementation(project(":core:navigation"))

// Compose
implementation(libs.ui)
implementation(libs.ui.graphics)
implementation(libs.ui.tooling.preview)
implementation(libs.material3)
implementation(platform(libs.compose.bom))
implementation(libs.material)
implementation(libs.lifecycle.compose.ktx)

// Test
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)
androidTestImplementation(platform(libs.compose.bom))
androidTestImplementation(libs.ui.test.junit4)
debugImplementation(libs.ui.tooling)
debugImplementation(libs.ui.test.manifest)
testImplementation(libs.junit)

// Hilt
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
implementation(libs.hilt.navigation.compose)

// Orbit
implementation(libs.orbit.core)
implementation(libs.orbit.viewmodel)
implementation(libs.orbit.compose)
}
Empty file added feature/save/consumer-rules.pro
Empty file.
21 changes: 21 additions & 0 deletions feature/save/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.dorabangs.feature.save

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import junit.framework.TestCase.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.dorabangs.feature.save.test", appContext.packageName)
}
}
4 changes: 4 additions & 0 deletions feature/save/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.dorabangs.feature.save

import junit.framework.TestCase.assertEquals
import org.junit.Test

/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
1 change: 1 addition & 0 deletions save/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
Loading

0 comments on commit 11c74f1

Please sign in to comment.