From 05de10c9127d016027e12e1bb809bc31b398d869 Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Sun, 4 Oct 2026 03:19:35 +0000 Subject: [PATCH] clear the build warnings and fail on new ones A clean build now emits no warnings of its own, and Kotlin `allWarningsAsErrors` plus lint `warningsAsErrors` stop new ones from sneaking back in. - Kotlin: give SearchFilter's @StringRes parameter an explicit @param: target; use safe calls for File.parentFile in StringResourcesTest. - Packaging: keep debug symbols for the prebuilt .so files that have no symbol table, which is what the "unable to strip" warning was about. - Lint: move `modifier` to the first optional parameter across the Compose screens, use mutableIntStateOf for int state, read Resources via LocalResources, use the KTX Bitmap.get/String.toUri, drop the unused ic_action_name and ic_stat_name bitmaps and the dead -v24 qualifier on the notification vector, fix the pt-BR "album" accents and the unused Vietnamese/Thai plural quantities, and suppress the intentional cleartext/user-certificate, backup, exported-service and plural-candidate findings. Disable the version-update nags, which the dependency-update process owns. The AboutLibraries plugin still resolves the variant classpaths during configuration, so AGP keeps warning about that one; upstream in mikepenz/AboutLibraries#1369. --- app/build.gradle.kts | 26 +++++++++++++++++- app/src/main/AndroidManifest.xml | 9 ++++-- .../data/download/SystemDownloadEngine.kt | 4 +-- .../ui/components/HeroDetailScaffold.kt | 2 +- .../com/subtracks/ui/home/HomeListScreen.kt | 6 ++-- .../com/subtracks/ui/home/HomeScreen.kt | 4 +-- .../subtracks/ui/library/AlbumDetailScreen.kt | 2 +- .../com/subtracks/ui/library/AlbumsContent.kt | 2 +- .../ui/library/ArtistDetailScreen.kt | 2 +- .../subtracks/ui/library/ArtistsContent.kt | 2 +- .../com/subtracks/ui/library/LibraryScreen.kt | 3 +- .../ui/library/PlaylistDetailScreen.kt | 2 +- .../subtracks/ui/library/PlaylistsContent.kt | 2 +- .../com/subtracks/ui/library/SongsContent.kt | 2 +- .../com/subtracks/ui/playback/MiniPlayer.kt | 2 +- .../subtracks/ui/playback/NowPlayingScreen.kt | 4 +-- .../com/subtracks/ui/playback/QueueScreen.kt | 6 ++-- .../com/subtracks/ui/search/SearchScreen.kt | 4 +-- .../subtracks/ui/settings/AddSourceScreen.kt | 2 +- .../subtracks/ui/settings/SettingsScreen.kt | 5 ++-- .../subtracks/ui/theme/ArtworkSeedCache.kt | 3 +- .../ic_stat_name.xml | 0 .../main/res/drawable-hdpi/ic_action_name.png | Bin 441 -> 0 bytes .../main/res/drawable-hdpi/ic_stat_name.png | Bin 401 -> 0 bytes .../main/res/drawable-mdpi/ic_action_name.png | Bin 318 -> 0 bytes .../main/res/drawable-mdpi/ic_stat_name.png | Bin 284 -> 0 bytes .../res/drawable-xhdpi/ic_action_name.png | Bin 600 -> 0 bytes .../main/res/drawable-xhdpi/ic_stat_name.png | Bin 575 -> 0 bytes .../res/drawable-xxhdpi/ic_action_name.png | Bin 925 -> 0 bytes .../main/res/drawable-xxhdpi/ic_stat_name.png | Bin 921 -> 0 bytes .../media3_notification_small_icon.xml | 4 ++- app/src/main/res/values-b+pt+BR/strings.xml | 6 ++-- app/src/main/res/values-th/strings.xml | 1 - app/src/main/res/values-vi/strings.xml | 2 -- app/src/main/res/values/strings.xml | 6 ++-- .../main/res/xml/network_security_config.xml | 10 +++++-- .../com/subtracks/i18n/StringResourcesTest.kt | 10 +++---- .../com/subtracks/ui/DemoScreenshotTest.kt | 2 +- 38 files changed, 85 insertions(+), 50 deletions(-) rename app/src/main/res/{drawable-anydpi-v24 => drawable-anydpi}/ic_stat_name.xml (100%) delete mode 100644 app/src/main/res/drawable-hdpi/ic_action_name.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_stat_name.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_action_name.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_stat_name.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_action_name.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_name.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_name.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_stat_name.png diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3818a427..d20f3ca8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -43,7 +43,28 @@ android { lint { checkReleaseBuilds = false - disable += setOf("MissingTranslation", "MissingQuantity") + warningsAsErrors = true + disable += + setOf( + "MissingTranslation", + "MissingQuantity", + // Version nags are handled by the dependency-update process, not the build. + "AndroidGradlePluginVersion", + "GradleDependency", + "NewerVersionAvailable", + ) + } + + packaging { + jniLibs { + // Prebuilt .so files with no symbol table; leaving them unstripped avoids the strip warning. + keepDebugSymbols += + setOf( + "**/libandroidx.graphics.path.so", + "**/libdatastore_shared_counter.so", + "**/libsqliteJni.so", + ) + } } testOptions { @@ -71,6 +92,7 @@ android { kotlin { compilerOptions { jvmTarget.set(JvmTarget.JVM_17) + allWarningsAsErrors.set(true) } } @@ -82,6 +104,8 @@ ksp { arg("room.schemaLocation", "$projectDir/schemas") } +// Resolving the variant classpaths here makes AGP warn that a configuration was resolved during +// configuration time; upstream, tracked in mikepenz/AboutLibraries#1369. aboutLibraries { collect { configPath = file("config") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index db459a74..6a1ea6c8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ - + @@ -18,7 +19,8 @@ android:networkSecurityConfig="@xml/network_security_config" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.Subtracks"> + android:theme="@style/Theme.Subtracks" + tools:ignore="DataExtractionRules,UnusedAttribute"> + android:foregroundServiceType="mediaPlayback" + tools:ignore="ExportedService"> diff --git a/app/src/main/kotlin/com/subtracks/data/download/SystemDownloadEngine.kt b/app/src/main/kotlin/com/subtracks/data/download/SystemDownloadEngine.kt index ebaf84f0..77a6df14 100644 --- a/app/src/main/kotlin/com/subtracks/data/download/SystemDownloadEngine.kt +++ b/app/src/main/kotlin/com/subtracks/data/download/SystemDownloadEngine.kt @@ -2,8 +2,8 @@ package com.subtracks.data.download import android.app.DownloadManager import android.content.Context -import android.net.Uri import android.os.Environment +import androidx.core.net.toUri import com.subtracks.data.model.DownloadError class SystemDownloadEngine( @@ -12,7 +12,7 @@ class SystemDownloadEngine( override fun enqueue(request: EngineRequest): Long { val download = DownloadManager - .Request(Uri.parse(request.uri)) + .Request(request.uri.toUri()) .setTitle(request.title) .setDestinationInExternalFilesDir(context, Environment.DIRECTORY_MUSIC, request.path) .setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN) diff --git a/app/src/main/kotlin/com/subtracks/ui/components/HeroDetailScaffold.kt b/app/src/main/kotlin/com/subtracks/ui/components/HeroDetailScaffold.kt index 12d4b86b..33d0b73d 100644 --- a/app/src/main/kotlin/com/subtracks/ui/components/HeroDetailScaffold.kt +++ b/app/src/main/kotlin/com/subtracks/ui/components/HeroDetailScaffold.kt @@ -248,11 +248,11 @@ fun HeroHeader( onDownloadAction: (BulkDownloadAction) -> Unit, onMore: () -> Unit, topInset: Dp, + modifier: Modifier = Modifier, controlsModifier: Modifier = Modifier, thumbnailRef: CoverArtRef? = null, comment: String? = null, onSubtitleClick: (() -> Unit)? = null, - modifier: Modifier = Modifier, ) { Column( modifier = diff --git a/app/src/main/kotlin/com/subtracks/ui/home/HomeListScreen.kt b/app/src/main/kotlin/com/subtracks/ui/home/HomeListScreen.kt index 92197cc5..11cc3a69 100644 --- a/app/src/main/kotlin/com/subtracks/ui/home/HomeListScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/home/HomeListScreen.kt @@ -35,7 +35,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -123,6 +123,7 @@ fun HomeListScreen( artists: LazyPagingItems, songs: LazyPagingItems, playlists: LazyPagingItems, + modifier: Modifier = Modifier, genres: List = emptyList(), decades: List = emptyList(), coverArt: (String?, Boolean) -> CoverArtRef? = { _, _ -> null }, @@ -135,10 +136,9 @@ fun HomeListScreen( onLongClick: (MenuTarget) -> Unit = {}, onGenreClick: (String) -> Unit = {}, onDecadeClick: (Long) -> Unit = {}, - modifier: Modifier = Modifier, ) { val now = remember { System.currentTimeMillis() } - val resources = LocalContext.current.resources + val resources = LocalResources.current Scaffold( modifier = modifier, topBar = { diff --git a/app/src/main/kotlin/com/subtracks/ui/home/HomeScreen.kt b/app/src/main/kotlin/com/subtracks/ui/home/HomeScreen.kt index 88965cad..3ac2f22c 100644 --- a/app/src/main/kotlin/com/subtracks/ui/home/HomeScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/home/HomeScreen.kt @@ -172,6 +172,7 @@ fun HomeScreen( feed: HomeFeed, coverArt: (String?, Boolean) -> CoverArtRef?, playingSongId: String?, + modifier: Modifier = Modifier, topInset: Dp = 0.dp, bottomInset: Dp = 0.dp, onAlbumClick: (Album) -> Unit = {}, @@ -182,7 +183,6 @@ fun HomeScreen( onGenreClick: (String) -> Unit = {}, onDecadeClick: (Long) -> Unit = {}, onSync: () -> Unit = {}, - modifier: Modifier = Modifier, ) { CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) { if (feed.loading) { @@ -295,6 +295,7 @@ fun OfflineHomeScreen( songs: List, coverArt: (String?, Boolean) -> CoverArtRef?, playingSongId: String?, + modifier: Modifier = Modifier, topInset: Dp = 0.dp, bottomInset: Dp = 0.dp, onAlbumClick: (Album) -> Unit = {}, @@ -303,7 +304,6 @@ fun OfflineHomeScreen( onSongPlay: (Song) -> Unit = {}, onLongClick: (MenuTarget) -> Unit = {}, onMore: (OfflineListKind) -> Unit = {}, - modifier: Modifier = Modifier, ) { CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) { LazyColumn( diff --git a/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt index 2293941f..e2c49d52 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt @@ -146,6 +146,7 @@ fun AlbumDetailRoute( fun AlbumDetailScreen( album: Album?, songs: List, + modifier: Modifier = Modifier, discs: List = emptyList(), coverArt: (String?, Boolean) -> CoverArtRef?, artwork: ArtworkColors?, @@ -160,7 +161,6 @@ fun AlbumDetailScreen( onMore: () -> Unit = {}, onArtistClick: (() -> Unit)? = null, playingSongId: String? = null, - modifier: Modifier = Modifier, ) { val multiDisc = songs.map { it.disc ?: 1L }.distinct().size > 1 val resources = LocalResources.current diff --git a/app/src/main/kotlin/com/subtracks/ui/library/AlbumsContent.kt b/app/src/main/kotlin/com/subtracks/ui/library/AlbumsContent.kt index 18712500..375cec4f 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/AlbumsContent.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/AlbumsContent.kt @@ -48,6 +48,7 @@ fun AlbumsContent( coverArt: (String?, Boolean) -> CoverArtRef?, bottomInset: Dp, onAlbumClick: (Album) -> Unit, + modifier: Modifier = Modifier, onLongClick: (MenuTarget) -> Unit = {}, filtered: Boolean = false, onClearFilters: () -> Unit = {}, @@ -55,7 +56,6 @@ fun AlbumsContent( topInset: Dp = 0.dp, onSync: () -> Unit = {}, downloadStatuses: Map = emptyMap(), - modifier: Modifier = Modifier, ) { when { items.itemCount == 0 && items.loadState.refresh is LoadState.Loading -> { diff --git a/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt index 8d0c26ca..386c6bb1 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt @@ -217,6 +217,7 @@ fun ArtistDetailRoute( @Composable fun ArtistDetailScreen( artist: Artist?, + modifier: Modifier = Modifier, artistName: String = "", isAlbumArtist: Boolean = false, albums: List, @@ -232,7 +233,6 @@ fun ArtistDetailScreen( starred: Boolean = false, onToggleStar: (() -> Unit)? = null, onShuffle: () -> Unit = {}, - modifier: Modifier = Modifier, ) { val listState = rememberLazyGridState() val fill = rememberViewportFill(listState) diff --git a/app/src/main/kotlin/com/subtracks/ui/library/ArtistsContent.kt b/app/src/main/kotlin/com/subtracks/ui/library/ArtistsContent.kt index 9334fe81..f1e2aebf 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/ArtistsContent.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/ArtistsContent.kt @@ -45,6 +45,7 @@ fun ArtistsContent( coverArt: (String?, Boolean) -> CoverArtRef?, bottomInset: Dp, onArtistClick: (Artist) -> Unit, + modifier: Modifier = Modifier, onLongClick: (MenuTarget) -> Unit = {}, filtered: Boolean = false, onClearFilters: () -> Unit = {}, @@ -52,7 +53,6 @@ fun ArtistsContent( topInset: Dp = 0.dp, onSync: () -> Unit = {}, downloadStatuses: Map = emptyMap(), - modifier: Modifier = Modifier, ) { when { items.itemCount == 0 && items.loadState.refresh is LoadState.Loading -> { diff --git a/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt index 9b52f895..a32eb928 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt @@ -386,6 +386,7 @@ fun LibraryScreen( onPlaylistClick: (Playlist) -> Unit, onSync: () -> Unit, onOpenSettings: () -> Unit, + modifier: Modifier = Modifier, onOpenSearch: () -> Unit = {}, offline: Boolean = false, onExitOffline: () -> Unit = {}, @@ -409,7 +410,6 @@ fun LibraryScreen( playlistDownloads: Map = emptyMap(), dismissals: Flow = emptyFlow(), homeContent: @Composable (topInset: Dp, bottomInset: Dp) -> Unit = { _, _ -> }, - modifier: Modifier = Modifier, ) { val pagerState = rememberPagerState( @@ -831,6 +831,7 @@ private fun ListOptionsGlyph(modifier: Modifier = Modifier) { } } +@Suppress("FrequentlyChangingValue") @OptIn(ExperimentalMaterial3Api::class) @Composable internal fun LibraryTabs( diff --git a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt index 32df8bae..33b90f6e 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt @@ -120,6 +120,7 @@ fun PlaylistDetailScreen( songs: LazyPagingItems, coverArt: (String?, Boolean) -> CoverArtRef?, artwork: ArtworkColors?, + modifier: Modifier = Modifier, downloads: Map = emptyMap(), downloadStatus: ListDownloadStatus = ListDownloadStatus(), offline: Boolean = false, @@ -131,7 +132,6 @@ fun PlaylistDetailScreen( onPlay: () -> Unit = {}, onMore: () -> Unit = {}, playingSongId: String? = null, - modifier: Modifier = Modifier, ) { val context = LocalContext.current HeroDetailScaffold( diff --git a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistsContent.kt b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistsContent.kt index d4a0bcb0..300428e5 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistsContent.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistsContent.kt @@ -44,6 +44,7 @@ fun PlaylistsContent( coverArt: (String?, Boolean) -> CoverArtRef?, bottomInset: Dp, onPlaylistClick: (Playlist) -> Unit, + modifier: Modifier = Modifier, onLongClick: (MenuTarget) -> Unit = {}, filtered: Boolean = false, onClearFilters: () -> Unit = {}, @@ -51,7 +52,6 @@ fun PlaylistsContent( topInset: Dp = 0.dp, onSync: () -> Unit = {}, downloadStatuses: Map = emptyMap(), - modifier: Modifier = Modifier, ) { when { items.itemCount == 0 && items.loadState.refresh is LoadState.Loading -> { diff --git a/app/src/main/kotlin/com/subtracks/ui/library/SongsContent.kt b/app/src/main/kotlin/com/subtracks/ui/library/SongsContent.kt index eb7e3535..1b835107 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/SongsContent.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/SongsContent.kt @@ -93,6 +93,7 @@ private fun buildVectorPath(vector: ImageVector): Path { @Composable fun SongRow( song: Song, + modifier: Modifier = Modifier, coverArtId: String? = null, coverArt: ((String?, Boolean) -> CoverArtRef?)? = null, isPlaying: Boolean = false, @@ -100,7 +101,6 @@ fun SongRow( durationSeconds: Long? = null, download: SongDownload? = null, trailingContent: (@Composable () -> Unit)? = null, - modifier: Modifier = Modifier, ) { ListItem( modifier = modifier, diff --git a/app/src/main/kotlin/com/subtracks/ui/playback/MiniPlayer.kt b/app/src/main/kotlin/com/subtracks/ui/playback/MiniPlayer.kt index 3890a1f6..6837dc78 100644 --- a/app/src/main/kotlin/com/subtracks/ui/playback/MiniPlayer.kt +++ b/app/src/main/kotlin/com/subtracks/ui/playback/MiniPlayer.kt @@ -60,10 +60,10 @@ fun MiniPlayer( onExpand: () -> Unit, onPlayPause: () -> Unit, onNext: () -> Unit, + modifier: Modifier = Modifier, progressInset: Boolean = false, onExpandDrag: (Float) -> Unit = {}, onExpandRelease: (Float) -> Unit = {}, - modifier: Modifier = Modifier, ) { val item = state.item ?: return var dragUpPx by remember { mutableFloatStateOf(0f) } diff --git a/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt b/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt index 1ead9d8e..267a18e8 100644 --- a/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt @@ -182,9 +182,9 @@ fun NowPlayingRoute( onQueue: () -> Unit, onViewAlbum: (String) -> Unit, onViewArtist: (String) -> Unit, + modifier: Modifier = Modifier, contextMenuHost: ContextMenuHost? = null, setStar: (StarType, String, Boolean) -> Unit, - modifier: Modifier = Modifier, controller: PlaybackController = koinInject(), libraryRepository: LibraryRepository = koinInject(), downloadRepository: DownloadRepository = koinInject(), @@ -286,6 +286,7 @@ fun NowPlayingScreen( onPlayPause: () -> Unit, onNext: () -> Unit, onPrevious: () -> Unit, + modifier: Modifier = Modifier, onSkipPrevious: () -> Unit = onPrevious, onShuffle: () -> Unit = {}, onRepeat: () -> Unit = {}, @@ -298,7 +299,6 @@ fun NowPlayingScreen( thumbnailRef: CoverArtRef? = null, previousArt: NowPlayingArt? = null, nextArt: NowPlayingArt? = null, - modifier: Modifier = Modifier, ) { val playButtonSize = 90.dp val playCircleDiameter = playButtonSize * 20f / 24f diff --git a/app/src/main/kotlin/com/subtracks/ui/playback/QueueScreen.kt b/app/src/main/kotlin/com/subtracks/ui/playback/QueueScreen.kt index 9619f3ba..2e1e91fd 100644 --- a/app/src/main/kotlin/com/subtracks/ui/playback/QueueScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/playback/QueueScreen.kt @@ -33,6 +33,7 @@ import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -106,10 +107,10 @@ class QueueViewModel( var ready by mutableStateOf(false) private set - var initialIndex by mutableStateOf(0) + var initialIndex by mutableIntStateOf(0) private set - var generation by mutableStateOf(0) + var generation by mutableIntStateOf(0) private set private var nextId = 0L @@ -562,6 +563,7 @@ internal fun dropTarget( return (before - if (before > from) 1 else 0) + 1 } +@Suppress("ModifierParameter") @Composable private fun QueueRowItem( row: QueueRow, diff --git a/app/src/main/kotlin/com/subtracks/ui/search/SearchScreen.kt b/app/src/main/kotlin/com/subtracks/ui/search/SearchScreen.kt index 5d7ccd7c..043ab41d 100644 --- a/app/src/main/kotlin/com/subtracks/ui/search/SearchScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/search/SearchScreen.kt @@ -59,7 +59,7 @@ import org.koin.compose.koinInject import org.koin.compose.viewmodel.koinViewModel enum class SearchFilter( - @StringRes val label: Int, + @param:StringRes val label: Int, ) { Songs(R.string.search_songs), Albums(R.string.resources_album_name), @@ -125,6 +125,7 @@ fun SearchScreen( query: String, onQueryChange: (String) -> Unit, results: SearchResults, + modifier: Modifier = Modifier, filters: Set = ALL_FILTERS, onToggleFilter: (SearchFilter) -> Unit = {}, coverArt: (String?, Boolean) -> CoverArtRef? = { _, _ -> null }, @@ -135,7 +136,6 @@ fun SearchScreen( onPlaylistClick: (Playlist) -> Unit = {}, onSongClick: (Song) -> Unit = {}, onLongClick: (MenuTarget) -> Unit = {}, - modifier: Modifier = Modifier, ) { val focusRequester = remember { FocusRequester() } val backLabel = stringResource(R.string.navigation_back) diff --git a/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt b/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt index d3036db4..324ff67b 100644 --- a/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt @@ -90,8 +90,8 @@ fun AddSourceScreen( onSave: () -> Unit, onDelete: () -> Unit, onBack: (() -> Unit)?, - dismissals: Flow = emptyFlow(), modifier: Modifier = Modifier, + dismissals: Flow = emptyFlow(), ) { val nameFocus = remember { FocusRequester() } val addressFocus = remember { FocusRequester() } diff --git a/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt b/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt index 2c3b40e1..082941f1 100644 --- a/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt @@ -41,6 +41,7 @@ import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -124,6 +125,7 @@ fun SettingsScreen( downloadQuality: StreamQuality, downloadOverMetered: Boolean, scrobbling: Boolean, + modifier: Modifier = Modifier, offline: Boolean = false, onSelectSource: (Long) -> Unit, onEditServer: (Long) -> Unit, @@ -139,7 +141,6 @@ fun SettingsScreen( onOpenLicenses: () -> Unit, onBack: () -> Unit, dismissals: Flow = emptyFlow(), - modifier: Modifier = Modifier, ) { var dialog by remember { mutableStateOf(null) } DismissOnRequest(dismissals) { dialog = null } @@ -397,7 +398,7 @@ private fun ConcurrencyDialog( onDismiss: () -> Unit, ) { val resources = LocalResources.current - var draft by remember(selected) { mutableStateOf(selected) } + var draft by remember(selected) { mutableIntStateOf(selected) } AlertDialog( onDismissRequest = onDismiss, title = { Text(stringResource(R.string.sync_concurrency)) }, diff --git a/app/src/main/kotlin/com/subtracks/ui/theme/ArtworkSeedCache.kt b/app/src/main/kotlin/com/subtracks/ui/theme/ArtworkSeedCache.kt index 5d0aef1a..a2afdb44 100644 --- a/app/src/main/kotlin/com/subtracks/ui/theme/ArtworkSeedCache.kt +++ b/app/src/main/kotlin/com/subtracks/ui/theme/ArtworkSeedCache.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.luminance +import androidx.core.graphics.get import androidx.palette.graphics.Palette import coil3.SingletonImageLoader import coil3.compose.LocalPlatformContext @@ -202,7 +203,7 @@ object ArtworkSeedCache { x: Int, y: Int, ): Float { - val color = Color(bitmap.getPixel(x, y)) + val color = Color(bitmap[x, y]) return 0.2126f * color.red + 0.7152f * color.green + 0.0722f * color.blue } diff --git a/app/src/main/res/drawable-anydpi-v24/ic_stat_name.xml b/app/src/main/res/drawable-anydpi/ic_stat_name.xml similarity index 100% rename from app/src/main/res/drawable-anydpi-v24/ic_stat_name.xml rename to app/src/main/res/drawable-anydpi/ic_stat_name.xml diff --git a/app/src/main/res/drawable-hdpi/ic_action_name.png b/app/src/main/res/drawable-hdpi/ic_action_name.png deleted file mode 100644 index 64abb5906f837a1703a96785f19cc76a876760bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 441 zcmeAS@N?(olHy`uVBq!ia0y~yU{C>J4mJh`hKCF@W-u@?Hh8)?hE&A84c{1a*g)j; znLAUb)-}w%bMO?G_L|t2r?|AUBYsBDyCrc?xa^UIYUCR0*x3=&MCZ?cY~t&BwDrN9 z-LH1NOXEIu!&=zo$D_UfZ%vx?kT-JHw%qwU3$?wbIV;y!)dmOEal|Xvq&L?m^gGy_ zt32Er6}Flo`4x|vK=*YgUX#|y#(=I(;Wi7HK4|Yr_2s(s-0!>X)KZq4jYnSG3Kng; zVH|PVBSdx2w>74cXILGXWR;hxKYAG{-(Yrab)EaQ**wpZTuz8QcE85Hp!e&}$2y!P z3AGHjBIaA4%TRc8D@QEC%K1ae-jfM>9Gc07e@lMx`Z`FP+~M!B^(a$laOU0oZF!Ky zg%3Q(4>4?JTH7dz@BJo;Xx-IaU9LaaGR+p|MMiA*V_;xl@O1TaS?83{1OObh!Yu#* diff --git a/app/src/main/res/drawable-hdpi/ic_stat_name.png b/app/src/main/res/drawable-hdpi/ic_stat_name.png deleted file mode 100644 index 86f9858e1003c47cb131601b9aab959906fbf2f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 401 zcmeAS@N?(olHy`uVBq!ia0y~yU{C>J4mJh`hKCF@W-u@?MtHh7hE&A8o%(QMlYvN! z?m?k-EY=f(G!F9la9(dLDNyxbPuIMD&^nAMr|gX6p~lBP`)2;}DEoXbOW{pft5c%# znKj$47hW@9FWuA7#cU~fyO-^8Qlna8>aMuu?X`xA3#D48I_kfA9Z|90;qI?}((bYK zY_Ag6uVY@%YazC%aZNq*`X$Z!-6o6|b`^4NzmqL9?him`88rB_SVlpume!TJK9f!E?i<|lzmpxvk(~9-@WPchnMbCJ zavW#-`>gcOuUWSJ4ach)zb$h6kQU{)z!c(=`wrLQryM^b7}L_F%bW7C{j0v#T4RRZ zn!eU64)>pUtL~U987;)|`pL}G?bn#6NxU%0ow?yh?G&fQUmIHc8$w%|Jc9btJQCPlEboYT7`!;qRWm@q-?3XI1 zfX9ywOssb<+x2k1+1610z()S--nIq3c3*he6T=cTC$Ur*^*vJO`#+mw5=%gtdRg~I zMujxin3P#M$5zeYIPkJ%(s!ribBkNv#~wGjt}&sA_x_}vKNGm@q~=xl8l}H^W#;pN aiGPmCxt9-g92giF7(8A5T-G@yGywp3B8+4J diff --git a/app/src/main/res/drawable-mdpi/ic_stat_name.png b/app/src/main/res/drawable-mdpi/ic_stat_name.png deleted file mode 100644 index e14e26bb03ae5ca1fb76d782de63fc037cc30199..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 284 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJo9(%ethE&A8ot((q?7-7H zv4KU!he@cwK!%5Nas$g89`*+f#TzVNtb4pJ_tewAHy+#MYdniT{JJI1By#j*JOhKS zjK4aw&9Q4UBH3iD4osNP$v=_FXp<`covAz)pNy1gI|7RsJ?4)_OO1B z?c7f$i>C8PWaOkO8CR!0m2}aUym0x(DW9}&DXdqv#rYlItZG~x^>n4HzMR6BsO(u2 z(#sEQf5X@C)wo7w71x=!d=fGGZt^p@*>nyyM|o;LvdNvAbuGb}YaZv1i{cBHM>ISy oILZx0z*UD1g-4YGEcIHp?yGG@$@8@PO?>aE?kEegrbnD-9EVj*FwlYL( zs?v+!bzAS|#fvR66|aA>>s_|zrdjuoJ(~aHQBca(_p`U< ztHQYxco+_b>w7pxXG`dR+9>SZ^g48L!IC&bF85cWV202Q>rWZh5BaPY?G5q& zF+aJ;QSTPV?$_u3#TD`>f9)z{UK1dbFSWs{Ag61?BAz>PY=<{aFW4g`xaP3(@wlv0 z3VWVTxMfvzj^p^MhYA1M9?S4rUgk9HDE$;EeU4RTd7E>}s}6(tmeU=1o>z9|t^kR= ztJJ*qQgx>}b8V5{0}E4`pwIPFj@lOMHA|fPEK<#H;m6y~Iah7ED$s9G) zq*A??EYp!;PZYnTNkLCLxwW4-T^t+4O uQcim3KVwslY6^HA`f;k)(ogv{%$n7e^`GCWcr!3CFnGH9xvXHV|=T zPFy(UAe)n7i{t49Z2@f3Y|(7I&AQC(j?)ju-aU14#qprr>)(!8FE;-C?@8^CxaguO zZ_1{6Ee(p4@+?=Z%Tsx`V!elkT}#FFvW?r=U;R^1c^A1iQEugZwtpM44sW@V&-^66 zp%)tJP( zNsZA7zAGJ`t!~`9aaoAM=lezrcJ$3pJGSEQ;;B3`7r)C&ojdz**OtzoC)q^a*S$=! zYCZV4{UR6JF&W)sMGtBgb+YxH5k8vyK4?#oo!~U>&n6F+2HuI0D&I2i)V%9E7wm|+ zy=8`}NkY`u`x4V5lHLlRuhDXOAMgBXd!uo;*_oNYs%NJ>{!*u3v*7<>m$;g)N12zU hOM@Nff+BC`S^NG;jr;+xpMeqvgQu&X%Q~loCIAs#5g7mg diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_name.png b/app/src/main/res/drawable-xxhdpi/ic_action_name.png deleted file mode 100644 index 9a7db099050a21ed1778da4f9ff4526d130723e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 925 zcmeAS@N?(olHy`uVBq!ia0y~yVDJE84mJh`hS0a0-5D5|Q#@T9Ln`9l&fJ@S$AIT( z{<%3@vp2JSV85^~_O@mAwUV>9*2U^)|G)j}=A?<$Vya%--UrRLfAEmu@)Ff3q13xC zQzY6FK}c%Xy5Cp6|9!5^Rr|cg=fDkp3G*ecy>9^Sz3l)|aHe8!k<0GWe?( z_E~mPbkY$P%j4>N+roo9y;ME!nY`sOfBSC7|C=m@6ZRhdyPZYwPQAClK?LKzj^jF| zJL&y=VQMzQ`*SWI`WtWRs4@9RUZ%1-)46Y(TsKYNIr8lJLf#DSTSx3Pl?sp9d}uwn z;K<$I7c~5suicsYyZ7#!)Cm(-d_3Xgc%*(pPQZin6Vvuhy5$->HrUjf8V)IU3_kQp%f7XKkg75aLc0BkO-Nb=l{C~#jl=|}bzu%%? zTIa_yf3N?{a<$I<>Wbhw63-sYaNLy0ctfISk8bN(rR@tv`Xp7P#Tw@79KRjqZJ%lp zHz8-mk@s2M|0*M#-|gJLLszw6kHXCW&U-4ycP(0FZ?3eF?PQzR2Q|xUTU!ntczf~C z#wHi%v*H!IKP1%hUfp6H8ghi?>XdWY)5<(G1n#VpS()nS6JV{k<(1`K(Rq4#D<^e5 zyR9oWHKd7c=fm$(H}}SIeBW???bBOd4!uozIL~aNOvc6k(beJ2|1aAe+VwHeH00F*|V5m9u>Pa S`z-?l1B0ilpUXO@geCxw_rHJu diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_name.png b/app/src/main/res/drawable-xxhdpi/ic_stat_name.png deleted file mode 100644 index 926e3c7589f2feff11019642c35de65c04d57029..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 921 zcmeAS@N?(olHy`uVBq!ia0y~yVDJE84mJh`hS0a0-5D5|6FglULn`9l-hLQ(+d-f$ z(aVEVuaWN&pA&l_`$Fb*%@-K;8inpKzGSdckj?qB@N-|q+skuVrgfB@@2Pvaduo}f z+op!qt5?B5=FFSlMRTsdv0fcnayjSxHo5g@zjYT|tmb^TqsmpzqQ89Bfoa-dFWQO= z&z^H%7XG5MxX@>v=<`PsE!Ele6|a*mQn=#_Zb$QDU!O=qH3EU?~)Z^n{D^nx9m=~J1X@2^qgb^t}}s?Z$|uT+1=%DcT~u?@tkV4 zqfTHq*aeH#iXSYJTRi{N)@etpmh3NaGdtR_Wj?pjm!hl>=T+BsX18;!xxDmmjKUd9 zw#5fx!Z-hK<>q3!b~5wYolPE%;n!Yn^5#ErYqiy}d0UHgKJHz4plxekP7`CUq+UtF zTA8(p6P=>3S#9EEn^KcHp)g^sjP(C)#iyg(%U&{a9&TlN{Un38drHDwJ?|?i=L{uS zpY6)IGxhE!zrJf5JQ|r_m)vw=zGZSdUhkFRFV;ENHbuC-KfK7-P+{Yz=nZU^KO|px zWGD9uHNN(g)DwCp(;S%aP9}SP(Qm)F@cJ(WeId%%ye?Xb*si@jg;^-uKaM?=S^wI- zS?_1(9)IH=S?w4Sef+}45+B*!Ka`IA;RNf?)4U=*TaznLowZpY%N=`R+Hw6vWBwO2TlF%|Kc2o}CtJ$n zINzEpZOv~GspLL z!S~R&7Sqdf=0$%A-}v0-+@^0o9rX8KciMZeh%d72S3Ya^og3w$P;j;NFLR(~;F)DF TkE$^+Ffe$!`njxgN@xNAmi4=N diff --git a/app/src/main/res/drawable/media3_notification_small_icon.xml b/app/src/main/res/drawable/media3_notification_small_icon.xml index 3fe84db5..1706d6c9 100644 --- a/app/src/main/res/drawable/media3_notification_small_icon.xml +++ b/app/src/main/res/drawable/media3_notification_small_icon.xml @@ -1,8 +1,10 @@ + android:viewportHeight="300" + tools:ignore="UnusedResources"> Biblioteca Configurações - %1$d album - %1$d albums + %1$d álbum + %1$d álbuns Álbum Artista @@ -42,7 +42,7 @@ Senha Usuário Home - Albums + Álbuns Artists Playlists diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 167ed9c7..65f6e727 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -17,7 +17,6 @@ ประเภท ให้ดาว - %1$d เพลง %1$d เพลง ศิลปิน diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 30eec41d..494866c7 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -10,7 +10,6 @@ Thư viện Cài đặt - %1$d album %1$d album Theo album @@ -18,7 +17,6 @@ Theo thể loại Theo yêu thích - %1$d bài hát %1$d bài hát Nghệ sĩ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 39301538..7db8a5c2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - + subtracks Progress while songs download @@ -124,7 +124,7 @@ Search Search this list Songs - Type at least %1$d characters to search. + Type at least %1$d characters to search. No results for “%1$s”. Sort by Sort ascending @@ -245,7 +245,7 @@ Unknown error Malformed response from the server Truncated response from the server - Library is too large to sync: it exceeds %1$d rows + Library is too large to sync: it exceeds %1$d rows HTTP %1$d Recently played artists diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml index 8a76775f..3aad9801 100644 --- a/app/src/main/res/xml/network_security_config.xml +++ b/app/src/main/res/xml/network_security_config.xml @@ -1,9 +1,13 @@ - - + + - + diff --git a/app/src/test/kotlin/com/subtracks/i18n/StringResourcesTest.kt b/app/src/test/kotlin/com/subtracks/i18n/StringResourcesTest.kt index e2764034..e4c9d07c 100644 --- a/app/src/test/kotlin/com/subtracks/i18n/StringResourcesTest.kt +++ b/app/src/test/kotlin/com/subtracks/i18n/StringResourcesTest.kt @@ -34,17 +34,17 @@ class StringResourcesTest { val locale = parse(file) locale.forEach { (name, resource) -> val base = default[name] - assertTrue("$name in ${file.parentFile.name} is missing from values/strings.xml", base != null) - assertEquals("$name kind differs in ${file.parentFile.name}", base!!.kind, resource.kind) + assertTrue("$name in ${file.parentFile?.name} is missing from values/strings.xml", base != null) + assertEquals("$name kind differs in ${file.parentFile?.name}", base!!.kind, resource.kind) if (resource.kind == "plurals") { assertTrue( - "$name has an invalid quantity in ${file.parentFile.name}", + "$name has an invalid quantity in ${file.parentFile?.name}", resource.quantities.all { it in validQuantities }, ) - assertTrue("$name in ${file.parentFile.name} is missing the required 'other' quantity", "other" in resource.quantities) + assertTrue("$name in ${file.parentFile?.name} is missing the required 'other' quantity", "other" in resource.quantities) } assertEquals( - "$name placeholders differ in ${file.parentFile.name}", + "$name placeholders differ in ${file.parentFile?.name}", placeholders(base.text), placeholders(resource.text), ) diff --git a/app/src/test/kotlin/com/subtracks/ui/DemoScreenshotTest.kt b/app/src/test/kotlin/com/subtracks/ui/DemoScreenshotTest.kt index fb5dde29..d8d6414a 100644 --- a/app/src/test/kotlin/com/subtracks/ui/DemoScreenshotTest.kt +++ b/app/src/test/kotlin/com/subtracks/ui/DemoScreenshotTest.kt @@ -275,8 +275,8 @@ class DemoScreenshotTest { private fun DemoData.MiniPlayerOverlay( song: Song, album: Album, - progressInset: Boolean = false, modifier: Modifier = Modifier, + progressInset: Boolean = false, ) { MiniPlayer( state = playbackFor(song, album),