Skip to content

Commit 17277c7

Browse files
authored
msbelaid/#105_Permission_List_item (#118)
1 parent 636027e commit 17277c7

16 files changed

Lines changed: 418 additions & 1 deletion

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ dependencies {
9494
implementation(libs.androidx.ui.graphics)
9595
implementation(libs.androidx.ui.tooling.preview)
9696
implementation(libs.androidx.material3)
97+
implementation(libs.androidx.compose.material.icons.extended)
9798
implementation(libs.coil.compose)
9899
implementation(libs.koin.core)
99100
implementation(libs.koin.android)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package app.plugbrain.android.ui.designsystem.components.listitem
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.padding
5+
import androidx.compose.foundation.layout.size
6+
import androidx.compose.foundation.shape.RoundedCornerShape
7+
import androidx.compose.material3.Icon
8+
import androidx.compose.material3.MaterialTheme
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.graphics.vector.ImageVector
12+
import androidx.compose.ui.unit.dp
13+
14+
@Composable
15+
internal fun LeadingIcon(
16+
modifier: Modifier = Modifier.Companion,
17+
icon: ImageVector,
18+
isSelected: Boolean,
19+
) {
20+
val tint =
21+
if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurfaceVariant
22+
val background =
23+
if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant
24+
Icon(
25+
imageVector = icon,
26+
contentDescription = "",
27+
tint = tint,
28+
modifier = modifier
29+
.background(
30+
color = background,
31+
shape = RoundedCornerShape(4.dp),
32+
)
33+
.size(40.dp)
34+
.padding(8.dp),
35+
)
36+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package app.plugbrain.android.ui.designsystem.components.listitem
2+
3+
import android.content.res.Configuration
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.layout.Arrangement
6+
import androidx.compose.foundation.layout.Column
7+
import androidx.compose.foundation.layout.Row
8+
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.material.icons.Icons
10+
import androidx.compose.material.icons.automirrored.rounded.TrendingUp
11+
import androidx.compose.material.icons.rounded.LockOpen
12+
import androidx.compose.material.icons.rounded.TrackChanges
13+
import androidx.compose.material3.MaterialTheme
14+
import androidx.compose.material3.Text
15+
import androidx.compose.runtime.Composable
16+
import androidx.compose.ui.Alignment
17+
import androidx.compose.ui.Modifier
18+
import androidx.compose.ui.graphics.vector.ImageVector
19+
import androidx.compose.ui.tooling.preview.Preview
20+
import androidx.compose.ui.unit.dp
21+
import app.plugbrain.android.ui.theme.MathlockAppTheme
22+
23+
@Composable
24+
fun PlugInfoListItem(
25+
title: String,
26+
description: String,
27+
icon: ImageVector,
28+
) {
29+
Row(
30+
horizontalArrangement = Arrangement.spacedBy(24.dp),
31+
verticalAlignment = Alignment.CenterVertically,
32+
modifier = Modifier
33+
.background(MaterialTheme.colorScheme.surface),
34+
) {
35+
LeadingIcon(
36+
icon = icon,
37+
isSelected = false,
38+
modifier = Modifier.align(Alignment.Top).padding(top = 3.dp),
39+
)
40+
Column(
41+
verticalArrangement = Arrangement.spacedBy(4.dp),
42+
modifier = Modifier.weight(1f),
43+
) {
44+
Text(title, style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onSurface)
45+
Text(description, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurface)
46+
}
47+
}
48+
}
49+
50+
@Preview(
51+
name = "Light Mode",
52+
showBackground = true,
53+
uiMode = Configuration.UI_MODE_NIGHT_NO,
54+
)
55+
@Preview(
56+
name = "Dark Mode",
57+
showBackground = true,
58+
uiMode = Configuration.UI_MODE_NIGHT_YES,
59+
)
60+
@Composable
61+
private fun PermissionListItemPreview() {
62+
MathlockAppTheme(dynamicColor = false) {
63+
Column(
64+
verticalArrangement = Arrangement.spacedBy(24.dp),
65+
modifier = Modifier
66+
.background(MaterialTheme.colorScheme.surface)
67+
.padding(32.dp),
68+
) {
69+
PlugInfoListItem(
70+
title = "Focus your attention",
71+
description = "Spend less time on apps that distract you.",
72+
icon = Icons.Rounded.TrackChanges,
73+
)
74+
PlugInfoListItem(
75+
title = "Unlock with a challenge",
76+
description = "Solve a quick math challenge to keep using the app.",
77+
icon = Icons.Rounded.LockOpen,
78+
)
79+
PlugInfoListItem(
80+
title = "Gets harder the longer you stay",
81+
description = "Challenges increase in difficulty the longer you keep scrolling.",
82+
icon = Icons.AutoMirrored.Rounded.TrendingUp,
83+
)
84+
}
85+
}
86+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package app.plugbrain.android.ui.designsystem.components.listitem
2+
3+
import android.content.res.Configuration
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.border
6+
import androidx.compose.foundation.clickable
7+
import androidx.compose.foundation.layout.Arrangement
8+
import androidx.compose.foundation.layout.Column
9+
import androidx.compose.foundation.layout.Row
10+
import androidx.compose.foundation.layout.padding
11+
import androidx.compose.foundation.shape.RoundedCornerShape
12+
import androidx.compose.material.icons.Icons
13+
import androidx.compose.material.icons.filled.Search
14+
import androidx.compose.material.icons.rounded.Layers
15+
import androidx.compose.material3.MaterialTheme
16+
import androidx.compose.material3.Text
17+
import androidx.compose.runtime.Composable
18+
import androidx.compose.ui.Alignment
19+
import androidx.compose.ui.Modifier
20+
import androidx.compose.ui.draw.alpha
21+
import androidx.compose.ui.graphics.vector.ImageVector
22+
import androidx.compose.ui.tooling.preview.Preview
23+
import androidx.compose.ui.unit.dp
24+
import app.plugbrain.android.ui.theme.MathlockAppTheme
25+
26+
@Composable
27+
fun PlugPermissionListItem(
28+
title: String,
29+
description: String,
30+
icon: ImageVector,
31+
isGranted: Boolean,
32+
onClick: () -> Unit,
33+
) {
34+
Row(
35+
horizontalArrangement = Arrangement.spacedBy(12.dp),
36+
verticalAlignment = Alignment.CenterVertically,
37+
modifier = Modifier
38+
.alpha(if (isGranted) 0.5f else 1f)
39+
.border(
40+
width = 1.dp,
41+
color = MaterialTheme.colorScheme.outlineVariant,
42+
shape = RoundedCornerShape(8.dp),
43+
)
44+
.background(MaterialTheme.colorScheme.surface)
45+
.background(
46+
color = if (isGranted) MaterialTheme.colorScheme.primary.copy(0.1f) else MaterialTheme.colorScheme.surface,
47+
shape = RoundedCornerShape(8.dp),
48+
)
49+
.clickable(onClick = onClick)
50+
.padding(vertical = 12.dp, horizontal = 16.dp),
51+
) {
52+
LeadingIcon(
53+
icon = icon,
54+
isSelected = isGranted,
55+
modifier = Modifier.align(Alignment.Top).padding(top = 3.dp),
56+
)
57+
Column(
58+
verticalArrangement = Arrangement.spacedBy(4.dp),
59+
modifier = Modifier.weight(1f),
60+
) {
61+
Text(title, style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurface)
62+
Text(description, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurface)
63+
}
64+
TrailingIcon(isGranted)
65+
}
66+
}
67+
68+
@Preview(
69+
name = "Light Mode",
70+
showBackground = true,
71+
uiMode = Configuration.UI_MODE_NIGHT_NO,
72+
)
73+
@Preview(
74+
name = "Dark Mode",
75+
showBackground = true,
76+
uiMode = Configuration.UI_MODE_NIGHT_YES,
77+
)
78+
@Composable
79+
private fun PermissionListItemPreview() {
80+
MathlockAppTheme(dynamicColor = false) {
81+
Column(
82+
verticalArrangement = Arrangement.spacedBy(8.dp),
83+
modifier = Modifier
84+
.background(MaterialTheme.colorScheme.surface)
85+
.padding(32.dp),
86+
) {
87+
PlugPermissionListItem(
88+
title = "App Usage access",
89+
description = "Lets PlugBrain track app usage so it can block distracting apps at the right time.",
90+
isGranted = true,
91+
icon = Icons.Filled.Search,
92+
onClick = {},
93+
)
94+
PlugPermissionListItem(
95+
title = "Display over other apps",
96+
description = "Allows PlugBrain to display a challenge while you use a distracting app.",
97+
isGranted = false,
98+
icon = Icons.Rounded.Layers,
99+
onClick = {},
100+
)
101+
}
102+
}
103+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package app.plugbrain.android.ui.designsystem.components.listitem
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.padding
5+
import androidx.compose.foundation.layout.size
6+
import androidx.compose.foundation.shape.RoundedCornerShape
7+
import androidx.compose.material.icons.Icons
8+
import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight
9+
import androidx.compose.material.icons.rounded.Check
10+
import androidx.compose.material3.Icon
11+
import androidx.compose.material3.MaterialTheme
12+
import androidx.compose.runtime.Composable
13+
import androidx.compose.ui.Modifier
14+
import androidx.compose.ui.graphics.Color
15+
import androidx.compose.ui.unit.dp
16+
17+
@Composable
18+
internal fun TrailingIcon(isSelected: Boolean) {
19+
val tint =
20+
if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurfaceVariant
21+
val background =
22+
if (isSelected) MaterialTheme.colorScheme.primary else Color.Companion.Transparent
23+
Icon(
24+
imageVector = if (isSelected) Icons.Rounded.Check else Icons.AutoMirrored.Rounded.KeyboardArrowRight,
25+
contentDescription = "",
26+
tint = tint,
27+
modifier = Modifier.Companion
28+
.background(color = background, shape = RoundedCornerShape(50))
29+
.size(24.dp)
30+
.then(if (isSelected) Modifier.Companion.padding(4.dp) else Modifier.Companion),
31+
)
32+
}

app/src/main/java/app/plugbrain/android/ui/theme/Theme.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ private val DarkColorScheme =
2121
background = Neutral900,
2222
error = Error600,
2323
outline = Neutral200,
24+
outlineVariant = Neutral500,
2425
surfaceVariant = Neutral500,
2526
onSurfaceVariant = Neutral300,
2627
tertiary = Success300,
28+
onTertiary = White,
2729
)
2830

2931
private val LightColorScheme =
@@ -37,9 +39,11 @@ private val LightColorScheme =
3739
background = White,
3840
error = Error500,
3941
outline = Neutral300,
42+
outlineVariant = Neutral200,
4043
surfaceVariant = Neutral100,
41-
onSurfaceVariant = Neutral300,
44+
onSurfaceVariant = Neutral400,
4245
tertiary = Success500,
46+
onTertiary = White,
4347
)
4448

4549
@Composable

app/src/main/java/app/plugbrain/android/ui/theme/Type.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ val Typography =
4040
),
4141

4242
titleLarge = TextStyle(
43+
fontFamily = SoraFontFamily,
44+
fontWeight = FontWeight.SemiBold,
45+
fontSize = 16.sp,
46+
lineHeight = 22.sp,
47+
),
48+
49+
titleMedium = TextStyle(
4350
fontFamily = SoraFontFamily,
4451
fontWeight = FontWeight.SemiBold,
4552
fontSize = 14.sp,
@@ -53,6 +60,13 @@ val Typography =
5360
lineHeight = 22.sp,
5461
),
5562

63+
bodyMedium = TextStyle(
64+
fontFamily = SoraFontFamily,
65+
fontWeight = FontWeight.Normal,
66+
fontSize = 14.sp,
67+
lineHeight = 17.sp,
68+
),
69+
5670
labelLarge = TextStyle(
5771
fontFamily = SoraFontFamily,
5872
fontWeight = FontWeight.SemiBold,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package app.plugbrain.android.screenshots
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.padding
7+
import androidx.compose.material.icons.Icons
8+
import androidx.compose.material.icons.automirrored.rounded.TrendingUp
9+
import androidx.compose.material.icons.rounded.LockOpen
10+
import androidx.compose.material.icons.rounded.TrackChanges
11+
import androidx.compose.material3.MaterialTheme
12+
import androidx.compose.runtime.Composable
13+
import androidx.compose.ui.Modifier
14+
import androidx.compose.ui.unit.dp
15+
import app.cash.paparazzi.DeviceConfig
16+
import app.cash.paparazzi.Paparazzi
17+
import app.plugbrain.android.ui.designsystem.components.listitem.PlugInfoListItem
18+
import app.plugbrain.android.ui.theme.MathlockAppTheme
19+
import org.junit.Rule
20+
import org.junit.Test
21+
22+
class InfoListItemScreenshotTest {
23+
@get:Rule
24+
val paparazzi =
25+
Paparazzi(
26+
deviceConfig = DeviceConfig.PIXEL_5,
27+
)
28+
29+
@Test
30+
fun permissionListItemGrantedTest() {
31+
paparazzi.snapshot {
32+
infoItemTest()
33+
}
34+
}
35+
36+
@Test
37+
fun permissionListItemDarkModeTest() {
38+
paparazzi.snapshot {
39+
infoItemTest(darkTheme = true)
40+
}
41+
}
42+
43+
@Composable
44+
private fun infoItemTest(darkTheme: Boolean = false) {
45+
MathlockAppTheme(dynamicColor = false, darkTheme = darkTheme) {
46+
Column(
47+
verticalArrangement = Arrangement.spacedBy(24.dp),
48+
modifier =
49+
Modifier
50+
.background(MaterialTheme.colorScheme.surface)
51+
.padding(32.dp),
52+
) {
53+
PlugInfoListItem(
54+
title = "Focus your attention",
55+
description = "Spend less time on apps that distract you.",
56+
icon = Icons.Rounded.TrackChanges,
57+
)
58+
PlugInfoListItem(
59+
title = "Unlock with a challenge",
60+
description = "Solve a quick math challenge to keep using the app.",
61+
icon = Icons.Rounded.LockOpen,
62+
)
63+
PlugInfoListItem(
64+
title = "Gets harder the longer you stay",
65+
description = "Challenges increase in difficulty the longer you keep scrolling.",
66+
icon = Icons.AutoMirrored.Rounded.TrendingUp,
67+
)
68+
}
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)