Рефакторинг компонентов и исправление календаря
This commit is contained in:
Generated
+1
-1
@@ -12,6 +12,6 @@
|
|||||||
</deviceKey>
|
</deviceKey>
|
||||||
</Target>
|
</Target>
|
||||||
</runningDeviceTargetSelectedWithDropDown>
|
</runningDeviceTargetSelectedWithDropDown>
|
||||||
<timeTargetWasSelectedWithDropDown value="2023-02-28T10:56:39.519355800Z" />
|
<timeTargetWasSelectedWithDropDown value="2023-04-02T15:04:59.965857200Z" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.megboyzz.dnevnik
|
package ru.megboyzz.dnevnik
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.window.SplashScreen
|
import android.window.SplashScreen
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
@@ -13,7 +14,6 @@ import ru.megboyzz.dnevnik.ui.theme.*
|
|||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContent {
|
setContent {
|
||||||
Surface(
|
Surface(
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -24,14 +22,12 @@ import androidx.compose.ui.res.vectorResource
|
|||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import com.kizitonwose.calendar.compose.CalendarLayoutInfo
|
||||||
|
import com.kizitonwose.calendar.compose.CalendarState
|
||||||
|
import com.kizitonwose.calendar.core.CalendarMonth
|
||||||
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import ru.megboyzz.dnevnik.navigation.BaseNavRote
|
import ru.megboyzz.dnevnik.navigation.BaseNavRote
|
||||||
import ru.megboyzz.dnevnik.screens.ui.Month
|
|
||||||
import ru.megboyzz.dnevnik.ui.theme.dark
|
import ru.megboyzz.dnevnik.ui.theme.dark
|
||||||
import java.time.DayOfWeek
|
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.Year
|
|
||||||
import java.time.temporal.TemporalAdjusters
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Int.AsPainter() = painterResource(this)
|
fun Int.AsPainter() = painterResource(this)
|
||||||
@@ -110,21 +106,6 @@ fun Modifier.drawColoredShadow(
|
|||||||
}
|
}
|
||||||
} else this
|
} else this
|
||||||
|
|
||||||
fun getMonthDaysBy(year: Int, month: Month, dayOfWeek: DayOfWeek): List<Int>{
|
|
||||||
var date: LocalDate =
|
|
||||||
Year.of(year).atMonth(month.ordinal + 1).atDay(1).with(TemporalAdjusters.firstInMonth(dayOfWeek))
|
|
||||||
var mi = date.month
|
|
||||||
|
|
||||||
val list = mutableListOf<Int>()
|
|
||||||
|
|
||||||
while (mi.ordinal == month.ordinal) {
|
|
||||||
list.add(date.dayOfMonth)
|
|
||||||
date = date.with(TemporalAdjusters.next(dayOfWeek))
|
|
||||||
mi = date.month
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Modifier.mainClickable(
|
fun Modifier.mainClickable(
|
||||||
radius: Dp = Dp.Unspecified,
|
radius: Dp = Dp.Unspecified,
|
||||||
@@ -138,4 +119,33 @@ fun Modifier.mainClickable(
|
|||||||
onClick = onClick
|
onClick = onClick
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberFirstMostVisibleMonth(
|
||||||
|
state: CalendarState,
|
||||||
|
viewportPercent: Float = 50f,
|
||||||
|
): CalendarMonth {
|
||||||
|
val visibleMonth = remember(state) { mutableStateOf(state.firstVisibleMonth) }
|
||||||
|
LaunchedEffect(state) {
|
||||||
|
snapshotFlow { state.layoutInfo.firstMostVisibleMonth(viewportPercent) }
|
||||||
|
.filterNotNull()
|
||||||
|
.collect { month -> visibleMonth.value = month }
|
||||||
|
}
|
||||||
|
return visibleMonth.value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun CalendarLayoutInfo.firstMostVisibleMonth(viewportPercent: Float = 50f): CalendarMonth? {
|
||||||
|
return if (visibleMonthsInfo.isEmpty()) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
val viewportSize = (viewportEndOffset + viewportStartOffset) * viewportPercent / 100f
|
||||||
|
visibleMonthsInfo.firstOrNull { itemInfo ->
|
||||||
|
if (itemInfo.offset < 0) {
|
||||||
|
itemInfo.offset + itemInfo.size >= viewportSize
|
||||||
|
} else {
|
||||||
|
itemInfo.size - itemInfo.offset >= viewportSize
|
||||||
|
}
|
||||||
|
}?.month
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,13 +38,6 @@ sealed class AppNavRoute(override val route: String): BaseNavRote(route){
|
|||||||
@Composable
|
@Composable
|
||||||
fun AppNavHost(){
|
fun AppNavHost(){
|
||||||
|
|
||||||
/*val activity = LocalContext.current as MainActivity
|
|
||||||
|
|
||||||
val application = activity.application as App
|
|
||||||
|
|
||||||
val viewModel: AppViewModel = viewModel(factory = AppViewModelFactory(application))*/
|
|
||||||
|
|
||||||
|
|
||||||
val scaffoldState = rememberScaffoldState()
|
val scaffoldState = rememberScaffoldState()
|
||||||
val navController = rememberAnimatedNavController()
|
val navController = rememberAnimatedNavController()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package ru.megboyzz.dnevnik.screens.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import ru.megboyzz.dnevnik.*
|
||||||
|
import ru.megboyzz.dnevnik.navigation.AppNavRoute
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.MainText
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.mainBlue
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.white
|
||||||
|
import ru.megboyzz.dnevnik.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BottomBar(navController: NavController) {
|
||||||
|
//Box(Modifier.fillMaxWidth().height(90.dp).shadow(8.dp))
|
||||||
|
|
||||||
|
// УЖАСНЫЙ КОСТЫЛЬ ДЛЯ ПЕРЕХОДОВ С ПОМОЩЬЮ СТЕЙТОВ TODO - УБРАТЬ
|
||||||
|
val goToMarks = remember { mutableStateOf(false) }
|
||||||
|
val goToHw = remember { mutableStateOf(false) }
|
||||||
|
val goToSchedule = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
if(goToMarks.value){
|
||||||
|
navController.navigate(AppNavRoute.Marks)
|
||||||
|
//goToMarks.value = false
|
||||||
|
}
|
||||||
|
if(goToHw.value){
|
||||||
|
navController.navigate(AppNavRoute.HomeWorks)
|
||||||
|
//goToHw.value = false
|
||||||
|
}
|
||||||
|
if(goToSchedule.value){
|
||||||
|
navController.navigate(AppNavRoute.Schedule)
|
||||||
|
//goToSchedule.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.drawColoredShadow(
|
||||||
|
offsetY = 1.dp
|
||||||
|
)
|
||||||
|
.height(90.dp)
|
||||||
|
.background(white)
|
||||||
|
.padding(10.dp, 10.dp, 10.dp, 15.dp),
|
||||||
|
){
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.clip(RoundedCornerShape(20.dp))
|
||||||
|
.background(mainBlue)
|
||||||
|
){
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
BottomNavButton(
|
||||||
|
icon = R.drawable.ic_marks.AsPainter(),
|
||||||
|
text = R.string.title_marks.AsString()
|
||||||
|
) { goToMarks.value = true }
|
||||||
|
BottomNavButton(
|
||||||
|
icon = R.drawable.ic_homework.AsPainter(),
|
||||||
|
text = R.string.title_hw.AsString()
|
||||||
|
) { goToHw.value = true }
|
||||||
|
BottomNavButton(
|
||||||
|
icon = R.drawable.ic_schedule.AsPainter(),
|
||||||
|
text = R.string.title_schedule.AsString()
|
||||||
|
) { goToSchedule.value = true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BottomNavButton(
|
||||||
|
icon: Painter,
|
||||||
|
text: String,
|
||||||
|
color: Color = white,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
) {
|
||||||
|
//Возможно стоит убрать анимацию клика
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.mainClickable(onClick = onClick, radius = 20.dp)
|
||||||
|
.padding(10.dp)) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = icon,
|
||||||
|
contentDescription = "",
|
||||||
|
modifier = Modifier.padding(5.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
style = MainText,
|
||||||
|
color = color,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
package ru.megboyzz.dnevnik.screens.ui
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.*
|
|
||||||
import androidx.compose.foundation.layout.*
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.Card
|
|
||||||
import androidx.compose.material.Divider
|
|
||||||
import androidx.compose.material.IconButton
|
|
||||||
import androidx.compose.material.Text
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import com.kizitonwose.calendar.compose.CalendarState
|
|
||||||
import com.kizitonwose.calendar.compose.HorizontalCalendar
|
|
||||||
import com.kizitonwose.calendar.compose.WeekCalendar
|
|
||||||
import com.kizitonwose.calendar.compose.rememberCalendarState
|
|
||||||
import com.kizitonwose.calendar.compose.weekcalendar.rememberWeekCalendarState
|
|
||||||
import com.kizitonwose.calendar.core.CalendarDay
|
|
||||||
import com.kizitonwose.calendar.core.CalendarMonth
|
|
||||||
import com.kizitonwose.calendar.core.DayPosition
|
|
||||||
import com.kizitonwose.calendar.core.firstDayOfWeekFromLocale
|
|
||||||
import ru.megboyzz.dnevnik.AsPainter
|
|
||||||
import ru.megboyzz.dnevnik.AsString
|
|
||||||
import ru.megboyzz.dnevnik.R
|
|
||||||
import ru.megboyzz.dnevnik.ui.theme.*
|
|
||||||
import java.time.DayOfWeek
|
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.YearMonth
|
|
||||||
import java.time.format.TextStyle
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MonthToggler(calendarState: CalendarState) {
|
|
||||||
|
|
||||||
//TODO убрать это куда нибудь
|
|
||||||
var listOfMonth = listOf(
|
|
||||||
R.string.title_january.AsString(),
|
|
||||||
R.string.title_february.AsString(),
|
|
||||||
R.string.title_march.AsString(),
|
|
||||||
R.string.title_april.AsString(),
|
|
||||||
R.string.title_may.AsString(),
|
|
||||||
R.string.title_june.AsString(),
|
|
||||||
R.string.title_july.AsString(),
|
|
||||||
R.string.title_august.AsString(),
|
|
||||||
R.string.title_september.AsString(),
|
|
||||||
R.string.title_october.AsString(),
|
|
||||||
R.string.title_november.AsString(),
|
|
||||||
R.string.title_december.AsString()
|
|
||||||
)
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(0.dp, 20.dp),
|
|
||||||
horizontalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
IconButton(onClick = { calendarState.startMonth = calendarState.startMonth.minusMonths(1) }) {
|
|
||||||
Image(
|
|
||||||
painter = R.drawable.ic_month_swipe_left.AsPainter(),
|
|
||||||
contentDescription = "left",
|
|
||||||
alignment = Alignment.Center
|
|
||||||
)
|
|
||||||
}
|
|
||||||
for(style in TextStyle.values())
|
|
||||||
Log.i("check", calendarState.startMonth.month.getDisplayName(style, Locale.getDefault()))
|
|
||||||
Text(
|
|
||||||
//TODO Возможно стоит сделать эту строчку меньше((
|
|
||||||
text = "${listOfMonth[calendarState.startMonth.month.ordinal]} ${calendarState.startMonth.year}",
|
|
||||||
style = H1,
|
|
||||||
color = dark
|
|
||||||
)
|
|
||||||
IconButton(
|
|
||||||
onClick = { calendarState.startMonth = calendarState.startMonth.plusMonths(1) }
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
painter = R.drawable.ic_month_swipe_right.AsPainter(),
|
|
||||||
contentDescription = "right",
|
|
||||||
alignment = Alignment.Center
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO доделать свертку календаря, он почти идеально работает
|
|
||||||
@Composable
|
|
||||||
fun NiceCalendar(
|
|
||||||
startMonth: YearMonth,
|
|
||||||
onClick: (day: CalendarDay, month: YearMonth, year: Int) -> Unit
|
|
||||||
) {
|
|
||||||
val endMonth = startMonth.plusMonths(100) // Adjust as needed
|
|
||||||
val firstDayOfWeek = remember { firstDayOfWeekFromLocale() } // Available from the library
|
|
||||||
|
|
||||||
val state = rememberCalendarState(
|
|
||||||
startMonth = startMonth,
|
|
||||||
endMonth = endMonth,
|
|
||||||
firstVisibleMonth = startMonth,
|
|
||||||
firstDayOfWeek = firstDayOfWeek
|
|
||||||
)
|
|
||||||
|
|
||||||
val weekState = rememberWeekCalendarState(
|
|
||||||
startDate = startMonth.atDay(1),
|
|
||||||
endDate = startMonth.atDay(7),
|
|
||||||
firstVisibleWeekDate = startMonth.atDay(1),
|
|
||||||
firstDayOfWeek = firstDayOfWeek
|
|
||||||
)
|
|
||||||
|
|
||||||
var selectedDate by remember { mutableStateOf<LocalDate?>(null) }
|
|
||||||
|
|
||||||
Column {
|
|
||||||
|
|
||||||
MonthToggler(calendarState = state)
|
|
||||||
|
|
||||||
Card(
|
|
||||||
shape = RoundedCornerShape(10.dp),
|
|
||||||
modifier = Modifier.defaultMinSize(300.dp)
|
|
||||||
) {
|
|
||||||
if(selectedDate == null)
|
|
||||||
HorizontalCalendar(
|
|
||||||
state = state,
|
|
||||||
dayContent = { day ->
|
|
||||||
Day(day, isSelected = selectedDate == day.date) { day ->
|
|
||||||
selectedDate = if (selectedDate == day.date) null else day.date
|
|
||||||
onClick(day, startMonth, startMonth.year)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
monthHeader = { DaysOfWeekTitle(daysOfWeek = DayOfWeek.values().asList()) },
|
|
||||||
modifier = Modifier.padding(10.dp)
|
|
||||||
)
|
|
||||||
else
|
|
||||||
//TODO по возможности устранить повторы
|
|
||||||
WeekCalendar(
|
|
||||||
state = weekState,
|
|
||||||
weekHeader = { _ ->
|
|
||||||
DaysOfWeekTitle(daysOfWeek = DayOfWeek.values().asList())
|
|
||||||
},
|
|
||||||
dayContent = { day ->
|
|
||||||
Day(CalendarDay(day.date, DayPosition.InDate), isSelected = selectedDate == day.date) { day ->
|
|
||||||
selectedDate = if (selectedDate == day.date) null else day.date
|
|
||||||
onClick(day, startMonth, startMonth.year)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifier = Modifier.padding(10.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun DaysOfWeekTitle(daysOfWeek: List<DayOfWeek>) {
|
|
||||||
Column {
|
|
||||||
Row(modifier = Modifier.fillMaxWidth()) {
|
|
||||||
for (dayOfWeek in daysOfWeek) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
text = dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.getDefault()).uppercase(),
|
|
||||||
style = MainText
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Divider(
|
|
||||||
thickness = 1.dp,
|
|
||||||
color = dark,
|
|
||||||
modifier = Modifier.padding(vertical = 10.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Composable
|
|
||||||
fun Day(day: CalendarDay, isSelected: Boolean, onClick: (CalendarDay) -> Unit) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.aspectRatio(ratio = 1f) // This is important for square sizing!
|
|
||||||
.clip(CircleShape)
|
|
||||||
.background(color = if (isSelected) lightGray else Color.Transparent)
|
|
||||||
.border(
|
|
||||||
border = BorderStroke(
|
|
||||||
width = 1.dp,
|
|
||||||
color = if (isSelected) mainBlue else Color.Transparent
|
|
||||||
),
|
|
||||||
shape = CircleShape
|
|
||||||
)
|
|
||||||
.clickable(
|
|
||||||
enabled = day.position == DayPosition.MonthDate,
|
|
||||||
onClick = { onClick(day) }
|
|
||||||
),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = day.date.dayOfMonth.toString(),
|
|
||||||
style = MainText,
|
|
||||||
color = if (day.position == DayPosition.MonthDate) dark else Color.Gray
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -50,152 +50,10 @@ import java.time.DayOfWeek
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
//Рефакторинг компонентов: разбиение файла с компонентами на отдельные файлы
|
||||||
fun MainScaffold(
|
//Этот файл должен хранить только базовые реализации компонентов и общие компонеты компонеты
|
||||||
icon: Painter,
|
|
||||||
title: String,
|
|
||||||
/* TODO viewModel */
|
|
||||||
navController: NavController,
|
|
||||||
scaffoldState: ScaffoldState,
|
|
||||||
content: (@Composable (it: PaddingValues) -> Unit),
|
|
||||||
) {
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
Scaffold(
|
|
||||||
scaffoldState = scaffoldState,
|
|
||||||
topBar = {
|
|
||||||
TopAppBar(
|
|
||||||
backgroundColor = mainBlue,
|
|
||||||
contentColor = Color.White
|
|
||||||
) {
|
|
||||||
IconButton(
|
|
||||||
onClick = {
|
|
||||||
val drawerState = scaffoldState.drawerState
|
|
||||||
scope.launch {
|
|
||||||
if (drawerState.isClosed)
|
|
||||||
drawerState.open()
|
|
||||||
else
|
|
||||||
drawerState.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Menu,
|
|
||||||
contentDescription = "menu",
|
|
||||||
tint = white
|
|
||||||
)
|
|
||||||
}
|
|
||||||
SpacerWidth(width = 5.dp)
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
fontSize = 16.sp,
|
|
||||||
color = white
|
|
||||||
)
|
|
||||||
Spacer(Modifier.weight(1f))
|
|
||||||
Box(Modifier.padding(15.dp, 15.dp)) {
|
|
||||||
Image(painter = icon, contentDescription = "icon")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
content = content,
|
|
||||||
drawerBackgroundColor = mainBlue,
|
|
||||||
drawerContentColor = white,
|
|
||||||
drawerShape = drawerShape,
|
|
||||||
drawerContent = { DrawerContent(navController, scaffoldState) },
|
|
||||||
bottomBar = { BottomBar(navController) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun BottomBar(navController: NavController) {
|
|
||||||
//Box(Modifier.fillMaxWidth().height(90.dp).shadow(8.dp))
|
|
||||||
|
|
||||||
// УЖАСНЫЙ КОСТЫЛЬ ДЛЯ ПЕРЕХОДОВ С ПОМОЩЬЮ СТЕЙТОВ TODO - УБРАТЬ
|
|
||||||
val goToMarks = remember { mutableStateOf(false) }
|
|
||||||
val goToHw = remember { mutableStateOf(false) }
|
|
||||||
val goToSchedule = remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
if(goToMarks.value){
|
|
||||||
navController.navigate(AppNavRoute.Marks)
|
|
||||||
//goToMarks.value = false
|
|
||||||
}
|
|
||||||
if(goToHw.value){
|
|
||||||
navController.navigate(AppNavRoute.HomeWorks)
|
|
||||||
//goToHw.value = false
|
|
||||||
}
|
|
||||||
if(goToSchedule.value){
|
|
||||||
navController.navigate(AppNavRoute.Schedule)
|
|
||||||
//goToSchedule.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.drawColoredShadow(
|
|
||||||
offsetY = 1.dp
|
|
||||||
)
|
|
||||||
.height(90.dp)
|
|
||||||
.background(white)
|
|
||||||
.padding(10.dp, 10.dp, 10.dp, 15.dp),
|
|
||||||
){
|
|
||||||
Box(
|
|
||||||
Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.clip(RoundedCornerShape(20.dp))
|
|
||||||
.background(mainBlue)
|
|
||||||
){
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
) {
|
|
||||||
BottomNavButton(
|
|
||||||
icon = R.drawable.ic_marks.AsPainter(),
|
|
||||||
text = R.string.title_marks.AsString()
|
|
||||||
) { goToMarks.value = true }
|
|
||||||
BottomNavButton(
|
|
||||||
icon = R.drawable.ic_homework.AsPainter(),
|
|
||||||
text = R.string.title_hw.AsString()
|
|
||||||
) { goToHw.value = true }
|
|
||||||
BottomNavButton(
|
|
||||||
icon = R.drawable.ic_schedule.AsPainter(),
|
|
||||||
text = R.string.title_schedule.AsString()
|
|
||||||
) { goToSchedule.value = true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun BottomNavButton(
|
|
||||||
icon: Painter,
|
|
||||||
text: String,
|
|
||||||
color: Color = white,
|
|
||||||
onClick: () -> Unit,
|
|
||||||
) {
|
|
||||||
//Возможно стоит убрать анимацию клика
|
|
||||||
Box(
|
|
||||||
Modifier
|
|
||||||
.mainClickable(onClick = onClick, radius = 20.dp)
|
|
||||||
.padding(10.dp)) {
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
painter = icon,
|
|
||||||
contentDescription = "",
|
|
||||||
modifier = Modifier.padding(5.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = text,
|
|
||||||
style = MainText,
|
|
||||||
color = color,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AlmostOutlinedText(
|
fun AlmostOutlinedText(
|
||||||
@@ -251,34 +109,6 @@ fun ProfileCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun LoginBackground() {
|
|
||||||
val icon = R.drawable.ic_header.AsPainter()
|
|
||||||
val size = icon.intrinsicSize
|
|
||||||
Column {
|
|
||||||
Image(
|
|
||||||
painter = icon,
|
|
||||||
contentDescription = "",
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
contentScale = ContentScale.FillWidth,
|
|
||||||
alignment = Alignment.TopStart
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun BigLoginBackground() {
|
|
||||||
val icon = R.drawable.header_big.AsPainter()
|
|
||||||
Column(Modifier.fillMaxWidth()) {
|
|
||||||
Image(
|
|
||||||
painter = icon,
|
|
||||||
contentDescription = "",
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
alignment = Alignment.TopStart
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainTextField(
|
fun MainTextField(
|
||||||
value: MutableState<String>,
|
value: MutableState<String>,
|
||||||
@@ -425,180 +255,6 @@ fun MainButton(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun LoginScreenContent(
|
|
||||||
login: MutableState<String>,
|
|
||||||
password: MutableState<String>,
|
|
||||||
isError: MutableState<Boolean>,
|
|
||||||
isRememberMe: MutableState<Boolean>,
|
|
||||||
onSignIn: () -> Unit,
|
|
||||||
onSignUp: () -> Unit,
|
|
||||||
onForgetPassword: () -> Unit
|
|
||||||
) {
|
|
||||||
val configuration = LocalConfiguration.current
|
|
||||||
val screenWidth = configuration.screenWidthDp
|
|
||||||
|
|
||||||
var defaultPadding = 65.dp
|
|
||||||
|
|
||||||
val isNormal = screenWidth < 500
|
|
||||||
|
|
||||||
Box(Modifier.fillMaxSize()) {
|
|
||||||
|
|
||||||
if(!isNormal) BigLoginBackground()
|
|
||||||
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
if (isNormal) LoginBackground()
|
|
||||||
else {
|
|
||||||
defaultPadding *= 4
|
|
||||||
}
|
|
||||||
Row(horizontalArrangement = Arrangement.Center) {
|
|
||||||
Text(
|
|
||||||
text = R.string.title_welcome.AsString(),
|
|
||||||
style = Big,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
modifier = Modifier.padding(defaultPadding, 20.dp, defaultPadding, 40.dp),
|
|
||||||
color = dark
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(defaultPadding, 0.dp)
|
|
||||||
) {
|
|
||||||
Column(Modifier.fillMaxWidth()) {
|
|
||||||
MainTextField(
|
|
||||||
value = login,
|
|
||||||
label = R.string.title_login.AsString(),
|
|
||||||
isError = isError
|
|
||||||
)
|
|
||||||
SpacerHeight(15.dp)
|
|
||||||
MainTextField(
|
|
||||||
value = password,
|
|
||||||
keyboardType = KeyboardType.Password,
|
|
||||||
label = R.string.title_password.AsString(),
|
|
||||||
isError = isError
|
|
||||||
)
|
|
||||||
}
|
|
||||||
SpacerHeight(5.dp)
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(30.dp),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxHeight(),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
MainCheckbox(isRememberMe) { }
|
|
||||||
SpacerWidth(5.dp)
|
|
||||||
Text(
|
|
||||||
text = R.string.title_remember_me.AsString(),
|
|
||||||
style = MainText,
|
|
||||||
color = dark
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
text = R.string.title_forget_password.AsString(),
|
|
||||||
style = MainText,
|
|
||||||
color = dark,
|
|
||||||
modifier = Modifier.clickable(onClick = onForgetPassword)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(0.dp, 10.dp),
|
|
||||||
verticalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
MainButton(
|
|
||||||
text = R.string.title_sign_in.AsString(),
|
|
||||||
onClick = onSignIn
|
|
||||||
)
|
|
||||||
SpacerHeight(5.dp)
|
|
||||||
Text(
|
|
||||||
text = R.string.title_sign_up.AsString(),
|
|
||||||
modifier = Modifier
|
|
||||||
.clickable(onClick = onSignUp)
|
|
||||||
.padding(5.dp)
|
|
||||||
.fillMaxWidth(),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
style = Mini,
|
|
||||||
color = dark
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SubScreenNavButton(
|
|
||||||
text: String,
|
|
||||||
isClicked: MutableState<Boolean>,
|
|
||||||
onCLick: () -> Unit
|
|
||||||
) {
|
|
||||||
val colors = ButtonDefaults.buttonColors(
|
|
||||||
backgroundColor = if(isClicked.value) mainBlue else white,
|
|
||||||
contentColor = if(isClicked.value) white else dark
|
|
||||||
)
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
isClicked.value = !isClicked.value
|
|
||||||
onCLick.invoke()
|
|
||||||
},
|
|
||||||
shape = RoundedCornerShape(20.dp),
|
|
||||||
border = BorderStroke(
|
|
||||||
width = 1.dp,
|
|
||||||
color = mainBlue,
|
|
||||||
),
|
|
||||||
colors = colors,
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = text,
|
|
||||||
style= MainText
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class SubScreenData(
|
|
||||||
val title: String,
|
|
||||||
val to: BaseNavRote,
|
|
||||||
val isClicked: MutableState<Boolean>
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SubScreenNavBar(
|
|
||||||
list: List<SubScreenData>,
|
|
||||||
subScreenNavController: NavController
|
|
||||||
) {
|
|
||||||
val horizontalScroll = rememberScrollState()
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.horizontalScroll(horizontalScroll)
|
|
||||||
.padding(15.dp),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(15.dp)
|
|
||||||
){
|
|
||||||
for(data in list){
|
|
||||||
if(data.isClicked.value)
|
|
||||||
subScreenNavController.navigate(data.to)
|
|
||||||
SubScreenNavButton(
|
|
||||||
text = data.title,
|
|
||||||
isClicked = data.isClicked
|
|
||||||
) {
|
|
||||||
for(d in list){
|
|
||||||
if(data != d)
|
|
||||||
d.isClicked.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Базовая карточка для оценок, карточек с диаграммами
|
//Базовая карточка для оценок, карточек с диаграммами
|
||||||
@Composable
|
@Composable
|
||||||
fun BaseCard(
|
fun BaseCard(
|
||||||
@@ -746,349 +402,6 @@ fun LastMarkCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Month{
|
|
||||||
January,
|
|
||||||
February,
|
|
||||||
March,
|
|
||||||
April,
|
|
||||||
May,
|
|
||||||
June,
|
|
||||||
July,
|
|
||||||
August,
|
|
||||||
September,
|
|
||||||
October,
|
|
||||||
November,
|
|
||||||
December,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
|
||||||
fun NewCardCalendar(
|
|
||||||
month: Month,
|
|
||||||
year: Int,
|
|
||||||
onClick: (day: Int) -> Unit,
|
|
||||||
) {
|
|
||||||
val listOfDays = listOf(
|
|
||||||
R.string.title_mon.AsString(),
|
|
||||||
R.string.title_tue.AsString(),
|
|
||||||
R.string.title_wed.AsString(),
|
|
||||||
R.string.title_thu.AsString(),
|
|
||||||
R.string.title_fri.AsString(),
|
|
||||||
R.string.title_sat.AsString(),
|
|
||||||
)
|
|
||||||
|
|
||||||
//TODO Сделать сворачивание календаря
|
|
||||||
val expanded = remember {
|
|
||||||
mutableStateOf(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
Card(
|
|
||||||
backgroundColor = white,
|
|
||||||
modifier = Modifier.defaultMinSize(minWidth = 300.dp),
|
|
||||||
shape = RoundedCornerShape(10.dp),
|
|
||||||
elevation = 5.dp
|
|
||||||
){
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(0.dp)
|
|
||||||
) {
|
|
||||||
/*LazyRow(
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(10.dp, 10.dp, 10.dp, 5.dp)
|
|
||||||
.defaultMinSize(minWidth = 300.dp)
|
|
||||||
){
|
|
||||||
items(listOfDays){
|
|
||||||
Text(
|
|
||||||
text = it,
|
|
||||||
style = MainText,
|
|
||||||
color = dark
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Box(
|
|
||||||
Modifier
|
|
||||||
.defaultMinSize(minWidth = 320.dp)
|
|
||||||
.height(1.dp)
|
|
||||||
.background(Color.Black))*/
|
|
||||||
LazyVerticalGrid(
|
|
||||||
columns = GridCells.Fixed(count = 6),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(0.dp),
|
|
||||||
){
|
|
||||||
items(listOfDays){
|
|
||||||
Text(
|
|
||||||
text = it,
|
|
||||||
style = MainText,
|
|
||||||
color = dark
|
|
||||||
)
|
|
||||||
}
|
|
||||||
items((1..30).toList()){
|
|
||||||
NumberOnCalendar(
|
|
||||||
isClicked = remember { mutableStateOf(false) },
|
|
||||||
number = it.toString()
|
|
||||||
) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val offset = 8 - getMonthDaysBy(year, month, DayOfWeek.MONDAY)[0]
|
|
||||||
|
|
||||||
val clicked = mutableListOf<MutableState<Boolean>>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CardCalendar(
|
|
||||||
month: Month,
|
|
||||||
year: Int,
|
|
||||||
onClick: (day: Int) -> Unit,
|
|
||||||
) {
|
|
||||||
val listOfDays = listOf(
|
|
||||||
R.string.title_mon.AsString(),
|
|
||||||
R.string.title_tue.AsString(),
|
|
||||||
R.string.title_wed.AsString(),
|
|
||||||
R.string.title_thu.AsString(),
|
|
||||||
R.string.title_fri.AsString(),
|
|
||||||
R.string.title_sat.AsString(),
|
|
||||||
)
|
|
||||||
|
|
||||||
//TODO Сделать сворачивание календаря
|
|
||||||
val expanded = remember {
|
|
||||||
mutableStateOf(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
Card(
|
|
||||||
backgroundColor = white,
|
|
||||||
modifier = Modifier.defaultMinSize(minWidth = 200.dp),
|
|
||||||
shape = RoundedCornerShape(10.dp),
|
|
||||||
elevation = 5.dp
|
|
||||||
){
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(15.dp)
|
|
||||||
){
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(10.dp, 0.dp, 10.dp, 5.dp)
|
|
||||||
){
|
|
||||||
for(day in listOfDays){
|
|
||||||
Text(
|
|
||||||
text = day,
|
|
||||||
style = MainText,
|
|
||||||
color = dark
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Divider(
|
|
||||||
thickness = 1.dp,
|
|
||||||
color = dark,
|
|
||||||
modifier = Modifier.padding(0.dp, 0.dp, 0.dp, 10.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
val offset = 8 - getMonthDaysBy(year, month, DayOfWeek.MONDAY)[0]
|
|
||||||
|
|
||||||
val clicked = mutableListOf<MutableState<Boolean>>()
|
|
||||||
var lastClicked = 0
|
|
||||||
var lastInd = 0
|
|
||||||
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(0.dp, 10.dp, 0.dp, 5.dp)
|
|
||||||
) {
|
|
||||||
if(expanded.value)
|
|
||||||
for(day in DayOfWeek.values()){
|
|
||||||
if(day != DayOfWeek.SUNDAY) Column {
|
|
||||||
val list = getMonthDaysBy(year, month, day)
|
|
||||||
var len = 0
|
|
||||||
if(day.ordinal + 1 <= offset && offset !in 6..7){
|
|
||||||
EmptyNumberOnCalendar()
|
|
||||||
len++
|
|
||||||
}
|
|
||||||
for(i in list.indices){
|
|
||||||
val data = list[i]
|
|
||||||
val isClicked = remember { mutableStateOf(false) }
|
|
||||||
clicked.add(isClicked)
|
|
||||||
NumberOnCalendar(
|
|
||||||
isClicked = isClicked,
|
|
||||||
number = data.toString()
|
|
||||||
) {
|
|
||||||
expanded.value != expanded.value
|
|
||||||
lastClicked = data
|
|
||||||
lastInd = i
|
|
||||||
for(click in clicked)
|
|
||||||
if(click != isClicked)
|
|
||||||
click.value = false
|
|
||||||
onClick.invoke(data)
|
|
||||||
}
|
|
||||||
len++
|
|
||||||
}
|
|
||||||
if(day.ordinal + 1 > offset && len < 5){
|
|
||||||
EmptyNumberOnCalendar()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun EmptyNumberOnCalendar(){
|
|
||||||
NumberOnCalendar(isClicked = remember {
|
|
||||||
mutableStateOf(false)
|
|
||||||
}, number = "") {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun NumberOnCalendar(
|
|
||||||
isClicked: MutableState<Boolean>,
|
|
||||||
number: String,
|
|
||||||
onClick: () -> Unit
|
|
||||||
) {
|
|
||||||
val isClickedModifier = if(isClicked.value)
|
|
||||||
Modifier
|
|
||||||
.border(
|
|
||||||
width = 1.dp,
|
|
||||||
color = mainBlue,
|
|
||||||
shape = RoundedCornerShape(20.dp)
|
|
||||||
)
|
|
||||||
.background(
|
|
||||||
color = lightGray,
|
|
||||||
shape = RoundedCornerShape(20.dp)
|
|
||||||
)
|
|
||||||
.padding(2.dp)
|
|
||||||
else Modifier
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(30.dp)
|
|
||||||
.clickable(
|
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
|
||||||
indication = rememberRipple(radius = 15.dp, color = dark),
|
|
||||||
onClick = {
|
|
||||||
if (number != "") {
|
|
||||||
isClicked.value = !isClicked.value
|
|
||||||
onClick.invoke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(isClickedModifier),
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
){
|
|
||||||
Text(
|
|
||||||
text = number,
|
|
||||||
style = H2,
|
|
||||||
color = dark,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MonthToggle(
|
|
||||||
startMonth: Month,
|
|
||||||
startYear: Int,
|
|
||||||
onClick: (day: Int) -> Unit
|
|
||||||
) {
|
|
||||||
|
|
||||||
var listOfMonth = listOf(
|
|
||||||
R.string.title_january.AsString(),
|
|
||||||
R.string.title_february.AsString(),
|
|
||||||
R.string.title_march.AsString(),
|
|
||||||
R.string.title_april.AsString(),
|
|
||||||
R.string.title_may.AsString(),
|
|
||||||
R.string.title_june.AsString(),
|
|
||||||
R.string.title_july.AsString(),
|
|
||||||
R.string.title_august.AsString(),
|
|
||||||
R.string.title_september.AsString(),
|
|
||||||
R.string.title_october.AsString(),
|
|
||||||
R.string.title_november.AsString(),
|
|
||||||
R.string.title_december.AsString()
|
|
||||||
)
|
|
||||||
|
|
||||||
val month = remember {
|
|
||||||
mutableStateOf(startMonth)
|
|
||||||
}
|
|
||||||
val year = remember {
|
|
||||||
mutableStateOf(startYear)
|
|
||||||
}
|
|
||||||
|
|
||||||
val configuration = LocalConfiguration.current
|
|
||||||
val screenWidth = configuration.screenWidthDp
|
|
||||||
|
|
||||||
var defaultPadding = 35.dp
|
|
||||||
|
|
||||||
val isNormal = screenWidth < 500
|
|
||||||
if(!isNormal) defaultPadding *= 4
|
|
||||||
Column() {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(0.dp, 20.dp),
|
|
||||||
horizontalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
IconButton(onClick = {
|
|
||||||
var ind = month.value.ordinal - 1
|
|
||||||
if(ind == -1){
|
|
||||||
ind = 11
|
|
||||||
year.value = year.value - 1
|
|
||||||
}
|
|
||||||
month.value = Month.values()[ind]
|
|
||||||
}) {
|
|
||||||
Image(
|
|
||||||
painter = R.drawable.ic_month_swipe_left.AsPainter(),
|
|
||||||
contentDescription = "left",
|
|
||||||
alignment = Alignment.Center
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
text = "${listOfMonth[month.value.ordinal]} ${year.value}",
|
|
||||||
style = H1,
|
|
||||||
color = dark
|
|
||||||
)
|
|
||||||
IconButton(
|
|
||||||
onClick = {
|
|
||||||
var ind = month.value.ordinal + 1
|
|
||||||
if(ind == 12){
|
|
||||||
ind = 0
|
|
||||||
year.value = year.value + 1
|
|
||||||
}
|
|
||||||
month.value = Month.values()[ind]
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
painter = R.drawable.ic_month_swipe_right.AsPainter(),
|
|
||||||
contentDescription = "right",
|
|
||||||
alignment = Alignment.Center
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CardCalendar(
|
|
||||||
month = month.value,
|
|
||||||
year = year.value,
|
|
||||||
onClick = onClick
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UnderlinedText(
|
fun UnderlinedText(
|
||||||
text: String
|
text: String
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
package ru.megboyzz.dnevnik.screens.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ru.megboyzz.dnevnik.*
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.Big
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.MainText
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.Mini
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.dark
|
||||||
|
import ru.megboyzz.dnevnik.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoginScreenContent(
|
||||||
|
login: MutableState<String>,
|
||||||
|
password: MutableState<String>,
|
||||||
|
isError: MutableState<Boolean>,
|
||||||
|
isRememberMe: MutableState<Boolean>,
|
||||||
|
onSignIn: () -> Unit,
|
||||||
|
onSignUp: () -> Unit,
|
||||||
|
onForgetPassword: () -> Unit
|
||||||
|
) {
|
||||||
|
val configuration = LocalConfiguration.current
|
||||||
|
val screenWidth = configuration.screenWidthDp
|
||||||
|
|
||||||
|
var defaultPadding = 65.dp
|
||||||
|
|
||||||
|
val isNormal = screenWidth < 500
|
||||||
|
|
||||||
|
Box(Modifier.fillMaxSize()) {
|
||||||
|
|
||||||
|
if(!isNormal) BigLoginBackground()
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
if (isNormal) LoginBackground()
|
||||||
|
else {
|
||||||
|
defaultPadding *= 4
|
||||||
|
}
|
||||||
|
Row(horizontalArrangement = Arrangement.Center) {
|
||||||
|
Text(
|
||||||
|
text = R.string.title_welcome.AsString(),
|
||||||
|
style = Big,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(defaultPadding, 20.dp, defaultPadding, 40.dp),
|
||||||
|
color = dark
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(defaultPadding, 0.dp)
|
||||||
|
) {
|
||||||
|
Column(Modifier.fillMaxWidth()) {
|
||||||
|
MainTextField(
|
||||||
|
value = login,
|
||||||
|
label = R.string.title_login.AsString(),
|
||||||
|
isError = isError
|
||||||
|
)
|
||||||
|
SpacerHeight(15.dp)
|
||||||
|
MainTextField(
|
||||||
|
value = password,
|
||||||
|
keyboardType = KeyboardType.Password,
|
||||||
|
label = R.string.title_password.AsString(),
|
||||||
|
isError = isError
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SpacerHeight(5.dp)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(30.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxHeight(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
MainCheckbox(isRememberMe) { }
|
||||||
|
SpacerWidth(5.dp)
|
||||||
|
Text(
|
||||||
|
text = R.string.title_remember_me.AsString(),
|
||||||
|
style = MainText,
|
||||||
|
color = dark
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = R.string.title_forget_password.AsString(),
|
||||||
|
style = MainText,
|
||||||
|
color = dark,
|
||||||
|
modifier = Modifier.clickable(onClick = onForgetPassword)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(0.dp, 10.dp),
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
MainButton(
|
||||||
|
text = R.string.title_sign_in.AsString(),
|
||||||
|
onClick = onSignIn
|
||||||
|
)
|
||||||
|
SpacerHeight(5.dp)
|
||||||
|
Text(
|
||||||
|
text = R.string.title_sign_up.AsString(),
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable(onClick = onSignUp)
|
||||||
|
.padding(5.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = Mini,
|
||||||
|
color = dark
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoginBackground() {
|
||||||
|
val icon = R.drawable.ic_header.AsPainter()
|
||||||
|
val size = icon.intrinsicSize
|
||||||
|
Column {
|
||||||
|
Image(
|
||||||
|
painter = icon,
|
||||||
|
contentDescription = "",
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
contentScale = ContentScale.FillWidth,
|
||||||
|
alignment = Alignment.TopStart
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BigLoginBackground() {
|
||||||
|
val icon = R.drawable.header_big.AsPainter()
|
||||||
|
Column(Modifier.fillMaxWidth()) {
|
||||||
|
Image(
|
||||||
|
painter = icon,
|
||||||
|
contentDescription = "",
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
alignment = Alignment.TopStart
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package ru.megboyzz.dnevnik.screens.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Menu
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import ru.megboyzz.dnevnik.SpacerWidth
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.mainBlue
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.white
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MainScaffold(
|
||||||
|
icon: Painter,
|
||||||
|
title: String,
|
||||||
|
/* TODO viewModel */
|
||||||
|
navController: NavController,
|
||||||
|
scaffoldState: ScaffoldState,
|
||||||
|
content: (@Composable (it: PaddingValues) -> Unit),
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
Scaffold(
|
||||||
|
scaffoldState = scaffoldState,
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
backgroundColor = mainBlue,
|
||||||
|
contentColor = Color.White
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
val drawerState = scaffoldState.drawerState
|
||||||
|
scope.launch {
|
||||||
|
if (drawerState.isClosed)
|
||||||
|
drawerState.open()
|
||||||
|
else
|
||||||
|
drawerState.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Menu,
|
||||||
|
contentDescription = "menu",
|
||||||
|
tint = white
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SpacerWidth(width = 5.dp)
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = white
|
||||||
|
)
|
||||||
|
Spacer(Modifier.weight(1f))
|
||||||
|
Box(Modifier.padding(15.dp, 15.dp)) {
|
||||||
|
Image(painter = icon, contentDescription = "icon")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
content = content,
|
||||||
|
drawerBackgroundColor = mainBlue,
|
||||||
|
drawerContentColor = white,
|
||||||
|
drawerShape = drawerShape,
|
||||||
|
drawerContent = { DrawerContent(navController, scaffoldState) },
|
||||||
|
bottomBar = { BottomBar(navController) }
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -16,6 +16,10 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
||||||
import ru.megboyzz.dnevnik.screens.ui.*
|
import ru.megboyzz.dnevnik.screens.ui.*
|
||||||
|
import ru.megboyzz.dnevnik.screens.ui.calendar.NiceCalendar
|
||||||
|
import ru.megboyzz.dnevnik.screens.ui.piechart.PieChart
|
||||||
|
import ru.megboyzz.dnevnik.screens.ui.piechart.PieChartCard
|
||||||
|
import ru.megboyzz.dnevnik.screens.ui.piechart.PieChartData
|
||||||
import ru.megboyzz.dnevnik.ui.theme.mainBlue
|
import ru.megboyzz.dnevnik.ui.theme.mainBlue
|
||||||
import ru.megboyzz.dnevnik.ui.theme.white
|
import ru.megboyzz.dnevnik.ui.theme.white
|
||||||
import java.time.YearMonth
|
import java.time.YearMonth
|
||||||
@@ -103,16 +107,6 @@ fun BaseCardPrev() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun MonthTglPrev() {
|
|
||||||
MonthToggle(
|
|
||||||
startMonth = Month.January, startYear = 2023
|
|
||||||
){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun UnderlinedTextPrev() {
|
fun UnderlinedTextPrev() {
|
||||||
@@ -217,22 +211,16 @@ fun AllMarksCardPrev1() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun NewCalendarPrev() {
|
|
||||||
NewCardCalendar(
|
|
||||||
month = Month.January,
|
|
||||||
year = 2023
|
|
||||||
){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun NiceCalendarPrev() {
|
fun NiceCalendarPrev() {
|
||||||
|
|
||||||
|
var startMonth by remember{
|
||||||
|
mutableStateOf(YearMonth.now())
|
||||||
|
}
|
||||||
|
|
||||||
NiceCalendar(
|
NiceCalendar(
|
||||||
startMonth = YearMonth.now()
|
currentMonth = startMonth,
|
||||||
){ day, month, year ->
|
){ day, month, year ->
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package ru.megboyzz.dnevnik.screens.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.horizontalScroll
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.ButtonDefaults
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import ru.megboyzz.dnevnik.navigate
|
||||||
|
import ru.megboyzz.dnevnik.navigation.BaseNavRote
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.MainText
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.dark
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.mainBlue
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.white
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SubScreenNavButton(
|
||||||
|
text: String,
|
||||||
|
isClicked: MutableState<Boolean>,
|
||||||
|
onCLick: () -> Unit
|
||||||
|
) {
|
||||||
|
val colors = ButtonDefaults.buttonColors(
|
||||||
|
backgroundColor = if(isClicked.value) mainBlue else white,
|
||||||
|
contentColor = if(isClicked.value) white else dark
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
isClicked.value = !isClicked.value
|
||||||
|
onCLick.invoke()
|
||||||
|
},
|
||||||
|
shape = RoundedCornerShape(20.dp),
|
||||||
|
border = BorderStroke(
|
||||||
|
width = 1.dp,
|
||||||
|
color = mainBlue,
|
||||||
|
),
|
||||||
|
colors = colors,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
style= MainText
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class SubScreenData(
|
||||||
|
val title: String,
|
||||||
|
val to: BaseNavRote,
|
||||||
|
val isClicked: MutableState<Boolean>
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SubScreenNavBar(
|
||||||
|
list: List<SubScreenData>,
|
||||||
|
subScreenNavController: NavController
|
||||||
|
) {
|
||||||
|
val horizontalScroll = rememberScrollState()
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.horizontalScroll(horizontalScroll)
|
||||||
|
.padding(15.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(15.dp)
|
||||||
|
){
|
||||||
|
for(data in list){
|
||||||
|
if(data.isClicked.value)
|
||||||
|
subScreenNavController.navigate(data.to)
|
||||||
|
SubScreenNavButton(
|
||||||
|
text = data.title,
|
||||||
|
isClicked = data.isClicked
|
||||||
|
) {
|
||||||
|
for(d in list){
|
||||||
|
if(data != d)
|
||||||
|
d.isClicked.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
package ru.megboyzz.dnevnik.screens.ui.calendar
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.foundation.*
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.semantics.Role
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.kizitonwose.calendar.compose.HorizontalCalendar
|
||||||
|
import com.kizitonwose.calendar.compose.WeekCalendar
|
||||||
|
import com.kizitonwose.calendar.compose.rememberCalendarState
|
||||||
|
import com.kizitonwose.calendar.compose.weekcalendar.rememberWeekCalendarState
|
||||||
|
import com.kizitonwose.calendar.core.*
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import ru.megboyzz.dnevnik.*
|
||||||
|
import ru.megboyzz.dnevnik.R
|
||||||
|
import ru.megboyzz.dnevnik.ui.theme.*
|
||||||
|
import java.time.DayOfWeek
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.Month
|
||||||
|
import java.time.YearMonth
|
||||||
|
import java.time.format.TextStyle
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
//TODO доделать свертку календаря, он почти идеально работает
|
||||||
|
@Composable
|
||||||
|
fun NiceCalendar(
|
||||||
|
currentMonth: YearMonth,
|
||||||
|
onClick: (day: CalendarDay, month: YearMonth, year: Int) -> Unit
|
||||||
|
) {
|
||||||
|
|
||||||
|
val selections = remember { mutableStateListOf<CalendarDay>() }
|
||||||
|
val daysOfWeek = remember { daysOfWeek() }
|
||||||
|
|
||||||
|
val state = rememberCalendarState(
|
||||||
|
startMonth = startMonth,
|
||||||
|
endMonth = endMonth,
|
||||||
|
firstVisibleMonth = currentMonth,
|
||||||
|
firstDayOfWeek = daysOfWeek.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
val weekState = rememberWeekCalendarState(
|
||||||
|
startDate = currentMonth.atDay(1),
|
||||||
|
endDate = currentMonth.atDay(7),
|
||||||
|
firstVisibleWeekDate = currentMonth.atDay(1),
|
||||||
|
firstDayOfWeek = daysOfWeek.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
var selectedDate by remember { mutableStateOf<LocalDate?>(null) }
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val visibleMonth = rememberFirstMostVisibleMonth(state, viewportPercent = 90f)
|
||||||
|
|
||||||
|
Column {
|
||||||
|
|
||||||
|
SimpleCalendarTitle(
|
||||||
|
currentMonth = visibleMonth.yearMonth,
|
||||||
|
goToPrevious = {
|
||||||
|
coroutineScope.launch {
|
||||||
|
state.animateScrollToMonth(state.firstVisibleMonth.yearMonth.previousMonth)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
goToNext = {
|
||||||
|
coroutineScope.launch {
|
||||||
|
state.animateScrollToMonth(state.firstVisibleMonth.yearMonth.nextMonth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Card(
|
||||||
|
shape = RoundedCornerShape(10.dp),
|
||||||
|
modifier = Modifier.defaultMinSize(300.dp)
|
||||||
|
) {
|
||||||
|
if(selectedDate == null) {
|
||||||
|
HorizontalCalendar(
|
||||||
|
state = state,
|
||||||
|
dayContent = { day ->
|
||||||
|
Day(day, isSelected = selectedDate == day.date) { day ->
|
||||||
|
selectedDate = if (selectedDate == day.date) null else day.date
|
||||||
|
onClick(day, currentMonth, currentMonth.year)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
monthHeader = { DaysOfWeekTitle(daysOfWeek = DayOfWeek.values().asList()) },
|
||||||
|
modifier = Modifier.padding(10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//TODO по возможности устранить повторы
|
||||||
|
WeekCalendar(
|
||||||
|
state = weekState,
|
||||||
|
weekHeader = { _ ->
|
||||||
|
DaysOfWeekTitle(daysOfWeek = DayOfWeek.values().asList())
|
||||||
|
},
|
||||||
|
dayContent = { day ->
|
||||||
|
Day(
|
||||||
|
CalendarDay(day.date, DayPosition.InDate),
|
||||||
|
isSelected = selectedDate == day.date
|
||||||
|
) { calendarDay ->
|
||||||
|
selectedDate = if (selectedDate == calendarDay.date) null else calendarDay.date
|
||||||
|
onClick(calendarDay, currentMonth, currentMonth.year)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.padding(10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CalendarNavigationIcon(
|
||||||
|
icon: Painter,
|
||||||
|
contentDescription: String,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
) = Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(35.dp)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.clip(shape = CircleShape)
|
||||||
|
.clickable(role = Role.Button, onClick = onClick),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(4.dp)
|
||||||
|
.align(Alignment.Center),
|
||||||
|
painter = icon,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SimpleCalendarTitle(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
currentMonth: YearMonth,
|
||||||
|
goToPrevious: () -> Unit,
|
||||||
|
goToNext: () -> Unit,
|
||||||
|
) {
|
||||||
|
|
||||||
|
val listOfMonth = listOf(
|
||||||
|
R.string.title_january.AsString(),
|
||||||
|
R.string.title_february.AsString(),
|
||||||
|
R.string.title_march.AsString(),
|
||||||
|
R.string.title_april.AsString(),
|
||||||
|
R.string.title_may.AsString(),
|
||||||
|
R.string.title_june.AsString(),
|
||||||
|
R.string.title_july.AsString(),
|
||||||
|
R.string.title_august.AsString(),
|
||||||
|
R.string.title_september.AsString(),
|
||||||
|
R.string.title_october.AsString(),
|
||||||
|
R.string.title_november.AsString(),
|
||||||
|
R.string.title_december.AsString()
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(10.dp),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.height(40.dp)
|
||||||
|
.padding(vertical = 0.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(10.dp)
|
||||||
|
) {
|
||||||
|
CalendarNavigationIcon(
|
||||||
|
icon = R.drawable.ic_month_swipe_left.AsPainter(),
|
||||||
|
contentDescription = "Previous",
|
||||||
|
onClick = goToPrevious,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = currentMonth.displayText(listOfMonth),
|
||||||
|
style = H1,
|
||||||
|
color = dark
|
||||||
|
)
|
||||||
|
CalendarNavigationIcon(
|
||||||
|
icon = R.drawable.ic_month_swipe_right.AsPainter(),
|
||||||
|
contentDescription = "Next",
|
||||||
|
onClick = goToNext,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fun YearMonth.displayText(list: List<String>): String {
|
||||||
|
return "${list[this.month.ordinal]} ${this.year}"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Month.displayText(short: Boolean = true): String {
|
||||||
|
val style = if (short) TextStyle.SHORT else TextStyle.FULL_STANDALONE
|
||||||
|
return getDisplayName(style, Locale.getDefault())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DayOfWeek.displayText(uppercase: Boolean = false): String {
|
||||||
|
return getDisplayName(TextStyle.SHORT, Locale.getDefault()).let { value ->
|
||||||
|
if (uppercase) value.uppercase(Locale.getDefault()) else value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DaysOfWeekTitle(daysOfWeek: List<DayOfWeek>) {
|
||||||
|
Column {
|
||||||
|
Row(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
for (dayOfWeek in daysOfWeek) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
text = dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.getDefault()).uppercase(),
|
||||||
|
style = MainText
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Divider(
|
||||||
|
thickness = 1.dp,
|
||||||
|
color = dark,
|
||||||
|
modifier = Modifier.padding(vertical = 10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Composable
|
||||||
|
fun Day(day: CalendarDay, isSelected: Boolean, onClick: (CalendarDay) -> Unit) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.aspectRatio(ratio = 1f) // This is important for square sizing!
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(color = if (isSelected) lightGray else Color.Transparent)
|
||||||
|
.border(
|
||||||
|
border = BorderStroke(
|
||||||
|
width = 1.dp,
|
||||||
|
color = if (isSelected) mainBlue else Color.Transparent
|
||||||
|
),
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
.clickable(
|
||||||
|
enabled = day.position == DayPosition.MonthDate,
|
||||||
|
onClick = { onClick(day) }
|
||||||
|
),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = day.date.dayOfMonth.toString(),
|
||||||
|
style = MainText,
|
||||||
|
color = if (day.position == DayPosition.MonthDate) dark else Color.Gray
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.megboyzz.dnevnik.screens.ui.calendar
|
||||||
|
|
||||||
|
import java.time.YearMonth
|
||||||
|
|
||||||
|
//Константы для календаря
|
||||||
|
|
||||||
|
val startMonth = YearMonth.of(2009, 9)
|
||||||
|
val endMonth = YearMonth.of(2100, 9)
|
||||||
+1
-3
@@ -1,8 +1,7 @@
|
|||||||
package ru.megboyzz.dnevnik.screens.ui
|
package ru.megboyzz.dnevnik.screens.ui.piechart
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
@@ -12,7 +11,6 @@ import com.github.mikephil.charting.data.PieData
|
|||||||
import com.github.mikephil.charting.data.PieDataSet
|
import com.github.mikephil.charting.data.PieDataSet
|
||||||
import com.github.mikephil.charting.data.PieEntry
|
import com.github.mikephil.charting.data.PieEntry
|
||||||
import com.github.mikephil.charting.formatter.PercentFormatter
|
import com.github.mikephil.charting.formatter.PercentFormatter
|
||||||
import ru.megboyzz.dnevnik.ui.theme.MainText
|
|
||||||
|
|
||||||
class DataPieChart(context: Context) : PieChart(context) {
|
class DataPieChart(context: Context) : PieChart(context) {
|
||||||
|
|
||||||
+3
-1
@@ -1,4 +1,4 @@
|
|||||||
package ru.megboyzz.dnevnik.screens.ui
|
package ru.megboyzz.dnevnik.screens.ui.piechart
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
@@ -12,6 +12,8 @@ import ru.megboyzz.dnevnik.AsString
|
|||||||
import ru.megboyzz.dnevnik.ui.theme.H2
|
import ru.megboyzz.dnevnik.ui.theme.H2
|
||||||
import ru.megboyzz.dnevnik.ui.theme.dark
|
import ru.megboyzz.dnevnik.ui.theme.dark
|
||||||
import ru.megboyzz.dnevnik.R
|
import ru.megboyzz.dnevnik.R
|
||||||
|
import ru.megboyzz.dnevnik.screens.ui.BaseCard
|
||||||
|
import ru.megboyzz.dnevnik.screens.ui.EmptyMessage
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс для предоставления данных для круговых диаграм
|
* Класс для предоставления данных для круговых диаграм
|
||||||
@@ -8,12 +8,4 @@ import java.time.DayOfWeek
|
|||||||
|
|
||||||
class UtilsTest {
|
class UtilsTest {
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testForDaysFunc(){
|
|
||||||
val days = getMonthDaysBy(2023, Month.January, DayOfWeek.MONDAY)
|
|
||||||
assertEquals(
|
|
||||||
listOf(2, 9, 16, 23, 30),
|
|
||||||
days
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user