Skip to content

Commit a2467d7

Browse files
authored
Merge pull request #18 from pseudoankit/refactor
Refactor
2 parents 2338d40 + 9f88ddf commit a2467d7

File tree

27 files changed

+169
-195
lines changed

27 files changed

+169
-195
lines changed

app/build.gradle.kts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ dependencies {
4141
implementation(project(Core))
4242
implementation(project(CoreUi))
4343
implementation(project(DataBaseManager))
44-
implementation(project(Navigation))
4544
implementation(project(AgendaManager))
4645
implementation(project(AlarmManager))
4746
implementation(project(NotificationManager))
@@ -51,14 +50,20 @@ dependencies {
5150
}
5251

5352
with(Modules.Feature) {
53+
implementation(project(Authentication))
54+
implementation(project(Home))
55+
implementation(project(Event))
56+
implementation(project(Reminder))
57+
implementation(project(Task))
5458
implementation(project(DeveloperTools))
5559
}
5660

57-
implementation("io.insert-koin:koin-androidx-compose:3.2.1")
58-
5961
with(Dependencies.Compose) {
6062
implementation(ComposeDestinations)
63+
implementation(OrbitMvi)
6164
}
62-
implementation("androidx.core:core-splashscreen:1.0.0-beta02")
65+
66+
implementation(Dependencies.Koin.Compose)
67+
implementation(Dependencies.AndroidX.SplashScreen)
6368
implementation(Dependencies.ProfilerInstaller)
6469
}

app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,17 @@
1515
android:label="@string/app_name"
1616
android:roundIcon="@mipmap/ic_launcher_round"
1717
android:supportsRtl="true"
18-
android:theme="@style/Theme.Tasky"
18+
android:theme="@style/Theme.Launcher"
1919
android:usesCleartextTraffic="false"
2020
tools:targetApi="31">
2121
<profileable
2222
android:shell="true"
2323
tools:targetApi="29" />
2424

2525
<activity
26-
android:name=".MainActivity"
26+
android:name=".launcher.MainActivity"
2727
android:exported="true"
28-
android:launchMode="singleTop"
29-
android:theme="@style/Theme.Launcher">
28+
android:launchMode="singleTop">
3029
<intent-filter>
3130
<action android:name="android.intent.action.MAIN" />
3231

app/src/main/java/pseudoankit/droid/tasky/di/AppModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import pseudoankit.droid.core.di.CoreModule
66
import pseudoankit.droid.dbmanager.di.DataBaseModule
77
import pseudoankit.droid.di.PreferencesModule
88
import pseudoankit.droid.di.WidgetsNShortcutsModule
9-
import pseudoankit.droid.navigation.di.NavigationModule
109
import pseudoankit.droid.notification_manager.di.NotifierModule
10+
import pseudoankit.droid.tasky.navigation.di.NavigationModule
1111

1212
internal val AppModule = listOf(
1313
DataBaseModule(),
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
package pseudoankit.droid.tasky
1+
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,29 +11,24 @@ 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.navigation.navgraph.mainNavGraph
36-
import pseudoankit.droid.navigation.navigator.CoreFeatureNavigator
37-
import pseudoankit.droid.preferencesmanager.PreferenceRepository
30+
import pseudoankit.droid.tasky.navigation.navgraph.mainNavGraph
31+
import pseudoankit.droid.tasky.navigation.navigator.CoreFeatureNavigator
3832
import pseudoankit.droid.tasky.util.hide
3933
import pseudoankit.droid.tasky.util.show
4034
import pseudoankit.droid.unify.token.UnifyColors
@@ -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()) {
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
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package pseudoankit.droid.tasky.launcher
2+
3+
import org.koin.androidx.viewmodel.dsl.viewModel
4+
import org.koin.core.module.Module
5+
import org.koin.dsl.module
6+
import pseudoankit.droid.core.koin.BaseKoinModule
7+
8+
object MainActivityModule : BaseKoinModule() {
9+
10+
override val modules: Module
11+
get() = module {
12+
viewModel { MainActivityViewModel(get()) }
13+
}
14+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package pseudoankit.droid.tasky.launcher
2+
3+
import android.os.Build
4+
import androidx.lifecycle.ViewModel
5+
import androidx.lifecycle.viewModelScope
6+
import kotlinx.coroutines.flow.launchIn
7+
import kotlinx.coroutines.flow.onEach
8+
import kotlinx.coroutines.runBlocking
9+
import org.orbitmvi.orbit.Container
10+
import org.orbitmvi.orbit.ContainerHost
11+
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
16+
17+
class MainActivityViewModel(
18+
private val preferenceRepository: PreferenceRepository
19+
) : ViewModel(),
20+
ContainerHost<MainActivityViewModel.State, MainActivityViewModel.SideEffect> {
21+
22+
override val container: Container<State, SideEffect> = viewModelScope.container(
23+
initialState = State(
24+
isUserLoggedIn = runBlocking { preferenceRepository.isLoggedIn().orFalse }
25+
)
26+
)
27+
28+
init {
29+
observeLoggedInStatus()
30+
handleNotificationPermission()
31+
}
32+
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
60+
}
61+
}

core/navigation/src/main/java/pseudoankit/droid/navigation/deeplink/DeepLinkProvider.kt renamed to app/src/main/java/pseudoankit/droid/tasky/navigation/deeplink/DeepLinkProvider.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package pseudoankit.droid.navigation.deeplink
1+
package pseudoankit.droid.tasky.navigation.deeplink
22

33
import pseudoankit.droid.agendamanger.domain.model.AgendaTypes
44
import pseudoankit.droid.app_widgets.util.WidgetDeeplinkProvider
@@ -20,10 +20,6 @@ internal class DeepLinkProvider : ReminderDeepLinkProvider, HomeDeepLinkProvider
2020
is AgendaTypes.Task -> TODO()
2121
}
2222

