diff --git a/app/src/main/java/com/otus/dihomework/MainActivity.kt b/app/src/main/java/com/otus/dihomework/MainActivity.kt index 76fe201..6c4efc7 100644 --- a/app/src/main/java/com/otus/dihomework/MainActivity.kt +++ b/app/src/main/java/com/otus/dihomework/MainActivity.kt @@ -4,11 +4,19 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import com.otus.dihomework.di.MainActivityModule import com.otus.dihomework.ui.theme.DIHomeworkTheme class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + + (application as ProductsApplication).component + .mainActivityComponent() + .create(MainActivityModule(this)) + .inject(this) + enableEdgeToEdge() setContent { diff --git a/app/src/main/java/com/otus/dihomework/ProductsApplication.kt b/app/src/main/java/com/otus/dihomework/ProductsApplication.kt index 2e3799d..76c696e 100644 --- a/app/src/main/java/com/otus/dihomework/ProductsApplication.kt +++ b/app/src/main/java/com/otus/dihomework/ProductsApplication.kt @@ -1,10 +1,13 @@ package com.otus.dihomework import android.app.Application +import com.otus.dihomework.di.AppComponent +import com.otus.dihomework.di.DaggerAppComponent +import com.otus.dihomework.di.DependenciesProvider -class ProductsApplication : Application() { - override fun onCreate() { - super.onCreate() - ServiceLocator.init(this) - } +class ProductsApplication : Application(), DependenciesProvider { + + val component: AppComponent = DaggerAppComponent.factory().create(this) + + override fun getDependencies() = component } diff --git a/app/src/main/java/com/otus/dihomework/ServiceLocator.kt b/app/src/main/java/com/otus/dihomework/ServiceLocator.kt deleted file mode 100644 index 1a56c01..0000000 --- a/app/src/main/java/com/otus/dihomework/ServiceLocator.kt +++ /dev/null @@ -1,106 +0,0 @@ -package com.otus.dihomework - -import android.content.Context -import com.google.gson.GsonBuilder -import com.otus.dihomework.common.data.FavoritesRepositoryImpl -import com.otus.dihomework.common.data.ProductApiService -import com.otus.dihomework.common.data.ProductDomainMapper -import com.otus.dihomework.common.data.ProductRemoteDataSource -import com.otus.dihomework.common.data.ProductRepositoryImpl -import com.otus.dihomework.common.domain_api.ConsumeFavoritesUseCase -import com.otus.dihomework.common.domain_api.ConsumeProductsUseCase -import com.otus.dihomework.common.domain_api.ToggleFavoriteUseCase -import com.otus.dihomework.common.domain_impl.ConsumeFavoritesUseCaseImpl -import com.otus.dihomework.common.domain_impl.ConsumeProductsUseCaseImpl -import com.otus.dihomework.common.domain_impl.FavoritesRepository -import com.otus.dihomework.common.domain_impl.ProductRepository -import com.otus.dihomework.common.domain_impl.ToggleFavoriteUseCaseImpl -import com.otus.dihomework.common.util.PriceFormatter -import com.otus.dihomework.features.favorites.FavoritesStateFactory -import com.otus.dihomework.features.products.ProductsStateFactory -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import java.util.concurrent.TimeUnit - -object ServiceLocator { - - private var applicationContext: Context? = null - - fun init(context: Context) { - applicationContext = context.applicationContext - } - - private val httpLoggingInterceptor: HttpLoggingInterceptor by lazy { - HttpLoggingInterceptor().apply { - level = HttpLoggingInterceptor.Level.BODY - } - } - - private val okHttpClient: OkHttpClient by lazy { - OkHttpClient.Builder() - .addInterceptor(httpLoggingInterceptor) - .connectTimeout(30, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) - .build() - } - - private val retrofit: Retrofit by lazy { - Retrofit.Builder() - .baseUrl("https://otus-android.github.io/") - .client(okHttpClient) - .addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())) - .build() - } - - private val _productApiService: ProductApiService by lazy { - retrofit.create(ProductApiService::class.java) - } - - fun getProductApiService(): ProductApiService { - return _productApiService - } - - fun getProductDomainMapper(): ProductDomainMapper { - return ProductDomainMapper() - } - - fun getProductRemoteDataSource(): ProductRemoteDataSource { - return ProductRemoteDataSource() - } - - fun getFavoritesRepository(): FavoritesRepository { - val context = applicationContext - checkNotNull(context) { "ServiceLocator not initialized! Call init() first." } - return FavoritesRepositoryImpl(context) - } - - fun getProductRepository(): ProductRepository { - return ProductRepositoryImpl() - } - - fun getConsumeProductsUseCase(): ConsumeProductsUseCase { - return ConsumeProductsUseCaseImpl() - } - - fun getConsumeFavoritesUseCase(): ConsumeFavoritesUseCase { - return ConsumeFavoritesUseCaseImpl() - } - - fun getToggleFavoriteUseCase(): ToggleFavoriteUseCase { - return ToggleFavoriteUseCaseImpl() - } - - fun getPriceFormatter(): PriceFormatter { - return PriceFormatter() - } - - fun getProductsStateFactory(): ProductsStateFactory { - return ProductsStateFactory() - } - - fun getFavoritesStateFactory(): FavoritesStateFactory { - return FavoritesStateFactory() - } -} diff --git a/app/src/main/java/com/otus/dihomework/common/data/FavoritesRepositoryImpl.kt b/app/src/main/java/com/otus/dihomework/common/data/FavoritesRepositoryImpl.kt index ad70211..9e438d4 100644 --- a/app/src/main/java/com/otus/dihomework/common/data/FavoritesRepositoryImpl.kt +++ b/app/src/main/java/com/otus/dihomework/common/data/FavoritesRepositoryImpl.kt @@ -9,10 +9,11 @@ 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 by preferencesDataStore(name = "favorites") -class FavoritesRepositoryImpl( +class FavoritesRepositoryImpl @Inject constructor( private val context: Context ) : FavoritesRepository { diff --git a/app/src/main/java/com/otus/dihomework/common/data/ProductDomainMapper.kt b/app/src/main/java/com/otus/dihomework/common/data/ProductDomainMapper.kt index 762959d..0ba54f1 100644 --- a/app/src/main/java/com/otus/dihomework/common/data/ProductDomainMapper.kt +++ b/app/src/main/java/com/otus/dihomework/common/data/ProductDomainMapper.kt @@ -1,8 +1,9 @@ package com.otus.dihomework.common.data import com.otus.dihomework.common.domain_api.Product +import javax.inject.Inject -class ProductDomainMapper() { +class ProductDomainMapper @Inject constructor() { fun fromDto(dto: ProductDto): Product { return Product( diff --git a/app/src/main/java/com/otus/dihomework/common/data/ProductRemoteDataSource.kt b/app/src/main/java/com/otus/dihomework/common/data/ProductRemoteDataSource.kt index ae9935f..ba9670e 100644 --- a/app/src/main/java/com/otus/dihomework/common/data/ProductRemoteDataSource.kt +++ b/app/src/main/java/com/otus/dihomework/common/data/ProductRemoteDataSource.kt @@ -1,11 +1,12 @@ 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() +class ProductRemoteDataSource @Inject constructor( + private val apiService: ProductApiService +) { fun consumeProducts(): Flow> = flow { emit(apiService.getProducts()) diff --git a/app/src/main/java/com/otus/dihomework/common/data/ProductRepositoryImpl.kt b/app/src/main/java/com/otus/dihomework/common/data/ProductRepositoryImpl.kt index 7027dca..7b3c407 100644 --- a/app/src/main/java/com/otus/dihomework/common/data/ProductRepositoryImpl.kt +++ b/app/src/main/java/com/otus/dihomework/common/data/ProductRepositoryImpl.kt @@ -1,15 +1,15 @@ 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 com.otus.dihomework.common.domain_impl.ProductRepository 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> { return remoteDataSource.consumeProducts() diff --git a/app/src/main/java/com/otus/dihomework/common/domain_impl/ConsumeFavoritesUseCaseImpl.kt b/app/src/main/java/com/otus/dihomework/common/domain_impl/ConsumeFavoritesUseCaseImpl.kt index bc9b71f..7094d2f 100644 --- a/app/src/main/java/com/otus/dihomework/common/domain_impl/ConsumeFavoritesUseCaseImpl.kt +++ b/app/src/main/java/com/otus/dihomework/common/domain_impl/ConsumeFavoritesUseCaseImpl.kt @@ -1,15 +1,15 @@ 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> { return combine( diff --git a/app/src/main/java/com/otus/dihomework/common/domain_impl/ConsumeProductsUseCaseImpl.kt b/app/src/main/java/com/otus/dihomework/common/domain_impl/ConsumeProductsUseCaseImpl.kt index 6314f50..65eae32 100644 --- a/app/src/main/java/com/otus/dihomework/common/domain_impl/ConsumeProductsUseCaseImpl.kt +++ b/app/src/main/java/com/otus/dihomework/common/domain_impl/ConsumeProductsUseCaseImpl.kt @@ -1,16 +1,17 @@ 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> { return combine( diff --git a/app/src/main/java/com/otus/dihomework/common/domain_impl/ToggleFavoriteUseCaseImpl.kt b/app/src/main/java/com/otus/dihomework/common/domain_impl/ToggleFavoriteUseCaseImpl.kt index 4b5c8b7..99b52ae 100644 --- a/app/src/main/java/com/otus/dihomework/common/domain_impl/ToggleFavoriteUseCaseImpl.kt +++ b/app/src/main/java/com/otus/dihomework/common/domain_impl/ToggleFavoriteUseCaseImpl.kt @@ -1,11 +1,11 @@ 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) { diff --git a/app/src/main/java/com/otus/dihomework/di/AppComponent.kt b/app/src/main/java/com/otus/dihomework/di/AppComponent.kt new file mode 100644 index 0000000..5cc58c4 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/AppComponent.kt @@ -0,0 +1,30 @@ +package com.otus.dihomework.di + +import android.content.Context +import dagger.BindsInstance +import dagger.Component +import javax.inject.Singleton + +@Singleton +@Component( + modules = [ + NetModule::class, + RepositoryModule::class, + DomainModule::class, + UtilsModule::class, + SubcomponentsModule::class, + ] +) +interface AppComponent : ProductDependencies { + + fun favoritesComponent(): FavoritesComponent.Factory + + fun mainActivityComponent(): MainActivityComponent.Factory + + @Component.Factory + interface Factory { + fun create( + @BindsInstance context: Context + ): AppComponent + } +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/Dependencies.kt b/app/src/main/java/com/otus/dihomework/di/Dependencies.kt new file mode 100644 index 0000000..84fc107 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/Dependencies.kt @@ -0,0 +1,13 @@ +package com.otus.dihomework.di + +import android.content.Context + +interface Dependencies + +interface DependenciesProvider { + fun getDependencies(): Dependencies +} + +inline fun Context.findDependencies(): T { + return (applicationContext as DependenciesProvider).getDependencies() as T +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/DomainModule.kt b/app/src/main/java/com/otus/dihomework/di/DomainModule.kt new file mode 100644 index 0000000..402cd59 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/DomainModule.kt @@ -0,0 +1,23 @@ +package com.otus.dihomework.di + +import com.otus.dihomework.common.domain_api.ConsumeFavoritesUseCase +import com.otus.dihomework.common.domain_api.ConsumeProductsUseCase +import com.otus.dihomework.common.domain_api.ToggleFavoriteUseCase +import com.otus.dihomework.common.domain_impl.ConsumeFavoritesUseCaseImpl +import com.otus.dihomework.common.domain_impl.ConsumeProductsUseCaseImpl +import com.otus.dihomework.common.domain_impl.ToggleFavoriteUseCaseImpl +import dagger.Binds +import dagger.Module + +@Module +abstract class DomainModule { + + @Binds + abstract fun getConsumeFavoritesUseCase(impl: ConsumeFavoritesUseCaseImpl): ConsumeFavoritesUseCase + + @Binds + abstract fun getConsumeProductsUseCase(impl: ConsumeProductsUseCaseImpl): ConsumeProductsUseCase + + @Binds + abstract fun getToggleFavoriteUseCase(impl: ToggleFavoriteUseCaseImpl): ToggleFavoriteUseCase +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/FavoritesComponent.kt b/app/src/main/java/com/otus/dihomework/di/FavoritesComponent.kt new file mode 100644 index 0000000..62672eb --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/FavoritesComponent.kt @@ -0,0 +1,17 @@ +package com.otus.dihomework.di + +import com.otus.dihomework.common.di.FeatureScope +import com.otus.dihomework.features.favorites.FavoritesViewModelFactory +import dagger.Subcomponent + +@FeatureScope +@Subcomponent +interface FavoritesComponent { + + fun viewModelFactory(): FavoritesViewModelFactory + + @Subcomponent.Factory + interface Factory { + fun create(): FavoritesComponent + } +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/MainActivityComponent.kt b/app/src/main/java/com/otus/dihomework/di/MainActivityComponent.kt new file mode 100644 index 0000000..0da6fa3 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/MainActivityComponent.kt @@ -0,0 +1,21 @@ +package com.otus.dihomework.di + +import com.otus.dihomework.MainActivity +import com.otus.dihomework.di.scopes.ActivityScope +import dagger.Subcomponent + +@ActivityScope +@Subcomponent( + modules = [MainActivityModule::class] +) +interface MainActivityComponent { + + fun inject(activity: MainActivity) + + @Subcomponent.Factory + interface Factory { + fun create( + mainActivityModule: MainActivityModule + ): MainActivityComponent + } +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/MainActivityModule.kt b/app/src/main/java/com/otus/dihomework/di/MainActivityModule.kt new file mode 100644 index 0000000..c91f70a --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/MainActivityModule.kt @@ -0,0 +1,14 @@ +package com.otus.dihomework.di + +import com.otus.dihomework.MainActivity +import com.otus.dihomework.di.scopes.ActivityScope +import dagger.Module +import dagger.Provides + +@Module +class MainActivityModule(private val activity: MainActivity) { + + @ActivityScope + @Provides + fun provideMainActivity(): MainActivity = activity +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/NetModule.kt b/app/src/main/java/com/otus/dihomework/di/NetModule.kt new file mode 100644 index 0000000..452f04d --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/NetModule.kt @@ -0,0 +1,45 @@ +package com.otus.dihomework.di + +import com.google.gson.GsonBuilder +import com.otus.dihomework.common.data.ProductApiService +import dagger.Module +import dagger.Provides +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +@Module +class NetModule { + + @Singleton + @Provides + fun retrofit(okHttpClient: OkHttpClient): Retrofit { + return Retrofit.Builder().baseUrl("https://otus-android.github.io/").client(okHttpClient) + .addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())).build() + } + + @Singleton + @Provides + fun okHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient { + return OkHttpClient.Builder() + .addInterceptor(httpLoggingInterceptor) + .connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS) + .build() + } + + @Provides + fun httpLoggingInterceptor(): HttpLoggingInterceptor { + return HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + } + + @Singleton + @Provides + fun productApiService(retrofit: Retrofit): ProductApiService { + return retrofit.create(ProductApiService::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/ProductDependencies.kt b/app/src/main/java/com/otus/dihomework/di/ProductDependencies.kt new file mode 100644 index 0000000..82a7253 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/ProductDependencies.kt @@ -0,0 +1,14 @@ +package com.otus.dihomework.di + +import com.otus.dihomework.common.domain_api.ConsumeProductsUseCase +import com.otus.dihomework.common.domain_api.ToggleFavoriteUseCase +import com.otus.dihomework.common.util.PriceFormatter +import com.otus.dihomework.features.products.ProductsStateFactory + +interface ProductDependencies: Dependencies { + + fun consumeProductsUseCase(): ConsumeProductsUseCase + fun toggleFavoriteUseCase(): ToggleFavoriteUseCase + fun priceFormatter(): PriceFormatter + fun productsStateFactory(): ProductsStateFactory +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/ProductsComponent.kt b/app/src/main/java/com/otus/dihomework/di/ProductsComponent.kt new file mode 100644 index 0000000..7d2cee8 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/ProductsComponent.kt @@ -0,0 +1,16 @@ +package com.otus.dihomework.di + +import com.otus.dihomework.common.di.FeatureScope +import com.otus.dihomework.features.products.ProductsViewModelFactory +import dagger.Component + +@FeatureScope +@Component(dependencies = [ProductDependencies::class]) +interface ProductsComponent { + fun viewModelFactory(): ProductsViewModelFactory + + @Component.Factory + interface Factory { + fun create(dependencies: ProductDependencies): ProductsComponent + } +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/RepositoryModule.kt b/app/src/main/java/com/otus/dihomework/di/RepositoryModule.kt new file mode 100644 index 0000000..ea77ae5 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/RepositoryModule.kt @@ -0,0 +1,31 @@ +package com.otus.dihomework.di + +import android.content.Context +import com.otus.dihomework.common.data.FavoritesRepositoryImpl +import com.otus.dihomework.common.data.ProductApiService +import com.otus.dihomework.common.data.ProductDomainMapper +import com.otus.dihomework.common.data.ProductRemoteDataSource +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.Module +import dagger.Provides + +@Module +class RepositoryModule { + + @Provides + fun getProductRepository( + remoteDataSource: ProductRemoteDataSource, + mapper: ProductDomainMapper + ): ProductRepository = ProductRepositoryImpl(remoteDataSource, mapper) + + @Provides + fun getFavoritesRepository(context: Context): FavoritesRepository = + FavoritesRepositoryImpl(context) + + @Provides + fun productRemoteDataSource( + apiService: ProductApiService, + ): ProductRemoteDataSource = ProductRemoteDataSource(apiService) +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/SubcomponentsModule.kt b/app/src/main/java/com/otus/dihomework/di/SubcomponentsModule.kt new file mode 100644 index 0000000..b267b85 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/SubcomponentsModule.kt @@ -0,0 +1,6 @@ +package com.otus.dihomework.di + +import dagger.Module + +@Module(subcomponents = [FavoritesComponent::class]) +class SubcomponentsModule \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/UtilsModule.kt b/app/src/main/java/com/otus/dihomework/di/UtilsModule.kt new file mode 100644 index 0000000..f0f2e99 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/UtilsModule.kt @@ -0,0 +1,12 @@ +package com.otus.dihomework.di + +import com.otus.dihomework.common.util.PriceFormatter +import dagger.Module +import dagger.Provides + +@Module +class UtilsModule { + + @Provides + fun getPriceFormatter(): PriceFormatter = PriceFormatter() +} \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/di/scopes/ActivityScope.kt b/app/src/main/java/com/otus/dihomework/di/scopes/ActivityScope.kt new file mode 100644 index 0000000..3045605 --- /dev/null +++ b/app/src/main/java/com/otus/dihomework/di/scopes/ActivityScope.kt @@ -0,0 +1,7 @@ +package com.otus.dihomework.di.scopes + +import javax.inject.Scope + +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class ActivityScope \ No newline at end of file diff --git a/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesStateFactory.kt b/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesStateFactory.kt index d2569a4..56c6c82 100644 --- a/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesStateFactory.kt +++ b/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesStateFactory.kt @@ -1,10 +1,12 @@ package com.otus.dihomework.features.favorites -import com.otus.dihomework.ServiceLocator import com.otus.dihomework.common.domain_api.ProductWithFavorite +import com.otus.dihomework.common.util.PriceFormatter +import javax.inject.Inject -class FavoritesStateFactory() { - private val priceFormatter = ServiceLocator.getPriceFormatter() +class FavoritesStateFactory @Inject constructor( + private val priceFormatter: PriceFormatter +) { fun create(favorites: List): List { return favorites.map { createFavoriteState(it) } diff --git a/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesViewModel.kt b/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesViewModel.kt index 9d41c4b..0f96b04 100644 --- a/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesViewModel.kt +++ b/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesViewModel.kt @@ -2,7 +2,8 @@ package com.otus.dihomework.features.favorites import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.otus.dihomework.ServiceLocator +import com.otus.dihomework.common.domain_api.ConsumeFavoritesUseCase +import com.otus.dihomework.common.domain_api.ToggleFavoriteUseCase import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -12,12 +13,13 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import javax.inject.Inject -class FavoritesViewModel() : ViewModel() { - - private val consumeFavoritesUseCase = ServiceLocator.getConsumeFavoritesUseCase() - private val toggleFavoriteUseCase = ServiceLocator.getToggleFavoriteUseCase() - private val favoritesStateFactory = ServiceLocator.getFavoritesStateFactory() +class FavoritesViewModel @Inject constructor( + private val consumeFavoritesUseCase: ConsumeFavoritesUseCase, + private val toggleFavoriteUseCase: ToggleFavoriteUseCase, + private val favoritesStateFactory: FavoritesStateFactory +) : ViewModel() { private val _state = MutableStateFlow(FavoritesScreenState()) val state: StateFlow = _state.asStateFlow() diff --git a/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesViewModelFactory.kt b/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesViewModelFactory.kt index a30f8fc..9558eb6 100644 --- a/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesViewModelFactory.kt +++ b/app/src/main/java/com/otus/dihomework/features/favorites/FavoritesViewModelFactory.kt @@ -2,12 +2,23 @@ package com.otus.dihomework.features.favorites import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.otus.dihomework.common.domain_api.ConsumeFavoritesUseCase +import com.otus.dihomework.common.domain_api.ToggleFavoriteUseCase +import javax.inject.Inject -class FavoritesViewModelFactory() : ViewModelProvider.Factory { +class FavoritesViewModelFactory @Inject constructor( + private val consumeFavoritesUseCase: ConsumeFavoritesUseCase, + private val toggleFavoriteUseCase: ToggleFavoriteUseCase, + private val favoritesStateFactory: FavoritesStateFactory +) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { require(modelClass == FavoritesViewModel::class.java) - return FavoritesViewModel() as T + return FavoritesViewModel( + consumeFavoritesUseCase = consumeFavoritesUseCase, + toggleFavoriteUseCase = toggleFavoriteUseCase, + favoritesStateFactory = favoritesStateFactory + ) as T } } diff --git a/app/src/main/java/com/otus/dihomework/features/favorites/ui/FavoritesScreen.kt b/app/src/main/java/com/otus/dihomework/features/favorites/ui/FavoritesScreen.kt index 6c9c79b..b147bf3 100644 --- a/app/src/main/java/com/otus/dihomework/features/favorites/ui/FavoritesScreen.kt +++ b/app/src/main/java/com/otus/dihomework/features/favorites/ui/FavoritesScreen.kt @@ -14,20 +14,27 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.otus.dihomework.R +import com.otus.dihomework.di.AppComponent +import com.otus.dihomework.di.DependenciesProvider import com.otus.dihomework.features.favorites.FavoritesScreenState import com.otus.dihomework.features.favorites.FavoritesViewModel -import com.otus.dihomework.features.favorites.FavoritesViewModelFactory @Composable fun FavoritesScreenContent( modifier: Modifier = Modifier ) { + val context = LocalContext.current + val appComponent = + (context.applicationContext as DependenciesProvider).getDependencies() as AppComponent + val favoritesComponent = appComponent.favoritesComponent().create() + val viewModel: FavoritesViewModel = viewModel( - factory = FavoritesViewModelFactory() + factory = favoritesComponent.viewModelFactory() ) val state by viewModel.state.collectAsState() diff --git a/app/src/main/java/com/otus/dihomework/features/products/ProductsStateFactory.kt b/app/src/main/java/com/otus/dihomework/features/products/ProductsStateFactory.kt index d78f6e7..cea5b8d 100644 --- a/app/src/main/java/com/otus/dihomework/features/products/ProductsStateFactory.kt +++ b/app/src/main/java/com/otus/dihomework/features/products/ProductsStateFactory.kt @@ -1,10 +1,12 @@ package com.otus.dihomework.features.products -import com.otus.dihomework.ServiceLocator import com.otus.dihomework.common.domain_api.ProductWithFavorite +import com.otus.dihomework.common.util.PriceFormatter +import javax.inject.Inject -class ProductsStateFactory() { - private val priceFormatter = ServiceLocator.getPriceFormatter() +class ProductsStateFactory @Inject constructor( + private val priceFormatter: PriceFormatter +) { fun create(products: List): List { return products diff --git a/app/src/main/java/com/otus/dihomework/features/products/ProductsViewModel.kt b/app/src/main/java/com/otus/dihomework/features/products/ProductsViewModel.kt index ad2ce7d..dcca307 100644 --- a/app/src/main/java/com/otus/dihomework/features/products/ProductsViewModel.kt +++ b/app/src/main/java/com/otus/dihomework/features/products/ProductsViewModel.kt @@ -2,7 +2,8 @@ package com.otus.dihomework.features.products import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.otus.dihomework.ServiceLocator +import com.otus.dihomework.common.domain_api.ConsumeProductsUseCase +import com.otus.dihomework.common.domain_api.ToggleFavoriteUseCase import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -12,12 +13,13 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import javax.inject.Inject -class ProductsViewModel() : ViewModel() { - - private val consumeProductsUseCase = ServiceLocator.getConsumeProductsUseCase() - private val toggleFavoriteUseCase = ServiceLocator.getToggleFavoriteUseCase() - private val productsStateFactory = ServiceLocator.getProductsStateFactory() +class ProductsViewModel @Inject constructor( + private val consumeProductsUseCase: ConsumeProductsUseCase, + private val toggleFavoriteUseCase: ToggleFavoriteUseCase, + private val productsStateFactory: ProductsStateFactory, +) : ViewModel() { private val _state = MutableStateFlow(ProductsScreenState()) val state: StateFlow = _state.asStateFlow() diff --git a/app/src/main/java/com/otus/dihomework/features/products/ProductsViewModelFactory.kt b/app/src/main/java/com/otus/dihomework/features/products/ProductsViewModelFactory.kt index 82defc9..7c9abc0 100644 --- a/app/src/main/java/com/otus/dihomework/features/products/ProductsViewModelFactory.kt +++ b/app/src/main/java/com/otus/dihomework/features/products/ProductsViewModelFactory.kt @@ -2,12 +2,23 @@ package com.otus.dihomework.features.products import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.otus.dihomework.common.domain_api.ConsumeProductsUseCase +import com.otus.dihomework.common.domain_api.ToggleFavoriteUseCase +import javax.inject.Inject -class ProductsViewModelFactory() : ViewModelProvider.Factory { +class ProductsViewModelFactory @Inject constructor( + private val consumeProductsUseCase: ConsumeProductsUseCase, + private val toggleFavoriteUseCase: ToggleFavoriteUseCase, + private val productsStateFactory: ProductsStateFactory +) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { require(modelClass == ProductsViewModel::class.java) - return ProductsViewModel() as T + return ProductsViewModel( + consumeProductsUseCase = consumeProductsUseCase, + toggleFavoriteUseCase = toggleFavoriteUseCase, + productsStateFactory = productsStateFactory, + ) as T } } diff --git a/app/src/main/java/com/otus/dihomework/features/products/ui/ProductsScreen.kt b/app/src/main/java/com/otus/dihomework/features/products/ui/ProductsScreen.kt index 0072b10..d160721 100644 --- a/app/src/main/java/com/otus/dihomework/features/products/ui/ProductsScreen.kt +++ b/app/src/main/java/com/otus/dihomework/features/products/ui/ProductsScreen.kt @@ -15,18 +15,25 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import com.otus.dihomework.di.DaggerProductsComponent +import com.otus.dihomework.di.ProductDependencies +import com.otus.dihomework.di.findDependencies import com.otus.dihomework.features.products.ProductsScreenState import com.otus.dihomework.features.products.ProductsViewModel -import com.otus.dihomework.features.products.ProductsViewModelFactory @Composable fun ProductsScreenContent( modifier: Modifier = Modifier ) { + val context = LocalContext.current + val dependencies = context.findDependencies() + val productsComponent = DaggerProductsComponent.factory().create(dependencies) + val viewModel: ProductsViewModel = viewModel( - factory = ProductsViewModelFactory() + factory = productsComponent.viewModelFactory() ) val state by viewModel.state.collectAsState()