Skip to content

Commit

Permalink
feat: enable/disable repo (#288)
Browse files Browse the repository at this point in the history
* Enable/Disable repo

* update extensions list when refresh
  • Loading branch information
cuong-tran committed Aug 25, 2024
1 parent 1dea30a commit d7fec68
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class SourcePreferences(
false,
)

// KMK -->
fun disabledRepos() = preferenceStore.getStringSet("disabled_repos", emptySet())
// KMK <--

// SY -->
fun enableSourceBlacklist() = preferenceStore.getBoolean("eh_enable_source_blacklist", true)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ 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.i18n.kmk.KMR
import tachiyomi.presentation.core.screens.LoadingScreen

class ExtensionReposScreen(
Expand Down Expand Up @@ -47,6 +48,16 @@ class ExtensionReposScreen(
onClickCreate = { screenModel.showDialog(RepoDialog.Create) },
onOpenWebsite = { context.openInBrowser(it.website) },
onClickDelete = { screenModel.showDialog(RepoDialog.Delete(it)) },
// KMK -->
onClickEnable = {
screenModel.enableRepo(it)
context.toast(KMR.strings.extensions_page_need_refresh)
},
onClickDisable = {
screenModel.disableRepo(it)
context.toast(KMR.strings.extensions_page_need_refresh)
},
// KMK <--
onClickRefresh = { screenModel.refreshRepos() },
navigateUp = navigator::pop,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ 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.source.service.SourcePreferences
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.toImmutableSet
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import mihon.domain.extensionrepo.interactor.CreateExtensionRepo
Expand All @@ -27,6 +30,9 @@ class ExtensionReposScreenModel(
private val deleteExtensionRepo: DeleteExtensionRepo = Injekt.get(),
private val replaceExtensionRepo: ReplaceExtensionRepo = Injekt.get(),
private val updateExtensionRepo: UpdateExtensionRepo = Injekt.get(),
// KMK -->
private val sourcePreferences: SourcePreferences = Injekt.get(),
// KMK <--
) : StateScreenModel<RepoScreenState>(RepoScreenState.Loading) {

private val _events: Channel<RepoEvent> = Channel(Int.MAX_VALUE)
Expand All @@ -39,10 +45,26 @@ class ExtensionReposScreenModel(
mutableState.update {
RepoScreenState.Success(
repos = repos.toImmutableSet(),
// KMK -->
disabledRepos = sourcePreferences.disabledRepos().get(),
// KMK <--
)
}
}
}

// KMK -->
sourcePreferences.disabledRepos().changes()
.onEach { disabledRepos ->
mutableState.update {
when (it) {
is RepoScreenState.Success -> it.copy(disabledRepos = disabledRepos)
else -> it
}
}
}
.launchIn(screenModelScope)
// KMK <--
}

/**
Expand Down Expand Up @@ -91,11 +113,35 @@ class ExtensionReposScreenModel(
* Deletes the given repo from the database
*/
fun deleteRepo(baseUrl: String) {
// KMK -->
// Remove repo from disabled list
enableRepo(baseUrl)
// KMK <--
screenModelScope.launchIO {
deleteExtensionRepo.await(baseUrl)
}
}

// KMK -->
fun enableRepo(baseUrl: String) {
val disabledRepos = sourcePreferences.disabledRepos().get()
if (baseUrl in disabledRepos) {
sourcePreferences.disabledRepos().set(
disabledRepos.filterNot { it == baseUrl }.toSet(),
)
}
}

fun disableRepo(baseUrl: String) {
val disabledRepos = sourcePreferences.disabledRepos().get()
if (baseUrl !in disabledRepos) {
sourcePreferences.disabledRepos().set(
disabledRepos + baseUrl,
)
}
}
// KMK <--

fun showDialog(dialog: RepoDialog) {
mutableState.update {
when (it) {
Expand Down Expand Up @@ -137,6 +183,9 @@ sealed class RepoScreenState {
val repos: ImmutableSet<ExtensionRepo>,
val oldRepos: ImmutableSet<String>? = null,
val dialog: RepoDialog? = null,
// KMK -->
val disabledRepos: Set<String> = emptySet(),
// KMK <--
) : RepoScreenState() {

val isEmpty: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,23 @@ import androidx.compose.material.icons.automirrored.outlined.Label
import androidx.compose.material.icons.automirrored.outlined.OpenInNew
import androidx.compose.material.icons.outlined.ContentCopy
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.material.icons.outlined.VisibilityOff
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import eu.kanade.tachiyomi.util.system.copyToClipboard
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.persistentSetOf
import mihon.domain.extensionrepo.model.ExtensionRepo
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
Expand All @@ -35,6 +41,11 @@ fun ExtensionReposContent(
paddingValues: PaddingValues,
onOpenWebsite: (ExtensionRepo) -> Unit,
onClickDelete: (String) -> Unit,
// KMK -->
onClickEnable: (String) -> Unit,
onClickDisable: (String) -> Unit,
disabledRepos: Set<String>,
// KMK <--
modifier: Modifier = Modifier,
) {
LazyColumn(
Expand All @@ -50,6 +61,11 @@ fun ExtensionReposContent(
repo = it,
onOpenWebsite = { onOpenWebsite(it) },
onDelete = { onClickDelete(it.baseUrl) },
// KMK -->
onEnable = { onClickEnable(it.baseUrl) },
onDisable = { onClickDisable(it.baseUrl) },
isDisabled = it.baseUrl in disabledRepos,
// KMK <--
)
}
}
Expand All @@ -62,6 +78,11 @@ private fun ExtensionRepoListItem(
onOpenWebsite: () -> Unit,
onDelete: () -> Unit,
modifier: Modifier = Modifier,
// KMK -->
isDisabled: Boolean,
onEnable: () -> Unit,
onDisable: () -> Unit,
// KMK <--
) {
val context = LocalContext.current

Expand All @@ -78,11 +99,21 @@ private fun ExtensionRepoListItem(
),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(imageVector = Icons.AutoMirrored.Outlined.Label, contentDescription = null)
Icon(
imageVector = Icons.AutoMirrored.Outlined.Label,
contentDescription = null,
// KMK -->
tint = LocalContentColor.current.let { if (isDisabled) it.copy(alpha = 0.6f) else it },
// KMK <--
)
Text(
text = repo.name,
modifier = Modifier.padding(start = MaterialTheme.padding.medium),
style = MaterialTheme.typography.titleMedium,
// KMK -->
color = LocalContentColor.current.let { if (isDisabled) it.copy(alpha = 0.6f) else it },
textDecoration = TextDecoration.LineThrough.takeIf { isDisabled },
// KMK <--
)
}

Expand All @@ -109,6 +140,15 @@ private fun ExtensionRepoListItem(
)
}

// KMK -->
IconButton(onClick = if (isDisabled) onEnable else onDisable) {
Icon(
imageVector = if (isDisabled) Icons.Outlined.VisibilityOff else Icons.Outlined.Visibility,
contentDescription = stringResource(MR.strings.action_disable),
)
}
// KMK <--

IconButton(onClick = onDelete) {
Icon(
imageVector = Icons.Outlined.Delete,
Expand All @@ -118,3 +158,24 @@ private fun ExtensionRepoListItem(
}
}
}

// KMK -->
@Preview
@Composable
fun ExtensionReposContentPreview() {
val repos = persistentSetOf(
ExtensionRepo("url1", "Repo 1", "", "", "key1"),
ExtensionRepo("url2", "Repo 2", "", "", "key2"),
)
ExtensionReposContent(
repos = repos,
lazyListState = LazyListState(),
paddingValues = PaddingValues(),
onOpenWebsite = {},
onClickDelete = {},
onClickEnable = {},
onClickDisable = {},
disabledRepos = setOf("url2"),
)
}
// KMK <--
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ fun ExtensionReposScreen(
onClickCreate: () -> Unit,
onOpenWebsite: (ExtensionRepo) -> Unit,
onClickDelete: (String) -> Unit,
// KMK -->
onClickEnable: (String) -> Unit,
onClickDisable: (String) -> Unit,
// KMK <--
onClickRefresh: () -> Unit,
navigateUp: () -> Unit,
) {
Expand Down Expand Up @@ -93,6 +97,11 @@ fun ExtensionReposScreen(
PaddingValues(horizontal = MaterialTheme.padding.medium),
onOpenWebsite = onOpenWebsite,
onClickDelete = onClickDelete,
// KMK -->
onClickEnable = onClickEnable,
onClickDisable = onClickDisable,
disabledRepos = state.disabledRepos,
// KMK <--
)
}
}
Expand All @@ -101,12 +110,36 @@ fun ExtensionReposScreen(
@Preview
@Composable
private fun ExtensionReposScreenPreview() {
val state = RepoScreenState.Success(
repos = persistentSetOf(
ExtensionRepo("url1", "Repo 1", "", "", "key1"),
ExtensionRepo("url2", "Repo 2", "", "", "key2"),
),
disabledRepos = setOf("url2"),
)
ExtensionReposScreen(
state = state,
onClickCreate = { },
onOpenWebsite = { },
onClickDelete = { },
onClickEnable = { },
onClickDisable = { },
onClickRefresh = { },
navigateUp = { },
)
}

@Preview
@Composable
private fun ExtensionReposScreenEmptyPreview() {
val state = RepoScreenState.Success(repos = persistentSetOf())
ExtensionReposScreen(
state = state,
onClickCreate = { },
onOpenWebsite = { },
onClickDelete = { },
onClickEnable = { },
onClickDisable = { },
onClickRefresh = { },
navigateUp = { },
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,25 +214,32 @@ class ExtensionManager(
* @param availableExtensions The list of extensions given by the [api].
*/
private fun updatedInstalledExtensionsStatuses(availableExtensions: List<Extension.Available>) {
if (availableExtensions.isEmpty()) {
preferences.extensionUpdatesCount().set(0)
return
}

// KMK -->
val noExtAvailable = availableExtensions.isEmpty()
// KMK <--
val installedExtensionsMap = installedExtensionMapFlow.value.toMutableMap()
var changed = false
for ((pkgName, extension) in installedExtensionsMap) {
val availableExt = availableExtensions.find { it.pkgName == pkgName }

if (availableExt == null && !extension.isObsolete) {
installedExtensionsMap[pkgName] = extension.copy(isObsolete = true)
changed = true
// KMK -->
if (availableExt == null/* KMK --> && !extension.isObsolete // KMK <-- */) {
// Clear hasUpdate & set isObsolete
val isObsolete = !noExtAvailable && !extension.isObsolete
// KMK: installedExtensionsMap[pkgName] = extension.copy(isObsolete = true)
installedExtensionsMap[pkgName] = extension.copy(
isObsolete = isObsolete,
hasUpdate = false,
)
// KMK: changed = true
changed = changed || isObsolete || noExtAvailable && (extension.isObsolete || extension.hasUpdate)
// KMK <--
// SY -->
} else if (extension.isBlacklisted() && !extension.isRedundant) {
installedExtensionsMap[pkgName] = extension.copy(isRedundant = true)
changed = true
// SY <--
} else if (availableExt != null) {
} else /* KMK --> if (availableExt != null) // KMK <-- */ {
val hasUpdate = extension.updateExists(availableExt)
if (extension.hasUpdate != hasUpdate) {
installedExtensionsMap[pkgName] = extension.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,22 @@ internal class ExtensionApi {
private val sourcePreferences: SourcePreferences by injectLazy()

// SY <--

private val json: Json by injectLazy()

private val lastExtCheck: Preference<Long> by lazy {
preferenceStore.getLong(Preference.appStateKey("last_ext_check"), 0)
}

suspend fun findExtensions(): List<Extension.Available> {
// KMK -->
val disabledRepos = sourcePreferences.disabledRepos().get()
// KMK <--
return withIOContext {
getExtensionRepo.getAll()
// KMK -->
.filterNot { it.baseUrl in disabledRepos }
// KMK <--
.map { async { getExtensions(it) } }
.awaitAll()
.flatten()
Expand Down
1 change: 1 addition & 0 deletions i18n-kmk/src/commonMain/moko-resources/base/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
<!-- Extension section -->
<string name="ext_unofficial">Unofficial</string>
<string name="unofficial_extension_message">This extension is not from the official repo.</string>
<string name="extensions_page_need_refresh">Refresh extension page to update list.</string>
<string name="extensions_page_more">More extensions...</string>

<!-- Extension repos -->
Expand Down

0 comments on commit d7fec68

Please sign in to comment.