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
31 changes: 18 additions & 13 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.composeCompiler)
}

android {
Expand Down Expand Up @@ -33,7 +34,12 @@ android {
jvmTarget = '17'
}
buildFeatures {
viewBinding true
compose true
}

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

Expand All @@ -44,18 +50,7 @@ dependencies {
implementation project(":common:data:products")
implementation project(":common:data:promo")

implementation libs.core.ktx
implementation libs.appcompat
implementation libs.material
implementation libs.constraintlayout
implementation libs.swipetorefresh
implementation libs.lifecycle.livedata.ktx
implementation libs.lifecycle.viewmodel.ktx
implementation libs.fragment.ktx
implementation libs.lifecycle.runtime.ktx
implementation libs.navigation.fragment.ktx
implementation libs.navigation.ui.ktx
implementation libs.coil
implementation libs.coil.compose
implementation libs.gson
implementation libs.bundles.network
implementation libs.kotlin.serialization
Expand All @@ -69,4 +64,14 @@ dependencies {
testImplementation libs.junit
androidTestImplementation libs.androidx.test.ext.junit
androidTestImplementation libs.espresso.core

implementation libs.androidx.activity.compose
implementation libs.androidx.navigation.compose

implementation platform(libs.androidx.compose.bom)
implementation libs.androidx.material3

// Android Studio Preview support
implementation libs.androidx.ui.tooling.preview
debugImplementation libs.androidx.ui.tooling
}
90 changes: 74 additions & 16 deletions app/src/main/java/ru/otus/marketsample/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,26 +1,84 @@
package ru.otus.marketsample

import android.os.Bundle
import androidx.activity.ComponentActivity
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

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import ru.otus.marketsample.common.ObserveAsEvents
import ru.otus.marketsample.navigation.BottomBar
import ru.otus.marketsample.navigation.MarketSampleNavHost
import ru.otus.marketsample.navigation.SnackbarController
import ru.otus.marketsample.navigation.rememberBarVisibility
import ru.otus.marketsample.navigation.rememberNavigationState
import ru.otus.marketsample.navigation.rememberSnackbarHostState
import theme.MarketSampleTheme

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
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
enableEdgeToEdge()
setContent {
MarketSampleTheme {
val bottomBarState = rememberBarVisibility()
val navigationState = rememberNavigationState()
val snackbarHostState = rememberSnackbarHostState()
val scope = rememberCoroutineScope()

ObserveAsEvents(
flow = SnackbarController.events,
snackbarHostState,
) { event ->
scope.launch {
snackbarHostState.currentSnackbarData?.dismiss()
snackbarHostState.showSnackbar(
message = event.message,
duration = SnackbarDuration.Short,
)
}
}

Scaffold(
bottomBar = {
Box(
modifier = Modifier.height(100.dp)
) {
Crossfade(
targetState = bottomBarState.isVisible,
animationSpec = tween(200),
) { isBottomBarVisible ->
when (isBottomBarVisible) {
true -> BottomBar(navigationState)
false -> Spacer(modifier = Modifier)
}
}
}
},
snackbarHost = {
SnackbarHost(
hostState = snackbarHostState,
)
},
) {
MarketSampleNavHost(
navigationState,
bottomBarState,
Modifier.padding(it),
)
}
}
}
}
}
49 changes: 0 additions & 49 deletions app/src/main/java/ru/otus/marketsample/MainFragment.kt

This file was deleted.

11 changes: 9 additions & 2 deletions app/src/main/java/ru/otus/marketsample/MarketSampleApp.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package ru.otus.marketsample

import android.app.Application
import ru.otus.marketsample.di.AppComponent
import ru.otus.marketsample.di.DaggerAppComponent
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import ru.otus.common.di.Dependencies
import ru.otus.common.di.DependenciesProvider
import ru.otus.marketsample.di.AppComponent
import ru.otus.marketsample.di.DaggerAppComponent

class MarketSampleApp: Application(), DependenciesProvider {
val appComponent: AppComponent = DaggerAppComponent.factory().create(this)
Expand All @@ -13,3 +15,8 @@ class MarketSampleApp: Application(), DependenciesProvider {
return appComponent
}
}

@Composable
fun getApplicationComponent(): AppComponent {
return (LocalContext.current.applicationContext as MarketSampleApp).appComponent
}
73 changes: 73 additions & 0 deletions app/src/main/java/ru/otus/marketsample/common/Discount.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package ru.otus.marketsample.common

import androidx.compose.foundation.border
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import theme.MarketSampleTheme
import theme.purple_200
import theme.purple_500
import theme.white

@Composable
fun Discount(
discount: String,
style: TextStyle,
modifier: Modifier = Modifier,
) {
val roundedCornerShape = RoundedCornerShape(
topStart = 40.dp,
topEnd = 10.dp,
bottomEnd = 40.dp,
bottomStart = 40.dp,
)

Text(
text = discount,
style = style,
modifier = modifier
.clip(roundedCornerShape)
.drawBehind {
drawRect(
brush = Brush.linearGradient(
colors = listOf(
purple_200,
purple_500,
),
start = Offset(x = 0f, y = size.height),
end = Offset(x = size.width, y = 0f),
),
)
}
.border(
width = 2.dp,
color = white,
shape = roundedCornerShape,
)
.padding(
vertical = 4.dp,
horizontal = 10.dp,
),
)
}

@Composable
@PreviewLightDark
private fun DiscountPreview() {
MarketSampleTheme {
Discount(
discount = "-20%",
style = MaterialTheme.typography.displayLarge,
)
}
}
26 changes: 26 additions & 0 deletions app/src/main/java/ru/otus/marketsample/common/ObserveAsEvents.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ru.otus.marketsample.common

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext

@Composable
fun <T> ObserveAsEvents(
flow: Flow<T>,
key: Any? = null,
onEvent: (T) -> Unit
) {
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(lifecycleOwner.lifecycle, key, flow) {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
withContext(Dispatchers.Main.immediate) {
flow.collect(onEvent)
}
}
}
}
Loading