Skip to content

Commit

Permalink
Implement new app shell
Browse files Browse the repository at this point in the history
  • Loading branch information
AleksandarIlic committed Oct 9, 2024
1 parent 399cce5 commit 3fdee18
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,11 @@ import net.primal.android.LocalPrimalTheme
import net.primal.android.R
import net.primal.android.core.compose.foundation.ClickDebounce
import net.primal.android.core.compose.icons.PrimalIcons
import net.primal.android.core.compose.icons.primaliconpack.Explore
import net.primal.android.core.compose.icons.primaliconpack.Home
import net.primal.android.core.compose.icons.primaliconpack.HomeFilled
import net.primal.android.core.compose.icons.primaliconpack.LongRead
import net.primal.android.core.compose.icons.primaliconpack.LongReadFilled
import net.primal.android.core.compose.icons.primaliconpack.Messages
import net.primal.android.core.compose.icons.primaliconpack.MessagesFilled
import net.primal.android.core.compose.icons.primaliconpack.NavWalletBolt
import net.primal.android.core.compose.icons.primaliconpack.NavWalletBoltFilled
import net.primal.android.core.compose.icons.primaliconpack.Notifications
Expand Down Expand Up @@ -82,7 +81,6 @@ fun PrimalNavigationBar(
containerColor = AppTheme.colorScheme.surface,
) {
val badgesMap = mapOf(
Pair(PrimalTopLevelDestination.Messages, badges.unreadMessagesCount),
Pair(PrimalTopLevelDestination.Notifications, badges.unreadNotificationsCount),
)
PrimalTopLevelDestination.entries.forEach {
Expand Down Expand Up @@ -112,7 +110,6 @@ fun PrimalNavigationBarLightningBolt(
) {
val clickDebounce by remember(onTopLevelDestinationChanged) { mutableStateOf(ClickDebounce()) }
val badgesMap = mapOf(
Pair(PrimalTopLevelDestination.Messages, badges.unreadMessagesCount),
Pair(PrimalTopLevelDestination.Notifications, badges.unreadNotificationsCount),
)

Expand Down Expand Up @@ -171,7 +168,7 @@ fun PrimalNavigationBarLightningBolt(
)

NavItemDestination(
destination = PrimalTopLevelDestination.Messages,
destination = PrimalTopLevelDestination.Explore,
activeDestination = activeDestination,
onTopLevelDestinationChanged = onTopLevelDestinationChanged,
onActiveDestinationClick = onActiveDestinationClick,
Expand Down Expand Up @@ -310,16 +307,16 @@ enum class PrimalTopLevelDestination {
Reads,
Wallet,
Notifications,
Messages,
Explore,
}

private fun PrimalTopLevelDestination.imageVector(): ImageVector {
return when (this) {
PrimalTopLevelDestination.Home -> PrimalIcons.Home
PrimalTopLevelDestination.Reads -> PrimalIcons.LongRead
PrimalTopLevelDestination.Wallet -> PrimalIcons.NavWalletBolt
PrimalTopLevelDestination.Messages -> PrimalIcons.Messages
PrimalTopLevelDestination.Notifications -> PrimalIcons.Notifications
PrimalTopLevelDestination.Explore -> PrimalIcons.Explore
}
}

Expand All @@ -328,8 +325,8 @@ private fun PrimalTopLevelDestination.imageVectorSelected(): ImageVector {
PrimalTopLevelDestination.Home -> PrimalIcons.HomeFilled
PrimalTopLevelDestination.Reads -> PrimalIcons.LongReadFilled
PrimalTopLevelDestination.Wallet -> PrimalIcons.NavWalletBoltFilled
PrimalTopLevelDestination.Messages -> PrimalIcons.MessagesFilled
PrimalTopLevelDestination.Notifications -> PrimalIcons.NotificationsFilled
PrimalTopLevelDestination.Explore -> PrimalIcons.Explore
}
}

Expand All @@ -339,8 +336,8 @@ private fun PrimalTopLevelDestination.label(): String {
PrimalTopLevelDestination.Home -> stringResource(id = R.string.primary_destination_feed_label)
PrimalTopLevelDestination.Reads -> stringResource(id = R.string.primary_destination_reads_label)
PrimalTopLevelDestination.Wallet -> stringResource(id = R.string.primary_destination_wallet_label)
PrimalTopLevelDestination.Messages -> stringResource(id = R.string.primary_destination_messages_label)
PrimalTopLevelDestination.Notifications -> stringResource(id = R.string.primary_destination_notifications_label)
PrimalTopLevelDestination.Explore -> stringResource(id = R.string.primary_destination_explore_label)
}
}

Expand Down
44 changes: 34 additions & 10 deletions app/src/main/kotlin/net/primal/android/drawer/PrimalDrawer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Badge
import androidx.compose.material3.BadgedBox
import androidx.compose.material3.DrawerState
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
Expand Down Expand Up @@ -48,6 +53,7 @@ import net.primal.android.core.compose.preview.PrimalPreview
import net.primal.android.core.utils.formatNip05Identifier
import net.primal.android.theme.AppTheme
import net.primal.android.theme.domain.PrimalTheme
import net.primal.android.user.domain.Badges
import net.primal.android.user.domain.UserAccount

@Composable
Expand Down Expand Up @@ -109,6 +115,7 @@ fun PrimalDrawer(
.weight(1.0f)
.padding(vertical = 32.dp),
menuItems = state.menuItems,
badges = state.badges,
onDrawerDestinationClick = onDrawerDestinationClick,
)

Expand Down Expand Up @@ -234,6 +241,7 @@ private fun DrawerHeader(userAccount: UserAccount?, onQrCodeClick: () -> Unit) {
private fun DrawerMenu(
modifier: Modifier,
menuItems: List<DrawerScreenDestination>,
badges: Badges,
onDrawerDestinationClick: (DrawerScreenDestination) -> Unit,
) {
LazyColumn(
Expand All @@ -243,20 +251,33 @@ private fun DrawerMenu(
items(
items = menuItems,
key = { it.toString() },
) {
) { item ->
ListItem(
modifier = Modifier.clickable {
onDrawerDestinationClick(it)
onDrawerDestinationClick(item)
},
headlineContent = {
Text(
text = it.label().uppercase(),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp, vertical = 8.dp),
style = AppTheme.typography.titleLarge,
color = AppTheme.colorScheme.onSurfaceVariant,
)
BadgedBox(
badge = {
if (item is DrawerScreenDestination.Messages && badges.unreadMessagesCount > 0) {
Badge(
modifier = Modifier
.size(size = 10.dp)
.offset(x = 8.dp),
containerColor = AppTheme.colorScheme.primary,
)
}
},
) {
Text(
text = item.label().uppercase(),
modifier = Modifier
.wrapContentWidth()
.padding(horizontal = 8.dp, vertical = 8.dp),
style = AppTheme.typography.titleLarge,
color = AppTheme.colorScheme.onSurfaceVariant,
)
}
},
)
}
Expand All @@ -283,6 +304,7 @@ private fun DrawerFooter(onThemeSwitch: () -> Unit) {

sealed class DrawerScreenDestination {
data object Profile : DrawerScreenDestination()
data object Messages : DrawerScreenDestination()
data class Bookmarks(val userId: String) : DrawerScreenDestination()
data object Settings : DrawerScreenDestination()
data object SignOut : DrawerScreenDestination()
Expand All @@ -292,6 +314,7 @@ sealed class DrawerScreenDestination {
private fun DrawerScreenDestination.label(): String {
return when (this) {
DrawerScreenDestination.Profile -> stringResource(R.string.drawer_destination_profile)
DrawerScreenDestination.Messages -> stringResource(R.string.drawer_destination_messages)
is DrawerScreenDestination.Bookmarks -> stringResource(R.string.drawer_destination_bookmarks)
DrawerScreenDestination.Settings -> stringResource(R.string.drawer_destination_settings)
DrawerScreenDestination.SignOut -> stringResource(R.string.drawer_destination_sign_out)
Expand All @@ -306,6 +329,7 @@ fun PrimalDrawerPreview() {
state = PrimalDrawerContract.UiState(
menuItems = listOf(
DrawerScreenDestination.Profile,
DrawerScreenDestination.Messages,
DrawerScreenDestination.Bookmarks(userId = "none"),
DrawerScreenDestination.Settings,
DrawerScreenDestination.SignOut,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.primal.android.drawer

import net.primal.android.user.domain.Badges
import net.primal.android.user.domain.UserAccount

interface PrimalDrawerContract {
Expand All @@ -8,6 +9,7 @@ interface PrimalDrawerContract {
val menuItems: List<DrawerScreenDestination>,
val loading: Boolean = false,
val activeUserAccount: UserAccount? = null,
val badges: Badges = Badges(),
)

sealed class UiEvent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ import kotlinx.coroutines.launch
import net.primal.android.theme.active.ActiveThemeStore
import net.primal.android.theme.domain.PrimalTheme
import net.primal.android.user.accounts.active.ActiveAccountStore
import net.primal.android.user.subscriptions.SubscriptionsManager

@HiltViewModel
class PrimalDrawerViewModel @Inject constructor(
private val activeAccountStore: ActiveAccountStore,
private val activeThemeStore: ActiveThemeStore,
private val subscriptionsManager: SubscriptionsManager,
) : ViewModel() {

private val _state = MutableStateFlow(
PrimalDrawerContract.UiState(
menuItems = listOf(
DrawerScreenDestination.Profile,
DrawerScreenDestination.Messages,
DrawerScreenDestination.Bookmarks(userId = activeAccountStore.activeUserId()),
DrawerScreenDestination.Settings,
DrawerScreenDestination.SignOut,
Expand All @@ -43,6 +46,7 @@ class PrimalDrawerViewModel @Inject constructor(
init {
subscribeToEvents()
observeActiveAccount()
subscribeToBadgesUpdates()
}

private fun subscribeToEvents() =
Expand All @@ -63,6 +67,15 @@ class PrimalDrawerViewModel @Inject constructor(
}
}

private fun subscribeToBadgesUpdates() =
viewModelScope.launch {
subscriptionsManager.badges.collect {
setState {
copy(badges = it)
}
}
}

private suspend fun invertTheme(event: PrimalDrawerContract.UiEvent.ThemeSwitchClick) {
val activeTheme = activeThemeStore.userThemeState.firstOrNull()
val newThemeName = activeTheme?.inverseThemeName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material3.DrawerState
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
Expand All @@ -26,6 +27,7 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.TopAppBarState
import androidx.compose.material3.rememberDrawerState
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
Expand All @@ -35,22 +37,25 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import net.primal.android.LocalContentDisplaySettings
import net.primal.android.R
import net.primal.android.core.compose.IconText
import net.primal.android.core.compose.PrimalDivider
import net.primal.android.core.compose.PrimalTopLevelDestination
import net.primal.android.core.compose.icons.PrimalIcons
import net.primal.android.core.compose.icons.primaliconpack.AdvancedSearch
import net.primal.android.core.compose.icons.primaliconpack.ArrowBack
import net.primal.android.core.compose.preview.PrimalPreview
import net.primal.android.core.errors.UiError
import net.primal.android.core.errors.resolveUiErrorMessage
import net.primal.android.drawer.DrawerScreenDestination
import net.primal.android.drawer.PrimalDrawerScaffold
import net.primal.android.explore.home.feeds.ExploreFeeds
import net.primal.android.explore.home.people.ExplorePeople
import net.primal.android.explore.home.topics.ExploreTopics
Expand All @@ -70,6 +75,9 @@ import net.primal.android.theme.domain.PrimalTheme
@Composable
fun ExploreHomeScreen(
viewModel: ExploreHomeViewModel,
onTopLevelDestinationChanged: (PrimalTopLevelDestination) -> Unit,
onDrawerScreenClick: (DrawerScreenDestination) -> Unit,
onDrawerQrCodeClick: () -> Unit,
onHashtagClick: (String) -> Unit,
onNoteClick: (String) -> Unit,
onProfileClick: (String) -> Unit,
Expand All @@ -81,6 +89,9 @@ fun ExploreHomeScreen(

ExploreHomeScreen(
state = uiState.value,
onPrimaryDestinationChanged = onTopLevelDestinationChanged,
onDrawerDestinationClick = onDrawerScreenClick,
onDrawerQrCodeClick = onDrawerQrCodeClick,
onHashtagClick = onHashtagClick,
onNoteClick = onNoteClick,
onSearchClick = onSearchClick,
Expand All @@ -94,6 +105,9 @@ fun ExploreHomeScreen(
@Composable
private fun ExploreHomeScreen(
state: ExploreHomeContract.UiState,
onPrimaryDestinationChanged: (PrimalTopLevelDestination) -> Unit,
onDrawerDestinationClick: (DrawerScreenDestination) -> Unit,
onDrawerQrCodeClick: () -> Unit,
onHashtagClick: (String) -> Unit,
onNoteClick: (String) -> Unit,
onSearchClick: () -> Unit,
Expand All @@ -103,15 +117,23 @@ private fun ExploreHomeScreen(
) {
val context = LocalContext.current
val uiScope = rememberCoroutineScope()
val drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed)
val snackbarHostState = remember { SnackbarHostState() }
val pagerState = rememberPagerState { EXPLORE_HOME_TAB_COUNT }

val topAppBarState: TopAppBarState = rememberTopAppBarState()
val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)

Scaffold(
modifier = Modifier.nestedScroll(topAppBarScrollBehavior.nestedScrollConnection),
topBar = {
PrimalDrawerScaffold(
drawerState = drawerState,
activeDestination = PrimalTopLevelDestination.Explore,
onPrimaryDestinationChanged = onPrimaryDestinationChanged,
onDrawerDestinationClick = onDrawerDestinationClick,
onDrawerQrCodeClick = onDrawerQrCodeClick,
badges = state.badges,
focusModeEnabled = LocalContentDisplaySettings.current.focusModeEnabled,
topAppBarState = topAppBarState,
topAppBar = {
ExploreTopAppBar(
onClose = onClose,
onSearchClick = onSearchClick,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@ package net.primal.android.messages.conversation

import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
import net.primal.android.attachments.domain.CdnImage
import net.primal.android.messages.conversation.model.MessageConversationUi
import net.primal.android.messages.domain.ConversationRelation
import net.primal.android.user.domain.Badges

interface MessageConversationListContract {
data class UiState(
val activeRelation: ConversationRelation,
val conversations: Flow<PagingData<MessageConversationUi>>,
val activeAccountAvatarCdnImage: CdnImage? = null,
val badges: Badges = Badges(),
)

sealed class UiEvent {
Expand Down
Loading

0 comments on commit 3fdee18

Please sign in to comment.