-
Notifications
You must be signed in to change notification settings - Fork 1
PrezelTabs 구현 #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
PrezelTabs 구현 #49
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
257 changes: 257 additions & 0 deletions
257
...core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelTabs.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,257 @@ | ||
| package com.team.prezel.core.designsystem.component | ||
|
|
||
| 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.fillMaxSize | ||
| import androidx.compose.foundation.layout.fillMaxWidth | ||
| import androidx.compose.foundation.layout.height | ||
| import androidx.compose.foundation.pager.HorizontalPager | ||
| import androidx.compose.foundation.pager.PagerState | ||
| import androidx.compose.foundation.pager.rememberPagerState | ||
| import androidx.compose.material3.SecondaryTabRow | ||
| import androidx.compose.material3.Tab | ||
| import androidx.compose.material3.Text | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.Immutable | ||
| import androidx.compose.runtime.rememberCoroutineScope | ||
| import androidx.compose.ui.Alignment | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.graphics.Color | ||
| import androidx.compose.ui.unit.dp | ||
| import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles | ||
| import com.team.prezel.core.designsystem.preview.ThemePreview | ||
| import com.team.prezel.core.designsystem.theme.PrezelTheme | ||
| import kotlinx.collections.immutable.ImmutableList | ||
| import kotlinx.collections.immutable.persistentListOf | ||
| import kotlinx.coroutines.CoroutineScope | ||
| import kotlinx.coroutines.launch | ||
| import kotlin.math.abs | ||
|
|
||
| @Immutable | ||
| data class PrezelTabItem( | ||
| val label: String, | ||
| val badgeCount: Int? = null, | ||
| val enabled: Boolean = true, | ||
| ) | ||
|
|
||
| enum class PrezelTabSize { Small, Regular } | ||
|
|
||
| @Composable | ||
| fun PrezelTabs( | ||
| tabs: ImmutableList<PrezelTabItem>, | ||
| pagerState: PagerState, | ||
| modifier: Modifier = Modifier, | ||
| size: PrezelTabSize = PrezelTabSize.Regular, | ||
| userScrolledEnabled: Boolean = true, | ||
| content: @Composable (pageIndex: Int) -> Unit, | ||
| ) { | ||
| require(tabs.isNotEmpty()) { "tabs는 비어있을 수 없습니다." } | ||
| require(pagerState.pageCount == tabs.size) { | ||
| "pagerState.pageCount(${pagerState.pageCount})와 tabs.size(${tabs.size})가 일치해야 합니다." | ||
| } | ||
|
|
||
| val scope = rememberCoroutineScope() | ||
|
|
||
| Column(modifier = modifier.fillMaxSize()) { | ||
| PrezelTabsBar( | ||
| tabs = tabs, | ||
| pagerState = pagerState, | ||
| size = size, | ||
| onTabClick = { index, enabled -> | ||
| if (!enabled) return@PrezelTabsBar | ||
| handleTabClick(scope, pagerState, index) | ||
| }, | ||
| ) | ||
|
|
||
| PrezelTabsPager( | ||
| pagerState = pagerState, | ||
| userScrolledEnabled = userScrolledEnabled, | ||
| content = content, | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Composable | ||
| private fun PrezelTabsBar( | ||
| tabs: ImmutableList<PrezelTabItem>, | ||
| pagerState: PagerState, | ||
| size: PrezelTabSize, | ||
| onTabClick: (index: Int, enabled: Boolean) -> Unit, | ||
| ) { | ||
| SecondaryTabRow( | ||
| selectedTabIndex = pagerState.currentPage, | ||
| modifier = Modifier.fillMaxWidth(), | ||
| containerColor = Color.Transparent, | ||
| indicator = { | ||
| Spacer( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(2.dp) | ||
| .tabIndicatorOffset( | ||
| selectedTabIndex = pagerState.currentPage, | ||
| ).background(PrezelTheme.colors.solidBlack), | ||
| ) | ||
| }, | ||
| ) { | ||
| tabs.forEachIndexed { index, item -> | ||
| PrezelTabItem( | ||
| item = item, | ||
| selected = pagerState.currentPage == index, | ||
| size = size, | ||
| onClick = { onTabClick(index, item.enabled) }, | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Composable | ||
| private fun PrezelTabItem( | ||
| item: PrezelTabItem, | ||
| selected: Boolean, | ||
| size: PrezelTabSize, | ||
| onClick: () -> Unit, | ||
| ) { | ||
| Tab( | ||
| selected = selected, | ||
| onClick = onClick, | ||
| modifier = Modifier.height(if (size == PrezelTabSize.Small) 36.dp else 48.dp), | ||
| enabled = item.enabled, | ||
| text = { | ||
| PrezelTabLabel( | ||
| label = item.label, | ||
| size = size, | ||
| badgeCount = item.badgeCount, | ||
| selected = selected, | ||
| ) | ||
| }, | ||
| selectedContentColor = PrezelTheme.colors.solidBlack, | ||
| unselectedContentColor = PrezelTheme.colors.textDisabled, | ||
| ) | ||
| } | ||
|
|
||
| @Composable | ||
| private fun PrezelTabLabel( | ||
| label: String, | ||
| size: PrezelTabSize, | ||
| selected: Boolean, | ||
| badgeCount: Int? = null, | ||
| ) { | ||
| Row( | ||
| verticalAlignment = Alignment.CenterVertically, | ||
| horizontalArrangement = Arrangement.spacedBy(8.dp), | ||
| ) { | ||
| Text( | ||
| text = label, | ||
| style = if (size == PrezelTabSize.Small) PrezelTextStyles.Body3Medium.toTextStyle() else PrezelTextStyles.Body2Bold.toTextStyle(), | ||
| ) | ||
|
|
||
| if (badgeCount != null) { | ||
| PrezelBadge( | ||
| active = false, | ||
| count = badgeCount, | ||
| size = PrezelBadgeSize.REGULAR, | ||
| disabled = !selected, | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Composable | ||
| private fun PrezelTabsPager( | ||
| pagerState: PagerState, | ||
| userScrolledEnabled: Boolean, | ||
| content: @Composable (pageIndex: Int) -> Unit, | ||
| ) { | ||
| HorizontalPager( | ||
| state = pagerState, | ||
| userScrollEnabled = userScrolledEnabled, | ||
| overscrollEffect = null, | ||
| ) { page -> | ||
| content(page) | ||
| } | ||
| } | ||
|
|
||
| private fun handleTabClick( | ||
| scope: CoroutineScope, | ||
| pagerState: PagerState, | ||
| target: Int, | ||
| ) { | ||
| scope.launch { | ||
| val current = pagerState.currentPage | ||
| val distance = abs(current - target) | ||
|
|
||
| if (distance <= 1) { | ||
| pagerState.animateScrollToPage(target) | ||
| } else { | ||
| pagerState.scrollToPage(target) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @ThemePreview | ||
| @Composable | ||
| private fun PrezelMediumTabPreview() { | ||
| val tabs = persistentListOf( | ||
| PrezelTabItem(label = "Label", badgeCount = 0), | ||
| PrezelTabItem(label = "Label", badgeCount = 0), | ||
| PrezelTabItem(label = "Label", badgeCount = 0), | ||
| ) | ||
| val pagerState = rememberPagerState(initialPage = 0) { tabs.size } | ||
|
|
||
| PrezelTheme { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxSize() | ||
| .background(PrezelTheme.colors.bgRegular), | ||
| ) { | ||
| PrezelTabs( | ||
| tabs = tabs, | ||
| pagerState = pagerState, | ||
| size = PrezelTabSize.Regular, | ||
| modifier = Modifier, | ||
| ) { page -> | ||
| Box( | ||
| modifier = Modifier.fillMaxSize(), | ||
| contentAlignment = Alignment.Center, | ||
| ) { | ||
| Text("Page: $page") | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @ThemePreview | ||
| @Composable | ||
| private fun PrezelSmallTabPreview() { | ||
| val tabs = persistentListOf( | ||
| PrezelTabItem(label = "Label", badgeCount = 2), | ||
| PrezelTabItem(label = "Label", badgeCount = 3), | ||
| ) | ||
| val pagerState = rememberPagerState(initialPage = 0) { tabs.size } | ||
|
|
||
| PrezelTheme { | ||
| Box( | ||
| modifier = Modifier | ||
| .fillMaxSize() | ||
| .background(PrezelTheme.colors.bgRegular), | ||
| ) { | ||
| PrezelTabs( | ||
| tabs = tabs, | ||
| pagerState = pagerState, | ||
| size = PrezelTabSize.Small, | ||
| ) { page -> | ||
| Box( | ||
| modifier = Modifier.fillMaxSize(), | ||
| contentAlignment = Alignment.Center, | ||
| ) { | ||
| Text("Page: $page") | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
9 changes: 9 additions & 0 deletions
9
Prezel/core/designsystem/src/main/res/drawable/core_designsystem_ic_edit.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="24dp" | ||
| android:height="24dp" | ||
| android:viewportWidth="24" | ||
| android:viewportHeight="24"> | ||
| <path | ||
| android:pathData="M3.898,20.994C3.427,20.946 3.053,20.572 3.005,20.101L3,20V17.413C3,17.148 3.106,16.894 3.293,16.706L16.413,3.586C17.194,2.805 18.462,2.805 19.243,3.586L20.414,4.758C21.195,5.539 21.195,6.806 20.414,7.587L7.294,20.707L7.221,20.773C7.043,20.919 6.819,21 6.587,21H4L3.898,20.994ZM18.182,4.647C17.987,4.452 17.67,4.452 17.475,4.647L4.5,17.62V19.5H6.38L19.353,6.526C19.549,6.331 19.549,6.014 19.353,5.819L18.182,4.647Z" | ||
| android:fillColor="#6E737D"/> | ||
| </vector> |
9 changes: 9 additions & 0 deletions
9
Prezel/core/designsystem/src/main/res/drawable/core_designsystem_ic_lock.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="24dp" | ||
| android:height="24dp" | ||
| android:viewportWidth="24" | ||
| android:viewportHeight="24"> | ||
| <path | ||
| android:pathData="M12,3C14.761,3 17,5.066 17,7.615V9H19C20.105,9 21,9.895 21,11V19L20.989,19.204C20.894,20.146 20.146,20.894 19.204,20.989L19,21H5L4.796,20.989C3.854,20.894 3.106,20.146 3.011,19.204L3,19V11C3,9.895 3.895,9 5,9H7V7.615C7,5.066 9.239,3 12,3ZM5,10.5C4.724,10.5 4.5,10.724 4.5,11V19C4.5,19.276 4.724,19.5 5,19.5H19C19.276,19.5 19.5,19.276 19.5,19V11C19.5,10.724 19.276,10.5 19,10.5H5ZM12,13.25C12.414,13.25 12.75,13.586 12.75,14V16C12.75,16.414 12.414,16.75 12,16.75C11.586,16.75 11.25,16.414 11.25,16V14C11.25,13.586 11.586,13.25 12,13.25ZM12,4.5C9.952,4.5 8.5,6.005 8.5,7.615V9H15.5V7.615C15.5,6.005 14.048,4.5 12,4.5Z" | ||
| android:fillColor="#6E737D"/> | ||
| </vector> |
9 changes: 9 additions & 0 deletions
9
Prezel/core/designsystem/src/main/res/drawable/core_designsystem_ic_setting.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="24dp" | ||
| android:height="24dp" | ||
| android:viewportWidth="24" | ||
| android:viewportHeight="24"> | ||
| <path | ||
| android:pathData="M9.802,3.585C10.501,1.471 13.499,1.471 14.198,3.585L14.522,4.567C14.868,5.612 15.899,6.259 16.976,6.139L17.191,6.104L18.206,5.893C20.39,5.441 21.888,8.03 20.403,9.691L19.714,10.463L19.576,10.632C18.934,11.502 18.98,12.716 19.714,13.537L20.403,14.309C21.842,15.918 20.481,18.398 18.408,18.14L18.206,18.106L17.191,17.896C16.04,17.657 14.891,18.318 14.522,19.433L14.198,20.415L14.126,20.606C13.34,22.465 10.66,22.465 9.874,20.606L9.802,20.415L9.478,19.433C9.109,18.318 7.96,17.657 6.809,17.896L5.794,18.106L5.592,18.14C3.586,18.39 2.246,16.075 3.466,14.467L3.597,14.309L4.286,13.537C5.069,12.661 5.069,11.339 4.286,10.463L3.597,9.691C2.112,8.03 3.61,5.441 5.794,5.893L6.809,6.104C7.888,6.328 8.965,5.761 9.399,4.77L9.478,4.567L9.802,3.585ZM12.773,4.056C12.528,3.315 11.472,3.315 11.226,4.056L10.901,5.038C10.293,6.878 8.4,7.966 6.505,7.573L5.489,7.362C4.71,7.201 4.202,8.118 4.715,8.691L5.404,9.463C6.696,10.908 6.696,13.092 5.404,14.537L4.715,15.309C4.202,15.882 4.71,16.799 5.489,16.638L6.505,16.427C8.4,16.034 10.293,17.122 10.901,18.962L11.226,19.943C11.472,20.685 12.528,20.685 12.773,19.943L13.099,18.962C13.707,17.122 15.6,16.034 17.495,16.427L18.511,16.638C19.29,16.799 19.798,15.882 19.285,15.309L18.596,14.537C17.304,13.092 17.303,10.908 18.596,9.463L19.285,8.691C19.798,8.118 19.29,7.201 18.511,7.362L17.495,7.573C15.6,7.966 13.707,6.878 13.099,5.038L12.773,4.056ZM12,8C14.209,8 16,9.791 16,12C16,14.209 14.209,16 12,16C9.791,16 8,14.209 8,12C8,9.791 9.791,8 12,8ZM12,9.5C10.619,9.5 9.5,10.619 9.5,12C9.5,13.381 10.619,14.5 12,14.5C13.381,14.5 14.5,13.381 14.5,12C14.5,10.619 13.381,9.5 12,9.5Z" | ||
| android:fillColor="#6E737D"/> | ||
| </vector> |
9 changes: 9 additions & 0 deletions
9
Prezel/core/designsystem/src/main/res/drawable/core_designsystem_ic_storage.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="24dp" | ||
| android:height="24dp" | ||
| android:viewportWidth="24" | ||
| android:viewportHeight="24"> | ||
| <path | ||
| android:pathData="M19,8C20.105,8 21,8.895 21,10V18.637C21,19.942 20.104,21 19,21H5C3.896,21 3,19.942 3,18.637V10C3,8.895 3.895,8 5,8H19ZM11,12.25C10.586,12.25 10.25,12.586 10.25,13C10.25,13.414 10.586,13.75 11,13.75H13C13.414,13.75 13.75,13.414 13.75,13C13.75,12.586 13.414,12.25 13,12.25H11ZM19,5.496C19.414,5.496 19.75,5.832 19.75,6.246C19.75,6.66 19.414,6.996 19,6.996H5C4.586,6.996 4.25,6.66 4.25,6.246C4.25,5.832 4.586,5.496 5,5.496H19ZM18,3.001C18.414,3.001 18.75,3.337 18.75,3.751C18.75,4.165 18.414,4.501 18,4.501H6C5.586,4.501 5.25,4.165 5.25,3.751C5.25,3.337 5.586,3.001 6,3.001H18Z" | ||
| android:fillColor="#6E737D"/> | ||
| </vector> |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.