observe invite changes and render a ! badge on the profile bottom item
This commit is contained in:
parent
7320690162
commit
40461f692f
|
@ -181,7 +181,7 @@ internal class FeatureModules internal constructor(
|
|||
clock
|
||||
)
|
||||
}
|
||||
val homeModule by unsafeLazy { HomeModule(storeModule.value, matrixModules.profile, buildMeta) }
|
||||
val homeModule by unsafeLazy { HomeModule(storeModule.value, matrixModules.profile, matrixModules.sync, buildMeta) }
|
||||
val settingsModule by unsafeLazy {
|
||||
SettingsModule(
|
||||
storeModule.value,
|
||||
|
|
|
@ -3,6 +3,7 @@ applyAndroidComposeLibraryModule(project)
|
|||
dependencies {
|
||||
implementation project(":matrix:services:profile")
|
||||
implementation project(":matrix:services:crypto")
|
||||
implementation project(":matrix:services:sync")
|
||||
implementation project(":features:directory")
|
||||
implementation project(":features:login")
|
||||
implementation project(":features:settings")
|
||||
|
|
|
@ -6,11 +6,13 @@ import app.dapk.st.directory.DirectoryViewModel
|
|||
import app.dapk.st.domain.StoreModule
|
||||
import app.dapk.st.login.LoginViewModel
|
||||
import app.dapk.st.matrix.room.ProfileService
|
||||
import app.dapk.st.matrix.sync.SyncService
|
||||
import app.dapk.st.profile.ProfileViewModel
|
||||
|
||||
class HomeModule(
|
||||
private val storeModule: StoreModule,
|
||||
private val profileService: ProfileService,
|
||||
private val syncService: SyncService,
|
||||
private val buildMeta: BuildMeta,
|
||||
) : ProvidableModule {
|
||||
|
||||
|
@ -26,6 +28,7 @@ class HomeModule(
|
|||
storeModule.applicationStore(),
|
||||
buildMeta,
|
||||
),
|
||||
syncService,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,12 @@ package app.dapk.st.home
|
|||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.dapk.st.core.LifecycleEffect
|
||||
import app.dapk.st.core.components.CenteredLoading
|
||||
import app.dapk.st.design.components.CircleishAvatar
|
||||
import app.dapk.st.design.components.SmallTalkTheme
|
||||
import app.dapk.st.directory.DirectoryScreen
|
||||
import app.dapk.st.home.HomeScreenState.*
|
||||
import app.dapk.st.home.HomeScreenState.Page.Directory
|
||||
|
@ -20,41 +19,42 @@ import app.dapk.st.profile.ProfileScreen
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun HomeScreen(homeViewModel: HomeViewModel) {
|
||||
Surface(Modifier.fillMaxSize()) {
|
||||
LaunchedEffect(true) {
|
||||
homeViewModel.start()
|
||||
}
|
||||
LifecycleEffect(
|
||||
onStart = { homeViewModel.start() },
|
||||
onStop = { homeViewModel.stop() }
|
||||
)
|
||||
|
||||
when (val state = homeViewModel.state) {
|
||||
Loading -> CenteredLoading()
|
||||
is SignedIn -> {
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
BottomBar(state, homeViewModel)
|
||||
},
|
||||
content = { innerPadding ->
|
||||
Box(modifier = Modifier.padding(innerPadding)) {
|
||||
when (state.page) {
|
||||
Directory -> DirectoryScreen(homeViewModel.directory())
|
||||
Profile -> {
|
||||
ProfileScreen(homeViewModel.profile()) {
|
||||
homeViewModel.changePage(Directory)
|
||||
}
|
||||
}
|
||||
when (val state = homeViewModel.state) {
|
||||
Loading -> CenteredLoading()
|
||||
is SignedIn -> {
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
BottomBar(state, homeViewModel)
|
||||
},
|
||||
content = { innerPadding ->
|
||||
Box(modifier = Modifier.padding(innerPadding)) {
|
||||
when (state.page) {
|
||||
Directory -> DirectoryScreen(homeViewModel.directory())
|
||||
Profile -> {
|
||||
ProfileScreen(homeViewModel.profile()) {
|
||||
homeViewModel.changePage(Directory)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
SignedOut -> {
|
||||
LoginScreen(homeViewModel.login()) {
|
||||
homeViewModel.loggedIn()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
SignedOut -> {
|
||||
LoginScreen(homeViewModel.login()) {
|
||||
homeViewModel.loggedIn()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun BottomBar(state: SignedIn, homeViewModel: HomeViewModel) {
|
||||
Column {
|
||||
|
@ -72,11 +72,17 @@ private fun BottomBar(state: SignedIn, homeViewModel: HomeViewModel) {
|
|||
}
|
||||
},
|
||||
)
|
||||
Profile -> NavigationBarItem(
|
||||
|
||||
Profile -> NavigationBarItem(
|
||||
icon = {
|
||||
Box {
|
||||
CircleishAvatar(state.me.avatarUrl?.value, state.me.displayName ?: state.me.userId.value, size = 25.dp)
|
||||
BadgedBox(badge = {
|
||||
if (state.invites > 0) {
|
||||
Badge(containerColor = MaterialTheme.colorScheme.primary) { Text("!", color = MaterialTheme.colorScheme.onPrimary) }
|
||||
}
|
||||
}) {
|
||||
Box {
|
||||
CircleishAvatar(state.me.avatarUrl?.value, state.me.displayName ?: state.me.userId.value, size = 25.dp)
|
||||
}
|
||||
}
|
||||
},
|
||||
selected = state.page == page,
|
||||
|
|
|
@ -10,7 +10,7 @@ sealed interface HomeScreenState {
|
|||
|
||||
object Loading : HomeScreenState
|
||||
object SignedOut : HomeScreenState
|
||||
data class SignedIn(val page: Page, val me: ProfileService.Me) : HomeScreenState
|
||||
data class SignedIn(val page: Page, val me: ProfileService.Me, val invites: Int) : HomeScreenState
|
||||
|
||||
enum class Page(val icon: ImageVector) {
|
||||
Directory(Icons.Filled.Menu),
|
||||
|
|
|
@ -8,8 +8,15 @@ import app.dapk.st.login.LoginViewModel
|
|||
import app.dapk.st.matrix.common.CredentialsStore
|
||||
import app.dapk.st.matrix.common.isSignedIn
|
||||
import app.dapk.st.matrix.room.ProfileService
|
||||
import app.dapk.st.matrix.sync.SyncService
|
||||
import app.dapk.st.profile.ProfileViewModel
|
||||
import app.dapk.st.viewmodel.DapkViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class HomeViewModel(
|
||||
|
@ -20,10 +27,13 @@ class HomeViewModel(
|
|||
private val profileService: ProfileService,
|
||||
private val cacheCleaner: StoreCleaner,
|
||||
private val betaVersionUpgradeUseCase: BetaVersionUpgradeUseCase,
|
||||
private val syncService: SyncService,
|
||||
) : DapkViewModel<HomeScreenState, HomeEvent>(
|
||||
initialState = Loading
|
||||
) {
|
||||
|
||||
private var listenForInvitesJob: Job? = null
|
||||
|
||||
fun directory() = directoryViewModel
|
||||
fun login() = loginViewModel
|
||||
fun profile() = profileViewModel
|
||||
|
@ -31,21 +41,47 @@ class HomeViewModel(
|
|||
fun start() {
|
||||
viewModelScope.launch {
|
||||
state = if (credentialsProvider.isSignedIn()) {
|
||||
val me = profileService.me(forceRefresh = false)
|
||||
SignedIn(Page.Directory, me)
|
||||
initialHomeContent()
|
||||
} else {
|
||||
SignedOut
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
if (credentialsProvider.isSignedIn()) {
|
||||
listenForInviteChanges()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private suspend fun initialHomeContent(): SignedIn {
|
||||
val me = profileService.me(forceRefresh = false)
|
||||
val initialInvites = syncService.invites().first().size
|
||||
return SignedIn(Page.Directory, me, invites = initialInvites)
|
||||
}
|
||||
|
||||
fun loggedIn() {
|
||||
viewModelScope.launch {
|
||||
val me = profileService.me(forceRefresh = false)
|
||||
state = SignedIn(Page.Directory, me)
|
||||
state = initialHomeContent()
|
||||
listenForInviteChanges()
|
||||
}
|
||||
}
|
||||
|
||||
private fun CoroutineScope.listenForInviteChanges() {
|
||||
listenForInvitesJob?.cancel()
|
||||
listenForInvitesJob = syncService.invites()
|
||||
.onEach { invites ->
|
||||
when (val currentState = state) {
|
||||
is SignedIn -> updateState { currentState.copy(invites = invites.size) }
|
||||
Loading,
|
||||
SignedOut -> {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}.launchIn(this)
|
||||
}
|
||||
|
||||
fun hasVersionChanged() = betaVersionUpgradeUseCase.hasVersionChanged()
|
||||
|
||||
fun clearCache() {
|
||||
|
@ -66,4 +102,8 @@ class HomeViewModel(
|
|||
SignedOut -> current
|
||||
}
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
viewModelScope.cancel()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package app.dapk.st.home
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import app.dapk.st.core.DapkActivity
|
||||
import app.dapk.st.core.module
|
||||
|
@ -35,7 +37,9 @@ class MainActivity : DapkActivity() {
|
|||
if (homeViewModel.hasVersionChanged()) {
|
||||
BetaUpgradeDialog()
|
||||
} else {
|
||||
HomeScreen(homeViewModel)
|
||||
Surface(Modifier.fillMaxSize()) {
|
||||
HomeScreen(homeViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue