diff --git a/app/src/main/java/com/fluxa/app/plugins/PluginRepositoryManager.kt b/app/src/main/java/com/fluxa/app/plugins/PluginRepositoryManager.kt index 2d6cc97..4abfb82 100644 --- a/app/src/main/java/com/fluxa/app/plugins/PluginRepositoryManager.kt +++ b/app/src/main/java/com/fluxa/app/plugins/PluginRepositoryManager.kt @@ -133,6 +133,11 @@ class PluginRepositoryManager @Inject constructor( persistCurrentState() } + suspend fun refreshRepository(manifestUrl: String) { + runtime.dispatch(mapOf("type" to "pluginRepositoryAddRequested", "manifestUrl" to manifestUrl)) + persistCurrentState() + } + suspend fun toggleScraper(scraperId: String, enabled: Boolean) { runtime.dispatch(mapOf("type" to "pluginScraperToggled", "scraperId" to scraperId, "enabled" to enabled)) persistCurrentState() diff --git a/app/src/main/java/com/fluxa/app/ui/settings/PluginsSettingsScreen.kt b/app/src/main/java/com/fluxa/app/ui/settings/PluginsSettingsScreen.kt index 06457fa..91c2109 100644 --- a/app/src/main/java/com/fluxa/app/ui/settings/PluginsSettingsScreen.kt +++ b/app/src/main/java/com/fluxa/app/ui/settings/PluginsSettingsScreen.kt @@ -1,10 +1,12 @@ package com.fluxa.app.ui.settings import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -13,17 +15,24 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.AlertDialog +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.TextField -import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -33,14 +42,14 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.Settings -import androidx.compose.material3.Icon import com.fluxa.app.common.AppStrings import com.fluxa.app.plugins.PluginRepositoryUiModel import com.fluxa.app.plugins.PluginScraperUiModel @@ -59,6 +68,7 @@ fun PluginsSettingsRoute( language = language, onAddRepository = viewModel::addRepository, onRemoveRepository = viewModel::removeRepository, + onRefreshRepository = viewModel::refreshRepository, onToggleScraper = viewModel::toggleScraper, onOpenScraperSettings = viewModel::openScraperSettings, onBackRequested = onBackRequested @@ -84,155 +94,233 @@ fun PluginsSettingsScreen( language: String?, onAddRepository: (String) -> Unit, onRemoveRepository: (String) -> Unit, + onRefreshRepository: (String) -> Unit, onToggleScraper: (String, Boolean) -> Unit, onOpenScraperSettings: (PluginScraperUiModel) -> Unit, onBackRequested: () -> Unit, modifier: Modifier = Modifier ) { - var showAddDialog by remember { mutableStateOf(false) } + val scrapersByRepository = state.scrapers.groupBy { it.repositoryUrl } Box(modifier = modifier.fillMaxSize().background(FluxaColors.background)) { - Column(modifier = Modifier.fillMaxSize().padding(horizontal = 20.dp)) { - PluginsTopBar(title = AppStrings.t(language, "settings.plugins.title"), onBack = onBackRequested) - Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { - PluginsSectionHeader(AppStrings.t(language, "settings.plugins.repositories")) - PluginsActionRow(AppStrings.t(language, "settings.plugins.add_repository")) { showAddDialog = true } - - if (state.addingRepositoryUrl != null) { - Text( - AppStrings.t(language, "settings.plugins.adding"), - color = Color.White.copy(alpha = 0.6f), - fontSize = 13.sp, - modifier = Modifier.padding(vertical = 8.dp) - ) - } - state.error?.let { error -> - Text( - AppStrings.format(language, "settings.plugins.error", error), - color = FluxaColors.errorRed, - fontSize = 13.sp, - modifier = Modifier.padding(vertical = 8.dp) - ) - } - - if (state.repositories.isEmpty()) { - Text( - AppStrings.t(language, "settings.plugins.no_repositories"), - color = Color.White.copy(alpha = 0.5f), - modifier = Modifier.padding(vertical = 12.dp) - ) - } else { - state.repositories.forEach { repository -> - PluginRepositoryRow( - repository = repository, - language = language, - onRemove = { onRemoveRepository(repository.manifestUrl) } - ) - } - } - - Spacer(Modifier.height(20.dp)) - PluginsSectionHeader(AppStrings.t(language, "settings.plugins.scrapers")) - if (state.scrapers.isEmpty()) { - Text( - AppStrings.t(language, "settings.plugins.no_scrapers"), - color = Color.White.copy(alpha = 0.5f), - modifier = Modifier.padding(vertical = 12.dp) - ) - } else { - state.scrapers.forEach { scraper -> - PluginScraperRow( - scraper = scraper, - language = language, - onToggle = { enabled -> onToggleScraper(scraper.id, enabled) }, - onOpenSettings = { onOpenScraperSettings(scraper) } - ) - } - } - Spacer(Modifier.height(120.dp)) - } - } - } - - if (showAddDialog) { - PluginAddRepositoryDialog( - language = language, - onDismiss = { showAddDialog = false }, - onConfirm = { url -> - onAddRepository(url) - showAddDialog = false - } - ) - } -} - -@Composable -private fun PluginsTopBar(title: String, onBack: () -> Unit) { - Row(modifier = Modifier.fillMaxWidth().padding(vertical = 16.dp), verticalAlignment = Alignment.CenterVertically) { - Box( - modifier = Modifier.size(40.dp).clip(CircleShape).background(Color.White.copy(alpha = 0.05f)).clickable(onClick = onBack), - contentAlignment = Alignment.Center + LazyColumn( + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 20.dp), + verticalArrangement = Arrangement.spacedBy(14.dp) ) { - Text("←", color = Color.White) + item { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(18.dp)) { + var backFocused by remember { mutableStateOf(false) } + Box( + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + .onFocusChanged { backFocused = it.isFocused } + .background(if (backFocused) Color.White else Color.White.copy(alpha = 0.05f)) + .clickable(onClick = onBackRequested), + contentAlignment = Alignment.Center + ) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = null, + tint = if (backFocused) Color.Black else Color.White, + modifier = Modifier.size(20.dp) + ) + } + Text( + text = AppStrings.t(language, "settings.plugins.title"), + color = Color.White, + fontWeight = FontWeight.Black, + fontSize = 26.sp + ) + } + } + + item { + PluginRepositoryInput(language = language, onSubmit = onAddRepository) + } + + if (state.error != null) { + item { + Text( + text = AppStrings.format(language, "settings.plugins.error", state.error), + color = FluxaColors.errorRed, + fontSize = 13.sp + ) + } + } + + val addingNewRepositoryUrl = state.addingRepositoryUrl + ?.takeIf { url -> state.repositories.none { it.manifestUrl == url } } + if (addingNewRepositoryUrl != null) { + item { + Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp)) { + CircularProgressIndicator(color = Color.White.copy(alpha = 0.68f), strokeWidth = 2.dp, modifier = Modifier.size(16.dp)) + Text( + text = AppStrings.t(language, "settings.plugins.adding"), + color = Color.White.copy(alpha = 0.6f), + fontSize = 13.sp + ) + } + } + } + + item { + Text( + text = AppStrings.t(language, "settings.plugins.installed_repositories"), + color = Color.White, + fontWeight = FontWeight.Bold, + fontSize = 16.sp + ) + } + + if (state.repositories.isEmpty()) { + item { + Text( + text = AppStrings.t(language, "settings.plugins.no_repositories"), + color = Color.White.copy(alpha = 0.5f), + fontSize = 13.sp, + modifier = Modifier.padding(vertical = 8.dp) + ) + } + } else { + items(state.repositories, key = { "repo:${it.manifestUrl}" }) { repository -> + PluginRepositoryGroup( + repository = repository, + scrapers = scrapersByRepository[repository.manifestUrl].orEmpty(), + language = language, + isRefreshing = state.addingRepositoryUrl == repository.manifestUrl, + onRemove = { onRemoveRepository(repository.manifestUrl) }, + onRefresh = { onRefreshRepository(repository.manifestUrl) }, + onToggleScraper = onToggleScraper, + onOpenScraperSettings = onOpenScraperSettings + ) + } + } + + item { Spacer(Modifier.height(80.dp)) } } - Spacer(Modifier.width(12.dp)) - Text(title, color = Color.White, fontWeight = FontWeight.Black, fontSize = 22.sp) } } @Composable -private fun PluginsSectionHeader(title: String) { - Text( - title.uppercase(), - color = Color.White.copy(alpha = 0.4f), - fontSize = 12.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(top = 16.dp, bottom = 8.dp) - ) -} - -@Composable -private fun PluginsActionRow(label: String, onClick: () -> Unit) { - Row( - modifier = Modifier.fillMaxWidth().clickable(onClick = onClick).padding(vertical = 12.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text(label, color = Color.White) - Text("+", color = Color.White.copy(alpha = 0.6f), fontSize = 18.sp) - } -} - -@Composable -private fun PluginRepositoryRow( - repository: PluginRepositoryUiModel, +private fun PluginRepositoryInput( language: String?, - onRemove: () -> Unit + onSubmit: (String) -> Unit ) { - Row( + var url by remember { mutableStateOf("") } + Column( modifier = Modifier .fillMaxWidth() - .padding(vertical = 6.dp) - .clip(RoundedCornerShape(10.dp)) - .background(Color.White.copy(alpha = 0.05f)) - .padding(horizontal = 14.dp, vertical = 12.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically + .clip(RoundedCornerShape(18.dp)) + .background(Color.White.copy(alpha = 0.04f)) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) ) { - Column(modifier = Modifier.weight(1f)) { - Text(repository.name.ifBlank { repository.manifestUrl }, color = Color.White, fontWeight = FontWeight.Bold) - Text( - AppStrings.format(language, "settings.plugins.scraper_count", repository.scraperCount), - color = Color.White.copy(alpha = 0.5f), - fontSize = 12.sp - ) - } - Text( - AppStrings.t(language, "settings.plugins.remove"), - color = FluxaColors.errorRed, - fontSize = 13.sp, - modifier = Modifier.clickable(onClick = onRemove).padding(8.dp) + OutlinedTextField( + value = url, + onValueChange = { url = it }, + modifier = Modifier.fillMaxWidth().height(52.dp), + singleLine = true, + placeholder = { + Text( + AppStrings.t(language, "settings.plugins.repository_url_placeholder"), + color = Color.White.copy(alpha = 0.3f), + fontSize = 13.sp + ) + }, + colors = OutlinedTextFieldDefaults.colors( + unfocusedBorderColor = Color.White.copy(alpha = 0.1f), + focusedTextColor = Color.White, + unfocusedTextColor = Color.White, + cursorColor = Color.White, + focusedContainerColor = Color.Black.copy(alpha = 0.2f), + unfocusedContainerColor = Color.Black.copy(alpha = 0.2f) + ), + shape = RoundedCornerShape(12.dp) ) + androidx.compose.material3.Button( + onClick = { + val trimmed = url.trim() + if (trimmed.isNotEmpty()) { + onSubmit(trimmed) + url = "" + } + }, + enabled = url.isNotBlank(), + modifier = Modifier.fillMaxWidth().height(44.dp), + shape = RoundedCornerShape(12.dp), + colors = androidx.compose.material3.ButtonDefaults.buttonColors(containerColor = Color.White, contentColor = Color.Black) + ) { + Icon(Icons.Filled.Add, contentDescription = null, modifier = Modifier.size(18.dp)) + Spacer(Modifier.width(6.dp)) + Text(AppStrings.t(language, "settings.plugins.add_repository"), fontWeight = FontWeight.Bold, fontSize = 14.sp) + } + } +} + +@Composable +private fun PluginRepositoryGroup( + repository: PluginRepositoryUiModel, + scrapers: List, + language: String?, + isRefreshing: Boolean, + onRemove: () -> Unit, + onRefresh: () -> Unit, + onToggleScraper: (String, Boolean) -> Unit, + onOpenScraperSettings: (PluginScraperUiModel) -> Unit +) { + Column( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(18.dp)) + .background(Color.White.copy(alpha = 0.04f)) + .border(1.dp, Color.White.copy(alpha = 0.06f), RoundedCornerShape(18.dp)) + .padding(vertical = 4.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + text = repository.name.ifBlank { repository.manifestUrl }, + color = Color.White, + fontWeight = FontWeight.Bold, + fontSize = 15.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Text( + text = AppStrings.format(language, "settings.plugins.scraper_count", repository.scraperCount), + color = Color.White.copy(alpha = 0.5f), + fontSize = 12.sp + ) + } + if (isRefreshing) { + Box(modifier = Modifier.size(36.dp), contentAlignment = Alignment.Center) { + CircularProgressIndicator(color = Color.White.copy(alpha = 0.68f), strokeWidth = 2.dp, modifier = Modifier.size(18.dp)) + } + } else { + PluginIconButton(icon = Icons.Filled.Refresh, onClick = onRefresh) + } + PluginIconButton(icon = Icons.Filled.Close, tint = Color.White.copy(alpha = 0.5f), onClick = onRemove) + } + + if (scrapers.isNotEmpty()) { + HorizontalDivider(color = Color.White.copy(alpha = 0.06f), thickness = 0.5.dp) + scrapers.forEachIndexed { index, scraper -> + PluginScraperRow( + scraper = scraper, + language = language, + onToggle = { enabled -> onToggleScraper(scraper.id, enabled) }, + onOpenSettings = { onOpenScraperSettings(scraper) } + ) + if (index < scrapers.lastIndex) { + HorizontalDivider(color = Color.White.copy(alpha = 0.06f), thickness = 0.5.dp, modifier = Modifier.padding(horizontal = 16.dp)) + } + } + } } } @@ -244,31 +332,31 @@ private fun PluginScraperRow( onOpenSettings: () -> Unit ) { Row( - modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp), - horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 12.dp), verticalAlignment = Alignment.CenterVertically ) { Column(modifier = Modifier.weight(1f)) { - Text(scraper.name, color = Color.White) - Text(scraper.supportedTypes.joinToString(", "), color = Color.White.copy(alpha = 0.4f), fontSize = 11.sp) + Text( + text = scraper.name, + color = Color.White, + fontWeight = FontWeight.SemiBold, + fontSize = 14.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Text( + text = scraper.supportedTypes.joinToString(", "), + color = Color.White.copy(alpha = 0.45f), + fontSize = 11.sp + ) } if (scraper.hasSettings) { - Box( - modifier = Modifier - .size(32.dp) - .clip(CircleShape) - .background(Color.White.copy(alpha = 0.05f)) - .clickable(onClick = onOpenSettings), - contentAlignment = Alignment.Center - ) { - Icon( - Icons.Rounded.Settings, - contentDescription = AppStrings.t(language, "settings.plugins.settings"), - tint = Color.White.copy(alpha = 0.7f), - modifier = Modifier.size(18.dp) - ) - } - Spacer(Modifier.width(8.dp)) + PluginIconButton( + icon = Icons.Filled.Settings, + contentDescription = AppStrings.t(language, "settings.plugins.settings"), + onClick = onOpenSettings + ) + Spacer(Modifier.width(4.dp)) } Switch( checked = scraper.enabled, @@ -276,47 +364,35 @@ private fun PluginScraperRow( colors = SwitchDefaults.colors( checkedTrackColor = Color.White, checkedThumbColor = Color.Black, - uncheckedTrackColor = Color.White.copy(alpha = 0.15f), - uncheckedThumbColor = Color.White.copy(alpha = 0.7f) + uncheckedTrackColor = Color.White.copy(alpha = 0.18f), + uncheckedThumbColor = Color.White.copy(alpha = 0.72f) ) ) } } @Composable -private fun PluginAddRepositoryDialog( - language: String?, - onDismiss: () -> Unit, - onConfirm: (String) -> Unit +private fun PluginIconButton( + icon: ImageVector, + contentDescription: String? = null, + tint: Color = Color.White.copy(alpha = 0.68f), + onClick: () -> Unit ) { - var url by remember { mutableStateOf("") } - AlertDialog( - onDismissRequest = onDismiss, - title = { Text(AppStrings.t(language, "settings.plugins.add_repository")) }, - text = { - TextField( - value = url, - onValueChange = { url = it }, - placeholder = { Text(AppStrings.t(language, "settings.plugins.repository_url_placeholder")) }, - label = { Text(AppStrings.t(language, "settings.plugins.repository_url")) }, - singleLine = true, - colors = TextFieldDefaults.colors( - focusedContainerColor = Color.White.copy(alpha = 0.05f), - unfocusedContainerColor = Color.White.copy(alpha = 0.05f), - focusedTextColor = Color.White, - unfocusedTextColor = Color.White - ) - ) - }, - confirmButton = { - TextButton(onClick = { onConfirm(url) }, enabled = url.isNotBlank()) { - Text(AppStrings.t(language, "settings.plugins.add")) - } - }, - dismissButton = { - TextButton(onClick = onDismiss) { - Text(AppStrings.t(language, "settings.plugins.cancel")) - } - } - ) + var focused by remember { mutableStateOf(false) } + Box( + modifier = Modifier + .size(36.dp) + .clip(CircleShape) + .onFocusChanged { focused = it.isFocused } + .background(if (focused) Color.White else Color.Transparent) + .clickable(onClick = onClick), + contentAlignment = Alignment.Center + ) { + Icon( + icon, + contentDescription = contentDescription, + tint = if (focused) Color.Black else tint, + modifier = Modifier.size(18.dp) + ) + } } diff --git a/app/src/main/java/com/fluxa/app/ui/settings/PluginsSettingsViewModel.kt b/app/src/main/java/com/fluxa/app/ui/settings/PluginsSettingsViewModel.kt index 7aa7c8e..5b72f81 100644 --- a/app/src/main/java/com/fluxa/app/ui/settings/PluginsSettingsViewModel.kt +++ b/app/src/main/java/com/fluxa/app/ui/settings/PluginsSettingsViewModel.kt @@ -43,6 +43,10 @@ class PluginsSettingsViewModel @Inject constructor( viewModelScope.launch { manager.removeRepository(manifestUrl) } } + fun refreshRepository(manifestUrl: String) { + viewModelScope.launch { manager.refreshRepository(manifestUrl) } + } + fun toggleScraper(scraperId: String, enabled: Boolean) { viewModelScope.launch { manager.toggleScraper(scraperId, enabled) } } diff --git a/core/src/commonMain/resources/i18n/english_us.json b/core/src/commonMain/resources/i18n/english_us.json index ee5bc12..091b160 100644 --- a/core/src/commonMain/resources/i18n/english_us.json +++ b/core/src/commonMain/resources/i18n/english_us.json @@ -282,9 +282,8 @@ "settings.torrent_speed_default": "Default", "settings.torrent_speed_fast": "Fast", "settings.torrent_speed_ultra_fast": "Ultra Fast", - "settings.plugins.manage": "Scraper Plugins", - "settings.plugins.title": "Scraper Plugins", - "settings.plugins.repositories": "Repositories", + "settings.plugins.manage": "Plugins", + "settings.plugins.title": "Plugins", "settings.plugins.add_repository": "Add Repository", "settings.plugins.repository_url": "Repository manifest URL", "settings.plugins.repository_url_placeholder": "https://example.com/repo.json", @@ -292,11 +291,8 @@ "settings.plugins.cancel": "Cancel", "settings.plugins.remove": "Remove", "settings.plugins.refresh": "Refresh", - "settings.plugins.scrapers": "Scrapers", "settings.plugins.no_repositories": "No repositories added yet.", - "settings.plugins.no_scrapers": "No scrapers available.", "settings.plugins.scraper_count": "%s scrapers", - "settings.plugins.adding": "Adding repository…", "settings.plugins.error": "Failed to add repository: %s", "settings.plugins.settings": "Settings", "settings.plugins.settings_title": "%s Settings", @@ -1128,5 +1124,7 @@ "settings.bottom_bar_labels_desc": "Display destination names below navigation icons.", "settings.home_top_bar": "Home top bar", "settings.home_top_bar_desc": "Show Home, Series, Movies, notifications, and profile above the hero.", - "common.add_to_library": "Add to Library" + "common.add_to_library": "Add to Library", + "settings.plugins.installed_repositories": "Plugin Repositories", + "settings.plugins.adding": "Adding repository…" } diff --git a/core/src/commonMain/resources/i18n/tr_tr.json b/core/src/commonMain/resources/i18n/tr_tr.json index 598c82b..4d58190 100644 --- a/core/src/commonMain/resources/i18n/tr_tr.json +++ b/core/src/commonMain/resources/i18n/tr_tr.json @@ -282,9 +282,8 @@ "settings.torrent_speed_default": "Varsayılan", "settings.torrent_speed_fast": "Hızlı", "settings.torrent_speed_ultra_fast": "Ultra Hızlı", - "settings.plugins.manage": "Kazıyıcı Eklentiler", - "settings.plugins.title": "Kazıyıcı Eklentiler", - "settings.plugins.repositories": "Depolar", + "settings.plugins.manage": "Eklentiler", + "settings.plugins.title": "Eklentiler", "settings.plugins.add_repository": "Depo Ekle", "settings.plugins.repository_url": "Depo manifest URL'si", "settings.plugins.repository_url_placeholder": "https://example.com/repo.json", @@ -292,11 +291,8 @@ "settings.plugins.cancel": "İptal", "settings.plugins.remove": "Kaldır", "settings.plugins.refresh": "Yenile", - "settings.plugins.scrapers": "Kazıyıcılar", "settings.plugins.no_repositories": "Henüz depo eklenmedi.", - "settings.plugins.no_scrapers": "Kullanılabilir kazıyıcı yok.", "settings.plugins.scraper_count": "%s kazıyıcı", - "settings.plugins.adding": "Depo ekleniyor…", "settings.plugins.error": "Depo eklenemedi: %s", "settings.plugins.settings": "Ayarlar", "settings.plugins.settings_title": "%s Ayarları", @@ -1128,5 +1124,7 @@ "settings.bottom_bar_labels_desc": "Gezinme simgelerinin altında hedef adlarını gösterir.", "settings.home_top_bar": "Ana sayfa üst çubuğu", "settings.home_top_bar_desc": "Hero alanının üzerinde Ana Sayfa, Diziler, Filmler, bildirimler ve profili gösterir.", - "common.add_to_library": "Kitaplığa ekle" + "common.add_to_library": "Kitaplığa ekle", + "settings.plugins.installed_repositories": "Eklenti Depoları", + "settings.plugins.adding": "Depo ekleniyor…" }