Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ plugins {

android {
namespace = "com.prauga.pvot"
compileSdk {
version = release(36)
}
compileSdk = 36

defaultConfig {
applicationId = "com.prauga.pvot"
Expand Down Expand Up @@ -56,6 +54,11 @@ dependencies {
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)

// Add Material Icons
implementation("androidx.compose.material:material-icons-core")
implementation("androidx.compose.material:material-icons-extended")

testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
Expand Down
70 changes: 38 additions & 32 deletions app/src/main/java/com/prauga/pvot/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
Expand All @@ -18,9 +19,11 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.prauga.pvot.utils.PreferencesManager
import com.prauga.pvot.designsystem.components.navigation.PvotNavBar
import com.prauga.pvot.designsystem.components.navigation.PvotTabItem
Expand Down Expand Up @@ -74,44 +77,47 @@ fun DesignSystemShowcase() {

Scaffold(
modifier = Modifier.fillMaxSize(),
containerColor = Color.Transparent,
bottomBar = {
PvotNavBar(
selectedTab = selectedTab,
onTabClick = { selectedTab = it },
tabs = tabs
)
}
containerColor = MaterialTheme.colorScheme.background,
) { innerPadding ->
val containerModifer = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.padding(top = innerPadding.calculateTopPadding())
Box(modifier = Modifier.fillMaxSize()) {
// Main Content Area (Full Screen)
val screenModifier = Modifier
.fillMaxSize()
.padding(top = innerPadding.calculateTopPadding()) // Respect status bar

when (selectedTab) {
0 -> HomeScreen(
label = "Home",
modifier = containerModifer
)
when (selectedTab) {
0 -> HomeScreen(
label = "Home",
modifier = screenModifier
)

1 -> AppsScreen(
label = "Apps",
modifier = containerModifer
)
1 -> AppsScreen(
label = "Apps",
modifier = screenModifier
)

2 -> CatalogScreen(
label = "Design Catalog",
modifier = containerModifer
)
2 -> CatalogScreen(
label = "Design Catalog",
modifier = screenModifier
)

3 -> AboutScreen(
label = "About",
modifier = containerModifer
)
3 -> AboutScreen(
label = "About",
modifier = screenModifier
)

else -> EmptyScreen(
label = "None",
modifier = screenModifier
)
}

else -> EmptyScreen(
label = "None",
modifier = containerModifer
// Floating Navigation Bar (On Top)
PvotNavBar(
selectedTab = selectedTab,
onTabClick = { selectedTab = it },
tabs = tabs,
modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = 16.dp)
)
}
}
Expand Down
139 changes: 97 additions & 42 deletions app/src/main/java/com/prauga/pvot/components/AppCard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,33 @@

package com.prauga.pvot.components

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil3.compose.AsyncImage
import com.prauga.pvot.R
import com.prauga.pvot.data.model.GithubRepo
Expand All @@ -36,14 +40,33 @@ fun AppCard(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Card(
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
val scale by animateFloatAsState(if (isPressed) 0.96f else 1f, label = "scale")

val cardColor = if (isSystemInDarkTheme()) {
MaterialTheme.colorScheme.surface.copy(alpha = 0.4f)
} else {
MaterialTheme.colorScheme.surface
}

Surface(
modifier = modifier
.fillMaxWidth()
.clickable(onClick = onClick),
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
)
.graphicsLayer {
scaleX = scale
scaleY = scale
}
.clip(RoundedCornerShape(32.dp))
.clickable(
interactionSource = interactionSource,
indication = ripple(),
onClick = onClick
),
shape = RoundedCornerShape(32.dp),
color = cardColor,
tonalElevation = 2.dp,
shadowElevation = 2.dp
) {
Column(
modifier = Modifier.fillMaxWidth()
Expand All @@ -53,50 +76,82 @@ fun AppCard(
contentDescription = stringResource(R.string.cd_preview, repo.name),
modifier = Modifier
.fillMaxWidth()
.aspectRatio(2f)
.clip(RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)),
contentScale = ContentScale.Crop
.aspectRatio(1.91f)
.clip(RoundedCornerShape(topStart = 32.dp, topEnd = 32.dp)),
contentScale = ContentScale.FillWidth
)

Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.background(
brush = Brush.verticalGradient(
colors = listOf(
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.2f),
Color.Transparent
)
)
)
.padding(24.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = repo.name,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
Icon(
painter = painterResource(id = R.drawable.ic_star),
contentDescription = stringResource(R.string.stars),
modifier = Modifier.size(16.dp),
tint = MaterialTheme.colorScheme.primary
)
Column(modifier = Modifier.weight(1f)) {
Text(
text = repo.stars.toString(),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary
text = repo.name,
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.ExtraBold,
color = MaterialTheme.colorScheme.onSurface,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)

Surface(
shape = RoundedCornerShape(8.dp),
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f),
contentColor = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(top = 4.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
) {
Icon(
imageVector = Icons.Default.Star,
contentDescription = null,
modifier = Modifier.size(12.dp)
)
Text(
text = "${repo.stars} Stars",
style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Bold
)
}
}
}

// Unified Arrow Icon (Clean, no background box)
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
modifier = Modifier.size(24.dp).padding(start = 8.dp)
)
}

if (repo.description != null) {
Text(
text = repo.description,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(top = 8.dp)
modifier = Modifier.padding(top = 16.dp),
lineHeight = 22.sp
)
}
}
Expand Down
Loading