diff --git a/composeApp/src/commonMain/composeResources/values-es/strings.xml b/composeApp/src/commonMain/composeResources/values-es/strings.xml index 421b1531..725a89a0 100644 --- a/composeApp/src/commonMain/composeResources/values-es/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-es/strings.xml @@ -90,6 +90,9 @@ Elige los catálogos del complemento que debe agrupar esta carpeta. Seleccionar catálogos Seleccionar género + %1$d seleccionados + %1$d catálogos + %1$d seleccionados Póster Cuadrado Panorámico @@ -102,6 +105,121 @@ Filas Pestañas Modo de vista + Fuentes de TMDB + Lista pública + Producción + Cadena + Colección + Personalizado + Elige una fuente preparada. Puedes editarla o quitarla después de añadirla. + Pega una URL de lista pública de TMDB o solo el número de la URL. + Busca por nombre de estudio, o pega un ID/URL de compañía de TMDB y añádelo directamente. + Introduce un ID de cadena. Las cadenas comunes están disponibles en ajustes predefinidos y filtros rápidos. + Busca el nombre de una colección de películas o pega el ID de colección de TMDB. + Crea una fila dinámica de TMDB con filtros opcionales. Deja los campos vacíos cuando no necesites ese filtro. + Lista pública de TMDB + ID de cadena + ID de colección + Nombre, ID o URL de compañía de producción + ID o URL de TMDB + https://www.themoviedb.org/list/8504994 o 8504994 + 213 para Netflix, 49 para HBO, 2739 para Disney+ + 10 para Star Wars Collection + Marvel Studios, 420 o URL de compañía + Ejemplos: Marvel Studios, 420 o https://www.themoviedb.org/company/420. + Ejemplo: Star Wars Collection, Harry Potter Collection o una URL de colección. + IDs de ejemplo: Netflix 213, HBO 49, Disney+ 2739. + Ejemplo: https://www.themoviedb.org/list/8504994 o 8504994. + Título visible + Se muestra como nombre de fila/pestaña. Si queda vacío, Nuvio crea uno desde la fuente. + Películas de Marvel, Originales de Netflix, Pixar + Mejores películas de acción, dramas coreanos, animación 2024 + Resultados de búsqueda + Colección de TMDB + Compañía de TMDB %1$d + Colección de TMDB %1$d + Tipo + Películas + Series + Ambos + Orden + Filtros + Deja los campos vacíos cuando no necesites ese filtro. + Géneros rápidos + Idiomas rápidos + Países rápidos + Palabras clave rápidas + Estudios rápidos + Cadenas rápidas + IDs de género + Usa números de género de TMDB. Separa varios con comas para AND, o barras verticales para OR. + Fecha de estreno o emisión desde + Fecha de estreno o emisión hasta + Usa YYYY-MM-DD, por ejemplo 2024-01-01. + Calificación mínima + Calificación máxima + Calificación de TMDB de 0 a 10. Ejemplo: 7.0. + Votos mínimos + Úsalo para evitar títulos poco conocidos con pocos votos. Ejemplo: 100. + Idioma original + Usa códigos de idioma de dos letras, por ejemplo en, ko, ja, hi. + País de origen + Usa códigos de país de dos letras, por ejemplo US, KR, JP, IN. + IDs de palabra clave + Usa números de palabra clave de TMDB. Los chips rápidos rellenan ejemplos comunes. + 9715 para superhéroes + IDs de compañía + Usa IDs de estudio/compañía. Los chips rápidos rellenan ejemplos comunes. + 420 para Marvel Studios + IDs de cadena + Solo para series. Usa IDs de cadena como Netflix 213 o HBO 49. + 213 para Netflix + Año + Usa un año de cuatro dígitos, por ejemplo 2024. + Predefinidos + Buscar + Añadir fuente + Acción + Aventura + Animación + Comedia + Terror + Ciencia ficción + Drama + Crimen + Reality + Inglés + Coreano + Japonés + Hindi + Español + Estados Unidos + Corea + Japón + India + Reino Unido + Superhéroes + Basado en novela + Viaje en el tiempo + Espacio + Marvel + Disney + Pixar + Lucasfilm + Warner Bros. + Netflix + HBO + Disney+ + Prime Video + Hulu + Popular + Mejor valoradas + Reciente + Lista de TMDB + Colección de películas de TMDB + Producción + Cadena + Discover de TMDB Crea una para organizar tus catálogos. Aún no hay colecciones %1$d carpeta(s) diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index 842bef80..7ddc8923 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -90,6 +90,9 @@ Choose the addon catalogs this folder should aggregate. Select Catalogs Select genre + %1$d selected + %1$d catalogs + %1$d selected Poster Square Wide @@ -102,6 +105,121 @@ Rows Tabs View Mode + TMDB Sources + Public List + Production + Network + Collection + Custom + Pick a ready-made source. You can edit or remove it after adding. + Paste a public TMDB list URL or only the number from the URL. + Search by studio name, or paste a TMDB company ID/URL and add it directly. + Enter a network ID. Common networks are available in Presets and quick filters. + Search a movie collection name or paste the collection ID from TMDB. + Build a live TMDB row using optional filters. Leave fields empty when you do not need that filter. + Public TMDB list + Network ID + Collection ID + Production company name, ID, or URL + TMDB ID or URL + https://www.themoviedb.org/list/8504994 or 8504994 + 213 for Netflix, 49 for HBO, 2739 for Disney+ + 10 for Star Wars Collection + Marvel Studios, 420, or company URL + Examples: Marvel Studios, 420, or https://www.themoviedb.org/company/420. + Example: Star Wars Collection, Harry Potter Collection, or a collection URL. + Example IDs: Netflix 213, HBO 49, Disney+ 2739. + Example: https://www.themoviedb.org/list/8504994 or 8504994. + Display title + Shown as the row/tab name. If blank, Nuvio creates one from the source. + Marvel Movies, Netflix Originals, Pixar + Best Action Movies, Korean Dramas, 2024 Animation + Search Results + TMDB Collection + TMDB Company %1$d + TMDB Collection %1$d + Type + Movies + Series + Both + Sort + Filters + Leave fields empty when you do not need that filter. + Quick genres + Quick languages + Quick countries + Quick keywords + Quick studios + Quick networks + Genre IDs + Use TMDB genre numbers. Separate multiple with commas for AND, or pipes for OR. + Release or air date from + Release or air date to + Use YYYY-MM-DD, for example 2024-01-01. + Minimum rating + Maximum rating + TMDB rating from 0 to 10. Example: 7.0. + Minimum votes + Use this to avoid obscure low-vote titles. Example: 100. + Original language + Use two-letter language codes, for example en, ko, ja, hi. + Origin country + Use two-letter country codes, for example US, KR, JP, IN. + Keyword IDs + Use TMDB keyword numbers. Quick chips fill common examples. + 9715 for superhero + Company IDs + Use studio/company IDs. Quick chips fill common examples. + 420 for Marvel Studios + Network IDs + For series only. Use network IDs like Netflix 213 or HBO 49. + 213 for Netflix + Year + Use a four-digit year, for example 2024. + Presets + Search + Add Source + Action + Adventure + Animation + Comedy + Horror + Sci-Fi + Drama + Crime + Reality + English + Korean + Japanese + Hindi + Spanish + United States + Korea + Japan + India + United Kingdom + Superhero + Based on Novel + Time Travel + Space + Marvel + Disney + Pixar + Lucasfilm + Warner Bros. + Netflix + HBO + Disney+ + Prime Video + Hulu + Popular + Top Rated + Recent + TMDB List + TMDB Movie Collection + Production + Network + TMDB Discover Create one to organize your catalogs. No collections yet %1$d folder(s) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorScreen.kt index 15b2a28a..41ee6532 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorScreen.kt @@ -714,7 +714,7 @@ private fun FolderEditorPage( modifier = Modifier.size(18.dp), ) Spacer(modifier = Modifier.width(4.dp)) - Text("TMDB") + Text(stringResource(Res.string.source_tmdb)) } TextButton(onClick = { CollectionEditorRepository.showCatalogPicker() }) { Icon( @@ -829,7 +829,7 @@ private fun CatalogPickerScreen( color = MaterialTheme.colorScheme.onSurfaceVariant, ) Text( - text = "${selectedSources.size} selected", + text = stringResource(Res.string.collections_editor_selected_count, selectedSources.size), style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.SemiBold, color = MaterialTheme.colorScheme.primary, @@ -850,7 +850,11 @@ private fun CatalogPickerScreen( } PickerPanel( title = addonName, - subtitle = if (selectedCount > 0) "$selectedCount selected" else "${catalogs.size} catalogs", + subtitle = if (selectedCount > 0) { + stringResource(Res.string.collections_editor_catalog_selected_count, selectedCount) + } else { + stringResource(Res.string.collections_editor_catalog_count, catalogs.size) + }, ) { catalogs.forEachIndexed { index, catalog -> val isSelected = selectedSources.any { @@ -896,6 +900,12 @@ private fun TmdbSourcePickerScreen( TmdbBuilderMode.DISCOVER -> TmdbCollectionSourceType.DISCOVER } val requiresId = sourceType != TmdbCollectionSourceType.DISCOVER + val showMediaControls = state.tmdbBuilderMode == TmdbBuilderMode.PRODUCTION || + state.tmdbBuilderMode == TmdbBuilderMode.DISCOVER + val showSortControls = state.tmdbBuilderMode == TmdbBuilderMode.PRODUCTION || + state.tmdbBuilderMode == TmdbBuilderMode.NETWORK || + state.tmdbBuilderMode == TmdbBuilderMode.DISCOVER + val showFilterControls = state.tmdbBuilderMode == TmdbBuilderMode.DISCOVER PlatformBackHandler(enabled = true) { onBack() @@ -905,7 +915,7 @@ private fun TmdbSourcePickerScreen( NuvioScreen(modifier = Modifier.fillMaxSize()) { stickyHeader { NuvioScreenHeader( - title = "TMDB Sources", + title = stringResource(Res.string.collections_editor_tmdb_sources), onBack = onBack, ) } @@ -957,11 +967,11 @@ private fun TmdbSourcePickerScreen( ) } TmdbLabeledField( - label = "Display title", + label = stringResource(Res.string.collections_editor_tmdb_display_title), value = state.tmdbTitleInput, onValueChange = { CollectionEditorRepository.setTmdbTitleInput(it) }, placeholder = tmdbTitlePlaceholder(state.tmdbBuilderMode), - helper = "Shown as the row/tab name. If blank, Nuvio creates one from the source.", + helper = stringResource(Res.string.collections_editor_tmdb_title_helper), ) if (state.tmdbSearchError != null) { Text( @@ -976,20 +986,25 @@ private fun TmdbSourcePickerScreen( if (state.tmdbBuilderMode == TmdbBuilderMode.PRODUCTION && state.tmdbCompanyResults.isNotEmpty()) { item { - PickerSectionLabel("Search Results") + PickerSectionLabel(stringResource(Res.string.collections_editor_tmdb_search_results)) } itemsIndexed(state.tmdbCompanyResults) { _, result -> - val title = result.name ?: "TMDB Company ${result.id}" + val title = result.name ?: stringResource(Res.string.collections_editor_tmdb_company_fallback, result.id) + val movieSuffix = stringResource(Res.string.collections_editor_tmdb_movies) + val seriesSuffix = stringResource(Res.string.collections_editor_tmdb_series) PickerOptionRow( title = title, - subtitle = listOfNotNull("Production", result.originCountry).joinToString(" • "), + subtitle = listOfNotNull( + stringResource(Res.string.collections_editor_tmdb_subtitle_production), + result.originCountry, + ).joinToString(" • "), selected = false, onClick = { val sources = tmdbSelectedMediaTypes(state).map { mediaType -> CollectionSource( provider = "tmdb", tmdbSourceType = TmdbCollectionSourceType.COMPANY.name, - title = tmdbTitleForMedia(title, mediaType, state.tmdbMediaBoth), + title = tmdbTitleForMedia(title, mediaType, state.tmdbMediaBoth, movieSuffix, seriesSuffix), tmdbId = result.id, mediaType = mediaType.name, sortBy = state.tmdbSortBy, @@ -1004,13 +1019,13 @@ private fun TmdbSourcePickerScreen( if (state.tmdbBuilderMode == TmdbBuilderMode.COLLECTION && state.tmdbCollectionResults.isNotEmpty()) { item { - PickerSectionLabel("Search Results") + PickerSectionLabel(stringResource(Res.string.collections_editor_tmdb_search_results)) } itemsIndexed(state.tmdbCollectionResults) { _, result -> - val title = result.name ?: "TMDB Collection ${result.id}" + val title = result.name ?: stringResource(Res.string.collections_editor_tmdb_collection_fallback, result.id) PickerOptionRow( title = title, - subtitle = "TMDB Movie Collection", + subtitle = stringResource(Res.string.collections_editor_tmdb_collection), selected = false, onClick = { CollectionEditorRepository.addTmdbSource( @@ -1028,11 +1043,10 @@ private fun TmdbSourcePickerScreen( } } - if (sourceType == TmdbCollectionSourceType.COMPANY || sourceType == TmdbCollectionSourceType.DISCOVER) { + if (showMediaControls) { item { PickerPanel( - title = "Media", - subtitle = "Create one source or split it into movie and series feeds.", + title = stringResource(Res.string.collections_editor_tmdb_type), ) { FlowRow( horizontalArrangement = Arrangement.spacedBy(8.dp), @@ -1044,7 +1058,7 @@ private fun TmdbSourcePickerScreen( CollectionEditorRepository.setTmdbMediaBoth(false) CollectionEditorRepository.setTmdbMediaType(TmdbCollectionMediaType.MOVIE) }, - label = { Text("Movies") }, + label = { Text(stringResource(Res.string.collections_editor_tmdb_movies)) }, ) FilterChip( selected = state.tmdbMediaType == TmdbCollectionMediaType.TV && !state.tmdbMediaBoth, @@ -1052,26 +1066,22 @@ private fun TmdbSourcePickerScreen( CollectionEditorRepository.setTmdbMediaBoth(false) CollectionEditorRepository.setTmdbMediaType(TmdbCollectionMediaType.TV) }, - label = { Text("Series") }, + label = { Text(stringResource(Res.string.collections_editor_tmdb_series)) }, ) FilterChip( selected = state.tmdbMediaBoth, onClick = { CollectionEditorRepository.setTmdbMediaBoth(true) }, - label = { Text("Both") }, + label = { Text(stringResource(Res.string.collections_editor_tmdb_both)) }, ) } } } } - if (sourceType == TmdbCollectionSourceType.COMPANY || - sourceType == TmdbCollectionSourceType.NETWORK || - sourceType == TmdbCollectionSourceType.DISCOVER - ) { + if (showSortControls) { item { PickerPanel( - title = "Sort", - subtitle = "Controls the default order TMDB returns.", + title = stringResource(Res.string.collections_editor_tmdb_sort), ) { FlowRow( horizontalArrangement = Arrangement.spacedBy(8.dp), @@ -1096,23 +1106,27 @@ private fun TmdbSourcePickerScreen( } } } + } + if (showFilterControls) { item { PickerPanel( - title = "Filters", - subtitle = "Combine TMDB IDs and date/rating constraints for exact feeds.", + title = stringResource(Res.string.collections_editor_tmdb_filters), + subtitle = stringResource(Res.string.collections_editor_tmdb_filters_helper), ) { Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { TmdbQuickChips( - label = "Quick genres", + label = stringResource(Res.string.collections_editor_tmdb_quick_genres), chips = tmdbGenreQuickChips(state.tmdbMediaType), onSelect = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withGenres = value) } }, ) TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_genres), + helper = stringResource(Res.string.collections_editor_tmdb_genres_helper), value = state.tmdbFilters.withGenres.orEmpty(), - placeholder = "Genre IDs, comma-separated", + placeholder = if (state.tmdbMediaType == TmdbCollectionMediaType.MOVIE) "28,12" else "18,35", onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withGenres = value.ifBlank { null }) @@ -1120,17 +1134,10 @@ private fun TmdbSourcePickerScreen( }, ) TmdbFilterField( - value = state.tmdbFilters.year?.toString().orEmpty(), - placeholder = "Year", - onValueChange = { value -> - CollectionEditorRepository.updateTmdbFilters { - it.copy(year = value.toIntOrNull()) - } - }, - ) - TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_date_from), + helper = stringResource(Res.string.collections_editor_tmdb_date_helper), value = state.tmdbFilters.releaseDateGte.orEmpty(), - placeholder = "Release from YYYY-MM-DD", + placeholder = "2020-01-01", onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(releaseDateGte = value.ifBlank { null }) @@ -1138,8 +1145,10 @@ private fun TmdbSourcePickerScreen( }, ) TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_date_to), + helper = stringResource(Res.string.collections_editor_tmdb_date_helper), value = state.tmdbFilters.releaseDateLte.orEmpty(), - placeholder = "Release until YYYY-MM-DD", + placeholder = "2024-12-31", onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(releaseDateLte = value.ifBlank { null }) @@ -1147,8 +1156,10 @@ private fun TmdbSourcePickerScreen( }, ) TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_rating_min), + helper = stringResource(Res.string.collections_editor_tmdb_rating_helper), value = state.tmdbFilters.voteAverageGte?.toString().orEmpty(), - placeholder = "Minimum rating", + placeholder = "7.0", onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(voteAverageGte = value.toDoubleOrNull()) @@ -1156,33 +1167,45 @@ private fun TmdbSourcePickerScreen( }, ) TmdbFilterField( - value = state.tmdbFilters.voteCountGte?.toString().orEmpty(), - placeholder = "Minimum vote count", - onValueChange = { value -> - CollectionEditorRepository.updateTmdbFilters { - it.copy(voteCountGte = value.toIntOrNull()) - } - }, - ) - TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_rating_max), + helper = stringResource(Res.string.collections_editor_tmdb_rating_helper), value = state.tmdbFilters.voteAverageLte?.toString().orEmpty(), - placeholder = "Maximum rating", + placeholder = "10", onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(voteAverageLte = value.toDoubleOrNull()) } }, ) + TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_votes_min), + helper = stringResource(Res.string.collections_editor_tmdb_votes_helper), + value = state.tmdbFilters.voteCountGte?.toString().orEmpty(), + placeholder = "100", + onValueChange = { value -> + CollectionEditorRepository.updateTmdbFilters { + it.copy(voteCountGte = value.toIntOrNull()) + } + }, + ) TmdbQuickChips( - label = "Quick languages", - chips = listOf("English" to "en", "Korean" to "ko", "Japanese" to "ja", "Hindi" to "hi", "Spanish" to "es"), + label = stringResource(Res.string.collections_editor_tmdb_quick_languages), + chips = listOf( + stringResource(Res.string.collections_editor_tmdb_language_english) to "en", + stringResource(Res.string.collections_editor_tmdb_language_korean) to "ko", + stringResource(Res.string.collections_editor_tmdb_language_japanese) to "ja", + stringResource(Res.string.collections_editor_tmdb_language_hindi) to "hi", + stringResource(Res.string.collections_editor_tmdb_language_spanish) to "es", + ), onSelect = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withOriginalLanguage = value) } }, ) TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_language), + helper = stringResource(Res.string.collections_editor_tmdb_language_helper), value = state.tmdbFilters.withOriginalLanguage.orEmpty(), - placeholder = "Original language, e.g. en", + placeholder = "en, ko, ja, hi", onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withOriginalLanguage = value.ifBlank { null }) @@ -1190,15 +1213,23 @@ private fun TmdbSourcePickerScreen( }, ) TmdbQuickChips( - label = "Quick countries", - chips = listOf("United States" to "US", "Korea" to "KR", "Japan" to "JP", "India" to "IN", "United Kingdom" to "GB"), + label = stringResource(Res.string.collections_editor_tmdb_quick_countries), + chips = listOf( + stringResource(Res.string.collections_editor_tmdb_country_us) to "US", + stringResource(Res.string.collections_editor_tmdb_country_korea) to "KR", + stringResource(Res.string.collections_editor_tmdb_country_japan) to "JP", + stringResource(Res.string.collections_editor_tmdb_country_india) to "IN", + stringResource(Res.string.collections_editor_tmdb_country_uk) to "GB", + ), onSelect = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withOriginCountry = value) } }, ) TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_country), + helper = stringResource(Res.string.collections_editor_tmdb_country_helper), value = state.tmdbFilters.withOriginCountry.orEmpty(), - placeholder = "Origin country, e.g. US", + placeholder = "US, KR, JP, IN", onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withOriginCountry = value.ifBlank { null }) @@ -1206,15 +1237,22 @@ private fun TmdbSourcePickerScreen( }, ) TmdbQuickChips( - label = "Quick keywords", - chips = listOf("Superhero" to "9715", "Based on Novel" to "818", "Time Travel" to "4379", "Space" to "9882"), + label = stringResource(Res.string.collections_editor_tmdb_quick_keywords), + chips = listOf( + stringResource(Res.string.collections_editor_tmdb_keyword_superhero) to "9715", + stringResource(Res.string.collections_editor_tmdb_keyword_based_on_novel) to "818", + stringResource(Res.string.collections_editor_tmdb_keyword_time_travel) to "4379", + stringResource(Res.string.collections_editor_tmdb_keyword_space) to "9882", + ), onSelect = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withKeywords = value) } }, ) TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_keywords), + helper = stringResource(Res.string.collections_editor_tmdb_keywords_helper), value = state.tmdbFilters.withKeywords.orEmpty(), - placeholder = "Keyword IDs", + placeholder = stringResource(Res.string.collections_editor_tmdb_keywords_placeholder), onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withKeywords = value.ifBlank { null }) @@ -1222,15 +1260,23 @@ private fun TmdbSourcePickerScreen( }, ) TmdbQuickChips( - label = "Quick companies", - chips = listOf("Marvel" to "420", "Disney" to "2", "Pixar" to "3", "Lucasfilm" to "1", "Warner Bros." to "174"), + label = stringResource(Res.string.collections_editor_tmdb_quick_studios), + chips = listOf( + stringResource(Res.string.collections_editor_tmdb_studio_marvel) to "420", + stringResource(Res.string.collections_editor_tmdb_studio_disney) to "2", + stringResource(Res.string.collections_editor_tmdb_studio_pixar) to "3", + stringResource(Res.string.collections_editor_tmdb_studio_lucasfilm) to "1", + stringResource(Res.string.collections_editor_tmdb_studio_warner) to "174", + ), onSelect = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withCompanies = value) } }, ) TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_companies), + helper = stringResource(Res.string.collections_editor_tmdb_companies_helper), value = state.tmdbFilters.withCompanies.orEmpty(), - placeholder = "Company IDs, e.g. 420", + placeholder = stringResource(Res.string.collections_editor_tmdb_companies_placeholder), onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withCompanies = value.ifBlank { null }) @@ -1238,28 +1284,47 @@ private fun TmdbSourcePickerScreen( }, ) TmdbQuickChips( - label = "Quick networks", - chips = listOf("Netflix" to "213", "HBO" to "49", "Disney+" to "2739", "Prime Video" to "1024", "Hulu" to "453"), + label = stringResource(Res.string.collections_editor_tmdb_quick_networks), + chips = listOf( + stringResource(Res.string.collections_editor_tmdb_network_netflix) to "213", + stringResource(Res.string.collections_editor_tmdb_network_hbo) to "49", + stringResource(Res.string.collections_editor_tmdb_network_disney_plus) to "2739", + stringResource(Res.string.collections_editor_tmdb_network_prime_video) to "1024", + stringResource(Res.string.collections_editor_tmdb_network_hulu) to "453", + ), onSelect = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withNetworks = value) } }, ) TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_networks), + helper = stringResource(Res.string.collections_editor_tmdb_networks_helper), value = state.tmdbFilters.withNetworks.orEmpty(), - placeholder = "Network IDs, e.g. 213", + placeholder = stringResource(Res.string.collections_editor_tmdb_networks_placeholder), onValueChange = { value -> CollectionEditorRepository.updateTmdbFilters { it.copy(withNetworks = value.ifBlank { null }) } }, ) + TmdbFilterField( + label = stringResource(Res.string.collections_editor_tmdb_year), + helper = stringResource(Res.string.collections_editor_tmdb_year_helper), + value = state.tmdbFilters.year?.toString().orEmpty(), + placeholder = "2024", + onValueChange = { value -> + CollectionEditorRepository.updateTmdbFilters { + it.copy(year = value.toIntOrNull()) + } + }, + ) } } } } if (state.tmdbBuilderMode == TmdbBuilderMode.PRESETS) item { - PickerSectionLabel("Presets") + PickerSectionLabel(stringResource(Res.string.collections_editor_tmdb_presets)) } if (state.tmdbBuilderMode == TmdbBuilderMode.PRESETS) { itemsIndexed(TmdbCollectionSourceResolver.presets()) { _, preset -> @@ -1313,11 +1378,11 @@ private fun TmdbSourcePickerScreen( modifier = Modifier.size(18.dp), ) Spacer(modifier = Modifier.width(4.dp)) - Text("Search") + Text(stringResource(Res.string.collections_editor_tmdb_search)) } } NuvioPrimaryButton( - text = "Add TMDB source", + text = stringResource(Res.string.collections_editor_add_source), modifier = Modifier.weight(1f), enabled = !requiresId || state.tmdbInput.isNotBlank(), onClick = { CollectionEditorRepository.addTmdbSourceFromInput() }, @@ -1510,23 +1575,24 @@ private fun TmdbQuickChips( } } +@Composable private fun tmdbGenreQuickChips(mediaType: TmdbCollectionMediaType): List> = when (mediaType) { TmdbCollectionMediaType.MOVIE -> listOf( - "Action" to "28", - "Adventure" to "12", - "Animation" to "16", - "Comedy" to "35", - "Horror" to "27", - "Sci-Fi" to "878", + stringResource(Res.string.collections_editor_tmdb_genre_action) to "28", + stringResource(Res.string.collections_editor_tmdb_genre_adventure) to "12", + stringResource(Res.string.collections_editor_tmdb_genre_animation) to "16", + stringResource(Res.string.collections_editor_tmdb_genre_comedy) to "35", + stringResource(Res.string.collections_editor_tmdb_genre_horror) to "27", + stringResource(Res.string.collections_editor_tmdb_genre_scifi) to "878", ) TmdbCollectionMediaType.TV -> listOf( - "Drama" to "18", - "Comedy" to "35", - "Animation" to "16", - "Crime" to "80", - "Sci-Fi" to "10765", - "Reality" to "10764", + stringResource(Res.string.collections_editor_tmdb_genre_drama) to "18", + stringResource(Res.string.collections_editor_tmdb_genre_comedy) to "35", + stringResource(Res.string.collections_editor_tmdb_genre_animation) to "16", + stringResource(Res.string.collections_editor_tmdb_genre_crime) to "80", + stringResource(Res.string.collections_editor_tmdb_genre_scifi) to "10765", + stringResource(Res.string.collections_editor_tmdb_genre_reality) to "10764", ) } @@ -1541,11 +1607,13 @@ private fun tmdbTitleForMedia( title: String, mediaType: TmdbCollectionMediaType, addSuffix: Boolean, + movieSuffix: String, + seriesSuffix: String, ): String { if (!addSuffix) return title val suffix = when (mediaType) { - TmdbCollectionMediaType.MOVIE -> "Movies" - TmdbCollectionMediaType.TV -> "Series" + TmdbCollectionMediaType.MOVIE -> movieSuffix + TmdbCollectionMediaType.TV -> seriesSuffix } return "$title $suffix" } @@ -1687,7 +1755,7 @@ private fun FolderTmdbSourceCard( Row(verticalAlignment = Alignment.CenterVertically) { Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(2.dp)) { Text( - text = source.title?.takeIf { it.isNotBlank() } ?: "TMDB", + text = source.title?.takeIf { it.isNotBlank() } ?: stringResource(Res.string.source_tmdb), style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Medium, color = MaterialTheme.colorScheme.onSurface, @@ -1695,7 +1763,7 @@ private fun FolderTmdbSourceCard( overflow = TextOverflow.Ellipsis, ) Text( - text = "TMDB", + text = stringResource(Res.string.source_tmdb), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -1816,41 +1884,106 @@ private fun FolderCatalogSourceCard( } } +@Composable private fun tmdbBuilderModeLabel(mode: TmdbBuilderMode): String = when (mode) { - TmdbBuilderMode.PRESETS -> "Presets" - TmdbBuilderMode.LIST -> "List" - TmdbBuilderMode.COLLECTION -> "Collection" - TmdbBuilderMode.PRODUCTION -> "Production" - TmdbBuilderMode.NETWORK -> "Network" - TmdbBuilderMode.DISCOVER -> "Discover" + TmdbBuilderMode.PRESETS -> stringResource(Res.string.collections_editor_tmdb_presets) + TmdbBuilderMode.LIST -> stringResource(Res.string.collections_editor_tmdb_public_list_mode) + TmdbBuilderMode.PRODUCTION -> stringResource(Res.string.collections_editor_tmdb_production_mode) + TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_network_mode) + TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_collection_mode) + TmdbBuilderMode.DISCOVER -> stringResource(Res.string.collections_editor_tmdb_custom_mode) } +@Composable +private fun tmdbModeHelpText(mode: TmdbBuilderMode): String = + when (mode) { + TmdbBuilderMode.PRESETS -> stringResource(Res.string.collections_editor_tmdb_help_presets) + TmdbBuilderMode.LIST -> stringResource(Res.string.collections_editor_tmdb_help_list) + TmdbBuilderMode.PRODUCTION -> stringResource(Res.string.collections_editor_tmdb_help_production) + TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_help_network) + TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_help_collection) + TmdbBuilderMode.DISCOVER -> stringResource(Res.string.collections_editor_tmdb_help_discover) + } + +@Composable +private fun tmdbInputLabel(mode: TmdbBuilderMode): String = + when (mode) { + TmdbBuilderMode.LIST -> stringResource(Res.string.collections_editor_tmdb_public_list) + TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_network_id) + TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_collection_id) + TmdbBuilderMode.PRODUCTION -> stringResource(Res.string.collections_editor_tmdb_company_search) + else -> stringResource(Res.string.collections_editor_tmdb_id_or_url) + } + +@Composable +private fun tmdbInputPlaceholder(mode: TmdbBuilderMode): String = + when (mode) { + TmdbBuilderMode.LIST -> stringResource(Res.string.collections_editor_tmdb_list_placeholder) + TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_network_placeholder) + TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_collection_placeholder) + TmdbBuilderMode.PRODUCTION -> stringResource(Res.string.collections_editor_tmdb_company_placeholder) + else -> stringResource(Res.string.collections_editor_tmdb_id_or_url) + } + +@Composable +private fun tmdbInputHelper(mode: TmdbBuilderMode): String = + when (mode) { + TmdbBuilderMode.PRODUCTION -> stringResource(Res.string.collections_editor_tmdb_search_helper) + TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_collection_helper) + TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_network_helper) + TmdbBuilderMode.LIST -> stringResource(Res.string.collections_editor_tmdb_list_helper) + else -> "" + } + +@Composable +private fun tmdbTitlePlaceholder(mode: TmdbBuilderMode): String = + when (mode) { + TmdbBuilderMode.DISCOVER -> stringResource(Res.string.collections_editor_tmdb_discover_title_placeholder) + else -> stringResource(Res.string.collections_editor_tmdb_title_placeholder) + } + +@Composable private fun tmdbSortLabel(sort: TmdbCollectionSort): String = when (sort) { - TmdbCollectionSort.POPULAR_DESC -> "Popular" - TmdbCollectionSort.VOTE_AVERAGE_DESC -> "Top rated" - TmdbCollectionSort.RELEASE_DATE_DESC -> "Newest movies" - TmdbCollectionSort.FIRST_AIR_DATE_DESC -> "Newest series" + TmdbCollectionSort.POPULAR_DESC -> stringResource(Res.string.collections_editor_tmdb_sort_popular) + TmdbCollectionSort.VOTE_AVERAGE_DESC -> stringResource(Res.string.collections_editor_tmdb_sort_top_rated) + TmdbCollectionSort.RELEASE_DATE_DESC -> stringResource(Res.string.collections_editor_tmdb_sort_recent) + TmdbCollectionSort.FIRST_AIR_DATE_DESC -> stringResource(Res.string.collections_editor_tmdb_sort_recent) } +@Composable private fun tmdbSourceSubtitle(source: CollectionSource): String { val media = when (TmdbCollectionMediaType.fromString(source.mediaType)) { - TmdbCollectionMediaType.MOVIE -> "Movies" - TmdbCollectionMediaType.TV -> "Series" + TmdbCollectionMediaType.MOVIE -> stringResource(Res.string.collections_editor_tmdb_movies) + TmdbCollectionMediaType.TV -> stringResource(Res.string.collections_editor_tmdb_series) } val sort = source.sortBy?.let { value -> - TmdbCollectionSort.entries.firstOrNull { it.value == value }?.let(::tmdbSortLabel) - } ?: "Popular" + TmdbCollectionSort.entries.firstOrNull { it.value == value }?.let { sort -> + tmdbSortLabel(sort) + } + } ?: stringResource(Res.string.collections_editor_tmdb_sort_popular) val sourceType = runCatching { TmdbCollectionSourceType.valueOf(source.tmdbSourceType.orEmpty()) }.getOrDefault(TmdbCollectionSourceType.DISCOVER) return when (sourceType) { - TmdbCollectionSourceType.LIST -> "TMDB List" - TmdbCollectionSourceType.COLLECTION -> "TMDB Movie Collection" - TmdbCollectionSourceType.COMPANY -> listOf("Production", media, sort).joinToString(" • ") - TmdbCollectionSourceType.NETWORK -> listOf("Network", "Series", sort).joinToString(" • ") - TmdbCollectionSourceType.DISCOVER -> listOf("TMDB Discover", media, sort).joinToString(" • ") + TmdbCollectionSourceType.LIST -> stringResource(Res.string.collections_editor_tmdb_subtitle_list) + TmdbCollectionSourceType.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_subtitle_movie_collection) + TmdbCollectionSourceType.COMPANY -> listOf( + stringResource(Res.string.collections_editor_tmdb_subtitle_production), + media, + sort, + ).joinToString(" • ") + TmdbCollectionSourceType.NETWORK -> listOf( + stringResource(Res.string.collections_editor_tmdb_subtitle_network), + stringResource(Res.string.collections_editor_tmdb_series), + sort, + ).joinToString(" • ") + TmdbCollectionSourceType.DISCOVER -> listOf( + stringResource(Res.string.collections_editor_tmdb_subtitle_discover), + media, + sort, + ).joinToString(" • ") } }