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