Skip to content

Commit 29fcc9d

Browse files
committed
moved logics to viewmodel from activity
1 parent a04e3dc commit 29fcc9d

File tree

4 files changed

+87
-48
lines changed

4 files changed

+87
-48
lines changed

app/src/main/java/pseudoankit/droid/tasky/launcher/MainActivity.kt

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package pseudoankit.droid.tasky.launcher
22

33
import android.Manifest
44
import android.content.Intent
5-
import android.os.Build
65
import android.os.Bundle
76
import android.view.WindowManager
87
import androidx.activity.ComponentActivity
@@ -12,27 +11,22 @@ import androidx.compose.foundation.layout.fillMaxSize
1211
import androidx.compose.material3.Surface
1312
import androidx.compose.runtime.Composable
1413
import androidx.compose.runtime.LaunchedEffect
15-
import androidx.compose.runtime.collectAsState
16-
import androidx.compose.runtime.getValue
1714
import androidx.compose.ui.Modifier
1815
import androidx.compose.ui.platform.LocalContext
1916
import androidx.core.splashscreen.SplashScreen
2017
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
2118
import androidx.navigation.NavHostController
22-
import com.example.permission_manager.taskyStatus
2319
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
2420
import com.google.accompanist.permissions.rememberPermissionState
2521
import com.ramcosta.composedestinations.DestinationsNavHost
2622
import com.ramcosta.composedestinations.animations.rememberAnimatedNavHostEngine
2723
import com.ramcosta.composedestinations.navigation.dependency
28-
import kotlinx.coroutines.flow.firstOrNull
29-
import kotlinx.coroutines.runBlocking
30-
import org.koin.android.ext.android.inject
24+
import kotlinx.coroutines.flow.collectLatest
25+
import org.koin.androidx.viewmodel.ext.android.getViewModel
26+
import org.orbitmvi.orbit.compose.collectAsState
3127
import pseudoankit.droid.core.deeplink.TaskyDeeplink
32-
import pseudoankit.droid.core.logger.logInfo
3328
import pseudoankit.droid.coreui.deeplink.navigateViaDeepLink
3429
import pseudoankit.droid.coreui.util.extension.clearStack
35-
import pseudoankit.droid.preferencesmanager.PreferenceRepository
3630
import pseudoankit.droid.tasky.navigation.navgraph.mainNavGraph
3731
import pseudoankit.droid.tasky.navigation.navigator.CoreFeatureNavigator
3832
import pseudoankit.droid.tasky.util.hide
@@ -44,14 +38,14 @@ import pseudoankit.droid.unify.utils.enableTestTagAsResourceId
4438
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterialNavigationApi::class)
4539
internal class MainActivity : ComponentActivity() {
4640

47-
private val preferenceRepository: PreferenceRepository by inject()
4841
private var navController: NavHostController? = null
4942
private val splashScreen: SplashScreen by lazy { installSplashScreen() }
5043

5144
override fun onCreate(savedInstanceState: Bundle?) {
5245
splashScreen.show()
5346
super.onCreate(savedInstanceState)
5447

48+
MainActivityModule.loadModules()
5549
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
5650

5751
setContent {
@@ -60,26 +54,30 @@ internal class MainActivity : ComponentActivity() {
6054
modifier = Modifier.fillMaxSize(),
6155
color = UnifyColors.White
6256
) {
63-
InitializeNavigation()
64-
HandlePermissions()
65-
ObserveLoginStatus()
57+
val viewModel = getViewModel<MainActivityViewModel>()
58+
val state = viewModel.collectAsState().value
59+
60+
InitializeNavigation(
61+
isUserLoggedIn = state.isUserLoggedIn
62+
)
63+
viewModel.HandleSideEffect()
6664
HideSplashScreenAfterNavigation()
6765
}
6866
}
6967
}
7068
}
7169

