Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grab extension repo detail from repo.json and include in DB #506

Merged
merged 29 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
55956d4
WIP Extension Repo DB Support
sirlag Mar 10, 2024
ee0a829
Wired in to extension screen, browse settings screen
sirlag Mar 11, 2024
7e69c72
Detekt changes
sirlag Mar 11, 2024
30153f9
Ui tweaks and open in browser
sirlag Mar 11, 2024
1c7a003
Migrate ExtensionRepos on Update
sirlag Mar 15, 2024
ea81aca
Migration Cleanup
sirlag Mar 15, 2024
7893306
Slight cleanup / error handling
sirlag Mar 15, 2024
13bd542
Update ExtensionRepo from Repo.json during extension search.
sirlag Mar 15, 2024
5979f7e
Split repo fetching into separate API module, major refactor work
sirlag Mar 19, 2024
aa3eac1
Removed development strings
sirlag Mar 19, 2024
5457e16
Moved migration to #3
sirlag Mar 19, 2024
3acaea8
Fixed rebase
sirlag Mar 19, 2024
0f6b05e
Detekt changes
sirlag Mar 19, 2024
e4f2961
Added Replace Repository Dialog
sirlag Mar 19, 2024
4ba7c6b
Cleanup, removed platform specific code, PR comments
sirlag Mar 22, 2024
b1de63d
Removed extra function, reverted small change
sirlag Mar 22, 2024
b08aabf
Detekt cleanup
sirlag Mar 22, 2024
f322441
Apply suggestions from code review
sirlag Mar 22, 2024
2f549db
Fixed error introduced in cleanup
sirlag Mar 22, 2024
52db344
Tweak for multiline when
sirlag Mar 22, 2024
cf93e02
Moved getCount() to flow
sirlag Mar 22, 2024
30bfeb9
changed getCount to non-suspend, used property delegation
sirlag Mar 22, 2024
febed97
Apply suggestions from code review
sirlag Mar 22, 2024
5572e9e
Fixed formatting with updated comment string
sirlag Mar 22, 2024
a5d01f7
Big wave of PR comments, renaming/other tweaks
sirlag Mar 22, 2024
ca260a4
onOpenWebsite changes
sirlag Mar 22, 2024
6d27251
onOpenWebsite changes
sirlag Mar 22, 2024
b3053ef
trying to make single line
sirlag Mar 22, 2024
5357b7f
Renamed ExtensionRepoApi.kt to ExtensionRepoService.kt
sirlag Mar 22, 2024
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
17 changes: 13 additions & 4 deletions app/src/main/java/eu/kanade/domain/DomainModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import eu.kanade.domain.chapter.interactor.GetAvailableScanlators
import eu.kanade.domain.chapter.interactor.SetReadStatus
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
import eu.kanade.domain.download.interactor.DeleteDownload
import eu.kanade.domain.extension.interactor.CreateExtensionRepo
import eu.kanade.domain.extension.interactor.DeleteExtensionRepo
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
import eu.kanade.domain.extension.interactor.GetExtensionRepos
import eu.kanade.domain.extension.interactor.GetExtensionSources
import eu.kanade.domain.extension.interactor.GetExtensionsByType
import eu.kanade.domain.extension.interactor.TrustExtension
Expand All @@ -26,6 +23,14 @@ import eu.kanade.domain.track.interactor.AddTracks
import eu.kanade.domain.track.interactor.RefreshTracks
import eu.kanade.domain.track.interactor.SyncChapterProgressWithTrack
import eu.kanade.domain.track.interactor.TrackChapter
import mihon.data.repository.ExtensionRepoRepositoryImpl
import mihon.domain.extensionrepo.interactor.CreateExtensionRepo
import mihon.domain.extensionrepo.interactor.DeleteExtensionRepo
import mihon.domain.extensionrepo.interactor.GetExtensionRepo
import mihon.domain.extensionrepo.interactor.GetExtensionRepoCount
import mihon.domain.extensionrepo.interactor.ReplaceExtensionRepo
import mihon.domain.extensionrepo.interactor.UpdateExtensionRepo
import mihon.domain.extensionrepo.repository.ExtensionRepoRepository
import tachiyomi.data.category.CategoryRepositoryImpl
import tachiyomi.data.chapter.ChapterRepositoryImpl
import tachiyomi.data.history.HistoryRepositoryImpl
Expand Down Expand Up @@ -173,8 +178,12 @@ class DomainModule : InjektModule {
addFactory { ToggleSourcePin(get()) }
addFactory { TrustExtension(get()) }

addSingletonFactory<ExtensionRepoRepository> { ExtensionRepoRepositoryImpl(get()) }
addFactory { GetExtensionRepo(get()) }
addFactory { GetExtensionRepoCount(get()) }
addFactory { CreateExtensionRepo(get()) }
addFactory { DeleteExtensionRepo(get()) }
addFactory { GetExtensionRepos(get()) }
addFactory { ReplaceExtensionRepo(get()) }
addFactory { UpdateExtensionRepo(get(), get()) }
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package eu.kanade.presentation.more.settings.screen

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
Expand All @@ -13,11 +14,11 @@ import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.more.settings.screen.browse.ExtensionReposScreen
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate
import kotlinx.collections.immutable.persistentListOf
import mihon.domain.extensionrepo.interactor.GetExtensionRepoCount
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.pluralStringResource
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

Expand All @@ -33,7 +34,9 @@ object SettingsBrowseScreen : SearchableSettings {
val navigator = LocalNavigator.currentOrThrow

val sourcePreferences = remember { Injekt.get<SourcePreferences>() }
val reposCount by sourcePreferences.extensionRepos().collectAsState()
val getExtensionRepoCount = remember { Injekt.get<GetExtensionRepoCount>() }

val reposCount by getExtensionRepoCount.subscribe().collectAsState(0)

return listOf(
Preference.PreferenceGroup(
Expand All @@ -45,7 +48,7 @@ object SettingsBrowseScreen : SearchableSettings {
),
Preference.PreferenceItem.TextPreference(
title = stringResource(MR.strings.label_extension_repos),
subtitle = pluralStringResource(MR.plurals.num_repos, reposCount.size, reposCount.size),
subtitle = pluralStringResource(MR.plurals.num_repos, reposCount, reposCount),
onClick = {
navigator.push(ExtensionReposScreen())
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import androidx.compose.ui.platform.LocalContext
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionRepoConflictDialog
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionRepoCreateDialog
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionRepoDeleteDialog
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionReposScreen
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.collections.immutable.toImmutableSet
import kotlinx.coroutines.flow.collectLatest
import tachiyomi.presentation.core.screens.LoadingScreen

Expand Down Expand Up @@ -42,17 +45,19 @@ class ExtensionReposScreen(
ExtensionReposScreen(
state = successState,
onClickCreate = { screenModel.showDialog(RepoDialog.Create) },
onClickOpen = { context.openInBrowser(it.website) },
onClickDelete = { screenModel.showDialog(RepoDialog.Delete(it)) },
onClickRefresh = { screenModel.refreshRepos() },
navigateUp = navigator::pop,
)

when (val dialog = successState.dialog) {
null -> {}
RepoDialog.Create -> {
is RepoDialog.Create -> {
ExtensionRepoCreateDialog(
onDismissRequest = screenModel::dismissDialog,
onCreate = { screenModel.createRepo(it) },
repos = successState.repos,
repos = successState.repos.map { it.baseUrl }.toImmutableSet(),
sirlag marked this conversation as resolved.
Show resolved Hide resolved
)
}
is RepoDialog.Delete -> {
Expand All @@ -62,6 +67,15 @@ class ExtensionReposScreen(
repo = dialog.repo,
)
}

is RepoDialog.Conflict -> {
ExtensionRepoConflictDialog(
onDismissRequest = screenModel::dismissDialog,
onMigrate = { screenModel.replaceRepo(dialog.newRepo) },
oldRepo = dialog.oldRepo,
newRepo = dialog.newRepo,
)
}
}

LaunchedEffect(Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,37 @@ import androidx.compose.runtime.Immutable
import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import dev.icerock.moko.resources.StringResource
import eu.kanade.domain.extension.interactor.CreateExtensionRepo
import eu.kanade.domain.extension.interactor.DeleteExtensionRepo
import eu.kanade.domain.extension.interactor.GetExtensionRepos
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.toImmutableSet
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import mihon.domain.extensionrepo.interactor.CreateExtensionRepo
import mihon.domain.extensionrepo.interactor.DeleteExtensionRepo
import mihon.domain.extensionrepo.interactor.GetExtensionRepo
import mihon.domain.extensionrepo.interactor.ReplaceExtensionRepo
import mihon.domain.extensionrepo.interactor.UpdateExtensionRepo
import mihon.domain.extensionrepo.model.ExtensionRepo
import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.i18n.MR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

class ExtensionReposScreenModel(
private val getExtensionRepos: GetExtensionRepos = Injekt.get(),
private val getExtensionRepo: GetExtensionRepo = Injekt.get(),
private val createExtensionRepo: CreateExtensionRepo = Injekt.get(),
private val deleteExtensionRepo: DeleteExtensionRepo = Injekt.get(),
private val replaceExtensionRepo: ReplaceExtensionRepo = Injekt.get(),
private val updateExtensionRepo: UpdateExtensionRepo = Injekt.get(),
) : StateScreenModel<RepoScreenState>(RepoScreenState.Loading) {

private val _events: Channel<RepoEvent> = Channel(Int.MAX_VALUE)
val events = _events.receiveAsFlow()

init {
screenModelScope.launchIO {
getExtensionRepos.subscribe()
getExtensionRepo.subscribeAll()
.collectLatest { repos ->
mutableState.update {
RepoScreenState.Success(
Expand All @@ -47,21 +52,47 @@ class ExtensionReposScreenModel(
*/
fun createRepo(name: String) {
sirlag marked this conversation as resolved.
Show resolved Hide resolved
screenModelScope.launchIO {
when (createExtensionRepo.await(name)) {
is CreateExtensionRepo.Result.InvalidUrl -> _events.send(RepoEvent.InvalidUrl)
when (val result = createExtensionRepo.await(name)) {
CreateExtensionRepo.Result.InvalidUrl -> _events.send(RepoEvent.InvalidUrl)
CreateExtensionRepo.Result.RepoAlreadyExists -> _events.send(RepoEvent.RepoAlreadyExists)
is CreateExtensionRepo.Result.DuplicateFingerprint -> {
showDialog(RepoDialog.Conflict(result.oldRepo, result.newRepo))
}
else -> {}
}
}
}

/**
* Deletes the given repo from the database.
* Inserts a repo to the database, replace a matching repo with the same fingerprint if found.
*
* @param repo The repo to delete.
* @param newRepo The repo to insert
*/
fun replaceRepo(newRepo: ExtensionRepo) {
screenModelScope.launchIO {
replaceExtensionRepo.await(newRepo)
}
}

/**
* Refreshes information for each repository.
*/
fun refreshRepos() {
val status = state.value

if (status is RepoScreenState.Success) {
screenModelScope.launchIO {
status.repos.forEach { updateExtensionRepo.await(it) }
}
}
sirlag marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Deletes the given repo from the database
*/
fun deleteRepo(repo: String) {
fun deleteRepo(baseUrl: String) {
screenModelScope.launchIO {
deleteExtensionRepo.await(repo)
deleteExtensionRepo.await(baseUrl)
}
}

Expand All @@ -87,11 +118,13 @@ class ExtensionReposScreenModel(
sealed class RepoEvent {
sealed class LocalizedMessage(val stringRes: StringResource) : RepoEvent()
data object InvalidUrl : LocalizedMessage(MR.strings.invalid_repo_name)
data object RepoAlreadyExists : LocalizedMessage(MR.strings.error_repo_exists)
}

sealed class RepoDialog {
data object Create : RepoDialog()
data class Delete(val repo: String) : RepoDialog()
data class Conflict(val oldRepo: ExtensionRepo, val newRepo: ExtensionRepo) : RepoDialog()
}

sealed class RepoScreenState {
Expand All @@ -101,7 +134,8 @@ sealed class RepoScreenState {

@Immutable
data class Success(
val repos: ImmutableSet<String>,
val repos: ImmutableSet<ExtensionRepo>,
val oldRepos: ImmutableSet<String>? = null,
val dialog: RepoDialog? = null,
) : RepoScreenState() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Label
import androidx.compose.material.icons.outlined.ContentCopy
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.OpenInBrowser
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
Expand All @@ -22,15 +23,17 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import eu.kanade.tachiyomi.util.system.copyToClipboard
import kotlinx.collections.immutable.ImmutableSet
import mihon.domain.extensionrepo.model.ExtensionRepo
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource

@Composable
fun ExtensionReposContent(
repos: ImmutableSet<String>,
repos: ImmutableSet<ExtensionRepo>,
lazyListState: LazyListState,
paddingValues: PaddingValues,
onClickOpen: (ExtensionRepo) -> Unit,
onClickDelete: (String) -> Unit,
modifier: Modifier = Modifier,
) {
Expand All @@ -44,8 +47,9 @@ fun ExtensionReposContent(
item {
ExtensionRepoListItem(
modifier = Modifier.animateItemPlacement(),
repo = it,
onDelete = { onClickDelete(it) },
repo = it.name,
onClick = { onClickOpen(it) },
onDelete = { onClickDelete(it.baseUrl) },
)
}
}
Expand All @@ -55,6 +59,7 @@ fun ExtensionReposContent(
@Composable
private fun ExtensionRepoListItem(
repo: String,
onClick: () -> Unit,
sirlag marked this conversation as resolved.
Show resolved Hide resolved
onDelete: () -> Unit,
modifier: Modifier = Modifier,
) {
Expand All @@ -74,13 +79,24 @@ private fun ExtensionRepoListItem(
verticalAlignment = Alignment.CenterVertically,
) {
Icon(imageVector = Icons.AutoMirrored.Outlined.Label, contentDescription = null)
Text(text = repo, modifier = Modifier.padding(start = MaterialTheme.padding.medium))
Text(
text = repo,
modifier = Modifier.padding(start = MaterialTheme.padding.medium),
style = MaterialTheme.typography.titleMedium,
)
}

Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End,
) {
IconButton(onClick = onClick) {
Icon(
imageVector = Icons.Outlined.OpenInBrowser,
sirlag marked this conversation as resolved.
Show resolved Hide resolved
contentDescription = stringResource(MR.strings.action_open_in_browser),
)
}

IconButton(
onClick = {
val url = "$repo/index.min.json"
Expand Down
Loading