Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@ dependencies {
implementation(project(Module.splashImpl))
implementation(project(Module.platformImpl))
implementation(project(Module.uiComponentImpl))
implementation(project(Module.navigationPublicAndroid))

implementation(Navigation.fragmentKtx)
implementation(Navigation.uiKtx)
implementation(Koin.android)
implementation(Timber.timber)

Expand Down
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
android:theme="@style/AppTheme"
tools:replace="android:icon">

<activity
android:name=".home.HomeActivity"
android:exported="true"
android:theme="@style/AppTheme" />
<meta-data
android:name="google_analytics_adid_collection_enabled"
android:value="false" />
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/br/com/sailboat/todozy/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal class App : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
allowOverride(true)
androidLogger(Level.ERROR)
androidContext(this@App)
modules(DiProvider.modules)
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/br/com/sailboat/todozy/di/DiProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import br.com.sailboat.todozy.feature.task.details.impl.di.taskDetailsModule
import br.com.sailboat.todozy.feature.task.form.impl.di.taskFormModule
import br.com.sailboat.todozy.feature.task.history.impl.di.taskHistoryModule
import br.com.sailboat.todozy.feature.task.list.impl.di.taskListModule
import br.com.sailboat.todozy.navigation.appNavigationModule
import br.com.sailboat.todozy.platform.impl.di.platformModule
import br.com.sailboat.uicomponent.impl.di.uiComponentModule
import org.koin.core.module.Module
Expand All @@ -25,5 +26,6 @@ internal object DiProvider {
taskListModule,
taskDetailsModule,
uiComponentModule,
appNavigationModule,
).flatten()
}
110 changes: 110 additions & 0 deletions app/src/main/java/br/com/sailboat/todozy/home/HomeActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package br.com.sailboat.todozy.home

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.navOptions
import br.com.sailboat.todozy.R
import br.com.sailboat.todozy.databinding.ActivityHomeBinding
import br.com.sailboat.todozy.feature.navigation.android.HomeDestination
import br.com.sailboat.todozy.feature.navigation.android.HomeNavigationExtras.EXTRA_HOME_DESTINATION
import br.com.sailboat.todozy.feature.navigation.android.HomeTabNavigator

class HomeActivity : AppCompatActivity(), HomeTabNavigator {
private lateinit var binding: ActivityHomeBinding

private val rootDestinations =
setOf(
R.id.nav_tasks,
R.id.nav_history,
R.id.nav_settings,
)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root)

val navController = resolveNavController()
configureBottomNav(navController)
applyStartDestination(navController)
}

private fun configureBottomNav(navController: NavController) {
binding.homeBottomNav.setOnItemSelectedListener { item ->
navigateToRoot(item.itemId, navController)
true
}

binding.homeBottomNav.setOnItemReselectedListener { item ->
if (navController.currentDestination?.id == item.itemId) {
navController.popBackStack(item.itemId, inclusive = false)
}
}

navController.addOnDestinationChangedListener { _, destination, _ ->
binding.homeBottomNav.isVisible = destination.id in rootDestinations
}
}

private fun applyStartDestination(navController: NavController) {
val targetDestination =
when (intent.getSerializableExtra(EXTRA_HOME_DESTINATION) as? HomeDestination) {
HomeDestination.HISTORY -> R.id.nav_history
HomeDestination.SETTINGS -> R.id.nav_settings
else -> R.id.nav_tasks
}
if (binding.homeBottomNav.selectedItemId != targetDestination) {
binding.homeBottomNav.selectedItemId = targetDestination
navigateToRoot(targetDestination, navController)
}
}

private fun navigateToRoot(
itemId: Int,
navController: NavController,
) {
val options =
navOptions {
launchSingleTop = true
restoreState = true
popUpTo(navController.graph.startDestinationId) {
saveState = true
}
}
navController.navigate(itemId, null, options)
}

private fun resolveNavController(): NavController {
val navHost =
supportFragmentManager.findFragmentById(R.id.home_nav_host) as NavHostFragment
return navHost.navController
}

override fun switchTo(destination: HomeDestination) {
val navController = resolveNavController()
val targetId =
when (destination) {
HomeDestination.TASKS -> R.id.nav_tasks
HomeDestination.HISTORY -> R.id.nav_history
HomeDestination.SETTINGS -> R.id.nav_settings
}
if (binding.homeBottomNav.selectedItemId != targetId) {
binding.homeBottomNav.selectedItemId = targetId
}
navigateToRoot(targetId, navController)
}

