UI refactor

This commit is contained in:
2025-10-15 21:57:19 +09:00
parent c00924be85
commit f57cd956bd
7 changed files with 391 additions and 124 deletions

View File

@@ -1,5 +1,6 @@
package kr.smartsoltech.wellshe.ui.components package kr.smartsoltech.wellshe.ui.components
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
@@ -95,7 +96,8 @@ fun PhasePill(
Surface( Surface(
modifier = modifier, modifier = modifier,
shape = RoundedCornerShape(50), shape = RoundedCornerShape(50),
color = color.copy(alpha = 0.2f) color = Color.Transparent,
border = BorderStroke(1.dp, color)
) { ) {
Text( Text(
text = label, text = label,

View File

@@ -139,6 +139,13 @@ fun CycleScreenPreview() {
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp) horizontalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
QuickActionsCard(
onMarkStart = { },
onMarkEnd = { },
onAddSymptom = { },
onAddNote = { }
)
StatCard( StatCard(
title = "След. менструация", title = "След. менструация",
value = previewState.forecast?.nextPeriodStart?.format( value = previewState.forecast?.nextPeriodStart?.format(
@@ -158,22 +165,6 @@ fun CycleScreenPreview() {
) )
} }
QuickActionsCard(
onMarkStart = { },
onMarkEnd = { },
onAddSymptom = { },
onAddNote = { }
)
InfoCard(
title = "Симптомы сегодня",
content = previewState.todaySymptoms
)
InfoCard(
title = "Прогноз недели",
content = previewState.weekInsight
)
} }
} }
} }

View File

@@ -0,0 +1,244 @@
package kr.smartsoltech.wellshe.ui.cycle.components
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import kr.smartsoltech.wellshe.model.CycleForecast
import kr.smartsoltech.wellshe.ui.theme.*
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import java.util.*
/**
* Вычисление аналитики цикла для отображения текущего статуса
*/
@Composable
fun CycleStatusCard(
forecast: CycleForecast?,
modifier: Modifier = Modifier
) {
if (forecast == null) return
val today = LocalDate.now()
val cycleAnalytics = computeCycleAnalytics(today, forecast)
val dateFormatter = DateTimeFormatter.ofPattern("dd MMM", Locale("ru"))
Card(
modifier = modifier.fillMaxWidth(),
shape = RoundedCornerShape(20.dp),
colors = CardDefaults.cardColors(
containerColor = CycleTabColor.copy(alpha = 0.15f)
)
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(
text = "Статус на сегодня",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold
)
// Текущий день цикла и фаза
Text(
text = "День цикла ${cycleAnalytics.cycleDay} (${cycleAnalytics.phaseName} фаза)",
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium
)
Divider(modifier = Modifier.padding(vertical = 4.dp))
// Ближайшие события
Text(
text = "Ближайшие события:",
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium
)
// Показываем информацию о фертильном окне
if (!cycleAnalytics.flags.isFertileToday) {
val fertileStartFormatted = cycleAnalytics.ranges.fertile.first.format(dateFormatter)
val fertileEndFormatted = cycleAnalytics.ranges.fertile.second.format(dateFormatter)
Text(
text = "• Фертильное окно: $fertileStartFormatted$fertileEndFormatted",
style = MaterialTheme.typography.bodyMedium
)
} else {
Text(
text = "• Фертильное окно: сейчас",
style = MaterialTheme.typography.bodyMedium
)
}
// Информация о дне овуляции
val ovulationFormatted = cycleAnalytics.next.ovulation.format(dateFormatter)
val daysToOvulation = cycleAnalytics.deltas.daysToOvulation
val ovulationText = when {
daysToOvulation < 0 -> "• Овуляция: была $ovulationFormatted (${-daysToOvulation} дн. назад)"
daysToOvulation == 0 -> "• Овуляция: сегодня"
else -> "• Овуляция: $ovulationFormatted (через $daysToOvulation дн.)"
}
Text(
text = ovulationText,
style = MaterialTheme.typography.bodyMedium
)
// Информация о ПМС
if (cycleAnalytics.flags.isPMSToday) {
Text(
text = "• ПМС: сейчас",
style = MaterialTheme.typography.bodyMedium
)
} else if (today.isBefore(cycleAnalytics.ranges.pms.first)) {
val pmsStartFormatted = cycleAnalytics.ranges.pms.first.format(dateFormatter)
Text(
text = "• ПМС: с $pmsStartFormatted",
style = MaterialTheme.typography.bodyMedium
)
}
// Информация о следующей менструации
val nextPeriodFormatted = cycleAnalytics.next.nextPeriodStart.format(dateFormatter)
val daysToNextPeriod = cycleAnalytics.deltas.daysToNextPeriod
val nextPeriodText = when {
cycleAnalytics.flags.isMenstruationToday -> "• Менструация: сейчас"
else -> "• След. менструация: $nextPeriodFormatted (через $daysToNextPeriod дн.)"
}
Text(
text = nextPeriodText,
style = MaterialTheme.typography.bodyMedium
)
// Дополнительная подсказка о текущем статусе
if (cycleAnalytics.flags.isMenstruationToday ||
cycleAnalytics.flags.isFertileToday ||
cycleAnalytics.flags.isOvulationToday ||
cycleAnalytics.flags.isPMSToday) {
Divider(modifier = Modifier.padding(vertical = 4.dp))
val tipText = when {
cycleAnalytics.flags.isOvulationToday -> "Пик вероятности зачатия сегодня. Важно следить за самочувствием, возможны изменения настроения и энергии."
cycleAnalytics.flags.isMenstruationToday -> "В эти дни важно обеспечить организму покой и комфорт. Следите за самочувствием и избегайте чрезмерных нагрузок."
cycleAnalytics.flags.isFertileToday -> "Повышенная вероятность зачатия. Хорошее время для физической активности и новых начинаний."
cycleAnalytics.flags.isPMSToday -> "Возможны колебания настроения и некоторый дискомфорт. Важно следить за гидратацией и сбалансированным питанием."
else -> ""
}
Text(
text = tipText,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
/**
* Вычисление аналитических данных цикла
*/
private fun computeCycleAnalytics(today: LocalDate, forecast: CycleForecast): CycleAnalytics {
// Используем поля из модели CycleForecast
val nextPeriodStart = forecast.nextPeriodStart
val ovulation = forecast.nextOvulation
val fertileStart = forecast.fertileStart
val fertileEnd = forecast.fertileEnd
val pmsStart = forecast.pmsStart
val periodEnd = forecast.periodEnd
// Вычисляем примерную дату начала текущего цикла
val estimatedCycleStart = if (today < nextPeriodStart) {
nextPeriodStart.minusDays(28) // Примерная длина цикла, если точных данных нет
} else {
nextPeriodStart
}
// Считаем текущий день цикла
val cycleDay = ChronoUnit.DAYS.between(estimatedCycleStart, today) + 1
// Определяем фазы
val isMenstruationToday = today in nextPeriodStart..periodEnd
val isFertileToday = today in fertileStart..fertileEnd
val isOvulationToday = today == ovulation
val isPMSToday = today in pmsStart..nextPeriodStart.minusDays(1)
// Определяем текущую фазу
val phaseName = when {
isMenstruationToday -> "Менструация"
today.isBefore(ovulation) -> "Фолликулярная"
today == ovulation -> "Овуляция"
today.isAfter(ovulation) -> "Лютеиновая"
else -> "Неопределена"
}
// Вычисляем дни до следующих событий
val daysToOvulation = ChronoUnit.DAYS.between(today, ovulation)
val daysToNextPeriod = ChronoUnit.DAYS.between(today, nextPeriodStart)
return CycleAnalytics(
cycleDay = cycleDay.toInt(),
phaseName = phaseName,
ranges = CycleRanges(
period = Pair(nextPeriodStart, periodEnd),
fertile = Pair(fertileStart, fertileEnd),
pms = Pair(pmsStart, nextPeriodStart.minusDays(1))
),
next = NextEvents(
ovulation = ovulation,
nextPeriodStart = nextPeriodStart
),
flags = CycleFlags(
isMenstruationToday = isMenstruationToday,
isFertileToday = isFertileToday,
isOvulationToday = isOvulationToday,
isPMSToday = isPMSToday
),
deltas = TimingDeltas(
daysToOvulation = daysToOvulation.toInt(),
daysToNextPeriod = daysToNextPeriod.toInt()
)
)
}
/**
* Класс для аналитики цикла
*/
data class CycleAnalytics(
val cycleDay: Int,
val phaseName: String,
val ranges: CycleRanges,
val next: NextEvents,
val flags: CycleFlags,
val deltas: TimingDeltas
)
data class CycleRanges(
val period: Pair<LocalDate, LocalDate>,
val fertile: Pair<LocalDate, LocalDate>,
val pms: Pair<LocalDate, LocalDate>
)
data class NextEvents(
val ovulation: LocalDate,
val nextPeriodStart: LocalDate
)
data class CycleFlags(
val isMenstruationToday: Boolean,
val isFertileToday: Boolean,
val isOvulationToday: Boolean,
val isPMSToday: Boolean
)
data class TimingDeltas(
val daysToOvulation: Int,
val daysToNextPeriod: Int
)

View File

@@ -9,9 +9,11 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowLeft import androidx.compose.material.icons.filled.KeyboardArrowLeft
import androidx.compose.material.icons.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material.icons.filled.WbSunny import androidx.compose.material.icons.filled.WbSunny
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@@ -38,7 +40,8 @@ fun CycleCalendarCard(
onPrev: () -> Unit, onPrev: () -> Unit,
onNext: () -> Unit, onNext: () -> Unit,
forecast: CycleForecast?, forecast: CycleForecast?,
modifier: Modifier = Modifier modifier: Modifier = Modifier,
onOpenSettings: () -> Unit = {} // Добавлен новый параметр для обработки нажатия на кнопку настроек
) { ) {
val daysOfWeek = listOf("Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс") val daysOfWeek = listOf("Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс")
val monthFormat = DateTimeFormatter.ofPattern("LLLL yyyy", Locale("ru")) val monthFormat = DateTimeFormatter.ofPattern("LLLL yyyy", Locale("ru"))
@@ -47,14 +50,14 @@ fun CycleCalendarCard(
modifier = modifier.fillMaxWidth(), modifier = modifier.fillMaxWidth(),
shape = RoundedCornerShape(20.dp), shape = RoundedCornerShape(20.dp),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = CycleTabColor.copy(alpha = 0.3f) containerColor = Color.Transparent
) )
) { ) {
Column( Column(
modifier = Modifier.padding(16.dp), modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp) verticalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
// Заголовок карточки с иконкой // Заголовок карточки с иконкой и кнопкой настроек
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
@@ -72,6 +75,15 @@ fun CycleCalendarCard(
fontWeight = FontWeight.SemiBold fontWeight = FontWeight.SemiBold
) )
} }
// Кнопка настроек цикла
IconButton(onClick = onOpenSettings) {
Icon(
imageVector = Icons.Filled.Tune,
contentDescription = "Настройки цикла",
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
} }
// Заголовок месяца с кнопками навигации // Заголовок месяца с кнопками навигации
@@ -129,10 +141,16 @@ fun CycleCalendarCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp) horizontalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
PhasePill(label = "Менструация", color = Color(0xFFE57373)) PhasePill(label = "Менструация", color = PeriodColor)
PhasePill(label = "Фертильное окно", color = Color(0xFF4CAF50)) PhasePill(label = "Фертильное окно", color = FertileColor)
PhasePill(label = "Овуляция", color = Color(0xFF3F51B5)) PhasePill(label = "Овуляция", color = OvulationColor)
PhasePill(label = "ПМС", color = Color(0xFFFFA726)) PhasePill(label = "ПМС", color = PmsColor)
}
// Блок расширенной аналитики "Статус на сегодня"
if (forecast != null) {
Spacer(modifier = Modifier.height(16.dp))
CycleStatusCard(forecast = forecast)
} }
} }
} }
@@ -155,7 +173,7 @@ fun CalendarGrid(
// Вычисляем смещение первого дня месяца // Вычисляем смещение первого дня месяца
val dayOfWeekValue = firstDay.dayOfWeek.value // 1 для понедельника, 7 для воскресенья val dayOfWeekValue = firstDay.dayOfWeek.value // 1 для понедельника, 7 для воскресенья
val firstDayOffset = if (dayOfWeekValue == 7) 0 else dayOfWeekValue val firstDayOffset = dayOfWeekValue - 1 // Смещение (0 для понедельника)
// Создаем полную сетку календаря (6 недель по 7 дней) // Создаем полную сетку календаря (6 недель по 7 дней)
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
@@ -170,7 +188,7 @@ fun CalendarGrid(
if (isValidDay) { if (isValidDay) {
val date = month.atDay(dayNumber) val date = month.atDay(dayNumber)
CalendarDay(date = date, today = today, forecast = forecast) CalendarDay(date = date, today = today, forecast = forecast, modifier = Modifier.weight(1f))
} else { } else {
// Пустая ячейка для выравнивания // Пустая ячейка для выравнивания
Box( Box(
@@ -192,7 +210,8 @@ fun CalendarGrid(
fun CalendarDay( fun CalendarDay(
date: LocalDate, date: LocalDate,
today: LocalDate, today: LocalDate,
forecast: CycleForecast? forecast: CycleForecast?,
modifier: Modifier = Modifier
) { ) {
// Определяем, в какой фазе цикла находится день // Определяем, в какой фазе цикла находится день
val isPeriod = forecast?.let { date in it.nextPeriodStart..it.periodEnd } ?: false val isPeriod = forecast?.let { date in it.nextPeriodStart..it.periodEnd } ?: false
@@ -201,25 +220,31 @@ fun CalendarDay(
val isOvulation = forecast?.let { date == it.nextOvulation } ?: false val isOvulation = forecast?.let { date == it.nextOvulation } ?: false
val isToday = date == today val isToday = date == today
// Определяем цвет фона // Создаем базовый модификатор для всех дней
val backgroundColor = when { var finalModifier = modifier
isPeriod -> PeriodColor .size(36.dp)
isFertile -> FertileColor .clip(RoundedCornerShape(8.dp))
isPms -> PmsColor
else -> Color.Transparent // Добавляем контур в зависимости от фазы (приоритет: Ovulation > Period > Fertile > PMS)
finalModifier = when {
isOvulation -> finalModifier
.border(BorderStroke(2.dp, OvulationColor), RoundedCornerShape(8.dp))
isPeriod -> finalModifier
.border(BorderStroke(1.dp, PeriodColor), RoundedCornerShape(8.dp))
isFertile -> finalModifier
.border(BorderStroke(1.dp, FertileColor), RoundedCornerShape(8.dp))
isPms -> finalModifier
.border(BorderStroke(1.dp, PmsColor), RoundedCornerShape(8.dp))
else -> finalModifier
.border(BorderStroke(1.dp, Color.Transparent), RoundedCornerShape(8.dp))
} }
// Добавляем модификаторы в зависимости от фазы // Добавляем дополнительный тонкий контур для выделения сегодняшнего дня
val baseModifier = Modifier if (isToday && !isOvulation && !isPeriod && !isFertile && !isPms) {
.size(36.dp) finalModifier = finalModifier.border(
.clip(CircleShape) BorderStroke(1.dp, MaterialTheme.colorScheme.outline.copy(alpha = 0.6f)),
.background(backgroundColor) RoundedCornerShape(8.dp)
)
// Особое выделение для овуляции
val finalModifier = if (isOvulation) {
baseModifier.border(BorderStroke(2.dp, OvulationBorder), CircleShape)
} else {
baseModifier
} }
Box( Box(
@@ -230,7 +255,7 @@ fun CalendarDay(
text = date.dayOfMonth.toString(), text = date.dayOfMonth.toString(),
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
fontWeight = if (isToday) FontWeight.Bold else FontWeight.Normal, fontWeight = if (isToday) FontWeight.Bold else FontWeight.Normal,
color = if (isToday) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface color = MaterialTheme.colorScheme.onSurface
) )
} }
} }

View File

@@ -1,24 +1,13 @@
package kr.smartsoltech.wellshe.ui.navigation package kr.smartsoltech.wellshe.ui.navigation
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material3.*
import androidx.compose.material.icons.filled.Analytics
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.WbSunny
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.NavigationBarItemDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -36,82 +25,93 @@ fun BottomNavigation(
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
NavigationBar( NavigationBar(
modifier = modifier.fillMaxWidth(), modifier = modifier
.fillMaxWidth()
.height(80.dp), // Минимальная высота Material3
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
tonalElevation = 8.dp tonalElevation = 8.dp,
windowInsets = WindowInsets(0.dp) // Убираем стандартные отступы
) { ) {
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination val currentDestination = navBackStackEntry?.destination
val items = listOf( val items = BottomNavItem.items
BottomNavItem.Cycle,
BottomNavItem.Body,
BottomNavItem.Mood,
BottomNavItem.Analytics,
BottomNavItem.Profile
)
items.forEach { item -> Row(
val selected = currentDestination?.hierarchy?.any { it.route == item.route } == true modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
items.forEach { item ->
val selected = currentDestination?.hierarchy?.any { it.route == item.route } == true
// Определяем цвет фона для выбранного элемента // Определяем цвет фона для выбранного элемента
val backgroundColor = when (item) { val backgroundColor = when (item) {
BottomNavItem.Cycle -> CycleTabColor BottomNavItem.Cycle -> CycleTabColor
BottomNavItem.Body -> BodyTabColor BottomNavItem.Body -> BodyTabColor
BottomNavItem.Mood -> MoodTabColor BottomNavItem.Mood -> MoodTabColor
BottomNavItem.Analytics -> AnalyticsTabColor BottomNavItem.Analytics -> AnalyticsTabColor
BottomNavItem.Profile -> ProfileTabColor BottomNavItem.Profile -> ProfileTabColor
} }
NavigationBarItem( // Создаем кастомный элемент навигации с привязкой к верхнему краю
icon = { Column(
modifier = Modifier
.weight(1f)
.clickable {
navController.navigate(item.route) {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
// Avoid multiple copies of the same destination
launchSingleTop = true
// Restore state when reselecting
restoreState = true
}
}
.padding(4.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top // Привязываем контент к верхнему краю
) {
// Иконка - размещаем вверху
if (selected) { if (selected) {
Icon( Icon(
imageVector = item.icon, imageVector = item.icon,
contentDescription = item.title, contentDescription = item.title,
modifier = Modifier modifier = Modifier
.size(24.dp) .padding(top = 4.dp)
.clip(RoundedCornerShape(4.dp)) .size(36.dp)
.clip(RoundedCornerShape(6.dp))
.background(backgroundColor) .background(backgroundColor)
.padding(2.dp) .padding(4.dp),
tint = MaterialTheme.colorScheme.onPrimaryContainer
) )
} else { } else {
Icon( Icon(
imageVector = item.icon, imageVector = item.icon,
contentDescription = item.title, contentDescription = item.title,
modifier = Modifier.size(24.dp) modifier = Modifier
.padding(top = 4.dp)
.size(32.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant
) )
} }
},
label = { // Текстовая метка
Spacer(modifier = Modifier.height(2.dp))
Text( Text(
text = item.title, text = item.title,
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
textAlign = TextAlign.Center color = if (selected)
MaterialTheme.colorScheme.onSurface
else
MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center,
maxLines = 1
) )
}, }
selected = selected, }
onClick = {
navController.navigate(item.route) {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true
}
},
colors = NavigationBarItemDefaults.colors(
selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer,
selectedTextColor = MaterialTheme.colorScheme.onSurface,
unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant
)
)
} }
} }
} }

View File

@@ -8,10 +8,14 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.navigation.compose.rememberNavController
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.compose.rememberNavController
import kr.smartsoltech.wellshe.ui.theme.WellSheTheme import kr.smartsoltech.wellshe.ui.theme.WellSheTheme
// Добавляем явный импорт для BottomNavigation из того же пакета
// Важно импортировать именно эту функцию, а не Material3 компонент с тем же именем
import kr.smartsoltech.wellshe.ui.navigation.BottomNavigation
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun WellSheNavigation() { fun WellSheNavigation() {

View File

@@ -39,8 +39,6 @@ val ErrorRedLight = Color(0xFFFFCDD2)
// Фоновые цвета // Фоновые цвета
val BackgroundPrimary = Color(0xFFFFFFFF) val BackgroundPrimary = Color(0xFFFFFFFF)
val BackgroundSecondary = Color(0xFFFAFAFA)
val BackgroundTertiary = Color(0xFFF5F5F5)
// Цвета для графиков и статистики // Цвета для графиков и статистики
val ChartPink = Color(0xFFE91E63) val ChartPink = Color(0xFFE91E63)
@@ -51,17 +49,20 @@ val ChartOrange = Color(0xFFFF9800)
val ChartRed = Color(0xFFF44336) val ChartRed = Color(0xFFF44336)
// Цвета для фаз цикла // Цвета для фаз цикла
val PeriodColor = Color(0xFFFFD6E0) // Розовый для менструации val PeriodColor = Color(0xFFE57373) // Менструация (розовый)
val FertileColor = Color(0xFFD6F5E3) // Зелёный для фертильного окна val FertileColor = Color(0xFF4CAF50) // Фертильное окно (зеленый)
val PmsColor = Color(0xFFFFF2CC) // Янтарный для ПМС val OvulationColor = Color(0xFF3F51B5) // Овуляция (синий)
val OvulationBorder = Color(0xFF6366F1) // Индиго для обводки дня овуляции val OvulationBorder = Color(0xFF3F51B5) // Граница для дня овуляции
val PmsColor = Color(0xFFFFA726) // ПМС (оранжевый/янтарный)
// Цвета для вкладок // Цвет вкладки цикла
val CycleTabColor = Color(0xFFFFF8E1) // Янтарный для вкладки Цикл val CycleTabColor = Color(0xFFFFD54F) // Янтарный цвет для вкладки цикла
val BodyTabColor = Color(0xFFE3F2FD) // Синий для вкладки Тело
val MoodTabColor = Color(0xFFFCE4EC) // Розовый для вкладки Настроение // Цвета для вкладок приложения
val AnalyticsTabColor = Color(0xFFE0F2F1) // Изумрудный для вкладки Аналитика val AnalyticsTabColor = Color(0xFFB2DFDB) // Бирюзовый для вкладки Аналитика
val ProfileTabColor = Color(0xFFF5F5F5) // Серый для вкладки Профиль val BodyTabColor = Color(0xFFBBDEFB) // Голубой для вкладки Тело
val MoodTabColor = Color(0xFFF8BBD0) // Розовый для вкладки Настроение
val ProfileTabColor = Color(0xFFD1C4E9) // Лавандовый для вкладки Профиль
// Акцентные цвета для разделов // Акцентные цвета для разделов
val WaterColor = Color(0xFF2196F3) // Синий для воды val WaterColor = Color(0xFF2196F3) // Синий для воды