Skip to content
Permalink
Browse files

Migrate popular shows to Store

  • Loading branch information
chrisbanes committed Feb 16, 2020
1 parent 6e01108 commit c63d6eafb6215300ad721040f0610f0c02ccfd27
@@ -17,6 +17,7 @@
package app.tivi.data

import app.tivi.data.repositories.episodes.EpisodesModule
import app.tivi.data.repositories.popularshows.PopularShowsModule
import app.tivi.data.repositories.recommendedshows.RecommendedShowsModule
import app.tivi.data.repositories.relatedshows.RelatedShowsModule
import app.tivi.data.repositories.showimages.ShowsImagesModule
@@ -37,7 +38,8 @@ import kotlinx.coroutines.CoroutineScope
TrendingShowsModule::class,
WatchedShowsModule::class,
RecommendedShowsModule::class,
RelatedShowsModule::class
RelatedShowsModule::class,
PopularShowsModule::class
])
class DataModule {
@ForStore
@@ -27,8 +27,12 @@ import kotlinx.coroutines.flow.Flow
@Dao
abstract class PopularDao : PaginatedEntryDao<PopularShowEntry, PopularEntryWithShow>() {
@Transaction
@Query("SELECT * FROM popular_shows ORDER BY page, page_order LIMIT :count OFFSET :offset")
abstract fun entriesObservable(count: Int, offset: Int): Flow<List<PopularEntryWithShow>>
@Query("SELECT * FROM popular_shows WHERE page = :page ORDER BY page_order")
abstract fun entriesObservable(page: Int): Flow<List<PopularShowEntry>>

@Transaction
@Query("SELECT * FROM popular_shows ORDER BY page, page_order")
abstract fun entriesObservable(): Flow<List<PopularEntryWithShow>>

@Transaction
@Query("SELECT * FROM popular_shows ORDER BY page, page_order")
@@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.Flow
@Dao
abstract class TrendingDao : PaginatedEntryDao<TrendingShowEntry, TrendingEntryWithShow>() {
@Query("SELECT * FROM trending_shows WHERE page = :page ORDER BY watchers DESC, id ASC")
abstract fun entriesForPage(page: Int): Flow<List<TrendingShowEntry>>
abstract fun entriesObservable(page: Int): Flow<List<TrendingShowEntry>>

@Query("SELECT * FROM trending_shows ORDER BY page ASC, watchers DESC, id ASC LIMIT :count OFFSET :offset")
abstract fun entriesObservable(count: Int, offset: Int): Flow<List<TrendingEntryWithShow>>

This file was deleted.

This file was deleted.

This file was deleted.

@@ -30,10 +30,10 @@ import com.uwetrottmann.trakt5.services.Shows
import javax.inject.Inject
import javax.inject.Provider

class TraktPopularShowsDataSource @Inject constructor(
internal class TraktPopularShowsDataSource @Inject constructor(
private val showService: Provider<Shows>,
private val showMapper: TraktShowToTiviShow
) : PopularShowsDataSource {
) {
private val entryMapper = object : IndexedMapper<Show, PopularShowEntry> {
override suspend fun map(index: Int, from: Show): PopularShowEntry {
return PopularShowEntry(showId = 0, pageOrder = index, page = 0)
@@ -42,7 +42,7 @@ class TraktPopularShowsDataSource @Inject constructor(

private val resultsMapper = pairMapperOf(showMapper, entryMapper)

override suspend fun getPopularShows(
suspend operator fun invoke(
page: Int,
pageSize: Int
): Result<List<Pair<TiviShow, PopularShowEntry>>> {
@@ -0,0 +1,70 @@
/*
* Copyright 2020 Google LLC
*
* 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
*
* http://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 app.tivi.data.repositories.popularshows

import app.tivi.data.daos.PopularDao
import app.tivi.data.daos.TiviShowDao
import app.tivi.data.entities.PopularShowEntry
import app.tivi.data.entities.Success
import app.tivi.inject.ForStore
import com.dropbox.android.external.store4.Store
import com.dropbox.android.external.store4.StoreBuilder
import dagger.Module
import dagger.Provides
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineScope

typealias PopularShowsStore = Store<Int, List<PopularShowEntry>>

@Module
internal class PopularShowsModule {
@Provides
@Singleton
fun providePopularShowsStore(
traktPopularShows: TraktPopularShowsDataSource,
popularShowsDao: PopularDao,
showDao: TiviShowDao,
lastRequestStore: PopularShowsLastRequestStore,
@ForStore scope: CoroutineScope
): PopularShowsStore {
return StoreBuilder.fromNonFlow { page: Int ->
val response = traktPopularShows(page, 20)
if (page == 0 && response is Success) {
lastRequestStore.updateLastRequest()
}
response.getOrThrow()
}.persister(
reader = popularShowsDao::entriesObservable,
writer = { page, response ->
popularShowsDao.withTransaction {
val entries = response.map { (show, entry) ->
entry.copy(showId = showDao.getIdOrSavePlaceholder(show), page = page)
}
if (page == 0) {
// If we've requested page 0, remove any existing entries first
popularShowsDao.deleteAll()
popularShowsDao.insertAll(entries)
} else {
popularShowsDao.updatePage(page, entries)
}
}
},
delete = popularShowsDao::deletePage,
deleteAll = popularShowsDao::deleteAll
).scope(scope).build()
}
}
@@ -48,7 +48,7 @@ class TrendingShowsModule {
}
response.getOrThrow()
}.persister(
reader = trendingShowsDao::entriesForPage,
reader = trendingShowsDao::entriesObservable,
writer = { page, response ->
trendingShowsDao.withTransaction {
val entries = response.map { (show, entry) ->
@@ -16,32 +16,47 @@

package app.tivi.domain.interactors

import app.tivi.data.repositories.popularshows.PopularShowsRepository
import app.tivi.data.daos.PopularDao
import app.tivi.data.fetch
import app.tivi.data.fetchCollection
import app.tivi.data.repositories.popularshows.PopularShowsLastRequestStore
import app.tivi.data.repositories.popularshows.PopularShowsStore
import app.tivi.data.repositories.showimages.ShowImagesStore
import app.tivi.data.repositories.shows.ShowStore
import app.tivi.domain.Interactor
import app.tivi.domain.interactors.UpdatePopularShows.Params
import app.tivi.extensions.parallelForEach
import app.tivi.inject.ProcessLifetime
import app.tivi.util.AppCoroutineDispatchers
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.plus
import org.threeten.bp.Period

class UpdatePopularShows @Inject constructor(
private val popularShowsRepository: PopularShowsRepository,
private val popularShowStore: PopularShowsStore,
private val popularDao: PopularDao,
private val lastRequestStore: PopularShowsLastRequestStore,
private val showsStore: ShowStore,
private val showImagesStore: ShowImagesStore,
dispatchers: AppCoroutineDispatchers,
@ProcessLifetime val processScope: CoroutineScope
) : Interactor<Params>() {
override val scope: CoroutineScope = processScope + dispatchers.io

override suspend fun doWork(params: Params) {
when (params.page) {
Page.NEXT_PAGE -> {
popularShowsRepository.loadNextPage()
}
Page.REFRESH -> {
if (params.forceRefresh || popularShowsRepository.needUpdate()) {
popularShowsRepository.update()
}
}
val lastPage = popularDao.getLastPage()
val page = when {
lastPage != null && params.page == Page.NEXT_PAGE -> lastPage + 1
else -> 0
}

popularShowStore.fetchCollection(page, forceFresh = params.forceRefresh) {
// Refresh if our local data is over 7 days old
page == 0 && lastRequestStore.isRequestExpired(Period.ofDays(7))
}.parallelForEach {
showsStore.fetch(it.showId)
showImagesStore.fetchCollection(it.showId)
}
}

@@ -35,10 +35,10 @@ import org.threeten.bp.Duration

class UpdateTrendingShows @Inject constructor(
private val trendingShowsStore: TrendingShowsStore,
private val showsStore: ShowStore,
private val showImagesStore: ShowImagesStore,
private val trendingShowsDao: TrendingDao,
private val lastRequestStore: TrendingShowsLastRequestStore,
private val showsStore: ShowStore,
private val showImagesStore: ShowImagesStore,
dispatchers: AppCoroutineDispatchers,
@ProcessLifetime val processScope: CoroutineScope
) : Interactor<Params>() {

0 comments on commit c63d6ea

Please sign in to comment.
You can’t perform that action at this time.