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
3 changes: 2 additions & 1 deletion app/src/main/java/com/otus/dihomework/MainNavigation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ sealed class Screen(val route: String, val titleRes: Int, val icon: ImageVector)

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainNavigation() {
fun MainNavigation(modifier: Modifier = Modifier) {
val navController = rememberNavController()
val screens = listOf(Screen.Products, Screen.Favorites)

Scaffold(
modifier = modifier,
topBar = {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
Expand Down
19 changes: 17 additions & 2 deletions app/src/main/java/com/otus/dihomework/ProductsApplication.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
package com.otus.dihomework

import android.app.Application
import com.otus.dihomework.common.di.Dependencies
import com.otus.dihomework.common.di.DependenciesProvider
import com.otus.dihomework.di.AppComponent
import com.otus.dihomework.di.DaggerAppComponent

/**
* Класс приложения, инициализирующий Dagger граф.
*/
class ProductsApplication : Application(), DependenciesProvider {

lateinit var appComponent: AppComponent
private set

class ProductsApplication : Application() {
override fun onCreate() {
super.onCreate()
ServiceLocator.init(this)
appComponent = DaggerAppComponent.factory().create(this)
}

override fun getDependencies(): Dependencies {
return appComponent
}
}
106 changes: 0 additions & 106 deletions app/src/main/java/com/otus/dihomework/ServiceLocator.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ import androidx.datastore.preferences.preferencesDataStore
import com.otus.dihomework.common.domain_impl.FavoritesRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "favorites")

class FavoritesRepositoryImpl(
/**
* Реализация репозитория избранного с использованием DataStore.
*/
class FavoritesRepositoryImpl @Inject constructor(
private val context: Context
) : FavoritesRepository {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.otus.dihomework.common.data

import com.otus.dihomework.common.domain_api.Product
import javax.inject.Inject

class ProductDomainMapper() {
/**
* Маппер для преобразования DTO продуктов в доменные модели.
*/
class ProductDomainMapper @Inject constructor() {

fun fromDto(dto: ProductDto): Product {
return Product(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.otus.dihomework.common.data

import com.otus.dihomework.ServiceLocator
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import javax.inject.Inject

class ProductRemoteDataSource() {
private val apiService = ServiceLocator.getProductApiService()
/**
* Удаленный источник данных для получения продуктов из API.
*/
class ProductRemoteDataSource @Inject constructor(
private val apiService: ProductApiService
) {

fun consumeProducts(): Flow<List<ProductDto>> = flow {
emit(apiService.getProducts())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package com.otus.dihomework.common.data

import com.otus.dihomework.ServiceLocator
import com.otus.dihomework.common.domain_impl.ProductRepository
import com.otus.dihomework.common.domain_api.Product
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class ProductRepositoryImpl() : ProductRepository {

private val remoteDataSource = ServiceLocator.getProductRemoteDataSource()
private val mapper = ServiceLocator.getProductDomainMapper()
/**
* Реализация репозитория продуктов.
*/
class ProductRepositoryImpl @Inject constructor(
private val remoteDataSource: ProductRemoteDataSource,
private val mapper: ProductDomainMapper
) : ProductRepository {

override fun consumeProducts(): Flow<List<Product>> {
return remoteDataSource.consumeProducts()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package com.otus.dihomework.common.domain_impl

import com.otus.dihomework.ServiceLocator
import com.otus.dihomework.common.domain_api.ConsumeFavoritesUseCase
import com.otus.dihomework.common.domain_api.ProductWithFavorite
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import javax.inject.Inject

class ConsumeFavoritesUseCaseImpl() : ConsumeFavoritesUseCase {

private val productRepository = ServiceLocator.getProductRepository()
private val favoritesRepository = ServiceLocator.getFavoritesRepository()
/**
* Реализация сценария получения списка избранных продуктов.
*/
class ConsumeFavoritesUseCaseImpl @Inject constructor(
private val productRepository: ProductRepository,
private val favoritesRepository: FavoritesRepository
) : ConsumeFavoritesUseCase {

override fun invoke(): Flow<List<ProductWithFavorite>> {
return combine(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.otus.dihomework.common.domain_impl

import com.otus.dihomework.ServiceLocator
import com.otus.dihomework.common.domain_api.ConsumeProductsUseCase
import com.otus.dihomework.common.domain_api.ProductWithFavorite
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class ConsumeProductsUseCaseImpl() : ConsumeProductsUseCase {

private val productRepository = ServiceLocator.getProductRepository()
private val favoritesRepository = ServiceLocator.getFavoritesRepository()
/**
* Реализация сценария получения списка продуктов с информацией об избранном.
*/
class ConsumeProductsUseCaseImpl @Inject constructor(
private val productRepository: ProductRepository,
private val favoritesRepository: FavoritesRepository
) : ConsumeProductsUseCase {

override fun invoke(): Flow<List<ProductWithFavorite>> {
return combine(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.otus.dihomework.common.domain_impl

import com.otus.dihomework.ServiceLocator
import com.otus.dihomework.common.domain_api.ToggleFavoriteUseCase
import javax.inject.Inject

class ToggleFavoriteUseCaseImpl() : ToggleFavoriteUseCase {

private val favoritesRepository = ServiceLocator.getFavoritesRepository()
/**
* Реализация сценария добавления/удаления продукта из избранного.
*/
class ToggleFavoriteUseCaseImpl @Inject constructor(
private val favoritesRepository: FavoritesRepository
) : ToggleFavoriteUseCase {

override suspend fun invoke(productId: String, isFavorite: Boolean) {
if (isFavorite) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package com.otus.dihomework.common.util

class PriceFormatter() {
import javax.inject.Inject

/**
* Утилита для форматирования цены продукта.
*/
class PriceFormatter @Inject constructor() {

fun format(price: Double): String {
return "${price.toInt()} ₽"
Expand Down
39 changes: 39 additions & 0 deletions app/src/main/java/com/otus/dihomework/di/AppComponent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.otus.dihomework.di

import android.content.Context
import com.otus.dihomework.features.favorites.FavoritesComponent
import dagger.BindsInstance
import dagger.Component
import javax.inject.Singleton

/**
* Основной компонент приложения.
* Управляет жизненным циклом зависимостей, которые должны существовать в единственном экземпляре.
*/
@Singleton
@Component(
modules = [
NetworkModule::class,
DataModule::class,
DomainModule::class,
SubcomponentsModule::class
]
)
interface AppComponent : ProductsDependencies {

/**
* Предоставляет фабрику для создания сабкомпонента избранного.
*/
fun favoritesComponent(): FavoritesComponent.Factory

/**
* Фабрика для создания экземпляра AppComponent.
*/
@Component.Factory
interface Factory {
/**
* Создает экземпляр AppComponent, передавая контекст приложения.
*/
fun create(@BindsInstance context: Context): AppComponent
}
}
30 changes: 30 additions & 0 deletions app/src/main/java/com/otus/dihomework/di/DataModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.otus.dihomework.di

import com.otus.dihomework.common.data.FavoritesRepositoryImpl
import com.otus.dihomework.common.data.ProductRepositoryImpl
import com.otus.dihomework.common.domain_impl.FavoritesRepository
import com.otus.dihomework.common.domain_impl.ProductRepository
import dagger.Binds
import dagger.Module
import javax.inject.Singleton

/**
* Модуль для предоставления зависимостей уровня данных.
*/
@Module
interface DataModule {

/**
* Связывает реализацию репозитория продуктов с его интерфейсом.
*/
@Binds
@Singleton
fun bindProductRepository(impl: ProductRepositoryImpl): ProductRepository

/**
* Связывает реализацию репозитория избранного с его интерфейсом.
*/
@Binds
@Singleton
fun bindFavoritesRepository(impl: FavoritesRepositoryImpl): FavoritesRepository
}
Loading