Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource

val BackIcon: ImageVector
@Composable
get() = ImageVector.vectorResource(id = R.drawable.ic_back)

val ArrowRightIcon: ImageVector
@Composable
get() = ImageVector.vectorResource(id = R.drawable.ic_arrow_right)

val CalendarIcon: ImageVector
@Composable
get() = ImageVector.vectorResource(id = R.drawable.ic_calendar)
Expand Down Expand Up @@ -98,4 +106,16 @@ val CherryUnselectedIcon: ImageVector

val CherrySelectedIcon: ImageVector
@Composable
get() = ImageVector.vectorResource(id = R.drawable.ic_cherry_selected)
get() = ImageVector.vectorResource(id = R.drawable.ic_cherry_selected)

val CircleSelectedIcon: ImageVector
@Composable
get() = ImageVector.vectorResource(id = R.drawable.ic_circle_selected)

val CircleUnselectedIcon: ImageVector
@Composable
get() = ImageVector.vectorResource(id = R.drawable.ic_circle_unselected)

val CircleCheckedIcon: ImageVector
@Composable
get() = ImageVector.vectorResource(id = R.drawable.ic_circle_checked)
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package com.hyunjung.core.presentation.designsystem.component

import com.hyunjung.core.presentation.designsystem.component.CherrydanFixedTabRowDefaults.fixedTabIndicatorOffset
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
import com.hyunjung.auth.presentation.LocalCherrydanContentColor
import com.hyunjung.core.presentation.designsystem.CherrydanColors
import com.hyunjung.core.presentation.designsystem.CherrydanTheme
import com.hyunjung.core.presentation.designsystem.CherrydanTypography

@Composable
fun CherrydanFixedTabRow(
selectedTabIndex: Int,
modifier: Modifier = Modifier,
containerColor: Color = CherrydanFixedTabRowDefaults.ContainerColor,
contentColor: Color = CherrydanFixedTabRowDefaults.ContentColor,
indicator: @Composable (tabPositions: List<CherrydanTabPosition>) -> Unit =
@Composable { tabPositions ->
CherrydanFixedTabRowDefaults.Indicator(
Modifier.fixedTabIndicatorOffset(tabPositions[selectedTabIndex])
)
},
tabs: @Composable () -> Unit
) {
Surface(
modifier = modifier,
color = containerColor,
contentColor = contentColor
) {
SubcomposeLayout(
modifier = Modifier
.fillMaxWidth()
.selectableGroup()
.clipToBounds()
) { constraints ->
val tabMeasurables = subcompose(FixedTabSlots.Tabs, tabs)
val tabCount = tabMeasurables.size
val tabWidth = if (tabCount > 0) constraints.maxWidth / tabCount else 0

val tabConstraints = constraints.copy(
minWidth = tabWidth,
maxWidth = tabWidth
)

val tabPlaceables = tabMeasurables.map { measurable ->
measurable.measure(tabConstraints)
}

val layoutHeight = tabPlaceables.maxOfOrNull { it.height } ?: 0
val layoutWidth = constraints.maxWidth

layout(layoutWidth, layoutHeight) {
val tabPositions = mutableListOf<CherrydanTabPosition>()

tabPlaceables.fastForEachIndexed { index, placeable ->
val left = index * tabWidth
placeable.placeRelative(left, 0)

tabPositions.add(
CherrydanTabPosition(
left = left.toDp(),
width = tabWidth.toDp(),
contentWidth = (tabWidth - HorizontalTextPadding.roundToPx() * 2).toDp()
)
)
}

subcompose(FixedTabSlots.Indicator) {
indicator(tabPositions)
}.fastForEach { measurable ->
val indicatorPlaceable = measurable.measure(
Constraints.fixed(layoutWidth, layoutHeight)
)
indicatorPlaceable.placeRelative(0, 0)
}
}
}
}
}

private enum class FixedTabSlots {
Tabs,
Indicator
}

@Preview(showBackground = true)
@Composable
private fun CherrydanFixedTabsPreview() {
val tabs = listOf("활동", "맞춤형")
val selectedIndex = 0

CherrydanTheme {
CherrydanFixedTabRow(selectedTabIndex = selectedIndex) {
tabs.forEachIndexed { index, label ->
val selected = index == selectedIndex
CherrydanTab(
selected = selected,
onClick = {}
) {
Text(
text = label,
color = LocalCherrydanContentColor.current,
style = if (selected) CherrydanTypography.Main3_B else CherrydanTypography.Main3_R
)
}
}
}
}
}

object CherrydanFixedTabRowDefaults {
val ContainerColor: Color = Color.Transparent
val ContentColor: Color = CherrydanColors.MainPink3

@Composable
fun Indicator(
modifier: Modifier = Modifier,
height: Dp = 2.dp,
color: Color = ContentColor
) {
Box(
modifier
.fillMaxWidth()
.height(height)
.background(color = color)
)
}

fun Modifier.fixedTabIndicatorOffset(currentTabPosition: CherrydanTabPosition): Modifier =
composed(
inspectorInfo = debugInspectorInfo {
name = "fixedTabIndicatorOffset"
value = currentTabPosition
}
) {
val currentTabWidth by animateDpAsState(
targetValue = currentTabPosition.width,
animationSpec = FixedTabRowIndicatorSpec,
label = "indicator-width"
)
val indicatorOffset by animateDpAsState(
targetValue = currentTabPosition.left,
animationSpec = FixedTabRowIndicatorSpec,
label = "indicator-offset"
)
fillMaxWidth()
.wrapContentSize(Alignment.BottomStart)
.offset { IntOffset(indicatorOffset.roundToPx(), 0) }
.width(currentTabWidth)
}
}

