Skip to content

Commit

Permalink
⚡ background data refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
jforatier committed Oct 14, 2023
1 parent b008dd0 commit 5e2a842
Show file tree
Hide file tree
Showing 16 changed files with 332 additions and 183 deletions.
4 changes: 4 additions & 0 deletions app/src/main/java/fr/boitakub/bogadex/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.android.components.ActivityComponent
import fr.boitakub.bogadex.WorkManagerScheduler.refreshUpdateExistingBoardGameWork
import fr.boitakub.bogadex.WorkManagerScheduler.upsetMissingBoardGame
import fr.boitakub.bogadex.boardgame.BoardGameCollectionRepository
import fr.boitakub.bogadex.boardgame.ui.BoardGameCollectionNavigation
import fr.boitakub.bogadex.boardgame.ui.BoardGameCollectionViewModel
Expand Down Expand Up @@ -74,6 +76,8 @@ class MainActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
upsetMissingBoardGame(this)
refreshUpdateExistingBoardGameWork(this)

setContent {
val settingsState by userSettingsFlow.collectAsStateWithLifecycle(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2022, Boitakub
* Copyright (c) 2021-2023, Boitakub
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand All @@ -26,59 +26,52 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package fr.boitakub.bogadex.boardgame
package fr.boitakub.bogadex

import android.content.Context
import android.util.Log
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.tickaroo.tikxml.TikXml
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import fr.boitakub.bgg.client.BggGameInfoResult
import fr.boitakub.bgg.client.BggService
import fr.boitakub.bogadex.boardgame.mapper.BoardGameMapper
import fr.boitakub.bogadex.boardgame.BoardGameDao
import fr.boitakub.bogadex.boardgame.work.scheduleRetrieveMissingBoardGameWork
import kotlinx.coroutines.CancellationException
import okio.buffer
import okio.sink
import java.io.File

@HiltWorker
class UpdateBoardGameIntentWorker @AssistedInject constructor(
class UpdateExistingBoardGameWork @AssistedInject constructor(
@Assisted val context: Context,
@Assisted val workerParams: WorkerParameters,
val service: BggService,
val database: BoardGameDao,
val mapper: BoardGameMapper
) : CoroutineWorker(context, workerParams) {

companion object {
const val MAX_GAME_TO_REFRESH_PER_CYCLE = 30
}

override suspend fun doWork(): Result {
if (runAttemptCount > 2) {
if (runAttemptCount > 4) {
return Result.failure()
}
Log.d("UpdateExistingBoardGameWork", "Starting job")

val result = try {
val bggId = inputData.getString("bggId")
val networkResult = service.boardGame(bggId)
if (BuildConfig.DEBUG) writeMockData(bggId, networkResult)
val mappedValues = networkResult?.let { mapper.map(it.games) }
mappedValues?.let { database.insertAllBoardGame(listOf(it)) }
database.getBoardGameByUpdateDate().filter { item -> item.isOutdated() }.shuffled()
.take(MAX_GAME_TO_REFRESH_PER_CYCLE)
.forEach { itemToRefresh ->
Log.d("UpdateExistingBoardGameWork", "Schedule retrieving of : " + itemToRefresh.bggId)
scheduleRetrieveMissingBoardGameWork(context, itemToRefresh.bggId)
}
Result.success()
} catch (error: IllegalStateException) {
if (error is CancellationException) {
Log.d("UpdateBoardGameIntentWorker", "Job was Cancelled....")
Log.d("UpdateExistingBoardGameWork", "Job was Cancelled....")
}
Result.retry()
}
return result
}

private fun writeMockData(bggId: String?, result: BggGameInfoResult?) {
val parser: TikXml = TikXml.Builder()
.build()
val file = File(context.filesDir?.path + "/" + File.separator + bggId + ".xml")
file.sink().buffer().use { sink ->
parser.write(sink, result)
}
}
}
77 changes: 77 additions & 0 deletions app/src/main/java/fr/boitakub/bogadex/UpsetMissingBoardGameWork.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2021-2023, Boitakub
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of mosquitto nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package fr.boitakub.bogadex

import android.content.Context
import android.util.Log
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import fr.boitakub.bgg.client.BggService
import fr.boitakub.bogadex.boardgame.BoardGameListDao
import fr.boitakub.bogadex.boardgame.work.scheduleRetrieveMissingBoardGameWork
import kotlinx.coroutines.CancellationException

@HiltWorker
class UpsetMissingBoardGameWork @AssistedInject constructor(
@Assisted val context: Context,
@Assisted val workerParams: WorkerParameters,
val service: BggService,
val database: BoardGameListDao,
) : CoroutineWorker(context, workerParams) {

companion object {
const val MAX_GAME_TO_REFRESH_PER_CYCLE = 30
}

override suspend fun doWork(): Result {
Log.d("UpsetMissingBoardGameWork", "Starting job")
if (runAttemptCount > 4) {
return Result.failure()
}

val result = try {
database.collectionWithDetails().filter { item -> item.details == null }.shuffled()
.take(MAX_GAME_TO_REFRESH_PER_CYCLE)
.forEach { itemToRefresh ->
Log.d("UpsetMissingBoardGameWork", "Schedule retrieving of : " + itemToRefresh.item.bggId)
scheduleRetrieveMissingBoardGameWork(context, itemToRefresh.item.bggId)
}
Result.success()
} catch (error: IllegalStateException) {
if (error is CancellationException) {
Log.d("UpsetMissingBoardGameWork", "Job was Cancelled....")
}
Result.retry()
}
return result
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023, Boitakub
* Copyright (c) 2023, Boitakub
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand All @@ -26,45 +26,48 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package fr.boitakub.bogadex.boardgame.usecase
package fr.boitakub.bogadex

import android.content.Context
import androidx.work.Constraints
import androidx.work.Data
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import dagger.hilt.android.qualifiers.ApplicationContext
import fr.boitakub.bogadex.boardgame.UpdateBoardGameIntentWorker
import fr.boitakub.bogadex.boardgame.model.CollectionItemWithDetails
import javax.inject.Inject
import javax.inject.Singleton
import java.util.concurrent.TimeUnit

@Singleton
class RefreshGameDetails @Inject constructor(@ApplicationContext val context: Context) {
object WorkManagerScheduler {
fun upsetMissingBoardGame(context: Context) {
val myConstraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()

var scheduledRefresh = SCHEDULED_REFRESH_START
val work = PeriodicWorkRequest.Builder(UpsetMissingBoardGameWork::class.java, 15, TimeUnit.MINUTES)
.setConstraints(myConstraints)
.addTag("UpsetMissingBoardGameWork")
.build()

fun apply(input: CollectionItemWithDetails) {
if (scheduledRefresh < SCHEDULED_REFRESH_MAX) {
val data = Data.Builder()
data.putString("bggId", input.item.bggId)

val request = OneTimeWorkRequestBuilder<UpdateBoardGameIntentWorker>()
.addTag("Sync")
.setInputData(data.build())
.setConstraints(
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(),
)
.build()

scheduledRefresh++
WorkManager.getInstance(context).enqueue(request)
}
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"UpsetMissingBoardGameWork",
ExistingPeriodicWorkPolicy.UPDATE,
work,
)
}
fun refreshUpdateExistingBoardGameWork(context: Context) {
val myConstraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresCharging(true)
.build()

val work = PeriodicWorkRequest.Builder(UpdateExistingBoardGameWork::class.java, 24, TimeUnit.HOURS)
.setConstraints(myConstraints)
.addTag("UpdateExistingBoardGameWork")
.build()

companion object {
const val SCHEDULED_REFRESH_START = 0
const val SCHEDULED_REFRESH_MAX = 20
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"UpdateExistingBoardGameWork",
ExistingPeriodicWorkPolicy.UPDATE,
work,
)
}
}
1 change: 0 additions & 1 deletion detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,6 @@ style:
ForbiddenComment:
active: true
values:
- 'TODO:'
- 'FIXME:'
- 'STOPSHIP:'
allowedPatterns: ''
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Boitakub
* Copyright (c) 2021-2023, Boitakub
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -38,6 +38,9 @@ import kotlinx.coroutines.flow.Flow
@Dao
interface BoardGameDao {

@Query("SELECT * FROM boardgame ORDER BY update_date DESC")
fun getBoardGameByUpdateDate(): List<BoardGame>

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAllBoardGame(boardGames: List<BoardGame>)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2022, Boitakub
* Copyright (c) 2021-2023, Boitakub
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down
Loading

0 comments on commit 5e2a842

Please sign in to comment.