23-
override fun homeScreenRoute(): String {
24-
return TaskyDeeplink.home
25-
}
26-
2723
override fun reminderScreenRoute(action: AgendaTypes.Action): String {
2824
return TaskyDeeplink.reminder.replace(
2925
TaskyDeeplink.Path.Reminder.action,

core/navigation/src/main/java/pseudoankit/droid/navigation/di/NavigationModule.kt renamed to app/src/main/java/pseudoankit/droid/tasky/navigation/di/NavigationModule.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package pseudoankit.droid.navigation.di
1+
package pseudoankit.droid.tasky.navigation.di
22

33
import org.koin.dsl.module
44
import pseudoankit.droid.app_widgets.util.WidgetDeeplinkProvider
5-
import pseudoankit.droid.navigation.deeplink.DeepLinkProvider
65
import pseudoankit.droid.tasky.home.navigator.HomeDeepLinkProvider
6+
import pseudoankit.droid.tasky.navigation.deeplink.DeepLinkProvider
77
import pseudoankit.droid.tasky.reminder.navigator.ReminderDeepLinkProvider
88

99
object NavigationModule {

core/navigation/src/main/java/pseudoankit/droid/navigation/navgraph/MainNavGraph.kt renamed to app/src/main/java/pseudoankit/droid/tasky/navigation/navgraph/MainNavGraph.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package pseudoankit.droid.navigation.navgraph
1+
package pseudoankit.droid.tasky.navigation.navgraph
22

33
import com.ramcosta.composedestinations.spec.DestinationSpec
44
import com.ramcosta.composedestinations.spec.NavGraphSpec

core/navigation/src/main/java/pseudoankit/droid/navigation/navigator/CoreFeatureNavigator.kt renamed to app/src/main/java/pseudoankit/droid/tasky/navigation/navigator/CoreFeatureNavigator.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
package pseudoankit.droid.navigation.navigator
1+
package pseudoankit.droid.tasky.navigation.navigator
22

33
import android.content.Context
44
import androidx.navigation.NavController
55
import com.ramcosta.composedestinations.navigation.navigate
66
import pseudoankit.droid.authentication.navigator.AuthNavigator
77
import pseudoankit.droid.coreui.util.extension.clearStack
88
import pseudoankit.droid.coreui.util.extension.finish
9-
import pseudoankit.droid.navigation.navigator.feature.AuthNavigatorImpl
10-
import pseudoankit.droid.navigation.navigator.feature.HomeScreenNavigatorImpl
119
import pseudoankit.droid.tasky.home.navigator.HomeScreenNavigator
1210
import pseudoankit.droid.tasky.home.presentation.destinations.HomeScreenDestination
11+
import pseudoankit.droid.tasky.navigation.navigator.feature.AuthNavigatorImpl
12+
import pseudoankit.droid.tasky.navigation.navigator.feature.HomeScreenNavigatorImpl
1313
import pseudoankit.droid.tasky.reminder.navigator.ReminderNavigator
1414

1515
class CoreFeatureNavigator(

0 commit comments

Comments
 (0)