diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 227ca106..96899ad2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -25,8 +25,8 @@ android { applicationId = "org.grakovne.lissen" minSdk = 28 targetSdk = 35 - versionCode = 49 - versionName = "1.1.18" + versionCode = 50 + versionName = "1.1.19" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { @@ -62,7 +62,7 @@ android { } packaging { resources { - excludes += "/META-INF/{AL2.0,LGPL2.1}" + excludes += "/META-INF/{AL2.0,LGPL2.1,MIT}" } } @@ -71,7 +71,7 @@ android { dependencies { implementation(libs.androidx.palette.ktx) - implementation(libs.accompanist.systemuicontroller) + //implementation(libs.accompanist.systemuicontroller) implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.navigation.compose) implementation(libs.material) diff --git a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/common/converter/LibraryPageResponseConverter.kt b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/common/converter/LibraryPageResponseConverter.kt index 5fa2d1cf..c9cfe31d 100644 --- a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/common/converter/LibraryPageResponseConverter.kt +++ b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/common/converter/LibraryPageResponseConverter.kt @@ -14,6 +14,11 @@ class LibraryPageResponseConverter @Inject constructor() { .mapNotNull { val title = it.media.metadata.title ?: return@mapNotNull null + val hasMediaItems = (it.media.numAudioFiles ?: 0) > 0 + if (hasMediaItems.not()) { + return@mapNotNull null + } + Book( id = it.id, title = title, diff --git a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/library/converter/LibrarySearchItemsConverter.kt b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/library/converter/LibrarySearchItemsConverter.kt index b9bf747b..b3364393 100644 --- a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/library/converter/LibrarySearchItemsConverter.kt +++ b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/library/converter/LibrarySearchItemsConverter.kt @@ -9,9 +9,16 @@ import javax.inject.Singleton class LibrarySearchItemsConverter @Inject constructor() { fun apply(response: List) = response .mapNotNull { + val title = it.media.metadata.title ?: return@mapNotNull null + + val hasMediaItems = (it.media.numAudioFiles ?: 0) > 0 + if (hasMediaItems.not()) { + return@mapNotNull null + } + Book( id = it.id, - title = it.media.metadata.title ?: return@mapNotNull null, + title = title, author = it.media.metadata.authorName, duration = it.media.duration.toInt(), ) diff --git a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/library/model/LibraryItemsResponse.kt b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/library/model/LibraryItemsResponse.kt index ad2bab82..76435a07 100644 --- a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/library/model/LibraryItemsResponse.kt +++ b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/library/model/LibraryItemsResponse.kt @@ -13,6 +13,7 @@ data class LibraryItem( data class Media( val duration: Double, val metadata: LibraryMetadata, + val numAudioFiles: Int?, ) data class LibraryMetadata( diff --git a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/converter/PodcastPageResponseConverter.kt b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/converter/PodcastPageResponseConverter.kt index 505ec47d..df58b51d 100644 --- a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/converter/PodcastPageResponseConverter.kt +++ b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/converter/PodcastPageResponseConverter.kt @@ -14,6 +14,11 @@ class PodcastPageResponseConverter @Inject constructor() { .mapNotNull { val title = it.media.metadata.title ?: return@mapNotNull null + val hasMediaItems = (it.media.numAudioFiles ?: 0) > 0 + if (hasMediaItems.not()) { + return@mapNotNull null + } + Book( id = it.id, title = title, diff --git a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/converter/PodcastSearchItemsConverter.kt b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/converter/PodcastSearchItemsConverter.kt index ed790ddf..a3dc04bf 100644 --- a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/converter/PodcastSearchItemsConverter.kt +++ b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/converter/PodcastSearchItemsConverter.kt @@ -12,6 +12,11 @@ class PodcastSearchItemsConverter @Inject constructor() { .mapNotNull { val title = it.media.metadata.title ?: return@mapNotNull null + val hasMediaItems = (it.media.numAudioFiles ?: 0) > 0 + if (hasMediaItems.not()) { + return@mapNotNull null + } + Book( id = it.id, title = title, diff --git a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/model/PodcastItemsResponse.kt b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/model/PodcastItemsResponse.kt index 3a5a4214..cdd58f35 100644 --- a/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/model/PodcastItemsResponse.kt +++ b/app/src/main/java/org/grakovne/lissen/channel/audiobookshelf/podcast/model/PodcastItemsResponse.kt @@ -13,6 +13,7 @@ data class PodcastItem( data class PodcastItemMedia( val duration: Double, val metadata: PodcastMetadata, + val numAudioFiles: Int?, ) data class PodcastMetadata( diff --git a/app/src/main/java/org/grakovne/lissen/ui/navigation/AppNavHost.kt b/app/src/main/java/org/grakovne/lissen/ui/navigation/AppNavHost.kt index 6107a758..307820d0 100644 --- a/app/src/main/java/org/grakovne/lissen/ui/navigation/AppNavHost.kt +++ b/app/src/main/java/org/grakovne/lissen/ui/navigation/AppNavHost.kt @@ -1,5 +1,6 @@ package org.grakovne.lissen.ui.navigation +import android.annotation.SuppressLint import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable @@ -21,6 +22,7 @@ import org.grakovne.lissen.ui.screens.player.PlayerScreen import org.grakovne.lissen.ui.screens.settings.SettingsScreen import org.grakovne.lissen.ui.screens.settings.advanced.CustomHeadersSettingsScreen +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @Composable fun AppNavHost( navController: NavHostController, @@ -39,9 +41,7 @@ fun AppNavHost( else -> "login_screen" } - Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - println(innerPadding) - + Scaffold(modifier = Modifier.fillMaxSize()) { _ -> NavHost( navController = navController, startDestination = startDestination, diff --git a/app/src/main/java/org/grakovne/lissen/ui/theme/Theme.kt b/app/src/main/java/org/grakovne/lissen/ui/theme/Theme.kt index 03a612c9..ab8786a8 100644 --- a/app/src/main/java/org/grakovne/lissen/ui/theme/Theme.kt +++ b/app/src/main/java/org/grakovne/lissen/ui/theme/Theme.kt @@ -5,9 +5,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.SideEffect import androidx.compose.ui.graphics.Color -import com.google.accompanist.systemuicontroller.rememberSystemUiController import org.grakovne.lissen.common.ColorScheme private val LightColorScheme = lightColorScheme( @@ -35,18 +33,6 @@ fun LissenTheme( } val colors = if (isDarkTheme) DarkColorScheme else LightColorScheme - val systemUiController = rememberSystemUiController() - - SideEffect { - systemUiController.setNavigationBarColor( - color = colors.background, - darkIcons = !isDarkTheme, - ) - systemUiController.setStatusBarColor( - color = colors.background, - darkIcons = !isDarkTheme, - ) - } MaterialTheme( colorScheme = colors, diff --git a/app/src/main/java/org/grakovne/lissen/widget/MediaRepository.kt b/app/src/main/java/org/grakovne/lissen/widget/MediaRepository.kt index 5d710dea..e12c3076 100644 --- a/app/src/main/java/org/grakovne/lissen/widget/MediaRepository.kt +++ b/app/src/main/java/org/grakovne/lissen/widget/MediaRepository.kt @@ -249,6 +249,11 @@ class MediaRepository @Inject constructor( } fun togglePlayPause() { + if (currentChapterIndex.value == -1) { + Log.w(TAG, "Tried to toggle play/pause in the empty book. Skipping") + return + } + when (isPlaying.value) { true -> pause() else -> play() diff --git a/app/src/main/java/org/grakovne/lissen/widget/PlayerWidget.kt b/app/src/main/java/org/grakovne/lissen/widget/PlayerWidget.kt index e9e88d2a..d55a0d70 100644 --- a/app/src/main/java/org/grakovne/lissen/widget/PlayerWidget.kt +++ b/app/src/main/java/org/grakovne/lissen/widget/PlayerWidget.kt @@ -3,6 +3,7 @@ package org.grakovne.lissen.widget import android.content.Context import android.content.Intent import android.graphics.BitmapFactory.decodeResource +import android.util.Log import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.ui.graphics.Color @@ -311,15 +312,21 @@ private suspend fun safelyRun( context: Context, action: (WidgetPlaybackController) -> Unit, ) { - val playbackController = EntryPointAccessors - .fromApplication( - context = context.applicationContext, - entryPoint = WidgetPlaybackControllerEntryPoint::class.java, - ) - .widgetPlaybackController() - - when (playbackController.providePlayingItem()) { - null -> playbackController.prepareAndRun(playingItemId) { action(playbackController) } - else -> action(playbackController) + try { + val playbackController = EntryPointAccessors + .fromApplication( + context = context.applicationContext, + entryPoint = WidgetPlaybackControllerEntryPoint::class.java, + ) + .widgetPlaybackController() + + when (playbackController.providePlayingItem()) { + null -> playbackController.prepareAndRun(playingItemId) { action(playbackController) } + else -> action(playbackController) + } + } catch (ex: Exception) { + Log.w(TAG, "Unable to run $action on $playingItemId due to $ex") } } + +private const val TAG = "PlayerWidget" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 69479a73..39777ca7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,11 @@ [versions] -accompanistSystemuicontroller = "0.30.0" acraCore = "5.11.4" agp = "8.6.1" coilCompose = "2.7.0" composeShimmerAndroid = "1.3.1" -converterGson = "2.9.0" +converterGson = "2.11.0" glance = "1.1.1" -hiltAndroid = "2.52" +hiltAndroid = "2.53" hiltNavigationCompose = "1.2.0" kotlin = "2.0.21" coreKtx = "1.15.0" @@ -15,27 +14,26 @@ junitVersion = "1.2.1" espressoCore = "3.6.1" lifecycleRuntimeKtx = "2.8.7" activityCompose = "1.9.3" -composeBom = "2024.11.00" -compose = "1.7.5" +composeBom = "2024.12.01" +compose = "1.7.6" lifecycleViewmodelCompose = "2.8.7" loggingInterceptor = "4.11.0" -material = "1.7.5" +material = "1.7.6" material3 = "1.3.1" materialVersion = "1.12.0" media3Exoplayer = "1.5.0" -navigationCompose = "2.8.4" +navigationCompose = "2.8.5" okhttp = "4.12.0" -pagingCompose = "3.3.4" +pagingCompose = "3.3.5" paletteKtx = "1.0.0" -retrofit = "2.9.0" +retrofit = "2.11.0" roomRuntime = "2.6.1" rules = "1.6.1" -runtimeLivedata = "1.7.5" +runtimeLivedata = "1.7.6" media3Session = "1.5.0" media3DatasourceOkhttp = "1.5.0" [libraries] -accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanistSystemuicontroller" } acra-core = { module = "ch.acra:acra-core", version.ref = "acraCore" } acra-http = { module = "ch.acra:acra-http", version.ref = "acraCore" } acra-toast = { module = "ch.acra:acra-toast", version.ref = "acraCore" }