companion object {
fun createIntent(
context: Context,
destination: HomeDestination = HomeDestination.TASKS,
): Intent = Intent(context, HomeActivity::class.java).apply {
putExtra(EXTRA_HOME_DESTINATION, destination)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package br.com.sailboat.todozy.navigation

import android.content.Context
import android.content.Intent
import androidx.activity.result.ActivityResultLauncher
import br.com.sailboat.todozy.feature.navigation.android.HomeDestination
import br.com.sailboat.todozy.feature.navigation.android.SettingsNavigator
import br.com.sailboat.todozy.feature.navigation.android.TaskHistoryNavigator
import br.com.sailboat.todozy.feature.navigation.android.TaskListNavigator
import br.com.sailboat.todozy.home.HomeActivity
import org.koin.core.module.Module
import org.koin.dsl.module

private fun Context.startHome(destination: HomeDestination) {
val intent = HomeActivity.createIntent(this, destination)
startActivity(intent)
}

private fun ActivityResultLauncher<Intent>.launchHome(
context: Context,
destination: HomeDestination,
) {
val intent = HomeActivity.createIntent(context, destination)
launch(intent)
}

internal val appNavigationModule: List<Module> =
listOf(
module(override = true) {
factory<TaskListNavigator> {
object : TaskListNavigator {
override fun navigateToTaskList(context: Context) {
context.startHome(HomeDestination.TASKS)
}
}
}

factory<TaskHistoryNavigator> {
object : TaskHistoryNavigator {
override fun navigateToTaskHistory(context: Context) {
context.startHome(HomeDestination.HISTORY)
}
}
}

factory<SettingsNavigator> {
object : SettingsNavigator {
override fun navigateToSettings(
context: Context,
launcher: ActivityResultLauncher<Intent>,
) {
launcher.launchHome(context, HomeDestination.SETTINGS)
}
}
}
},
)
5 changes: 5 additions & 0 deletions app/src/main/res/color/selector_bottom_nav.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorPrimary" android:state_checked="true" />
<item android:color="?attr/colorOnSurface" />
</selector>
32 changes: 32 additions & 0 deletions app/src/main/res/layout/activity_home.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.fragment.app.FragmentContainerView
android:id="@+id/home_nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@id/home_bottom_nav"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_home" />

<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/home_bottom_nav"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:itemIconTint="@color/selector_bottom_nav"
app:itemTextColor="@color/selector_bottom_nav"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/menu_home_bottom_nav" />

</androidx.constraintlayout.widget.ConstraintLayout>
15 changes: 15 additions & 0 deletions app/src/main/res/menu/menu_home_bottom_nav.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/nav_tasks"
android:icon="@android:drawable/ic_menu_agenda"
android:title="@string/app_name" />
<item
android:id="@+id/nav_history"
android:icon="@android:drawable/ic_menu_recent_history"
android:title="@string/history" />
<item
android:id="@+id/nav_settings"
android:icon="@android:drawable/ic_menu_preferences"
android:title="@string/settings" />
</menu>
23 changes: 23 additions & 0 deletions app/src/main/res/navigation/nav_home.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_home"
app:startDestination="@id/nav_tasks">

<fragment
android:id="@+id/nav_tasks"
android:name="br.com.sailboat.todozy.feature.task.list.impl.presentation.TaskListFragment"
tools:layout="@layout/activity_base" />

<fragment
android:id="@+id/nav_history"
android:name="br.com.sailboat.todozy.feature.task.history.impl.presentation.TaskHistoryFragment"
tools:layout="@layout/frg_task_history" />

<fragment
android:id="@+id/nav_settings"
android:name="br.com.sailboat.todozy.feature.settings.impl.presentation.SettingsFragment"
tools:layout="@layout/frg_settings" />

</navigation>
9 changes: 9 additions & 0 deletions buildSrc/src/main/java/Dependency.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ object AndroidX {
const val activity = "androidx.activity:activity:${Versions.activity}"
}

object Navigation {
object Version {
const val navigation = "2.7.7"
}

const val fragmentKtx = "androidx.navigation:navigation-fragment-ktx:${Version.navigation}"
const val uiKtx = "androidx.navigation:navigation-ui-ktx:${Version.navigation}"
}

object AndroidXTest {
object Version {
const val test = "1.5.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package br.com.sailboat.todozy.feature.navigation.android

enum class HomeDestination {
TASKS,
HISTORY,
SETTINGS,
}

interface HomeTabNavigator {
fun switchTo(destination: HomeDestination)
}

object HomeNavigationExtras {
const val EXTRA_HOME_DESTINATION = "extra_home_destination"
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.Fragment
import br.com.sailboat.todozy.domain.model.TaskProgressRange
import br.com.sailboat.todozy.feature.navigation.android.AboutNavigator
import br.com.sailboat.todozy.feature.navigation.android.HomeDestination
import br.com.sailboat.todozy.feature.navigation.android.HomeTabNavigator
import br.com.sailboat.todozy.feature.navigation.android.SettingsNavigator
import br.com.sailboat.todozy.feature.navigation.android.TaskDetailsNavigator
import br.com.sailboat.todozy.feature.navigation.android.TaskFormNavigator
Expand Down Expand Up @@ -113,10 +115,6 @@ internal class TaskListFragment : Fragment() {
) {
super.onViewCreated(view, savedInstanceState)
observeActions()
}

override fun onResume() {
super.onResume()
viewModel.dispatchViewIntent(TaskListViewIntent.OnStart)
}

Expand Down Expand Up @@ -144,15 +142,25 @@ internal class TaskListFragment : Fragment() {
}

private fun navigateToSettings() {
settingsNavigator.navigateToSettings(requireContext(), launcher)
val homeNavigator = activity as? HomeTabNavigator
if (homeNavigator != null) {
homeNavigator.switchTo(HomeDestination.SETTINGS)
} else {
settingsNavigator.navigateToSettings(requireContext(), launcher)
}
}

private fun navigateToTaskDetails(taskId: Long) {
taskDetailsNavigator.navigateToTaskDetails(requireContext(), taskId, launcher)
}

private fun navigateToHistory() {
taskHistoryNavigator.navigateToTaskHistory(requireContext())
val homeNavigator = activity as? HomeTabNavigator
if (homeNavigator != null) {
homeNavigator.switchTo(HomeDestination.HISTORY)
} else {
taskHistoryNavigator.navigateToTaskHistory(requireContext())
}
}

private fun showErrorLoadingTasks() {
Expand Down
Loading