🤫小彩蛋🤫
This commit is contained in:
parent
87bb8adfa0
commit
9c4c6d6b32
6 changed files with 267 additions and 3 deletions
|
|
@ -12,6 +12,7 @@ import cn.super12138.todo.ui.pages.editor.TodoEditorPage
|
|||
import cn.super12138.todo.ui.pages.main.MainPage
|
||||
import cn.super12138.todo.ui.pages.settings.SettingsAbout
|
||||
import cn.super12138.todo.ui.pages.settings.SettingsAboutLicence
|
||||
import cn.super12138.todo.ui.pages.settings.SettingsAboutSpecial
|
||||
import cn.super12138.todo.ui.pages.settings.SettingsAppearance
|
||||
import cn.super12138.todo.ui.pages.settings.SettingsData
|
||||
import cn.super12138.todo.ui.pages.settings.SettingsInterface
|
||||
|
|
@ -123,8 +124,16 @@ fun TodoNavigation(
|
|||
|
||||
composable(TodoScreen.SettingsAbout.name) {
|
||||
SettingsAbout(
|
||||
toSpecialPage = { navController.navigate(TodoScreen.SettingsAboutSpecial.name) },
|
||||
toLicencePage = { navController.navigate(TodoScreen.SettingsAboutLicence.name) },
|
||||
onNavigateUp = { navController.navigateUp() },
|
||||
toLicencePage = { navController.navigate(TodoScreen.SettingsAboutLicence.name) }
|
||||
)
|
||||
}
|
||||
|
||||
composable(TodoScreen.SettingsAboutSpecial.name) {
|
||||
SettingsAboutSpecial(
|
||||
viewModel = viewModel,
|
||||
onNavigateUp = { navController.navigateUp() }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,5 +8,6 @@ enum class TodoScreen {
|
|||
SettingsInterface,
|
||||
SettingsData,
|
||||
SettingsAbout,
|
||||
SettingsAboutSpecial,
|
||||
SettingsAboutLicence
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package cn.super12138.todo.ui.pages.settings
|
|||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
|
|
@ -14,6 +15,10 @@ import androidx.compose.material.icons.outlined.Person4
|
|||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
|
@ -28,8 +33,9 @@ import cn.super12138.todo.utils.SystemUtils
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SettingsAbout(
|
||||
onNavigateUp: () -> Unit,
|
||||
toSpecialPage: () -> Unit,
|
||||
toLicencePage: () -> Unit,
|
||||
onNavigateUp: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||
|
|
@ -46,10 +52,22 @@ fun SettingsAbout(
|
|||
.padding(innerPadding)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
var clickCount by remember { mutableIntStateOf(0) }
|
||||
SettingsItem(
|
||||
leadingIcon = Icons.Outlined.Numbers,
|
||||
title = stringResource(R.string.pref_app_version),
|
||||
description = SystemUtils.getAppVersion(context)
|
||||
description = SystemUtils.getAppVersion(context),
|
||||
onClick = {
|
||||
clickCount++
|
||||
if (clickCount == 5) {
|
||||
if ((System.currentTimeMillis() % 2) == 0.toLong()) {
|
||||
toSpecialPage()
|
||||
} else {
|
||||
Toast.makeText(context, "✨", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
clickCount = 0
|
||||
}
|
||||
}
|
||||
)
|
||||
SettingsItem(
|
||||
leadingIcon = Icons.Outlined.Person4,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,234 @@
|
|||
package cn.super12138.todo.ui.pages.settings
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
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.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
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.size
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cn.super12138.todo.R
|
||||
import cn.super12138.todo.ui.viewmodels.MainViewModel
|
||||
import cn.super12138.todo.utils.VibrationUtils
|
||||
|
||||
@Composable
|
||||
fun SettingsAboutSpecial(
|
||||
viewModel: MainViewModel,
|
||||
onNavigateUp: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val configuration = LocalConfiguration.current
|
||||
val screenHeight = configuration.screenHeightDp.dp
|
||||
var showBanner by rememberSaveable { mutableStateOf(false) }
|
||||
Surface(color = SpecialDefaults.WallColor) {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
AnimatedVisibility(
|
||||
visible = showBanner,
|
||||
enter = expandVertically(),
|
||||
exit = shrinkVertically()
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(screenHeight / 4)
|
||||
.clip(MaterialTheme.shapes.large)
|
||||
.background(SpecialDefaults.BannerColor)
|
||||
.padding(WindowInsets.statusBars.asPaddingValues())
|
||||
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.happy_birthday),
|
||||
style = MaterialTheme.typography.headlineMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
// 蛋糕
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
) {
|
||||
Cake(
|
||||
onCandleClick = {
|
||||
showBanner = it
|
||||
if (it) viewModel.playConfetti()
|
||||
}
|
||||
)
|
||||
// 桌子
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.height(SpecialDefaults.TableHeight)
|
||||
.background(SpecialDefaults.TableColor)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun Cake(
|
||||
onCandleClick: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier
|
||||
) {
|
||||
val configuration = LocalConfiguration.current
|
||||
val screenWidth = configuration.screenWidthDp.dp
|
||||
Row {
|
||||
Candle(onClick = onCandleClick)
|
||||
}
|
||||
CakePiece(
|
||||
width = screenWidth / 4,
|
||||
height = SpecialDefaults.Cake2Height,
|
||||
color = SpecialDefaults.Cake2Color
|
||||
)
|
||||
CakePiece(
|
||||
width = screenWidth / 3,
|
||||
height = SpecialDefaults.Cake1Height,
|
||||
color = SpecialDefaults.Cake1Color
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CakePiece(
|
||||
width: Dp,
|
||||
height: Dp,
|
||||
color: Color,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Box(
|
||||
modifier
|
||||
.width(width)
|
||||
.height(height)
|
||||
.clip(
|
||||
MaterialTheme.shapes.small.copy(
|
||||
bottomStart = CornerSize(0.dp),
|
||||
bottomEnd = CornerSize(0.dp)
|
||||
)
|
||||
)
|
||||
.background(color)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Candle(
|
||||
onClick: (Boolean) -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var showFlame by rememberSaveable { mutableStateOf(false) }
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val view = LocalView.current
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier.clickable(
|
||||
interactionSource = interactionSource,
|
||||
indication = null,
|
||||
onClick = {
|
||||
showFlame = !showFlame
|
||||
VibrationUtils.performHapticFeedback(view)
|
||||
onClick(showFlame)
|
||||
}
|
||||
)
|
||||
) {
|
||||
// 火苗
|
||||
Box {
|
||||
androidx.compose.animation.AnimatedVisibility(
|
||||
visible = showFlame,
|
||||
enter = scaleIn(),
|
||||
exit = scaleOut(),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.padding(bottom = 2.5.dp)
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.size(10.dp)
|
||||
.background(
|
||||
brush = Brush.radialGradient(
|
||||
listOf(
|
||||
SpecialDefaults.FlameCenterColor,
|
||||
SpecialDefaults.FlameAroundColor,
|
||||
Color.Transparent
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.width(SpecialDefaults.WickWidth)
|
||||
.height(SpecialDefaults.WickHeight)
|
||||
.background(SpecialDefaults.WickColor)
|
||||
.align(Alignment.BottomCenter)
|
||||
)
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.width(SpecialDefaults.CandleBodyWidth)
|
||||
.height(SpecialDefaults.CandleBodyHeight)
|
||||
.background(Color(0xFFECCE48))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private object SpecialDefaults {
|
||||
// Color
|
||||
val WallColor = Color(0xFFFFFBEA)
|
||||
val TableColor = Color(0xFF412200)
|
||||
val Cake1Color = Color(0xFFFFE9A0)
|
||||
val Cake2Color = Color(0xFFFFECBF)
|
||||
val FlameCenterColor = Color(0xFFFF5100)
|
||||
val FlameAroundColor = Color(0xFFF82323)
|
||||
val WickColor = Color(0xFF1E1E1E)
|
||||
val BannerColor = Color(0xFFFFF1BC)
|
||||
|
||||
// Size
|
||||
val TableHeight = 30.dp
|
||||
val Cake1Height = 60.dp
|
||||
val Cake2Height = 45.dp
|
||||
val CandleBodyWidth = 10.dp
|
||||
val CandleBodyHeight = 20.dp
|
||||
val WickWidth = 1.5.dp
|
||||
val WickHeight = 8.dp
|
||||
}
|
||||
|
|
@ -107,4 +107,5 @@
|
|||
<string name="pref_secure_mode">安全模式</string>
|
||||
<string name="pref_secure_mode_desc">阻止截屏并保护后台预览图</string>
|
||||
<string name="label_more">更多</string>
|
||||
<string name="happy_birthday">待办1岁生日快乐</string>
|
||||
</resources>
|
||||
|
|
@ -108,4 +108,5 @@
|
|||
<string name="pref_secure_mode">Secure Mode</string>
|
||||
<string name="pref_secure_mode_desc">Prevent screenshots and protect the background preview image</string>
|
||||
<string name="label_more">More</string>
|
||||
<string name="happy_birthday">Happy 1st birthday to ToDo</string>
|
||||
</resources>
|
||||
Loading…
Reference in a new issue