m

    miqbaldc

    6 months ago
    Does it possible to provide dependency w/o direct module dependency? Hilt: 2.40.5 AGP: 7.1.2 Gradle: 7.4 e.g:
    :presentation -> :domain <- :data
    // in :domain module
    class class AnalyticsUseCase @Inject constructor(
        private val repository: AnalyticsRepository,
    ) {
       // omitted
    }
    // in :data module
    
    @InstallIn(SingletonComponent::class)
    @Module
    interface BindAnalyticsModule {
        @get:[Binds]
        val AnalyticsRepositoryImpl.analyticsRepo: AnalyticsRepository
    }
    
    internal const val DEFAULT_DATASTORE = "_datastore"
    
    @InstallIn(SingletonComponent::class)
    @Module
    object ProvideAnalyticsModule {
        @Singleton
        @Provides
        fun provideDataStorePreference(
            @ApplicationContext context: Context,
        ): DataStore<Preferences> {
            val packageName = context.packageName
            val dataStoreName = "$packageName$DEFAULT_DATASTORE"
            return PreferenceDataStoreFactory.create(
                produceFile = { context.preferencesDataStoreFile(dataStoreName) }
            )
        }
    }
    // in :presentation module
    
    @HiltViewModel
    class DashboardViewModel @Inject constructor(
        private val analyticsUseCase: AnalyticsUseCase,
        private val dataStore: DataStore<Preferences>,
    )
    :presentation
    has no dependency to
    :data
    in
    presentation/build.gradle
    This seems not possible especially since depends on
    hilt-android
    , after trying it out
    will try this with
    hilt-core
    (for dependency that not requires android related)
    Javier

    Javier

    6 months ago
    it is possible
    m

    miqbaldc

    6 months ago
    in my part, especially when depends on both
    hilt-android
    &
    datastore-preferences
    (w/o
    -core
    suffix, has android dependencies) fails to compile. Any references or samples to lookup first, if there’s any?
    Javier

    Javier

    6 months ago
    data is being added as dependency in app or the di module?
    m

    miqbaldc

    6 months ago
    currently still using the former (added as dependency in app) as failed to compile when doing the later (added as deps in di module)
    Javier

    Javier

    6 months ago
    is it open source?
    m

    miqbaldc

    6 months ago
    unfortunately no 🙏
    Javier

    Javier

    6 months ago
    if you create a repro I can try to fix it
    m

    miqbaldc

    6 months ago
    hopefully, will do this weekend!
    https://github.com/mochadwi/hilt-bridge-module hopefully this minimal project makes senses, lmk if there’s something I can do to help 🙏
    Javier

    Javier

    6 months ago
    can you add the presentation module with hilt and viewmodel dependencies?
    m

    miqbaldc

    6 months ago
    updated
    Javier

    Javier

    6 months ago
    I can't see the presentation module, you want that the app and the presentation module would be the same?
    in that case you can't isolate data for presentation, app module needs to know everything
    the only way is: app adds as dependencies the three modules presentation -> domain <- data
    merging presentation and app into one implies presentation needs to know everything
    m

    miqbaldc

    6 months ago
    wait, I’m renaming the module from
    legacy
    to
    presentation
    now
    cmiiw, did you mean we need to have a dedicated
    presentation
    module? e.g:
    | domain // kotlin library
    | data:analytics // android library
    | presentation // contains dagger moduler provider etc, android library
    | app // android application
    Javier

    Javier

    6 months ago
    exactly
    providers can be in data or in app
    presentation probably doesn't need providers since they are viewmodels so the viewmodel annotation is enough
    I mean, presentation only needs @Provides if it has to provide some presentation dependency, which is not usual because you usually provides third party dependencies which would be in data, generally. There can be exceptions tho
    i.e. ktor or retrofit client, room and so on, they are in data
    m

    miqbaldc

    6 months ago
    I seee, :til: :thank-you:. Previously we though the
    app
    modules behaves as
    presentation
    app adds as dependencies the three modules
    This part seems inevitable right? I tho’ we can prevent our application to have import from
    data
    layer
    Javier

    Javier

    6 months ago
    you can't prevent that
    but at same time you can organice your modules so you app module is almost empty (only having the application file with hilt annotation and the manifest
    m

    miqbaldc

    6 months ago
    this is also applicable for dynamic feature I presume? as our original codebase using dynamic feature and due to its limitation us frequently provide dependencies inside dynamic feature module as well
    Javier

    Javier

    6 months ago
    I only mounted the setup for dynamic feature one time, but before hilt even exists. I don't like how it works because the dependencies are totally (or was) inversed. If that doesn't change, I wouldn't use it
    and Hilt doesnt work very well with dynamic features
    you have to do hacks/workarounds
    m

    miqbaldc

    6 months ago
    Thank you for the guidance, there’s might be a few questions in mind, one of them are following: Does it also mean
    :app
    needs to depends on different data-layer implementation
    :data:<sub module>
    , e.g:
    :data // common or core
    :data:analytics // implementation details of analytics tracker
    dependency:
    :presentation -> :domain <- :data <- :data:analytics // like this, I presume?
    :presentation <- :data:analytics // avoid doing this?
    Based on your suggestions here (cmiiw):
    :app -> :domain
    :app -> :data
    :app -> :data:analytics
    :app -> :presentation
    Javier

    Javier

    6 months ago
    it depends
    if data modules are adding as dependency other data modules using api, no, if not, yes
    m

    miqbaldc

    6 months ago
    to summarize, the
    :app
    required to add everything (
    :data:<submodule(s)>
    ) as dependencies (using
    api
    ?) even tho’ there’s no direct import / usage in
    :app
    as long all of the
    @Provider
    (for concrete impl.) are exist inside
    :data:<submodule>
    (and
    :data
    ) in order for dagger to compiled properly? cmiiw
    let me also confirm this statement here:
    if data modules are adding as dependency other data modules using api,
    does this means (see image attachment by order): 1️⃣ 2️⃣ 3️⃣
    Javier

    Javier

    6 months ago
    app —impl—> analytics —api—> data
    app should not have api in its gradle file, because no module adds app as dependency
    m

    miqbaldc

    5 months ago
    another issues I’ve found: e.g:
    // interface in :data (a kotlin library)
    interface DataSource {}
    
    // and injected by
    class SomeClassDataStore @Inject constructor(private val dataSource: DataSource)
    // concrete implementation & DI provider in :data:sharedprefs
    // (is an android library)
    class SharedPrefsManager : DataSource {}
    
    @InstallIn(SingletonComponent::class)
    @Module
    interface BindSharedPrefsModule {
        @get:[Binds DataStorePreferences]
        val SharedPrefsManager.sharedPrefsManager: DataSource
    }
    as
    :data
    doesn’t have direct dependencies to
    :data:sharedprefs
    , meanwhile doing that will resulting in a cyclic dependencies
    is there any workaround for this that I might’ve missed? should we move the
    SomeClassDataStore
    to another modules’ that has dependencies on both:
    :data
    &
    :data:sharedprefs
    in this case?
    Javier

    Javier

    5 months ago
    probably yes
    but not sure what are you putting inside data and inside sharedPrefs
    what you app module is adding as dependencies?
    if it knows everything dagger should has no problems
    m

    miqbaldc

    5 months ago
    what you app module is adding as dependencies?
    // app/build.gradle
    
    implementation(project(":data"))
    implementation(project(":data:analytics"))
    implementation(project(":data:shared-preferences"))
    Does it possible to create a dagger bridge module instead? so the app module can depends on dagger bridge module only e.g:
    :app -> :dagger-bridge
    
    :dagger-bridge -> :data
    :dagger-bridge -> :data:sharedprefs
    :dagger-bridge -> :domain
    Javier

    Javier

    5 months ago