Skip to content

Commit

Permalink
feat: 누락된 컴포넌트 추가 (#387)
Browse files Browse the repository at this point in the history
* feat: QuackGridLayout 에 아이템 사이 간격 인자 추가

* feat: QuackSingeLazyRowTag 추가

* chore: TrailingComma 린트 비활성화

* chore: bump ui-components

* refactor: 코드 스타일 문제 해결

* chore: api dump
  • Loading branch information
jisungbin committed Nov 25, 2022
1 parent fc86234 commit 6388451
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import team.duckie.quackquack.ui.util.DpSize
class ImagePlayground : PlaygroundActivity(
name = "Image",
) {
@Suppress("MaxLineLength")
override val items: ImmutableList<Pair<String, @Composable () -> Unit>> = persistentListOf(
::QuackImageDemo.name to { QuackImageDemo() },
::QuackSelectableImageTypeTopEndCheckboxDemo.name to { QuackSelectableImageTypeTopEndCheckboxDemo() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
package team.duckie.quackquack.playground.realworld

import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import kotlinx.collections.immutable.ImmutableList
Expand Down Expand Up @@ -76,16 +74,18 @@ fun QuackBasic2TextFieldDemo() {
)
}

private const val MaxLength = 5

@Composable
fun QuackErrorableTextFieldDemo() {
val (text, setText) = remember { mutableStateOf("") }

QuackErrorableTextField(
text = text,
onTextChanged = setText,
placeholderText = "MaxLength: 5",
maxLength = 5,
isError = text.length > 5,
placeholderText = "MaxLength: $MaxLength",
maxLength = MaxLength,
isError = text.length > MaxLength,
errorText = "ErrorText",
showClearButton = true,
onCleared = { setText("") },
Expand All @@ -99,9 +99,9 @@ fun QuackErrorableTextFieldWithoutClearButtonDemo() {
QuackErrorableTextField(
text = text,
onTextChanged = setText,
placeholderText = "MaxLength: 5",
maxLength = 5,
isError = text.length > 5,
placeholderText = "MaxLength: $MaxLength",
maxLength = MaxLength,
isError = text.length > MaxLength,
errorText = "ErrorText",
)
}
88 changes: 67 additions & 21 deletions ui-components/api/ui-components.api

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions ui-components/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ android {

// FIXME: https://github.com/duckie-team/quack-quack-android/issues/368
disable.add("SpecifyAnimationSpec")

// FIXME: https://github.com/duckie-team/quack-quack-android/issues/383
disable.add("TrailingComma")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.compose.foundation.lazy.grid.itemsIndexed
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.ImmutableList

Expand All @@ -39,6 +40,8 @@ private object QuackGridDefaults {
* @param modifier the modifier to apply to this layout
* @param items the data list
* @param state the state object to be used to control or observe the list's state
* @param verticalSpacing the vertical spacing between items
* @param horizontalSpacing the horizontal spacing between items
* @param key a factory of stable and unique keys representing the item. Using the same key
* for multiple items in the grid is not allowed. Type of the key should be saveable
* via Bundle on Android. If null is passed the position in the grid will represent the key.
Expand All @@ -58,6 +61,8 @@ public fun <T> QuackGridLayout(
modifier: Modifier = Modifier,
items: ImmutableList<T>,
state: LazyGridState = rememberLazyGridState(),
verticalSpacing: Dp = QuackGridDefaults.VerticalGap,
horizontalSpacing: Dp = QuackGridDefaults.HorizontalGap,
key: ((index: Int, item: T) -> Any)? = null,
span: (LazyGridItemSpanScope.(index: Int, item: T) -> GridItemSpan)? = null,
contentType: (index: Int, item: T) -> Any? = { _, _ -> null },
Expand All @@ -72,10 +77,10 @@ public fun <T> QuackGridLayout(
count = MaxComponentCountsForLine
),
verticalArrangement = Arrangement.spacedBy(
space = VerticalGap,
space = verticalSpacing,
),
horizontalArrangement = Arrangement.spacedBy(
space = HorizontalGap,
space = horizontalSpacing,
),
) {
itemsIndexed(
Expand Down
133 changes: 114 additions & 19 deletions ui-components/src/main/kotlin/team/duckie/quackquack/ui/component/tag.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.layout.LazyLayout
Expand Down Expand Up @@ -607,8 +608,7 @@ private fun quackTagInternalAssert(
/**
* [LazyVerticalGrid] 형식으로 주어진 태그들을 배치합니다.
* 이 컴포넌트는 항상 상위 컴포저블의 가로 길이만큼 width 가 지정되고,
* (즉, 좌우 패딩이 허용되지 않습니다) 한 줄에 최대 [itemChunkedSize]개가 들어갈 수 있습니다.
* 또한 가로와 세로 스크롤을 모두 지원합니다.
* 한 줄에 최대 [itemChunkedSize]개가 들어갈 수 있습니다. 또한 가로와 세로 스크롤을 모두 지원합니다.
*
* 퍼포먼스 측면에서 [LazyLayout] 를 사용하는 것이 좋지만, 덕키의 경우
* 표시해야 하는 태그의 개수가 많지 않기 때문에 컴포저블을 직접 그려도
Expand All @@ -633,6 +633,9 @@ private fun quackTagInternalAssert(
* When you specify the key the scroll position will be maintained based on the key, which
* means if you add/remove items before the current visible item the item with the given key
* will be kept as the first visible one.
* @param contentType a factory of the content types for the item. The item compositions of
* the same type could be reused more efficiently. Note that null is a valid type and items of such
* type will be considered compatible.
* @param onClick 사용자가 태그를 클릭했을 때 호출되는 람다.
* 람다식의 인자로는 선택된 태그의 index 가 들어옵니다.
*/
Expand All @@ -647,13 +650,9 @@ public fun QuackLazyVerticalGridTag(
horizontalSpace: Dp = QuackTagDefaults.LazyTag.HorizontalSpacedBy,
verticalSpace: Dp = QuackTagDefaults.LazyTag.VerticalSpacedBy,
tagType: QuackTagType,
key: ((
index: Int,
items: List<String>,
) -> Any)? = null,
onClick: (
index: Int,
) -> Unit,
key: ((index: Int, items: List<String>) -> Any)? = null,
contentType: (index: Int, items: List<String>) -> Any? = { _, _ -> null },
onClick: (index: Int) -> Unit,
): Unit = with(
receiver = QuackTagDefaults.LazyTag,
) {
Expand Down Expand Up @@ -693,16 +692,8 @@ public fun QuackLazyVerticalGridTag(
}
itemsIndexed(
items = chunkedItems,
key = { index: Int, items: List<String> ->
key!!.invoke(
/* index = */
index,
/* items = */
items,
)
}.takeIf {
key != null
},
key = key,
contentType = contentType,
) { rowIndex, rowItems ->
Row(
modifier = Modifier
Expand Down Expand Up @@ -758,3 +749,107 @@ public fun QuackLazyVerticalGridTag(
}
}
}

/**
* [LazyRow] 형식으로 주어진 태그들을 **한 줄로** 배치합니다.
* 이 컴포넌트는 항상 상위 컴포저블의 가로 길이만큼 width 가 지정됩니다.
*
* @param modifier 이 컴포넌트에 적용할 [Modifier]
* @param contentPadding 이 컴포넌트의 광역에 적용될 [PaddingValues]
* @param title 상단에 표시될 제목. 만약 null 을 제공할 시 표시되지 않습니다.
* @param items 표시할 태그들의 제목. **중복되는 태그 제목은 허용하지 않습니다.**
* 이 항목은 바뀔 수 있으므로 [ImmutableList] 가 아닌 일반 [List] 로 받습니다.
* @param itemSelections 태그들의 선택 여부.
* 이 항목은 바뀔 수 있으므로 [ImmutableList] 가 아닌 [List] 로 받습니다.
* @param horizontalSpace 아이템들의 가로 간격
* @param tagType [QuackLazyVerticalGridTag] 에서 표시할 태그의 타입을 지정합니다.
* 여러 종류의 태그가 [QuackLazyVerticalGridTag] 으로 표시될 수 있게 태그의 타입을 따로 받습니다.
* @param key a factory of stable and unique keys representing the item. Using the same key
* for multiple items in the list is not allowed. Type of the key should be saveable
* via Bundle on Android. If null is passed the position in the list will represent the key.
* When you specify the key the scroll position will be maintained based on the key, which
* means if you add/remove items before the current visible item the item with the given key
* will be kept as the first visible one.
* @param contentType a factory of the content types for the item. The item compositions of
* the same type could be reused more efficiently. Note that null is a valid type and items of such
* type will be considered compatible.
* @param onClick 사용자가 태그를 클릭했을 때 호출되는 람다.
* 람다식의 인자로는 선택된 태그의 index 가 들어옵니다.
*/
@Composable
public fun QuackSingeLazyRowTag(
modifier: Modifier = Modifier,
contentPadding: PaddingValues = NoPadding,
title: String? = null,
items: List<String>,
itemSelections: List<Boolean>? = null,
horizontalSpace: Dp = QuackTagDefaults.LazyTag.HorizontalSpacedBy,
tagType: QuackTagType,
key: ((index: Int, item: String) -> Any)? = null,
contentType: (index: Int, item: String) -> Any? = { _, _ -> null },
onClick: (index: Int) -> Unit,
): Unit = with(QuackTagDefaults.LazyTag) {
if (itemSelections != null) {
runtimeCheck(
value = items.size == itemSelections.size,
) {
"The size of items and the size of itemsSelection must always be the same. " +
"[items.size (${items.size}) != itemsSelection.size (${itemSelections.size})]"
}
}
LazyRow(
modifier = modifier.fillMaxWidth(),
contentPadding = contentPadding,
horizontalArrangement = Arrangement.spacedBy(space = horizontalSpace),
) {
if (title != null) {
item {
QuackText(
modifier = Modifier.padding(bottom = TitleSpacedBy),
text = title,
style = TitleTypogrphy,
singleLine = true,
)
}
}
itemsIndexed(
items = items,
key = key,
contentType = contentType,
) { index, item ->
val isSelected = itemSelections?.get(index) ?: false
with(tagType) {
when (this) {
is QuackTagType.Grayscale -> QuackGrayscaleTagInternal(
modifier = Modifier.animateItemPlacement(
animationSpec = QuackAnimationSpec(),
),
text = item,
trailingText = trailingText,
actualIndex = index,
onClickWithIndex = onClick,
)
is QuackTagType.Circle -> QuackCircleTagInternal(
modifier = Modifier.animateItemPlacement(
animationSpec = QuackAnimationSpec(),
),
text = item,
trailingIcon = trailingIcon,
isSelected = isSelected,
actualIndex = index,
onClickWithIndex = onClick,
)
QuackTagType.Round -> QuackRoundTagInternal(
modifier = Modifier.animateItemPlacement(
animationSpec = QuackAnimationSpec(),
),
text = item,
isSelected = isSelected,
actualIndex = index,
onClickWithIndex = onClick,
)
}
}
}
}
}
2 changes: 1 addition & 1 deletion versions/ui-components.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
major=1
minor=3
patch=2
patch=3

0 comments on commit 6388451

Please sign in to comment.