draft3
This commit is contained in:
parent
502aaf51f0
commit
9e17e190cc
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,81 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Info
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ActivityItem(title: String, time: String, icon: ImageVector, colors: AppThemes.Colors) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(RoundedCornerShape(10.dp))
|
||||||
|
.background(colors.surface.copy(alpha = 0.5f))
|
||||||
|
.border(1.dp, colors.border.copy(alpha = 0.3f), RoundedCornerShape(10.dp))
|
||||||
|
.padding(horizontal = 16.dp, vertical = 12.dp), // Adjusted padding for mobile
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = colors.accent,
|
||||||
|
modifier = Modifier.size(24.dp) // Slightly larger icon for mobile list items
|
||||||
|
)
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
fontSize = 15.sp,
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.Normal // Adjusted weight
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = time,
|
||||||
|
fontSize = 13.sp,
|
||||||
|
color = colors.secondaryText
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ActivityItemPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ActivityItem(
|
||||||
|
title = "Sample Activity",
|
||||||
|
time = "10:00 AM",
|
||||||
|
icon = Icons.Default.Info,
|
||||||
|
colors = AppThemes.LightThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ActivityItemDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ActivityItem(
|
||||||
|
title = "Sample Activity (Dark)",
|
||||||
|
time = "10:00 AM",
|
||||||
|
icon = Icons.Default.Info,
|
||||||
|
colors = AppThemes.DarkThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ChartPlaceholder(text: String, colors: AppThemes.Colors, modifier: Modifier = Modifier) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.background(colors.background.copy(alpha = 0.5f), RoundedCornerShape(10.dp))
|
||||||
|
.border(1.dp, colors.border.copy(alpha = 0.7f), RoundedCornerShape(10.dp))
|
||||||
|
.padding(16.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
color = colors.secondaryText,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ChartPlaceholderPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ChartPlaceholder(
|
||||||
|
text = "Sample Chart Placeholder",
|
||||||
|
colors = AppThemes.LightThemeColors,
|
||||||
|
modifier = Modifier.fillMaxWidth().height(200.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ChartPlaceholderDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ChartPlaceholder(
|
||||||
|
text = "Sample Chart Placeholder (Dark)",
|
||||||
|
colors = AppThemes.DarkThemeColors,
|
||||||
|
modifier = Modifier.fillMaxWidth().height(200.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,95 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Info
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun InfoItem(
|
||||||
|
icon: ImageVector,
|
||||||
|
text: String,
|
||||||
|
colors: AppThemes.Colors,
|
||||||
|
isLink: Boolean = false,
|
||||||
|
linkUrl: String? = null, // Not used in preview, but kept for component signature
|
||||||
|
onClick: (() -> Unit)? = null
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.clickable(enabled = onClick != null || (isLink && linkUrl != null), onClick = {
|
||||||
|
onClick?.invoke()
|
||||||
|
// if (isLink && linkUrl != null) { /* uriHandler.openUri(linkUrl) */ } // Link opening logic removed for preview
|
||||||
|
})
|
||||||
|
.padding(vertical = 12.dp, horizontal = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = colors.accentVariant,
|
||||||
|
modifier = Modifier.size(24.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
fontSize = 15.sp,
|
||||||
|
color = if (isLink) colors.accent else colors.onSurface,
|
||||||
|
fontWeight = FontWeight.Normal
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun InfoItemPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
InfoItem(
|
||||||
|
icon = Icons.Default.Info,
|
||||||
|
text = "This is an informational item.",
|
||||||
|
colors = AppThemes.LightThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun InfoItemLinkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
InfoItem(
|
||||||
|
icon = Icons.Default.Info,
|
||||||
|
text = "This is a clickable link item.",
|
||||||
|
colors = AppThemes.LightThemeColors,
|
||||||
|
isLink = true,
|
||||||
|
linkUrl = "https://example.com",
|
||||||
|
onClick = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun InfoItemDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
InfoItem(
|
||||||
|
icon = Icons.Default.Info,
|
||||||
|
text = "This is an informational item (Dark).",
|
||||||
|
colors = AppThemes.DarkThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Star
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MetricCard(
|
||||||
|
title: String,
|
||||||
|
value: String,
|
||||||
|
icon: ImageVector,
|
||||||
|
colors: AppThemes.Colors,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
StyledCard(colors = colors, modifier = modifier) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(6.dp) // Tighter spacing for mobile
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = title,
|
||||||
|
tint = colors.accent,
|
||||||
|
modifier = Modifier.size(28.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.labelMedium.copy(color = colors.secondaryText),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = value,
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MetricCardPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MetricCard(
|
||||||
|
title = "Total Users",
|
||||||
|
value = "1,234",
|
||||||
|
icon = Icons.Default.Star,
|
||||||
|
colors = AppThemes.LightThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MetricCardDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MetricCard(
|
||||||
|
title = "Active Sessions (Dark)",
|
||||||
|
value = "56",
|
||||||
|
icon = Icons.Default.Star, // Placeholder
|
||||||
|
colors = AppThemes.DarkThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,98 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Download
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
|
import androidx.compose.material.icons.filled.Visibility
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ReportItem(
|
||||||
|
title: String,
|
||||||
|
period: String,
|
||||||
|
icon: ImageVector,
|
||||||
|
colors: AppThemes.Colors,
|
||||||
|
onDownload: () -> Unit,
|
||||||
|
onView: () -> Unit
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(RoundedCornerShape(10.dp))
|
||||||
|
.clickable { onView() } // Make the whole item clickable for viewing
|
||||||
|
.padding(vertical = 12.dp, horizontal = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = colors.accent,
|
||||||
|
modifier = Modifier.size(32.dp) // Larger icon for report items
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
fontSize = 16.sp, // Slightly larger title
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.Medium
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = period,
|
||||||
|
fontSize = 13.sp,
|
||||||
|
color = colors.secondaryText
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
IconButton(onClick = onDownload, modifier = Modifier.size(40.dp)) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Download,
|
||||||
|
contentDescription = "Download Report",
|
||||||
|
tint = colors.accentVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ReportItemPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ReportItem(
|
||||||
|
title = "Weekly Summary",
|
||||||
|
period = "May 5 - May 11",
|
||||||
|
icon = Icons.Default.Edit, // Changed to avoid conflict with other previews
|
||||||
|
colors = AppThemes.LightThemeColors,
|
||||||
|
onDownload = {},
|
||||||
|
onView = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ReportItemDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ReportItem(
|
||||||
|
title = "Monthly Summary (Dark)",
|
||||||
|
period = "April 2024",
|
||||||
|
icon = Icons.Default.Visibility, // Changed to avoid conflict
|
||||||
|
colors = AppThemes.DarkThemeColors,
|
||||||
|
onDownload = {},
|
||||||
|
onView = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ChevronRight
|
||||||
|
import androidx.compose.material.icons.filled.Settings
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingItem(
|
||||||
|
title: String,
|
||||||
|
subtitle: String,
|
||||||
|
icon: ImageVector,
|
||||||
|
colors: AppThemes.Colors,
|
||||||
|
onClick: (() -> Unit)? = null,
|
||||||
|
showSwitch: Boolean = false,
|
||||||
|
switchChecked: Boolean = false,
|
||||||
|
onSwitchChange: ((Boolean) -> Unit)? = null
|
||||||
|
) {
|
||||||
|
val itemModifier = if (onClick != null || showSwitch) {
|
||||||
|
Modifier.clickable {
|
||||||
|
if (showSwitch && onSwitchChange != null) {
|
||||||
|
onSwitchChange(!switchChecked)
|
||||||
|
} else {
|
||||||
|
onClick?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Modifier
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.then(itemModifier) // Apply clickable if needed
|
||||||
|
.padding(horizontal = 16.dp, vertical = 14.dp), // Standard padding for list items
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = colors.accentVariant,
|
||||||
|
modifier = Modifier.size(24.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
fontSize = 16.sp, // Standard mobile list item title size
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.Normal
|
||||||
|
)
|
||||||
|
if (subtitle.isNotEmpty()) {
|
||||||
|
Text(
|
||||||
|
text = subtitle,
|
||||||
|
fontSize = 13.sp,
|
||||||
|
color = colors.secondaryText
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
if (showSwitch && onSwitchChange != null) {
|
||||||
|
Switch(
|
||||||
|
checked = switchChecked,
|
||||||
|
onCheckedChange = null, // Click handled by Row
|
||||||
|
colors = SwitchDefaults.colors(
|
||||||
|
checkedThumbColor = colors.accent,
|
||||||
|
checkedTrackColor = colors.accent.copy(alpha = 0.5f),
|
||||||
|
uncheckedThumbColor = colors.secondaryText,
|
||||||
|
uncheckedTrackColor = colors.border.copy(alpha = 0.5f)
|
||||||
|
),
|
||||||
|
modifier = Modifier.size(40.dp)
|
||||||
|
)
|
||||||
|
} else if (onClick != null && !showSwitch) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ChevronRight,
|
||||||
|
contentDescription = "Go to setting",
|
||||||
|
tint = colors.secondaryText.copy(alpha = 0.7f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SettingItemPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
SettingItem(
|
||||||
|
title = "Display Settings",
|
||||||
|
subtitle = "Configure screen brightness and theme",
|
||||||
|
icon = Icons.Default.Settings,
|
||||||
|
colors = AppThemes.LightThemeColors,
|
||||||
|
onClick = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SettingItemWithSwitchPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
SettingItem(
|
||||||
|
title = "Enable Notifications",
|
||||||
|
subtitle = "Receive updates and alerts",
|
||||||
|
icon = Icons.Default.Settings, // Placeholder
|
||||||
|
colors = AppThemes.LightThemeColors,
|
||||||
|
showSwitch = true,
|
||||||
|
switchChecked = true,
|
||||||
|
onSwitchChange = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SettingItemDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
SettingItem(
|
||||||
|
title = "Storage Settings (Dark)",
|
||||||
|
subtitle = "Manage local and cloud storage",
|
||||||
|
icon = Icons.Default.Settings, // Placeholder
|
||||||
|
colors = AppThemes.DarkThemeColors,
|
||||||
|
onClick = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.List
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SimpleListItem(
|
||||||
|
icon: ImageVector,
|
||||||
|
text: String,
|
||||||
|
colors: AppThemes.Colors,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier.padding(vertical = 8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = colors.accentVariant,
|
||||||
|
modifier = Modifier.size(22.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
style = MaterialTheme.typography.bodyLarge.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontSize = 15.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SimpleListItemPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Default.List,
|
||||||
|
text = "Sample List Item",
|
||||||
|
colors = AppThemes.LightThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SimpleListItemDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Default.List,
|
||||||
|
text = "Sample List Item (Dark)",
|
||||||
|
colors = AppThemes.DarkThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Favorite
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StyledButton(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
icon: ImageVector,
|
||||||
|
text: String,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
colors: AppThemes.Colors,
|
||||||
|
enabled: Boolean = true
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier.height(48.dp), // Consistent height for mobile buttons
|
||||||
|
enabled = enabled,
|
||||||
|
shape = RoundedCornerShape(10.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = colors.accent.copy(alpha = 0.15f), // Slightly more opaque for visibility
|
||||||
|
contentColor = colors.accent,
|
||||||
|
disabledContainerColor = colors.border.copy(alpha = 0.1f),
|
||||||
|
disabledContentColor = colors.secondaryText.copy(alpha = 0.7f)
|
||||||
|
),
|
||||||
|
border = BorderStroke(1.dp, colors.accent.copy(alpha = 0.4f)),
|
||||||
|
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 10.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Icon(imageVector = icon, contentDescription = null, modifier = Modifier.size(20.dp))
|
||||||
|
Text(text = text, fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun StyledButtonPreview() {
|
||||||
|
StyledButton(
|
||||||
|
icon = Icons.Default.Favorite,
|
||||||
|
text = "Preview Button",
|
||||||
|
onClick = {},
|
||||||
|
colors = AppThemes.LightThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun StyledButtonDarkPreview() {
|
||||||
|
StyledButton(
|
||||||
|
icon = Icons.Default.Favorite,
|
||||||
|
text = "Preview Button Dark",
|
||||||
|
onClick = {},
|
||||||
|
colors = AppThemes.DarkThemeColors
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StyledCard(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
colors: AppThemes.Colors,
|
||||||
|
content: @Composable ColumnScope.() -> Unit
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(RoundedCornerShape(12.dp)), // Slightly more rounded for mobile
|
||||||
|
colors = CardDefaults.cardColors(
|
||||||
|
containerColor = colors.surface
|
||||||
|
),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp), // Slightly more elevation for mobile
|
||||||
|
border = BorderStroke(1.dp, colors.border.copy(alpha = 0.4f)),
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun StyledCardPreview() {
|
||||||
|
StyledCard(
|
||||||
|
colors = AppThemes.LightThemeColors
|
||||||
|
) {
|
||||||
|
// Preview content
|
||||||
|
Text("123")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,165 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.InfoItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.SettingItem
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MobileAboutScreen(colors: AppThemes.Colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Analytics, // App Icon
|
||||||
|
contentDescription = "App Logo",
|
||||||
|
tint = colors.accent,
|
||||||
|
modifier = Modifier.size(72.dp) // Slightly smaller for mobile about screen
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"Activity Analyzer",
|
||||||
|
style = MaterialTheme.typography.headlineMedium.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 24.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"Version 1.0.0-beta",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.secondaryText,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
"Your personal screen time companion, helping you understand and manage your digital habits across platforms.",
|
||||||
|
style = MaterialTheme.typography.bodyLarge.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontSize = 15.sp
|
||||||
|
),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Developer Info Section
|
||||||
|
Text(
|
||||||
|
"Developer",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.accent,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.Start).padding(top = 8.dp)
|
||||||
|
)
|
||||||
|
InfoItem(icon = Icons.Filled.Person, text = "grtsinry43", colors = colors, onClick = {})
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.2f))
|
||||||
|
InfoItem(
|
||||||
|
icon = Icons.Filled.Email,
|
||||||
|
text = "grtsinry43@outlook.com",
|
||||||
|
colors = colors,
|
||||||
|
isLink = true,
|
||||||
|
linkUrl = "mailto:grtsinry43@outlook.com",
|
||||||
|
onClick = {})
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.2f))
|
||||||
|
InfoItem(
|
||||||
|
icon = Icons.Filled.Language,
|
||||||
|
text = "blog.grtsinry43.com",
|
||||||
|
colors = colors,
|
||||||
|
isLink = true,
|
||||||
|
linkUrl = "https://blog.grtsinry43.com",
|
||||||
|
onClick = {})
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.2f))
|
||||||
|
InfoItem(
|
||||||
|
icon = Icons.Filled.Code,
|
||||||
|
text = "github.com/grtsinry43",
|
||||||
|
colors = colors,
|
||||||
|
isLink = true,
|
||||||
|
linkUrl = "https://github.com/grtsinry43",
|
||||||
|
onClick = {})
|
||||||
|
|
||||||
|
|
||||||
|
// Application Info Section
|
||||||
|
Text(
|
||||||
|
"Application Info",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.accent,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.Start).padding(top = 16.dp)
|
||||||
|
)
|
||||||
|
SettingItem(
|
||||||
|
title = "Check for Updates",
|
||||||
|
subtitle = "Last checked: Today",
|
||||||
|
icon = Icons.Default.SystemUpdateAlt,
|
||||||
|
colors = colors,
|
||||||
|
onClick = {})
|
||||||
|
Divider(
|
||||||
|
color = colors.border.copy(alpha = 0.2f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
) // Use full width divider for settings like items
|
||||||
|
SettingItem(
|
||||||
|
title = "Acknowledgements",
|
||||||
|
subtitle = "Libraries and resources",
|
||||||
|
icon = Icons.Default.FavoriteBorder,
|
||||||
|
colors = colors,
|
||||||
|
onClick = {})
|
||||||
|
Divider(
|
||||||
|
color = colors.border.copy(alpha = 0.2f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
SettingItem(
|
||||||
|
title = "License Information",
|
||||||
|
subtitle = "View license",
|
||||||
|
icon = Icons.Default.Gavel,
|
||||||
|
colors = colors,
|
||||||
|
onClick = {})
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Text(
|
||||||
|
"© 2025 grtsinry43. All rights reserved.",
|
||||||
|
style = MaterialTheme.typography.bodySmall.copy(
|
||||||
|
color = colors.secondaryText,
|
||||||
|
fontSize = 12.sp
|
||||||
|
),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp, top = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileAboutScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileAboutScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileAboutScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileAboutScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,191 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.ChartPlaceholder
|
||||||
|
import com.grtsinry43.activityanalyzer.components.MetricCard
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledButton
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledCard
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MobileAnalyticsScreen(colors: AppThemes.Colors) {
|
||||||
|
var selectedTimeRange by remember { mutableStateOf("Last 7 Days") }
|
||||||
|
val timeRanges =
|
||||||
|
listOf("Today", "Yesterday", "Last 7 Days", "Last 30 Days") // Simplified for mobile
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Screen Time Analytics",
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 22.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
Box(modifier = Modifier.fillMaxWidth()) { // Make dropdown full width for better mobile UX
|
||||||
|
OutlinedButton(
|
||||||
|
onClick = { expanded = true },
|
||||||
|
shape = MaterialTheme.shapes.medium,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
contentPadding = PaddingValues(16.dp)
|
||||||
|
) {
|
||||||
|
Text(selectedTimeRange, color = colors.accent, fontSize = 16.sp)
|
||||||
|
Spacer(Modifier.weight(1f))
|
||||||
|
Icon(
|
||||||
|
Icons.Default.ArrowDropDown,
|
||||||
|
contentDescription = "Select time range",
|
||||||
|
tint = colors.accent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false },
|
||||||
|
modifier = Modifier.fillMaxWidth(0.9f) // Adjust width as needed
|
||||||
|
) {
|
||||||
|
timeRanges.forEach { range ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(range, fontSize = 16.sp) },
|
||||||
|
onClick = {
|
||||||
|
selectedTimeRange = range
|
||||||
|
expanded = false
|
||||||
|
// TODO: Update analytics data
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key Metrics - Use a Grid for better mobile layout if more than 2, or stacked Rows
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
|
MetricCard(
|
||||||
|
title = "Total Time",
|
||||||
|
value = "25h 10m",
|
||||||
|
icon = Icons.Default.Smartphone,
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
MetricCard(
|
||||||
|
title = "Avg Daily",
|
||||||
|
value = "3h 35m",
|
||||||
|
icon = Icons.Default.AvTimer,
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
|
MetricCard(
|
||||||
|
title = "Most Used",
|
||||||
|
value = "App A",
|
||||||
|
icon = Icons.Default.StarOutline,
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
MetricCard(
|
||||||
|
title = "Pickups",
|
||||||
|
value = "75",
|
||||||
|
icon = Icons.Default.TouchApp,
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Usage Patterns",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ChartPlaceholder(
|
||||||
|
text = "Daily Screen Time (Bar Chart)",
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.fillMaxWidth().height(180.dp)
|
||||||
|
) // Slightly smaller charts for mobile
|
||||||
|
ChartPlaceholder(
|
||||||
|
text = "App Usage (Pie Chart)",
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.fillMaxWidth().height(180.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Analysis Tools",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Icons.Default.PieChartOutline,
|
||||||
|
text = "App Usage Breakdown",
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Icons.Default.AccessTime,
|
||||||
|
text = "Time of Day Analysis",
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Icons.Default.TrackChanges,
|
||||||
|
text = "Set Usage Goals",
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileAnalyticsScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileAnalyticsScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileAnalyticsScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileAnalyticsScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,174 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.ActivityItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.SimpleListItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledButton
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledCard
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MobileHomeScreen(colors: AppThemes.Colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp), // Standard padding for mobile screens
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Welcome Back, grtsinry43!",
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 22.sp // Adjusted for mobile
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Today's Screen Time",
|
||||||
|
style = MaterialTheme.typography.titleLarge.copy( // Larger title for emphasis
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 18.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "3h 45m", // Placeholder
|
||||||
|
style = MaterialTheme.typography.displayMedium.copy( // Prominent display
|
||||||
|
color = colors.accent,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 36.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "You're on track with your daily goal!", // Placeholder
|
||||||
|
style = MaterialTheme.typography.bodyMedium.copy(
|
||||||
|
color = colors.secondaryText,
|
||||||
|
fontSize = 14.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Quick Glance: Top Apps",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.SmartDisplay,
|
||||||
|
text = "App A: 1h 15m",
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.PhotoCamera,
|
||||||
|
text = "App B: 45m",
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
SimpleListItem(icon = Icons.Filled.Chat, text = "App C: 30m", colors = colors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp) // Spacing for buttons
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Quick Actions",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
StyledButton( // Full width buttons for mobile quick actions
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Icons.Default.HourglassTop,
|
||||||
|
text = "Start Focus Session",
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Icons.Default.CalendarViewDay, // Changed icon
|
||||||
|
text = "View Today's Details",
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Recent Insights",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ActivityItem(
|
||||||
|
title = "Exceeded daily goal for App X.",
|
||||||
|
time = "Today, 2:30 PM",
|
||||||
|
icon = Icons.Default.WarningAmber,
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
ActivityItem(
|
||||||
|
title = "Screen time 20% higher yesterday.",
|
||||||
|
time = "Insight from yesterday",
|
||||||
|
icon = Icons.Default.TrendingUp,
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileHomeScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileHomeScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileHomeScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileHomeScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,188 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.SimpleListItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledButton
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledCard
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MobileProfileScreen(colors: AppThemes.Colors) {
|
||||||
|
var nickname by remember { mutableStateOf("grtsinry43") }
|
||||||
|
var email by remember { mutableStateOf("grtsinry43@outlook.com") }
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(20.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally // Center content like avatar
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"User Profile",
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 22.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.Start) // Align title to start
|
||||||
|
)
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.AccountCircle,
|
||||||
|
contentDescription = "User Avatar",
|
||||||
|
tint = colors.accent,
|
||||||
|
modifier = Modifier.size(120.dp) // Large avatar for profile screen
|
||||||
|
)
|
||||||
|
// TODO: Add option to change avatar (e.g., an Edit icon button)
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = nickname,
|
||||||
|
onValueChange = { nickname = it },
|
||||||
|
label = { Text("Nickname") },
|
||||||
|
singleLine = true,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
colors = OutlinedTextFieldDefaults.colors(
|
||||||
|
focusedBorderColor = colors.accent,
|
||||||
|
unfocusedBorderColor = colors.border,
|
||||||
|
focusedLabelColor = colors.accent,
|
||||||
|
cursorColor = colors.accent,
|
||||||
|
focusedTextColor = colors.onSurface,
|
||||||
|
unfocusedTextColor = colors.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = email,
|
||||||
|
onValueChange = { email = it },
|
||||||
|
label = { Text("Email") },
|
||||||
|
singleLine = true,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
colors = OutlinedTextFieldDefaults.colors(
|
||||||
|
focusedBorderColor = colors.accent,
|
||||||
|
unfocusedBorderColor = colors.border,
|
||||||
|
focusedLabelColor = colors.accent,
|
||||||
|
cursorColor = colors.accent,
|
||||||
|
focusedTextColor = colors.onSurface,
|
||||||
|
unfocusedTextColor = colors.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
icon = Icons.Default.Save,
|
||||||
|
text = "Save Changes",
|
||||||
|
onClick = { /* TODO: Save profile changes */ },
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Overall Statistics Card
|
||||||
|
StyledCard(colors = colors, modifier = Modifier.padding(top = 16.dp)) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Overall Statistics",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.Timer,
|
||||||
|
text = "Total Time Tracked: 1250 hrs",
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.CheckCircleOutline,
|
||||||
|
text = "Goals Met Streak: 15 days",
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.EventAvailable,
|
||||||
|
text = "Joined: Jan 1, 2024",
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account Actions
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(top = 16.dp).fillMaxWidth(),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Account Actions",
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 4.dp)
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
icon = Icons.Default.LockReset,
|
||||||
|
text = "Change Password",
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
Button( // Destructive action button styling
|
||||||
|
onClick = { /* TODO: Show confirmation dialog */ },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(10.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = Color.Red.copy(alpha = 0.1f),
|
||||||
|
contentColor = Color.Red.copy(alpha = 0.9f)
|
||||||
|
),
|
||||||
|
border = BorderStroke(1.dp, Color.Red.copy(alpha = 0.3f)),
|
||||||
|
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 12.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.DeleteForever,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(20.dp)
|
||||||
|
)
|
||||||
|
Text("Delete Account", fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileProfileScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileProfileScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileProfileScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileProfileScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.ReportItem
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MobileReportsScreen(colors: AppThemes.Colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Screen Time Reports",
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 22.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
IconButton(onClick = { /* TODO: Generate new report */ }) { // Icon button for mobile
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Addchart,
|
||||||
|
contentDescription = "Generate New Report",
|
||||||
|
tint = colors.accent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example Reports - for mobile, a simple list is often best
|
||||||
|
ReportItem(
|
||||||
|
title = "Weekly Summary - May 5-11",
|
||||||
|
period = "Generated: May 12, 2025",
|
||||||
|
icon = Icons.Default.CalendarToday,
|
||||||
|
colors = colors,
|
||||||
|
onDownload = {},
|
||||||
|
onView = {})
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.2f), thickness = 0.5.dp)
|
||||||
|
ReportItem(
|
||||||
|
title = "Monthly App Usage - April",
|
||||||
|
period = "Generated: May 1, 2025",
|
||||||
|
icon = Icons.Default.PieChart,
|
||||||
|
colors = colors,
|
||||||
|
onDownload = {},
|
||||||
|
onView = {})
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.2f), thickness = 0.5.dp)
|
||||||
|
ReportItem(
|
||||||
|
title = "Q1 Device Pickups",
|
||||||
|
period = "Generated: April 5, 2025",
|
||||||
|
icon = Icons.Default.TouchApp,
|
||||||
|
colors = colors,
|
||||||
|
onDownload = {},
|
||||||
|
onView = {})
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.2f), thickness = 0.5.dp)
|
||||||
|
ReportItem(
|
||||||
|
title = "Focus Session - Project X",
|
||||||
|
period = "Generated: May 10, 2025",
|
||||||
|
icon = Icons.Default.HourglassEmpty,
|
||||||
|
colors = colors,
|
||||||
|
onDownload = {},
|
||||||
|
onView = {})
|
||||||
|
|
||||||
|
// Placeholder if no reports
|
||||||
|
// Box(modifier = Modifier.fillMaxSize().padding(top = 32.dp), contentAlignment = Alignment.Center) {
|
||||||
|
// Text("No reports generated yet.", color = colors.secondaryText, style = MaterialTheme.typography.bodyLarge)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileReportsScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileReportsScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileReportsScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileReportsScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,182 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.SettingItem
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MobileSettingsScreen(
|
||||||
|
colors: AppThemes.Colors,
|
||||||
|
isDarkTheme: Boolean,
|
||||||
|
onThemeChange: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
var autoBackupEnabled by remember { mutableStateOf(true) }
|
||||||
|
var notificationsEnabled by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(bottom = 16.dp), // Padding at the bottom for scrollable content
|
||||||
|
verticalArrangement = Arrangement.spacedBy(0.dp) // No space between items, handled by SettingItem padding and dividers
|
||||||
|
) {
|
||||||
|
// General Group
|
||||||
|
SettingsGroupHeader(title = "General", colors = colors)
|
||||||
|
SettingItem(
|
||||||
|
title = "Dark Theme",
|
||||||
|
subtitle = if (isDarkTheme) "Enabled" else "Disabled",
|
||||||
|
icon = Icons.Default.Brightness6,
|
||||||
|
colors = colors,
|
||||||
|
showSwitch = true,
|
||||||
|
switchChecked = isDarkTheme,
|
||||||
|
onSwitchChange = onThemeChange
|
||||||
|
)
|
||||||
|
Divider(
|
||||||
|
color = colors.border.copy(alpha = 0.2f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
SettingItem(
|
||||||
|
title = "Data Storage",
|
||||||
|
subtitle = "Manage storage location", // Simplified for mobile
|
||||||
|
icon = Icons.Default.FolderOpen,
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO */ }
|
||||||
|
)
|
||||||
|
Divider(
|
||||||
|
color = colors.border.copy(alpha = 0.2f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
SettingItem(
|
||||||
|
title = "Auto Backup",
|
||||||
|
subtitle = if (autoBackupEnabled) "Daily at 2:00 AM" else "Disabled",
|
||||||
|
icon = Icons.Default.SaveAlt,
|
||||||
|
colors = colors,
|
||||||
|
showSwitch = true,
|
||||||
|
switchChecked = autoBackupEnabled,
|
||||||
|
onSwitchChange = { autoBackupEnabled = it }
|
||||||
|
)
|
||||||
|
Divider(
|
||||||
|
color = colors.border.copy(alpha = 0.2f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
SettingItem(
|
||||||
|
title = "Cloud Sync",
|
||||||
|
subtitle = "Not Connected",
|
||||||
|
icon = Icons.Default.CloudQueue,
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO */ }
|
||||||
|
)
|
||||||
|
Divider(
|
||||||
|
color = colors.border.copy(alpha = 0.2f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
SettingItem(
|
||||||
|
title = "Export Data",
|
||||||
|
subtitle = "Export activity data",
|
||||||
|
icon = Icons.Default.Output,
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO */ }
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tracking Group
|
||||||
|
SettingsGroupHeader(title = "Tracking", colors = colors)
|
||||||
|
SettingItem(
|
||||||
|
title = "Apps to Track",
|
||||||
|
subtitle = "All Apps", // Placeholder
|
||||||
|
icon = Icons.Default.AppBlocking,
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO */ }
|
||||||
|
)
|
||||||
|
Divider(
|
||||||
|
color = colors.border.copy(alpha = 0.2f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
SettingItem(
|
||||||
|
title = "Tracking Sensitivity",
|
||||||
|
subtitle = "Medium", // Placeholder
|
||||||
|
icon = Icons.Default.Tune,
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO */ }
|
||||||
|
)
|
||||||
|
|
||||||
|
// Notifications Group
|
||||||
|
SettingsGroupHeader(title = "Notifications", colors = colors)
|
||||||
|
SettingItem(
|
||||||
|
title = "Screen Time Limits",
|
||||||
|
subtitle = "Notify when limits exceeded",
|
||||||
|
icon = Icons.Default.NotificationsActive,
|
||||||
|
colors = colors,
|
||||||
|
showSwitch = true,
|
||||||
|
switchChecked = notificationsEnabled,
|
||||||
|
onSwitchChange = { notificationsEnabled = it }
|
||||||
|
)
|
||||||
|
Divider(
|
||||||
|
color = colors.border.copy(alpha = 0.2f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
SettingItem(
|
||||||
|
title = "Break Reminders",
|
||||||
|
subtitle = "Get reminded to take breaks",
|
||||||
|
icon = Icons.Default.SelfImprovement,
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO */ }
|
||||||
|
)
|
||||||
|
Divider(
|
||||||
|
color = colors.border.copy(alpha = 0.2f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
SettingItem(
|
||||||
|
title = "Weekly Summary",
|
||||||
|
subtitle = "Notify every Monday",
|
||||||
|
icon = Icons.Default.MarkEmailRead,
|
||||||
|
colors = colors,
|
||||||
|
showSwitch = true,
|
||||||
|
switchChecked = true, // Placeholder
|
||||||
|
onSwitchChange = { /* TODO */ }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingsGroupHeader(title: String, colors: AppThemes.Colors) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.titleSmall.copy( // Using titleSmall for group headers
|
||||||
|
color = colors.accent, // Use accent color for headers
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 14.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(colors.background) // Ensure header background matches screen
|
||||||
|
.padding(horizontal = 16.dp, vertical = 12.dp) // More padding for group headers
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileSettingsScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileSettingsScreen(colors = AppThemes.LightThemeColors, isDarkTheme = false, onThemeChange = {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MobileSettingsScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
MobileSettingsScreen(colors = AppThemes.DarkThemeColors, isDarkTheme = true, onThemeChange = {})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.theme
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
// --- THEMES (Reused from Desktop App) ---
|
||||||
|
// 定义颜色主题,提供更传统的桌面应用外观
|
||||||
|
object AppThemes {
|
||||||
|
data class Colors(
|
||||||
|
val background: Color,
|
||||||
|
val surface: Color,
|
||||||
|
val onSurface: Color,
|
||||||
|
val onBackground: Color,
|
||||||
|
val accent: Color,
|
||||||
|
val accentVariant: Color, // 用于细微强调或悬停状态
|
||||||
|
val border: Color,
|
||||||
|
val secondaryText: Color,
|
||||||
|
val onAccent: Color // 强调背景上的文本/图标颜色
|
||||||
|
)
|
||||||
|
|
||||||
|
val LightThemeColors = Colors(
|
||||||
|
background = Color(0xFFE0E0E0), // Light Gray // 浅灰色
|
||||||
|
surface = Color(0xFFFFFFFF), // White // 白色
|
||||||
|
onSurface = Color(0xFF212121), // Dark Gray // 深灰色
|
||||||
|
onBackground = Color(0xFF212121), // Dark Gray // 深灰色
|
||||||
|
accent = Color(0xFF0D47A1), // Dark Blue // 深蓝色
|
||||||
|
accentVariant = Color(0xFF1565C0), // Medium Blue // 中蓝色
|
||||||
|
border = Color(0xFFB0B0B0), // Medium Gray // 中灰色
|
||||||
|
secondaryText = Color(0xFF757575), // Gray // 灰色
|
||||||
|
onAccent = Color.White
|
||||||
|
)
|
||||||
|
|
||||||
|
val DarkThemeColors = Colors(
|
||||||
|
background = Color(0xFF212121), // Very Dark Gray // 非常深的灰色
|
||||||
|
surface = Color(0xFF303030), // Dark Gray // 深灰色
|
||||||
|
onSurface = Color(0xFFE0E0E0), // Light Gray // 浅灰色
|
||||||
|
onBackground = Color(0xFFE0E0E0), // Light Gray // 浅灰色
|
||||||
|
accent = Color(0xFF42A5F5), // Light Blue // 浅蓝色
|
||||||
|
accentVariant = Color(0xFF64B5F6), // Lighter Blue // 更浅的蓝色
|
||||||
|
border = Color(0xFF525252), // Medium Dark Gray // 中度深灰色
|
||||||
|
secondaryText = Color(0xFFBDBDBD), // Light Gray // 浅灰色
|
||||||
|
onAccent = Color.Black
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package com.grtsinry43.activityanalyzer
|
package com.grtsinry43.activityanalyzer
|
||||||
|
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@ -13,13 +12,19 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
|
import com.grtsinry43.activityanalyzer.components.*
|
||||||
|
import com.grtsinry43.activityanalyzer.screens.AboutScreen
|
||||||
|
import com.grtsinry43.activityanalyzer.screens.AnalyticsScreen
|
||||||
|
import com.grtsinry43.activityanalyzer.screens.HomeScreen
|
||||||
|
import com.grtsinry43.activityanalyzer.screens.ProfileScreen
|
||||||
|
import com.grtsinry43.activityanalyzer.screens.ReportsScreen
|
||||||
|
import com.grtsinry43.activityanalyzer.screens.SettingsScreen
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@Preview
|
@Preview
|
||||||
@ -175,927 +180,3 @@ fun DesktopApp() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun NavItem(
|
|
||||||
icon: ImageVector, // 导航项图标
|
|
||||||
text: String, // 导航项文本
|
|
||||||
isSelected: Boolean, // 是否被选中
|
|
||||||
onClick: () -> Unit, // 点击事件回调
|
|
||||||
colors: AppThemes.Colors, // 当前颜色主题
|
|
||||||
isSidebarCollapsed: Boolean // 侧边栏是否折叠
|
|
||||||
) {
|
|
||||||
val interactionSource = remember { MutableInteractionSource() } // 用于自定义点击效果
|
|
||||||
val backgroundColor =
|
|
||||||
if (isSelected) colors.accent.copy(alpha = 0.15f) else Color.Transparent // 选中时背景色高亮
|
|
||||||
val contentColor =
|
|
||||||
if (isSelected) colors.accent else colors.onSurface.copy(alpha = 0.8f) // 选中时内容颜色使用强调色
|
|
||||||
|
|
||||||
Row( // 使用 Row 布局导航项
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth() // 填充宽度
|
|
||||||
.height(if (isSidebarCollapsed) 50.dp else 44.dp) // 根据折叠状态调整高度
|
|
||||||
.clip(RoundedCornerShape(8.dp)) // 圆角
|
|
||||||
.background(backgroundColor) // 背景色
|
|
||||||
.clickable( // 设置点击事件
|
|
||||||
onClick = onClick,
|
|
||||||
interactionSource = interactionSource,
|
|
||||||
indication = null // 不使用默认的点击涟漪效果,依赖背景色变化
|
|
||||||
)
|
|
||||||
.padding(horizontal = if (isSidebarCollapsed) 0.dp else 12.dp), // 折叠时水平内边距为0,使图标居中
|
|
||||||
verticalAlignment = Alignment.CenterVertically, // 垂直居中对齐
|
|
||||||
horizontalArrangement = if (isSidebarCollapsed) Arrangement.Center else Arrangement.Start // 折叠时水平居中,否则从左开始
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = icon,
|
|
||||||
contentDescription = text.ifEmpty { null }, // 如果文本为空,则内容描述为null
|
|
||||||
tint = contentColor, // 图标颜色
|
|
||||||
modifier = Modifier.size(if (isSidebarCollapsed) 28.dp else 22.dp) // 根据折叠状态调整图标大小
|
|
||||||
)
|
|
||||||
if (!isSidebarCollapsed) { // 如果侧边栏未折叠,则显示文本
|
|
||||||
Spacer(modifier = Modifier.width(12.dp)) // 图标和文本之间的间距
|
|
||||||
Text(
|
|
||||||
text = text,
|
|
||||||
color = contentColor, // 文本颜色
|
|
||||||
fontSize = 15.sp, // 字体大小
|
|
||||||
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal // 选中时字体加粗
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun HomeScreen(colors: AppThemes.Colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(8.dp)
|
|
||||||
.verticalScroll(rememberScrollState()), // 添加垂直滚动
|
|
||||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
|
||||||
) {
|
|
||||||
SelectionContainer { // 允许文本选择
|
|
||||||
Text(
|
|
||||||
text = "Welcome Back, grtsinry43!", // 个性化欢迎语
|
|
||||||
style = MaterialTheme.typography.headlineSmall.copy(
|
|
||||||
color = colors.onBackground,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overview of today's screen time
|
|
||||||
// 今日屏幕使用时间概览
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Today's Screen Time", // 今日屏幕使用时间
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "3h 45m", // 占位符数据
|
|
||||||
style = MaterialTheme.typography.displaySmall.copy(
|
|
||||||
color = colors.accent,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
),
|
|
||||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "You're on track with your daily goal!", // 占位符提示
|
|
||||||
style = MaterialTheme.typography.bodyMedium.copy(color = colors.secondaryText),
|
|
||||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Quick Glance: Top Apps Today
|
|
||||||
// 快速浏览:今日热门应用
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Quick Glance: Top Apps Today", // 快速浏览:今日热门应用
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
SimpleListItem(
|
|
||||||
icon = Icons.Filled.SmartDisplay,
|
|
||||||
text = "App A: 1h 15m",
|
|
||||||
colors = colors
|
|
||||||
) // 示例应用A
|
|
||||||
SimpleListItem(
|
|
||||||
icon = Icons.Filled.PhotoCamera,
|
|
||||||
text = "App B: 45m",
|
|
||||||
colors = colors
|
|
||||||
) // 示例应用B
|
|
||||||
SimpleListItem(
|
|
||||||
icon = Icons.Filled.Chat,
|
|
||||||
text = "App C: 30m",
|
|
||||||
colors = colors
|
|
||||||
) // 示例应用C
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Quick actions
|
|
||||||
// 快捷操作
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Quick Actions", // 快捷操作
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
|
||||||
) {
|
|
||||||
StyledButton(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
icon = Icons.Default.HourglassTop, // 专注时段图标
|
|
||||||
text = "Focus Session", // 开始专注时段
|
|
||||||
onClick = { /* TODO: Start focus session */ },
|
|
||||||
colors = colors
|
|
||||||
)
|
|
||||||
StyledButton(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
icon = Icons.Default.CalendarViewWeek, // 每周报告图标
|
|
||||||
text = "Weekly Report", // 查看每周报告
|
|
||||||
onClick = { /* TODO: Navigate to weekly report */ },
|
|
||||||
colors = colors
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recent Alerts/Insights
|
|
||||||
// 近期提醒/洞察
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Recent Insights", // 近期洞察
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
ActivityItem(
|
|
||||||
title = "You've exceeded your daily goal for App X.", // 应用X超出每日目标
|
|
||||||
time = "Today, 2:30 PM", // 时间
|
|
||||||
icon = Icons.Default.WarningAmber, // 警告图标
|
|
||||||
colors = colors
|
|
||||||
)
|
|
||||||
ActivityItem(
|
|
||||||
title = "Screen time was 20% higher yesterday.", // 昨日屏幕时间增加20%
|
|
||||||
time = "Insight from yesterday", // 时间
|
|
||||||
icon = Icons.Default.TrendingUp, // 趋势向上图标
|
|
||||||
colors = colors
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun AnalyticsScreen(colors: AppThemes.Colors) {
|
|
||||||
var selectedTimeRange by remember { mutableStateOf("Last 7 Days") } // 记住选中的时间范围
|
|
||||||
val timeRanges =
|
|
||||||
listOf("Today", "Yesterday", "Last 7 Days", "Last 30 Days", "Custom Range") // 可选时间范围
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(8.dp)
|
|
||||||
.verticalScroll(rememberScrollState()), // 添加垂直滚动
|
|
||||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Screen Time Analytics", // 屏幕时间分析
|
|
||||||
style = MaterialTheme.typography.headlineSmall.copy(
|
|
||||||
color = colors.onBackground,
|
|
||||||
fontWeight = FontWeight.Bold // 标题加粗
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Time Range Filter
|
|
||||||
// 时间范围筛选器
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Time Range:",
|
|
||||||
style = MaterialTheme.typography.titleSmall.copy(color = colors.onBackground)
|
|
||||||
) // 时间范围标签
|
|
||||||
var expanded by remember { mutableStateOf(false) } // 下拉菜单是否展开
|
|
||||||
Box {
|
|
||||||
OutlinedButton(
|
|
||||||
onClick = { expanded = true },
|
|
||||||
shape = RoundedCornerShape(8.dp)
|
|
||||||
) { // 点击展开下拉菜单
|
|
||||||
Text(selectedTimeRange, color = colors.accent) // 显示当前选中的时间范围
|
|
||||||
Icon(
|
|
||||||
Icons.Default.ArrowDropDown,
|
|
||||||
contentDescription = "Select time range",
|
|
||||||
tint = colors.accent
|
|
||||||
) // 下拉箭头图标
|
|
||||||
}
|
|
||||||
DropdownMenu( // 下拉菜单
|
|
||||||
expanded = expanded,
|
|
||||||
onDismissRequest = { expanded = false } // 点击外部关闭下拉菜单
|
|
||||||
) {
|
|
||||||
timeRanges.forEach { range ->
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(range) },
|
|
||||||
onClick = {
|
|
||||||
selectedTimeRange = range // 更新选中的时间范围
|
|
||||||
expanded = false // 关闭下拉菜单
|
|
||||||
// TODO: Update analytics data based on range // 根据选择的时间范围更新分析数据
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Key Metrics Cards
|
|
||||||
// 关键指标卡片
|
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
|
||||||
MetricCard(
|
|
||||||
title = "Total Screen Time",
|
|
||||||
value = "25h 10m",
|
|
||||||
icon = Icons.Default.Smartphone,
|
|
||||||
colors = colors,
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
) // 总屏幕时间
|
|
||||||
MetricCard(
|
|
||||||
title = "Avg Daily Time",
|
|
||||||
value = "3h 35m",
|
|
||||||
icon = Icons.Default.AvTimer,
|
|
||||||
colors = colors,
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
) // 平均每日时间
|
|
||||||
}
|
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
|
||||||
MetricCard(
|
|
||||||
title = "Most Used App",
|
|
||||||
value = "App A (8h)",
|
|
||||||
icon = Icons.Default.StarOutline,
|
|
||||||
colors = colors,
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
) // 最常用应用
|
|
||||||
MetricCard(
|
|
||||||
title = "Pickups",
|
|
||||||
value = "75 today",
|
|
||||||
icon = Icons.Default.TouchApp,
|
|
||||||
colors = colors,
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
) // 今日拿起次数
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Charts Section
|
|
||||||
// 图表区域
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Usage Patterns", // 使用模式
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// Placeholder for Daily/Weekly Screen Time Bar Chart
|
|
||||||
// 每日/每周屏幕时间柱状图占位符
|
|
||||||
ChartPlaceholder(
|
|
||||||
text = "Daily/Weekly Screen Time (Bar Chart)",
|
|
||||||
colors = colors,
|
|
||||||
modifier = Modifier.fillMaxWidth().height(200.dp)
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
// Placeholder for App Usage Distribution Pie Chart
|
|
||||||
// 应用使用分布饼图占位符
|
|
||||||
ChartPlaceholder(
|
|
||||||
text = "App Usage Distribution (Pie Chart)",
|
|
||||||
colors = colors,
|
|
||||||
modifier = Modifier.fillMaxWidth().height(200.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Analysis Tools
|
|
||||||
// 分析工具
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Analysis Tools", // 分析工具
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
|
||||||
) {
|
|
||||||
StyledButton(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
icon = Icons.Default.PieChartOutline, // 应用细分图标
|
|
||||||
text = "App Breakdown", // 应用细分
|
|
||||||
onClick = { /* TODO */ },
|
|
||||||
colors = colors
|
|
||||||
)
|
|
||||||
StyledButton(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
icon = Icons.Default.AccessTime, // 时间段图标
|
|
||||||
text = "Time of Day", // 按时间段分析
|
|
||||||
onClick = { /* TODO */ },
|
|
||||||
colors = colors
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
|
||||||
) {
|
|
||||||
StyledButton(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
icon = Icons.Default.TrackChanges, // 使用目标图标
|
|
||||||
text = "Usage Goals", // 使用目标
|
|
||||||
onClick = { /* TODO */ },
|
|
||||||
colors = colors
|
|
||||||
)
|
|
||||||
StyledButton(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
icon = Icons.Default.CompareArrows, // 比较时段图标
|
|
||||||
text = "Compare Periods", // 比较时段
|
|
||||||
onClick = { /* TODO */ },
|
|
||||||
colors = colors
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ReportsScreen(colors: AppThemes.Colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(8.dp)
|
|
||||||
.verticalScroll(rememberScrollState()), // 添加垂直滚动
|
|
||||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween, // 两端对齐
|
|
||||||
verticalAlignment = Alignment.CenterVertically // 垂直居中
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Screen Time Reports", // 屏幕时间报告
|
|
||||||
style = MaterialTheme.typography.headlineSmall.copy(
|
|
||||||
color = colors.onBackground,
|
|
||||||
fontWeight = FontWeight.Bold // 标题加粗
|
|
||||||
)
|
|
||||||
)
|
|
||||||
StyledButton(
|
|
||||||
icon = Icons.Default.Addchart, // 生成报告图标
|
|
||||||
text = "Generate New Report", // 生成新报告
|
|
||||||
onClick = { /* TODO: Open report generation dialog */ }, // 打开报告生成对话框
|
|
||||||
colors = colors
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
StyledCard(colors = colors) { // 已生成报告列表卡片
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp) // 列表项之间的紧凑间距
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Generated Reports", // 已生成报告
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
),
|
|
||||||
modifier = Modifier.padding(bottom = 8.dp) // 标题下方间距
|
|
||||||
)
|
|
||||||
ReportItem( // 报告项示例1
|
|
||||||
title = "Weekly Summary - May 5-11, 2025", // 每周总结
|
|
||||||
period = "Generated: May 12, 2025", // 生成日期
|
|
||||||
icon = Icons.Default.CalendarToday, // 日历图标
|
|
||||||
colors = colors,
|
|
||||||
onDownload = { /* TODO */ }, // 下载回调
|
|
||||||
onView = { /* TODO */ } // 查看回调
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f)) // 分隔线
|
|
||||||
ReportItem( // 报告项示例2
|
|
||||||
title = "Monthly App Usage - April 2025", // 每月应用使用情况
|
|
||||||
period = "Generated: May 1, 2025", // 生成日期
|
|
||||||
icon = Icons.Default.PieChart, // 饼图图标
|
|
||||||
colors = colors,
|
|
||||||
onDownload = { /* TODO */ },
|
|
||||||
onView = { /* TODO */ }
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
ReportItem( // 报告项示例3
|
|
||||||
title = "Q1 Device Pickup Analysis", // Q1设备拿起分析
|
|
||||||
period = "Generated: April 5, 2025", // 生成日期
|
|
||||||
icon = Icons.Default.TouchApp, // 触摸应用图标
|
|
||||||
colors = colors,
|
|
||||||
onDownload = { /* TODO */ },
|
|
||||||
onView = { /* TODO */ }
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
ReportItem( // 报告项示例4
|
|
||||||
title = "Focus Session Report - Project X", // 专注时段报告 - 项目X
|
|
||||||
period = "Generated: May 10, 2025", // 生成日期
|
|
||||||
icon = Icons.Default.HourglassEmpty, // 沙漏图标
|
|
||||||
colors = colors,
|
|
||||||
onDownload = { /* TODO */ },
|
|
||||||
onView = { /* TODO */ }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Placeholder if no reports
|
|
||||||
// 如果没有报告,显示占位符
|
|
||||||
// Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
|
||||||
// Text("No reports generated yet.", color = colors.secondaryText, style = MaterialTheme.typography.bodyLarge)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ProfileScreen(colors: AppThemes.Colors) {
|
|
||||||
var nickname by remember { mutableStateOf("grtsinry43") } // 记住用户昵称
|
|
||||||
var email by remember { mutableStateOf("grtsinry43@outlook.com") } // 记住用户邮箱 (占位符)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(8.dp)
|
|
||||||
.verticalScroll(rememberScrollState()), // 添加垂直滚动
|
|
||||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"User Profile", // 用户个人资料
|
|
||||||
style = MaterialTheme.typography.headlineSmall.copy(
|
|
||||||
color = colors.onBackground,
|
|
||||||
fontWeight = FontWeight.Bold // 标题加粗
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Profile Details Card
|
|
||||||
// 个人资料详情卡片
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally, // 水平居中
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp) // 垂直间距
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.AccountCircle, // 用户头像图标
|
|
||||||
contentDescription = "User Avatar", // 内容描述
|
|
||||||
tint = colors.accent, // 图标颜色
|
|
||||||
modifier = Modifier.size(100.dp) // 图标大小
|
|
||||||
)
|
|
||||||
// TODO: Add option to change avatar // 添加更换头像的选项
|
|
||||||
|
|
||||||
OutlinedTextField( // 昵称输入框
|
|
||||||
value = nickname,
|
|
||||||
onValueChange = { nickname = it },
|
|
||||||
label = { Text("Nickname") }, // 标签:昵称
|
|
||||||
singleLine = true, // 单行输入
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
colors = OutlinedTextFieldDefaults.colors( // 自定义输入框颜色
|
|
||||||
focusedBorderColor = colors.accent,
|
|
||||||
unfocusedBorderColor = colors.border,
|
|
||||||
focusedLabelColor = colors.accent,
|
|
||||||
cursorColor = colors.accent
|
|
||||||
)
|
|
||||||
)
|
|
||||||
OutlinedTextField( // 邮箱输入框
|
|
||||||
value = email,
|
|
||||||
onValueChange = { email = it },
|
|
||||||
label = { Text("Email") }, // 标签:邮箱
|
|
||||||
singleLine = true,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
colors = OutlinedTextFieldDefaults.colors(
|
|
||||||
focusedBorderColor = colors.accent,
|
|
||||||
unfocusedBorderColor = colors.border,
|
|
||||||
focusedLabelColor = colors.accent,
|
|
||||||
cursorColor = colors.accent
|
|
||||||
)
|
|
||||||
)
|
|
||||||
StyledButton( // 保存更改按钮
|
|
||||||
icon = Icons.Default.Save, // 保存图标
|
|
||||||
text = "Save Changes", // 保存更改
|
|
||||||
onClick = { /* TODO: Save profile changes */ }, // 保存个人资料更改
|
|
||||||
colors = colors,
|
|
||||||
modifier = Modifier.fillMaxWidth(0.6f)
|
|
||||||
.align(Alignment.CenterHorizontally) // 按钮宽度为父容器的60%,并居中
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overall Statistics Card
|
|
||||||
// 总体统计数据卡片
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Overall Statistics", // 总体统计
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
SimpleListItem(
|
|
||||||
icon = Icons.Filled.Timer,
|
|
||||||
text = "Total Time Tracked: 1250 hours",
|
|
||||||
colors = colors
|
|
||||||
) // 总追踪时间
|
|
||||||
SimpleListItem(
|
|
||||||
icon = Icons.Filled.CheckCircleOutline,
|
|
||||||
text = "Goals Met Streak: 15 days",
|
|
||||||
colors = colors
|
|
||||||
) // 目标达成连胜天数
|
|
||||||
SimpleListItem(
|
|
||||||
icon = Icons.Filled.EventAvailable,
|
|
||||||
text = "Joined: January 1, 2024",
|
|
||||||
colors = colors
|
|
||||||
) // 加入日期
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account Actions
|
|
||||||
// 账户操作卡片
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Account Actions", // 账户操作
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
StyledButton( // 更改密码按钮
|
|
||||||
icon = Icons.Default.LockReset, // 重置锁定图标
|
|
||||||
text = "Change Password", // 更改密码
|
|
||||||
onClick = { /* TODO */ },
|
|
||||||
colors = colors,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
StyledButton( // 删除账户按钮
|
|
||||||
icon = Icons.Default.DeleteForever, // 永久删除图标
|
|
||||||
text = "Delete Account", // 删除账户
|
|
||||||
onClick = { /* TODO: Show confirmation dialog */ }, // 显示确认对话框
|
|
||||||
colors = AppThemes.Colors( // 为删除按钮使用警示性颜色主题
|
|
||||||
background = colors.background,
|
|
||||||
surface = colors.surface,
|
|
||||||
onSurface = colors.onSurface,
|
|
||||||
onBackground = colors.onBackground,
|
|
||||||
accent = Color.Red.copy(alpha = 0.7f), // 红色强调色
|
|
||||||
accentVariant = Color.Red,
|
|
||||||
border = colors.border,
|
|
||||||
secondaryText = colors.secondaryText,
|
|
||||||
onAccent = Color.White
|
|
||||||
),
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsScreen(
|
|
||||||
colors: AppThemes.Colors, // 颜色主题
|
|
||||||
isDarkTheme: Boolean, // 当前是否为暗色主题
|
|
||||||
onThemeChange: (Boolean) -> Unit // 主题更改回调
|
|
||||||
) {
|
|
||||||
var autoBackupEnabled by remember { mutableStateOf(true) } // 自动备份是否启用
|
|
||||||
var notificationsEnabled by remember { mutableStateOf(true) } // 通知是否启用
|
|
||||||
var selectedTrackingApps by remember { mutableStateOf("All Apps") } // 选中的追踪应用 (示例状态)
|
|
||||||
var trackingSensitivity by remember { mutableStateOf("Medium") } // 追踪灵敏度 (示例状态)
|
|
||||||
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(8.dp)
|
|
||||||
.verticalScroll(rememberScrollState()), // 添加垂直滚动,因为设置项可能很多
|
|
||||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Application Settings", // 应用设置
|
|
||||||
style = MaterialTheme.typography.headlineSmall.copy(
|
|
||||||
color = colors.onBackground,
|
|
||||||
fontWeight = FontWeight.Bold // 标题加粗
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// General Settings
|
|
||||||
// 常规设置卡片
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp) // 设置项之间的紧凑间距
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"General", // 常规
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
),
|
|
||||||
modifier = Modifier.padding(bottom = 8.dp) // 组标题下方间距
|
|
||||||
)
|
|
||||||
SettingItem( // 暗色主题切换
|
|
||||||
title = "Dark Theme", // 暗色主题
|
|
||||||
subtitle = if (isDarkTheme) "Enabled" else "Disabled", // 已启用/已禁用
|
|
||||||
icon = Icons.Default.Brightness6, // 亮度图标
|
|
||||||
colors = colors,
|
|
||||||
showSwitch = true, // 显示切换开关
|
|
||||||
switchChecked = isDarkTheme, // 开关状态
|
|
||||||
onSwitchChange = onThemeChange // 开关切换回调
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f)) // 分隔线
|
|
||||||
SettingItem( // 数据存储位置
|
|
||||||
title = "Data Storage Location", // 数据存储位置
|
|
||||||
subtitle = "/Users/grtsinry43/Documents/ActivityAnalyzer", // 示例路径
|
|
||||||
icon = Icons.Default.FolderOpen, // 打开文件夹图标
|
|
||||||
colors = colors,
|
|
||||||
onClick = { /* TODO: Open file dialog or path editor */ } // 打开文件对话框或路径编辑器
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
SettingItem( // 自动备份
|
|
||||||
title = "Auto Backup", // 自动备份
|
|
||||||
subtitle = if (autoBackupEnabled) "Daily at 2:00 AM" else "Disabled", // 每日凌晨2点/已禁用
|
|
||||||
icon = Icons.Default.SaveAlt, // 保存图标
|
|
||||||
colors = colors,
|
|
||||||
showSwitch = true,
|
|
||||||
switchChecked = autoBackupEnabled,
|
|
||||||
onSwitchChange = { autoBackupEnabled = it }
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
SettingItem( // 云同步
|
|
||||||
title = "Cloud Sync", // 云同步
|
|
||||||
subtitle = "Not Connected", // 未连接 (占位符)
|
|
||||||
icon = Icons.Default.CloudQueue, // 云队列图标
|
|
||||||
colors = colors,
|
|
||||||
onClick = { /* TODO: Cloud sync setup */ } // 云同步设置
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
SettingItem( // 导出数据
|
|
||||||
title = "Export Data", // 导出数据
|
|
||||||
subtitle = "Export your activity data (CSV, JSON)", // 导出活动数据 (CSV, JSON)
|
|
||||||
icon = Icons.Default.Output, // 输出图标
|
|
||||||
colors = colors,
|
|
||||||
onClick = { /* TODO: Data export options */ } // 数据导出选项
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tracking Settings
|
|
||||||
// 追踪设置卡片
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Tracking", // 追踪
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
),
|
|
||||||
modifier = Modifier.padding(bottom = 8.dp)
|
|
||||||
)
|
|
||||||
SettingItem( // 要追踪的应用
|
|
||||||
title = "Apps to Track", // 要追踪的应用
|
|
||||||
subtitle = selectedTrackingApps, // 当前选中的应用
|
|
||||||
icon = Icons.Default.AppBlocking, // 应用阻止图标 (或类似)
|
|
||||||
colors = colors,
|
|
||||||
onClick = { /* TODO: Open app selection dialog */ } // 打开应用选择对话框
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
SettingItem( // 追踪灵敏度
|
|
||||||
title = "Tracking Sensitivity", // 追踪灵敏度
|
|
||||||
subtitle = "Ignore app opens shorter than: $trackingSensitivity", // 忽略短于...的应用打开 (示例)
|
|
||||||
icon = Icons.Default.Tune, // 调整图标
|
|
||||||
colors = colors,
|
|
||||||
onClick = { /* TODO: Open sensitivity options */ } // 打开灵敏度选项
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Notification Settings
|
|
||||||
// 通知设置卡片
|
|
||||||
StyledCard(colors = colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Notifications", // 通知
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
),
|
|
||||||
modifier = Modifier.padding(bottom = 8.dp)
|
|
||||||
)
|
|
||||||
SettingItem( // 屏幕时间限制通知
|
|
||||||
title = "Screen Time Limits", // 屏幕时间限制
|
|
||||||
subtitle = "Notify when daily/app limits exceeded", // 超出每日/应用限制时通知
|
|
||||||
icon = Icons.Default.NotificationsActive, // 活动通知图标
|
|
||||||
colors = colors,
|
|
||||||
showSwitch = true,
|
|
||||||
switchChecked = notificationsEnabled, // 假设此开关控制所有通知
|
|
||||||
onSwitchChange = { notificationsEnabled = it }
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
SettingItem( // 休息提醒
|
|
||||||
title = "Break Reminders", // 休息提醒
|
|
||||||
subtitle = "Get reminded to take breaks", // 获取休息提醒
|
|
||||||
icon = Icons.Default.SelfImprovement, // 自我提升/休息图标
|
|
||||||
colors = colors,
|
|
||||||
onClick = { /* TODO: Configure break reminders */ } // 配置休息提醒
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
SettingItem( // 每周总结通知
|
|
||||||
title = "Weekly Summary Notification", // 每周总结通知
|
|
||||||
subtitle = "Receive a summary every Monday", // 每周一接收总结
|
|
||||||
icon = Icons.Default.MarkEmailRead, // 已读邮件图标
|
|
||||||
colors = colors,
|
|
||||||
showSwitch = true,
|
|
||||||
switchChecked = true, // 占位符
|
|
||||||
onSwitchChange = { /* TODO */ }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun AboutScreen(colors: AppThemes.Colors) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(16.dp)
|
|
||||||
.verticalScroll(rememberScrollState()), // 添加垂直滚动
|
|
||||||
verticalArrangement = Arrangement.spacedBy(20.dp), // 垂直间距
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally // 水平居中
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Analytics, // 应用图标
|
|
||||||
contentDescription = "App Logo", // 内容描述
|
|
||||||
tint = colors.accent, // 图标颜色
|
|
||||||
modifier = Modifier.size(80.dp) // 图标大小
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
"Activity Analyzer", // 应用名称
|
|
||||||
style = MaterialTheme.typography.headlineMedium.copy(
|
|
||||||
color = colors.onBackground,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
"Version 1.0.0-beta", // 版本号 (从设置页移至此)
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(color = colors.secondaryText)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp)) // 间距
|
|
||||||
|
|
||||||
StyledCard(colors = colors) { // 应用描述卡片
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Your personal screen time companion, helping you understand and manage your digital habits across platforms.", // 应用描述
|
|
||||||
style = MaterialTheme.typography.bodyLarge.copy(color = colors.onSurface),
|
|
||||||
textAlign = TextAlign.Center // 文本居中
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
StyledCard(colors = colors) { // 开发者信息卡片
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Developer", // 开发者
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
),
|
|
||||||
modifier = Modifier.padding(bottom = 8.dp)
|
|
||||||
)
|
|
||||||
InfoItem(icon = Icons.Filled.Person, text = "grtsinry43", colors = colors) // 开发者昵称
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
InfoItem(
|
|
||||||
icon = Icons.Filled.Email,
|
|
||||||
text = "grtsinry43@outlook.com",
|
|
||||||
colors = colors,
|
|
||||||
isLink = true,
|
|
||||||
linkUrl = "mailto:grtsinry43@outlook.com"
|
|
||||||
) // 开发者邮箱 (可点击)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
InfoItem(
|
|
||||||
icon = Icons.Filled.Language,
|
|
||||||
text = "blog.grtsinry43.com",
|
|
||||||
colors = colors,
|
|
||||||
isLink = true,
|
|
||||||
linkUrl = "https://blog.grtsinry43.com"
|
|
||||||
) // 开发者博客 (可点击)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
InfoItem(
|
|
||||||
icon = Icons.Filled.Code,
|
|
||||||
text = "github.com/grtsinry43",
|
|
||||||
colors = colors,
|
|
||||||
isLink = true,
|
|
||||||
linkUrl = "https://github.com/grtsinry43"
|
|
||||||
) // 开发者 GitHub (可点击)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledCard(colors = colors) { // 应用信息卡片
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
"Application Info", // 应用信息
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = colors.onSurface,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
),
|
|
||||||
modifier = Modifier.padding(bottom = 8.dp)
|
|
||||||
)
|
|
||||||
SettingItem( // 检查更新 (复用 SettingItem)
|
|
||||||
title = "Check for Updates", // 检查更新
|
|
||||||
subtitle = "Last checked: Today", // 上次检查时间 (占位符)
|
|
||||||
icon = Icons.Default.SystemUpdateAlt, // 系统更新图标
|
|
||||||
colors = colors,
|
|
||||||
onClick = { /* TODO: Implement update check */ } // 实现更新检查逻辑
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
SettingItem( // 致谢
|
|
||||||
title = "Acknowledgements", // 致谢
|
|
||||||
subtitle = "Libraries and resources used", // 使用的库和资源
|
|
||||||
icon = Icons.Default.FavoriteBorder, // 爱心边框图标
|
|
||||||
colors = colors,
|
|
||||||
onClick = { /* TODO: Show acknowledgements dialog/screen */ } // 显示致谢对话框/屏幕
|
|
||||||
)
|
|
||||||
Divider(color = colors.border.copy(alpha = 0.3f))
|
|
||||||
SettingItem( // 许可证信息
|
|
||||||
title = "License Information", // 许可证信息
|
|
||||||
subtitle = "View application license", // 查看应用许可证
|
|
||||||
icon = Icons.Default.Gavel, // 法槌图标 (代表法律/许可)
|
|
||||||
colors = colors,
|
|
||||||
onClick = { /* TODO: Show license */ } // 显示许可证
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.weight(1f)) // 弹性空间,将版权信息推到底部
|
|
||||||
Text(
|
|
||||||
"© 2025 grtsinry43. All rights reserved.", // 版权信息
|
|
||||||
style = MaterialTheme.typography.bodySmall.copy(color = colors.secondaryText),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
modifier = Modifier.padding(bottom = 8.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,132 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Home
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
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.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NavItem(
|
||||||
|
icon: ImageVector, // 导航项图标
|
||||||
|
text: String, // 导航项文本
|
||||||
|
isSelected: Boolean, // 是否被选中
|
||||||
|
onClick: () -> Unit, // 点击事件回调
|
||||||
|
colors: AppThemes.Colors, // 当前颜色主题
|
||||||
|
isSidebarCollapsed: Boolean // 侧边栏是否折叠
|
||||||
|
) {
|
||||||
|
val interactionSource = remember { MutableInteractionSource() } // 用于自定义点击效果
|
||||||
|
val backgroundColor =
|
||||||
|
if (isSelected) colors.accent.copy(alpha = 0.15f) else Color.Transparent // 选中时背景色高亮
|
||||||
|
val contentColor =
|
||||||
|
if (isSelected) colors.accent else colors.onSurface.copy(alpha = 0.8f) // 选中时内容颜色使用强调色
|
||||||
|
|
||||||
|
Row( // 使用 Row 布局导航项
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth() // 填充宽度
|
||||||
|
.height(if (isSidebarCollapsed) 50.dp else 44.dp) // 根据折叠状态调整高度
|
||||||
|
.clip(RoundedCornerShape(8.dp)) // 圆角
|
||||||
|
.background(backgroundColor) // 背景色
|
||||||
|
.clickable( // 设置点击事件
|
||||||
|
onClick = onClick,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
indication = null // 不使用默认的点击涟漪效果,依赖背景色变化
|
||||||
|
)
|
||||||
|
.padding(horizontal = if (isSidebarCollapsed) 0.dp else 12.dp), // 折叠时水平内边距为0,使图标居中
|
||||||
|
verticalAlignment = Alignment.CenterVertically, // 垂直居中对齐
|
||||||
|
horizontalArrangement = if (isSidebarCollapsed) Arrangement.Center else Arrangement.Start // 折叠时水平居中,否则从左开始
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = text.ifEmpty { null }, // 如果文本为空,则内容描述为null
|
||||||
|
tint = contentColor, // 图标颜色
|
||||||
|
modifier = Modifier.size(if (isSidebarCollapsed) 28.dp else 22.dp) // 根据折叠状态调整图标大小
|
||||||
|
)
|
||||||
|
if (!isSidebarCollapsed) { // 如果侧边栏未折叠,则显示文本
|
||||||
|
Spacer(modifier = Modifier.width(12.dp)) // 图标和文本之间的间距
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
color = contentColor, // 文本颜色
|
||||||
|
fontSize = 15.sp, // 字体大小
|
||||||
|
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal // 选中时字体加粗
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun NavItemSelectedPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
NavItem(
|
||||||
|
icon = Icons.Default.Home,
|
||||||
|
text = "Home",
|
||||||
|
isSelected = true,
|
||||||
|
onClick = {},
|
||||||
|
colors = AppThemes.LightThemeColors,
|
||||||
|
isSidebarCollapsed = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun NavItemUnselectedPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
NavItem(
|
||||||
|
icon = Icons.Default.Home,
|
||||||
|
text = "Home",
|
||||||
|
isSelected = false,
|
||||||
|
onClick = {},
|
||||||
|
colors = AppThemes.LightThemeColors,
|
||||||
|
isSidebarCollapsed = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun NavItemSelectedCollapsedPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
NavItem(
|
||||||
|
icon = Icons.Default.Home,
|
||||||
|
text = "Home", // Text won't be visible
|
||||||
|
isSelected = true,
|
||||||
|
onClick = {},
|
||||||
|
colors = AppThemes.LightThemeColors,
|
||||||
|
isSidebarCollapsed = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun NavItemDarkSelectedPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
NavItem(
|
||||||
|
icon = Icons.Default.Home,
|
||||||
|
text = "Home",
|
||||||
|
isSelected = true,
|
||||||
|
onClick = {},
|
||||||
|
colors = AppThemes.DarkThemeColors,
|
||||||
|
isSidebarCollapsed = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,173 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.InfoItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.SettingItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledCard
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AboutScreen(colors: AppThemes.Colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp)
|
||||||
|
.verticalScroll(rememberScrollState()), // 允许垂直滚动
|
||||||
|
verticalArrangement = Arrangement.spacedBy(20.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally // 内容水平居中
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Analytics, // 应用Logo图标 (示例)
|
||||||
|
contentDescription = "App Logo", // 内容描述
|
||||||
|
tint = colors.accent, // 图标颜色
|
||||||
|
modifier = Modifier.size(80.dp) // 图标大小
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"Activity Analyzer", // 应用名称
|
||||||
|
style = MaterialTheme.typography.headlineMedium.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"Version 1.0.0-beta", // 应用版本号
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(color = colors.secondaryText)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp)) // 间距
|
||||||
|
|
||||||
|
// App Description Card
|
||||||
|
// 应用描述卡片
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Your personal screen time companion, helping you understand and manage your digital habits across platforms.", // 应用描述
|
||||||
|
style = MaterialTheme.typography.bodyLarge.copy(color = colors.onSurface),
|
||||||
|
textAlign = TextAlign.Center // 文本居中
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Developer Info Card
|
||||||
|
// 开发者信息卡片
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Developer", // 开发者
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
InfoItem(icon = Icons.Filled.Person, text = "grtsinry43", colors = colors) // 开发者名称
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
InfoItem(
|
||||||
|
icon = Icons.Filled.Email,
|
||||||
|
text = "grtsinry43@outlook.com", // 开发者邮箱
|
||||||
|
colors = colors,
|
||||||
|
isLink = true, // 可点击链接
|
||||||
|
linkUrl = "mailto:grtsinry43@outlook.com" // 邮箱链接
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
InfoItem(
|
||||||
|
icon = Icons.Filled.Language, // 网站/博客图标
|
||||||
|
text = "blog.grtsinry43.com", // 网站/博客地址
|
||||||
|
colors = colors,
|
||||||
|
isLink = true,
|
||||||
|
linkUrl = "https://blog.grtsinry43.com" // 网站链接
|
||||||
|
) // 个人网站/博客 (可点击)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
InfoItem(
|
||||||
|
icon = Icons.Filled.Code, // Github图标
|
||||||
|
text = "github.com/grtsinry43", // Github用户名
|
||||||
|
colors = colors,
|
||||||
|
isLink = true,
|
||||||
|
linkUrl = "https://github.com/grtsinry43" // Github链接
|
||||||
|
) // GitHub (可点击)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Application Info Card
|
||||||
|
// 应用信息卡片
|
||||||
|
StyledCard(colors = colors) { // 应用信息卡片
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Application Info", // 应用信息
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
SettingItem( // 检查更新 (复用 SettingItem)
|
||||||
|
title = "Check for Updates", // 检查更新
|
||||||
|
subtitle = "Last checked: Today", // 上次检查时间 (占位符)
|
||||||
|
icon = Icons.Default.SystemUpdateAlt, // 更新图标
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO: Implement update check */ } // 实现更新检查逻辑
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
SettingItem( // 致谢
|
||||||
|
title = "Acknowledgements", // 致谢
|
||||||
|
subtitle = "Libraries and resources used", // 使用的库和资源
|
||||||
|
icon = Icons.Default.FavoriteBorder, // 爱心图标 (代表感谢)
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO: Show acknowledgements dialog/screen */ } // 显示致谢对话框/屏幕
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
SettingItem( // 许可证信息
|
||||||
|
title = "License Information", // 许可证信息
|
||||||
|
subtitle = "View application license", // 查看应用许可证
|
||||||
|
icon = Icons.Default.Gavel, // 法槌图标 (代表法律/许可)
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO: Show license */ } // 显示许可证
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.weight(1f)) // 弹性空间,将版权信息推到底部
|
||||||
|
Text(
|
||||||
|
"© 2025 grtsinry43. All rights reserved.", // 版权信息
|
||||||
|
style = MaterialTheme.typography.bodySmall.copy(color = colors.secondaryText),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun AboutScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
AboutScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun AboutScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
AboutScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,222 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.ChartPlaceholder
|
||||||
|
import com.grtsinry43.activityanalyzer.components.MetricCard
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledButton
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledCard
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AnalyticsScreen(colors: AppThemes.Colors) {
|
||||||
|
var selectedTimeRange by remember { mutableStateOf("Last 7 Days") } // 默认选中的时间范围
|
||||||
|
val timeRanges = // 可选的时间范围
|
||||||
|
listOf("Today", "Yesterday", "Last 7 Days", "Last 30 Days", "Custom Range")
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(8.dp)
|
||||||
|
.verticalScroll(rememberScrollState()), // 允许垂直滚动
|
||||||
|
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Screen Time Analytics", // 屏幕时间分析
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold // 加粗
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Time Range Filter
|
||||||
|
// 时间范围筛选器
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Time Range:",
|
||||||
|
style = MaterialTheme.typography.titleSmall.copy(color = colors.onBackground)
|
||||||
|
) // 时间范围标签
|
||||||
|
var expanded by remember { mutableStateOf(false) } // 下拉菜单是否展开
|
||||||
|
Box {
|
||||||
|
OutlinedButton(
|
||||||
|
onClick = { expanded = true },
|
||||||
|
shape = RoundedCornerShape(8.dp) // 圆角按钮
|
||||||
|
) { // 点击展开下拉菜单
|
||||||
|
Text(selectedTimeRange, color = colors.accent) // 显示选中的时间范围
|
||||||
|
Icon(
|
||||||
|
Icons.Default.ArrowDropDown,
|
||||||
|
contentDescription = "Select time range", // 内容描述
|
||||||
|
tint = colors.accent
|
||||||
|
) // 下拉箭头图标
|
||||||
|
}
|
||||||
|
DropdownMenu( // 下拉菜单内容
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false } // 点击外部关闭下拉菜单
|
||||||
|
) {
|
||||||
|
timeRanges.forEach { range ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(range) },
|
||||||
|
onClick = {
|
||||||
|
selectedTimeRange = range // 更新选中的时间范围
|
||||||
|
expanded = false // 关闭下拉菜单
|
||||||
|
// TODO: Update analytics data based on range // 根据选中的时间范围更新分析数据
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key Metrics Cards
|
||||||
|
// 关键指标卡片
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
|
MetricCard(
|
||||||
|
title = "Total Screen Time",
|
||||||
|
value = "25h 10m", // 示例数据
|
||||||
|
icon = Icons.Default.Smartphone,
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) // 总屏幕时间
|
||||||
|
MetricCard(
|
||||||
|
title = "Avg Daily Time",
|
||||||
|
value = "3h 35m", // 示例数据
|
||||||
|
icon = Icons.Default.AvTimer,
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) // 平均每日时间
|
||||||
|
}
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
|
MetricCard(
|
||||||
|
title = "Most Used App",
|
||||||
|
value = "App A (8h)", // 示例数据
|
||||||
|
icon = Icons.Default.StarOutline,
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) // 最常用应用
|
||||||
|
MetricCard(
|
||||||
|
title = "Pickups",
|
||||||
|
value = "75 today", // 示例数据
|
||||||
|
icon = Icons.Default.TouchApp,
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) // 拿起次数
|
||||||
|
}
|
||||||
|
|
||||||
|
// Charts Section
|
||||||
|
// 图表部分
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Usage Patterns", // 使用模式
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// Placeholder for Daily/Weekly Screen Time Bar Chart
|
||||||
|
// 每日/每周屏幕时间柱状图占位符
|
||||||
|
ChartPlaceholder(
|
||||||
|
text = "Daily/Weekly Screen Time (Bar Chart)",
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.fillMaxWidth().height(200.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
// Placeholder for App Usage Distribution Pie Chart
|
||||||
|
// 应用使用分布饼图占位符
|
||||||
|
ChartPlaceholder(
|
||||||
|
text = "App Usage Distribution (Pie Chart)",
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.fillMaxWidth().height(200.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analysis Tools
|
||||||
|
// 分析工具
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Analysis Tools", // 分析工具
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
icon = Icons.Default.PieChartOutline, // 应用细分图标
|
||||||
|
text = "App Breakdown", // 应用细分
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
icon = Icons.Default.AccessTime, // 时段分析图标
|
||||||
|
text = "Time of Day", // 时段分析
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
icon = Icons.Default.TrackChanges, // 设定目标图标
|
||||||
|
text = "Usage Goals", // 设定目标
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
icon = Icons.Default.CompareArrows, // 比较时段图标
|
||||||
|
text = "Compare Periods", // 比较时段
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun AnalyticsScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
AnalyticsScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun AnalyticsScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
AnalyticsScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,184 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.ActivityItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.SimpleListItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledButton
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledCard
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HomeScreen(colors: AppThemes.Colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(8.dp)
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||||
|
) {
|
||||||
|
SelectionContainer {
|
||||||
|
Text(
|
||||||
|
text = "Welcome Back, grtsinry43!",
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overview of today's screen time
|
||||||
|
// 今日屏幕时间概览
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Today's Screen Time", // 今日屏幕时间
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "3h 45m", // 示例数据
|
||||||
|
style = MaterialTheme.typography.displaySmall.copy(
|
||||||
|
color = colors.accent,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
),
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "You're on track with your daily goal!", // 示例消息
|
||||||
|
style = MaterialTheme.typography.bodyMedium.copy(color = colors.secondaryText),
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick Glance: Top Apps Today
|
||||||
|
// 今日热门应用速览
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Quick Glance: Top Apps Today", // 今日热门应用
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.SmartDisplay, // 示例图标
|
||||||
|
text = "App A: 1h 15m", // 示例数据
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.PhotoCamera, // 示例图标
|
||||||
|
text = "App B: 45m", // 示例数据
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.Chat, // 示例图标
|
||||||
|
text = "App C: 30m", // 示例数据
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick actions
|
||||||
|
// 快捷操作
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Quick Actions", // 快捷操作
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
icon = Icons.Default.HourglassTop, // 专注时段图标
|
||||||
|
text = "Focus Session", // 专注时段
|
||||||
|
onClick = { /* TODO: Start focus session */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
icon = Icons.Default.CalendarViewWeek, // 每周报告图标
|
||||||
|
text = "Weekly Report", // 每周报告
|
||||||
|
onClick = { /* TODO: Navigate to weekly report */ },
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recent Alerts/Insights
|
||||||
|
// 最近提醒/洞察 (例如:与上周比较)
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Recent Insights", // 最近洞察
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ActivityItem(
|
||||||
|
title = "You've exceeded your daily goal for App X.", // 您已超出App X的每日目标
|
||||||
|
time = "Today, 2:30 PM", // 时间示例
|
||||||
|
icon = Icons.Default.WarningAmber, // 警告图标
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
ActivityItem(
|
||||||
|
title = "Screen time was 20% higher yesterday.", // 昨天的屏幕时间增加了20%
|
||||||
|
time = "Insight from yesterday", // 来自昨天的洞察
|
||||||
|
icon = Icons.Default.TrendingUp, // 上升趋势图标
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun HomeScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
HomeScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun HomeScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
HomeScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,183 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.SimpleListItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledButton
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledCard
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ProfileScreen(colors: AppThemes.Colors) {
|
||||||
|
var nickname by remember { mutableStateOf("grtsinry43") } // 用户昵称
|
||||||
|
var email by remember { mutableStateOf("grtsinry43@outlook.com") } // 用户邮箱 (占位符)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(8.dp)
|
||||||
|
.verticalScroll(rememberScrollState()), // 允许垂直滚动
|
||||||
|
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"User Profile", // 个人资料
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold // 加粗
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Profile Details Card
|
||||||
|
// 个人资料详情卡片
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally, // 水平居中
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp) // 子项间距
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.AccountCircle, // 用户头像图标
|
||||||
|
contentDescription = "User Avatar", // 内容描述
|
||||||
|
tint = colors.accent, // 图标颜色
|
||||||
|
modifier = Modifier.size(100.dp) // 图标大小
|
||||||
|
)
|
||||||
|
// TODO: Add option to change avatar // 添加更换头像的选项
|
||||||
|
|
||||||
|
OutlinedTextField( // 昵称输入框
|
||||||
|
value = nickname,
|
||||||
|
onValueChange = { nickname = it },
|
||||||
|
label = { Text("Nickname") }, // 标签:昵称
|
||||||
|
singleLine = true, // 单行输入
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
colors = OutlinedTextFieldDefaults.colors( // 自定义输入框颜色
|
||||||
|
focusedBorderColor = colors.accent,
|
||||||
|
unfocusedBorderColor = colors.border,
|
||||||
|
focusedLabelColor = colors.accent,
|
||||||
|
cursorColor = colors.accent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
OutlinedTextField( // 邮箱输入框
|
||||||
|
value = email,
|
||||||
|
onValueChange = { email = it },
|
||||||
|
label = { Text("Email") }, // 标签:邮箱
|
||||||
|
singleLine = true,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
colors = OutlinedTextFieldDefaults.colors(
|
||||||
|
focusedBorderColor = colors.accent,
|
||||||
|
unfocusedBorderColor = colors.border,
|
||||||
|
focusedLabelColor = colors.accent,
|
||||||
|
cursorColor = colors.accent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
StyledButton( // 保存更改按钮
|
||||||
|
icon = Icons.Default.Save, // 保存图标
|
||||||
|
text = "Save Changes", // 保存更改
|
||||||
|
onClick = { /* TODO: Save profile changes */ }, // 保存个人资料更改
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.fillMaxWidth(0.6f)
|
||||||
|
.align(Alignment.CenterHorizontally) // 按钮宽度为父容器的60%,并居中
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overall Statistics Card
|
||||||
|
// 总体统计数据卡片
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Overall Statistics", // 总体统计
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.Timer, // 计时器图标
|
||||||
|
text = "Total Time Tracked: 1250 hours", // 总追踪时间
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.CheckCircleOutline, // 勾选图标
|
||||||
|
text = "Goals Met Streak: 15 days", // 目标达成连胜天数
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
SimpleListItem(
|
||||||
|
icon = Icons.Filled.EventAvailable, // 日历图标
|
||||||
|
text = "Joined: January 1, 2024", // 加入日期
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account Actions Card
|
||||||
|
// 账户操作卡片
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Account Actions", // 账户操作
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
StyledButton( // 更改密码按钮
|
||||||
|
icon = Icons.Default.LockReset, // 密码重置图标
|
||||||
|
text = "Change Password", // 更改密码
|
||||||
|
onClick = { /* TODO */ },
|
||||||
|
colors = colors,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
StyledButton( // 删除账户按钮
|
||||||
|
icon = Icons.Default.DeleteForever, // 永久删除图标
|
||||||
|
text = "Delete Account", // 删除账户
|
||||||
|
onClick = { /* TODO: Show confirmation dialog */ }, // 显示确认对话框
|
||||||
|
colors = AppThemes.Colors( // 删除按钮使用警示性颜色主题
|
||||||
|
background = colors.background,
|
||||||
|
surface = colors.surface,
|
||||||
|
onSurface = colors.onSurface,
|
||||||
|
onBackground = colors.onBackground,
|
||||||
|
accent = Color.Red.copy(alpha = 0.7f), // 红色强调色
|
||||||
|
accentVariant = Color.Red,
|
||||||
|
border = colors.border,
|
||||||
|
secondaryText = colors.secondaryText,
|
||||||
|
onAccent = Color.White
|
||||||
|
),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ProfileScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ProfileScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ProfileScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ProfileScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,123 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.ReportItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledButton
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledCard
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ReportsScreen(colors: AppThemes.Colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(8.dp)
|
||||||
|
.verticalScroll(rememberScrollState()), // 允许垂直滚动
|
||||||
|
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween, // 两端对齐
|
||||||
|
verticalAlignment = Alignment.CenterVertically // 垂直居中
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Screen Time Reports", // 屏幕时间报告
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold // 加粗
|
||||||
|
)
|
||||||
|
)
|
||||||
|
StyledButton(
|
||||||
|
icon = Icons.Default.Addchart, // 生成报告图标
|
||||||
|
text = "Generate New Report", // 生成新报告
|
||||||
|
onClick = { /* TODO: Open report generation dialog */ }, // 打开报告生成对话框
|
||||||
|
colors = colors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generated Reports List
|
||||||
|
// 已生成报告列表
|
||||||
|
StyledCard(colors = colors) { // 报告列表卡片
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp) // 列表项之间的紧凑间距
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Generated Reports", // 已生成报告
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp) // 标题下方间距
|
||||||
|
)
|
||||||
|
ReportItem( // 报告项示例1
|
||||||
|
title = "Weekly Summary - May 5-11, 2025", // 每周总结
|
||||||
|
period = "Generated: May 12, 2025", // 生成日期
|
||||||
|
icon = Icons.Default.CalendarToday, // 日历图标
|
||||||
|
colors = colors,
|
||||||
|
onDownload = { /* TODO */ }, // 下载回调
|
||||||
|
onView = { /* TODO */ } // 查看回调
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f)) // 分隔线
|
||||||
|
ReportItem( // 报告项示例2
|
||||||
|
title = "Monthly App Usage - April 2025", // 每月应用使用情况
|
||||||
|
period = "Generated: May 1, 2025", // 生成日期
|
||||||
|
icon = Icons.Default.PieChart, // 饼图图标
|
||||||
|
colors = colors,
|
||||||
|
onDownload = { /* TODO */ },
|
||||||
|
onView = { /* TODO */ }
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
ReportItem( // 报告项示例3
|
||||||
|
title = "Q1 Device Pickup Analysis", // Q1设备拿起分析
|
||||||
|
period = "Generated: April 5, 2025", // 生成日期
|
||||||
|
icon = Icons.Default.TouchApp, // 触摸应用图标
|
||||||
|
colors = colors,
|
||||||
|
onDownload = { /* TODO */ },
|
||||||
|
onView = { /* TODO */ }
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
ReportItem( // 报告项示例4
|
||||||
|
title = "Focus Session Report - Project X", // 专注时段报告 - 项目X
|
||||||
|
period = "Generated: May 10, 2025", // 生成日期
|
||||||
|
icon = Icons.Default.HourglassEmpty, // 沙漏图标
|
||||||
|
colors = colors,
|
||||||
|
onDownload = { /* TODO */ },
|
||||||
|
onView = { /* TODO */ }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Placeholder if no reports
|
||||||
|
// 如果没有报告,显示占位符
|
||||||
|
// Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
|
// Text("No reports generated yet.", color = colors.secondaryText, style = MaterialTheme.typography.bodyLarge)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ReportsScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ReportsScreen(colors = AppThemes.LightThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ReportsScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
ReportsScreen(colors = AppThemes.DarkThemeColors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,207 @@
|
|||||||
|
package com.grtsinry43.activityanalyzer.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.grtsinry43.activityanalyzer.components.SettingItem
|
||||||
|
import com.grtsinry43.activityanalyzer.components.StyledCard
|
||||||
|
import com.grtsinry43.activityanalyzer.theme.AppThemes
|
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingsScreen(
|
||||||
|
colors: AppThemes.Colors, // 当前颜色主题
|
||||||
|
isDarkTheme: Boolean, // 当前是否为暗色主题
|
||||||
|
onThemeChange: (Boolean) -> Unit // 主题更改回调
|
||||||
|
) {
|
||||||
|
var autoBackupEnabled by remember { mutableStateOf(true) } // 自动备份是否启用
|
||||||
|
var notificationsEnabled by remember { mutableStateOf(true) } // 通知是否启用
|
||||||
|
var selectedTrackingApps by remember { mutableStateOf("All Apps") } // 要追踪的应用 (示例状态)
|
||||||
|
var trackingSensitivity by remember { mutableStateOf("Medium") } // 追踪灵敏度 (示例状态)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(8.dp)
|
||||||
|
.verticalScroll(rememberScrollState()), // 允许垂直滚动,因为设置项可能很多
|
||||||
|
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Application Settings", // 应用设置
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
color = colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold // 加粗
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// General Settings Card
|
||||||
|
// 通用设置卡片
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp) // 列表项之间的紧凑间距
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"General", // 通用
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp) // 标题下方间距
|
||||||
|
)
|
||||||
|
SettingItem( // 暗色主题切换
|
||||||
|
title = "Dark Theme", // 暗色主题
|
||||||
|
subtitle = if (isDarkTheme) "Enabled" else "Disabled", // 已启用/已禁用
|
||||||
|
icon = Icons.Default.Brightness6, // 主题图标
|
||||||
|
colors = colors,
|
||||||
|
showSwitch = true, // 显示切换开关
|
||||||
|
switchChecked = isDarkTheme, // 开关状态
|
||||||
|
onSwitchChange = onThemeChange // 开关切换回调
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f)) // 分隔线
|
||||||
|
SettingItem( // 数据存储位置
|
||||||
|
title = "Data Storage Location", // 数据存储位置
|
||||||
|
subtitle = "/Users/grtsinry43/Documents/ActivityAnalyzer", // 示例路径
|
||||||
|
icon = Icons.Default.FolderOpen, // 打开文件夹图标
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO: Open file dialog or path editor */ } // 打开文件对话框或路径编辑器
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
SettingItem( // 自动备份
|
||||||
|
title = "Auto Backup", // 自动备份
|
||||||
|
subtitle = if (autoBackupEnabled) "Daily at 2:00 AM" else "Disabled", // 每日凌晨2点/已禁用
|
||||||
|
icon = Icons.Default.SaveAlt, // 保存图标
|
||||||
|
colors = colors,
|
||||||
|
showSwitch = true,
|
||||||
|
switchChecked = autoBackupEnabled,
|
||||||
|
onSwitchChange = { autoBackupEnabled = it }
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
SettingItem( // 云同步
|
||||||
|
title = "Cloud Sync", // 云同步
|
||||||
|
subtitle = "Not Connected", // 未连接 (占位符)
|
||||||
|
icon = Icons.Default.CloudQueue, // 云队列图标
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO: Cloud sync setup */ } // 云同步设置
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
SettingItem( // 导出数据
|
||||||
|
title = "Export Data", // 导出数据
|
||||||
|
subtitle = "Export your activity data (CSV, JSON)", // 导出活动数据 (CSV, JSON)
|
||||||
|
icon = Icons.Default.Output, // 导出图标
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO: Data export options */ } // 数据导出选项
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracking Settings Card
|
||||||
|
// 追踪设置卡片
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Tracking", // 追踪
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
SettingItem( // 要追踪的应用
|
||||||
|
title = "Apps to Track", // 要追踪的应用
|
||||||
|
subtitle = selectedTrackingApps, // 当前选中的应用
|
||||||
|
icon = Icons.Default.AppBlocking, // 应用阻止图标 (或类似)
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO: Open app selection dialog */ } // 打开应用选择对话框
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
SettingItem( // 追踪灵敏度
|
||||||
|
title = "Tracking Sensitivity", // 追踪灵敏度
|
||||||
|
subtitle = "Ignore app opens shorter than: $trackingSensitivity", // 忽略短于...的应用打开 (示例)
|
||||||
|
icon = Icons.Default.Tune, // 调整图标
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO: Open sensitivity options */ } // 打开灵敏度选项
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notification Settings Card
|
||||||
|
// 通知设置卡片
|
||||||
|
StyledCard(colors = colors) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Notifications", // 通知
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = colors.onSurface,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
SettingItem( // 屏幕时间限制通知
|
||||||
|
title = "Screen Time Limits", // 屏幕时间限制
|
||||||
|
subtitle = "Notify when daily/app limits exceeded", // 当超出每日/应用限制时通知
|
||||||
|
icon = Icons.Default.NotificationsActive, // 活动通知图标
|
||||||
|
colors = colors,
|
||||||
|
showSwitch = true,
|
||||||
|
switchChecked = notificationsEnabled, // 示例状态
|
||||||
|
onSwitchChange = { notificationsEnabled = it }
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
SettingItem( // 休息提醒
|
||||||
|
title = "Break Reminders", // 休息提醒
|
||||||
|
subtitle = "Get reminded to take breaks", // 获取休息提醒
|
||||||
|
icon = Icons.Default.SelfImprovement, // 自我提升图标 (代表休息)
|
||||||
|
colors = colors,
|
||||||
|
onClick = { /* TODO: Configure break reminders */ } // 配置休息提醒
|
||||||
|
)
|
||||||
|
Divider(color = colors.border.copy(alpha = 0.3f))
|
||||||
|
SettingItem( // 每周总结通知
|
||||||
|
title = "Weekly Summary Notification", // 每周总结通知
|
||||||
|
subtitle = "Receive a summary every Monday", // 每周一接收总结
|
||||||
|
icon = Icons.Default.MarkEmailRead, // 已读邮件图标
|
||||||
|
colors = colors,
|
||||||
|
showSwitch = true,
|
||||||
|
switchChecked = true, // 示例状态,默认开启
|
||||||
|
onSwitchChange = { /* TODO */ }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SettingsScreenPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
SettingsScreen(
|
||||||
|
colors = AppThemes.LightThemeColors,
|
||||||
|
isDarkTheme = false,
|
||||||
|
onThemeChange = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SettingsScreenDarkPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
SettingsScreen(
|
||||||
|
colors = AppThemes.DarkThemeColors,
|
||||||
|
isDarkTheme = true,
|
||||||
|
onThemeChange = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user