Skip to content
Open
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
26 changes: 26 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
alias(libs.plugins.kotlinAndroid)
alias(libs.plugins.kotlinxSerialization)
alias(libs.plugins.kapt)
alias(libs.plugins.compose.compiler)
}

android {
Expand Down Expand Up @@ -34,10 +35,33 @@ android {
}
buildFeatures {
viewBinding true
compose true
}
}

composeCompiler {
reportsDestination = layout.buildDirectory.dir("compose_compiler")
metricsDestination = layout.buildDirectory.dir("compose_compiler")
}

dependencies {

implementation platform(libs.androidx.compose.bom)

implementation libs.androidx.compose.material3
implementation libs.androidx.compose.foundation
implementation libs.androidx.compose.ui
implementation libs.androidx.compose.ui.viewbinding

implementation libs.androidx.compose.ui.tooling.preview
implementation libs.androidx.fragment.compose
debugImplementation libs.androidx.compose.ui.tooling

implementation libs.androidx.activity.compose
implementation libs.androidx.lifecycle.viewmodel.compose

implementation libs.androidx.navigation.compose

implementation project(":common:di")
implementation project(":common:formatters")
implementation project(":common:ui")
Expand All @@ -56,6 +80,8 @@ dependencies {
implementation libs.navigation.fragment.ktx
implementation libs.navigation.ui.ktx
implementation libs.coil
implementation libs.coil.compose
implementation libs.coil.network
implementation libs.gson
implementation libs.bundles.network
implementation libs.kotlin.serialization
Expand Down
184 changes: 173 additions & 11 deletions app/src/main/java/ru/otus/marketsample/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,26 +1,188 @@
package ru.otus.marketsample

import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import ru.otus.marketsample.databinding.ActivityMainBinding
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.NavigationBarItemDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Snackbar
import androidx.compose.material3.Text
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.os.bundleOf
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController
import androidx.navigation.findNavController
import androidx.navigation.navigation
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import ru.otus.marketsample.details.feature.navigation.FragmentHost
import ru.otus.marketsample.details.feature.navigation.detailNavHost
import ru.otus.marketsample.di.DaggerAppComponent
import ru.otus.marketsample.di.ViewModelsFactory
import ru.otus.marketsample.navigation.MainDestination
import ru.otus.marketsample.navigation.Product
import ru.otus.marketsample.navigation.Products
import ru.otus.marketsample.navigation.Promo
import ru.otus.marketsample.products.feature.navigation.productGraph
import ru.otus.marketsample.promo.navigation.promoGraph
import javax.inject.Inject
import ru.otus.common.ui.R as RUi

private const val LENGTH_SHORT = 3000L

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding
@Inject
lateinit var viewModelsFactory: ViewModelsFactory

override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
DaggerAppComponent.factory()
.create(this)
.inject(this)
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

ViewCompat.setOnApplyWindowInsetsListener(binding.container) { view, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
view.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets

val mainScreens = listOf(
Products(),
Promo()
)

setContent {
var isShowSnackbar by remember {
mutableStateOf(false)
}
MaterialTheme {
var selected by remember {
mutableStateOf<MainDestination>(Products())
}
val navController = rememberNavController()
MaterialTheme {
Scaffold(
containerColor = colorResource(RUi.color.white),
snackbarHost = {
AnimatedVisibility(
isShowSnackbar,
enter = slideInVertically { -it },
exit = slideOutVertically { it },
) {
Snackbar() {
Text(
modifier = Modifier.padding(16.dp),
text = "Error wile loading data"
)
}
LaunchedEffect(isShowSnackbar) {
launch {
delay(LENGTH_SHORT)
isShowSnackbar = false
}
}
}
},
bottomBar = {
BottomAppBar(
containerColor = colorResource(RUi.color.white),
modifier = Modifier
) {
mainScreens.forEach { destination ->
NavigationBarItem(
colors = NavigationBarItemDefaults.colors(
indicatorColor = Color.Transparent,
selectedTextColor = colorResource(RUi.color.purple_500),
unselectedTextColor = colorResource(RUi.color.black),
selectedIconColor = colorResource(RUi.color.purple_500),
unselectedIconColor = colorResource(RUi.color.black),
),
selected = selected == destination,
onClick = {
selected = destination
navController.navigate(destination) {
launchSingleTop = true
restoreState = true
popUpTo(Products()) {
saveState = true
inclusive = true
}
}
},
label = {
Text(
text = getString(destination.labelRes),
fontSize = 12.sp,
fontWeight = if (selected == destination) {
FontWeight.Bold
} else {
FontWeight.Normal
}
)
},
icon = {
Icon(
modifier = Modifier
.size(24.dp),
painter = painterResource(destination.iconRes),
contentDescription = null,
)
}
)
}
}
}
) { paddingsValue ->
NavHost(
modifier = Modifier
.padding(paddingsValue),
navController = navController,
startDestination = Product,
enterTransition = {
slideInHorizontally() + fadeIn()
},
exitTransition = {
slideOutHorizontally() + fadeOut()
}
) {
promoGraph(navController, viewModelsFactory)
navigation<Product>(startDestination = Products()) {
productGraph(
navController = navController,
viewModelFactory = viewModelsFactory,
openDetail = {
navController.navigate(FragmentHost(it))
},
showSnackbarCallback = { isShowSnackbar = it }
)
detailNavHost(navController)
}
}
}
}
}

}
}
}
49 changes: 0 additions & 49 deletions app/src/main/java/ru/otus/marketsample/MainFragment.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.addCallback
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import coil.load
import androidx.navigation.fragment.findNavController
import coil3.load
import kotlinx.coroutines.launch
import ru.otus.common.di.findDependencies
import ru.otus.marketsample.details.feature.di.DaggerDetailsComponent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ru.otus.marketsample.details.feature.navigation

import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.core.os.bundleOf
import androidx.fragment.compose.AndroidFragment
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
import kotlinx.serialization.Serializable
import ru.otus.marketsample.details.feature.DetailsFragment

fun NavGraphBuilder.detailNavHost(navHostController: NavHostController) {
composable<FragmentHost>(
enterTransition = { scaleIn() + fadeIn() },
exitTransition = { scaleOut() + fadeOut() }
) {backstack ->
val id = backstack.arguments?.getString("productId")
Box(
modifier = Modifier
.fillMaxSize()
) {
AndroidFragment<DetailsFragment>(
modifier = Modifier
.fillMaxSize(),
arguments = bundleOf("productId" to id)
)
}
}
}

@Serializable
data class FragmentHost(val productId: String)
12 changes: 6 additions & 6 deletions app/src/main/java/ru/otus/marketsample/di/AppComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@ import ru.otus.marketsample.details.feature.di.DetailsComponentDependencies
import ru.otus.marketsample.products.feature.di.ProductListComponentDependencies
import ru.otus.marketsample.promo.feature.di.PromoComponentDependencies
import ru.otus.common.di.Dependencies
import ru.otus.marketsample.MainActivity
import javax.inject.Singleton

@Singleton
@Component(
modules = [
NetworkModule::class,
DataModule::class,
ViewModelModule::class,
]
)
interface AppComponent:
Dependencies,
DetailsComponentDependencies,
PromoComponentDependencies,
ProductListComponentDependencies
{
interface AppComponent : Dependencies,
DetailsComponentDependencies {
@Component.Factory
interface Factory {
fun create(@BindsInstance applicationContext: Context): AppComponent
}

fun inject(activity: MainActivity)
}
Loading