diff --git a/example/bottomnavapp/.gitignore b/example/bottomnavapp/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/example/bottomnavapp/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/example/bottomnavapp/build.gradle.kts b/example/bottomnavapp/build.gradle.kts new file mode 100644 index 0000000..fb35ec5 --- /dev/null +++ b/example/bottomnavapp/build.gradle.kts @@ -0,0 +1,115 @@ + +import Dependencies.Common.JAVA_TARGET +import Dependencies.Common.JAVA_VERSION + +plugins { + id("com.android.application") + kotlin(Dependencies.Plugins.ANDROID) +} + +android { + namespace = "com.rootstrap.example.bottomnavapp" + + with(Dependencies.ConfigData) { + compileSdk = COMPILE_SDK_VERSION + buildToolsVersion = BUILD_TOOLS_VERSION + + defaultConfig { + minSdk = MIN_SDK_VERSION + targetSdk = TARGET_SDK_VERSION + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + } + + buildTypes { + getByName("release") { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + + compileOptions { + sourceCompatibility = JAVA_VERSION + targetCompatibility = JAVA_VERSION + } + + kotlinOptions { + jvmTarget = JAVA_TARGET + /** + * Compose-metrics + * How to execute: + * ./gradlew assembleRelease -PcomposeCompilerReports=true + * Review reports in: app/build/compose_metrics + * */ + freeCompilerArgs += listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + project.buildDir.absolutePath + "/compose_metrics" + ) + freeCompilerArgs += listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + project.buildDir.absolutePath + "/compose_metrics" + ) + } + + buildFeatures { + compose = true + buildConfig = true + } + + composeOptions { + kotlinCompilerExtensionVersion = Dependencies.Versions.COMPOSE_COMPILER + } +} + +dependencies { + implementation(project(":core:di")) + implementation(project(":core:domain")) + implementation(project(":example:core:domain")) + implementation(project(":example:core:usecases")) + + with(Dependencies.Android) { + implementation(CORE) + implementation(APP_COMPAT) + implementation(LIFECYCLE_KTX) + implementation(LIFECYCLE_COMPOSE) + implementation(NAVIGATION_UI_RUNTIME) + implementation(SPLASH_SCREEN) + implementation(WINDOW) + } + with(Dependencies.Compose) { + implementation(ACTIVITY) + implementation(UI) + implementation(UI_TOOLING_PREVIEW) + implementation(MATERIAL3) + implementation(ICONS_EXTENDED) + implementation(NAVIGATION_COMPOSE) + implementation(LIFECYCLE_RUNTIME) + debugImplementation(UI_TOOLING) + } + with(Dependencies.Koin) { + implementation(CORE) + implementation(ANDROID) + implementation(ANDROID_NAVIGATION) + implementation(ANDROID_COMPAT) + implementation(WORK_MANAGER) + implementation(COMPOSE) + } + implementation(Dependencies.Rootstrap.FLOW_FORMS) + + with(Dependencies.Test) { + testImplementation(MOCKK) + testImplementation(JUNIT) + testImplementation(KOIN_TEST) + testImplementation(KOIN_TEST_JUNIT) + testImplementation(COROUTINES_TEST) + } + with(Dependencies.AndroidTest) { + androidTestImplementation(EXT_JUNIT) + androidTestImplementation(ESPRESSO_CORE) + androidTestImplementation(COMPOSE_JUNIT) + debugImplementation(COMPOSE_MANIFEST) + } +} diff --git a/example/bottomnavapp/proguard-rules.pro b/example/bottomnavapp/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/example/bottomnavapp/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/example/bottomnavapp/src/androidTest/java/com/rootstrap/example/app/bottomnavapp/ExampleInstrumentedTest.kt b/example/bottomnavapp/src/androidTest/java/com/rootstrap/example/app/bottomnavapp/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..882a060 --- /dev/null +++ b/example/bottomnavapp/src/androidTest/java/com/rootstrap/example/app/bottomnavapp/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.rootstrap.example.app.bottomnavapp + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.rootstrap.example.app.bottomnavapp", appContext.packageName) + } +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/AndroidManifest.xml b/example/bottomnavapp/src/main/AndroidManifest.xml new file mode 100644 index 0000000..62d926a --- /dev/null +++ b/example/bottomnavapp/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/App.kt b/example/bottomnavapp/src/main/java/com/rootstrap/App.kt new file mode 100644 index 0000000..48e6f7e --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/App.kt @@ -0,0 +1,13 @@ +package com.rootstrap + +import android.app.Application +import com.rootstrap.di.appModule +import com.rootstrap.di.initDI + +class App : Application() { + + override fun onCreate() { + super.onCreate() + initDI(appModule = appModule) + } +} diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/MainActivity.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/MainActivity.kt new file mode 100644 index 0000000..e9b7725 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/MainActivity.kt @@ -0,0 +1,63 @@ +package com.rootstrap.bottomnavapp.ui + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import com.rootstrap.bottomnavapp.ui.base.navigation.BottomBarNavigation +import com.rootstrap.bottomnavapp.ui.base.navigation.BottomBarRow +import com.rootstrap.bottomnavapp.ui.base.navigation.rememberAppState +import com.rootstrap.bottomnavapp.ui.theme.ArticlesRepositoryTheme + +class MainActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + ArticlesRepositoryTheme { + val appState = rememberAppState() + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + Scaffold( + bottomBar = { + if (appState.shouldShowBottomBar) + BottomAppBar( + containerColor = MaterialTheme.colorScheme.primary, + contentPadding = PaddingValues(horizontal = 20.dp), + modifier = Modifier + .height(70.dp) + .clip( + RoundedCornerShape( + topStart = 24.dp, topEnd = 24.dp + ) + ) + ) { + BottomBarRow( + navHostController = appState.navHostController, + ) + } + } + ) { innerPadding -> + BottomBarNavigation( + navHostController = appState.navHostController, + padding = innerPadding, + this + ) + } + } + } + } + } +} diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/AppState.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/AppState.kt new file mode 100644 index 0000000..3484f30 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/AppState.kt @@ -0,0 +1,27 @@ +package com.rootstrap.bottomnavapp.ui.base.navigation + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.remember +import androidx.navigation.NavHostController +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController + +@Composable +fun rememberAppState( + navHostController: NavHostController = rememberNavController() +) = remember(navHostController) { + AppState(navHostController) +} + +@Stable +class AppState( + val navHostController: NavHostController +) { + + private val routes = BottomBarRoutes.entries.map { it.routes } + + val shouldShowBottomBar: Boolean + @Composable get() = + navHostController.currentBackStackEntryAsState().value?.destination?.route in routes +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/BottomBarNavigation.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/BottomBarNavigation.kt new file mode 100644 index 0000000..eb78974 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/BottomBarNavigation.kt @@ -0,0 +1,51 @@ +package com.rootstrap.bottomnavapp.ui.base.navigation + +import android.app.Activity +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.navigation +import com.rootstrap.bottomnavapp.ui.pages.DetailScreen +import com.rootstrap.bottomnavapp.ui.pages.HomeScreen +import com.rootstrap.bottomnavapp.ui.pages.NotificationScreen +import com.rootstrap.bottomnavapp.ui.pages.ProfileScreen +import com.rootstrap.bottomnavapp.ui.pages.SplashScreen + +@Composable +fun BottomBarNavigation( + navHostController: NavHostController, + padding: PaddingValues, + context: Activity +) { + + NavHost( + navController = navHostController, startDestination = ScreenRoutes.Splash.route, + modifier = Modifier.padding(padding) + ) { + composable(ScreenRoutes.Splash.route) { + SplashScreen(navHostController = navHostController) + } + navigation( + route = ScreenRoutes.BottomBar.route, + startDestination = BottomBarRoutes.HOME.routes + ) { + composable(BottomBarRoutes.HOME.routes) { + HomeScreen(navHostController = navHostController,context) + } + composable(BottomBarRoutes.NOTIFICATION.routes) { + NotificationScreen(navHostController = navHostController) + } + composable(BottomBarRoutes.PROFILE.routes) { + ProfileScreen(navHostController = navHostController) + } + } + composable(ScreenRoutes.Detail.route) { + DetailScreen(navHostController = navHostController) + } + } + +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/BottomBarRoutes.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/BottomBarRoutes.kt new file mode 100644 index 0000000..5cb9565 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/BottomBarRoutes.kt @@ -0,0 +1,22 @@ +package com.rootstrap.bottomnavapp.ui.base.navigation + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import com.rootstrap.example.bottomnavapp.R + +private const val HOME_ROUTE = "/home" +private const val NOTIFICATION_ROUTE = "/notification" +private const val PROFILE_ROUTE = "/profile" + +enum class BottomBarRoutes( + val id: Int, + @StringRes val title: Int, + val routes: String, + @DrawableRes val icon: Int +) { + + HOME(1, R.string.home, HOME_ROUTE, R.drawable.home), + NOTIFICATION(2, R.string.notification, NOTIFICATION_ROUTE, R.drawable.notification), + PROFILE(3, R.string.profile, PROFILE_ROUTE, R.drawable.profile) + +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/BottomBarRow.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/BottomBarRow.kt new file mode 100644 index 0000000..1e54577 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/BottomBarRow.kt @@ -0,0 +1,78 @@ +package com.rootstrap.bottomnavapp.ui.base.navigation + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.navigation.NavDestination +import androidx.navigation.NavDestination.Companion.hierarchy +import androidx.navigation.NavHostController +import androidx.navigation.compose.currentBackStackEntryAsState +import com.rootstrap.bottomnavapp.ui.theme.compactDimensions + +@Composable +fun BottomBarRow( + navHostController: NavHostController +) { + + val tabList = listOf( + BottomBarRoutes.HOME, + BottomBarRoutes.NOTIFICATION, + BottomBarRoutes.PROFILE + ) + + val navStackBackEntry by navHostController.currentBackStackEntryAsState() + val currentDestination = navStackBackEntry?.destination + + + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically + ) { + tabList.forEach { tab -> + BottomBarItems( + tab = tab, + currentDestination = currentDestination, + navHostController = navHostController + ) + } + } + +} + +@Composable +fun BottomBarItems( + tab: BottomBarRoutes, + currentDestination: NavDestination?, + navHostController: NavHostController +) { + + val selected = currentDestination?.hierarchy?.any { it.route == tab.routes } == true + + val contentColor = + if (selected) Color.Unspecified else MaterialTheme.colorScheme.onPrimary + + IconButton(onClick = { + navHostController.navigate(tab.routes) + }) { + Icon( + painter = painterResource(id = tab.icon), + contentDescription = "", + tint = contentColor, + modifier = Modifier.size(compactDimensions.paddingThirtyQuarters) + ) + } + + +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/ScreenRoutes.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/ScreenRoutes.kt new file mode 100644 index 0000000..539e129 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/base/navigation/ScreenRoutes.kt @@ -0,0 +1,11 @@ +package com.rootstrap.bottomnavapp.ui.base.navigation + +private const val SCREEN_ROUTE_SPLASH = "/splash" +private const val SCREEN_ROUTE_BOTTOMBAR = "/bottombar" +private const val SCREEN_ROUTE_DETAIL = "/detail" + +sealed class ScreenRoutes(val route: String) { + data object Splash : ScreenRoutes(SCREEN_ROUTE_SPLASH) + data object BottomBar : ScreenRoutes(SCREEN_ROUTE_BOTTOMBAR) + data object Detail : ScreenRoutes(SCREEN_ROUTE_DETAIL) +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/model/Dimensions.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/model/Dimensions.kt new file mode 100644 index 0000000..9f26e00 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/model/Dimensions.kt @@ -0,0 +1,24 @@ +package com.rootstrap.bottomnavapp.ui.model + +import androidx.compose.ui.unit.Dp + +data class Dimensions( + val small: Dp, + val medium: Dp, + val big: Dp, + val huge: Dp, + val paddingEightQuarters: Dp, + val paddingQuarter: Dp, + val paddingHalf: Dp, + val paddingThreeQuarters: Dp, + val paddingNormal: Dp, + val paddingFiveQuarters: Dp, + val paddingSixQuarters: Dp, + val paddingDouble: Dp, + val paddingTenQuarters: Dp, + val paddingElevenQuarters: Dp, + val paddingFourteenQuarters: Dp, + val paddingQuadruple: Dp, + val paddingTwentyQuarters: Dp, + val paddingThirtyQuarters: Dp +) diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/model/WindowType.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/model/WindowType.kt new file mode 100644 index 0000000..3ff1f13 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/model/WindowType.kt @@ -0,0 +1,47 @@ +package com.rootstrap.bottomnavapp.ui.model + +import android.content.Context +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.toComposeRect +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.window.layout.WindowMetricsCalculator +import com.rootstrap.bottomnavapp.ui.theme.compactDimensions +import com.rootstrap.bottomnavapp.ui.theme.defaultDimensions +import com.rootstrap.bottomnavapp.ui.theme.expandedDimensions + +enum class WindowType( + val maxHeight: Dp, + val maxWidth: Dp, + val dimensions: Dimensions +) { + COMPACT(600.dp, 480.dp, compactDimensions), + MEDIUM(840.dp, 900.dp, defaultDimensions), + EXPANDED(Dp.Infinity, Dp.Infinity, expandedDimensions); + + companion object { + @Composable + fun getDimensions(context: Context): Dimensions { + val configuration = LocalConfiguration.current + val windowMetrics = remember(configuration) { + WindowMetricsCalculator.getOrCreate() + .computeCurrentWindowMetrics(context) + } + val windowDpSize = with(LocalDensity.current) { + windowMetrics.bounds.toComposeRect().size.toDpSize() + } + + val windowType = when { + windowDpSize.width < COMPACT.maxWidth -> COMPACT + windowDpSize.height < COMPACT.maxHeight -> COMPACT + windowDpSize.width < MEDIUM.maxWidth -> MEDIUM + windowDpSize.height < MEDIUM.maxHeight -> MEDIUM + else -> EXPANDED + } + return windowType.dimensions + } + } +} diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/DetailScreen.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/DetailScreen.kt new file mode 100644 index 0000000..4cca7aa --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/DetailScreen.kt @@ -0,0 +1,28 @@ +package com.rootstrap.bottomnavapp.ui.pages + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.navigation.NavHostController +import com.rootstrap.example.bottomnavapp.R + +@Composable +fun DetailScreen(navHostController: NavHostController) { + + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Text( + text = stringResource(id = R.string.detail_screen_label), + style = TextStyle( + color = Color.Black, + fontWeight = FontWeight.SemiBold + ) + ) + } +} diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/HomeScreen.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/HomeScreen.kt new file mode 100644 index 0000000..3d31a73 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/HomeScreen.kt @@ -0,0 +1,32 @@ +package com.rootstrap.bottomnavapp.ui.pages + +import android.app.Activity +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavHostController +import com.rootstrap.bottomnavapp.ui.base.navigation.ScreenRoutes +import com.rootstrap.example.bottomnavapp.R + +@Composable +fun HomeScreen( + navHostController: NavHostController, + context: Activity +) { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Button(onClick = { + navHostController.navigate(ScreenRoutes.Detail.route) + }) { + Text(text = stringResource(R.string.move_to_detail_screen)) + } + } + BackHandler { + context.finish() + } +} diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/NotificationScreen.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/NotificationScreen.kt new file mode 100644 index 0000000..81bf08d --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/NotificationScreen.kt @@ -0,0 +1,37 @@ +package com.rootstrap.bottomnavapp.ui.pages + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.navigation.NavHostController +import com.rootstrap.bottomnavapp.ui.base.navigation.BottomBarRoutes +import com.rootstrap.example.bottomnavapp.R + +@Composable +fun NotificationScreen(navHostController: NavHostController) { + + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Text( + text = stringResource(R.string.notification_screen_label), + style = TextStyle( + color = Color.Black, + fontWeight = FontWeight.SemiBold + ) + ) + } + BackHandler { + navHostController.navigate(BottomBarRoutes.HOME.routes) { + popUpTo(BottomBarRoutes.HOME.routes){ + inclusive = true + } + } + } +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/ProfileScreen.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/ProfileScreen.kt new file mode 100644 index 0000000..1952b5c --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/ProfileScreen.kt @@ -0,0 +1,38 @@ +package com.rootstrap.bottomnavapp.ui.pages + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.navigation.NavHostController +import com.rootstrap.bottomnavapp.ui.base.navigation.BottomBarRoutes +import com.rootstrap.example.bottomnavapp.R + +@Composable +fun ProfileScreen(navHostController: NavHostController) { + + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Text( + text = stringResource(id = R.string.profile_screen_label), + style = TextStyle( + color = Color.Black, + fontWeight = FontWeight.SemiBold + ) + ) + } + + BackHandler { + navHostController.navigate(BottomBarRoutes.HOME.routes) { + popUpTo(BottomBarRoutes.HOME.routes){ + inclusive = true + } + } + } +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/SplashScreen.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/SplashScreen.kt new file mode 100644 index 0000000..3970e3c --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/pages/SplashScreen.kt @@ -0,0 +1,31 @@ +package com.rootstrap.bottomnavapp.ui.pages + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavHostController +import com.rootstrap.bottomnavapp.ui.base.navigation.ScreenRoutes +import com.rootstrap.example.bottomnavapp.R +import kotlinx.coroutines.delay + +@Composable +fun SplashScreen(navHostController: NavHostController) { + + LaunchedEffect(key1 = Unit){ + delay(2000) + navHostController.navigate(ScreenRoutes.BottomBar.route) + } + + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Image( + painterResource(id = R.drawable.rootstrap_logo), + contentDescription = stringResource(id = R.string.splash_content_description) + ) + } +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Color.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Color.kt new file mode 100644 index 0000000..3a73226 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Color.kt @@ -0,0 +1,10 @@ +package com.rootstrap.bottomnavapp.ui.theme + + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + + diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Dimensions.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Dimensions.kt new file mode 100644 index 0000000..bc5b9b6 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Dimensions.kt @@ -0,0 +1,67 @@ +package com.rootstrap.bottomnavapp.ui.theme + +import androidx.compose.ui.unit.dp +import com.rootstrap.bottomnavapp.ui.model.Dimensions + +val defaultDimensions = Dimensions( + small = 4.dp, + medium = 8.dp, + big = 16.dp, + huge = 32.dp, + paddingEightQuarters = 1.dp, + paddingQuarter = 2.dp, + paddingHalf = 4.dp, + paddingThreeQuarters = 6.dp, + paddingNormal = 8.dp, + paddingFiveQuarters = 10.dp, + paddingSixQuarters = 12.dp, + paddingDouble = 16.dp, + paddingTenQuarters = 20.dp, + paddingElevenQuarters = 22.dp, + paddingFourteenQuarters = 28.dp, + paddingQuadruple = 32.dp, + paddingTwentyQuarters = 40.dp, + paddingThirtyQuarters = 60.dp +) + +val compactDimensions = Dimensions( + small = 2.dp, + medium = 4.dp, + big = 8.dp, + huge = 16.dp, + paddingEightQuarters = 0.5.dp, + paddingQuarter = 1.dp, + paddingHalf = 2.dp, + paddingThreeQuarters = 3.dp, + paddingNormal = 4.dp, + paddingFiveQuarters = 5.dp, + paddingSixQuarters = 6.dp, + paddingDouble = 8.dp, + paddingTenQuarters = 10.dp, + paddingElevenQuarters = 11.dp, + paddingFourteenQuarters = 14.dp, + paddingQuadruple = 16.dp, + paddingTwentyQuarters = 20.dp, + paddingThirtyQuarters = 30.dp +) + +val expandedDimensions = Dimensions( + small = 16.dp, + medium = 32.dp, + big = 64.dp, + huge = 128.dp, + paddingEightQuarters = 4.dp, + paddingQuarter = 8.dp, + paddingHalf = 16.dp, + paddingThreeQuarters = 24.dp, + paddingNormal = 32.dp, + paddingFiveQuarters = 40.dp, + paddingSixQuarters = 48.dp, + paddingDouble = 64.dp, + paddingTenQuarters = 80.dp, + paddingElevenQuarters = 88.dp, + paddingFourteenQuarters = 112.dp, + paddingQuadruple = 128.dp, + paddingTwentyQuarters = 160.dp, + paddingThirtyQuarters = 160.dp +) diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Theme.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Theme.kt new file mode 100644 index 0000000..4e2d7d5 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Theme.kt @@ -0,0 +1,65 @@ +package com.rootstrap.bottomnavapp.ui.theme + +import android.app.Activity +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Color.LightGray, + secondary = Color.LightGray, + tertiary = Color.Yellow, + surface = Color.Black + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun ArticlesRepositoryTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = Color.Black.toArgb() + window.navigationBarColor = Color.Black.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Type.kt b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Type.kt new file mode 100644 index 0000000..7436bb0 --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/bottomnavapp/ui/theme/Type.kt @@ -0,0 +1,32 @@ +package com.rootstrap.bottomnavapp.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ), + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) +) diff --git a/example/bottomnavapp/src/main/java/com/rootstrap/di/DI.kt b/example/bottomnavapp/src/main/java/com/rootstrap/di/DI.kt new file mode 100644 index 0000000..a34261e --- /dev/null +++ b/example/bottomnavapp/src/main/java/com/rootstrap/di/DI.kt @@ -0,0 +1,11 @@ +package com.rootstrap.di + +import org.koin.dsl.module + +/** + * app module provides viewModels and other objects in the app module + * For example: viewModel{}, single{}, factory{} + * */ +val appModule = module { + +} diff --git a/example/bottomnavapp/src/main/res/drawable/home.xml b/example/bottomnavapp/src/main/res/drawable/home.xml new file mode 100644 index 0000000..5a870f5 --- /dev/null +++ b/example/bottomnavapp/src/main/res/drawable/home.xml @@ -0,0 +1,5 @@ + + + diff --git a/example/bottomnavapp/src/main/res/drawable/ic_launcher_background.xml b/example/bottomnavapp/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/example/bottomnavapp/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/bottomnavapp/src/main/res/drawable/ic_launcher_foreground.xml b/example/bottomnavapp/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/example/bottomnavapp/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/example/bottomnavapp/src/main/res/drawable/notification.xml b/example/bottomnavapp/src/main/res/drawable/notification.xml new file mode 100644 index 0000000..605362e --- /dev/null +++ b/example/bottomnavapp/src/main/res/drawable/notification.xml @@ -0,0 +1,5 @@ + + + diff --git a/example/bottomnavapp/src/main/res/drawable/profile.xml b/example/bottomnavapp/src/main/res/drawable/profile.xml new file mode 100644 index 0000000..98c3b21 --- /dev/null +++ b/example/bottomnavapp/src/main/res/drawable/profile.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/example/bottomnavapp/src/main/res/drawable/rootstrap_logo.xml b/example/bottomnavapp/src/main/res/drawable/rootstrap_logo.xml new file mode 100644 index 0000000..83070f2 --- /dev/null +++ b/example/bottomnavapp/src/main/res/drawable/rootstrap_logo.xml @@ -0,0 +1,9 @@ + + + diff --git a/example/bottomnavapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/example/bottomnavapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/example/bottomnavapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/example/bottomnavapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/example/bottomnavapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/example/bottomnavapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/example/bottomnavapp/src/main/res/mipmap-hdpi/ic_launcher.webp b/example/bottomnavapp/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/example/bottomnavapp/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/example/bottomnavapp/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/example/bottomnavapp/src/main/res/mipmap-mdpi/ic_launcher.webp b/example/bottomnavapp/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/example/bottomnavapp/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/example/bottomnavapp/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/example/bottomnavapp/src/main/res/mipmap-xhdpi/ic_launcher.webp b/example/bottomnavapp/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/example/bottomnavapp/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/example/bottomnavapp/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/example/bottomnavapp/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/example/bottomnavapp/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/example/bottomnavapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/example/bottomnavapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/example/bottomnavapp/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/example/bottomnavapp/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/example/bottomnavapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/example/bottomnavapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/example/bottomnavapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/example/bottomnavapp/src/main/res/values/colors.xml b/example/bottomnavapp/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/example/bottomnavapp/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/example/bottomnavapp/src/main/res/values/strings.xml b/example/bottomnavapp/src/main/res/values/strings.xml new file mode 100644 index 0000000..6303516 --- /dev/null +++ b/example/bottomnavapp/src/main/res/values/strings.xml @@ -0,0 +1,11 @@ + + BottomNavApp + Home + Notification + Profile + Move to Detail Screen + Notification Screen + Detail Screen + Profile Screen + Rootstrap logo + \ No newline at end of file diff --git a/example/bottomnavapp/src/main/res/values/themes.xml b/example/bottomnavapp/src/main/res/values/themes.xml new file mode 100644 index 0000000..38dfa01 --- /dev/null +++ b/example/bottomnavapp/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +