|
@@ -1,19 +1,59 @@
|
|
|
package com.zaojiao.app.feat.home.plan
|
|
|
|
|
|
+import androidx.compose.foundation.ExperimentalFoundationApi
|
|
|
+import androidx.compose.foundation.background
|
|
|
+import androidx.compose.foundation.border
|
|
|
+import androidx.compose.foundation.layout.Arrangement
|
|
|
+import androidx.compose.foundation.layout.Box
|
|
|
+import androidx.compose.foundation.layout.Column
|
|
|
+import androidx.compose.foundation.layout.Row
|
|
|
+import androidx.compose.foundation.layout.aspectRatio
|
|
|
+import androidx.compose.foundation.layout.fillMaxHeight
|
|
|
+import androidx.compose.foundation.layout.fillMaxSize
|
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
|
+import androidx.compose.foundation.layout.height
|
|
|
+import androidx.compose.foundation.layout.padding
|
|
|
+import androidx.compose.foundation.layout.width
|
|
|
+import androidx.compose.foundation.layout.wrapContentHeight
|
|
|
+import androidx.compose.foundation.layout.wrapContentSize
|
|
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
|
+import androidx.compose.foundation.lazy.LazyRow
|
|
|
+import androidx.compose.foundation.pager.HorizontalPager
|
|
|
+import androidx.compose.foundation.pager.rememberPagerState
|
|
|
+import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
+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.draw.clip
|
|
|
+import androidx.compose.ui.draw.drawWithContent
|
|
|
+import androidx.compose.ui.geometry.Offset
|
|
|
+import androidx.compose.ui.geometry.Rect
|
|
|
+import androidx.compose.ui.geometry.Size
|
|
|
+import androidx.compose.ui.graphics.Brush
|
|
|
+import androidx.compose.ui.graphics.Color
|
|
|
+import androidx.compose.ui.graphics.Path
|
|
|
+import androidx.compose.ui.graphics.PathEffect
|
|
|
+import androidx.compose.ui.graphics.drawscope.DrawStyle
|
|
|
+import androidx.compose.ui.graphics.drawscope.Stroke
|
|
|
+import androidx.compose.ui.text.TextStyle
|
|
|
+import androidx.compose.ui.text.font.FontWeight
|
|
|
+import androidx.compose.ui.unit.dp
|
|
|
+import androidx.compose.ui.unit.sp
|
|
|
import androidx.hilt.navigation.compose.hiltViewModel
|
|
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
|
import com.zaojiao.app.data.model.studyplan.StudyPlanTodayModel
|
|
|
import com.zaojiao.app.data.model.studyplan.StudyPlanTomorrowModel
|
|
|
+import com.zaojiao.app.feat.design.Colors
|
|
|
+import com.zaojiao.app.feat.design.Expanded
|
|
|
+import com.zaojiao.app.feat.design.Images
|
|
|
+import com.zaojiao.app.feat.design.Spacer
|
|
|
import com.zaojiao.app.feat.design.StatePage
|
|
|
|
|
|
@Composable
|
|
|
-fun HomePlanIndexPage(
|
|
|
- viewModel: HomePlanViewModel = hiltViewModel()
|
|
|
+internal fun HomePlanIndexPage(
|
|
|
+ viewModel: HomePlanIndexViewModel = hiltViewModel()
|
|
|
) {
|
|
|
val uiState by viewModel.stateFlow.collectAsStateWithLifecycle()
|
|
|
|
|
@@ -22,26 +62,317 @@ fun HomePlanIndexPage(
|
|
|
modifier = Modifier.fillMaxWidth()
|
|
|
) {
|
|
|
item {
|
|
|
- HomePlanTomorrow(tomorrowPlanList = this@StatePage.tomorrowPlanList)
|
|
|
+ HomePlanTomorrow(
|
|
|
+ tomorrowPlanList = this@StatePage.tomorrowPlanList,
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
- item{
|
|
|
- HomePlanToday(todayPlanList = this@StatePage.todayPlanList)
|
|
|
+ item {
|
|
|
+ Box(modifier = Modifier.height(20.dp))
|
|
|
+ }
|
|
|
+
|
|
|
+ item {
|
|
|
+ HomePlanToday(
|
|
|
+ todayPlanList = this@StatePage.todayPlanList,
|
|
|
+ )
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+@OptIn(ExperimentalFoundationApi::class)
|
|
|
@Composable
|
|
|
internal fun HomePlanTomorrow(
|
|
|
tomorrowPlanList: List<StudyPlanTomorrowModel>
|
|
|
) {
|
|
|
+ val count = tomorrowPlanList.size
|
|
|
+ val pagerState = rememberPagerState()
|
|
|
+
|
|
|
+ HorizontalPager(
|
|
|
+ pageCount = count,
|
|
|
+ state = pagerState,
|
|
|
+ modifier = Modifier
|
|
|
+ .padding(horizontal = 16.dp)
|
|
|
+ .clip(RoundedCornerShape(35.dp))
|
|
|
+ .fillMaxWidth()
|
|
|
+ .height(70.dp)
|
|
|
+ ) {
|
|
|
+ val plan = tomorrowPlanList[it]
|
|
|
+
|
|
|
+ Box(
|
|
|
+ modifier = Modifier
|
|
|
+ .clip(RoundedCornerShape(35.dp))
|
|
|
+ .fillMaxSize(),
|
|
|
+ ) {
|
|
|
+ Images.Color(
|
|
|
+ color = Colors.from("#FFFF8024"),
|
|
|
+ description = "",
|
|
|
+ modifier = Modifier.fillMaxSize(),
|
|
|
+ )
|
|
|
+
|
|
|
+ Row(modifier = Modifier.fillMaxSize()) {
|
|
|
+ Images.Network(
|
|
|
+ url = plan.courseItemImgCover,
|
|
|
+ modifier = Modifier
|
|
|
+ .padding(6.dp)
|
|
|
+ .border(
|
|
|
+ width = 1.dp,
|
|
|
+ color = Color.White,
|
|
|
+ shape = RoundedCornerShape(35.dp),
|
|
|
+ )
|
|
|
+ .clip(RoundedCornerShape(35.dp))
|
|
|
+ .background(color = Colors.from("#36000000"))
|
|
|
+ .aspectRatio(ratio = 1f),
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ if (count > 1) {
|
|
|
+ Row(
|
|
|
+ modifier = Modifier
|
|
|
+ .padding(top = 8.dp)
|
|
|
+ .fillMaxWidth()
|
|
|
+ .height(4.dp),
|
|
|
+ horizontalArrangement = Arrangement.Center,
|
|
|
+ ) {
|
|
|
+ repeat(count) {
|
|
|
+ if (it == pagerState.currentPage) {
|
|
|
+ Box(
|
|
|
+ modifier = Modifier
|
|
|
+ .padding(horizontal = 2.dp)
|
|
|
+ .background(
|
|
|
+ color = Colors.from("#d8d8d8"),
|
|
|
+ shape = RoundedCornerShape(2.dp),
|
|
|
+ )
|
|
|
+ .fillMaxHeight()
|
|
|
+ .width(16.dp),
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ Box(
|
|
|
+ modifier = Modifier
|
|
|
+ .padding(horizontal = 2.dp)
|
|
|
+ .background(
|
|
|
+ color = Colors.from("#d8d8d8"),
|
|
|
+ shape = RoundedCornerShape(2.dp),
|
|
|
+ )
|
|
|
+ .height(4.dp)
|
|
|
+ .width(4.dp),
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Composable
|
|
|
internal fun HomePlanToday(
|
|
|
todayPlanList: List<StudyPlanTodayModel>
|
|
|
) {
|
|
|
+ Box(
|
|
|
+ modifier = Modifier
|
|
|
+ .padding(horizontal = 16.dp)
|
|
|
+ .fillMaxWidth()
|
|
|
+ .height(227.dp),
|
|
|
+ ) {
|
|
|
+ Box(
|
|
|
+ modifier = Modifier
|
|
|
+ .background(
|
|
|
+ brush = Brush.horizontalGradient(
|
|
|
+ colors = listOf(
|
|
|
+ Colors.from("#EBFEE6D5"),
|
|
|
+ Colors.from("#FFFFE7D6"),
|
|
|
+ )
|
|
|
+ ),
|
|
|
+ shape = RoundedCornerShape(20.dp)
|
|
|
+ )
|
|
|
+ .fillMaxSize()
|
|
|
+ )
|
|
|
+
|
|
|
+ Column(
|
|
|
+ modifier = Modifier.fillMaxSize(),
|
|
|
+ ) {
|
|
|
+ Row(
|
|
|
+ modifier = Modifier
|
|
|
+ .padding(horizontal = 12.dp, vertical = 20.dp)
|
|
|
+ .fillMaxWidth()
|
|
|
+ .wrapContentHeight(),
|
|
|
+ verticalAlignment = Alignment.CenterVertically,
|
|
|
+ ) {
|
|
|
+ Text(
|
|
|
+ text = "今日计划",
|
|
|
+ style = TextStyle(
|
|
|
+ color = Colors.from("#FFFF8024"),
|
|
|
+ fontWeight = FontWeight.SemiBold,
|
|
|
+ fontSize = 20.sp,
|
|
|
+ lineHeight = 28.sp,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+
|
|
|
+ Spacer(width = 6.dp)
|
|
|
|
|
|
+ Text(
|
|
|
+ text = "共${todayPlanList.size}节",
|
|
|
+ style = TextStyle(
|
|
|
+ color = Colors.from("#FFFF8024"),
|
|
|
+ fontWeight = FontWeight.Medium,
|
|
|
+ fontSize = 11.sp,
|
|
|
+ lineHeight = 12.sp,
|
|
|
+ ),
|
|
|
+ modifier = Modifier
|
|
|
+ .background(
|
|
|
+ color = Colors
|
|
|
+ .from("#FFFF8024")
|
|
|
+ .copy(alpha = 0.2f),
|
|
|
+ shape = RoundedCornerShape(
|
|
|
+ topStart = 15.dp,
|
|
|
+ bottomStart = 2.dp,
|
|
|
+ topEnd = 15.dp,
|
|
|
+ bottomEnd = 15.dp,
|
|
|
+ )
|
|
|
+ )
|
|
|
+ .padding(horizontal = 7.dp, vertical = 3.dp)
|
|
|
+ .wrapContentSize(),
|
|
|
+ )
|
|
|
+
|
|
|
+ Expanded()
|
|
|
+ Text(
|
|
|
+ text = "计划日历",
|
|
|
+ style = TextStyle(
|
|
|
+ color = Colors.from("#FFFF8024"),
|
|
|
+ fontWeight = FontWeight.Normal,
|
|
|
+ fontSize = 14.sp,
|
|
|
+ lineHeight = 16.sp,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ LazyRow(
|
|
|
+ modifier = Modifier
|
|
|
+ .weight(1f)
|
|
|
+ .fillMaxWidth(),
|
|
|
+ ) {
|
|
|
+ item {
|
|
|
+ Box(modifier = Modifier.width(12.dp))
|
|
|
+ }
|
|
|
+ todayPlanList.forEach {
|
|
|
+ item {
|
|
|
+ HomePlanTodayItem(it)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ item {
|
|
|
+ Box(modifier = Modifier.width(12.dp))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Spacer(height = 20.dp)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@Composable
|
|
|
+private fun HomePlanTodayItem(today: StudyPlanTodayModel) {
|
|
|
+ Box(
|
|
|
+ modifier = Modifier
|
|
|
+ .background(color = Color.Red.copy(alpha = 0.3f))
|
|
|
+ .fillMaxHeight()
|
|
|
+ .width(262.dp),
|
|
|
+ ) {
|
|
|
+ Box(
|
|
|
+ modifier = Modifier
|
|
|
+ .padding(start = 9.dp, bottom = 9.dp)
|
|
|
+ .align(Alignment.TopStart)
|
|
|
+ .border(
|
|
|
+ width = 3.dp, color = Color.White,
|
|
|
+ shape = RoundedCornerShape(14.dp)
|
|
|
+ )
|
|
|
+ .background(
|
|
|
+ color = Color.Green.copy(alpha = 0.3f),
|
|
|
+ shape = RoundedCornerShape(14.dp),
|
|
|
+ )
|
|
|
+ .fillMaxHeight()
|
|
|
+ .width(96.dp)
|
|
|
+ ) {
|
|
|
+ Images.Network(
|
|
|
+ url = today.courseItemImgCover,
|
|
|
+ modifier = Modifier
|
|
|
+ .clip(RoundedCornerShape(14.dp))
|
|
|
+ .fillMaxSize(),
|
|
|
+ )
|
|
|
+
|
|
|
+ Text(
|
|
|
+ text = today.courseCategoryName,
|
|
|
+ style = TextStyle(
|
|
|
+ color = Color.White,
|
|
|
+ fontWeight = FontWeight.SemiBold,
|
|
|
+ fontSize = 10.sp,
|
|
|
+ lineHeight = 10.sp,
|
|
|
+ ),
|
|
|
+ modifier = Modifier
|
|
|
+ .align(Alignment.TopStart)
|
|
|
+ .padding(3.dp)
|
|
|
+ .drawWithContent {
|
|
|
+ this.drawContent()
|
|
|
+ val radius = 3.dp.toPx()
|
|
|
+ val radius2 = 6.dp.toPx()
|
|
|
+
|
|
|
+ val width = this.size.width
|
|
|
+ val height = this.size.height
|
|
|
+
|
|
|
+ val path = Path().apply {
|
|
|
+ moveTo(width + radius, 0f)
|
|
|
+ arcTo(
|
|
|
+ rect = Rect(
|
|
|
+ center = Offset(width + radius, radius),
|
|
|
+ radius = radius,
|
|
|
+ ),
|
|
|
+ startAngleDegrees = -100f,
|
|
|
+ sweepAngleDegrees = -90f,
|
|
|
+ forceMoveTo = true,
|
|
|
+ )
|
|
|
+ lineTo(width, height - radius)
|
|
|
+ arcTo(
|
|
|
+ rect = Rect(
|
|
|
+ center = Offset(width - radius2, height - radius2),
|
|
|
+ radius = radius2,
|
|
|
+ ),
|
|
|
+ startAngleDegrees = 0f,
|
|
|
+ sweepAngleDegrees = 80f,
|
|
|
+ forceMoveTo = true,
|
|
|
+ )
|
|
|
+ lineTo(radius, height)
|
|
|
+ arcTo(
|
|
|
+ rect = Rect(
|
|
|
+ center = Offset(radius, height + radius),
|
|
|
+ radius = radius,
|
|
|
+ ),
|
|
|
+ startAngleDegrees = -90f,
|
|
|
+ sweepAngleDegrees = -90f,
|
|
|
+ forceMoveTo = true,
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ this.drawPath(
|
|
|
+ path = path,
|
|
|
+ color = Color.White,
|
|
|
+ style = Stroke(
|
|
|
+ width = 3.dp.toPx(),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ .background(
|
|
|
+ color = Colors
|
|
|
+ .from("#FFFF8024"),
|
|
|
+ shape = RoundedCornerShape(
|
|
|
+ topStart = 10.dp,
|
|
|
+ bottomStart = 4.dp,
|
|
|
+ topEnd = 0.dp,
|
|
|
+ bottomEnd = 0.dp,
|
|
|
+ )
|
|
|
+ )
|
|
|
+ .padding(horizontal = 7.dp, vertical = 3.dp)
|
|
|
+ .wrapContentSize(),
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|