redesign: modern indigo UI, new app icon, edge-to-edge theme

App icon: deep indigo-to-violet gradient background with white sync arrows;
replaced flat #2196F3 with layered adaptive icon.

Theme: disabled dynamic color; rich indigo/teal/amber Material3 palette;
edge-to-edge with transparent status bar; tighter typography letterSpacing.

HomeScreen: colored left accent bar per status; URL-decoded SAF paths;
relative timestamps (Just now / N min ago / N hr ago); indigo status pills;
FilledTonalButton empty state.

PairDetailScreen: hero StatusBanner with large icon and relative time;
InfoCard as bordered grid with icon backgrounds; colored dot event timeline;
URL-decoded local path display.

SettingsScreen: section headers with primary left bar; AccountCard with
primaryContainer icon backgrounds; Security/About in bordered cards.

Bump version to 1.0.13 (code 14).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 02:31:44 +00:00
parent 3d7a8b5f3d
commit 21d8f0dca2
19 changed files with 589 additions and 191 deletions
@@ -2,8 +2,27 @@ package com.syncflow.ui.theme
import androidx.compose.ui.graphics.Color
val SyncBlue = Color(0xFF2196F3)
val SyncGreen = Color(0xFF4CAF50)
val SyncOrange = Color(0xFFFF9800)
val SyncRed = Color(0xFFF44336)
val SyncPurple = Color(0xFF9C27B0)
// Primary — indigo
val Indigo600 = Color(0xFF4F46E5)
val Indigo900 = Color(0xFF312E81)
val Indigo100 = Color(0xFFE0E7FF)
val Indigo50 = Color(0xFFEEF2FF)
// Secondary — teal
val Teal600 = Color(0xFF0D9488)
val Teal100 = Color(0xFFCCFBF1)
// Tertiary — amber
val Amber500 = Color(0xFFF59E0B)
val Amber100 = Color(0xFFFEF3C7)
// Neutrals
val Slate50 = Color(0xFFF8FAFC)
val Slate100 = Color(0xFFF1F5F9)
val Slate200 = Color(0xFFE2E8F0)
val Slate600 = Color(0xFF475569)
val Slate900 = Color(0xFF0F172A)
// Semantic
val GreenSuccess = Color(0xFF16A34A)
val RedError = Color(0xFFDC2626)
@@ -1,50 +1,77 @@
package com.syncflow.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.core.view.WindowCompat
private val LightColors = lightColorScheme(
primary = SyncBlue,
onPrimary = androidx.compose.ui.graphics.Color.White,
secondary = SyncGreen,
tertiary = SyncPurple,
primary = Indigo600,
onPrimary = Color.White,
primaryContainer = Indigo100,
onPrimaryContainer = Indigo900,
secondary = Teal600,
onSecondary = Color.White,
secondaryContainer = Teal100,
tertiary = Amber500,
tertiaryContainer = Amber100,
background = Slate50,
surface = Color.White,
surfaceVariant = Slate100,
onSurfaceVariant = Slate600,
error = RedError,
errorContainer = Color(0xFFFEE2E2),
outline = Slate200,
)
private val DarkColors = darkColorScheme(
primary = SyncBlue,
secondary = SyncGreen,
tertiary = SyncPurple,
primary = Color(0xFF818CF8),
onPrimary = Indigo900,
primaryContainer = Color(0xFF3730A3),
onPrimaryContainer = Indigo100,
secondary = Color(0xFF2DD4BF),
onSecondary = Color(0xFF003731),
secondaryContainer = Color(0xFF00504A),
tertiary = Amber500,
tertiaryContainer = Color(0xFF92400E),
background = Color(0xFF0F0F1A),
surface = Color(0xFF1A1A2E),
surfaceVariant = Color(0xFF252538),
onSurfaceVariant = Color(0xFF94A3B8),
error = Color(0xFFF87171),
errorContainer = Color(0xFF7F1D1D),
outline = Color(0xFF334155),
)
private val AppTypography = Typography(
titleLarge = TextStyle(fontWeight = FontWeight.Bold, fontSize = 22.sp, letterSpacing = (-0.5).sp),
titleMedium = TextStyle(fontWeight = FontWeight.SemiBold, fontSize = 16.sp, letterSpacing = (-0.25).sp),
titleSmall = TextStyle(fontWeight = FontWeight.SemiBold, fontSize = 14.sp, letterSpacing = 0.sp),
labelMedium = TextStyle(fontWeight = FontWeight.Medium, fontSize = 12.sp, letterSpacing = 0.1.sp),
labelSmall = TextStyle(fontWeight = FontWeight.Medium, fontSize = 11.sp, letterSpacing = 0.1.sp),
)
@Composable
fun SyncFlowTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
content: @Composable () -> Unit,
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val ctx = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(ctx) else dynamicLightColorScheme(ctx)
}
darkTheme -> DarkColors
else -> LightColors
}
val colorScheme = if (darkTheme) DarkColors else LightColors
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.statusBarColor = colorScheme.primary.toArgb()
WindowCompat.setDecorFitsSystemWindows(window, false)
window.statusBarColor = android.graphics.Color.TRANSPARENT
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
}
}
MaterialTheme(colorScheme = colorScheme, typography = Typography(), content = content)
MaterialTheme(colorScheme = colorScheme, typography = AppTypography, content = content)
}