feat: Migrate UI theme system from hardcoded colors to Material3 dynamic theming

- Inject ThemePreferences into MainActivity and apply dynamic theme selection
- Replace all hardcoded color references (DeepNavy, DarkNavy, CyanPrimary, TextPrimary, etc.) with MaterialTheme.colorScheme equivalents throughout AddLinkScreen and LoginScreen
- Update component colors to use Material3 color roles (primary, onBackground, surfaceVariant, outline, etc.)
- Migrate GlassCard, buttons, text fields, switches, and progress
This commit is contained in:
Bruno Charest 2026-02-09 12:56:33 -05:00
parent 80ab3009aa
commit 98f2ef2e7e
17 changed files with 1116 additions and 526 deletions

View File

@ -8,18 +8,25 @@ import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import com.shaarit.presentation.nav.AppNavGraph
import com.shaarit.ui.theme.ShaarItTheme
import com.shaarit.ui.theme.ThemePreferences
import dagger.hilt.android.AndroidEntryPoint
import java.io.BufferedReader
import java.io.InputStreamReader
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject lateinit var themePreferences: ThemePreferences
override fun onCreate(savedInstanceState: Bundle?) {
// Install splash screen before super.onCreate
installSplashScreen()
@ -31,7 +38,8 @@ class MainActivity : ComponentActivity() {
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
ShaarItTheme {
val currentTheme by themePreferences.currentTheme.collectAsState()
ShaarItTheme(appTheme = currentTheme) {
// A surface container using the 'background' color from the theme
val context = LocalContext.current
var shareUrl: String? = null

View File

@ -34,8 +34,7 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import coil.compose.AsyncImage
import com.shaarit.ui.components.*
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Purple
import com.shaarit.ui.theme.Typography
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class, androidx.compose.foundation.ExperimentalFoundationApi::class)
@ -109,37 +108,37 @@ fun AddLinkScreen(
AlertDialog(
onDismissRequest = { viewModel.dismissConflict() },
title = {
Text("Lien déjà existant", fontWeight = FontWeight.Bold, color = TextPrimary)
Text("Lien déjà existant", fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onBackground)
},
text = {
Column {
Text("Un lien avec cette URL existe déjà:", color = TextSecondary)
Text("Un lien avec cette URL existe déjà:", color = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(modifier = Modifier.height(8.dp))
Text(
conflict.existingTitle ?: "Sans titre",
color = CyanPrimary,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Medium
)
Spacer(modifier = Modifier.height(16.dp))
Text(
"Voulez-vous mettre à jour le lien existant?",
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
},
confirmButton = {
TextButton(onClick = { viewModel.forceUpdateExistingLink() }) {
Text("Mettre à jour", color = CyanPrimary)
Text("Mettre à jour", color = MaterialTheme.colorScheme.primary)
}
},
dismissButton = {
TextButton(onClick = { viewModel.dismissConflict() }) {
Text("Annuler", color = TextMuted)
Text("Annuler", color = MaterialTheme.colorScheme.outline)
}
},
containerColor = CardBackground,
titleContentColor = TextPrimary,
textContentColor = TextSecondary
containerColor = MaterialTheme.colorScheme.surfaceVariant,
titleContentColor = MaterialTheme.colorScheme.onBackground,
textContentColor = MaterialTheme.colorScheme.onSurfaceVariant
)
}
@ -147,7 +146,7 @@ fun AddLinkScreen(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(colors = listOf(DeepNavy, DarkNavy))
brush = Brush.verticalGradient(colors = listOf(MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.surface))
)
) {
// Contenu principal avec Scaffold
@ -167,13 +166,13 @@ fun AddLinkScreen(
Icon(
Icons.Default.ArrowBack,
contentDescription = "Retour",
tint = TextPrimary
tint = MaterialTheme.colorScheme.onBackground
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = DeepNavy.copy(alpha = 0.9f),
titleContentColor = TextPrimary
containerColor = MaterialTheme.colorScheme.background.copy(alpha = 0.9f),
titleContentColor = MaterialTheme.colorScheme.onBackground
)
)
},
@ -191,7 +190,7 @@ fun AddLinkScreen(
// Content Type Selection (compact)
GlassCard(
modifier = Modifier.fillMaxWidth(),
glowColor = CyanPrimary
glowColor = MaterialTheme.colorScheme.primary
) {
Row(
modifier = Modifier.fillMaxWidth(),
@ -236,14 +235,14 @@ fun AddLinkScreen(
value = url,
onValueChange = { viewModel.url.value = it },
modifier = Modifier.weight(1f),
placeholder = { Text("https://example.com", color = TextMuted) },
placeholder = { Text("https://example.com", color = MaterialTheme.colorScheme.outline) },
singleLine = true,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
trailingIcon = {
if (isExtractingMetadata) {
CircularProgressIndicator(
modifier = Modifier.size(18.dp),
color = CyanPrimary,
color = MaterialTheme.colorScheme.primary,
strokeWidth = 2.dp
)
}
@ -288,14 +287,14 @@ fun AddLinkScreen(
else -> Icons.Default.Web
},
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = type,
style = MaterialTheme.typography.labelSmall,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -329,7 +328,7 @@ fun AddLinkScreen(
Text(
if (contentTypeSelection == ContentType.NOTE)
"Titre de la note" else "Titre du lien",
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
},
singleLine = true,
@ -365,7 +364,7 @@ fun AddLinkScreen(
Icon(
imageVector = Icons.Default.Description,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(20.dp)
)
Column {
@ -374,13 +373,13 @@ fun AddLinkScreen(
"Contenu" else "Description",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
if (contentTypeSelection == ContentType.NOTE) {
Text(
text = "Markdown supporté",
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
}
}
@ -397,7 +396,7 @@ fun AddLinkScreen(
Icon(
Icons.Default.Edit,
contentDescription = "Éditer",
tint = if (!showMarkdownPreview) CyanPrimary else TextMuted,
tint = if (!showMarkdownPreview) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline,
modifier = Modifier.size(18.dp)
)
}
@ -408,7 +407,7 @@ fun AddLinkScreen(
Icon(
Icons.Default.Preview,
contentDescription = "Aperçu",
tint = if (showMarkdownPreview) CyanPrimary else TextMuted,
tint = if (showMarkdownPreview) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline,
modifier = Modifier.size(18.dp)
)
}
@ -463,14 +462,14 @@ fun AddLinkScreen(
Icon(
imageVector = Icons.Default.Tag,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(20.dp)
)
Text(
text = "Tags",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
}
@ -511,7 +510,7 @@ fun AddLinkScreen(
}
}
},
placeholder = { Text("Ajouter un tag...", color = TextMuted) },
placeholder = { Text("Ajouter un tag...", color = MaterialTheme.colorScheme.outline) },
singleLine = true,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
@ -537,7 +536,7 @@ fun AddLinkScreen(
Icon(
Icons.Default.Add,
contentDescription = "Ajouter",
tint = if (newTagInput.isNotBlank()) CyanPrimary else TextMuted
tint = if (newTagInput.isNotBlank()) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline
)
}
}
@ -552,7 +551,7 @@ fun AddLinkScreen(
Text(
"Suggestions",
style = MaterialTheme.typography.labelSmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
modifier = Modifier.padding(bottom = 8.dp)
)
LazyRow(
@ -579,7 +578,7 @@ fun AddLinkScreen(
Text(
"Populaires",
style = MaterialTheme.typography.labelSmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
modifier = Modifier.padding(bottom = 8.dp)
)
LazyRow(
@ -617,16 +616,16 @@ fun AddLinkScreen(
Text(
if (isPrivate) "Seul vous pouvez voir" else "Visible par tous",
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Switch(
checked = isPrivate,
onCheckedChange = { viewModel.isPrivate.value = it },
colors = SwitchDefaults.colors(
checkedThumbColor = CyanPrimary,
checkedTrackColor = CyanPrimary.copy(alpha = 0.3f),
uncheckedThumbColor = TextMuted,
uncheckedTrackColor = SurfaceVariant
checkedThumbColor = MaterialTheme.colorScheme.primary,
checkedTrackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.3f),
uncheckedThumbColor = MaterialTheme.colorScheme.outline,
uncheckedTrackColor = MaterialTheme.colorScheme.outlineVariant
)
)
}
@ -652,8 +651,8 @@ fun AddLinkScreen(
if (uiState is AddLinkUiState.Loading) {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
color = CyanPrimary,
trackColor = SurfaceVariant
color = MaterialTheme.colorScheme.primary,
trackColor = MaterialTheme.colorScheme.outlineVariant
)
}
@ -685,8 +684,8 @@ private fun ContentTypeButton(
Surface(
onClick = onClick,
shape = RoundedCornerShape(10.dp),
color = if (isSelected) CyanPrimary.copy(alpha = 0.15f) else CardBackgroundElevated,
border = if (isSelected) androidx.compose.foundation.BorderStroke(1.5.dp, CyanPrimary) else null,
color = if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.15f) else MaterialTheme.colorScheme.primaryContainer,
border = if (isSelected) androidx.compose.foundation.BorderStroke(1.5.dp, MaterialTheme.colorScheme.primary) else null,
modifier = modifier
) {
Row(
@ -697,14 +696,14 @@ private fun ContentTypeButton(
Icon(
imageVector = icon,
contentDescription = null,
tint = if (isSelected) CyanPrimary else TextSecondary,
tint = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = label,
style = MaterialTheme.typography.bodyMedium,
color = if (isSelected) CyanPrimary else TextPrimary,
color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground,
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal
)
}
@ -731,7 +730,7 @@ private fun CompactFieldCard(
GlassCard(
modifier = finalModifier,
glowColor = CyanPrimary.copy(alpha = 0.3f)
glowColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.3f)
) {
Column {
Row(
@ -742,13 +741,13 @@ private fun CompactFieldCard(
Icon(
imageVector = icon,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(18.dp)
)
Text(
text = label,
style = MaterialTheme.typography.labelMedium,
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontWeight = FontWeight.Medium
)
}
@ -763,13 +762,13 @@ private fun CompactFieldCard(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun compactTextFieldColors() = OutlinedTextFieldDefaults.colors(
focusedBorderColor = CyanPrimary,
unfocusedBorderColor = SurfaceVariant,
focusedLabelColor = CyanPrimary,
unfocusedLabelColor = TextSecondary,
cursorColor = CyanPrimary,
focusedContainerColor = CardBackground.copy(alpha = 0.3f),
unfocusedContainerColor = CardBackground.copy(alpha = 0.2f)
focusedBorderColor = MaterialTheme.colorScheme.primary,
unfocusedBorderColor = MaterialTheme.colorScheme.outlineVariant,
focusedLabelColor = MaterialTheme.colorScheme.primary,
unfocusedLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
cursorColor = MaterialTheme.colorScheme.primary,
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f),
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.2f)
)
/**
@ -797,8 +796,8 @@ private fun AiMagicButton(
onClick = onClick,
enabled = enabled && !isLoading,
shape = RoundedCornerShape(10.dp),
color = if (enabled) Purple.copy(alpha = if (isLoading) shimmerAlpha * 0.3f else 0.15f) else SurfaceVariant,
border = if (enabled) androidx.compose.foundation.BorderStroke(1.5.dp, Purple) else null,
color = if (enabled) MaterialTheme.colorScheme.tertiary.copy(alpha = if (isLoading) shimmerAlpha * 0.3f else 0.15f) else MaterialTheme.colorScheme.outlineVariant,
border = if (enabled) androidx.compose.foundation.BorderStroke(1.5.dp, MaterialTheme.colorScheme.tertiary) else null,
modifier = modifier.size(48.dp)
) {
Box(
@ -808,14 +807,14 @@ private fun AiMagicButton(
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = Purple,
color = MaterialTheme.colorScheme.tertiary,
strokeWidth = 2.dp
)
} else {
Icon(
imageVector = Icons.Outlined.AutoAwesome,
contentDescription = "Magie IA",
tint = if (enabled) Purple else TextMuted,
tint = if (enabled) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.outline,
modifier = Modifier.size(22.dp)
)
}

View File

@ -19,7 +19,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import com.shaarit.ui.components.GlassCard
import com.shaarit.ui.components.GradientButton
import com.shaarit.ui.components.PremiumTextField
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Typography
@Composable
fun LoginScreen(onLoginSuccess: () -> Unit, viewModel: LoginViewModel = hiltViewModel()) {
@ -58,7 +58,7 @@ fun LoginScreen(onLoginSuccess: () -> Unit, viewModel: LoginViewModel = hiltView
.background(
brush =
Brush.verticalGradient(
colors = listOf(DeepNavy, DarkNavy)
colors = listOf(MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.surface)
)
)
) {
@ -71,7 +71,7 @@ fun LoginScreen(onLoginSuccess: () -> Unit, viewModel: LoginViewModel = hiltView
Brush.radialGradient(
colors =
listOf(
CyanPrimary.copy(
MaterialTheme.colorScheme.primary.copy(
alpha =
backgroundAlpha
),
@ -110,13 +110,13 @@ fun LoginScreen(onLoginSuccess: () -> Unit, viewModel: LoginViewModel = hiltView
text = "ShaarIt",
style = MaterialTheme.typography.displayMedium,
fontWeight = FontWeight.Bold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Your personal bookmark manager",
style = MaterialTheme.typography.bodyLarge,
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center
)
}
@ -131,7 +131,7 @@ fun LoginScreen(onLoginSuccess: () -> Unit, viewModel: LoginViewModel = hiltView
text = "Connect to Shaarli",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.SemiBold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
PremiumTextField(
@ -154,7 +154,7 @@ fun LoginScreen(onLoginSuccess: () -> Unit, viewModel: LoginViewModel = hiltView
Icon(
Icons.Default.Lock,
contentDescription = null,
tint = TextMuted
tint = MaterialTheme.colorScheme.outline
)
},
trailingIcon = {
@ -162,7 +162,7 @@ fun LoginScreen(onLoginSuccess: () -> Unit, viewModel: LoginViewModel = hiltView
Text(
if (showSecret) "Hide" else "Show",
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
}
}
@ -174,7 +174,7 @@ fun LoginScreen(onLoginSuccess: () -> Unit, viewModel: LoginViewModel = hiltView
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
) { CircularProgressIndicator(color = CyanPrimary) }
) { CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) }
} else {
GradientButton(
text = "Connect",
@ -192,7 +192,7 @@ fun LoginScreen(onLoginSuccess: () -> Unit, viewModel: LoginViewModel = hiltView
text =
"Find your API secret in Shaarli's\n\"Tools\"\"Configure your Shaarli\"",
style = MaterialTheme.typography.bodySmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
textAlign = TextAlign.Center,
modifier = Modifier.alpha(0.7f)
)

View File

@ -27,7 +27,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.shaarit.ui.components.GlassCard
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Typography
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -47,7 +47,7 @@ fun CollectionsScreen(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(colors = listOf(DeepNavy, DarkNavy))
brush = Brush.verticalGradient(colors = listOf(MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.surface))
)
) {
Scaffold(
@ -65,7 +65,7 @@ fun CollectionsScreen(
Icon(
Icons.Default.ArrowBack,
contentDescription = "Retour",
tint = TextPrimary
tint = MaterialTheme.colorScheme.onBackground
)
}
},
@ -74,13 +74,13 @@ fun CollectionsScreen(
Icon(
Icons.Default.Add,
contentDescription = "Nouvelle collection",
tint = CyanPrimary
tint = MaterialTheme.colorScheme.primary
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = DeepNavy.copy(alpha = 0.9f),
titleContentColor = TextPrimary
containerColor = MaterialTheme.colorScheme.background.copy(alpha = 0.9f),
titleContentColor = MaterialTheme.colorScheme.onBackground
)
)
},
@ -88,8 +88,8 @@ fun CollectionsScreen(
floatingActionButton = {
FloatingActionButton(
onClick = { showCreateDialog = true },
containerColor = CyanPrimary,
contentColor = DeepNavy
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.background
) {
Icon(Icons.Default.Add, contentDescription = "Nouvelle collection")
}
@ -103,7 +103,7 @@ fun CollectionsScreen(
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.align(Alignment.Center),
color = CyanPrimary
color = MaterialTheme.colorScheme.primary
)
} else if (collections.isEmpty()) {
EmptyCollectionsView(onCreateClick = { showCreateDialog = true })
@ -170,7 +170,7 @@ fun CollectionsScreen(
showDeleteConfirm = null
},
colors = ButtonDefaults.textButtonColors(
contentColor = ErrorRed
contentColor = MaterialTheme.colorScheme.error
)
) {
Text("Supprimer")
@ -181,9 +181,9 @@ fun CollectionsScreen(
Text("Annuler")
}
},
containerColor = CardBackground,
titleContentColor = TextPrimary,
textContentColor = TextSecondary
containerColor = MaterialTheme.colorScheme.surfaceVariant,
titleContentColor = MaterialTheme.colorScheme.onBackground,
textContentColor = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -226,7 +226,7 @@ private fun CollectionCard(
Icon(
imageVector = Icons.Default.AutoAwesome,
contentDescription = "Collection intelligente",
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(20.dp)
)
}
@ -238,7 +238,7 @@ private fun CollectionCard(
text = collection.name,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = TextPrimary,
color = MaterialTheme.colorScheme.onBackground,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
@ -248,7 +248,7 @@ private fun CollectionCard(
Text(
text = desc,
style = MaterialTheme.typography.bodySmall,
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(top = 4.dp)
@ -260,7 +260,7 @@ private fun CollectionCard(
Text(
text = "${collection.linkCount} lien${if (collection.linkCount > 1) "s" else ""}",
style = MaterialTheme.typography.labelMedium,
color = CyanPrimary,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(top = 8.dp)
)
}
@ -279,7 +279,7 @@ private fun CollectionCard(
Icon(
imageVector = Icons.Default.MoreVert,
contentDescription = "Options",
tint = TextSecondary,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp)
)
}
@ -287,7 +287,7 @@ private fun CollectionCard(
DropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false },
modifier = Modifier.background(CardBackground)
modifier = Modifier.background(MaterialTheme.colorScheme.surfaceVariant)
) {
DropdownMenuItem(
text = {
@ -298,10 +298,10 @@ private fun CollectionCard(
Icon(
Icons.Default.Edit,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(18.dp)
)
Text("Modifier", color = TextPrimary)
Text("Modifier", color = MaterialTheme.colorScheme.onBackground)
}
},
onClick = {
@ -318,10 +318,10 @@ private fun CollectionCard(
Icon(
Icons.Default.Delete,
contentDescription = null,
tint = ErrorRed,
tint = MaterialTheme.colorScheme.error,
modifier = Modifier.size(18.dp)
)
Text("Supprimer", color = ErrorRed)
Text("Supprimer", color = MaterialTheme.colorScheme.error)
}
},
onClick = {
@ -347,7 +347,7 @@ private fun EmptyCollectionsView(onCreateClick: () -> Unit) {
Icon(
imageVector = Icons.Default.FolderOpen,
contentDescription = null,
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier.size(80.dp)
)
@ -357,7 +357,7 @@ private fun EmptyCollectionsView(onCreateClick: () -> Unit) {
text = "Aucune collection",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
Spacer(modifier = Modifier.height(8.dp))
@ -365,7 +365,7 @@ private fun EmptyCollectionsView(onCreateClick: () -> Unit) {
Text(
text = "Créez des collections pour organiser vos liens par thème",
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = androidx.compose.ui.text.style.TextAlign.Center
)
@ -374,8 +374,8 @@ private fun EmptyCollectionsView(onCreateClick: () -> Unit) {
Button(
onClick = onCreateClick,
colors = ButtonDefaults.buttonColors(
containerColor = CyanPrimary,
contentColor = DeepNavy
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.background
)
) {
Icon(Icons.Default.Add, contentDescription = null)
@ -443,11 +443,11 @@ private fun CollectionDialogContent(
AlertDialog(
onDismissRequest = onDismiss,
containerColor = CardBackground,
containerColor = MaterialTheme.colorScheme.surfaceVariant,
title = {
Text(
title,
color = TextPrimary,
color = MaterialTheme.colorScheme.onBackground,
fontWeight = FontWeight.Bold
)
},
@ -463,14 +463,14 @@ private fun CollectionDialogContent(
OutlinedTextField(
value = name,
onValueChange = { name = it },
label = { Text("Nom", color = TextSecondary) },
label = { Text("Nom", color = MaterialTheme.colorScheme.onSurfaceVariant) },
singleLine = true,
modifier = Modifier.fillMaxWidth(),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = CyanPrimary,
unfocusedBorderColor = TextMuted,
focusedTextColor = TextPrimary,
unfocusedTextColor = TextPrimary
focusedBorderColor = MaterialTheme.colorScheme.primary,
unfocusedBorderColor = MaterialTheme.colorScheme.outline,
focusedTextColor = MaterialTheme.colorScheme.onBackground,
unfocusedTextColor = MaterialTheme.colorScheme.onBackground
)
)
@ -478,15 +478,15 @@ private fun CollectionDialogContent(
OutlinedTextField(
value = description,
onValueChange = { description = it },
label = { Text("Description (optionnel)", color = TextSecondary) },
label = { Text("Description (optionnel)", color = MaterialTheme.colorScheme.onSurfaceVariant) },
minLines = 2,
maxLines = 3,
modifier = Modifier.fillMaxWidth(),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = CyanPrimary,
unfocusedBorderColor = TextMuted,
focusedTextColor = TextPrimary,
unfocusedTextColor = TextPrimary
focusedBorderColor = MaterialTheme.colorScheme.primary,
unfocusedBorderColor = MaterialTheme.colorScheme.outline,
focusedTextColor = MaterialTheme.colorScheme.onBackground,
unfocusedTextColor = MaterialTheme.colorScheme.onBackground
)
)
@ -494,7 +494,7 @@ private fun CollectionDialogContent(
Text(
"Icône",
style = MaterialTheme.typography.labelMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
FlowRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
@ -507,12 +507,12 @@ private fun CollectionDialogContent(
.size(44.dp)
.clip(RoundedCornerShape(10.dp))
.background(
if (isSelected) CyanPrimary.copy(alpha = 0.2f)
else CardBackgroundElevated
if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.2f)
else MaterialTheme.colorScheme.surfaceVariant
)
.border(
width = if (isSelected) 2.dp else 0.dp,
color = if (isSelected) CyanPrimary else androidx.compose.ui.graphics.Color.Transparent,
color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline,
shape = RoundedCornerShape(10.dp)
)
.clickable { selectedIcon = icon },
@ -527,10 +527,10 @@ private fun CollectionDialogContent(
Card(
onClick = { isSmart = !isSmart },
colors = CardDefaults.cardColors(
containerColor = if (isSmart) CyanPrimary.copy(alpha = 0.1f) else CardBackgroundElevated
containerColor = if (isSmart) MaterialTheme.colorScheme.primary.copy(alpha = 0.1f) else MaterialTheme.colorScheme.primaryContainer
),
border = if (isSmart) {
androidx.compose.foundation.BorderStroke(1.dp, CyanPrimary.copy(alpha = 0.3f))
androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.3f))
} else null,
modifier = Modifier.fillMaxWidth()
) {
@ -548,19 +548,19 @@ private fun CollectionDialogContent(
Icon(
imageVector = Icons.Default.AutoAwesome,
contentDescription = null,
tint = if (isSmart) CyanPrimary else TextSecondary
tint = if (isSmart) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Column(modifier = Modifier.weight(1f)) {
Text(
"Collection intelligente",
style = MaterialTheme.typography.bodyMedium,
color = TextPrimary,
color = MaterialTheme.colorScheme.onBackground,
fontWeight = FontWeight.Medium
)
Text(
"Remplie automatiquement selon les tags sélectionnés",
style = MaterialTheme.typography.bodySmall,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -568,8 +568,8 @@ private fun CollectionDialogContent(
checked = isSmart,
onCheckedChange = { isSmart = it },
colors = SwitchDefaults.colors(
checkedThumbColor = CyanPrimary,
checkedTrackColor = CyanPrimary.copy(alpha = 0.5f)
checkedThumbColor = MaterialTheme.colorScheme.primary,
checkedTrackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f)
)
)
}
@ -581,7 +581,7 @@ private fun CollectionDialogContent(
Text(
"Tags sélectionnés (${selectedTags.size})",
style = MaterialTheme.typography.labelMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
FlowRow(
modifier = Modifier.fillMaxWidth(),
@ -608,22 +608,22 @@ private fun CollectionDialogContent(
tagSearch = it
showTagDropdown = it.isNotBlank() || tags.isNotEmpty()
},
label = { Text("Ajouter des tags...", color = TextSecondary) },
label = { Text("Ajouter des tags...", color = MaterialTheme.colorScheme.onSurfaceVariant) },
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.menuAnchor(),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = CyanPrimary,
unfocusedBorderColor = TextMuted,
focusedTextColor = TextPrimary,
unfocusedTextColor = TextPrimary
focusedBorderColor = MaterialTheme.colorScheme.primary,
unfocusedBorderColor = MaterialTheme.colorScheme.outline,
focusedTextColor = MaterialTheme.colorScheme.onBackground,
unfocusedTextColor = MaterialTheme.colorScheme.onBackground
),
trailingIcon = {
Icon(
imageVector = if (showTagDropdown) Icons.Default.ExpandLess else Icons.Default.ExpandMore,
contentDescription = null,
tint = TextSecondary
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
)
@ -643,7 +643,7 @@ private fun CollectionDialogContent(
expanded = showTagDropdown,
onDismissRequest = { showTagDropdown = false },
modifier = Modifier
.background(CardBackgroundElevated)
.background(MaterialTheme.colorScheme.primaryContainer)
.heightIn(max = 250.dp)
) {
availableTags.forEach { tag ->
@ -651,7 +651,7 @@ private fun CollectionDialogContent(
text = {
Text(
"#$tag",
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
},
onClick = {
@ -663,7 +663,7 @@ private fun CollectionDialogContent(
Icon(
imageVector = Icons.Default.Add,
contentDescription = null,
tint = CyanPrimary
tint = MaterialTheme.colorScheme.primary
)
}
)
@ -683,7 +683,7 @@ private fun CollectionDialogContent(
Text(
"Tags populaires",
style = MaterialTheme.typography.labelMedium,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
FlowRow(
modifier = Modifier.fillMaxWidth(),
@ -709,8 +709,8 @@ private fun CollectionDialogContent(
},
enabled = name.isNotBlank() && (!isSmart || selectedTags.isNotEmpty()),
colors = ButtonDefaults.buttonColors(
containerColor = CyanPrimary,
contentColor = DeepNavy
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.background
)
) {
Text(if (isEdit) "Enregistrer" else "Créer")
@ -718,7 +718,7 @@ private fun CollectionDialogContent(
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text("Annuler", color = TextSecondary)
Text("Annuler", color = MaterialTheme.colorScheme.onSurfaceVariant)
}
}
)
@ -731,8 +731,8 @@ private fun SelectedTagChip(
) {
Surface(
shape = MaterialTheme.shapes.small,
color = CyanPrimary.copy(alpha = 0.2f),
border = androidx.compose.foundation.BorderStroke(1.dp, CyanPrimary.copy(alpha = 0.5f))
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.2f),
border = androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.5f))
) {
Row(
verticalAlignment = Alignment.CenterVertically,
@ -741,7 +741,7 @@ private fun SelectedTagChip(
Text(
text = "#$tag",
style = MaterialTheme.typography.labelMedium,
color = CyanLight
color = MaterialTheme.colorScheme.tertiary
)
IconButton(
onClick = onRemove,
@ -750,7 +750,7 @@ private fun SelectedTagChip(
Icon(
imageVector = Icons.Default.Close,
contentDescription = "Retirer",
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(14.dp)
)
}
@ -766,7 +766,7 @@ private fun AvailableTagChip(
Surface(
onClick = onClick,
shape = MaterialTheme.shapes.small,
color = CardBackground
color = MaterialTheme.colorScheme.surfaceVariant
) {
Row(
verticalAlignment = Alignment.CenterVertically,
@ -775,14 +775,14 @@ private fun AvailableTagChip(
Icon(
imageVector = Icons.Default.Add,
contentDescription = null,
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier.size(14.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text(
text = "#$tag",
style = MaterialTheme.typography.labelMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}

View File

@ -26,7 +26,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import com.shaarit.presentation.feed.ListViewItem
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Typography
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -46,7 +46,7 @@ fun DeadLinksScreen(
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(DeepNavy, DarkNavy)
colors = listOf(MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.surface)
)
)
) {
@ -59,7 +59,7 @@ fun DeadLinksScreen(
if (isSelectionMode) "${selectedLinkIds.size} sélectionné(s)" else "Liens inaccessibles",
style = MaterialTheme.typography.headlineSmall,
fontWeight = FontWeight.Bold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
},
navigationIcon = {
@ -73,7 +73,7 @@ fun DeadLinksScreen(
Icon(
if (isSelectionMode) Icons.Default.Close else Icons.Default.ArrowBack,
contentDescription = if (isSelectionMode) "Annuler" else "Retour",
tint = TextPrimary
tint = MaterialTheme.colorScheme.onBackground
)
}
},
@ -87,14 +87,14 @@ fun DeadLinksScreen(
Icon(
imageVector = Icons.Default.CheckCircle,
contentDescription = "Exclure de la vérification",
tint = SuccessGreen
tint = Color(0xFF10B981)
)
}
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = DeepNavy.copy(alpha = 0.9f),
titleContentColor = TextPrimary
containerColor = MaterialTheme.colorScheme.background.copy(alpha = 0.9f),
titleContentColor = MaterialTheme.colorScheme.onBackground
)
)
},
@ -107,7 +107,7 @@ fun DeadLinksScreen(
) {
if (pagingItems.loadState.refresh is LoadState.Loading && pagingItems.itemCount == 0) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
CircularProgressIndicator(color = CyanPrimary)
CircularProgressIndicator(color = MaterialTheme.colorScheme.primary)
}
} else if (pagingItems.itemCount == 0) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
@ -115,19 +115,19 @@ fun DeadLinksScreen(
Icon(
imageVector = Icons.Default.BrokenImage,
contentDescription = null,
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier.size(64.dp)
)
Spacer(modifier = Modifier.height(16.dp))
Text(
"Aucun lien mort détecté",
style = MaterialTheme.typography.titleMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Tout semble fonctionner !",
style = MaterialTheme.typography.bodyMedium,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
}
}
@ -198,7 +198,7 @@ private fun DeadLinkItem(
onLongClick = onLongClick
),
colors = CardDefaults.cardColors(
containerColor = if (isSelected) CyanPrimary.copy(alpha = 0.1f) else CardBackground
containerColor = if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.1f) else MaterialTheme.colorScheme.surfaceVariant
)
) {
ListViewItem(

View File

@ -34,8 +34,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import coil.compose.AsyncImage
import com.shaarit.presentation.add.ContentType
import com.shaarit.ui.components.*
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Purple
import com.shaarit.ui.theme.Typography
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class, androidx.compose.foundation.ExperimentalFoundationApi::class)
@ -107,7 +106,7 @@ fun EditLinkScreen(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(colors = listOf(DeepNavy, DarkNavy))
brush = Brush.verticalGradient(colors = listOf(MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.surface))
)
) {
Scaffold(
@ -126,13 +125,13 @@ fun EditLinkScreen(
Icon(
Icons.Default.ArrowBack,
contentDescription = "Retour",
tint = TextPrimary
tint = MaterialTheme.colorScheme.onBackground
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = DeepNavy.copy(alpha = 0.9f),
titleContentColor = TextPrimary
containerColor = MaterialTheme.colorScheme.background.copy(alpha = 0.9f),
titleContentColor = MaterialTheme.colorScheme.onBackground
)
)
},
@ -147,11 +146,11 @@ fun EditLinkScreen(
contentAlignment = Alignment.Center
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
CircularProgressIndicator(color = CyanPrimary)
CircularProgressIndicator(color = MaterialTheme.colorScheme.primary)
Spacer(modifier = Modifier.height(16.dp))
Text(
"Chargement...",
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyMedium
)
}
@ -170,7 +169,7 @@ fun EditLinkScreen(
// Content Type Selection (compact)
GlassCard(
modifier = Modifier.fillMaxWidth(),
glowColor = CyanPrimary
glowColor = MaterialTheme.colorScheme.primary
) {
Row(
modifier = Modifier.fillMaxWidth(),
@ -215,7 +214,7 @@ fun EditLinkScreen(
value = url,
onValueChange = { viewModel.url.value = it },
modifier = Modifier.weight(1f),
placeholder = { Text("https://example.com", color = TextMuted) },
placeholder = { Text("https://example.com", color = MaterialTheme.colorScheme.outline) },
singleLine = true,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
colors = compactTextFieldColors(),
@ -230,21 +229,21 @@ fun EditLinkScreen(
modifier = Modifier
.size(48.dp) // Même taille que AiMagicButton
.background(
color = SurfaceVariant.copy(alpha = 0.5f),
color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f),
shape = RoundedCornerShape(12.dp)
)
) {
if (isExtractingMetadata) {
CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
strokeWidth = 2.dp
)
} else {
Icon(
Icons.Default.Refresh,
contentDescription = "Récupérer infos classique",
tint = TextSecondary
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -272,7 +271,7 @@ fun EditLinkScreen(
Text(
if (contentType == ContentType.NOTE)
"Titre de la note" else "Titre du lien",
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
},
singleLine = true,
@ -308,7 +307,7 @@ fun EditLinkScreen(
Icon(
imageVector = Icons.Default.Description,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(20.dp)
)
Column {
@ -317,13 +316,13 @@ fun EditLinkScreen(
"Contenu" else "Description",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
if (contentType == ContentType.NOTE) {
Text(
text = "Markdown supporté",
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
}
}
@ -340,7 +339,7 @@ fun EditLinkScreen(
Icon(
Icons.Default.Edit,
contentDescription = "Éditer",
tint = if (!showMarkdownPreview) CyanPrimary else TextMuted,
tint = if (!showMarkdownPreview) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline,
modifier = Modifier.size(18.dp)
)
}
@ -351,7 +350,7 @@ fun EditLinkScreen(
Icon(
Icons.Default.Preview,
contentDescription = "Aperçu",
tint = if (showMarkdownPreview) CyanPrimary else TextMuted,
tint = if (showMarkdownPreview) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline,
modifier = Modifier.size(18.dp)
)
}
@ -406,14 +405,14 @@ fun EditLinkScreen(
Icon(
imageVector = Icons.Default.Tag,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(20.dp)
)
Text(
text = "Tags",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
}
@ -454,7 +453,7 @@ fun EditLinkScreen(
}
}
},
placeholder = { Text("Ajouter un tag...", color = TextMuted) },
placeholder = { Text("Ajouter un tag...", color = MaterialTheme.colorScheme.outline) },
singleLine = true,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
@ -480,7 +479,7 @@ fun EditLinkScreen(
Icon(
Icons.Default.Add,
contentDescription = "Ajouter",
tint = if (newTagInput.isNotBlank()) CyanPrimary else TextMuted
tint = if (newTagInput.isNotBlank()) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline
)
}
@ -492,23 +491,23 @@ fun EditLinkScreen(
.size(40.dp)
.background(
color = if (aiTagsState is AiEnrichmentState.Loading)
SurfaceVariant.copy(alpha = 0.5f)
MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)
else
CyanPrimary.copy(alpha = 0.1f),
MaterialTheme.colorScheme.primary.copy(alpha = 0.1f),
shape = RoundedCornerShape(12.dp)
)
) {
if (aiTagsState is AiEnrichmentState.Loading) {
CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = CyanPrimary,
color = MaterialTheme.colorScheme.primary,
strokeWidth = 2.dp
)
} else {
Icon(
Icons.Outlined.AutoAwesome,
contentDescription = "Générer tags IA",
tint = CyanPrimary
tint = MaterialTheme.colorScheme.primary
)
}
}
@ -524,7 +523,7 @@ fun EditLinkScreen(
Text(
"Suggestions",
style = MaterialTheme.typography.labelSmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
modifier = Modifier.padding(bottom = 8.dp)
)
LazyRow(
@ -551,7 +550,7 @@ fun EditLinkScreen(
Text(
"Populaires",
style = MaterialTheme.typography.labelSmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
modifier = Modifier.padding(bottom = 8.dp)
)
LazyRow(
@ -589,16 +588,16 @@ fun EditLinkScreen(
Text(
if (isPrivate) "Seul vous pouvez voir" else "Visible par tous",
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Switch(
checked = isPrivate,
onCheckedChange = { viewModel.isPrivate.value = it },
colors = SwitchDefaults.colors(
checkedThumbColor = CyanPrimary,
checkedTrackColor = CyanPrimary.copy(alpha = 0.3f),
uncheckedThumbColor = TextMuted,
uncheckedTrackColor = SurfaceVariant
checkedThumbColor = MaterialTheme.colorScheme.primary,
checkedTrackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.3f),
uncheckedThumbColor = MaterialTheme.colorScheme.outline,
uncheckedTrackColor = MaterialTheme.colorScheme.outlineVariant
)
)
}
@ -624,8 +623,8 @@ fun EditLinkScreen(
if (uiState is EditLinkUiState.Saving) {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
color = CyanPrimary,
trackColor = SurfaceVariant
color = MaterialTheme.colorScheme.primary,
trackColor = MaterialTheme.colorScheme.outlineVariant
)
}
@ -659,8 +658,8 @@ private fun ContentTypeButton(
Surface(
onClick = onClick,
shape = RoundedCornerShape(10.dp),
color = if (isSelected) CyanPrimary.copy(alpha = 0.15f) else CardBackgroundElevated,
border = if (isSelected) androidx.compose.foundation.BorderStroke(1.5.dp, CyanPrimary) else null,
color = if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.15f) else MaterialTheme.colorScheme.primaryContainer,
border = if (isSelected) androidx.compose.foundation.BorderStroke(1.5.dp, MaterialTheme.colorScheme.primary) else null,
modifier = modifier
) {
Row(
@ -671,14 +670,14 @@ private fun ContentTypeButton(
Icon(
imageVector = icon,
contentDescription = null,
tint = if (isSelected) CyanPrimary else TextSecondary,
tint = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = label,
style = MaterialTheme.typography.bodyMedium,
color = if (isSelected) CyanPrimary else TextPrimary,
color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground,
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal
)
}
@ -705,7 +704,7 @@ private fun CompactFieldCard(
GlassCard(
modifier = finalModifier,
glowColor = CyanPrimary.copy(alpha = 0.3f)
glowColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.3f)
) {
Column {
Row(
@ -716,13 +715,13 @@ private fun CompactFieldCard(
Icon(
imageVector = icon,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(18.dp)
)
Text(
text = label,
style = MaterialTheme.typography.labelMedium,
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontWeight = FontWeight.Medium
)
}
@ -737,13 +736,13 @@ private fun CompactFieldCard(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun compactTextFieldColors() = OutlinedTextFieldDefaults.colors(
focusedBorderColor = CyanPrimary,
unfocusedBorderColor = SurfaceVariant,
focusedLabelColor = CyanPrimary,
unfocusedLabelColor = TextSecondary,
cursorColor = CyanPrimary,
focusedContainerColor = CardBackground.copy(alpha = 0.3f),
unfocusedContainerColor = CardBackground.copy(alpha = 0.2f)
focusedBorderColor = MaterialTheme.colorScheme.primary,
unfocusedBorderColor = MaterialTheme.colorScheme.outlineVariant,
focusedLabelColor = MaterialTheme.colorScheme.primary,
unfocusedLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
cursorColor = MaterialTheme.colorScheme.primary,
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f),
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.2f)
)
/**
@ -771,8 +770,8 @@ private fun AiMagicButton(
onClick = onClick,
enabled = enabled && !isLoading,
shape = RoundedCornerShape(10.dp),
color = if (enabled) Purple.copy(alpha = if (isLoading) shimmerAlpha * 0.3f else 0.15f) else SurfaceVariant,
border = if (enabled) androidx.compose.foundation.BorderStroke(1.5.dp, Purple) else null,
color = if (enabled) MaterialTheme.colorScheme.tertiary.copy(alpha = if (isLoading) shimmerAlpha * 0.3f else 0.15f) else MaterialTheme.colorScheme.outlineVariant,
border = if (enabled) androidx.compose.foundation.BorderStroke(1.5.dp, MaterialTheme.colorScheme.tertiary) else null,
modifier = modifier.size(48.dp)
) {
Box(
@ -782,14 +781,14 @@ private fun AiMagicButton(
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = Purple,
color = MaterialTheme.colorScheme.tertiary,
strokeWidth = 2.dp
)
} else {
Icon(
imageVector = Icons.Outlined.AutoAwesome,
contentDescription = "Magie IA",
tint = if (enabled) Purple else TextMuted,
tint = if (enabled) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.outline,
modifier = Modifier.size(22.dp)
)
}

View File

@ -43,7 +43,7 @@ import com.shaarit.domain.model.TagFilter
import com.shaarit.domain.model.ViewStyle
import com.shaarit.ui.components.PremiumTextField
import com.shaarit.ui.components.TagChip
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Typography
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.animation.*
@ -82,12 +82,12 @@ fun AccordionSection(
Text(
text = title,
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
Icon(
imageVector = if (expanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore,
contentDescription = if (expanded) "Réduire" else "Développer",
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier.size(16.dp)
)
}
@ -136,14 +136,14 @@ fun DrawerNavigationItem(
Icon(
imageVector = icon,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = label,
style = MaterialTheme.typography.bodyLarge,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
}
}
@ -158,7 +158,7 @@ fun DrawerCollectionItem(
) {
Surface(
onClick = onClick,
color = if (isSelected) CyanPrimary.copy(alpha = 0.15f) else Color.Transparent,
color = if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.15f) else Color.Transparent,
shape = MaterialTheme.shapes.medium,
modifier = Modifier
.fillMaxWidth()
@ -178,7 +178,7 @@ fun DrawerCollectionItem(
Text(
text = name,
style = MaterialTheme.typography.bodyMedium,
color = if (isSelected) CyanPrimary else TextPrimary,
color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground,
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal,
maxLines = 1,
overflow = TextOverflow.Ellipsis
@ -188,7 +188,7 @@ fun DrawerCollectionItem(
Box(
modifier = Modifier
.size(8.dp)
.background(CyanPrimary, shape = MaterialTheme.shapes.small)
.background(MaterialTheme.colorScheme.primary, shape = MaterialTheme.shapes.small)
)
}
}
@ -203,7 +203,7 @@ fun DrawerSmartCollectionItem(
) {
Surface(
onClick = onClick,
color = if (isSelected) CyanPrimary.copy(alpha = 0.15f) else Color.Transparent,
color = if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.15f) else Color.Transparent,
shape = MaterialTheme.shapes.medium,
modifier = Modifier
.fillMaxWidth()
@ -218,14 +218,14 @@ fun DrawerSmartCollectionItem(
Icon(
imageVector = Icons.Default.AutoAwesome,
contentDescription = null,
tint = if (isSelected) CyanPrimary else TealSecondary,
tint = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(20.dp)
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = name,
style = MaterialTheme.typography.bodyMedium,
color = if (isSelected) CyanPrimary else TextPrimary,
color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground,
fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal,
maxLines = 1,
overflow = TextOverflow.Ellipsis
@ -235,7 +235,7 @@ fun DrawerSmartCollectionItem(
Box(
modifier = Modifier
.size(8.dp)
.background(CyanPrimary, shape = MaterialTheme.shapes.small)
.background(MaterialTheme.colorScheme.primary, shape = MaterialTheme.shapes.small)
)
}
}
@ -251,16 +251,16 @@ fun DrawerTagChip(
Surface(
onClick = onClick,
shape = MaterialTheme.shapes.small,
color = if (isSelected) CyanPrimary.copy(alpha = 0.25f) else CardBackgroundElevated,
color = if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.25f) else MaterialTheme.colorScheme.primaryContainer,
border = if (isSelected) {
androidx.compose.foundation.BorderStroke(1.dp, CyanPrimary.copy(alpha = 0.5f))
androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.5f))
} else null,
modifier = Modifier.padding(2.dp)
) {
Text(
text = "#$tag",
style = MaterialTheme.typography.labelMedium,
color = if (isSelected) CyanLight else TextSecondary,
color = if (isSelected) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp)
)
}
@ -328,8 +328,8 @@ fun FeedScreen(
drawerContent = {
ModalDrawerSheet(
modifier = Modifier.width(320.dp),
drawerContainerColor = DeepNavy,
drawerContentColor = TextPrimary
drawerContainerColor = MaterialTheme.colorScheme.background,
drawerContentColor = MaterialTheme.colorScheme.onBackground
) {
// Header avec logo et titre (fixe, ne défile pas)
Column(
@ -338,8 +338,8 @@ fun FeedScreen(
.background(
brush = Brush.verticalGradient(
colors = listOf(
CardBackgroundElevated,
DeepNavy
MaterialTheme.colorScheme.primaryContainer,
MaterialTheme.colorScheme.background
)
)
)
@ -350,7 +350,7 @@ fun FeedScreen(
modifier = Modifier
.size(56.dp)
.background(
color = CyanPrimary.copy(alpha = 0.15f),
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.15f),
shape = MaterialTheme.shapes.large
),
contentAlignment = Alignment.Center
@ -358,7 +358,7 @@ fun FeedScreen(
Icon(
imageVector = Icons.Default.Bookmark,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(28.dp)
)
}
@ -369,13 +369,13 @@ fun FeedScreen(
text = "ShaarIt",
style = MaterialTheme.typography.headlineSmall,
fontWeight = FontWeight.Bold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
Text(
text = "Vos liens, organisés",
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
@ -453,7 +453,7 @@ fun FeedScreen(
}
Divider(
color = TextMuted.copy(alpha = 0.2f),
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f),
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
@ -584,7 +584,7 @@ fun FeedScreen(
}
Divider(
color = TextMuted.copy(alpha = 0.2f),
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f),
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
@ -603,7 +603,7 @@ fun FeedScreen(
Text(
"Voir tout",
style = MaterialTheme.typography.labelSmall,
color = CyanPrimary
color = MaterialTheme.colorScheme.primary
)
}
}
@ -650,7 +650,7 @@ fun FeedScreen(
}
Divider(
color = TextMuted.copy(alpha = 0.2f),
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f),
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
@ -669,7 +669,7 @@ fun FeedScreen(
Text(
"Voir tout",
style = MaterialTheme.typography.labelSmall,
color = CyanPrimary
color = MaterialTheme.colorScheme.primary
)
}
}
@ -702,7 +702,7 @@ fun FeedScreen(
Text(
text = "© 2026 ShaarIt",
style = MaterialTheme.typography.labelSmall,
color = TextMuted.copy(alpha = 0.6f),
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.6f),
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
@ -716,7 +716,7 @@ fun FeedScreen(
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(DeepNavy, DarkNavy)
colors = listOf(MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.surface)
)
)
) {
@ -729,7 +729,7 @@ fun FeedScreen(
"ShaarIt",
style = MaterialTheme.typography.headlineSmall,
fontWeight = FontWeight.Bold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
},
navigationIcon = {
@ -743,7 +743,7 @@ fun FeedScreen(
Icon(
imageVector = Icons.Default.Close,
contentDescription = "Exit selection",
tint = CyanPrimary
tint = MaterialTheme.colorScheme.primary
)
}
} else {
@ -751,7 +751,7 @@ fun FeedScreen(
Icon(
imageVector = Icons.Default.Menu,
contentDescription = "Menu",
tint = CyanPrimary
tint = MaterialTheme.colorScheme.primary
)
}
}
@ -760,7 +760,7 @@ fun FeedScreen(
if (selectionMode) {
Text(
text = selectedIds.size.toString(),
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = 8.dp)
)
IconButton(
@ -770,7 +770,7 @@ fun FeedScreen(
Icon(
imageVector = Icons.Default.Folder,
contentDescription = "Add to collection",
tint = if (selectedIds.isNotEmpty()) CyanPrimary else TextMuted
tint = if (selectedIds.isNotEmpty()) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline
)
}
IconButton(
@ -782,7 +782,7 @@ fun FeedScreen(
Icon(
imageVector = Icons.Default.Close,
contentDescription = "Cancel selection",
tint = TextSecondary
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
return@TopAppBar
@ -797,7 +797,7 @@ fun FeedScreen(
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = "Refresh",
tint = CyanPrimary
tint = MaterialTheme.colorScheme.primary
)
}
@ -811,14 +811,14 @@ fun FeedScreen(
ViewStyle.COMPACT -> Icons.Default.ViewList
},
contentDescription = "View style",
tint = CyanPrimary
tint = MaterialTheme.colorScheme.primary
)
}
DropdownMenu(
expanded = showViewStyleMenu,
onDismissRequest = { showViewStyleMenu = false },
modifier = Modifier.background(CardBackground)
modifier = Modifier.background(MaterialTheme.colorScheme.surfaceVariant)
) {
DropdownMenuItem(
text = {
@ -829,11 +829,11 @@ fun FeedScreen(
Icon(
Icons.Default.ViewStream,
contentDescription = null,
tint = if (viewStyle == ViewStyle.LIST) CyanPrimary else TextSecondary
tint = if (viewStyle == ViewStyle.LIST) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"List View",
color = if (viewStyle == ViewStyle.LIST) CyanPrimary else TextPrimary
color = if (viewStyle == ViewStyle.LIST) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -851,11 +851,11 @@ fun FeedScreen(
Icon(
Icons.Default.ViewModule,
contentDescription = null,
tint = if (viewStyle == ViewStyle.GRID) CyanPrimary else TextSecondary
tint = if (viewStyle == ViewStyle.GRID) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Grid View",
color = if (viewStyle == ViewStyle.GRID) CyanPrimary else TextPrimary
color = if (viewStyle == ViewStyle.GRID) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -873,11 +873,11 @@ fun FeedScreen(
Icon(
Icons.Default.ViewList,
contentDescription = null,
tint = if (viewStyle == ViewStyle.COMPACT) CyanPrimary else TextSecondary
tint = if (viewStyle == ViewStyle.COMPACT) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Compact View",
color = if (viewStyle == ViewStyle.COMPACT) CyanPrimary else TextPrimary
color = if (viewStyle == ViewStyle.COMPACT) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -895,20 +895,20 @@ fun FeedScreen(
Icon(
imageVector = Icons.Default.FilterList,
contentDescription = "Filters",
tint = CyanPrimary
tint = MaterialTheme.colorScheme.primary
)
}
DropdownMenu(
expanded = showSortOrderMenu,
onDismissRequest = { showSortOrderMenu = false },
modifier = Modifier.background(CardBackground)
modifier = Modifier.background(MaterialTheme.colorScheme.surfaceVariant)
) {
// Sort Direction Section
Text(
text = "TRI",
style = MaterialTheme.typography.labelSmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
DropdownMenuItem(
@ -920,11 +920,11 @@ fun FeedScreen(
Icon(
Icons.Default.ArrowDownward,
contentDescription = null,
tint = if (bookmarkFilter.sortDirection == SortDirection.NEWEST_FIRST) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.sortDirection == SortDirection.NEWEST_FIRST) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Plus récent d'abord",
color = if (bookmarkFilter.sortDirection == SortDirection.NEWEST_FIRST) CyanPrimary else TextPrimary
color = if (bookmarkFilter.sortDirection == SortDirection.NEWEST_FIRST) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -941,11 +941,11 @@ fun FeedScreen(
Icon(
Icons.Default.ArrowUpward,
contentDescription = null,
tint = if (bookmarkFilter.sortDirection == SortDirection.OLDEST_FIRST) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.sortDirection == SortDirection.OLDEST_FIRST) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Plus ancien d'abord",
color = if (bookmarkFilter.sortDirection == SortDirection.OLDEST_FIRST) CyanPrimary else TextPrimary
color = if (bookmarkFilter.sortDirection == SortDirection.OLDEST_FIRST) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -954,13 +954,13 @@ fun FeedScreen(
}
)
Divider(color = TextMuted.copy(alpha = 0.2f))
Divider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f))
// Time Filter Section
Text(
text = "PÉRIODE",
style = MaterialTheme.typography.labelSmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
DropdownMenuItem(
@ -972,11 +972,11 @@ fun FeedScreen(
Icon(
Icons.Default.AllInclusive,
contentDescription = null,
tint = if (bookmarkFilter.timeFilter == TimeFilter.ALL) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.timeFilter == TimeFilter.ALL) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Tous les bookmarks",
color = if (bookmarkFilter.timeFilter == TimeFilter.ALL) CyanPrimary else TextPrimary
color = if (bookmarkFilter.timeFilter == TimeFilter.ALL) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -993,11 +993,11 @@ fun FeedScreen(
Icon(
Icons.Default.Today,
contentDescription = null,
tint = if (bookmarkFilter.timeFilter == TimeFilter.TODAY) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.timeFilter == TimeFilter.TODAY) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Aujourd'hui",
color = if (bookmarkFilter.timeFilter == TimeFilter.TODAY) CyanPrimary else TextPrimary
color = if (bookmarkFilter.timeFilter == TimeFilter.TODAY) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -1014,11 +1014,11 @@ fun FeedScreen(
Icon(
Icons.Default.DateRange,
contentDescription = null,
tint = if (bookmarkFilter.timeFilter == TimeFilter.THIS_WEEK) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.timeFilter == TimeFilter.THIS_WEEK) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Cette semaine",
color = if (bookmarkFilter.timeFilter == TimeFilter.THIS_WEEK) CyanPrimary else TextPrimary
color = if (bookmarkFilter.timeFilter == TimeFilter.THIS_WEEK) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -1035,11 +1035,11 @@ fun FeedScreen(
Icon(
Icons.Default.CalendarMonth,
contentDescription = null,
tint = if (bookmarkFilter.timeFilter == TimeFilter.THIS_MONTH) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.timeFilter == TimeFilter.THIS_MONTH) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Ce mois-ci",
color = if (bookmarkFilter.timeFilter == TimeFilter.THIS_MONTH) CyanPrimary else TextPrimary
color = if (bookmarkFilter.timeFilter == TimeFilter.THIS_MONTH) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -1048,13 +1048,13 @@ fun FeedScreen(
}
)
Divider(color = TextMuted.copy(alpha = 0.2f))
Divider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f))
// Visibility Filter Section
Text(
text = "VISIBILITÉ",
style = MaterialTheme.typography.labelSmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
DropdownMenuItem(
@ -1066,11 +1066,11 @@ fun FeedScreen(
Icon(
Icons.Default.Visibility,
contentDescription = null,
tint = if (bookmarkFilter.visibilityFilter == VisibilityFilter.ALL) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.visibilityFilter == VisibilityFilter.ALL) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Publics et Privés",
color = if (bookmarkFilter.visibilityFilter == VisibilityFilter.ALL) CyanPrimary else TextPrimary
color = if (bookmarkFilter.visibilityFilter == VisibilityFilter.ALL) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -1087,11 +1087,11 @@ fun FeedScreen(
Icon(
Icons.Default.Public,
contentDescription = null,
tint = if (bookmarkFilter.visibilityFilter == VisibilityFilter.PUBLIC_ONLY) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.visibilityFilter == VisibilityFilter.PUBLIC_ONLY) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Publics uniquement",
color = if (bookmarkFilter.visibilityFilter == VisibilityFilter.PUBLIC_ONLY) CyanPrimary else TextPrimary
color = if (bookmarkFilter.visibilityFilter == VisibilityFilter.PUBLIC_ONLY) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -1108,11 +1108,11 @@ fun FeedScreen(
Icon(
Icons.Default.Lock,
contentDescription = null,
tint = if (bookmarkFilter.visibilityFilter == VisibilityFilter.PRIVATE_ONLY) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.visibilityFilter == VisibilityFilter.PRIVATE_ONLY) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Privés uniquement",
color = if (bookmarkFilter.visibilityFilter == VisibilityFilter.PRIVATE_ONLY) CyanPrimary else TextPrimary
color = if (bookmarkFilter.visibilityFilter == VisibilityFilter.PRIVATE_ONLY) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -1121,13 +1121,13 @@ fun FeedScreen(
}
)
Divider(color = TextMuted.copy(alpha = 0.2f))
Divider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f))
// Tag Filter Section
Text(
text = "TAGS",
style = MaterialTheme.typography.labelSmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
DropdownMenuItem(
@ -1139,11 +1139,11 @@ fun FeedScreen(
Icon(
Icons.Default.Label,
contentDescription = null,
tint = if (bookmarkFilter.tagFilter == TagFilter.ALL) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.tagFilter == TagFilter.ALL) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Tous les tags",
color = if (bookmarkFilter.tagFilter == TagFilter.ALL) CyanPrimary else TextPrimary
color = if (bookmarkFilter.tagFilter == TagFilter.ALL) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -1160,11 +1160,11 @@ fun FeedScreen(
Icon(
Icons.Default.LabelOff,
contentDescription = null,
tint = if (bookmarkFilter.tagFilter == TagFilter.UNTAGGED) CyanPrimary else TextSecondary
tint = if (bookmarkFilter.tagFilter == TagFilter.UNTAGGED) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Sans tags",
color = if (bookmarkFilter.tagFilter == TagFilter.UNTAGGED) CyanPrimary else TextPrimary
color = if (bookmarkFilter.tagFilter == TagFilter.UNTAGGED) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
)
}
},
@ -1173,7 +1173,7 @@ fun FeedScreen(
}
)
Divider(color = TextMuted.copy(alpha = 0.2f))
Divider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f))
// Reset button
DropdownMenuItem(
@ -1185,11 +1185,11 @@ fun FeedScreen(
Icon(
Icons.Default.Refresh,
contentDescription = null,
tint = TextSecondary
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
"Réinitialiser les filtres",
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
}
},
@ -1202,8 +1202,8 @@ fun FeedScreen(
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = DeepNavy.copy(alpha = 0.9f),
titleContentColor = TextPrimary
containerColor = MaterialTheme.colorScheme.background.copy(alpha = 0.9f),
titleContentColor = MaterialTheme.colorScheme.onBackground
)
)
@ -1220,7 +1220,7 @@ fun FeedScreen(
Row(
modifier = Modifier
.fillMaxWidth()
.background(DarkNavy)
.background(MaterialTheme.colorScheme.surface)
.padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.spacedBy(8.dp)
@ -1228,7 +1228,7 @@ fun FeedScreen(
Text(
"Filtering by:",
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(top = 6.dp)
)
@ -1240,8 +1240,8 @@ fun FeedScreen(
onClick = { viewModel.clearCollectionFilter() },
label = { Text(collectionName) },
colors = AssistChipDefaults.assistChipColors(
containerColor = CardBackground,
labelColor = CyanPrimary
containerColor = MaterialTheme.colorScheme.surfaceVariant,
labelColor = MaterialTheme.colorScheme.primary
)
)
}
@ -1282,7 +1282,7 @@ fun FeedScreen(
Icon(
Icons.Default.Close,
contentDescription = "Clear filter",
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier.size(18.dp)
)
}
@ -1300,7 +1300,7 @@ fun FeedScreen(
Icon(
Icons.Default.Search,
contentDescription = null,
tint = TextMuted
tint = MaterialTheme.colorScheme.outline
)
},
trailingIcon = {
@ -1311,7 +1311,7 @@ fun FeedScreen(
Icon(
Icons.Default.Close,
contentDescription = "Clear",
tint = TextMuted
tint = MaterialTheme.colorScheme.outline
)
}
}
@ -1324,8 +1324,8 @@ fun FeedScreen(
floatingActionButton = {
FloatingActionButton(
onClick = onNavigateToAdd,
containerColor = CyanPrimary,
contentColor = DeepNavy
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.background
) { Icon(Icons.Default.Add, contentDescription = "Add Link") }
},
containerColor = Color.Transparent
@ -1350,7 +1350,7 @@ fun FeedScreen(
Text(
"Failed to load links",
style = MaterialTheme.typography.titleMedium,
color = ErrorRed
color = MaterialTheme.colorScheme.error
)
Spacer(modifier = Modifier.height(8.dp))
IconButton(onClick = {
@ -1360,7 +1360,7 @@ fun FeedScreen(
Icon(
Icons.Default.Refresh,
contentDescription = "Refresh",
tint = CyanPrimary
tint = MaterialTheme.colorScheme.primary
)
}
}
@ -1377,7 +1377,7 @@ fun FeedScreen(
"No links found"
else "No links yet",
style = MaterialTheme.typography.titleMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(8.dp))
Text(
@ -1385,7 +1385,7 @@ fun FeedScreen(
"Try a different search"
else "Add your first link!",
style = MaterialTheme.typography.bodyMedium,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
}
}
@ -1447,7 +1447,7 @@ fun FeedScreen(
) {
CircularProgressIndicator(
modifier = Modifier.padding(16.dp),
color = CyanPrimary
color = MaterialTheme.colorScheme.primary
)
}
}
@ -1507,7 +1507,7 @@ fun FeedScreen(
) {
CircularProgressIndicator(
modifier = Modifier.padding(16.dp),
color = CyanPrimary
color = MaterialTheme.colorScheme.primary
)
}
}
@ -1568,7 +1568,7 @@ fun FeedScreen(
) {
CircularProgressIndicator(
modifier = Modifier.padding(16.dp),
color = CyanPrimary
color = MaterialTheme.colorScheme.primary
)
}
}
@ -1584,8 +1584,8 @@ fun FeedScreen(
refreshing = pagingItems.loadState.refresh is LoadState.Loading,
state = pullRefreshState,
modifier = Modifier.align(Alignment.TopCenter),
backgroundColor = DarkNavy,
contentColor = CyanPrimary
backgroundColor = MaterialTheme.colorScheme.surface,
contentColor = MaterialTheme.colorScheme.primary
)
}
}

View File

@ -37,7 +37,7 @@ import com.shaarit.domain.model.HealthStatus
import com.shaarit.domain.model.ShaarliLink
import com.shaarit.ui.components.GlassCard
import com.shaarit.ui.components.TagChip
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Typography
import dev.jeziellago.compose.markdowntext.MarkdownText
import coil.compose.AsyncImage
import androidx.compose.ui.layout.ContentScale
@ -78,7 +78,7 @@ fun ListViewItem(
modifier = Modifier.fillMaxWidth(),
onClick = { (onItemClick ?: { onLinkClick(link.url) }).invoke() },
onLongClick = onItemLongClick,
glowColor = if (isSelected) CyanPrimary else CyanPrimary
glowColor = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.primary
) {
Column {
Row(
@ -103,7 +103,7 @@ fun ListViewItem(
text = link.displayTitle,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = CyanPrimary,
color = MaterialTheme.colorScheme.primary,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
@ -118,9 +118,9 @@ fun ListViewItem(
text = link.url,
style = MaterialTheme.typography.bodySmall,
color = when (link.healthStatus) {
HealthStatus.DEAD -> ErrorRed
HealthStatus.OK -> TealSecondary
else -> TextMuted
HealthStatus.DEAD -> MaterialTheme.colorScheme.error
HealthStatus.OK -> MaterialTheme.colorScheme.secondary
else -> MaterialTheme.colorScheme.outline
},
maxLines = 1,
overflow = TextOverflow.Ellipsis
@ -143,7 +143,7 @@ fun ListViewItem(
Icon(
imageVector = Icons.Default.PushPin,
contentDescription = if (link.isPinned) "Désépingler" else "Épingler",
tint = if (link.isPinned) CyanPrimary else TextMuted,
tint = if (link.isPinned) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline,
modifier = Modifier.size(18.dp)
)
}
@ -151,7 +151,7 @@ fun ListViewItem(
Icon(
imageVector = Icons.Default.Visibility,
contentDescription = "View Details",
tint = CyanPrimary.copy(alpha = 0.7f),
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
modifier = Modifier.size(18.dp)
)
}
@ -159,7 +159,7 @@ fun ListViewItem(
Icon(
imageVector = Icons.Default.Edit,
contentDescription = "Edit",
tint = TealSecondary.copy(alpha = 0.7f),
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 0.7f),
modifier = Modifier.size(18.dp)
)
}
@ -167,7 +167,7 @@ fun ListViewItem(
Icon(
imageVector = Icons.Default.Delete,
contentDescription = "Delete",
tint = ErrorRed.copy(alpha = 0.7f),
tint = MaterialTheme.colorScheme.error.copy(alpha = 0.7f),
modifier = Modifier.size(18.dp)
)
}
@ -178,7 +178,7 @@ fun ListViewItem(
Spacer(modifier = Modifier.height(8.dp))
MarkdownText(
markdown = link.description,
style = MaterialTheme.typography.bodyMedium.copy(color = TextSecondary),
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onSurfaceVariant),
maxLines = 5,
modifier = Modifier.fillMaxWidth()
)
@ -203,7 +203,7 @@ fun ListViewItem(
Text(
text = link.date,
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
if (link.isPrivate) {
@ -214,13 +214,13 @@ fun ListViewItem(
Icon(
Icons.Default.Lock,
contentDescription = "Private",
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier.size(12.dp)
)
Text(
text = "Private",
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
}
}
@ -264,7 +264,7 @@ fun GridViewItem(
.heightIn(min = 220.dp),
onClick = { (onItemClick ?: { onLinkClick(link.url) }).invoke() },
onLongClick = onItemLongClick,
glowColor = if (isSelected) CyanPrimary else CyanPrimary
glowColor = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.primary
) {
Column(
modifier = Modifier.fillMaxSize(),
@ -301,9 +301,9 @@ fun GridViewItem(
style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.SemiBold,
color = when (link.healthStatus) {
HealthStatus.DEAD -> ErrorRed
HealthStatus.OK -> CyanPrimary
else -> CyanPrimary.copy(alpha = 0.7f)
HealthStatus.DEAD -> MaterialTheme.colorScheme.error
HealthStatus.OK -> MaterialTheme.colorScheme.primary
else -> MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)
},
maxLines = 2,
overflow = TextOverflow.Ellipsis,
@ -314,7 +314,7 @@ fun GridViewItem(
Icon(
imageVector = Icons.Default.PushPin,
contentDescription = "Épinglé",
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(16.dp)
)
}
@ -326,7 +326,7 @@ fun GridViewItem(
if (link.description.isNotBlank()) {
MarkdownText(
markdown = link.description,
style = MaterialTheme.typography.bodySmall.copy(color = TextSecondary),
style = MaterialTheme.typography.bodySmall.copy(color = MaterialTheme.colorScheme.onSurfaceVariant),
maxLines = 3,
modifier = Modifier.fillMaxWidth()
)
@ -344,7 +344,7 @@ fun GridViewItem(
Text(
text = "#$tag",
style = MaterialTheme.typography.labelSmall,
color = TealSecondary,
color = MaterialTheme.colorScheme.secondary,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
@ -353,7 +353,7 @@ fun GridViewItem(
Text(
text = "+${link.tags.size - 2}",
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
}
}
@ -379,14 +379,14 @@ fun GridViewItem(
Icon(
Icons.Default.Lock,
contentDescription = "Private",
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier.size(12.dp)
)
}
Text(
text = link.date.take(10),
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
}
@ -399,7 +399,7 @@ fun GridViewItem(
Icon(
imageVector = Icons.Default.PushPin,
contentDescription = if (link.isPinned) "Désépingler" else "Épingler",
tint = if (link.isPinned) CyanPrimary else TextMuted,
tint = if (link.isPinned) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline,
modifier = Modifier.size(14.dp)
)
}
@ -410,7 +410,7 @@ fun GridViewItem(
Icon(
imageVector = Icons.Default.Visibility,
contentDescription = "View Details",
tint = CyanPrimary.copy(alpha = 0.7f),
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
modifier = Modifier.size(14.dp)
)
}
@ -421,7 +421,7 @@ fun GridViewItem(
Icon(
imageVector = Icons.Default.Edit,
contentDescription = "Edit",
tint = TealSecondary.copy(alpha = 0.7f),
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 0.7f),
modifier = Modifier.size(14.dp)
)
}
@ -432,7 +432,7 @@ fun GridViewItem(
Icon(
imageVector = Icons.Default.Delete,
contentDescription = "Delete",
tint = ErrorRed.copy(alpha = 0.7f),
tint = MaterialTheme.colorScheme.error.copy(alpha = 0.7f),
modifier = Modifier.size(14.dp)
)
}
@ -481,7 +481,7 @@ fun CompactViewItem(
onClick = { (onItemClick ?: { onLinkClick(link.url) }).invoke() },
onLongClick = onItemLongClick
),
color = CardBackground.copy(alpha = 0.7f)
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.7f)
) {
Row(
modifier = Modifier
@ -506,7 +506,7 @@ fun CompactViewItem(
Icon(
imageVector = Icons.Default.PushPin,
contentDescription = "Épinglé",
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(14.dp)
)
}
@ -515,7 +515,7 @@ fun CompactViewItem(
Icon(
Icons.Default.Lock,
contentDescription = "Private",
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier.size(14.dp)
)
}
@ -531,9 +531,9 @@ fun CompactViewItem(
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium,
color = when (link.healthStatus) {
HealthStatus.DEAD -> ErrorRed
HealthStatus.OK -> CyanPrimary
else -> CyanPrimary.copy(alpha = 0.7f)
HealthStatus.DEAD -> MaterialTheme.colorScheme.error
HealthStatus.OK -> MaterialTheme.colorScheme.primary
else -> MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)
},
maxLines = 1,
overflow = TextOverflow.Ellipsis
@ -547,14 +547,14 @@ fun CompactViewItem(
Text(
text = link.date.take(10),
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
if (link.tags.isNotEmpty()) {
Text(
text = link.tags.take(2).joinToString { "#$it" },
style = MaterialTheme.typography.labelSmall,
color = TealSecondary,
color = MaterialTheme.colorScheme.secondary,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
@ -571,7 +571,7 @@ fun CompactViewItem(
Icon(
imageVector = Icons.Default.PushPin,
contentDescription = if (link.isPinned) "Désépingler" else "Épingler",
tint = if (link.isPinned) CyanPrimary else TextMuted,
tint = if (link.isPinned) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline,
modifier = Modifier.size(16.dp)
)
}
@ -579,7 +579,7 @@ fun CompactViewItem(
Icon(
imageVector = Icons.Default.Visibility,
contentDescription = "View Details",
tint = CyanPrimary.copy(alpha = 0.7f),
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
modifier = Modifier.size(16.dp)
)
}
@ -587,7 +587,7 @@ fun CompactViewItem(
Icon(
imageVector = Icons.Default.Edit,
contentDescription = "Edit",
tint = TealSecondary.copy(alpha = 0.7f),
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 0.7f),
modifier = Modifier.size(16.dp)
)
}
@ -595,7 +595,7 @@ fun CompactViewItem(
Icon(
imageVector = Icons.Default.Delete,
contentDescription = "Delete",
tint = ErrorRed.copy(alpha = 0.7f),
tint = MaterialTheme.colorScheme.error.copy(alpha = 0.7f),
modifier = Modifier.size(16.dp)
)
}
@ -615,14 +615,14 @@ fun DeleteConfirmationDialog(
) {
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("Delete Link", fontWeight = FontWeight.Bold, color = TextPrimary) },
title = { Text("Delete Link", fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onBackground) },
text = {
Column {
Text("Are you sure you want to delete this link?", color = TextSecondary)
Text("Are you sure you want to delete this link?", color = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(modifier = Modifier.height(8.dp))
Text(
linkTitle,
color = CyanPrimary,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Medium,
maxLines = 2,
overflow = TextOverflow.Ellipsis
@ -631,17 +631,17 @@ fun DeleteConfirmationDialog(
},
confirmButton = {
TextButton(onClick = onConfirm) {
Text("Delete", color = ErrorRed)
Text("Delete", color = MaterialTheme.colorScheme.error)
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text("Cancel", color = TextMuted)
Text("Cancel", color = MaterialTheme.colorScheme.outline)
}
},
containerColor = CardBackground,
titleContentColor = TextPrimary,
textContentColor = TextSecondary
containerColor = MaterialTheme.colorScheme.surfaceVariant,
titleContentColor = MaterialTheme.colorScheme.onBackground,
textContentColor = MaterialTheme.colorScheme.onSurfaceVariant
)
}
@ -691,7 +691,7 @@ fun LinkDetailsView(
text = link.displayTitle,
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
color = CyanPrimary,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.weight(1f)
)
IconButton(
@ -703,7 +703,7 @@ fun LinkDetailsView(
Icon(
imageVector = Icons.Default.Close,
contentDescription = "Close",
tint = TextSecondary
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -734,7 +734,7 @@ fun LinkDetailsView(
Text(
text = link.url,
style = MaterialTheme.typography.bodyMedium,
color = TealSecondary,
color = MaterialTheme.colorScheme.secondary,
modifier = Modifier
.clickable { onLinkClick(link.url) }
.padding(vertical = 4.dp)
@ -767,7 +767,7 @@ fun LinkDetailsView(
Text(
text = link.date,
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
if (link.isPrivate) {
Row(
@ -777,34 +777,34 @@ fun LinkDetailsView(
Icon(
Icons.Default.Lock,
contentDescription = "Private",
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier.size(14.dp)
)
Text(
text = "Private",
style = MaterialTheme.typography.labelSmall,
color = TextMuted
color = MaterialTheme.colorScheme.outline
)
}
}
}
Spacer(modifier = Modifier.height(24.dp))
Divider(color = TextMuted.copy(alpha = 0.2f))
Divider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f))
Spacer(modifier = Modifier.height(24.dp))
// Description
if (link.description.isNotBlank()) {
MarkdownText(
markdown = link.description,
style = MaterialTheme.typography.bodyMedium.copy(color = TextPrimary),
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onBackground),
modifier = Modifier.fillMaxWidth()
)
} else {
Text(
text = "No description",
style = MaterialTheme.typography.bodyMedium,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
fontStyle = androidx.compose.ui.text.font.FontStyle.Italic
)
}
@ -834,7 +834,7 @@ fun HealthStatusIcon(
Icon(
imageVector = Icons.Default.HelpOutline,
contentDescription = "Non testé",
tint = TextMuted,
tint = MaterialTheme.colorScheme.outline,
modifier = modifier
)
}
@ -842,7 +842,7 @@ fun HealthStatusIcon(
Icon(
imageVector = Icons.Default.CheckCircle,
contentDescription = "Lien fonctionnel",
tint = SuccessGreen,
tint = Color(0xFF10B981),
modifier = modifier
)
}
@ -858,7 +858,7 @@ fun HealthStatusIcon(
Icon(
imageVector = Icons.Default.BrokenImage,
contentDescription = "Lien mort",
tint = ErrorRed,
tint = MaterialTheme.colorScheme.error,
modifier = modifier
)
}

View File

@ -17,7 +17,7 @@ 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.shaarit.ui.theme.*
import com.shaarit.ui.theme.Typography
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -30,7 +30,7 @@ fun HelpScreen(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(colors = listOf(DeepNavy, DarkNavy))
brush = Brush.verticalGradient(colors = listOf(MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.surface))
)
) {
Scaffold(
@ -48,13 +48,13 @@ fun HelpScreen(
Icon(
Icons.Default.ArrowBack,
contentDescription = "Retour",
tint = TextPrimary
tint = MaterialTheme.colorScheme.onBackground
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = DeepNavy.copy(alpha = 0.9f),
titleContentColor = TextPrimary
containerColor = MaterialTheme.colorScheme.background.copy(alpha = 0.9f),
titleContentColor = MaterialTheme.colorScheme.onBackground
)
)
},
@ -600,7 +600,7 @@ fun HelpScreen(
Text(
text = "ShaarIt v1.0 • © 2026",
style = MaterialTheme.typography.labelSmall,
color = TextMuted.copy(alpha = 0.6f),
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.6f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
@ -618,9 +618,9 @@ private fun HelpHeader() {
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = CyanPrimary.copy(alpha = 0.15f)
containerColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.15f)
),
border = androidx.compose.foundation.BorderStroke(1.dp, CyanPrimary.copy(alpha = 0.3f))
border = androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.3f))
) {
Row(
modifier = Modifier
@ -632,7 +632,7 @@ private fun HelpHeader() {
modifier = Modifier
.size(48.dp)
.background(
color = CyanPrimary.copy(alpha = 0.2f),
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.2f),
shape = MaterialTheme.shapes.medium
),
contentAlignment = Alignment.Center
@ -640,7 +640,7 @@ private fun HelpHeader() {
Icon(
imageVector = Icons.Default.MenuBook,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(28.dp)
)
}
@ -650,12 +650,12 @@ private fun HelpHeader() {
text = "Guide Complet",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
Text(
text = "Tout ce qu'il faut savoir pour maîtriser ShaarIt",
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -673,7 +673,7 @@ private fun HelpSection(
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = CardBackground
containerColor = MaterialTheme.colorScheme.surfaceVariant
)
) {
Column {
@ -691,7 +691,7 @@ private fun HelpSection(
Icon(
imageVector = icon,
contentDescription = null,
tint = CyanPrimary,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(12.dp))
@ -699,13 +699,13 @@ private fun HelpSection(
text = title,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = TextPrimary,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.weight(1f)
)
Icon(
imageVector = if (isExpanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore,
contentDescription = if (isExpanded) "Réduire" else "Développer",
tint = TextMuted
tint = MaterialTheme.colorScheme.outline
)
}
}
@ -720,7 +720,7 @@ private fun HelpSection(
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
) {
Divider(color = TextMuted.copy(alpha = 0.2f))
Divider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f))
Spacer(modifier = Modifier.height(12.dp))
content()
}
@ -744,7 +744,7 @@ private fun HelpSubsection(
Icon(
imageVector = icon,
contentDescription = null,
tint = TealSecondary,
tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(20.dp)
)
Spacer(modifier = Modifier.width(12.dp))
@ -753,13 +753,13 @@ private fun HelpSubsection(
text = title,
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Medium,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
Spacer(modifier = Modifier.height(2.dp))
Text(
text = description,
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -770,7 +770,7 @@ private fun HelpText(text: String) {
Text(
text = text,
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
@ -780,7 +780,7 @@ private fun HelpSubtitle(text: String) {
text = text,
style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.SemiBold,
color = CyanLight
color = MaterialTheme.colorScheme.tertiary
)
}
@ -792,14 +792,14 @@ private fun HelpFeatureList(items: List<String>) {
Icon(
imageVector = Icons.Default.CheckCircle,
contentDescription = null,
tint = SuccessGreen,
tint = Color(0xFF10B981),
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = item,
style = MaterialTheme.typography.bodyMedium,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
}
}
@ -814,13 +814,13 @@ private fun HelpBulletList(items: List<String>) {
Text(
text = "",
style = MaterialTheme.typography.bodyMedium,
color = CyanPrimary,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.width(16.dp)
)
Text(
text = item,
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -836,7 +836,7 @@ private fun HelpNumberedList(items: List<Pair<String, String>>) {
modifier = Modifier
.size(24.dp)
.background(
color = CyanPrimary.copy(alpha = 0.2f),
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.2f),
shape = MaterialTheme.shapes.small
),
contentAlignment = Alignment.Center
@ -845,7 +845,7 @@ private fun HelpNumberedList(items: List<Pair<String, String>>) {
text = "${index + 1}",
style = MaterialTheme.typography.labelMedium,
fontWeight = FontWeight.Bold,
color = CyanPrimary
color = MaterialTheme.colorScheme.primary
)
}
Spacer(modifier = Modifier.width(12.dp))
@ -854,14 +854,14 @@ private fun HelpNumberedList(items: List<Pair<String, String>>) {
text = title,
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
if (description.isNotBlank()) {
Spacer(modifier = Modifier.height(2.dp))
Text(
text = description,
style = MaterialTheme.typography.bodySmall,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -878,7 +878,7 @@ private fun HelpInfoCard(
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = CardBackgroundElevated
containerColor = MaterialTheme.colorScheme.primaryContainer
)
) {
Column(
@ -888,7 +888,7 @@ private fun HelpInfoCard(
Icon(
imageVector = Icons.Default.Info,
contentDescription = null,
tint = TealSecondary,
tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
@ -896,14 +896,14 @@ private fun HelpInfoCard(
text = title,
style = MaterialTheme.typography.labelLarge,
fontWeight = FontWeight.SemiBold,
color = TealSecondary
color = MaterialTheme.colorScheme.secondary
)
}
Spacer(modifier = Modifier.height(8.dp))
Text(
text = content,
style = MaterialTheme.typography.bodySmall,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -915,7 +915,7 @@ private fun HelpTip(text: String) {
modifier = Modifier
.fillMaxWidth()
.background(
color = SuccessGreen.copy(alpha = 0.1f),
color = Color(0xFF10B981).copy(alpha = 0.1f),
shape = MaterialTheme.shapes.small
)
.padding(12.dp),
@ -924,14 +924,14 @@ private fun HelpTip(text: String) {
Icon(
imageVector = Icons.Default.Lightbulb,
contentDescription = null,
tint = SuccessGreen,
tint = Color(0xFF10B981),
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = text,
style = MaterialTheme.typography.bodySmall,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
}
}

View File

@ -5,10 +5,16 @@ import android.net.Uri
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
@ -18,14 +24,19 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.shaarit.data.export.BookmarkImporter
import com.shaarit.ui.theme.AppTheme
import com.shaarit.ui.theme.ThemePreferences
import com.shaarit.ui.theme.getColorSchemeForTheme
import java.text.SimpleDateFormat
import java.util.*
@ -34,10 +45,12 @@ import java.util.*
fun SettingsScreen(
onNavigateBack: () -> Unit,
onNavigateToDashboard: () -> Unit,
viewModel: SettingsViewModel = hiltViewModel()
viewModel: SettingsViewModel = hiltViewModel(),
themePreferences: ThemePreferences = viewModel.themePreferences
) {
val context = LocalContext.current
val uiState by viewModel.uiState.collectAsState()
val currentTheme by themePreferences.currentTheme.collectAsState()
// Export JSON
val exportJsonLauncher = rememberLauncherForActivityResult(
@ -101,8 +114,21 @@ fun SettingsScreen(
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
// Theme Section
item {
SettingsSection(title = "Apparence")
}
item {
ThemePickerItem(
currentTheme = currentTheme,
onThemeSelected = { themePreferences.setTheme(it) }
)
}
// AI Section - Gemini API Key
item {
Spacer(modifier = Modifier.height(16.dp))
SettingsSection(title = "Intelligence Artificielle")
}
@ -668,3 +694,153 @@ private fun HealthCheckStatusItem(
}
}
}
@Composable
private fun ThemePickerItem(
currentTheme: AppTheme,
onThemeSelected: (AppTheme) -> Unit
) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Default.Palette,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.width(16.dp))
Column {
Text(
text = "Th\u00e8me",
style = MaterialTheme.typography.bodyLarge
)
Text(
text = currentTheme.displayName,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
Spacer(modifier = Modifier.height(16.dp))
LazyRow(
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
items(AppTheme.entries.toList()) { theme ->
ThemePreviewCard(
theme = theme,
isSelected = theme == currentTheme,
onClick = { onThemeSelected(theme) }
)
}
}
}
}
}
@Composable
private fun ThemePreviewCard(
theme: AppTheme,
isSelected: Boolean,
onClick: () -> Unit
) {
val colors = getColorSchemeForTheme(theme)
val borderColor = if (isSelected) MaterialTheme.colorScheme.primary else colors.outline
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.width(100.dp)
.clip(RoundedCornerShape(12.dp))
.clickable(onClick = onClick)
) {
// Mini preview card
Box(
modifier = Modifier
.fillMaxWidth()
.height(72.dp)
.clip(RoundedCornerShape(12.dp))
.border(
BorderStroke(
if (isSelected) 2.dp else 1.dp,
borderColor
),
RoundedCornerShape(12.dp)
)
.background(colors.background)
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(8.dp),
verticalArrangement = Arrangement.SpaceBetween
) {
// Simulated top bar
Box(
modifier = Modifier
.fillMaxWidth()
.height(6.dp)
.clip(RoundedCornerShape(3.dp))
.background(colors.surface)
)
// Simulated content lines
Column(verticalArrangement = Arrangement.spacedBy(3.dp)) {
Box(
modifier = Modifier
.fillMaxWidth(0.7f)
.height(4.dp)
.clip(RoundedCornerShape(2.dp))
.background(colors.onBackground.copy(alpha = 0.6f))
)
Box(
modifier = Modifier
.fillMaxWidth(0.5f)
.height(4.dp)
.clip(RoundedCornerShape(2.dp))
.background(colors.onSurfaceVariant.copy(alpha = 0.4f))
)
}
// Simulated accent button
Box(
modifier = Modifier
.width(24.dp)
.height(6.dp)
.clip(RoundedCornerShape(3.dp))
.background(colors.primary)
)
}
}
Spacer(modifier = Modifier.height(6.dp))
// Theme name
Text(
text = theme.displayName,
style = MaterialTheme.typography.labelSmall,
color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
// Description
Text(
text = theme.description,
style = MaterialTheme.typography.labelSmall.copy(
fontSize = androidx.compose.ui.unit.TextUnit(9f, androidx.compose.ui.unit.TextUnitType.Sp)
),
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f),
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}
}

View File

@ -11,6 +11,7 @@ import com.shaarit.data.sync.SyncManager
import com.shaarit.data.sync.SyncState
import com.shaarit.data.worker.LinkHealthCheckWorker
import com.shaarit.domain.usecase.ClassifyBookmarksUseCase
import com.shaarit.ui.theme.ThemePreferences
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
@ -29,7 +30,8 @@ class SettingsViewModel @Inject constructor(
private val linkDao: LinkDao,
private val classifyBookmarksUseCase: ClassifyBookmarksUseCase,
private val tokenManager: TokenManager,
private val workManager: WorkManager
private val workManager: WorkManager,
val themePreferences: ThemePreferences
) : ViewModel() {
private val _uiState = MutableStateFlow(SettingsUiState())

View File

@ -30,7 +30,7 @@ import com.shaarit.domain.model.ShaarliTag
import com.shaarit.ui.components.GlassCard
import com.shaarit.ui.components.PremiumTextField
import com.shaarit.ui.components.TagChip
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Typography
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -48,7 +48,7 @@ fun TagsScreen(
.background(
brush =
Brush.verticalGradient(
colors = listOf(DeepNavy, DarkNavy)
colors = listOf(MaterialTheme.colorScheme.background, MaterialTheme.colorScheme.surface)
)
)
) {
@ -67,14 +67,14 @@ fun TagsScreen(
Icon(
Icons.Default.ArrowBack,
contentDescription = "Back",
tint = TextPrimary
tint = MaterialTheme.colorScheme.onBackground
)
}
},
colors =
TopAppBarDefaults.topAppBarColors(
containerColor = DeepNavy.copy(alpha = 0.9f),
titleContentColor = TextPrimary
containerColor = MaterialTheme.colorScheme.background.copy(alpha = 0.9f),
titleContentColor = MaterialTheme.colorScheme.onBackground
)
)
@ -85,7 +85,7 @@ fun TagsScreen(
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp),
placeholder = "Search tags...",
leadingIcon = {
Icon(Icons.Default.Search, contentDescription = null, tint = TextMuted)
Icon(Icons.Default.Search, contentDescription = null, tint = MaterialTheme.colorScheme.outline)
},
trailingIcon = {
if (searchQuery.isNotEmpty()) {
@ -93,7 +93,7 @@ fun TagsScreen(
Icon(
Icons.Default.Close,
contentDescription = "Clear",
tint = TextMuted
tint = MaterialTheme.colorScheme.outline
)
}
}
@ -103,7 +103,7 @@ fun TagsScreen(
when (val state = uiState) {
is TagsUiState.Loading -> {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
CircularProgressIndicator(color = CyanPrimary)
CircularProgressIndicator(color = MaterialTheme.colorScheme.primary)
}
}
is TagsUiState.Error -> {
@ -112,13 +112,13 @@ fun TagsScreen(
Text(
"Failed to load tags",
style = MaterialTheme.typography.titleMedium,
color = ErrorRed
color = MaterialTheme.colorScheme.error
)
Spacer(modifier = Modifier.height(8.dp))
Text(
state.message,
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
@ -139,7 +139,7 @@ fun TagsScreen(
private fun TagsGridView(tags: List<ShaarliTag>, onTagClick: (ShaarliTag) -> Unit) {
if (tags.isEmpty()) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text("No tags found", style = MaterialTheme.typography.bodyLarge, color = TextSecondary)
Text("No tags found", style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
} else {
LazyVerticalGrid(
@ -153,13 +153,13 @@ private fun TagsGridView(tags: List<ShaarliTag>, onTagClick: (ShaarliTag) -> Uni
@Composable
private fun TagGridItem(tag: ShaarliTag, onClick: () -> Unit) {
GlassCard(modifier = Modifier.fillMaxWidth(), onClick = onClick, glowColor = TealSecondary) {
GlassCard(modifier = Modifier.fillMaxWidth(), onClick = onClick, glowColor = MaterialTheme.colorScheme.secondary) {
Column(modifier = Modifier.padding(4.dp)) {
Text(
text = "#${tag.name}",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = CyanPrimary,
color = MaterialTheme.colorScheme.primary,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
@ -167,7 +167,7 @@ private fun TagGridItem(tag: ShaarliTag, onClick: () -> Unit) {
Text(
text = "${tag.occurrences} links",
style = MaterialTheme.typography.labelMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}

View File

@ -40,7 +40,7 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Typography
import dev.jeziellago.compose.markdowntext.MarkdownText
import java.text.SimpleDateFormat
import java.util.*
@ -210,10 +210,10 @@ fun SimpleMarkdownEditor(
// Zone d'édition principale (sans la toolbar - elle sera flottante)
Box(
modifier = modifier
.background(CardBackgroundElevated, RoundedCornerShape(12.dp))
.background(MaterialTheme.colorScheme.primaryContainer, RoundedCornerShape(12.dp))
.border(
width = if (internalState.isFocused) 2.dp else 1.dp,
color = if (internalState.isFocused) CyanPrimary else CyanPrimary.copy(alpha = 0.2f),
color = if (internalState.isFocused) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.primary.copy(alpha = 0.2f),
shape = RoundedCornerShape(12.dp)
)
.padding(16.dp)
@ -240,11 +240,11 @@ fun SimpleMarkdownEditor(
.focusRequester(focusRequester)
.onFocusChanged { internalState.isFocused = it.isFocused },
textStyle = TextStyle(
color = TextPrimary,
color = MaterialTheme.colorScheme.onBackground,
fontSize = if (isNoteMode) 17.sp else 15.sp,
lineHeight = if (isNoteMode) 26.sp else 22.sp
),
cursorBrush = SolidColor(CyanPrimary),
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
readOnly = readOnly,
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Sentences,
@ -254,7 +254,7 @@ fun SimpleMarkdownEditor(
if (internalState.textFieldValue.text.isEmpty()) {
Text(
text = placeholder,
color = TextSecondary.copy(alpha = 0.6f),
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
fontSize = if (isNoteMode) 17.sp else 15.sp
)
}
@ -366,7 +366,7 @@ fun FloatingMarkdownToolbar(
modifier = modifier.padding(bottom = bottomPadding)
) {
Surface(
color = CardBackground,
color = MaterialTheme.colorScheme.surfaceVariant,
shadowElevation = 16.dp,
tonalElevation = 8.dp,
modifier = Modifier.fillMaxWidth()
@ -417,7 +417,7 @@ fun MarkorStyleToolbar(
modifier: Modifier = Modifier
) {
Surface(
color = CardBackground.copy(alpha = 0.95f),
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.95f),
shadowElevation = 8.dp,
modifier = modifier.fillMaxWidth()
) {
@ -449,7 +449,7 @@ private fun MarkorToolButton(
Surface(
onClick = onClick,
shape = RoundedCornerShape(8.dp),
color = CardBackgroundElevated,
color = MaterialTheme.colorScheme.primaryContainer,
modifier = Modifier.size(42.dp)
) {
Box(
@ -459,7 +459,7 @@ private fun MarkorToolButton(
Icon(
imageVector = tool.icon,
contentDescription = tool.label,
tint = TextSecondary,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(22.dp)
)
}
@ -644,21 +644,21 @@ fun MarkdownPreview(
Box(
modifier = modifier
.fillMaxWidth()
.background(CardBackgroundElevated, RoundedCornerShape(12.dp))
.border(1.dp, CyanPrimary.copy(alpha = 0.2f), RoundedCornerShape(12.dp))
.background(MaterialTheme.colorScheme.primaryContainer, RoundedCornerShape(12.dp))
.border(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.2f), RoundedCornerShape(12.dp))
.padding(16.dp)
.verticalScroll(rememberScrollState())
) {
if (markdown.isBlank()) {
Text(
text = "Aucun contenu à prévisualiser...",
color = TextSecondary.copy(alpha = 0.6f),
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
style = MaterialTheme.typography.bodyMedium
)
} else {
MarkdownText(
markdown = markdown,
color = TextPrimary,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.fillMaxWidth()
)
}
@ -786,8 +786,8 @@ private fun ModeToggleButton(
Surface(
onClick = onClick,
shape = RoundedCornerShape(8.dp),
color = if (isSelected) CyanPrimary.copy(alpha = 0.15f) else CardBackground,
border = if (isSelected) androidx.compose.foundation.BorderStroke(1.dp, CyanPrimary) else null,
color = if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.15f) else MaterialTheme.colorScheme.surfaceVariant,
border = if (isSelected) androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.primary) else null,
modifier = modifier
) {
Row(
@ -798,13 +798,13 @@ private fun ModeToggleButton(
Icon(
imageVector = icon,
contentDescription = null,
tint = if (isSelected) CyanPrimary else TextSecondary,
tint = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(6.dp))
Text(
text = label,
color = if (isSelected) CyanPrimary else TextSecondary,
color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelMedium,
fontWeight = if (isSelected) FontWeight.Medium else FontWeight.Normal
)
@ -820,13 +820,13 @@ fun MarkdownHelp(modifier: Modifier = Modifier) {
Column(
modifier = modifier
.fillMaxWidth()
.background(CardBackground.copy(alpha = 0.5f), RoundedCornerShape(8.dp))
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f), RoundedCornerShape(8.dp))
.padding(12.dp)
) {
Text(
text = "Formatage rapide :",
style = MaterialTheme.typography.labelSmall,
color = TextMuted,
color = MaterialTheme.colorScheme.outline,
fontWeight = FontWeight.Medium
)
Spacer(modifier = Modifier.height(6.dp))
@ -850,13 +850,13 @@ fun MarkdownHelp(modifier: Modifier = Modifier) {
@Composable
private fun HelpChip(text: String) {
Surface(
color = CardBackgroundElevated,
color = MaterialTheme.colorScheme.primaryContainer,
shape = RoundedCornerShape(4.dp)
) {
Text(
text = text,
style = MaterialTheme.typography.labelSmall,
color = TextSecondary,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace
)

View File

@ -24,7 +24,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.shaarit.ui.theme.*
import com.shaarit.ui.theme.Typography
/** A glassmorphism-styled card with subtle border glow effect */
@OptIn(ExperimentalFoundationApi::class)
@ -33,7 +33,7 @@ fun GlassCard(
modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null,
onLongClick: (() -> Unit)? = null,
glowColor: Color = CyanPrimary,
glowColor: Color = MaterialTheme.colorScheme.primary,
content: @Composable ColumnScope.() -> Unit
) {
val interactionSource = remember { MutableInteractionSource() }
@ -77,8 +77,8 @@ fun GlassCard(
Brush.verticalGradient(
colors =
listOf(
CardBackground.copy(alpha = 0.95f),
CardBackgroundElevated.copy(
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.95f),
MaterialTheme.colorScheme.primaryContainer.copy(
alpha = 0.9f
)
)
@ -134,9 +134,9 @@ fun GradientButton(
Brush.horizontalGradient(
colors =
if (enabled) {
listOf(TealSecondary, CyanPrimary)
listOf(MaterialTheme.colorScheme.secondary, MaterialTheme.colorScheme.primary)
} else {
listOf(TextMuted, TextMuted)
listOf(MaterialTheme.colorScheme.outline, MaterialTheme.colorScheme.outline)
}
)
@ -150,8 +150,8 @@ fun GradientButton(
.shadow(
elevation = if (isPressed) 4.dp else 12.dp,
shape = RoundedCornerShape(12.dp),
ambientColor = CyanPrimary.copy(alpha = 0.3f),
spotColor = CyanPrimary.copy(alpha = 0.4f)
ambientColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.3f),
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.4f)
)
.clip(RoundedCornerShape(12.dp))
.background(gradient)
@ -176,7 +176,7 @@ fun GradientButton(
text = text,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = DeepNavy
color = MaterialTheme.colorScheme.background
)
}
}
@ -194,19 +194,19 @@ fun TagChip(
val backgroundColor by
animateColorAsState(
targetValue =
if (isSelected) CyanPrimary.copy(alpha = 0.2f) else CardBackground,
if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.2f) else MaterialTheme.colorScheme.surfaceVariant,
animationSpec = tween(200)
)
val borderColor by
animateColorAsState(
targetValue = if (isSelected) CyanPrimary else TextMuted.copy(alpha = 0.3f),
targetValue = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline.copy(alpha = 0.3f),
animationSpec = tween(200)
)
val textColor by
animateColorAsState(
targetValue = if (isSelected) CyanPrimary else TextSecondary,
targetValue = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
animationSpec = tween(200)
)
@ -258,7 +258,7 @@ fun PremiumTextField(
onValueChange = onValueChange,
modifier = modifier,
label = label?.let { { Text(it) } },
placeholder = placeholder?.let { { Text(it, color = TextMuted) } },
placeholder = placeholder?.let { { Text(it, color = MaterialTheme.colorScheme.outline) } },
singleLine = singleLine,
minLines = minLines,
leadingIcon = leadingIcon,
@ -278,15 +278,15 @@ fun PremiumTextField(
},
colors =
OutlinedTextFieldDefaults.colors(
focusedBorderColor = CyanPrimary,
unfocusedBorderColor = SurfaceVariant,
focusedLabelColor = CyanPrimary,
unfocusedLabelColor = TextSecondary,
cursorColor = CyanPrimary,
focusedContainerColor = CardBackground.copy(alpha = 0.5f),
unfocusedContainerColor = CardBackground.copy(alpha = 0.3f),
errorBorderColor = ErrorRed,
errorLabelColor = ErrorRed
focusedBorderColor = MaterialTheme.colorScheme.primary,
unfocusedBorderColor = MaterialTheme.colorScheme.outlineVariant,
focusedLabelColor = MaterialTheme.colorScheme.primary,
unfocusedLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
cursorColor = MaterialTheme.colorScheme.primary,
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f),
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f),
errorBorderColor = MaterialTheme.colorScheme.error,
errorLabelColor = MaterialTheme.colorScheme.error
),
shape = RoundedCornerShape(12.dp)
)
@ -310,13 +310,13 @@ fun SectionHeader(
text = title,
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
color = TextPrimary
color = MaterialTheme.colorScheme.onBackground
)
if (subtitle != null) {
Text(
text = subtitle,
style = MaterialTheme.typography.bodyMedium,
color = TextSecondary
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}

View File

@ -7,6 +7,7 @@ import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Surface
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -16,8 +17,6 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.shaarit.ui.theme.CardBackground
import com.shaarit.ui.theme.CardBackgroundElevated
fun Modifier.shimmerEffect(): Modifier = composed {
val transition = rememberInfiniteTransition(label = "shimmer")
@ -53,7 +52,7 @@ fun SkeletonLinkCard(
.fillMaxWidth()
.height(200.dp)
.clip(RoundedCornerShape(16.dp)), // Match GlassCard shape
color = CardBackground.copy(alpha = 0.5f)
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
) {
Column(
modifier = Modifier

View File

@ -0,0 +1,62 @@
package com.shaarit.ui.theme
import android.content.Context
import android.content.SharedPreferences
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
import javax.inject.Singleton
enum class AppTheme(
val displayName: String,
val description: String
) {
DEFAULT("ShaarIt", "Le thème original de l'application"),
GITHUB("GitHub", "Mode sombre équilibré, contrastes doux"),
LINEAR("Linear", "Dégradés subtils, teintes sombres douces"),
SPOTIFY("Spotify", "Noir pur avec accents verts"),
NOTION("Notion", "Sombre épuré, optimisé pour la lecture"),
DISCORD("Discord", "Gris bleuté, référence des interfaces communautaires"),
DRACULA("Dracula", "Sombre emblématique, accents rose, violet et vert"),
ONE_DARK_PRO("One Dark Pro", "Inspiré d'Atom, contraste doux bleuté"),
TOKYO_NIGHT("Tokyo Night", "Néons de Tokyo, bleu profond et couleurs électriques"),
NORD("Nord", "Style arctique, bleus froids et gris clairs sereins"),
NIGHT_OWL("Night Owl", "Optimisé pour la nuit, accessibilité renforcée"),
ANTHRACITE("Anthracite", "Gris mat Material Design, réduit la fatigue oculaire"),
CYBERPUNK("Cyberpunk", "Néons futuristes, cyan et magenta vibrants"),
NAVY_ELEGANCE("Navy Élégance", "Bleu marine profond, touches dorées luxueuses"),
EARTHY("Tons Terreux", "Verts forêt et bruns chocolat, ambiance organique");
companion object {
fun fromName(name: String): AppTheme {
return entries.find { it.name == name } ?: DEFAULT
}
}
}
@Singleton
class ThemePreferences @Inject constructor(
@ApplicationContext private val context: Context
) {
private val prefs: SharedPreferences =
context.getSharedPreferences("theme_prefs", Context.MODE_PRIVATE)
private val _currentTheme = MutableStateFlow(loadTheme())
val currentTheme: StateFlow<AppTheme> = _currentTheme.asStateFlow()
private fun loadTheme(): AppTheme {
val name = prefs.getString(KEY_THEME, AppTheme.DEFAULT.name) ?: AppTheme.DEFAULT.name
return AppTheme.fromName(name)
}
fun setTheme(theme: AppTheme) {
prefs.edit().putString(KEY_THEME, theme.name).apply()
_currentTheme.value = theme
}
companion object {
private const val KEY_THEME = "selected_theme"
}
}

View File

@ -1,18 +1,12 @@
package com.shaarit.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
@ -47,7 +41,8 @@ val GradientEnd = Color(0xFF00D4AA)
val Purple = Color(0xFFA855F7)
val PurpleLight = Color(0xFFC084FC)
private val DarkColorScheme =
// ── Default Theme (ShaarIt) ──
private val DefaultDarkColorScheme =
darkColorScheme(
primary = CyanPrimary,
onPrimary = DeepNavy,
@ -73,64 +68,414 @@ private val DarkColorScheme =
onErrorContainer = Color(0xFFFCA5A5)
)
private val LightColorScheme =
lightColorScheme(
primary = Color(0xFF0891B2),
onPrimary = Color.White,
primaryContainer = Color(0xFFCFFAFE),
onPrimaryContainer = Color(0xFF164E63),
secondary = Color(0xFF0284C7),
onSecondary = Color.White,
background = Color(0xFFF8FAFC),
onBackground = Color(0xFF0F172A),
surface = Color.White,
onSurface = Color(0xFF0F172A),
surfaceVariant = Color(0xFFF1F5F9),
onSurfaceVariant = Color(0xFF475569)
// ── GitHub (Smooth Dark) ──
private val GitHubDarkColorScheme =
darkColorScheme(
primary = Color(0xFF58A6FF),
onPrimary = Color(0xFF0D1117),
primaryContainer = Color(0xFF1F2937),
onPrimaryContainer = Color(0xFF79C0FF),
secondary = Color(0xFF3FB950),
onSecondary = Color(0xFF0D1117),
secondaryContainer = Color(0xFF1C2D22),
onSecondaryContainer = Color(0xFF56D364),
tertiary = Color(0xFFD2A8FF),
onTertiary = Color(0xFF0D1117),
background = Color(0xFF0D1117),
onBackground = Color(0xFFC9D1D9),
surface = Color(0xFF161B22),
onSurface = Color(0xFFC9D1D9),
surfaceVariant = Color(0xFF21262D),
onSurfaceVariant = Color(0xFF8B949E),
outline = Color(0xFF30363D),
outlineVariant = Color(0xFF21262D),
error = Color(0xFFF85149),
onError = Color.White,
errorContainer = Color(0xFF490202),
onErrorContainer = Color(0xFFFFA198)
)
// ── Linear (Soft Dark) ──
private val LinearDarkColorScheme =
darkColorScheme(
primary = Color(0xFF5E6AD2),
onPrimary = Color.White,
primaryContainer = Color(0xFF2A2B3D),
onPrimaryContainer = Color(0xFF8B8FE8),
secondary = Color(0xFF4EA7FC),
onSecondary = Color(0xFF12131A),
secondaryContainer = Color(0xFF1E2A3A),
onSecondaryContainer = Color(0xFF7DC4FF),
tertiary = Color(0xFFE8A861),
onTertiary = Color(0xFF12131A),
background = Color(0xFF12131A),
onBackground = Color(0xFFEEEFF2),
surface = Color(0xFF1B1C24),
onSurface = Color(0xFFEEEFF2),
surfaceVariant = Color(0xFF22232E),
onSurfaceVariant = Color(0xFF8A8F98),
outline = Color(0xFF3B3D4A),
outlineVariant = Color(0xFF2A2B3D),
error = Color(0xFFEB5757),
onError = Color.White,
errorContainer = Color(0xFF3D1515),
onErrorContainer = Color(0xFFFF9B9B)
)
// ── Spotify (Jet Black) ──
private val SpotifyDarkColorScheme =
darkColorScheme(
primary = Color(0xFF1DB954),
onPrimary = Color.Black,
primaryContainer = Color(0xFF1A3D27),
onPrimaryContainer = Color(0xFF1ED760),
secondary = Color(0xFF1DB954),
onSecondary = Color.Black,
secondaryContainer = Color(0xFF1A3D27),
onSecondaryContainer = Color(0xFF1ED760),
tertiary = Color(0xFFB3B3B3),
onTertiary = Color.Black,
background = Color(0xFF000000),
onBackground = Color(0xFFFFFFFF),
surface = Color(0xFF121212),
onSurface = Color(0xFFFFFFFF),
surfaceVariant = Color(0xFF1A1A1A),
onSurfaceVariant = Color(0xFFB3B3B3),
outline = Color(0xFF333333),
outlineVariant = Color(0xFF282828),
error = Color(0xFFE22134),
onError = Color.White,
errorContainer = Color(0xFF3D0A0F),
onErrorContainer = Color(0xFFFF6B7A)
)
// ── Notion (Clean Dark) ──
private val NotionDarkColorScheme =
darkColorScheme(
primary = Color(0xFF529CCA),
onPrimary = Color(0xFF191919),
primaryContainer = Color(0xFF2A3A4A),
onPrimaryContainer = Color(0xFF7AB8E0),
secondary = Color(0xFFE07A5F),
onSecondary = Color(0xFF191919),
secondaryContainer = Color(0xFF3D2A22),
onSecondaryContainer = Color(0xFFF0A08A),
tertiary = Color(0xFF81B29A),
onTertiary = Color(0xFF191919),
background = Color(0xFF191919),
onBackground = Color(0xFFE0E0E0),
surface = Color(0xFF202020),
onSurface = Color(0xFFE0E0E0),
surfaceVariant = Color(0xFF2B2B2B),
onSurfaceVariant = Color(0xFF9B9B9B),
outline = Color(0xFF3E3E3E),
outlineVariant = Color(0xFF2F2F2F),
error = Color(0xFFEB5757),
onError = Color.White,
errorContainer = Color(0xFF3D1515),
onErrorContainer = Color(0xFFFF9B9B)
)
// ── Discord (Blurple Dark) ──
private val DiscordDarkColorScheme =
darkColorScheme(
primary = Color(0xFF5865F2),
onPrimary = Color.White,
primaryContainer = Color(0xFF3C45A5),
onPrimaryContainer = Color(0xFF9BA2FF),
secondary = Color(0xFF57F287),
onSecondary = Color(0xFF1E2124),
secondaryContainer = Color(0xFF234D35),
onSecondaryContainer = Color(0xFF7DFFA8),
tertiary = Color(0xFFFEE75C),
onTertiary = Color(0xFF1E2124),
background = Color(0xFF313338),
onBackground = Color(0xFFDBDEE1),
surface = Color(0xFF2B2D31),
onSurface = Color(0xFFDBDEE1),
surfaceVariant = Color(0xFF383A40),
onSurfaceVariant = Color(0xFFB5BAC1),
outline = Color(0xFF4E5058),
outlineVariant = Color(0xFF3F4147),
error = Color(0xFFED4245),
onError = Color.White,
errorContainer = Color(0xFF4D1516),
onErrorContainer = Color(0xFFFFA0A1)
)
// ── Dracula (Iconic Dark) ──
private val DraculaDarkColorScheme =
darkColorScheme(
primary = Color(0xFFBD93F9),
onPrimary = Color(0xFF21222C),
primaryContainer = Color(0xFF44475A),
onPrimaryContainer = Color(0xFFD6BCFA),
secondary = Color(0xFF50FA7B),
onSecondary = Color(0xFF21222C),
secondaryContainer = Color(0xFF2D4A35),
onSecondaryContainer = Color(0xFF7DFFA0),
tertiary = Color(0xFFFF79C6),
onTertiary = Color(0xFF21222C),
background = Color(0xFF282A36),
onBackground = Color(0xFFF8F8F2),
surface = Color(0xFF21222C),
onSurface = Color(0xFFF8F8F2),
surfaceVariant = Color(0xFF343746),
onSurfaceVariant = Color(0xFFBFBFBF),
outline = Color(0xFF6272A4),
outlineVariant = Color(0xFF44475A),
error = Color(0xFFFF5555),
onError = Color.White,
errorContainer = Color(0xFF4D1A1A),
onErrorContainer = Color(0xFFFF9999)
)
// ── One Dark Pro (Atom-inspired) ──
private val OneDarkProColorScheme =
darkColorScheme(
primary = Color(0xFF61AFEF),
onPrimary = Color(0xFF1E2127),
primaryContainer = Color(0xFF2C3E50),
onPrimaryContainer = Color(0xFF8ECBF7),
secondary = Color(0xFF98C379),
onSecondary = Color(0xFF1E2127),
secondaryContainer = Color(0xFF2D3E2A),
onSecondaryContainer = Color(0xFFB5D99C),
tertiary = Color(0xFFE5C07B),
onTertiary = Color(0xFF1E2127),
background = Color(0xFF282C34),
onBackground = Color(0xFFABB2BF),
surface = Color(0xFF21252B),
onSurface = Color(0xFFABB2BF),
surfaceVariant = Color(0xFF2C313A),
onSurfaceVariant = Color(0xFF8B929E),
outline = Color(0xFF3E4452),
outlineVariant = Color(0xFF333842),
error = Color(0xFFE06C75),
onError = Color.White,
errorContainer = Color(0xFF4D2226),
onErrorContainer = Color(0xFFF0A0A6)
)
// ── Tokyo Night (Neon Deep Blue) ──
private val TokyoNightColorScheme =
darkColorScheme(
primary = Color(0xFF7AA2F7),
onPrimary = Color(0xFF1A1B26),
primaryContainer = Color(0xFF2A3A5E),
onPrimaryContainer = Color(0xFFA9C1FA),
secondary = Color(0xFF9ECE6A),
onSecondary = Color(0xFF1A1B26),
secondaryContainer = Color(0xFF2D3D24),
onSecondaryContainer = Color(0xFFBBE090),
tertiary = Color(0xFFBB9AF7),
onTertiary = Color(0xFF1A1B26),
background = Color(0xFF1A1B26),
onBackground = Color(0xFFC0CAF5),
surface = Color(0xFF16171F),
onSurface = Color(0xFFC0CAF5),
surfaceVariant = Color(0xFF24283B),
onSurfaceVariant = Color(0xFF9AA5CE),
outline = Color(0xFF3B4261),
outlineVariant = Color(0xFF292E42),
error = Color(0xFFF7768E),
onError = Color.White,
errorContainer = Color(0xFF4D2430),
onErrorContainer = Color(0xFFFAA8B6)
)
// ── Nord (Arctic) ──
private val NordDarkColorScheme =
darkColorScheme(
primary = Color(0xFF88C0D0),
onPrimary = Color(0xFF2E3440),
primaryContainer = Color(0xFF3B4C55),
onPrimaryContainer = Color(0xFFA3D4E2),
secondary = Color(0xFFA3BE8C),
onSecondary = Color(0xFF2E3440),
secondaryContainer = Color(0xFF3B4A36),
onSecondaryContainer = Color(0xFFBDD4A8),
tertiary = Color(0xFFEBCB8B),
onTertiary = Color(0xFF2E3440),
background = Color(0xFF2E3440),
onBackground = Color(0xFFECEFF4),
surface = Color(0xFF3B4252),
onSurface = Color(0xFFD8DEE9),
surfaceVariant = Color(0xFF434C5E),
onSurfaceVariant = Color(0xFFD8DEE9),
outline = Color(0xFF4C566A),
outlineVariant = Color(0xFF434C5E),
error = Color(0xFFBF616A),
onError = Color.White,
errorContainer = Color(0xFF4D2528),
onErrorContainer = Color(0xFFE09BA1)
)
// ── Night Owl (Accessibility-focused) ──
private val NightOwlDarkColorScheme =
darkColorScheme(
primary = Color(0xFF7FDBCA),
onPrimary = Color(0xFF011627),
primaryContainer = Color(0xFF1B4A42),
onPrimaryContainer = Color(0xFFA0EDDE),
secondary = Color(0xFFADDB67),
onSecondary = Color(0xFF011627),
secondaryContainer = Color(0xFF2D4A1E),
onSecondaryContainer = Color(0xFFC8EB8E),
tertiary = Color(0xFFC792EA),
onTertiary = Color(0xFF011627),
background = Color(0xFF011627),
onBackground = Color(0xFFD6DEEB),
surface = Color(0xFF0B2942),
onSurface = Color(0xFFD6DEEB),
surfaceVariant = Color(0xFF112B45),
onSurfaceVariant = Color(0xFF9FAFC2),
outline = Color(0xFF1D3B58),
outlineVariant = Color(0xFF15304D),
error = Color(0xFFEF5350),
onError = Color.White,
errorContainer = Color(0xFF4D1A19),
onErrorContainer = Color(0xFFF7A5A3)
)
// ── Anthracite (Material Design Dark) ──
private val AnthraciteDarkColorScheme =
darkColorScheme(
primary = Color(0xFFBB86FC),
onPrimary = Color(0xFF121212),
primaryContainer = Color(0xFF3D2E5C),
onPrimaryContainer = Color(0xFFD4AAFD),
secondary = Color(0xFF03DAC6),
onSecondary = Color(0xFF121212),
secondaryContainer = Color(0xFF0A3D38),
onSecondaryContainer = Color(0xFF4EEADB),
tertiary = Color(0xFFCF6679),
onTertiary = Color(0xFF121212),
background = Color(0xFF121212),
onBackground = Color(0xFFE1E1E1),
surface = Color(0xFF1E1E1E),
onSurface = Color(0xFFE1E1E1),
surfaceVariant = Color(0xFF2C2C2C),
onSurfaceVariant = Color(0xFFAAAAAA),
outline = Color(0xFF3D3D3D),
outlineVariant = Color(0xFF333333),
error = Color(0xFFCF6679),
onError = Color.White,
errorContainer = Color(0xFF4D1F27),
onErrorContainer = Color(0xFFEFA8B4)
)
// ── Cyberpunk (Neon Futuristic) ──
private val CyberpunkDarkColorScheme =
darkColorScheme(
primary = Color(0xFF00FFFF),
onPrimary = Color(0xFF0A0A14),
primaryContainer = Color(0xFF0D3D3D),
onPrimaryContainer = Color(0xFF66FFFF),
secondary = Color(0xFFFF00FF),
onSecondary = Color(0xFF0A0A14),
secondaryContainer = Color(0xFF3D0D3D),
onSecondaryContainer = Color(0xFFFF66FF),
tertiary = Color(0xFFFFFF00),
onTertiary = Color(0xFF0A0A14),
background = Color(0xFF0A0A14),
onBackground = Color(0xFFE0E0F0),
surface = Color(0xFF12121E),
onSurface = Color(0xFFE0E0F0),
surfaceVariant = Color(0xFF1A1A2E),
onSurfaceVariant = Color(0xFFA0A0C0),
outline = Color(0xFF2A2A44),
outlineVariant = Color(0xFF1F1F36),
error = Color(0xFFFF3366),
onError = Color.White,
errorContainer = Color(0xFF4D0F20),
onErrorContainer = Color(0xFFFF8FAB)
)
// ── Navy Elegance (Deep Navy + Gold) ──
private val NavyEleganceDarkColorScheme =
darkColorScheme(
primary = Color(0xFFD4AF37),
onPrimary = Color(0xFF0B1929),
primaryContainer = Color(0xFF3D3218),
onPrimaryContainer = Color(0xFFE8CC6E),
secondary = Color(0xFFC0C0C0),
onSecondary = Color(0xFF0B1929),
secondaryContainer = Color(0xFF2A2D33),
onSecondaryContainer = Color(0xFFD9D9D9),
tertiary = Color(0xFF87CEEB),
onTertiary = Color(0xFF0B1929),
background = Color(0xFF0B1929),
onBackground = Color(0xFFE0E4EA),
surface = Color(0xFF0F2035),
onSurface = Color(0xFFE0E4EA),
surfaceVariant = Color(0xFF162A42),
onSurfaceVariant = Color(0xFFA0AABB),
outline = Color(0xFF1E3550),
outlineVariant = Color(0xFF1A2E46),
error = Color(0xFFE57373),
onError = Color.White,
errorContainer = Color(0xFF4D2222),
onErrorContainer = Color(0xFFF0A8A8)
)
// ── Earthy (Forest & Chocolate) ──
private val EarthyDarkColorScheme =
darkColorScheme(
primary = Color(0xFF81C784),
onPrimary = Color(0xFF1A1510),
primaryContainer = Color(0xFF2E4A2F),
onPrimaryContainer = Color(0xFFA8D8AA),
secondary = Color(0xFFD4A574),
onSecondary = Color(0xFF1A1510),
secondaryContainer = Color(0xFF4A3526),
onSecondaryContainer = Color(0xFFE8C49E),
tertiary = Color(0xFFA5D6A7),
onTertiary = Color(0xFF1A1510),
background = Color(0xFF1A1510),
onBackground = Color(0xFFE0D8CF),
surface = Color(0xFF231E18),
onSurface = Color(0xFFE0D8CF),
surfaceVariant = Color(0xFF2E2720),
onSurfaceVariant = Color(0xFFADA49A),
outline = Color(0xFF3D342B),
outlineVariant = Color(0xFF332C24),
error = Color(0xFFE57373),
onError = Color.White,
errorContainer = Color(0xFF4D2222),
onErrorContainer = Color(0xFFF0A8A8)
)
fun getColorSchemeForTheme(appTheme: AppTheme): androidx.compose.material3.ColorScheme {
return when (appTheme) {
AppTheme.DEFAULT -> DefaultDarkColorScheme
AppTheme.GITHUB -> GitHubDarkColorScheme
AppTheme.LINEAR -> LinearDarkColorScheme
AppTheme.SPOTIFY -> SpotifyDarkColorScheme
AppTheme.NOTION -> NotionDarkColorScheme
AppTheme.DISCORD -> DiscordDarkColorScheme
AppTheme.DRACULA -> DraculaDarkColorScheme
AppTheme.ONE_DARK_PRO -> OneDarkProColorScheme
AppTheme.TOKYO_NIGHT -> TokyoNightColorScheme
AppTheme.NORD -> NordDarkColorScheme
AppTheme.NIGHT_OWL -> NightOwlDarkColorScheme
AppTheme.ANTHRACITE -> AnthraciteDarkColorScheme
AppTheme.CYBERPUNK -> CyberpunkDarkColorScheme
AppTheme.NAVY_ELEGANCE -> NavyEleganceDarkColorScheme
AppTheme.EARTHY -> EarthyDarkColorScheme
}
}
@Composable
fun ShaarItTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true, // Enable Material You by default
oledMode: Boolean = false, // Pure black for OLED screens
appTheme: AppTheme = AppTheme.DEFAULT,
content: @Composable () -> Unit
) {
val context = LocalContext.current
// Always use the explicit color scheme for the selected theme
val colorScheme = getColorSchemeForTheme(appTheme)
val colorScheme =
when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
// Material You (Monet) - dynamic colors from wallpaper
if (darkTheme) {
if (oledMode) {
// OLED pure black variant
dynamicDarkColorScheme(context).copy(
background = Color.Black,
surface = Color(0xFF0A0A0A),
surfaceVariant = Color(0xFF1A1A1A)
)
} else {
dynamicDarkColorScheme(context)
}
} else {
dynamicLightColorScheme(context)
}
}
darkTheme -> {
if (oledMode) {
// OLED pure black variant of custom theme
DarkColorScheme.copy(
background = Color.Black,
surface = Color(0xFF0A0A0A),
surfaceVariant = Color(0xFF1A1A1A)
)
} else {
DarkColorScheme
}
}
else -> LightColorScheme
}
// All custom themes are dark
val isEffectivelyDark = true
val view = LocalView.current
if (!view.isInEditMode) {
@ -138,7 +483,7 @@ fun ShaarItTheme(
val window = (view.context as Activity).window
window.statusBarColor = colorScheme.background.toArgb()
window.navigationBarColor = colorScheme.background.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !isEffectivelyDark
}
}