v1.1.1 我的页面增加节日倒计时
This commit is contained in:
@@ -13,8 +13,8 @@ android {
|
||||
applicationId = "com.memory.app"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 2
|
||||
versionName = "1.1.0"
|
||||
versionCode = 3
|
||||
versionName = "1.1.1"
|
||||
|
||||
buildConfigField("String", "API_BASE_URL", "\"https://x.amos.us.kg/api/\"")
|
||||
}
|
||||
|
||||
@@ -3,10 +3,13 @@ package com.memory.app.ui.screen
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -19,7 +22,9 @@ 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.layout.ContentScale
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@@ -27,7 +32,10 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.AsyncImage
|
||||
import com.memory.app.data.model.User
|
||||
|
||||
import com.memory.app.ui.theme.*
|
||||
import com.memory.app.util.HolidayUtils
|
||||
import com.memory.app.util.HolidayWithDays
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -60,6 +68,7 @@ fun ProfileScreen(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
// Header with theme toggle and logout button
|
||||
Row(
|
||||
@@ -261,10 +270,146 @@ fun ProfileScreen(
|
||||
|
||||
// Divider
|
||||
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
// Holiday Countdown
|
||||
HolidayCountdown()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HolidayCountdown() {
|
||||
var showAll by remember { mutableStateOf(false) }
|
||||
val allHolidays = remember { HolidayUtils.getUpcomingHolidays(20) }
|
||||
|
||||
if (allHolidays.isEmpty()) return
|
||||
|
||||
val mainHoliday = allHolidays.first()
|
||||
val upcomingHolidays = if (showAll) allHolidays.drop(1) else allHolidays.drop(1).take(2)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// Main Holiday Card
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, RoundedCornerShape(20.dp))
|
||||
.padding(vertical = 24.dp, horizontal = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = mainHoliday.holiday.emoji,
|
||||
fontSize = 48.sp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = mainHoliday.holiday.name,
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onBackground
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Text(
|
||||
text = mainHoliday.getDaysText(),
|
||||
fontSize = 36.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Brand500
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
val dateText = buildString {
|
||||
append(mainHoliday.getDateText())
|
||||
mainHoliday.getWeekdayText()?.let { append(" $it") }
|
||||
}
|
||||
Text(
|
||||
text = dateText,
|
||||
fontSize = 14.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
|
||||
// Upcoming Holidays
|
||||
if (upcomingHolidays.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "接下来",
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
|
||||
Text(
|
||||
text = if (showAll) "收起" else "更多",
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Brand500,
|
||||
modifier = Modifier.clickable { showAll = !showAll }
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
upcomingHolidays.forEach { holidayWithDays ->
|
||||
UpcomingHolidayItem(holidayWithDays)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpcomingHolidayItem(holidayWithDays: HolidayWithDays) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f))
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// Emoji
|
||||
Text(
|
||||
text = holidayWithDays.holiday.emoji,
|
||||
fontSize = 24.sp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
// Name
|
||||
Text(
|
||||
text = holidayWithDays.holiday.name,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
// Days
|
||||
Text(
|
||||
text = holidayWithDays.getDaysText(),
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Brand500
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StatColumn(count: Int, label: String) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
@@ -290,3 +435,5 @@ private fun StatColumn(count: Int, label: String) {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.memory.app.util
|
||||
|
||||
import java.time.LocalDate
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
data class Holiday(
|
||||
val name: String,
|
||||
val emoji: String,
|
||||
val date: LocalDate,
|
||||
val isLunar: Boolean = false
|
||||
)
|
||||
|
||||
object HolidayUtils {
|
||||
|
||||
// 获取所有节日(2025-2026年)
|
||||
private fun getAllHolidays(): List<Holiday> {
|
||||
return listOf(
|
||||
// 2024年剩余
|
||||
Holiday("圣诞节", "🎄", LocalDate.of(2024, 12, 25)),
|
||||
|
||||
// 2025年
|
||||
Holiday("元旦", "🎊", LocalDate.of(2025, 1, 1)),
|
||||
Holiday("春节", "🧧", LocalDate.of(2025, 1, 29), true),
|
||||
Holiday("元宵节", "🏮", LocalDate.of(2025, 2, 12), true),
|
||||
Holiday("情人节", "💕", LocalDate.of(2025, 2, 14)),
|
||||
Holiday("清明节", "🌿", LocalDate.of(2025, 4, 4)),
|
||||
Holiday("劳动节", "💪", LocalDate.of(2025, 5, 1)),
|
||||
Holiday("母亲节", "🌸", LocalDate.of(2025, 5, 11)),
|
||||
Holiday("端午节", "🐲", LocalDate.of(2025, 5, 31), true),
|
||||
Holiday("父亲节", "👔", LocalDate.of(2025, 6, 15)),
|
||||
Holiday("七夕节", "🎋", LocalDate.of(2025, 8, 29), true),
|
||||
Holiday("中秋节", "🥮", LocalDate.of(2025, 10, 6), true),
|
||||
Holiday("国庆节", "🇨🇳", LocalDate.of(2025, 10, 1)),
|
||||
Holiday("重阳节", "🍂", LocalDate.of(2025, 10, 29), true),
|
||||
Holiday("万圣节", "🎃", LocalDate.of(2025, 10, 31)),
|
||||
Holiday("感恩节", "🦃", LocalDate.of(2025, 11, 27)),
|
||||
Holiday("圣诞节", "🎄", LocalDate.of(2025, 12, 25)),
|
||||
|
||||
// 2026年
|
||||
Holiday("元旦", "🎊", LocalDate.of(2026, 1, 1)),
|
||||
Holiday("春节", "🧧", LocalDate.of(2026, 2, 17), true),
|
||||
Holiday("元宵节", "🏮", LocalDate.of(2026, 3, 3), true),
|
||||
Holiday("情人节", "💕", LocalDate.of(2026, 2, 14)),
|
||||
Holiday("清明节", "🌿", LocalDate.of(2026, 4, 5)),
|
||||
Holiday("劳动节", "💪", LocalDate.of(2026, 5, 1)),
|
||||
Holiday("母亲节", "🌸", LocalDate.of(2026, 5, 10)),
|
||||
Holiday("端午节", "🐲", LocalDate.of(2026, 6, 19), true),
|
||||
Holiday("父亲节", "👔", LocalDate.of(2026, 6, 21)),
|
||||
Holiday("七夕节", "🎋", LocalDate.of(2026, 8, 19), true),
|
||||
Holiday("中秋节", "🥮", LocalDate.of(2026, 9, 25), true),
|
||||
Holiday("国庆节", "🇨🇳", LocalDate.of(2026, 10, 1)),
|
||||
Holiday("重阳节", "🍂", LocalDate.of(2026, 10, 18), true),
|
||||
Holiday("万圣节", "🎃", LocalDate.of(2026, 10, 31)),
|
||||
Holiday("感恩节", "🦃", LocalDate.of(2026, 11, 26)),
|
||||
Holiday("圣诞节", "🎄", LocalDate.of(2026, 12, 25))
|
||||
)
|
||||
}
|
||||
|
||||
// 获取即将到来的节日(包括今天)
|
||||
fun getUpcomingHolidays(count: Int = 3): List<HolidayWithDays> {
|
||||
val today = LocalDate.now()
|
||||
return getAllHolidays()
|
||||
.filter { !it.date.isBefore(today) }
|
||||
.sortedBy { it.date }
|
||||
.take(count)
|
||||
.map { holiday ->
|
||||
val daysUntil = ChronoUnit.DAYS.between(today, holiday.date).toInt()
|
||||
HolidayWithDays(holiday, daysUntil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class HolidayWithDays(
|
||||
val holiday: Holiday,
|
||||
val daysUntil: Int
|
||||
) {
|
||||
fun getDaysText(): String {
|
||||
return when (daysUntil) {
|
||||
0 -> "今天"
|
||||
1 -> "明天"
|
||||
else -> "${daysUntil}天"
|
||||
}
|
||||
}
|
||||
|
||||
fun getDateText(): String {
|
||||
val date = holiday.date
|
||||
return "${date.monthValue}月${date.dayOfMonth}日"
|
||||
}
|
||||
|
||||
// 如果在下周内(2-7天),返回周几;否则返回null
|
||||
fun getWeekdayText(): String? {
|
||||
if (daysUntil in 2..7) {
|
||||
val weekdays = listOf("周一", "周二", "周三", "周四", "周五", "周六", "周日")
|
||||
val dayOfWeek = holiday.date.dayOfWeek.value // 1=Monday, 7=Sunday
|
||||
return weekdays[dayOfWeek - 1]
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user