Skip to content
This repository has been archived by the owner on Oct 3, 2022. It is now read-only.

Impl: Categories #239

Open
wants to merge 22 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ class BackupWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
private val chaptersRepository by instance<IChaptersRepository>()
private val extensionRepoRepository by instance<IExtensionRepoRepository>()
private val backupRepository by instance<IBackupRepository>()
private val categoriesRepository by instance<ICategoryRepository>()
private val novelCategoriesRepository by instance<INovelCategoryRepository>()

override val notificationManager: NotificationManagerCompat by notificationManager()

Expand Down Expand Up @@ -123,6 +125,15 @@ class BackupWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
return emptyList()
}

private suspend fun getBackupCategories(): Map<Int, BackupCategoryEntity> {
return categoriesRepository.getCategories().associate {
it.id!! to BackupCategoryEntity(
it.name,
it.order
)
}
}


@Throws(IOException::class)
override suspend fun doWork(): Result {
Expand All @@ -135,6 +146,7 @@ class BackupWorker(appContext: Context, params: WorkerParameters) : CoroutineWor

lateinit var novelsToChapters: List<Pair<NovelEntity, List<BackupChapterEntity>>>
lateinit var extensions: List<InstalledExtensionEntity>
lateinit var categories: Map<Int, BackupCategoryEntity>

/*
Run to isolate the variable 'novels' so it can be trashed, hopefully saving memory
Expand Down Expand Up @@ -170,6 +182,16 @@ class BackupWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
}
}.distinct()

// Categories each novel requires
categories = try {
getBackupCategories()
} catch (e: SQLiteException) {
ACRA.errorReporter.handleSilentException(e)
e.printStackTrace()
emptyMap()
}


true
}
System.gc() // please clean up
Expand Down Expand Up @@ -217,16 +239,21 @@ class BackupWorker(appContext: Context, params: WorkerParameters) : CoroutineWor
)
} ?: BackupNovelSettingEntity()

val novelCategories = novelCategoriesRepository.getNovelCategoriesFromNovel(novel.id!!)
.map { categories[it.categoryID]!!.order }

BackupNovelEntity(
novel.url,
novel.title,
novel.imageURL,
chapters,
settings = bSettings
settings = bSettings,
categories = novelCategories
)
}
)
}
},
categories = categories.values.toList()
)

logI("Encoding to json")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import app.shosetsu.android.common.consts.Notifications.ID_CHAPTER_UPDATE
import app.shosetsu.android.common.consts.WorkerTags.UPDATE_WORK_ID
import app.shosetsu.android.common.ext.*
import app.shosetsu.android.domain.model.local.ChapterEntity
import app.shosetsu.android.domain.model.local.NovelEntity
import app.shosetsu.android.domain.model.local.LibraryNovelEntity
import app.shosetsu.android.domain.repository.base.INovelsRepository
import app.shosetsu.android.domain.repository.base.ISettingsRepository
import app.shosetsu.android.domain.usecases.StartDownloadWorkerAfterUpdateUseCase
Expand All @@ -41,6 +41,7 @@ import app.shosetsu.lib.exceptions.HTTPException
import coil.imageLoader
import coil.request.ImageRequest
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import org.kodein.di.DI
import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
Expand Down Expand Up @@ -118,6 +119,12 @@ class NovelUpdateWorker(
private suspend fun onlyUpdateOngoing(): Boolean =
iSettingsRepository.getBoolean(OnlyUpdateOngoingNovels)

private suspend fun includedCategoriesInLibraryUpdate(): List<Int> =
iSettingsRepository.getStringSet(IncludeCategoriesInUpdate).map(String::toInt)

private suspend fun excludedCategoriesInLibraryUpdate(): List<Int> =
iSettingsRepository.getStringSet(ExcludedCategoriesInUpdate).map(String::toInt)

private suspend fun downloadOnUpdate(): Boolean =
iSettingsRepository.getBoolean(DownloadNewNovelChapters)

Expand All @@ -141,17 +148,39 @@ class NovelUpdateWorker(
}

/** Count of novels that have been updated */
val updateNovels = arrayListOf<NovelEntity>()
val updateNovels = arrayListOf<LibraryNovelEntity>()

/** Collect updated chapters to be used */
val updatedChapters = arrayListOf<ChapterEntity>()

iNovelsRepository.loadBookmarkedNovelEntities().let { list ->
iNovelsRepository.loadLibraryNovelEntities().first().let { list ->
val categoryID = inputData.getInt(KEY_CATEGORY, -1)
if (categoryID >= 0) {
list.filter { it.category == categoryID }
} else list
}.let { list ->
if (onlyUpdateOngoing())
list.filter { it.status != Novel.Status.COMPLETED }
else list
}.let { list ->
list.sortedBy { it.title }
val includedCategories = includedCategoriesInLibraryUpdate()
val includedNovels = if (includedCategories.isNotEmpty()) {
list.filter { it.category in includedCategories }
} else {
list
}

val excludedCategories = excludedCategoriesInLibraryUpdate()
val excludedNovels = if (excludedCategories.isNotEmpty()) {
list.filter { it.category in excludedCategories }.map { it.id }.toSet()
} else {
emptySet()
}

includedNovels.filterNot { it.id in excludedNovels }
}.let { list ->
list.distinctBy { it.id }
.sortedBy { it.title }
}.let { novels ->
var progress = 0

Expand All @@ -178,12 +207,12 @@ class NovelUpdateWorker(
}

val it = try {
loadRemoteNovelUseCase(nE, true)
loadRemoteNovelUseCase(nE.id, true)
} catch (e: LuaError) {
logE("Failed to load novel: $nE", e)
notify(
"${e.message}",
10000 + nE.id!!
10000 + nE.id
) {
setContentTitle(
getString(
Expand All @@ -202,7 +231,7 @@ class NovelUpdateWorker(
logE("Failed to load novel: $nE", e)
notify(
"${e.message}",
10000 + nE.id!!
10000 + nE.id
) {
setContentTitle(
getString(
Expand All @@ -221,7 +250,7 @@ class NovelUpdateWorker(
logE("Failed to load novel: $nE", e)
notify(
"${e.message}",
10000 + nE.id!!
10000 + nE.id
) {
setContentTitle(
getString(
Expand All @@ -244,7 +273,7 @@ class NovelUpdateWorker(
logE("Failed to load novel: $nE", e)
notify(
"${e.message}",
10000 + nE.id!!
10000 + nE.id
) {
setContentTitle(
getString(
Expand All @@ -260,7 +289,7 @@ class NovelUpdateWorker(

addReportErrorAction(
applicationContext,
10000 + nE.id!!,
10000 + nE.id,
e
)
}
Expand Down Expand Up @@ -307,7 +336,7 @@ class NovelUpdateWorker(
chapterSize,
chapterSize
),
10000 + novel.id!!
10000 + novel.id
) {
setContentTitle(
getString(
Expand All @@ -324,7 +353,7 @@ class NovelUpdateWorker(

if (firstChapterId != null) {
addOpenReader(
novel.id ?: return@notify,
novel.id,
firstChapterId
)
setAutoCancel(true)
Expand Down Expand Up @@ -422,7 +451,7 @@ class NovelUpdateWorker(
if (SDK_INT >= VERSION_CODES.M)
setRequiresDeviceIdle(updateOnlyIdle())
}.build()
).build()
).setInputData(data).build()
)
workerManager.getWorkInfosForUniqueWork(UPDATE_WORK_ID).await()[0].let {
Log.d(logID(), "State ${it.state}")
Expand All @@ -442,6 +471,6 @@ class NovelUpdateWorker(
const val KEY_CHAPTERS: String = "Novels"

const val KEY_NOVELS: Int = 0x00
const val KEY_CATEGORY: Int = 0x01
const val KEY_CATEGORY: String = "category"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import app.shosetsu.android.common.utils.backupJSON
import app.shosetsu.android.domain.model.local.*
import app.shosetsu.android.domain.model.local.backup.*
import app.shosetsu.android.domain.repository.base.*
import app.shosetsu.android.domain.usecases.AddCategoryUseCase
import app.shosetsu.android.domain.usecases.InstallExtensionUseCase
import app.shosetsu.android.domain.usecases.StartRepositoryUpdateManagerUseCase
import app.shosetsu.lib.IExtension
Expand Down Expand Up @@ -82,6 +83,9 @@ class RestoreBackupWorker(appContext: Context, params: WorkerParameters) : Corou
private val novelsSettingsRepo by instance<INovelSettingsRepository>()
private val chaptersRepo by instance<IChaptersRepository>()
private val backupUriRepo by instance<IBackupUriRepository>()
private val categoriesRepo by instance<ICategoryRepository>()
private val novelCategoriesRepo by instance<INovelCategoryRepository>()
private val addCategoryUseCase by instance<AddCategoryUseCase>()
override val baseNotificationBuilder: NotificationCompat.Builder
get() = notificationBuilder(applicationContext, Notifications.CHANNEL_BACKUP)
.setSubText(getString(R.string.restore_notification_subtitle))
Expand Down Expand Up @@ -186,6 +190,17 @@ class RestoreBackupWorker(appContext: Context, params: WorkerParameters) : Corou
unGZip(decodedBytes).use { stream ->
val backup = backupJSON.decodeFromStream<FleshedBackupEntity>(stream)

notify("Adding categories")
val currentCategories = categoriesRepo.getCategories()
val categoryOrderToCategoryIds = backup.categories.sortedBy { it.order }.associate { backupCategory ->
val currentCategory = currentCategories.find { backupCategory.name == it.name }
backupCategory.order to if (currentCategory != null) {
currentCategory.id!!
} else {
addCategoryUseCase(backupCategory.name)
}
}

notify("Adding repositories")
// Adds the repositories
backup.repos.forEach { (url, name) ->
Expand All @@ -212,7 +227,7 @@ class RestoreBackupWorker(appContext: Context, params: WorkerParameters) : Corou
val repoNovels: List<NovelEntity> = novelsRepo.loadNovels()
val extensions = extensionsRepo.loadRepositoryExtensions()

backup.extensions.forEach { restoreExtension(extensions, repoNovels, it) }
backup.extensions.forEach { restoreExtension(extensions, repoNovels, it, categoryOrderToCategoryIds) }
}


Expand All @@ -230,7 +245,8 @@ class RestoreBackupWorker(appContext: Context, params: WorkerParameters) : Corou
private suspend fun restoreExtension(
extensions: List<GenericExtensionEntity>,
repoNovels: List<NovelEntity>,
backupExtensionEntity: BackupExtensionEntity
backupExtensionEntity: BackupExtensionEntity,
categoryOrderToCategoryIds: Map<Int, Int>
) {
val extensionID = backupExtensionEntity.id
val backupNovels = backupExtensionEntity.novels
Expand All @@ -253,7 +269,8 @@ class RestoreBackupWorker(appContext: Context, params: WorkerParameters) : Corou
iExt,
extensionID,
novelEntity,
repoNovels
repoNovels,
categoryOrderToCategoryIds
)
} catch (e: Exception) {
e.printStackTrace()
Expand All @@ -266,7 +283,8 @@ class RestoreBackupWorker(appContext: Context, params: WorkerParameters) : Corou
iExt: IExtension,
extensionID: Int,
backupNovelEntity: BackupNovelEntity,
repoNovels: List<NovelEntity>
repoNovels: List<NovelEntity>,
categoryOrderToCategoryIds: Map<Int, Int>
) {
logV("$extensionID, ${backupNovelEntity.url}")
// Use a single memory location for the bitmap
Expand Down Expand Up @@ -486,6 +504,42 @@ class RestoreBackupWorker(appContext: Context, params: WorkerParameters) : Corou
)
}

notify(R.string.restore_notification_content_categories_restore) {
setContentTitle(name)
}
val novelCategories = try {
novelCategoriesRepo.getNovelCategoriesFromNovel(targetNovelID)
} catch (e: Exception) {// TODO specify
logE("Failed to load novel categories")
ACRA.errorReporter.handleSilentException(e)
return
}

if (novelCategories.isEmpty()) {
logI("Inserting novel categories")
novelCategoriesRepo.setNovelCategories(
backupNovelEntity.categories.map {
NovelCategoryEntity(
targetNovelID,
categoryOrderToCategoryIds[it]!!
)
}
)
} else {
val existingNovelCategories = novelCategories.map { it.categoryID }
novelCategoriesRepo.setNovelCategories(
backupNovelEntity.categories.mapNotNull {
val category = categoryOrderToCategoryIds[it]
if (category == null || it in existingNovelCategories)
return@mapNotNull null

NovelCategoryEntity(
targetNovelID,
categoryOrderToCategoryIds[it]!!
)
}
)
}

loadImageJob.join() // Finish the image loading job

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ sealed class SettingKey<T : Any>(val name: String, val default: T) {
object OnlyUpdateOngoingNovels : BooleanKey("onlyUpdateOngoing", false)
object UpdateNovelsOnStartup : BooleanKey("updateOnStartup", true)

object IncludeCategoriesInUpdate : StringSetKey("includedCategoriesInUpdate", emptySet())
object ExcludedCategoriesInUpdate : StringSetKey("excludedCategoriesInUpdate", emptySet())

object IncludeCategoriesToDownload : StringSetKey("includedCategoriesToDownload", emptySet())
object ExcludedCategoriesToDownload : StringSetKey("excludedCategoriesToDownload", emptySet())

object NovelUpdateCycle : IntKey("updateCycle", 12)
object NovelUpdateOnLowStorage : BooleanKey("updateLowStorage", true)
object NovelUpdateOnLowBattery : BooleanKey("updateLowBattery", true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const val APK_MIME = "application/vnd.android.package-archive"
/**
* The version of backups this build of shosetsu supports
*/
const val VERSION_BACKUP: String = "1.0.0"
const val VERSION_BACKUP: String = "1.1.0"
const val BACKUP_FILE_EXTENSION = "sbk"
const val REPOSITORY_HELP_URL = "https://shosetsu.app/help/guides/repositories/"
const val URL_WEBSITE = "https://shosetsu.app"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import org.kodein.di.singleton
* 01 / 01 / 2021
*/
val dbDataSourceModule = DI.Module("database_data_source") {
bind<IDBCategoriesDataSource>() with singleton { DBCategoriesDataSource(instance()) }
bind<IDBChaptersDataSource>() with singleton { DBChaptersDataSource(instance()) }
bind<IDBDownloadsDataSource>() with singleton { DBDownloadsDataSource(instance()) }

Expand All @@ -45,6 +46,8 @@ val dbDataSourceModule = DI.Module("database_data_source") {

bind<IDBExtLibDataSource>() with singleton { DBExtLibDataSource(instance()) }

bind<IDBNovelCategoriesDataSource>() with singleton { DBNovelCategoriesDataSource(instance()) }

bind<IDBNovelsDataSource>() with singleton { DBNovelsDataSource(instance()) }

bind<IDBExtRepoDataSource>() with singleton { DBExtRepoDataSource(instance()) }
Expand Down
Loading