7270
@Composable
73-
private fun InitializeNavigation() {
71+
private fun InitializeNavigation(
72+
isUserLoggedIn: Boolean
73+
) {
7474
val context = LocalContext.current
7575

7676
val engine = rememberAnimatedNavHostEngine()
7777
navController = engine.rememberNavController()
7878

79-
val isUserLoggedIn = runBlocking { preferenceRepository.isLoggedIn().firstOrNull() }
80-
8179
DestinationsNavHost(
82-
navGraph = mainNavGraph(isUserLoggedIn = isUserLoggedIn ?: true),
80+
navGraph = mainNavGraph(isUserLoggedIn = isUserLoggedIn),
8381
navController = navController!!,
8482
engine = engine,
8583
dependenciesContainerBuilder = {
@@ -89,31 +87,6 @@ internal class MainActivity : ComponentActivity() {
8987
)
9088
}
9189

92-
@Composable
93-
private fun ObserveLoginStatus() {
94-
val isLoggedIn by preferenceRepository.isLoggedIn().collectAsState(initial = true)
95-
96-
if (isLoggedIn.not() && navController?.currentDestination?.route?.equals("login_screen") == false) {
97-
navController?.apply {
98-
clearStack()
99-
navigateViaDeepLink(TaskyDeeplink.login)
100-
}
101-
}
102-
}
103-
104-
@Composable
105-
private fun HandlePermissions() {
106-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
107-
108-
val launcher = rememberPermissionState(permission = Manifest.permission.POST_NOTIFICATIONS)
109-
110-
logInfo("Notification Permission Status", launcher.taskyStatus.name)
111-
112-
LaunchedEffect(key1 = Unit) {
113-
launcher.launchPermissionRequest()
114-
}
115-
}
116-
11790
override fun onNewIntent(intent: Intent?) {
11891
super.onNewIntent(intent)
11992
navController?.navigateViaDeepLink(intent?.data.toString())
@@ -127,4 +100,26 @@ internal class MainActivity : ComponentActivity() {
127100
}
128101
}
129102
}
103+
104+
@Composable
105+
private fun MainActivityViewModel.HandleSideEffect() {
106+
val launcher = rememberPermissionState(permission = Manifest.permission.POST_NOTIFICATIONS)
107+
108+
LaunchedEffect(Unit) {
109+
container.sideEffectFlow.collectLatest { effect ->
110+
when (effect) {
111+
MainActivityViewModel.SideEffect.ClearBackStackAndNavigateToLogin -> {
112+
navController?.apply {
113+
clearStack()
114+
navigateViaDeepLink(TaskyDeeplink.login)
115+
}
116+
}
117+
118+
MainActivityViewModel.SideEffect.LaunchNotificationPermissionRequest -> {
119+
launcher.launchPermissionRequest()
120+
}
121+
}
122+
}
123+
}
124+
}
130125
}

app/src/main/java/pseudoankit/droid/tasky/launcher/MainActivityModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ object MainActivityModule : BaseKoinModule() {
99

1010
override val modules: Module
1111
get() = module {
12-
viewModel { MainActivityViewModel() }
12+
viewModel { MainActivityViewModel(get()) }
1313
}
1414
}
Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,61 @@
11
package pseudoankit.droid.tasky.launcher
22

3+
import android.os.Build
34
import androidx.lifecycle.ViewModel
45
import androidx.lifecycle.viewModelScope
6+
import kotlinx.coroutines.flow.launchIn
7+
import kotlinx.coroutines.flow.onEach
8+
import kotlinx.coroutines.runBlocking
59
import org.orbitmvi.orbit.Container
610
import org.orbitmvi.orbit.ContainerHost
711
import org.orbitmvi.orbit.container
12+
import pseudoankit.droid.core.util.extension.orFalse
13+
import pseudoankit.droid.coreui.util.extension.postSideEffect
14+
import pseudoankit.droid.coreui.util.extension.state
15+
import pseudoankit.droid.preferencesmanager.PreferenceRepository
816

9-
class MainActivityViewModel : ViewModel(),
17+
class MainActivityViewModel(
18+
private val preferenceRepository: PreferenceRepository
19+
) : ViewModel(),
1020
ContainerHost<MainActivityViewModel.State, MainActivityViewModel.SideEffect> {
1121

12-
override val container: Container<State, SideEffect> = viewModelScope.container(State())
22+
override val container: Container<State, SideEffect> = viewModelScope.container(
23+
initialState = State(
24+
isUserLoggedIn = runBlocking { preferenceRepository.isLoggedIn().orFalse }
25+
)
26+
)
1327

14-
class State()
15-
sealed interface SideEffect {
28+
init {
29+
observeLoggedInStatus()
30+
handleNotificationPermission()
31+
}
1632

33+
private fun observeLoggedInStatus() {
34+
preferenceRepository.isLoggedInFlow()
35+
.onEach { isLoggedIn ->
36+
if (!isLoggedIn && !state.isUserLoggedIn) {
37+
postSideEffect {
38+
SideEffect.ClearBackStackAndNavigateToLogin
39+
}
40+
}
41+
}
42+
.launchIn(viewModelScope)
43+
}
44+
45+
private fun handleNotificationPermission() {
46+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
47+
postSideEffect {
48+
SideEffect.LaunchNotificationPermissionRequest
49+
}
50+
}
51+
52+
53+
data class State(
54+
val isUserLoggedIn: Boolean = true
55+
)
56+
57+
sealed interface SideEffect {
58+
object ClearBackStackAndNavigateToLogin : SideEffect
59+
object LaunchNotificationPermissionRequest : SideEffect
1760
}
1861
}

core/preferences-manager/src/main/java/pseudoankit/droid/preferencesmanager/PreferenceRepository.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class PreferenceRepository(
88
datStore: DataStore<Preferences>
99
) : BasePreference(datStore) {
1010

11-
fun isLoggedIn() = getValueAsFlow(Keys.isLoggedIn).map { it == true }
11+
fun isLoggedInFlow() = getValueAsFlow(Keys.isLoggedIn).map { it == true }
12+
suspend fun isLoggedIn() = getValue(Keys.isLoggedIn)
1213
suspend fun setIsLoggedIn(value: Boolean) = setValue(Keys.isLoggedIn, value)
1314
}

0 commit comments

Comments
 (0)