Skip to content

Commit ae31b27

Browse files
authored
Adapt profile, notifications, and comments screens to dark mode (#68)
1 parent 47ab3a3 commit ae31b27

File tree

6 files changed

+121
-72
lines changed

6 files changed

+121
-72
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
5454
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
5555
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
5656
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
57+
androidx-material2 = { group = "androidx.compose.material", name = "material" }
5758
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
5859
coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
5960
coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" }

stream-feeds-android-sample/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ dependencies {
6666
implementation(libs.androidx.ui.graphics)
6767
implementation(libs.androidx.ui.tooling.preview)
6868
implementation(libs.androidx.material3)
69+
implementation(libs.androidx.material2)
6970
implementation(libs.composeDestinations.core)
7071
ksp(libs.composeDestinations.ksp)
7172
implementation(libs.composeDestinations.bottomSheet)

stream-feeds-android-sample/src/main/java/io/getstream/feeds/android/sample/feed/CommentsBottomSheet.kt

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
4040
import androidx.compose.material3.FloatingActionButton
4141
import androidx.compose.material3.Icon
4242
import androidx.compose.material3.MaterialTheme
43+
import androidx.compose.material3.Surface
4344
import androidx.compose.material3.Text
4445
import androidx.compose.runtime.Composable
4546
import androidx.compose.runtime.LaunchedEffect
@@ -81,27 +82,31 @@ data class CommentsSheetArgs(val feedId: String, val activityId: String) {
8182
)
8283
@OptIn(ExperimentalMaterial3Api::class)
8384
@Composable
84-
fun ColumnScope.CommentsBottomSheet(navigator: DestinationsNavigator) {
85+
fun CommentsBottomSheet(navigator: DestinationsNavigator) {
8586
val viewModel = hiltViewModel<CommentsSheetViewModel>()
8687
val state by viewModel.state.collectAsStateWithLifecycle()
8788

88-
when (val state = state) {
89-
AsyncResource.Loading -> LoadingScreen()
89+
Surface {
90+
when (val state = state) {
91+
AsyncResource.Loading -> LoadingScreen()
9092

91-
AsyncResource.Error -> {
92-
LaunchedEffect(Unit) { navigator.popBackStack() }
93-
return
94-
}
93+
AsyncResource.Error -> {
94+
LaunchedEffect(Unit) { navigator.popBackStack() }
95+
return@Surface
96+
}
9597

96-
is AsyncResource.Content -> {
97-
val comments by state.data.second.comments.collectAsStateWithLifecycle()
98-
val currentUserId = state.data.first.id
98+
is AsyncResource.Content -> {
99+
val comments by state.data.second.comments.collectAsStateWithLifecycle()
100+
val currentUserId = state.data.first.id
99101

100-
CommentsBottomSheetContent(
101-
comments = comments,
102-
currentUserId = currentUserId,
103-
onEvent = viewModel::onEvent,
104-
)
102+
Column {
103+
CommentsBottomSheetContent(
104+
comments = comments,
105+
currentUserId = currentUserId,
106+
onEvent = viewModel::onEvent,
107+
)
108+
}
109+
}
105110
}
106111
}
107112
}

stream-feeds-android-sample/src/main/java/io/getstream/feeds/android/sample/notification/NotificationsScreen.kt

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import androidx.compose.foundation.lazy.LazyColumn
3131
import androidx.compose.foundation.lazy.items
3232
import androidx.compose.foundation.shape.CircleShape
3333
import androidx.compose.material3.Button
34+
import androidx.compose.material3.Surface
3435
import androidx.compose.material3.Text
3536
import androidx.compose.runtime.Composable
3637
import androidx.compose.runtime.LaunchedEffect
@@ -66,19 +67,23 @@ data class NotificationsScreenArgs(val feedId: String) {
6667
fun NotificationsScreen(navigator: DestinationsNavigator) {
6768
val viewModel = hiltViewModel<NotificationsViewModel>()
6869
val state by viewModel.state.collectAsStateWithLifecycle()
69-
when (val state = state) {
70-
AsyncResource.Loading -> LoadingScreen()
71-
AsyncResource.Error -> {
72-
LaunchedEffect(Unit) { navigator.popBackStack() }
73-
return
70+
71+
Surface {
72+
when (val state = state) {
73+
AsyncResource.Loading -> LoadingScreen()
74+
AsyncResource.Error -> {
75+
LaunchedEffect(Unit) { navigator.popBackStack() }
76+
return@Surface
77+
}
78+
79+
is AsyncResource.Content ->
80+
NotificationsScreen(
81+
state = state.data,
82+
onMarkAllSeen = viewModel::onMarkAllSeen,
83+
onMarkAggregatedActivityRead = viewModel::onMarkAggregatedActivityRead,
84+
onMarkAllRead = viewModel::onMarkAllRead,
85+
)
7486
}
75-
is AsyncResource.Content ->
76-
NotificationsScreen(
77-
state = state.data,
78-
onMarkAllSeen = viewModel::onMarkAllSeen,
79-
onMarkAggregatedActivityRead = viewModel::onMarkAggregatedActivityRead,
80-
onMarkAllRead = viewModel::onMarkAllRead,
81-
)
8287
}
8388
}
8489

stream-feeds-android-sample/src/main/java/io/getstream/feeds/android/sample/profile/ProfileScreen.kt

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,25 @@
1616
package io.getstream.feeds.android.sample.profile
1717

1818
import androidx.compose.foundation.BorderStroke
19-
import androidx.compose.foundation.clickable
2019
import androidx.compose.foundation.layout.Arrangement
2120
import androidx.compose.foundation.layout.Column
2221
import androidx.compose.foundation.layout.Row
2322
import androidx.compose.foundation.layout.fillMaxSize
2423
import androidx.compose.foundation.layout.fillMaxWidth
2524
import androidx.compose.foundation.layout.padding
2625
import androidx.compose.foundation.layout.systemBarsPadding
27-
import androidx.compose.foundation.lazy.LazyColumn
28-
import androidx.compose.foundation.lazy.items
26+
import androidx.compose.foundation.rememberScrollState
2927
import androidx.compose.foundation.shape.CircleShape
30-
import androidx.compose.material3.Card
31-
import androidx.compose.material3.CardDefaults
28+
import androidx.compose.foundation.verticalScroll
3229
import androidx.compose.material3.HorizontalDivider
30+
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
31+
import androidx.compose.material3.MaterialTheme
32+
import androidx.compose.material3.OutlinedButton
33+
import androidx.compose.material3.Surface
3334
import androidx.compose.material3.Text
35+
import androidx.compose.material3.TextButton
3436
import androidx.compose.runtime.Composable
37+
import androidx.compose.runtime.CompositionLocalProvider
3538
import androidx.compose.runtime.LaunchedEffect
3639
import androidx.compose.runtime.getValue
3740
import androidx.compose.ui.Alignment
@@ -70,21 +73,23 @@ fun ProfileScreen(navigator: DestinationsNavigator) {
7073

7174
val state by viewModel.state.collectAsStateWithLifecycle()
7275

73-
when (val state = state) {
74-
AsyncResource.Loading -> LoadingScreen()
76+
Surface {
77+
when (val state = state) {
78+
AsyncResource.Loading -> LoadingScreen()
7579

76-
AsyncResource.Error -> {
77-
LaunchedEffect(Unit) { navigator.popBackStack() }
78-
return
79-
}
80+
AsyncResource.Error -> {
81+
LaunchedEffect(Unit) { navigator.popBackStack() }
82+
return@Surface
83+
}
8084

81-
is AsyncResource.Content ->
82-
ProfileScreen(
83-
state = state.data,
84-
followSuggestions = viewModel.followSuggestions,
85-
onFollowClick = viewModel::follow,
86-
onUnfollowClick = viewModel::unfollow,
87-
)
85+
is AsyncResource.Content ->
86+
ProfileScreen(
87+
state = state.data,
88+
followSuggestions = viewModel.followSuggestions,
89+
onFollowClick = viewModel::follow,
90+
onUnfollowClick = viewModel::unfollow,
91+
)
92+
}
8893
}
8994
}
9095

@@ -95,7 +100,12 @@ fun ProfileScreen(
95100
onFollowClick: (FeedId) -> Unit,
96101
onUnfollowClick: (FeedId) -> Unit,
97102
) {
98-
Column(modifier = Modifier.fillMaxSize().systemBarsPadding().padding(16.dp)) {
103+
val scrollState = rememberScrollState()
104+
105+
Column(
106+
modifier =
107+
Modifier.fillMaxSize().systemBarsPadding().verticalScroll(scrollState).padding(16.dp)
108+
) {
99109
Text(
100110
text = "Profile",
101111
fontSize = 24.sp,
@@ -154,14 +164,12 @@ fun ProfileScreen(
154164
val followSuggestions by followSuggestions.collectAsStateWithLifecycle()
155165
SectionTitle("Who to follow")
156166
if (followSuggestions.isNotEmpty()) {
157-
LazyColumn {
158-
items(followSuggestions) {
159-
FollowSuggestionItem(
160-
owner = it.createdBy,
161-
fid = it.fid,
162-
onFollowClick = onFollowClick,
163-
)
164-
}
167+
followSuggestions.forEach {
168+
FollowSuggestionItem(
169+
owner = it.createdBy,
170+
fid = it.fid,
171+
onFollowClick = onFollowClick,
172+
)
165173
}
166174
} else {
167175
Text(text = "-No follow suggestions-")
@@ -191,7 +199,7 @@ private fun <T> ProfileSection(
191199
if (items.isNotEmpty()) {
192200
items.forEach { item -> itemContent(item) }
193201
} else {
194-
Text(text = emptyText, color = Color.Gray)
202+
Text(text = emptyText, color = MaterialTheme.colorScheme.onSurfaceVariant)
195203
}
196204

197205
HorizontalDivider(Modifier.fillMaxWidth().padding(vertical = 16.dp))
@@ -200,20 +208,20 @@ private fun <T> ProfileSection(
200208
@Composable
201209
fun FollowingItem(follow: FollowData, onUnfollowClick: (FeedId) -> Unit) {
202210
Row(
203-
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp),
211+
modifier = Modifier.fillMaxWidth(),
204212
horizontalArrangement = Arrangement.SpaceBetween,
213+
verticalAlignment = Alignment.CenterVertically,
205214
) {
206215
Text(
207216
text = follow.targetFeed.createdBy.run { name ?: id },
208217
fontSize = 16.sp,
209218
fontWeight = FontWeight.Bold,
210219
)
211-
Text(
212-
modifier = Modifier.clickable { onUnfollowClick(follow.targetFeed.fid) },
213-
text = "Unfollow",
214-
fontSize = 14.sp,
215-
color = Color.Blue,
216-
)
220+
CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) {
221+
TextButton(onClick = { onUnfollowClick(follow.targetFeed.fid) }) {
222+
Text(text = "Unfollow")
223+
}
224+
}
217225
}
218226
}
219227

@@ -237,19 +245,13 @@ fun FollowSuggestionItem(owner: UserData, fid: FeedId, onFollowClick: (FeedId) -
237245
)
238246
}
239247
}
240-
Card(
248+
OutlinedButton(
241249
modifier = Modifier.padding(start = 8.dp).align(Alignment.CenterVertically),
242250
shape = CircleShape,
243251
border = BorderStroke(1.dp, Color.Gray),
244-
colors = CardDefaults.cardColors(containerColor = Color.Transparent),
245252
onClick = { onFollowClick(fid) },
246253
) {
247-
Text(
248-
text = "Follow",
249-
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
250-
fontSize = 14.sp,
251-
color = Color.Blue,
252-
)
254+
Text(text = "Follow")
253255
}
254256
}
255257
}

stream-feeds-android-sample/src/main/java/io/getstream/feeds/android/sample/ui/theme/Theme.kt

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,33 @@ import androidx.compose.runtime.Composable
2626
import androidx.compose.ui.platform.LocalContext
2727

2828
private val DarkColorScheme = darkColorScheme()
29-
3029
private val LightColorScheme = lightColorScheme()
3130

31+
private val LegacyDarkColors =
32+
androidx.compose.material.darkColors(
33+
primary = DarkColorScheme.primary,
34+
primaryVariant = DarkColorScheme.primaryContainer,
35+
secondary = DarkColorScheme.secondary,
36+
background = DarkColorScheme.background,
37+
surface = DarkColorScheme.surface,
38+
onPrimary = DarkColorScheme.onPrimary,
39+
onSecondary = DarkColorScheme.onSecondary,
40+
onBackground = DarkColorScheme.onBackground,
41+
onSurface = DarkColorScheme.onSurface,
42+
)
43+
private val LegacyLightColors =
44+
androidx.compose.material.lightColors(
45+
primary = LightColorScheme.primary,
46+
primaryVariant = LightColorScheme.primaryContainer,
47+
secondary = LightColorScheme.secondary,
48+
background = LightColorScheme.background,
49+
surface = LightColorScheme.surface,
50+
onPrimary = LightColorScheme.onPrimary,
51+
onSecondary = LightColorScheme.onSecondary,
52+
onBackground = LightColorScheme.onBackground,
53+
onSurface = LightColorScheme.onSurface,
54+
)
55+
3256
@Composable
3357
fun AppTheme(
3458
darkTheme: Boolean = isSystemInDarkTheme(),
@@ -46,5 +70,16 @@ fun AppTheme(
4670
else -> LightColorScheme
4771
}
4872

49-
MaterialTheme(colorScheme = colorScheme, typography = Typography, content = content)
73+
val legacyColors =
74+
when (darkTheme) {
75+
true -> LegacyDarkColors
76+
false -> LegacyLightColors
77+
}
78+
79+
// Also apply Material 2 theme because the bottom sheet from Compose Destinations uses it. We
80+
// can remove this alongside the material 2 library once they add support
81+
// https://github.com/raamcosta/compose-destinations/issues/756.
82+
androidx.compose.material.MaterialTheme(colors = legacyColors) {
83+
MaterialTheme(colorScheme = colorScheme, typography = Typography, content = content)
84+
}
5085
}

0 commit comments

Comments
 (0)