Use koin in the data module

pull/2064/head
lihenggui 2 years ago
parent 5e219e0f8c
commit fd58187a88

@ -15,7 +15,7 @@
*/
plugins {
alias(libs.plugins.nowinandroid.kmp.library)
alias(libs.plugins.nowinandroid.kotlin.inject)
alias(libs.plugins.nowinandroid.di.koin)
alias(libs.plugins.nowinandroid.android.library.jacoco)
id("kotlinx-serialization")
}

@ -1,58 +0,0 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.data.di
import android.app.Application
import com.google.samples.apps.nowinandroid.core.data.util.ConnectivityManagerNetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneBroadcastMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import com.google.samples.apps.nowinandroid.core.di.AndroidApplicationComponent
import com.google.samples.apps.nowinandroid.core.di.CoroutineScopeComponent
import com.google.samples.apps.nowinandroid.core.di.Dispatcher
import com.google.samples.apps.nowinandroid.core.di.DispatchersComponent
import com.google.samples.apps.nowinandroid.core.di.NiaDispatchers.IO
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
@Component
abstract class AndroidPlatformDependentDataModule(
@Component val applicationComponent: AndroidApplicationComponent,
@Component val dispatchersComponent: DispatchersComponent,
@Component val coroutineScopeComponent: CoroutineScopeComponent,
) : PlatformDependentDataModule() {
abstract val application: Application
@Dispatcher(IO)
abstract val ioDispatcher: CoroutineDispatcher
abstract val coroutineScope: CoroutineScope
@Provides
override fun bindsNetworkMonitor(): NetworkMonitor {
return ConnectivityManagerNetworkMonitor(
application,
ioDispatcher,
)
}
@Provides
override fun bindsTimeZoneMonitor(): TimeZoneMonitor {
return TimeZoneBroadcastMonitor(application, coroutineScope, ioDispatcher)
}
}

@ -0,0 +1,33 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.data.di
import android.content.Context
import com.google.samples.apps.nowinandroid.core.data.util.ConnectivityManagerNetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import kotlinx.coroutines.CoroutineDispatcher
import org.koin.core.annotation.Singleton
@Singleton
actual class NetworkMonitorProvider(
private val context: Context,
private val dispatcher: CoroutineDispatcher,
) {
actual fun provideNetworkMonitor(): NetworkMonitor {
return ConnectivityManagerNetworkMonitor(context, dispatcher)
}
}

@ -0,0 +1,34 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.data.di
import android.content.Context
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneBroadcastMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import org.koin.core.annotation.Singleton
@Singleton
actual class TimeZoneMonitorProvider(
private val context: Context,
private val coroutineScope: CoroutineScope,
private val dispatcher: CoroutineDispatcher,
) {
actual fun provideTimeZoneMonitor(): TimeZoneMonitor =
TimeZoneBroadcastMonitor(context, coroutineScope, dispatcher)
}

