增加深色模式

This commit is contained in:
amos
2025-12-17 14:33:53 +08:00
parent d972f9140f
commit 9b97810e8d
9 changed files with 203 additions and 129 deletions

View File

@@ -14,6 +14,8 @@ import coil.Coil
import coil.ImageLoader
import coil.disk.DiskCache
import coil.memory.MemoryCache
import com.memory.app.data.ThemeManager
import com.memory.app.data.ThemeMode
import com.memory.app.data.model.User
import com.memory.app.data.repository.AuthRepository
import com.memory.app.ui.navigation.MainNavigation
@@ -25,11 +27,14 @@ import okhttp3.OkHttpClient
class MainActivity : ComponentActivity() {
private lateinit var authRepository: AuthRepository
private lateinit var themeManager: ThemeManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
themeManager = ThemeManager(this)
// 配置 Coil 图片加载器
val imageLoader = ImageLoader.Builder(this)
.okHttpClient {
@@ -55,7 +60,10 @@ class MainActivity : ComponentActivity() {
authRepository = AuthRepository(this)
setContent {
MemoryTheme {
val themeMode by themeManager.themeMode.collectAsState()
val isDarkTheme = themeMode == ThemeMode.DARK
MemoryTheme(darkTheme = isDarkTheme) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
@@ -126,12 +134,16 @@ class MainActivity : ComponentActivity() {
user = currentUser,
postCount = 0,
likeCount = 0,
isDarkTheme = isDarkTheme,
onLogout = {
lifecycleScope.launch {
authRepository.logout()
isLoggedIn = false
currentUser = null
}
},
onToggleTheme = {
themeManager.toggleTheme()
}
)
}

View File

@@ -60,7 +60,7 @@ fun PostCard(
Column(
modifier = modifier
.fillMaxWidth()
.background(Color.White)
.background(MaterialTheme.colorScheme.surface)
.clickable(onClick = onPostClick)
.padding(horizontal = 20.dp, vertical = 20.dp)
) {
@@ -70,7 +70,7 @@ fun PostCard(
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.background(Slate100),
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = Alignment.Center
) {
if (post.user?.avatarUrl?.isNotEmpty() == true) {
@@ -83,7 +83,7 @@ fun PostCard(
} else {
Text(
text = post.user?.nickname?.firstOrNull()?.toString() ?: "?",
color = Slate600,
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontWeight = FontWeight.Bold,
fontSize = 16.sp
)
@@ -99,7 +99,7 @@ fun PostCard(
text = post.user?.nickname ?: post.user?.username ?: "",
fontWeight = FontWeight.Bold,
fontSize = 15.sp,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
// 认证徽章
Spacer(modifier = Modifier.width(4.dp))
@@ -112,13 +112,13 @@ fun PostCard(
Text(
text = " · ${TimeUtils.formatRelative(post.createdAt)}",
fontSize = 12.sp,
color = Slate400
color = MaterialTheme.colorScheme.onSurfaceVariant
)
if (post.updatedAt != null) {
Text(
text = " · 已编辑",
fontSize = 12.sp,
color = Slate400
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@@ -130,7 +130,7 @@ fun PostCard(
text = post.content,
fontSize = 15.sp,
lineHeight = 22.sp,
color = Slate800
color = MaterialTheme.colorScheme.onSurface
)
// Media
@@ -154,7 +154,7 @@ fun PostCard(
post.reactions.take(5).forEach { reaction ->
Surface(
shape = RoundedCornerShape(16.dp),
color = if (reaction.reacted) Brand500.copy(alpha = 0.1f) else Slate100,
color = if (reaction.reacted) Brand500.copy(alpha = 0.1f) else MaterialTheme.colorScheme.surfaceVariant,
modifier = Modifier.clickable { onReactionClick(reaction.emoji) }
) {
Row(
@@ -167,7 +167,7 @@ fun PostCard(
text = reaction.count.toString(),
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
color = if (reaction.reacted) Brand500 else Slate600
color = if (reaction.reacted) Brand500 else MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@@ -178,6 +178,8 @@ fun PostCard(
Spacer(modifier = Modifier.height(16.dp))
// Actions Row
val actionTint = MaterialTheme.colorScheme.onSurfaceVariant
val disabledTint = MaterialTheme.colorScheme.outlineVariant
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
@@ -188,7 +190,7 @@ fun PostCard(
icon = Icons.Outlined.ChatBubbleOutline,
count = post.commentCount,
onClick = onCommentClick,
tint = Slate400
tint = actionTint
)
// Edit (only show if user owns the post)
@@ -196,13 +198,13 @@ fun PostCard(
ActionButton(
icon = Icons.Outlined.Edit,
onClick = { onEditClick(post) },
tint = Slate400
tint = actionTint
)
} else {
ActionButton(
icon = Icons.Outlined.Edit,
onClick = { },
tint = Slate200
tint = disabledTint
)
}
@@ -211,14 +213,14 @@ fun PostCard(
icon = if (post.liked) Icons.Filled.Favorite else Icons.Outlined.FavoriteBorder,
count = post.likeCount,
onClick = onLikeClick,
tint = if (post.liked) LikeRed else Slate400
tint = if (post.liked) LikeRed else actionTint
)
// Emoji - using Mood icon like design
ActionButton(
icon = Icons.Outlined.Mood,
onClick = { showEmojiPicker = true },
tint = Slate400
tint = actionTint
)
}
}
@@ -307,7 +309,7 @@ fun EmojiPickerDialog(
) {
Surface(
shape = RoundedCornerShape(28.dp),
color = Color.White,
color = MaterialTheme.colorScheme.surface,
shadowElevation = 16.dp,
modifier = Modifier
.fillMaxWidth()
@@ -332,7 +334,7 @@ fun EmojiPickerDialog(
text = "选择表情",
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
Spacer(modifier = Modifier.weight(1f))
IconButton(
@@ -342,7 +344,7 @@ fun EmojiPickerDialog(
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = "关闭",
tint = Slate400,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp)
)
}
@@ -391,7 +393,7 @@ fun EditPostDialog(
Dialog(onDismissRequest = onDismiss) {
Surface(
shape = RoundedCornerShape(20.dp),
color = Color.White,
color = MaterialTheme.colorScheme.surface,
tonalElevation = 8.dp,
modifier = Modifier.fillMaxWidth()
) {
@@ -400,7 +402,7 @@ fun EditPostDialog(
text = "编辑帖子",
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
color = Slate900,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.padding(bottom = 16.dp)
)
@@ -410,10 +412,10 @@ fun EditPostDialog(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 120.dp),
placeholder = { Text("写点什么...", color = Slate400) },
placeholder = { Text("写点什么...", color = MaterialTheme.colorScheme.onSurfaceVariant) },
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Brand500,
unfocusedBorderColor = Slate200
unfocusedBorderColor = MaterialTheme.colorScheme.outline
),
shape = RoundedCornerShape(12.dp)
)
@@ -425,7 +427,7 @@ fun EditPostDialog(
horizontalArrangement = Arrangement.End
) {
TextButton(onClick = onDismiss) {
Text("取消", color = Slate500)
Text("取消", color = MaterialTheme.colorScheme.onSurfaceVariant)
}
Spacer(modifier = Modifier.width(8.dp))
Button(

View File

@@ -47,7 +47,9 @@ fun MainNavigation(
user: User?,
postCount: Int,
likeCount: Int,
onLogout: () -> Unit
isDarkTheme: Boolean = false,
onLogout: () -> Unit,
onToggleTheme: () -> Unit = {}
) {
val navController = rememberNavController()
var showCreatePost by remember { mutableStateOf(false) }
@@ -114,6 +116,7 @@ fun MainNavigation(
postCount = profilePostCount.takeIf { it > 0 } ?: postCount,
likeCount = profileLikeCount.takeIf { it > 0 } ?: likeCount,
dayCount = profileDayCount,
isDarkTheme = isDarkTheme,
onEditProfile = { },
onLogout = onLogout,
onUpdateNickname = { nickname ->
@@ -121,7 +124,8 @@ fun MainNavigation(
},
onUpdateAvatar = { uri ->
profileViewModel.updateAvatar(context, uri)
}
},
onToggleTheme = onToggleTheme
)
}
@@ -175,11 +179,11 @@ fun MainNavigation(
modifier = Modifier
.fillMaxWidth()
.align(androidx.compose.ui.Alignment.BottomCenter),
color = Color.White,
color = MaterialTheme.colorScheme.surface,
shadowElevation = 0.dp
) {
Column {
HorizontalDivider(color = Slate100, thickness = 1.dp)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
Row(
modifier = Modifier
.fillMaxWidth()
@@ -209,7 +213,7 @@ fun MainNavigation(
Icon(
imageVector = if (selected) screen.selectedIcon else screen.unselectedIcon,
contentDescription = screen.title,
tint = if (selected) Brand500 else Slate300,
tint = if (selected) Brand500 else Slate400,
modifier = Modifier.size(24.dp)
)
}

View File

@@ -65,14 +65,14 @@ fun ArchiveScreen(
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.background(MaterialTheme.colorScheme.background)
) {
// Header
Text(
text = "归档",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
color = Slate900,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier
.statusBarsPadding()
.padding(horizontal = 20.dp, vertical = 16.dp)
@@ -158,12 +158,12 @@ fun ArchiveScreen(
text = "${selectedYear}${getLastMonthOfQuarter(selectedQuarter)}",
fontSize = 14.sp,
fontWeight = FontWeight.Bold,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
Text(
text = "${recentPosts.size}",
fontSize = 12.sp,
color = Slate400
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@@ -242,8 +242,8 @@ private fun StatCard(
Column(
modifier = modifier
.clip(RoundedCornerShape(16.dp))
.background(Slate50)
.border(1.dp, Slate100, RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.surfaceVariant)
.border(1.dp, MaterialTheme.colorScheme.outline, RoundedCornerShape(16.dp))
.padding(12.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -258,13 +258,13 @@ private fun StatCard(
text = value,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
Text(
text = label,
fontSize = 10.sp,
fontWeight = FontWeight.Bold,
color = Slate400,
color = MaterialTheme.colorScheme.onSurfaceVariant,
letterSpacing = 0.5.sp
)
}
@@ -290,7 +290,7 @@ private fun QuarterSelector(
Icon(
Icons.AutoMirrored.Filled.KeyboardArrowLeft,
contentDescription = "上一季度",
tint = Slate400,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp)
)
}
@@ -300,13 +300,13 @@ private fun QuarterSelector(
text = "${year}",
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
color = Slate400
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = getQuarterMonthRange(quarter),
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
}
@@ -318,7 +318,7 @@ private fun QuarterSelector(
Icon(
Icons.AutoMirrored.Filled.KeyboardArrowRight,
contentDescription = "下一季度",
tint = if (canGoNext) Slate400 else Slate200,
tint = if (canGoNext) MaterialTheme.colorScheme.onSurfaceVariant else MaterialTheme.colorScheme.outlineVariant,
modifier = Modifier.size(20.dp)
)
}
@@ -534,13 +534,13 @@ private fun DatePostItem(
text = dayOfWeek,
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
color = Slate400
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = date.dayOfMonth.toString(),
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
}
@@ -550,12 +550,12 @@ private fun DatePostItem(
Surface(
modifier = Modifier.weight(1f),
shape = RoundedCornerShape(12.dp),
color = Slate50
color = MaterialTheme.colorScheme.surfaceVariant
) {
Text(
text = post.content.take(30) + if (post.content.length > 30) "..." else "",
fontSize = 14.sp,
color = Slate600,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(12.dp)
@@ -577,7 +577,7 @@ private fun DatePostsSheet(
ModalBottomSheet(
onDismissRequest = onDismiss,
sheetState = sheetState,
containerColor = Color.White
containerColor = MaterialTheme.colorScheme.surface
) {
Column(
modifier = Modifier
@@ -595,16 +595,16 @@ private fun DatePostsSheet(
text = date,
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
Text(
text = "${posts.size}条记录",
fontSize = 14.sp,
color = Slate400
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
HorizontalDivider(color = Slate100)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
if (posts.isEmpty()) {
Box(
@@ -615,7 +615,7 @@ private fun DatePostsSheet(
) {
Text(
text = "这一天没有记录",
color = Slate500
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
} else {
@@ -630,7 +630,7 @@ private fun DatePostsSheet(
onCommentClick = { onPostClick(post.id) },
onReactionClick = { }
)
HorizontalDivider(color = Slate100, thickness = 1.dp)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
}
}
}

View File

@@ -51,13 +51,13 @@ fun HomeScreen(
Box(
modifier = Modifier
.fillMaxSize()
.background(Slate50.copy(alpha = 0.5f))
.background(MaterialTheme.colorScheme.background)
) {
Column(modifier = Modifier.fillMaxSize()) {
// Sticky Header
Surface(
modifier = Modifier.fillMaxWidth(),
color = Color.White.copy(alpha = 0.9f),
color = MaterialTheme.colorScheme.surface.copy(alpha = 0.95f),
shadowElevation = 0.dp
) {
Row(
@@ -74,7 +74,7 @@ fun HomeScreen(
.size(36.dp)
.shadow(2.dp, CircleShape)
.clip(CircleShape)
.background(Slate200),
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = Alignment.Center
) {
if (user?.avatarUrl?.isNotEmpty() == true) {
@@ -87,7 +87,7 @@ fun HomeScreen(
} else {
Text(
text = user?.nickname?.firstOrNull()?.toString() ?: "?",
color = Slate600,
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontWeight = FontWeight.Bold,
fontSize = 14.sp
)
@@ -99,7 +99,7 @@ fun HomeScreen(
text = "时间轴",
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = Slate800
color = MaterialTheme.colorScheme.onSurface
)
// Bell Icon
@@ -110,7 +110,7 @@ fun HomeScreen(
Icon(
Icons.Outlined.Notifications,
contentDescription = "通知",
tint = Slate400,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp)
)
}
@@ -118,7 +118,7 @@ fun HomeScreen(
}
// Divider
HorizontalDivider(color = Slate100, thickness = 1.dp)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
// Content
PullToRefreshBox(
@@ -146,7 +146,7 @@ fun HomeScreen(
modifier = Modifier
.size(64.dp)
.clip(CircleShape)
.background(Slate100),
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = Alignment.Center
) {
Text(text = "📝", fontSize = 28.sp)
@@ -156,13 +156,13 @@ fun HomeScreen(
text = "还没有帖子",
fontSize = 16.sp,
fontWeight = FontWeight.Medium,
color = Slate800
color = MaterialTheme.colorScheme.onSurface
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = "点击右下角按钮发布第一条",
fontSize = 14.sp,
color = Slate500
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@@ -190,7 +190,7 @@ fun HomeScreen(
modifier = Modifier
.fillMaxWidth()
.height(8.dp)
.background(Slate100.copy(alpha = 0.5f))
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
)
}

View File

@@ -52,12 +52,12 @@ fun PostDetailScreen(
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.background(MaterialTheme.colorScheme.background)
) {
// Header
Surface(
modifier = Modifier.fillMaxWidth(),
color = Color.White.copy(alpha = 0.95f)
color = MaterialTheme.colorScheme.surface.copy(alpha = 0.95f)
) {
Row(
modifier = Modifier
@@ -71,7 +71,7 @@ fun PostDetailScreen(
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "返回",
tint = Slate900,
tint = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.size(24.dp)
)
}
@@ -80,7 +80,7 @@ fun PostDetailScreen(
text = "帖子详情",
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
Spacer(modifier = Modifier.weight(1f))
if (post?.userId == currentUserId) {
@@ -96,7 +96,7 @@ fun PostDetailScreen(
}
}
HorizontalDivider(color = Slate100, thickness = 1.dp)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
// Content
Box(modifier = Modifier.weight(1f)) {
@@ -121,7 +121,7 @@ fun PostDetailScreen(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.background(Slate100),
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = Alignment.Center
) {
if (post.user?.avatarUrl?.isNotEmpty() == true) {
@@ -134,7 +134,7 @@ fun PostDetailScreen(
} else {
Text(
text = post.user?.nickname?.firstOrNull()?.toString() ?: "?",
color = Slate600,
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontWeight = FontWeight.Bold,
fontSize = 18.sp
)
@@ -147,7 +147,7 @@ fun PostDetailScreen(
text = post.user?.nickname ?: "",
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
Spacer(modifier = Modifier.width(4.dp))
Icon(
@@ -159,7 +159,7 @@ fun PostDetailScreen(
}
Text(
text = "@${post.user?.username} · ${TimeUtils.formatRelative(post.createdAt)}",
color = Slate400,
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 14.sp
)
}
@@ -172,7 +172,7 @@ fun PostDetailScreen(
text = post.content,
fontSize = 15.sp,
lineHeight = 22.sp,
color = Slate800
color = MaterialTheme.colorScheme.onSurface
)
// Media
@@ -204,12 +204,12 @@ fun PostDetailScreen(
text = "${post.likeCount}",
fontWeight = FontWeight.Bold,
fontSize = 15.sp,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
Text(
text = " 获赞",
fontSize = 15.sp,
color = Slate500
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -217,18 +217,18 @@ fun PostDetailScreen(
text = "${comments.size}",
fontWeight = FontWeight.Bold,
fontSize = 15.sp,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
Text(
text = " 评论",
fontSize = 15.sp,
color = Slate500
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
HorizontalDivider(color = Slate50, thickness = 8.dp)
HorizontalDivider(color = MaterialTheme.colorScheme.surfaceVariant, thickness = 8.dp)
}
// Comments
@@ -250,7 +250,7 @@ fun PostDetailScreen(
) {
Text(
text = "还没有评论,快来抢沙发吧!",
color = Slate400,
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 14.sp
)
}
@@ -263,9 +263,9 @@ fun PostDetailScreen(
// Comment Input
Surface(
modifier = Modifier.fillMaxWidth(),
color = Color.White
color = MaterialTheme.colorScheme.surface
) {
HorizontalDivider(color = Slate100, thickness = 1.dp)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
Row(
modifier = Modifier
.fillMaxWidth()
@@ -276,14 +276,14 @@ fun PostDetailScreen(
OutlinedTextField(
value = commentText,
onValueChange = { commentText = it },
placeholder = { Text("写下你的评论...", color = Slate400, fontSize = 15.sp) },
placeholder = { Text("写下你的评论...", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 15.sp) },
modifier = Modifier
.weight(1f)
.heightIn(min = 48.dp),
shape = RoundedCornerShape(24.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedContainerColor = Slate50,
unfocusedContainerColor = Slate50,
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent
),
@@ -293,7 +293,7 @@ fun PostDetailScreen(
Spacer(modifier = Modifier.width(12.dp))
Text(
text = "发送",
color = if (commentText.isNotBlank()) Brand500 else Slate300,
color = if (commentText.isNotBlank()) Brand500 else MaterialTheme.colorScheme.outlineVariant,
fontWeight = FontWeight.Bold,
fontSize = 15.sp,
modifier = Modifier
@@ -314,7 +314,7 @@ fun PostDetailScreen(
Dialog(onDismissRequest = { showDeleteDialog = false }) {
Surface(
shape = RoundedCornerShape(28.dp),
color = Color.White,
color = MaterialTheme.colorScheme.surface,
shadowElevation = 16.dp,
modifier = Modifier
.fillMaxWidth()
@@ -336,7 +336,7 @@ fun PostDetailScreen(
text = "删除帖子",
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
}
@@ -346,7 +346,7 @@ fun PostDetailScreen(
Text(
text = "确定要删除这条帖子吗?此操作不可撤销。",
fontSize = 15.sp,
color = Slate600,
color = MaterialTheme.colorScheme.onSurfaceVariant,
lineHeight = 22.sp
)
@@ -363,7 +363,7 @@ fun PostDetailScreen(
) {
Text(
"取消",
color = Slate500,
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 15.sp,
fontWeight = FontWeight.Medium
)
@@ -469,7 +469,7 @@ private fun CommentItem(
text = comment.user?.nickname ?: "",
fontWeight = FontWeight.Bold,
fontSize = 14.sp,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
Spacer(modifier = Modifier.height(4.dp))
@@ -477,12 +477,12 @@ private fun CommentItem(
// Comment bubble
Surface(
shape = RoundedCornerShape(topStart = 4.dp, topEnd = 16.dp, bottomStart = 16.dp, bottomEnd = 16.dp),
color = Slate50
color = MaterialTheme.colorScheme.surfaceVariant
) {
Text(
text = comment.content,
fontSize = 14.sp,
color = Slate700,
color = MaterialTheme.colorScheme.onSurfaceVariant,
lineHeight = 20.sp,
modifier = Modifier.padding(12.dp)
)
@@ -497,12 +497,12 @@ private fun CommentItem(
text = "回复",
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
color = Slate400
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = " · ${TimeUtils.formatRelative(comment.createdAt)}",
fontSize = 12.sp,
color = Slate400
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@@ -516,7 +516,7 @@ private fun CommentItem(
Icons.Default.Delete,
contentDescription = "删除",
modifier = Modifier.size(16.dp),
tint = Slate300
tint = MaterialTheme.colorScheme.outline
)
}
}
@@ -526,7 +526,7 @@ private fun CommentItem(
Dialog(onDismissRequest = { showDeleteDialog = false }) {
Surface(
shape = RoundedCornerShape(28.dp),
color = Color.White,
color = MaterialTheme.colorScheme.surface,
shadowElevation = 16.dp,
modifier = Modifier
.fillMaxWidth()
@@ -547,7 +547,7 @@ private fun CommentItem(
text = "删除评论",
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
}
@@ -556,7 +556,7 @@ private fun CommentItem(
Text(
text = "确定要删除这条评论吗?",
fontSize = 15.sp,
color = Slate600
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(24.dp))
@@ -571,7 +571,7 @@ private fun CommentItem(
) {
Text(
"取消",
color = Slate500,
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 15.sp,
fontWeight = FontWeight.Medium
)

View File

@@ -11,7 +11,9 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CameraAlt
import androidx.compose.material.icons.outlined.DarkMode
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.LightMode
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@@ -34,10 +36,12 @@ fun ProfileScreen(
postCount: Int,
likeCount: Int,
dayCount: Int = 1,
isDarkTheme: Boolean = false,
onEditProfile: () -> Unit,
onLogout: () -> Unit,
onUpdateNickname: ((String) -> Unit)? = null,
onUpdateAvatar: ((Uri) -> Unit)? = null
onUpdateAvatar: ((Uri) -> Unit)? = null,
onToggleTheme: (() -> Unit)? = null
) {
var isEditing by remember { mutableStateOf(false) }
var editedNickname by remember(user) { mutableStateOf(user?.nickname ?: "") }
@@ -55,16 +59,43 @@ fun ProfileScreen(
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.background(MaterialTheme.colorScheme.background)
) {
// Header with logout button
// Header with theme toggle and logout button
Row(
modifier = Modifier
.fillMaxWidth()
.statusBarsPadding()
.padding(horizontal = 20.dp, vertical = 12.dp),
horizontalArrangement = Arrangement.End
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
// Theme Toggle Button
Surface(
onClick = { onToggleTheme?.invoke() },
shape = RoundedCornerShape(50),
color = MaterialTheme.colorScheme.surfaceVariant
) {
Row(
modifier = Modifier.padding(horizontal = 12.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = if (isDarkTheme) Icons.Outlined.DarkMode else Icons.Outlined.LightMode,
contentDescription = "切换主题",
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.width(6.dp))
Text(
text = if (isDarkTheme) "深色" else "浅色",
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 14.sp,
fontWeight = FontWeight.Medium
)
}
}
// Logout Button
Surface(
onClick = onLogout,
@@ -97,8 +128,8 @@ fun ProfileScreen(
modifier = Modifier
.size(96.dp)
.clip(CircleShape)
.background(Slate100)
.border(1.dp, Slate100, CircleShape)
.background(MaterialTheme.colorScheme.surfaceVariant)
.border(1.dp, MaterialTheme.colorScheme.outline, CircleShape)
.clickable { imagePicker.launch("image/*") },
contentAlignment = Alignment.Center
) {
@@ -124,7 +155,7 @@ fun ProfileScreen(
text = user?.nickname?.firstOrNull()?.toString() ?: "?",
fontSize = 36.sp,
fontWeight = FontWeight.Bold,
color = Slate600
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@@ -192,14 +223,14 @@ fun ProfileScreen(
text = user?.nickname ?: "",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
color = Slate900
color = MaterialTheme.colorScheme.onBackground
)
Spacer(modifier = Modifier.width(4.dp))
Icon(
Icons.Outlined.Edit,
contentDescription = "编辑昵称",
modifier = Modifier.size(16.dp),
tint = Slate300
tint = MaterialTheme.colorScheme.outline
)
}
}
@@ -211,7 +242,7 @@ fun ProfileScreen(
text = "@${user?.username ?: ""}",
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
color = Slate400
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(32.dp))
@@ -229,7 +260,7 @@ fun ProfileScreen(
Spacer(modifier = Modifier.height(32.dp))
// Divider
HorizontalDivider(color = Slate50, thickness = 1.dp)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
}
}
}
@@ -247,14 +278,14 @@ private fun StatColumn(count: Int, label: String) {
},
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
color = Slate900
color = MaterialTheme.colorScheme.onBackground
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = label,
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
color = Slate400,
color = MaterialTheme.colorScheme.onSurfaceVariant,
letterSpacing = 0.5.sp
)
}

View File

@@ -57,14 +57,14 @@ fun SearchScreen(
LazyColumn(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.background(MaterialTheme.colorScheme.background)
) {
// Header
item {
Column(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.background(MaterialTheme.colorScheme.background)
.statusBarsPadding()
.padding(horizontal = 20.dp, vertical = 16.dp)
) {
@@ -73,7 +73,7 @@ fun SearchScreen(
text = "搜索",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
color = Slate900,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.padding(bottom = 20.dp)
)
@@ -81,12 +81,12 @@ fun SearchScreen(
OutlinedTextField(
value = searchQuery,
onValueChange = { viewModel.updateQuery(it) },
placeholder = { Text("搜索内容关键词...", color = Slate400, fontSize = 15.sp) },
placeholder = { Text("搜索内容关键词...", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 15.sp) },
leadingIcon = {
Icon(
Icons.Outlined.Search,
contentDescription = null,
tint = Slate400,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp)
)
},
@@ -95,10 +95,10 @@ fun SearchScreen(
.shadow(2.dp, RoundedCornerShape(16.dp)),
shape = RoundedCornerShape(16.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedContainerColor = Slate50,
unfocusedContainerColor = Slate50,
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
focusedBorderColor = Brand500,
unfocusedBorderColor = Slate100,
unfocusedBorderColor = MaterialTheme.colorScheme.outline,
cursorColor = Brand500
),
singleLine = true
@@ -247,13 +247,13 @@ fun SearchScreen(
modifier = Modifier
.size(64.dp)
.clip(CircleShape)
.background(Slate100),
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = Alignment.Center
) {
Icon(
Icons.Outlined.Search,
contentDescription = null,
tint = Slate400,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(32.dp)
)
}
@@ -261,12 +261,12 @@ fun SearchScreen(
Text(
text = "输入关键词或选择日期",
fontSize = 14.sp,
color = Slate500
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = "探索过去的足迹",
fontSize = 14.sp,
color = Slate500
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@@ -280,7 +280,7 @@ fun SearchScreen(
onCommentClick = { onPostClick(post.id) },
onReactionClick = { }
)
HorizontalDivider(color = Slate100, thickness = 1.dp)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
}
// 底部留白
item {
@@ -333,7 +333,7 @@ private fun DatePickerDialog(
androidx.compose.ui.window.Dialog(onDismissRequest = onDismiss) {
Surface(
shape = RoundedCornerShape(28.dp),
color = Color.White,
color = MaterialTheme.colorScheme.surface,
shadowElevation = 16.dp,
modifier = Modifier
.fillMaxWidth()
@@ -356,7 +356,7 @@ private fun DatePickerDialog(
text = "选择日期",
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
color = Slate900
color = MaterialTheme.colorScheme.onSurface
)
}

View File

@@ -3,6 +3,7 @@ package com.memory.app.ui.theme
import android.app.Activity
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
@@ -34,21 +35,45 @@ private val LightColorScheme = lightColorScheme(
onError = Color.White
)
private val DarkColorScheme = darkColorScheme(
primary = Brand400,
onPrimary = Brand900,
primaryContainer = Brand700,
onPrimaryContainer = Brand100,
secondary = Slate300,
onSecondary = Slate900,
secondaryContainer = Slate700,
onSecondaryContainer = Slate100,
tertiary = Brand400,
onTertiary = Brand900,
background = Slate900,
onBackground = Slate100,
surface = Slate800,
onSurface = Slate100,
surfaceVariant = Slate700,
onSurfaceVariant = Slate300,
outline = Slate600,
outlineVariant = Slate700,
error = Color(0xFFFF6B6B),
onError = Color.White
)
@Composable
fun MemoryTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = LightColorScheme
val colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.statusBarColor = Color.Transparent.toArgb()
window.navigationBarColor = Color.White.toArgb()
window.navigationBarColor = if (darkTheme) Slate900.toArgb() else Color.White.toArgb()
WindowCompat.getInsetsController(window, view).apply {
isAppearanceLightStatusBars = true
isAppearanceLightNavigationBars = true
isAppearanceLightStatusBars = !darkTheme
isAppearanceLightNavigationBars = !darkTheme
}
}
}