This moves the responsibility for joining the UserData and the NewsResources to UserNewsResourceRepository. This way, the work can be done once and shared with all consumers in a SharedFlow, rather than having each consumer perform the join itself by invoking the UseCase.pull/595/head
parent
9ee2acf327
commit
bd450099fb
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.domain
|
||||
|
||||
import com.google.samples.apps.nowinandroid.core.data.repository.NewsRepository
|
||||
import com.google.samples.apps.nowinandroid.core.data.repository.NewsResourceQuery
|
||||
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
|
||||
import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource
|
||||
import com.google.samples.apps.nowinandroid.core.domain.model.mapToUserNewsResources
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.UserData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filterNot
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A use case responsible for obtaining news resources with their associated bookmarked (also known
|
||||
* as "saved") state.
|
||||
*/
|
||||
class GetUserNewsResourcesUseCase @Inject constructor(
|
||||
private val newsRepository: NewsRepository,
|
||||
private val userDataRepository: UserDataRepository,
|
||||
) {
|
||||
/**
|
||||
* Returns a list of UserNewsResources which match the supplied set of topic ids.
|
||||
*
|
||||
* @param query - Summary of query parameters for news resources.
|
||||
*/
|
||||
operator fun invoke(
|
||||
query: NewsResourceQuery = NewsResourceQuery(),
|
||||
): Flow<List<UserNewsResource>> =
|
||||
newsRepository.getNewsResources(
|
||||
query = query,
|
||||
).mapToUserNewsResources(userDataRepository.userData)
|
||||
}
|
||||
|
||||
private fun Flow<List<NewsResource>>.mapToUserNewsResources(
|
||||
userDataStream: Flow<UserData>,
|
||||
): Flow<List<UserNewsResource>> =
|
||||
filterNot { it.isEmpty() }
|
||||
.combine(userDataStream) { newsResources, userData ->
|
||||
newsResources.mapToUserNewsResources(userData)
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2023 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.domain.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import javax.inject.Qualifier
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Qualifier
|
||||
annotation class ApplicationScope
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
object CoroutinesScopesModule {
|
||||
|
||||
@Singleton
|
||||
@ApplicationScope
|
||||
@Provides
|
||||
fun providesCoroutineScope(): CoroutineScope =
|
||||
CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2023 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.domain.di
|
||||
|
||||
import com.google.samples.apps.nowinandroid.core.domain.repository.CompositeUserNewsResourceRepository
|
||||
import com.google.samples.apps.nowinandroid.core.domain.repository.UserNewsResourceRepository
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface UserNewsResourceRepositoryModule {
|
||||
@Binds
|
||||
fun bindsUserNewsResourceRepository(
|
||||
userDataRepository: CompositeUserNewsResourceRepository,
|
||||
): UserNewsResourceRepository
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2023 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.domain.repository
|
||||
|
||||
import com.google.samples.apps.nowinandroid.core.data.repository.NewsRepository
|
||||
import com.google.samples.apps.nowinandroid.core.data.repository.NewsResourceQuery
|
||||
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
|
||||
import com.google.samples.apps.nowinandroid.core.domain.di.ApplicationScope
|
||||
import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource
|
||||
import com.google.samples.apps.nowinandroid.core.domain.model.mapToUserNewsResources
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
|
||||
import com.google.samples.apps.nowinandroid.core.model.data.UserData
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filterNot
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Implements a [UserNewsResourceRepository] by combining a [NewsRepository] with a
|
||||
* [UserDataRepository].
|
||||
*/
|
||||
class CompositeUserNewsResourceRepository @Inject constructor(
|
||||
@ApplicationScope private val coroutineScope: CoroutineScope,
|
||||
val newsRepository: NewsRepository,
|
||||
val userDataRepository: UserDataRepository,
|
||||
) : UserNewsResourceRepository {
|
||||
|
||||
private val userNewsResources =
|
||||
newsRepository.getNewsResources().mapToUserNewsResources(userDataRepository.userData)
|
||||
.shareIn(coroutineScope, started = WhileSubscribed(5000), replay = 1)
|
||||
|
||||
override fun getUserNewsResources(
|
||||
query: NewsResourceQuery,
|
||||
): Flow<List<UserNewsResource>> =
|
||||
userNewsResources.map { resources ->
|
||||
resources.filter { resource ->
|
||||
query.filterTopicIds?.let { topics -> resource.hasTopic(topics) } ?: true &&
|
||||
query.filterNewsIds?.contains(resource.id) ?: true
|
||||
}
|
||||
}
|
||||
|
||||
override fun getUserNewsResourcesForFollowedTopics(): Flow<List<UserNewsResource>> =
|
||||
userDataRepository.userData.flatMapLatest { getUserNewsResources(NewsResourceQuery(filterTopicIds = it.followedTopics)) }
|
||||
|
||||
private fun UserNewsResource.hasTopic(filterTopicIds: Set<String>) =
|
||||
followableTopics.any { filterTopicIds.contains(it.topic.id) }
|
||||
}
|
||||
|
||||
private fun Flow<List<NewsResource>>.mapToUserNewsResources(
|
||||
userDataStream: Flow<UserData>,
|
||||
): Flow<List<UserNewsResource>> =
|
||||
filterNot { it.isEmpty() }
|
||||
.combine(userDataStream) { newsResources, userData ->
|
||||
newsResources.mapToUserNewsResources(userData)
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2023 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.domain.repository
|
||||
|
||||
import com.google.samples.apps.nowinandroid.core.data.repository.NewsResourceQuery
|
||||
import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Data layer implementation for [UserNewsResource]
|
||||
*/
|
||||
interface UserNewsResourceRepository {
|
||||
/**
|
||||
* Returns available news resources as a stream.
|
||||
*/
|
||||
fun getUserNewsResources(
|
||||
query: NewsResourceQuery = NewsResourceQuery(
|
||||
filterTopicIds = null,
|
||||
filterNewsIds = null,
|
||||
),
|
||||
): Flow<List<UserNewsResource>>
|
||||
|
||||
/**
|
||||
* Returns available news resources for the user's followed topics as a stream.
|
||||
*/
|
||||
fun getUserNewsResourcesForFollowedTopics(): Flow<List<UserNewsResource>>
|
||||
}
|
Loading…
Reference in new issue