package com.example
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.*
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.*
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.draw.drawBehind
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.example.ui.theme.MyApplicationTheme
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.sin
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
var isDarkMode by remember { mutableStateOf(false) }
MyApplicationTheme(darkTheme = isDarkMode) {
StatusDownloaderApp(
isDarkMode = isDarkMode,
onToggleDarkMode = { isDarkMode = !isDarkMode }
)
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun StatusDownloaderApp(
isDarkMode: Boolean,
onToggleDarkMode: () -> Unit
) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
// Core states
var searchQuery by remember { mutableStateOf(“”) }
var selectedTab by remember { mutableStateOf(MediaType.IMAGE) }
var isRefreshing by remember { mutableStateOf(false) }
var savedIds by remember { mutableStateOf(setOf()) }
var statusesList by remember { mutableStateOf(DummyData.initialStatuses) }
var previewItem by remember { mutableStateOf(null) }
var savingPercentage by remember { mutableStateOf(null) }
// Bottom Navigation tab state: “home” | “downloads” | “settings”
var currentBottomTab by remember { mutableStateOf(“home”) }
// Simulated Settings Toggles
var autoDownload by remember { mutableStateOf(false) }
var highQualityPreview by remember { mutableStateOf(true) }
var showInSystemGallery by remember { mutableStateOf(true) }
var isClearingCache by remember { mutableStateOf(false) }
// Custom filter logic
val filteredStatuses = remember(searchQuery, selectedTab, statusesList, currentBottomTab, savedIds) {
val baseList = if (currentBottomTab == “downloads”) {
statusesList.filter { savedIds.contains(it.id) }
} else {
statusesList.filter { it.mediaType == selectedTab }
}
if (searchQuery.isNotEmpty()) {
baseList.filter {
it.username.contains(searchQuery, ignoreCase = true) ||
it.category.contains(searchQuery, ignoreCase = true) ||
it.caption.contains(searchQuery, ignoreCase = true)
}
} else {
baseList
}
}
// Refresh function
val triggerRefresh: () -> Unit = {
coroutineScope.launch {
isRefreshing = true
delay(1200) // Simulated loading
// Randomize views a little bit to look active
statusesList = statusesList.map {
it.copy(views = it.views + (1..5).random())
}
isRefreshing = false
Toast.makeText(context, “Statuses scanned and updated successfully!”, Toast.LENGTH_SHORT).show()
}
}
// Download/Save Status function
val saveStatus: (StatusItem) -> Unit = { item ->
coroutineScope.launch {
// Emulate nice download progress bar
for (p in 0..100 step 20) {
savingPercentage = p
delay(120)
}
savingPercentage = null
savedIds = savedIds + item.id
Toast.makeText(context, “Status downloaded to gallery successfully!”, Toast.LENGTH_SHORT).show()
}
}
// Standard Theme Colors mapping (Matches “Sleek Interface” Theme)
val brandGreen = Color(0xFF008069)
val brandLightPill = Color(0xFFDCF8C6)
val whatsappTealAccent = Color(0xFF25D366)
val lightBgColor = Color(0xFFF0F2F5)
val darkBgColor = Color(0xFF111B21)
val darkCardColor = Color(0xFF202C33)
Scaffold(
modifier = Modifier.fillMaxSize(),
containerColor = if (isDarkMode) darkBgColor else lightBgColor,
topBar = {
Column(
modifier = Modifier
.fillMaxWidth()
.background(if (isDarkMode) Color(0xFF202C33) else brandGreen)
.statusBarsPadding()
) {
// Header Row
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 14.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(
text = when (currentBottomTab) {
“downloads” -> “Downloads Gallery”
“settings” -> “Settings”
else -> “Status Downloader”
},
fontSize = 22.sp,
fontWeight = FontWeight.Bold,
color = Color.White,
fontFamily = FontFamily.SansSerif
)
Text(
text = when (currentBottomTab) {
“downloads” -> “Offline files (${filteredStatuses.size} saved)”
“settings” -> “Preferences & Optimization”
else -> “WhatsApp Active Companion”
},
fontSize = 12.sp,
color = Color.White.copy(alpha = 0.82f),
fontFamily = FontFamily.SansSerif
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
// Refresh button (Only if not in Settings tab)
if (currentBottomTab != “settings”) {
IconButton(
onClick = { triggerRefresh() },
modifier = Modifier.testTag(“refresh_button”)
) {
Icon(
imageVector = Icons.Default.Cached,
contentDescription = “Refresh Button”,
tint = Color.White
)
}
}
// Dark Mode toggle
IconButton(
onClick = onToggleDarkMode,
modifier = Modifier.testTag(“dark_mode_toggle”)
) {
Icon(
imageVector = if (isDarkMode) Icons.Outlined.LightMode else Icons.Outlined.DarkMode,
contentDescription = “Theme Mode Switcher”,
tint = Color.White
)
}
}
}
// If not in Settings tab, display a modern sticky Search bar in top layout
if (currentBottomTab != “settings”) {
OutlinedTextField(
value = searchQuery,
onValueChange = { searchQuery = it },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
.testTag(“search_bar”),
placeholder = {
Text(
when (currentBottomTab) {
“downloads” -> “Search saved downloads…”
else -> “Search Active status, hashtags…”
},
color = if (isDarkMode) Color.LightGray.copy(alpha = 0.6f) else Color.Gray.copy(alpha = 0.8f),
fontSize = 14.sp
)
},
leadingIcon = {
Icon(
imageVector = Icons.Default.Search,
contentDescription = “Active Search icon”,
tint = if (isDarkMode) Color.LightGray.copy(alpha = 0.8f) else brandGreen,
modifier = Modifier.size(20.dp)
)
},
trailingIcon = {
if (searchQuery.isNotEmpty()) {
IconButton(onClick = { searchQuery = “” }) {
Icon(
imageVector = Icons.Default.Clear,
contentDescription = “Clear search filter”,
tint = if (isDarkMode) Color.LightGray else Color.Gray
)
}
}
},
shape = RoundedCornerShape(24.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = whatsappTealAccent,
unfocusedBorderColor = Color.Transparent,
focusedContainerColor = if (isDarkMode) Color(0xFF111B21) else Color.White,
unfocusedContainerColor = if (isDarkMode) Color(0xFF111B21) else Color.White,
focusedTextColor = if (isDarkMode) Color.White else Color.Black,
unfocusedTextColor = if (isDarkMode) Color.White else Color.Black
),
singleLine = true
)
Spacer(modifier = Modifier.height(4.dp))
}
// Render Sub-Tabs (Images/Videos) only if we are in Home tab
if (currentBottomTab == “home”) {
Row(
modifier = Modifier.fillMaxWidth()
) {
TabItem(
title = “IMAGES”,
icon = Icons.Default.Image,
isSelected = selectedTab == MediaType.IMAGE,
count = statusesList.count { it.mediaType == MediaType.IMAGE },
isDarkMode = isDarkMode,
onClick = { selectedTab = MediaType.IMAGE }
)
TabItem(
title = “VIDEOS”,
icon = Icons.Default.VideoLibrary,
isSelected = selectedTab == MediaType.VIDEO,
count = statusesList.count { it.mediaType == MediaType.VIDEO },
isDarkMode = isDarkMode,
onClick = { selectedTab = MediaType.VIDEO }
)
}
}
}
},
bottomBar = {
// “Sleek Interface” Theme Bottom Navigation Structure
Column(
modifier = Modifier
.background(if (isDarkMode) Color(0xFF202C33) else Color.White)
.border(
width = 1.dp,
color = if (isDarkMode) Color(0xFF2F3B43) else Color(0xFFE9EDEF),
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
)
.navigationBarsPadding()
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 10.dp),
horizontalArrangement = Arrangement.SpaceAround,
verticalAlignment = Alignment.CenterVertically
) {
BottomNavItem(
title = “HOME”,
icon = Icons.Default.Home,
isSelected = currentBottomTab == “home”,
isDarkMode = isDarkMode,
activePillColor = if (isDarkMode) Color(0xFF005C4B) else brandLightPill,
activeIconColor = if (isDarkMode) Color(0xFF00A884) else brandGreen,
onClick = { currentBottomTab = “home” }
)
BottomNavItem(
title = “DOWNLOADS”,
icon = Icons.Default.FileDownload,
isSelected = currentBottomTab == “downloads”,
isDarkMode = isDarkMode,
activePillColor = if (isDarkMode) Color(0xFF005C4B) else brandLightPill,
activeIconColor = if (isDarkMode) Color(0xFF00A884) else brandGreen,
onClick = { currentBottomTab = “downloads” }
)
BottomNavItem(
title = “SETTINGS”,
icon = Icons.Default.Settings,
isSelected = currentBottomTab == “settings”,
isDarkMode = isDarkMode,
activePillColor = if (isDarkMode) Color(0xFF005C4B) else brandLightPill,
activeIconColor = if (isDarkMode) Color(0xFF00A884) else brandGreen,
onClick = { currentBottomTab = “settings” }
)
}
// Beautiful micro branding disclaimer as requested by design HTML
Box(
modifier = Modifier
.fillMaxWidth()
.background(if (isDarkMode) Color(0xFF111B21) else Color(0xFFF8FAFC))
.padding(vertical = 5.dp),
contentAlignment = Alignment.Center
) {
Text(
text = “© 2026 STATUS DOWNLOADER • ALL RIGHTS RESERVED”,
fontSize = 8.sp,
fontWeight = FontWeight.Bold,
color = if (isDarkMode) Color.Gray.copy(alpha = 0.6f) else Color.Gray,
letterSpacing = 1.2.sp
)
}
}
}
) { innerPadding ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
if (isRefreshing) {
// Symmetrical scanner spinner loader
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
CircularProgressIndicator(
color = if (isDarkMode) whatsappTealAccent else brandGreen,
strokeWidth = 4.dp
)
Spacer(modifier = Modifier.height(16.dp))
Text(
“Scanning active status folder…”,
color = if (isDarkMode) Color.White else Color.DarkGray,
fontSize = 14.sp,
fontWeight = FontWeight.Medium
)
}
}
} else {
when (currentBottomTab) {
“home”, “downloads” -> {
if (filteredStatuses.isEmpty()) {
// High-fidelity responsive empty states
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.size(90.dp)
.background(
color = if (isDarkMode) Color(0xFF222E35) else Color.White,
shape = CircleShape
),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = if (currentBottomTab == “downloads”) Icons.Default.FolderOpen else Icons.Default.HourglassEmpty,
contentDescription = “Empty state icon”,
modifier = Modifier.size(44.dp),
tint = if (isDarkMode) Color.LightGray.copy(alpha = 0.6f) else Color.Gray.copy(alpha = 0.7f)
)
}
Spacer(modifier = Modifier.height(16.dp))
Text(
text = if (searchQuery.isNotEmpty()) “No Statuses Found” else if (currentBottomTab == “downloads”) “Gallery is Empty” else “No Active Statuses”,
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = if (isDarkMode) Color.White else Color.Black
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = if (searchQuery.isNotEmpty()) {
“Try tweaking your search keywords or hashtags above.”
} else if (currentBottomTab == “downloads”) {
“Saved statuses will be listed here offline. Long tap on item thumbnails to preview or download!”
} else {
“All active statuses from your business contacts will auto-populate here.”
},
fontSize = 13.sp,
textAlign = TextAlign.Center,
modifier = Modifier.padding(horizontal = 16.dp),
color = if (isDarkMode) Color.LightGray.copy(alpha = 0.7f) else Color.Gray
)
}
} else {
// Symmetrical card grid display
LazyVerticalGrid(
columns = GridCells.Fixed(2),
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 8.dp),
contentPadding = PaddingValues(top = 12.dp, bottom = 24.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
items(filteredStatuses, key = { it.id }) { item ->
val isSaved = savedIds.contains(item.id)
StatusCard(
item = item,
isSaved = isSaved,
isDarkMode = isDarkMode,
onPreview = { previewItem = item },
onSave = { saveStatus(item) }
)
}
}
}
}
“settings” -> {
// Polished Settings Pane with options
Column(
modifier = Modifier
.fillMaxSize()
.background(if (isDarkMode) darkBgColor else lightBgColor)
.verticalScroll(rememberScrollState())
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(
“GENERAL SETTINGS”,
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
color = if (isDarkMode) Color.LightGray.copy(alpha = 0.7f) else Color.DarkGray.copy(alpha = 0.8f),
modifier = Modifier.padding(start = 4.dp, bottom = 2.dp)
)
// Theme Toggle Item Card
SettingsToggleItem(
title = “Enable Dark Canvas”,
subtitle = “Reduces strain in low light conditions”,
icon = Icons.Outlined.DarkMode,
isChecked = isDarkMode,
onCheckedChange = { onToggleDarkMode() },
isDarkMode = isDarkMode
)
// Simulated Toggles
SettingsToggleItem(
title = “Auto-save Statuses”,
subtitle = “Silently downloads active statuses”,
icon = Icons.Outlined.CloudDownload,
isChecked = autoDownload,
onCheckedChange = { autoDownload = it },
isDarkMode = isDarkMode
)
SettingsToggleItem(
title = “Ultra Preview Engine”,
subtitle = “Preloads statuses in ultra high density”,
icon = Icons.Outlined.Hd,
isChecked = highQualityPreview,
onCheckedChange = { highQualityPreview = it },
isDarkMode = isDarkMode
)
SettingsToggleItem(
title = “Display in System Gallery”,
subtitle = “Reflects items inside system album”,
icon = Icons.Outlined.PhotoAlbum,
isChecked = showInSystemGallery,
onCheckedChange = { showInSystemGallery = it },
isDarkMode = isDarkMode
)
Text(
“STORAGE OPTIMIZATION”,
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
color = if (isDarkMode) Color.LightGray.copy(alpha = 0.7f) else Color.DarkGray.copy(alpha = 0.8f),
modifier = Modifier.padding(start = 4.dp, top = 8.dp)
)
// Clear Caches Card Option
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(
containerColor = if (isDarkMode) Color(0xFF202C33) else Color.White
),
border = BorderStroke(
width = 1.dp,
color = if (isDarkMode) Color(0xFF2F3B43) else Color(0xFFE9EDEF)
)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.weight(1f)
) {
Box(
modifier = Modifier
.size(40.dp)
.background(
color = if (isDarkMode) Color(0xFF111B21) else Color(0xFFF1F5F9),
shape = CircleShape
),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Outlined.DeleteSweep,
contentDescription = null,
tint = Color(0xFFEF4444)
)
}
Spacer(modifier = Modifier.width(12.dp))
Column {
Text(
“Cache & Junk Cleaner”,
fontWeight = FontWeight.Bold,
fontSize = 15.sp,
color = if (isDarkMode) Color.White else Color.Black
)
Text(
“Clear generated temp viewfiles (24.8 MB)”,
fontSize = 11.sp,
color = if (isDarkMode) Color.LightGray.copy(alpha = 0.8f) else Color.Gray
)
}
}
Button(
onClick = {
coroutineScope.launch {
isClearingCache = true
delay(1200)
isClearingCache = false
Toast.makeText(context, “Temp cache cleared successfully!”, Toast.LENGTH_SHORT).show()
}
},
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFEF4444).copy(alpha = 0.12f),
contentColor = Color(0xFFEF4444)
),
shape = RoundedCornerShape(12.dp),
contentPadding = PaddingValues(horizontal = 14.dp, vertical = 6.dp)
) {
Text(“CLEAR”, fontWeight = FontWeight.Bold, fontSize = 12.sp)
}
}
}
Spacer(modifier = Modifier.height(8.dp))
// Compact about segment Card
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(
containerColor = if (isDarkMode) Color(0xFF111B21).copy(alpha = 0.5f) else Color(0xFFE2E8F0).copy(alpha = 0.4f)
)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Icon(
imageVector = Icons.Default.VerifiedUser,
contentDescription = null,
tint = if (isDarkMode) whatsappTealAccent else brandGreen,
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.height(6.dp))
Text(
“WhatsApp Companion Pro • Active Protection”,
fontWeight = FontWeight.Bold,
fontSize = 12.sp,
color = if (isDarkMode) Color.White else Color.Black
)
Text(
“Build Configuration signature matches stable framework v1.2.5. Status files are fetched strictly in local sandboxes without online relay.”,
fontSize = 10.sp,
textAlign = TextAlign.Center,
color = if (isDarkMode) Color.LightGray.copy(alpha = 0.6f) else Color.Gray,
modifier = Modifier.padding(top = 4.dp, start = 8.dp, end = 8.dp)
)
}
}
}
}
}
}
// Global simulation clearing overlay dialog
if (isClearingCache) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.72f))
.clickable(enabled = false) {},
contentAlignment = Alignment.Center
) {
Card(
modifier = Modifier
.width(280.dp)
.padding(16.dp),
colors = CardDefaults.cardColors(
containerColor = if (isDarkMode) Color(0xFF222E35) else Color.White
),
shape = RoundedCornerShape(18.dp),
elevation = CardDefaults.cardElevation(8.dp)
) {
Column(
modifier = Modifier.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator(color = Color(0xFFEF4444), strokeWidth = 4.dp)
Spacer(modifier = Modifier.height(16.dp))
Text(
“Purging Caches…”,
fontWeight = FontWeight.Bold,
color = if (isDarkMode) Color.White else Color.Black,
fontSize = 15.sp
)
Text(
“Tuning indices block…”,
fontSize = 11.sp,
color = if (isDarkMode) Color.LightGray else Color.Gray,
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
}
// Global Download Block Progress Indicator Overlay
savingPercentage?.let { percentage ->
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.7f))
.clickable(enabled = false) {},
contentAlignment = Alignment.Center
) {
Card(
modifier = Modifier
.width(280.dp)
.padding(16.dp),
colors = CardDefaults.cardColors(
containerColor = if (isDarkMode) Color(0xFF222E35) else Color.White
),
shape = RoundedCornerShape(16.dp),
elevation = CardDefaults.cardElevation(8.dp)
) {
Column(
modifier = Modifier.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator(
progress = { percentage / 100f },
strokeWidth = 5.dp,
color = whatsappTealAccent
)
Spacer(modifier = Modifier.height(16.dp))
Text(
“Downloading Status… $percentage%”,
fontWeight = FontWeight.Bold,
color = if (isDarkMode) Color.White else Color.Black,
fontSize = 15.sp
)
Text(
“Writing temporary block…”,
fontSize = 11.sp,
color = if (isDarkMode) Color.LightGray else Color.Gray,
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
}
// Fullscreen Preview Overlay Modal Dialog
previewItem?.let { status ->
FullScreenPreviewDialog(
status = status,
isSaved = savedIds.contains(status.id),
isDarkMode = isDarkMode,
onDismiss = { previewItem = null },
onSave = {
saveStatus(status)
}
)
}
}
}
}
@Composable
fun RowScope.TabItem(
title: String,
icon: androidx.compose.ui.graphics.vector.ImageVector,
isSelected: Boolean,
count: Int,
isDarkMode: Boolean,
onClick: () -> Unit
) {
val indicatorColor = if (isDarkMode) Color(0xFF00A884) else Color.White
val contentColor = if (isSelected) Color.White else Color.White.copy(alpha = 0.65f)
Box(
modifier = Modifier
.weight(1f)
.clickable { onClick() }
.drawBehind {
if (isSelected) {
val strokeHeight = 4.dp.toPx()
drawRect(
color = indicatorColor,
topLeft = Offset(0f, size.height – strokeHeight),
size = Size(size.width, strokeHeight)
)
}
}
.padding(vertical = 14.dp),
contentAlignment = Alignment.Center
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Icon(
imageVector = icon,
contentDescription = null,
tint = contentColor,
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(6.dp))
Text(
text = title,
color = contentColor,
fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Medium,
fontSize = 14.sp
)
Spacer(modifier = Modifier.width(6.dp))
// Tab Badge Count
Box(
modifier = Modifier
.background(
color = if (isSelected) Color.White.copy(alpha = 0.25f) else Color.White.copy(alpha = 0.15f),
shape = CircleShape
)
.padding(horizontal = 6.dp, vertical = 2.dp)
) {
Text(
text = count.toString(),
color = Color.White,
fontSize = 10.sp,
fontWeight = FontWeight.Bold
)
}
}
}
}
@Composable
fun RowScope.BottomNavItem(
title: String,
icon: androidx.compose.ui.graphics.vector.ImageVector,
isSelected: Boolean,
isDarkMode: Boolean,
activePillColor: Color,
activeIconColor: Color,
onClick: () -> Unit
) {
val coroutineScope = rememberCoroutineScope()
val scaleState = remember { Animatable(1f) }
Column(
modifier = Modifier
.weight(1f)
.clickable(
onClick = {
coroutineScope.launch {
scaleState.animateTo(0.9f, animationSpec = tween(100))
scaleState.animateTo(1.0f, animationSpec = tween(100))
}
onClick()
}
)
.graphicsLayer {
scaleX = scaleState.value
scaleY = scaleState.value
},
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
// Icon wrapper pill matching Tailwind “bg-[#dcf8c6] px-5 py-1 rounded-full”
Box(
modifier = Modifier
.background(
color = if (isSelected) activePillColor else Color.Transparent,
shape = RoundedCornerShape(16.dp)
)
.padding(horizontal = 24.dp, vertical = 4.dp),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = icon,
contentDescription = title,
tint = if (isSelected) activeIconColor else if (isDarkMode) Color.LightGray.copy(alpha = 0.6f) else Color(0xFF64748B),
modifier = Modifier.size(24.dp)
)
}
Spacer(modifier = Modifier.height(4.dp))
Text(
text = title,
fontSize = 10.sp,
fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Medium,
color = if (isSelected) activeIconColor else if (isDarkMode) Color.LightGray.copy(alpha = 0.5f) else Color(0xFF64748B)
)
}
}
@Composable
fun SettingsToggleItem(
title: String,
subtitle: String,
icon: androidx.compose.ui.graphics.vector.ImageVector,
isChecked: Boolean,
onCheckedChange: (Boolean) -> Unit,
isDarkMode: Boolean
) {
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(
containerColor = if (isDarkMode) Color(0xFF202C33) else Color.White
),
border = BorderStroke(
width = 1.dp,
color = if (isDarkMode) Color(0xFF2F3B43) else Color(0xFFE9EDEF)
)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.weight(1f)
) {
Box(
modifier = Modifier
.size(40.dp)
.background(
color = if (isDarkMode) Color(0xFF111B21) else Color(0xFFF1F5F9),
shape = CircleShape
),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = icon,
contentDescription = null,
tint = if (isDarkMode) Color(0xFF00A884) else Color(0xFF008069)
)
}
Spacer(modifier = Modifier.width(12.dp))
Column {
Text(
title,
fontWeight = FontWeight.Bold,
fontSize = 15.sp,
color = if (isDarkMode) Color.White else Color.Black
)
Text(
subtitle,
fontSize = 11.sp,
color = if (isDarkMode) Color.LightGray.copy(alpha = 0.8f) else Color.Gray
)
}
}
Switch(
checked = isChecked,
onCheckedChange = onCheckedChange,
colors = SwitchDefaults.colors(
checkedThumbColor = Color.White,
checkedTrackColor = if (isDarkMode) Color(0xFF00A884) else Color(0xFF008069),
uncheckedThumbColor = Color.LightGray,
uncheckedTrackColor = Color.Transparent
)
)
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun StatusCard(
item: StatusItem,
isSaved: Boolean,
isDarkMode: Boolean,
onPreview: () -> Unit,
onSave: () -> Unit
) {
val cardBg = if (isDarkMode) Color(0xFF202C33) else Color.White
val borderStrokeColor = if (isDarkMode) Color(0xFF2F3B43) else Color(0xFFE9EDEF)
val whatsappGreen = Color(0xFF25D366)
val brandGreen = Color(0xFF008069)
Card(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
.combinedClickable(
onClick = onPreview,
onLongClick = onPreview
)
.border(1.dp, borderStrokeColor, RoundedCornerShape(16.dp))
.shadow(2.dp, RoundedCornerShape(16.dp)),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = cardBg)
) {
Column {
// Thumbnail container
Box(
modifier = Modifier
.fillMaxWidth()
.height(145.dp)
.background(Color.Black)
) {
// Coil image loading
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(item.mediaUrl)
.crossfade(true)
.build(),
contentDescription = “Status thumbnail by ${item.username}”,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
// If Video MediaType, render progress/play icon badge
if (item.mediaType == MediaType.VIDEO) {
Box(
modifier = Modifier
.size(36.dp)
.align(Alignment.Center)
.background(Color.Black.copy(alpha = 0.55f), CircleShape),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Default.PlayArrow,
contentDescription = “Play Status Icon”,
tint = Color.White,
modifier = Modifier.size(24.dp)
)
}
}
// Recent tag: Matches “absolute top-2 left-2 bg-black/30 backdrop-blur-md rounded-full”
val isRecent = item.timestamp.contains(“minute”)
if (isRecent) {
Box(
modifier = Modifier
.align(Alignment.TopStart)
.padding(8.dp)
.background(Color.Black.copy(alpha = 0.5f), CircleShape)
.padding(horizontal = 8.dp, vertical = 3.dp)
) {
Text(
text = “RECENT”,
color = Color.White,
fontSize = 8.sp,
fontWeight = FontWeight.Bold,
letterSpacing = 1.sp
)
}
}
// Top visual shading user info badge
Row(
modifier = Modifier
.fillMaxWidth()
.background(
brush = Brush.verticalGradient(
colors = listOf(Color.Black.copy(alpha = 0.7f), Color.Transparent)
)
)
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(20.dp)
.background(Color(item.avatarColor), CircleShape),
contentAlignment = Alignment.Center
) {
Text(
text = item.username.take(1).uppercase(),
color = Color.White,
fontSize = 11.sp,
fontWeight = FontWeight.Bold
)
}
Spacer(modifier = Modifier.width(6.dp))
Text(
text = item.username,
color = Color.White,
fontSize = 12.sp,
fontWeight = FontWeight.SemiBold,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
// File size bubble
Box(
modifier = Modifier
.align(Alignment.BottomStart)
.padding(8.dp)
.background(Color.Black.copy(alpha = 0.65f), RoundedCornerShape(4.dp))
.padding(horizontal = 6.dp, vertical = 2.dp)
) {
Text(
text = item.fileSize,
color = Color.White,
fontSize = 10.sp,
fontWeight = FontWeight.Bold
)
}
// View count bubble
Box(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(8.dp)
.background(Color.Black.copy(alpha = 0.65f), RoundedCornerShape(4.dp))
.padding(horizontal = 6.dp, vertical = 2.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(2.dp)
) {
Icon(
imageVector = Icons.Default.RemoveRedEye,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(10.dp)
)
Text(
text = item.views.toString(),
color = Color.White,
fontSize = 10.sp,
fontWeight = FontWeight.Bold
)
}
}
}
// Lower Action segment matching active:scale-90
Row(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = item.timestamp,
fontSize = 11.sp,
color = if (isDarkMode) Color.LightGray.copy(alpha = 0.8f) else Color.Gray,
fontWeight = FontWeight.Medium
)
Text(
text = “#${item.category}”,
fontSize = 9.sp,
color = if (isDarkMode) whatsappGreen else brandGreen,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(top = 1.dp)
)
}
// Action Save Custom Circular Button matching Tailwind active:scale-90
val interactionSource = remember { MutableInteractionSource() }
IconButton(
onClick = onSave,
interactionSource = interactionSource,
modifier = Modifier
.size(34.dp)
.background(
color = if (isSaved) Color(0xFF039BE5) else if (isDarkMode) Color(0xFF00A884) else brandGreen,
shape = CircleShape
)
.testTag(“download_status_button”),
) {
Icon(
imageVector = if (isSaved) Icons.Default.Check else Icons.Default.Download,
contentDescription = “Download click action”,
tint = Color.White,
modifier = Modifier.size(16.dp)
)
}
}
}
}
}
@Composable
fun FullScreenPreviewDialog(
status: StatusItem,
isSaved: Boolean,
isDarkMode: Boolean,
onDismiss: () -> Unit,
onSave: () -> Unit
) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
// Media Player progress loop representations
var isVideoPlaying by remember { mutableStateOf(true) }
var videoPlaybackProgress by remember { mutableStateOf(0.12f) }
if (status.mediaType == MediaType.VIDEO && isVideoPlaying) {
LaunchedEffect(isVideoPlaying) {
while (isVideoPlaying) {
delay(150)
videoPlaybackProgress += 0.015f
if (videoPlaybackProgress >= 1f) {
videoPlaybackProgress = 0.0f
}
}
}
}
Dialog(
onDismissRequest = onDismiss,
properties = DialogProperties(
usePlatformDefaultWidth = false,
dismissOnBackPress = true,
dismissOnClickOutside = true
)
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black)
.systemBarsPadding()
) {
Box(
modifier = Modifier
.fillMaxSize()
.clickable {
if (status.mediaType == MediaType.VIDEO) {
isVideoPlaying = !isVideoPlaying
}
},
contentAlignment = Alignment.Center
) {
if (status.mediaType == MediaType.IMAGE) {
AsyncImage(
model = ImageRequest.Builder(context)
.data(status.mediaUrl)
.build(),
contentDescription = “Full Image status”,
contentScale = ContentScale.Fit,
modifier = Modifier.fillMaxWidth()
)
} else {
// Custom LIVE VIDEO SHADER/CANVAS representation for premium visual touch
val animatedAngle = rememberInfiniteTransition().animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(12000, easing = LinearEasing),
repeatMode = RepeatMode.Restart
)
)
Canvas(
modifier = Modifier
.fillMaxSize()
.graphicsLayer { rotationZ = if (isVideoPlaying) animatedAngle.value else 0f }
) {
val strokeWidth = 1.5.dp.toPx()
when (status.category.uppercase()) {
“PETS” -> {
val numRains = 35
for (i in 0 until numRains) {
val xOffset = (sin(i.toDouble() + (animatedAngle.value / 40.0)) * 0.4 + 0.5) * size.width
val yVelocity = (i * 25 + (animatedAngle.value * 6f)) % size.height
drawLine(
color = Color(0xFF64FFDA).copy(alpha = 0.45f),
start = Offset(xOffset.toFloat(), yVelocity),
end = Offset((xOffset – 5).toFloat(), yVelocity + 25f),
strokeWidth = 3f
)
}
}
“FOOD” -> {
drawCircle(
brush = Brush.radialGradient(
colors = listOf(Color(0xFFFF3D00).copy(alpha = 0.6f), Color.Transparent),
center = center,
radius = (size.width / 2.5f) + (sin(animatedAngle.value * 0.1f) * 40f)
),
radius = size.width / 1.5f,
center = center
)
for (r in 1..4) {
drawCircle(
color = Color(0xFFFF9100).copy(alpha = 0.2f),
radius = (size.width / 5f) * r + (sin(animatedAngle.value * 0.05f) * 20f),
style = Stroke(strokeWidth)
)
}
}
else -> {
for (lineIndex in 1..5) {
val customPath = Path().apply {
val phase = lineIndex * 40f + (animatedAngle.value / 2f)
moveTo(0f, size.height / 2f)
for (xPoint in 0..size.width.toInt() step 15) {
val yOffset = sin((xPoint + phase) * 0.012f) * 110f
lineTo(xPoint.toFloat(), (size.height / 2f) + yOffset)
}
}
drawPath(
path = customPath,
color = when (lineIndex % 3) {
0 -> Color(0xFF00E676).copy(alpha = 0.4f)
1 -> Color(0xFF00B0FF).copy(alpha = 0.35f)
else -> Color(0xFFFF3D00).copy(alpha = 0.25f)
},
style = Stroke(width = strokeWidth * 2.5f)
)
}
}
}
}
AsyncImage(
model = ImageRequest.Builder(context)
.data(status.mediaUrl)
.build(),
contentDescription = “Video Thumbnail Ambient Face”,
alpha = 0.25f,
contentScale = ContentScale.Inside,
modifier = Modifier.fillMaxWidth()
)
AnimatedVisibility(
visible = !isVideoPlaying,
enter = fadeIn() + scaleIn(),
exit = fadeOut() + scaleOut()
) {
Box(
modifier = Modifier
.size(68.dp)
.background(Color.Black.copy(alpha = 0.6f), CircleShape),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Default.PlayArrow,
contentDescription = “Resume play button”,
tint = Color.White,
modifier = Modifier.size(44.dp)
)
}
}
}
}
// Top overlay layout
Row(
modifier = Modifier
.fillMaxWidth()
.background(
Brush.verticalGradient(
listOf(Color.Black.copy(alpha = 0.85f), Color.Transparent)
)
)
.padding(horizontal = 16.dp, vertical = 20.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(verticalAlignment = Alignment.CenterVertically) {
IconButton(
onClick = onDismiss,
modifier = Modifier.testTag(“back_button_preview”)
) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = “Navigate back”,
tint = Color.White
)
}
Spacer(modifier = Modifier.width(8.dp))
Box(
modifier = Modifier
.size(38.dp)
.background(Color(status.avatarColor), CircleShape),
contentAlignment = Alignment.Center
) {
Text(
text = status.username.take(1).uppercase(),
color = Color.White,
fontSize = 16.sp,
fontWeight = FontWeight.Bold
)
}
Spacer(modifier = Modifier.width(10.dp))
Column {
Text(
text = status.username,
color = Color.White,
fontSize = 15.sp,
fontWeight = FontWeight.Bold
)
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = “WhatsApp Status”,
color = Color.LightGray.copy(alpha = 0.82f),
fontSize = 11.sp
)
Spacer(modifier = Modifier.width(4.dp))
Text(
text = “• ${status.timestamp}”,
color = Color.LightGray.copy(alpha = 0.6f),
fontSize = 11.sp
)
}
}
}
// Quick Save inside Floating Header
IconButton(
onClick = {
onDismiss()
onSave()
},
modifier = Modifier
.background(Color(0xFF25D366), CircleShape)
.size(40.dp)
.testTag(“quick_download_button”)
) {
Icon(
imageVector = if (isSaved) Icons.Default.Check else Icons.Default.Download,
contentDescription = “Quick download button option”,
tint = Color.White,
modifier = Modifier.size(20.dp)
)
}
}
// Lower overlay bar options
Column(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.background(
Brush.verticalGradient(
listOf(Color.Transparent, Color.Black.copy(alpha = 0.9f))
)
)
.padding(horizontal = 20.dp, vertical = 24.dp)
) {
if (status.mediaType == MediaType.VIDEO) {
val progressSeconds = (15 * videoPlaybackProgress).toInt()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 12.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = “00:${String.format(“%02d”, progressSeconds)}”,
color = Color.White,
fontSize = 11.sp,
fontWeight = FontWeight.SemiBold
)
LinearProgressIndicator(
progress = { videoPlaybackProgress },
modifier = Modifier
.weight(1f)
.padding(horizontal = 12.dp)
.height(4.dp)
.clip(CircleShape),
color = Color(0xFF25D366),
trackColor = Color.White.copy(alpha = 0.3f)
)
Text(
text = “00:15”,
color = Color.White,
fontSize = 11.sp,
fontWeight = FontWeight.SemiBold
)
}
}
if (status.caption.isNotEmpty()) {
Text(
text = status.caption,
color = Color.White,
fontSize = 15.sp,
fontWeight = FontWeight.Medium,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp, top = 4.dp),
textAlign = TextAlign.Center
)
}
HorizontalDivider(
color = Color.White.copy(alpha = 0.15f),
modifier = Modifier.padding(bottom = 16.dp)
)
Button(
onClick = {
onDismiss()
onSave()
},
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
.testTag(“preview_save_button”),
colors = ButtonDefaults.buttonColors(
containerColor = if (isSaved) Color(0xFF1B5E20) else Color(0xFF008069)
),
shape = RoundedCornerShape(24.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Icon(
imageVector = if (isSaved) Icons.Default.CheckCircle else Icons.Default.DownloadForOffline,
contentDescription = null,
tint = Color.White
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = if (isSaved) “STATUS SAVED TO GALLERY” else “DOWNLOAD TO GALLERY”,
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 14.sp
)
}
}
}
}
}
}