@ -32,9 +32,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
import me.tatarka.inject.annotations.Inject
@Inject
internal class ConnectivityManagerNetworkMonitor(
private val context: Context,
private val ioDispatcher: CoroutineDispatcher,

@ -35,10 +35,8 @@ import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.shareIn
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toKotlinTimeZone
import me.tatarka.inject.annotations.Inject
import java.time.ZoneId
@Inject
internal class TimeZoneBroadcastMonitor(
private val context: Context,
appScope: CoroutineScope,

@ -16,44 +16,56 @@
package com.google.samples.apps.nowinandroid.core.data.di
import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.data.repository.DefaultRecentSearchRepository
import com.google.samples.apps.nowinandroid.core.data.repository.DefaultSearchContentsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.NewsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.OfflineFirstNewsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.OfflineFirstTopicsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.OfflineFirstUserDataRepository
import com.google.samples.apps.nowinandroid.core.data.repository.RecentSearchRepository
import com.google.samples.apps.nowinandroid.core.data.repository.SearchContentsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import org.koin.core.annotation.ComponentScan
import org.koin.core.annotation.Module
import org.koin.core.qualifier.named
import org.koin.dsl.module
import org.koin.ksp.generated.module
@Component
abstract class DataModule {
@Provides
fun bindsTopicRepository(
topicsRepository: OfflineFirstTopicsRepository,
): TopicsRepository = topicsRepository
internal val repositoryModule = module {
single { OfflineFirstTopicsRepository(get(), get()) }
single { OfflineFirstNewsRepository(get(), get(), get(), get(), get()) }
single { OfflineFirstUserDataRepository(get(), get()) }
single { DefaultRecentSearchRepository(get()) }
single {
DefaultSearchContentsRepository(
get(),
get(),
get(),
get(),
get(named("IoDispatcher")),
)
}
single { CompositeUserNewsResourceRepository(get(), get()) }
}
@Provides
fun bindsNewsResourceRepository(
newsRepository: OfflineFirstNewsRepository,
): NewsRepository = newsRepository
internal val networkMonitorModule = module {
single {
val networkMonitorProvider: NetworkMonitorProvider = get()
networkMonitorProvider.provideNetworkMonitor()
}
}
@Provides
fun bindsUserDataRepository(
userDataRepository: OfflineFirstUserDataRepository,
): UserDataRepository = userDataRepository
internal val timeZoneMonitorProviderModule = module {
single {
val timeZoneMonitorProvider: TimeZoneMonitorProvider = get()
timeZoneMonitorProvider.provideTimeZoneMonitor()
}
}
@Provides
fun bindsRecentSearchRepository(
recentSearchRepository: DefaultRecentSearchRepository,
): RecentSearchRepository = recentSearchRepository
val dataModule = listOf(
DataModule().module,
repositoryModule,
networkMonitorModule,
timeZoneMonitorProviderModule,
)
@Provides
fun bindsSearchContentsRepository(
searchContentsRepository: DefaultSearchContentsRepository,
): SearchContentsRepository = searchContentsRepository
}
@Module
@ComponentScan
class DataModule

@ -1,5 +1,5 @@
/*
* Copyright 2023 The Android Open Source Project
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,15 +16,8 @@
package com.google.samples.apps.nowinandroid.core.data.di
import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
@Component
abstract class UserNewsResourceRepositoryModule {
@Provides
fun bindsUserNewsResourceRepository(
userDataRepository: CompositeUserNewsResourceRepository,
): UserNewsResourceRepository = userDataRepository
expect class NetworkMonitorProvider {
fun provideNetworkMonitor(): NetworkMonitor
}

@ -16,14 +16,8 @@
package com.google.samples.apps.nowinandroid.core.data.di
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import me.tatarka.inject.annotations.Provides
abstract class PlatformDependentDataModule {
@Provides
abstract fun bindsNetworkMonitor(): NetworkMonitor
@Provides
abstract fun bindsTimeZoneMonitor(): TimeZoneMonitor
expect class TimeZoneMonitorProvider {
fun provideTimeZoneMonitor(): TimeZoneMonitor
}

@ -25,14 +25,12 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import me.tatarka.inject.annotations.Inject
/**
* Implements a [UserNewsResourceRepository] by combining a [NewsRepository] with a
* [UserDataRepository].
*/
@OptIn(ExperimentalCoroutinesApi::class)
@Inject
class CompositeUserNewsResourceRepository(
val newsRepository: NewsRepository,
val userDataRepository: UserDataRepository,

@ -23,9 +23,7 @@ import com.google.samples.apps.nowinandroid.core.database.model.RecentSearchQuer
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.datetime.Clock
import me.tatarka.inject.annotations.Inject
@Inject
class DefaultRecentSearchRepository(
private val recentSearchQueryDao: RecentSearchQueryDao,
) : RecentSearchRepository {

@ -35,10 +35,8 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.withContext
import me.tatarka.inject.annotations.Inject
@OptIn(ExperimentalCoroutinesApi::class)
@Inject
class DefaultSearchContentsRepository(
private val newsResourceDao: NewsResourceDao,
private val newsResourceFtsDao: NewsResourceFtsDao,

@ -35,7 +35,6 @@ import com.google.samples.apps.nowinandroid.core.notifications.Notifier
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import me.tatarka.inject.annotations.Inject
// Heuristic value to optimize for serialization and deserialization cost on client and server
// for each news resource batch.
@ -45,7 +44,6 @@ private const val SYNC_BATCH_SIZE = 40
* Disk storage backed implementation of the [NewsRepository].
* Reads are exclusively from local storage to support offline access.
*/
@Inject
class OfflineFirstNewsRepository(
private val niaPreferencesDataSource: NiaPreferencesDataSource,
private val newsResourceDao: NewsResourceDaoInterface,

@ -28,13 +28,11 @@ import com.google.samples.apps.nowinandroid.core.network.NiaNetworkDataSource
import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import me.tatarka.inject.annotations.Inject
/**
* Disk storage backed implementation of the [TopicsRepository].
* Reads are exclusively from local storage to support offline access.
*/
@Inject
class OfflineFirstTopicsRepository(
private val topicDao: TopicDaoInterface,
private val network: NiaNetworkDataSource,

@ -22,9 +22,7 @@ import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig
import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand
import com.google.samples.apps.nowinandroid.core.model.data.UserData
import kotlinx.coroutines.flow.Flow
import me.tatarka.inject.annotations.Inject
@Inject
class OfflineFirstUserDataRepository(
private val niaPreferencesDataSource: NiaPreferencesDataSource,
private val analyticsHelper: AnalyticsHelper,

@ -0,0 +1,30 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.data.di
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import org.koin.core.annotation.Singleton
@Singleton
actual class NetworkMonitorProvider {
actual fun provideNetworkMonitor(): NetworkMonitor = object : NetworkMonitor {
override val isOnline: Flow<Boolean>
get() = flowOf(true)
}
}

@ -16,33 +16,16 @@
package com.google.samples.apps.nowinandroid.core.data.di
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.datetime.TimeZone
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import org.koin.core.annotation.Singleton
/**
* JVM module that provides platform dependent data
* Leave empty for now
*/
@Component
abstract class JvmPlatformDependentDataModule : PlatformDependentDataModule() {
@Provides
override fun bindsNetworkMonitor(): NetworkMonitor {
return object : NetworkMonitor {
override val isOnline: Flow<Boolean>
get() = flowOf(true)
}
}
@Provides
override fun bindsTimeZoneMonitor(): TimeZoneMonitor {
return object : TimeZoneMonitor {
override val currentTimeZone: Flow<TimeZone>
get() = flowOf(TimeZone.UTC)
}
@Singleton
actual class TimeZoneMonitorProvider {
actual fun provideTimeZoneMonitor(): TimeZoneMonitor = object : TimeZoneMonitor {
override val currentTimeZone: Flow<TimeZone>
get() = flowOf(TimeZone.UTC)
}
}

@ -0,0 +1,30 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.data.di
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import org.koin.core.annotation.Singleton
@Singleton
actual class NetworkMonitorProvider {
actual fun provideNetworkMonitor(): NetworkMonitor = object : NetworkMonitor {
override val isOnline: Flow<Boolean>
get() = flowOf(true)
}
}

@ -16,33 +16,16 @@
package com.google.samples.apps.nowinandroid.core.data.di
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.datetime.TimeZone
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import org.koin.core.annotation.Singleton
/**
* Native module that provides platform dependent data
* Leave empty for now
*/
@Component
abstract class NativePlatformDependentDataModule : PlatformDependentDataModule() {
@Provides
override fun bindsNetworkMonitor(): NetworkMonitor {
return object : NetworkMonitor {
override val isOnline: Flow<Boolean>
get() = flowOf(true)
}
}
@Provides
override fun bindsTimeZoneMonitor(): TimeZoneMonitor {
return object : TimeZoneMonitor {
override val currentTimeZone: Flow<TimeZone>
get() = flowOf(TimeZone.UTC)
}
@Singleton
actual class TimeZoneMonitorProvider {
actual fun provideTimeZoneMonitor(): TimeZoneMonitor = object : TimeZoneMonitor {
override val currentTimeZone: Flow<TimeZone>
get() = flowOf(TimeZone.UTC)
}
}
Loading…
Cancel
Save