Migrate CheatImportWorker to Coroutines

This commit is contained in:
Rafael Caetano 2023-12-28 19:55:00 +00:00
parent 2e505830ec
commit cd57dbc5ad

View File

@ -3,34 +3,37 @@ package me.magnum.melonds.common.workers
import android.content.Context
import android.content.pm.ServiceInfo
import android.content.res.AssetFileDescriptor
import android.net.Uri
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
import androidx.work.RxWorker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.reactivex.Single
import me.magnum.melonds.MelonDSApplication
import me.magnum.melonds.R
import me.magnum.melonds.common.cheats.CheatDatabaseParser
import me.magnum.melonds.common.cheats.CheatDatabaseParserListener
import me.magnum.melonds.common.cheats.ProgressTrackerInputStream
import me.magnum.melonds.common.cheats.XmlCheatDatabaseParser
import me.magnum.melonds.domain.model.CheatDatabase
import me.magnum.melonds.domain.model.Game
import me.magnum.melonds.domain.repositories.CheatsRepository
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@HiltWorker
class CheatImportWorker @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
private val cheatsRepository: CheatsRepository
) : RxWorker(appContext, workerParams) {
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
private val cheatsRepository: CheatsRepository
) : CoroutineWorker(appContext, workerParams) {
companion object {
const val KEY_URI = "uri"
@ -40,77 +43,75 @@ class CheatImportWorker @AssistedInject constructor(
private const val NOTIFICATION_ID_CHEATS_IMPORT = 100
}
override fun createWork(): Single<Result> {
return Single.create { emitter ->
setForegroundAsync(createForegroundInfo(null, 0, true))
override suspend fun doWork(): Result {
setForeground(createForegroundInfo(null, 0, true))
val uri = inputData.getString(KEY_URI)?.toUri()
if (uri == null) {
emitter.onSuccess(Result.failure())
return@create
val uri = inputData.getString(KEY_URI)?.toUri() ?: return Result.failure()
try {
val databaseDocument = DocumentFile.fromSingleUri(applicationContext, uri)
if (databaseDocument?.isFile != true) {
return Result.failure()
}
try {
val databaseDocument = DocumentFile.fromSingleUri(applicationContext, uri)
if (databaseDocument?.isFile != true) {
emitter.onSuccess(Result.failure())
return@create
val totalFileSize = applicationContext.contentResolver.openAssetFileDescriptor(uri, "r")?.use {
val length = it.length
if (length == AssetFileDescriptor.UNKNOWN_LENGTH) {
null
} else {
length
}
}
val databaseExtension = databaseDocument.name?.substringAfterLast('.')
val parser = when (databaseExtension) {
"xml" -> XmlCheatDatabaseParser()
else -> {
return Result.failure()
}
}
return parseXmlDocument(uri, parser, totalFileSize)
} catch (e: Exception) {
return Result.failure()
}
}
private suspend fun parseXmlDocument(uri: Uri, parser: CheatDatabaseParser, totalFileSize: Long?) = suspendCoroutine { continuation ->
applicationContext.contentResolver.openInputStream(uri)?.use {
val progressTrackerStream = ProgressTrackerInputStream(it)
parser.parseCheatDatabase(progressTrackerStream, object : CheatDatabaseParserListener {
private var cheatDatabase: CheatDatabase? = null
override fun onDatabaseParseStart(databaseName: String) {
cheatsRepository.deleteCheatDatabaseIfExists(databaseName)
cheatDatabase = cheatsRepository.addCheatDatabase(databaseName)
}
val totalFileSize = applicationContext.contentResolver.openAssetFileDescriptor(uri, "r")?.use {
val length = it.length
if (length == AssetFileDescriptor.UNKNOWN_LENGTH)
null
else
length
override fun onGameParseStart(gameName: String) {
val readProgress = if (totalFileSize != null) {
(progressTrackerStream.totalReadBytes.toDouble() / totalFileSize * 100).toInt()
} else {
0
}
setForegroundAsync(createForegroundInfo(gameName, readProgress, totalFileSize == null))
setProgressAsync(workDataOf(
KEY_PROGRESS_RELATIVE to readProgress / 100f,
KEY_PROGRESS_ITEM to gameName
))
}
val databaseExtension = databaseDocument.name?.substringAfterLast('.')
val parser = when (databaseExtension) {
"xml" -> XmlCheatDatabaseParser()
else -> {
emitter.onSuccess(Result.failure())
return@create
override fun onGameParsed(game: Game) {
cheatDatabase?.id?.let {
cheatsRepository.addGameCheats(it, game)
}
}
applicationContext.contentResolver.openInputStream(uri)?.use {
val progressTrackerStream = ProgressTrackerInputStream(it)
parser.parseCheatDatabase(progressTrackerStream, object : CheatDatabaseParserListener {
private var cheatDatabase: CheatDatabase? = null
override fun onDatabaseParseStart(databaseName: String) {
cheatsRepository.deleteCheatDatabaseIfExists(databaseName)
cheatDatabase = cheatsRepository.addCheatDatabase(databaseName)
}
override fun onGameParseStart(gameName: String) {
val readProgress = if (totalFileSize != null)
(progressTrackerStream.totalReadBytes.toDouble() / totalFileSize * 100).toInt()
else
0
setForegroundAsync(createForegroundInfo(gameName, readProgress, totalFileSize == null))
setProgressAsync(workDataOf(
KEY_PROGRESS_RELATIVE to readProgress / 100f,
KEY_PROGRESS_ITEM to gameName
))
}
override fun onGameParsed(game: Game) {
cheatDatabase?.id?.let {
cheatsRepository.addGameCheats(it, game)
}
}
override fun onParseComplete() {
emitter.onSuccess(Result.success())
}
})
override fun onParseComplete() {
continuation.resume(Result.success())
}
} catch (e: Exception) {
emitter.onError(e)
}
})
}
}