private val FixedTabRowIndicatorSpec: AnimationSpec<Dp> =
tween(durationMillis = 250, easing = FastOutSlowInEasing)

private val HorizontalTextPadding: Dp = 16.dp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.hyunjung.auth.presentation.LocalCherrydanContentColor
import com.hyunjung.core.presentation.designsystem.BackIcon
import com.hyunjung.core.presentation.designsystem.CherrydanColors
import com.hyunjung.core.presentation.designsystem.CherrydanTypography

Expand Down Expand Up @@ -100,7 +101,7 @@ private fun TopAppBarBase(
.align(if (centeredTitle) Alignment.Center else Alignment.CenterStart)
.padding(
start = if (!centeredTitle && navigationIcon != null) {
CherrydanTopAppBarDefaults.HorizontalPadding + CherrydanTopAppBarDefaults.NavigationButtonSize
CherrydanTopAppBarDefaults.NavigationButtonSize
} else 0.dp
)
) {
Expand Down Expand Up @@ -194,7 +195,7 @@ private fun CherrydanTopAppBarPreview() {
title = "Title",
navigationIcon = {
TopBarIconButton(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
imageVector = BackIcon,
contentDescription = "Back",
onClick = {}
)
Expand All @@ -219,7 +220,7 @@ private fun CherrydanTopAppBarCenteredPreview() {
centeredTitle = true,
navigationIcon = {
TopBarIconButton(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
imageVector = BackIcon,
contentDescription = "Back",
onClick = {}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="37dp"
android:viewportWidth="32"
android:viewportHeight="37">
<path
android:strokeWidth="1"
android:pathData="M13,13.5L19,19.5L13,25.5"
android:fillColor="#00000000"
android:strokeColor="#262626"/>
</vector>
11 changes: 11 additions & 0 deletions core/presentation/designsystem/src/main/res/drawable/ic_back.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="33dp"
android:viewportWidth="32"
android:viewportHeight="33">
<path
android:strokeWidth="1"
android:pathData="M19,11.5L13,17.5L19,23.5"
android:fillColor="#00000000"
android:strokeColor="#262626"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:strokeWidth="1"
android:pathData="M12,12m-7,0a7,7 0,1 1,14 0a7,7 0,1 1,-14 0"
android:fillColor="#00000000"
android:strokeColor="#999999"/>
<path
android:strokeWidth="1"
android:pathData="M9,11.5L11.308,14L15,10"
android:fillColor="#00000000"
android:strokeColor="#999999"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<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,12m-7,0a7,7 0,1 1,14 0a7,7 0,1 1,-14 0"
android:fillColor="#F64F4D"/>
<path
android:strokeWidth="1"
android:pathData="M9,11.5L11.308,14L15,10"
android:fillColor="#00000000"
android:strokeColor="#ffffff"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:strokeWidth="1"
android:pathData="M12,12m-7,0a7,7 0,1 1,14 0a7,7 0,1 1,-14 0"
android:fillColor="#00000000"
android:strokeColor="#999999"/>
</vector>
9 changes: 9 additions & 0 deletions core/presentation/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,13 @@
<string name="home_nav_home">홈</string>
<string name="home_nav_my_campaigns">내 체험단</string>
<string name="home_nav_my_page">마이페이지</string>

<!-- Notification Screen -->
<string name="notification_title">알림</string>
<string name="notification_activity">활동</string>
<string name="notification_keyword">맞춤형</string>
<string name="notification_all_select">모두 선택</string>
<string name="notification_read">읽음</string>
<string name="notification_delete">삭제</string>
<string name="notification_cancel">취소</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
Expand All @@ -46,6 +47,7 @@ import com.hyunjung.core.presentation.designsystem.component.CherrydanTab
import com.hyunjung.core.presentation.designsystem.component.CherrydanTabPosition
import com.hyunjung.core.presentation.designsystem.component.CherrydanTopAppBar
import com.hyunjung.core.presentation.designsystem.component.TopBarIconButton
import com.hyunjung.core.presentation.ui.R

@Composable
fun HomeScreenRoot(modifier: Modifier = Modifier) {
Expand Down Expand Up @@ -87,8 +89,7 @@ fun HomeContent(
modifier = modifier,
topBar = {
CherrydanTopAppBar(
// todo : StringResource를 사용하여 문자열을 관리하는 것이 좋습니다.
title = "체리단",
title = stringResource(id = R.string.splash_title),
actions = {
TopBarIconButton(
imageVector = NotificationIcon,
Expand Down
1 change: 1 addition & 0 deletions notification/data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
16 changes: 16 additions & 0 deletions notification/data/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
alias(libs.plugins.hyunjung.cherrydan.android.library)
alias(libs.plugins.hyunjung.cherrydan.jvm.ktor)
}

android {
namespace = "com.hyunjung.notification.data"
}

dependencies {
implementation(libs.bundles.koin)

implementation(projects.notification.domain)
implementation(projects.core.domain)
implementation(projects.core.data)
}
Empty file.
Loading