├── .gitignore ├── .idea └── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── maruchin │ │ └── androidnavigation │ │ ├── MainActivity.kt │ │ ├── SampleApplication.kt │ │ ├── navigationbar │ │ ├── NavigationBar.kt │ │ ├── NavigationBarHost.kt │ │ └── NavigationBarState.kt │ │ └── root │ │ └── RootHost.kt │ └── res │ ├── values │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── build-logic ├── build.gradle.kts ├── gradle.properties ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ ├── AppModuleConventions.kt │ ├── DataModuleConventions.kt │ ├── FeatureModuleConventions.kt │ ├── UiModuleConventions.kt │ └── internal │ ├── Android.kt │ ├── Compose.kt │ ├── Hilt.kt │ ├── Navigation.kt │ ├── ProjectExtension.kt │ └── UnitTests.kt ├── build.gradle.kts ├── core ├── forms │ └── build.gradle.kts ├── intent │ └── build.gradle.kts └── ui │ ├── build.gradle.kts │ └── src │ └── main │ └── res │ └── values │ └── strings.xml ├── data ├── addresses │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── maruchin │ │ └── data │ │ └── addresses │ │ ├── Address.kt │ │ ├── AddressesRepository.kt │ │ ├── SampleData.kt │ │ └── internal │ │ ├── DataAddressesModule.kt │ │ └── FakeAddressesRepository.kt ├── cart │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── maruchin │ │ └── data │ │ └── cart │ │ ├── Cart.kt │ │ ├── CartProduct.kt │ │ ├── CartRepository.kt │ │ ├── SampleData.kt │ │ └── internal │ │ ├── DataCartModule.kt │ │ └── FakeCartRepository.kt ├── categories │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── maruchin │ │ └── data │ │ └── categories │ │ ├── CategoriesRepository.kt │ │ ├── Category.kt │ │ ├── SampleData.kt │ │ └── internal │ │ ├── DataCategoriesModule.kt │ │ └── FakeCategoriesRepository.kt ├── deliveries │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── data │ │ │ └── deliveries │ │ │ ├── DeliveriesRepository.kt │ │ │ ├── Delivery.kt │ │ │ ├── SampleData.kt │ │ │ └── internal │ │ │ ├── DataDeliveriesModule.kt │ │ │ └── FakeDeliveriesRepository.kt │ │ └── res │ │ └── drawable │ │ ├── dhl_logo.jpeg │ │ ├── gls_logo.jpeg │ │ └── ups_logo.png ├── order │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── maruchin │ │ └── data │ │ └── order │ │ ├── Order.kt │ │ ├── OrderProduct.kt │ │ ├── OrderRepository.kt │ │ ├── SampleData.kt │ │ └── internal │ │ ├── DataOrderModule.kt │ │ └── FakeOrderRepository.kt ├── payments │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── data │ │ │ └── payments │ │ │ ├── Payment.kt │ │ │ ├── PaymentsRepository.kt │ │ │ ├── SampleData.kt │ │ │ └── internal │ │ │ ├── DataPaymentsModule.kt │ │ │ └── FakePaymentsRepository.kt │ │ └── res │ │ └── drawable │ │ ├── google_pay_logo.png │ │ ├── mastercard_logo.png │ │ ├── paypal_logo.png │ │ └── visa_logo.jpeg ├── products │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── data │ │ │ └── products │ │ │ ├── Product.kt │ │ │ ├── ProductFilters.kt │ │ │ ├── ProductFiltersRepository.kt │ │ │ ├── ProductsRepository.kt │ │ │ ├── Rating.kt │ │ │ ├── SampleData.kt │ │ │ └── internal │ │ │ ├── DataProductsModule.kt │ │ │ ├── FakeProductFiltersRepository.kt │ │ │ └── FakeProductsRepository.kt │ │ └── res │ │ └── drawable │ │ └── product_image.jpg ├── promotions │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── maruchin │ │ └── data │ │ └── promotions │ │ ├── Promotion.kt │ │ ├── PromotionsRepository.kt │ │ ├── SampleData.kt │ │ └── internal │ │ ├── DataPromotionsModule.kt │ │ └── FakePromotionsRepository.kt └── user │ ├── build.gradle.kts │ └── src │ └── main │ └── java │ └── com │ └── maruchin │ └── data │ └── user │ ├── ClubData.kt │ ├── ClubLevel.kt │ ├── PersonalData.kt │ ├── SampleData.kt │ ├── User.kt │ ├── UserRepository.kt │ ├── ValidateEmail.kt │ ├── ValidatePassword.kt │ └── internal │ ├── DataUserModule.kt │ └── FakeUserRepository.kt ├── features ├── cart │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── cart │ │ │ ├── CartGraph.kt │ │ │ ├── CartNavigation.kt │ │ │ ├── CartScreen.kt │ │ │ └── CartViewModel.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── category-browser │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── categorybrowser │ │ │ ├── CategoryBrowserGraph.kt │ │ │ ├── categorylist │ │ │ ├── CategoryList.kt │ │ │ ├── CategoryListNavigation.kt │ │ │ ├── CategoryListScreen.kt │ │ │ └── CategoryListViewModel.kt │ │ │ └── subcategorylist │ │ │ ├── SubcategoryListNavigation.kt │ │ │ ├── SubcategoryListScreen.kt │ │ │ └── SubcategoryListViewModel.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── favorites │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── favorites │ │ │ ├── FavoritesGraph.kt │ │ │ ├── FavoritesNavigation.kt │ │ │ ├── FavoritesScreen.kt │ │ │ └── FavoritesViewModel.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── home │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── home │ │ │ ├── HomeGraph.kt │ │ │ ├── HomeNavigation.kt │ │ │ ├── HomeScreen.kt │ │ │ └── HomeViewModel.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── login │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── login │ │ │ ├── LoginGraph.kt │ │ │ ├── changepassword │ │ │ ├── ChangePasswordNavigation.kt │ │ │ ├── ChangePasswordScreen.kt │ │ │ └── ChangePasswordViewModel.kt │ │ │ ├── forgotpassword │ │ │ ├── EmailSentDialog.kt │ │ │ ├── ForgotPasswordNavigation.kt │ │ │ ├── ForgotPasswordScreen.kt │ │ │ └── ForgotPasswordViewModel.kt │ │ │ └── login │ │ │ ├── LoginNavigation.kt │ │ │ ├── LoginScreen.kt │ │ │ └── LoginViewModel.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── my-data │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── mydata │ │ │ ├── MyDataGraph.kt │ │ │ ├── addaddress │ │ │ ├── AddAddressNavigation.kt │ │ │ ├── AddAddressScreen.kt │ │ │ └── AddAddressViewModel.kt │ │ │ ├── changepassword │ │ │ ├── ChangePasswordNavigation.kt │ │ │ ├── ChangePasswordScreen.kt │ │ │ └── ChangePasswordViewModel.kt │ │ │ ├── deleteaccount │ │ │ ├── DeleteAccountNavigation.kt │ │ │ ├── DeleteAccountScreen.kt │ │ │ └── DeleteAccountViewModel.kt │ │ │ ├── editaddress │ │ │ ├── EditAddressNavigation.kt │ │ │ ├── EditAddressScreen.kt │ │ │ └── EditAddressViewModel.kt │ │ │ ├── editmydata │ │ │ ├── EditMyDataNavigation.kt │ │ │ ├── EditMyDataScreen.kt │ │ │ └── EditMyDataViewModel.kt │ │ │ ├── myaddresses │ │ │ ├── MyAddressesNavigation.kt │ │ │ ├── MyAddressesScreen.kt │ │ │ └── MyAddressesViewModel.kt │ │ │ └── mydata │ │ │ ├── MyDataNavigation.kt │ │ │ ├── MyDataScreen.kt │ │ │ └── MyDataViewModel.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── order │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── order │ │ │ ├── OrderGraph.kt │ │ │ ├── address │ │ │ ├── AddressNavigation.kt │ │ │ ├── AddressScreen.kt │ │ │ └── AddressViewModel.kt │ │ │ ├── confirmation │ │ │ ├── ConfirmationNavigation.kt │ │ │ ├── ConfirmationScreen.kt │ │ │ └── ConfirmationViewModel.kt │ │ │ ├── delivery │ │ │ ├── DeliveryNavigation.kt │ │ │ ├── DeliveryScreen.kt │ │ │ └── DeliveryViewModel.kt │ │ │ ├── payment │ │ │ ├── PaymentNavigation.kt │ │ │ ├── PaymentScreen.kt │ │ │ └── PaymentViewModel.kt │ │ │ └── summary │ │ │ ├── SummaryNavigation.kt │ │ │ ├── SummaryScreen.kt │ │ │ └── SummaryViewModel.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── product-browser │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── productbrowser │ │ │ ├── ProductBrowserGraph.kt │ │ │ ├── filters │ │ │ ├── FiltersNavigation.kt │ │ │ ├── FiltersScreen.kt │ │ │ └── FiltersViewModel.kt │ │ │ └── productlist │ │ │ ├── ProductListNavigation.kt │ │ │ ├── ProductListScreen.kt │ │ │ └── ProductListViewModel.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── product-card │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── productcard │ │ │ ├── ProductCardGraph.kt │ │ │ ├── card │ │ │ ├── CardNavigation.kt │ │ │ ├── CardScreen.kt │ │ │ └── CardViewModel.kt │ │ │ └── gallery │ │ │ ├── GalleryNavigation.kt │ │ │ ├── GalleryScreen.kt │ │ │ └── GalleryViewModel.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── profile │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── maruchin │ │ │ └── features │ │ │ └── profile │ │ │ ├── ProfileGraph.kt │ │ │ ├── club │ │ │ ├── ClubPage.kt │ │ │ └── ClubViewModel.kt │ │ │ ├── clubauth │ │ │ └── ClubAuthPage.kt │ │ │ ├── findoutmore │ │ │ ├── FindOutMoreNavigation.kt │ │ │ ├── FindOutMorePagerState.kt │ │ │ └── FindOutMoreScreen.kt │ │ │ ├── mydata │ │ │ └── MyDataPage.kt │ │ │ ├── myorders │ │ │ ├── MyOrdersNavigation.kt │ │ │ └── MyOrdersScreen.kt │ │ │ ├── profile │ │ │ ├── ProfileNavigation.kt │ │ │ ├── ProfileScreen.kt │ │ │ ├── ProfileTabsState.kt │ │ │ └── ProfileViewModel.kt │ │ │ ├── promotion │ │ │ ├── PromotionNavigation.kt │ │ │ ├── PromotionScreen.kt │ │ │ └── PromotionsViewModel.kt │ │ │ ├── promotions │ │ │ ├── PromotionsPage.kt │ │ │ └── PromotionsViewModel.kt │ │ │ ├── purchasehistory │ │ │ ├── PurchaseHistoryNavigation.kt │ │ │ └── PurchaseHistoryScreen.kt │ │ │ └── returns │ │ │ ├── ReturnsNavigation.kt │ │ │ └── ReturnsScreen.kt │ │ └── res │ │ ├── drawable │ │ └── club_auth_cover.jpg │ │ └── values │ │ └── strings.xml └── registration │ ├── build.gradle.kts │ └── src │ └── main │ ├── java │ └── com │ │ └── maruchin │ │ └── features │ │ └── registration │ │ ├── RegistrationGraph.kt │ │ ├── birthdate │ │ ├── BirthDateNavigation.kt │ │ ├── BirthDateScreen.kt │ │ └── BirthDateViewModel.kt │ │ └── registrationform │ │ ├── RegistrationFormNavigation.kt │ │ ├── RegistrationFormScreen.kt │ │ └── RegistrationViewModel.kt │ └── res │ └── values │ └── strings.xml ├── forms ├── build.gradle.kts └── src │ └── main │ ├── java │ └── com │ │ └── maruchin │ │ └── forms │ │ ├── addressform │ │ ├── AddressForm.kt │ │ └── AddressFormState.kt │ │ ├── changepasswordform │ │ ├── ChangePasswordForm.kt │ │ └── ChangePasswordFormState.kt │ │ ├── datefield │ │ ├── DateField.kt │ │ └── DateFieldState.kt │ │ ├── emailfield │ │ ├── EmailField.kt │ │ └── EmailFieldState.kt │ │ ├── loginform │ │ ├── LoginForm.kt │ │ └── LoginFormState.kt │ │ ├── passwordfield │ │ ├── PasswordField.kt │ │ └── PasswordFieldState.kt │ │ ├── passwordsform │ │ ├── PasswordsForm.kt │ │ └── PasswordsFormState.kt │ │ ├── personaldataform │ │ ├── PersonalDataForm.kt │ │ └── PersonalDataFormState.kt │ │ ├── registrationform │ │ ├── RegistrationForm.kt │ │ └── RegistrationFormState.kt │ │ └── textfield │ │ ├── TextField.kt │ │ └── TextFieldState.kt │ └── res │ └── values │ └── strings.xml ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── ui ├── build.gradle.kts └── src └── main ├── java └── com │ └── maruchin │ └── ui │ ├── AddressItem.kt │ ├── AllProductsButton.kt │ ├── Deeplink.kt │ ├── DeliveryItem.kt │ ├── NavigationTransitions.kt │ ├── OpenEmailApp.kt │ ├── OpenWebsite.kt │ ├── OrderProductItem.kt │ ├── PaymentItem.kt │ ├── ProductGrid.kt │ ├── ProductItem.kt │ └── ScreenContentPlaceholder.kt └── res └── values └── strings.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | build/ 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | .idea/**/* 16 | local.properties 17 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("buildlogic.appmodule") 3 | } 4 | 5 | android { 6 | namespace = "com.maruchin.androidnavigation" 7 | } 8 | 9 | dependencies { 10 | implementation(project(":ui")) 11 | 12 | implementation(project(":features:home")) 13 | implementation(project(":features:category-browser")) 14 | implementation(project(":features:product-browser")) 15 | implementation(project(":features:product-card")) 16 | implementation(project(":features:login")) 17 | implementation(project(":features:profile")) 18 | implementation(project(":features:my-data")) 19 | implementation(project(":features:registration")) 20 | implementation(project(":features:cart")) 21 | implementation(project(":features:order")) 22 | implementation(project(":features:favorites")) 23 | } 24 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/maruchin/androidnavigation/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.maruchin.androidnavigation 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.material3.MaterialTheme 7 | import com.maruchin.androidnavigation.root.RootHost 8 | import dagger.hilt.android.AndroidEntryPoint 9 | 10 | @AndroidEntryPoint 11 | class MainActivity : ComponentActivity() { 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setContent { 16 | MaterialTheme { 17 | RootHost() 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/maruchin/androidnavigation/SampleApplication.kt: -------------------------------------------------------------------------------- 1 | package com.maruchin.androidnavigation 2 | 3 | import android.app.Application 4 | import dagger.hilt.android.HiltAndroidApp 5 | 6 | @HiltAndroidApp 7 | class SampleApplication : Application() -------------------------------------------------------------------------------- /app/src/main/java/com/maruchin/androidnavigation/navigationbar/NavigationBarState.kt: -------------------------------------------------------------------------------- 1 | package com.maruchin.androidnavigation.navigationbar 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.runtime.Stable 5 | import androidx.compose.runtime.remember 6 | import androidx.navigation.NavController 7 | import androidx.navigation.NavGraph.Companion.findStartDestination 8 | import com.maruchin.features.cart.CART_GRAPH_ROUTE 9 | import com.maruchin.features.categorybrowser.CATEGORY_BROWSER_GRAPH_ROUTE 10 | import com.maruchin.features.favorites.FAVORITES_GRAPH_ROUTE 11 | import com.maruchin.features.home.HOME_GRAPH_ROUTE 12 | import com.maruchin.features.profile.PROFILE_GRAPH_ROUTE 13 | import kotlinx.coroutines.flow.Flow 14 | import kotlinx.coroutines.flow.map 15 | 16 | @Stable 17 | internal class NavigationBarState(private val navController: NavController) { 18 | private val navigationBarRoutes = listOf( 19 | HOME_GRAPH_ROUTE, 20 | CATEGORY_BROWSER_GRAPH_ROUTE, 21 | FAVORITES_GRAPH_ROUTE, 22 | CART_GRAPH_ROUTE, 23 | PROFILE_GRAPH_ROUTE, 24 | ) 25 | 26 | fun isRouteSelected(route: String): Flow { 27 | return navController.currentBackStack.map { backStack -> 28 | backStack 29 | .map { it.destination.route } 30 | .lastOrNull { navigationBarRoutes.contains(it) } 31 | .let { it == route } 32 | } 33 | } 34 | 35 | fun openRoute(route: String) { 36 | navController.navigate(route) { 37 | popUpTo(navController.graph.findStartDestination().id) { 38 | saveState = true 39 | } 40 | launchSingleTop = true 41 | restoreState = true 42 | } 43 | } 44 | } 45 | 46 | @Composable 47 | internal fun rememberNavigationBarState(navController: NavController): NavigationBarState { 48 | return remember(navController) { 49 | NavigationBarState(navController) 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | android-navigation 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |