diff --git a/app/build.gradle b/app/build.gradle
index 29761d1e..f4ba9142 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -159,8 +159,8 @@ android {
// Version code schema (not used):
// "1.2.3-beta4" -> 1020304
// "1.2.3" -> 1020395
- versionCode 3020142
- versionName "5.1.0"
+ versionCode 3020143
+ versionName "5.2.0"
def commit = ""
try {
@@ -262,10 +262,6 @@ dependencies {
implementation "io.coil-kt:coil:2.6.0"
-// implementation "com.github.bumptech.glide:glide:4.16.0"
-// implementation "com.github.bumptech.glide:okhttp3-integration:4.16.0@aar"
-// kapt "com.github.bumptech.glide:ksp:4.16.0"
-
implementation "com.squareup.okhttp3:okhttp:4.12.0"
implementation "com.squareup.okhttp3:okhttp-urlconnection:4.12.0"
implementation 'com.squareup.okio:okio:3.9.0'
diff --git a/app/src/androidTest/java/ac/test/podcini/service/download/HttpDownloaderTest.kt b/app/src/androidTest/java/ac/test/podcini/service/download/HttpDownloaderTest.kt
index 85d743b5..397dc531 100644
--- a/app/src/androidTest/java/ac/test/podcini/service/download/HttpDownloaderTest.kt
+++ b/app/src/androidTest/java/ac/test/podcini/service/download/HttpDownloaderTest.kt
@@ -9,6 +9,7 @@ import ac.mdiq.podcini.storage.model.download.DownloadError
import ac.mdiq.podcini.storage.model.feed.FeedFile
import ac.mdiq.podcini.net.download.serviceinterface.DownloadRequest
import ac.mdiq.podcini.preferences.UserPreferences.init
+import ac.mdiq.podcini.util.Logd
import de.test.podcini.util.service.download.HTTPBin
import org.junit.After
import org.junit.Assert
@@ -54,7 +55,7 @@ class HttpDownloaderTest {
val fileUrl = File(destDir, title).absolutePath
val file = File(fileUrl)
if (deleteExisting) {
- Log.d(TAG, "Deleting file: " + file.delete())
+ Logd(TAG, "Deleting file: " + file.delete())
}
feedfile.setFile_url(fileUrl)
return feedfile
diff --git a/app/src/main/java/ac/mdiq/podcini/feed/ChapterMerger.kt b/app/src/main/java/ac/mdiq/podcini/feed/ChapterMerger.kt
index ef7f70ea..d8ecf065 100644
--- a/app/src/main/java/ac/mdiq/podcini/feed/ChapterMerger.kt
+++ b/app/src/main/java/ac/mdiq/podcini/feed/ChapterMerger.kt
@@ -2,6 +2,7 @@ package ac.mdiq.podcini.feed
import android.util.Log
import ac.mdiq.podcini.storage.model.feed.Chapter
+import ac.mdiq.podcini.util.Logd
import kotlin.math.abs
object ChapterMerger {
@@ -11,7 +12,7 @@ object ChapterMerger {
* This method might modify the input data.
*/
fun merge(chapters1: List?, chapters2: List?): List? {
- Log.d(TAG, "Merging chapters")
+ Logd(TAG, "Merging chapters")
when {
chapters1 == null -> return chapters2
chapters2 == null -> return chapters1
diff --git a/app/src/main/java/ac/mdiq/podcini/feed/LocalFeedUpdater.kt b/app/src/main/java/ac/mdiq/podcini/feed/LocalFeedUpdater.kt
index 077aa8d9..6346a726 100644
--- a/app/src/main/java/ac/mdiq/podcini/feed/LocalFeedUpdater.kt
+++ b/app/src/main/java/ac/mdiq/podcini/feed/LocalFeedUpdater.kt
@@ -25,6 +25,7 @@ import ac.mdiq.podcini.feed.parser.media.id3.ID3ReaderException
import ac.mdiq.podcini.feed.parser.media.id3.Id3MetadataReader
import ac.mdiq.podcini.feed.parser.media.vorbis.VorbisCommentMetadataReader
import ac.mdiq.podcini.feed.parser.media.vorbis.VorbisCommentReaderException
+import ac.mdiq.podcini.util.Logd
import org.apache.commons.io.input.CountingInputStream
import java.io.BufferedInputStream
import java.io.IOException
@@ -186,8 +187,7 @@ object LocalFeedUpdater {
item.setDescriptionIfLonger(reader.comment)
}
} catch (e: IOException) {
- Log.d(TAG, "Unable to parse ID3 of " + file.uri + ": " + e.message)
-
+ Logd(TAG, "Unable to parse ID3 of " + file.uri + ": " + e.message)
try {
context.contentResolver.openInputStream(file.uri).use { inputStream ->
val reader = VorbisCommentMetadataReader(inputStream)
@@ -195,12 +195,12 @@ object LocalFeedUpdater {
item.setDescriptionIfLonger(reader.description)
}
} catch (e2: IOException) {
- Log.d(TAG, "Unable to parse vorbis comments of " + file.uri + ": " + e2.message)
+ Logd(TAG, "Unable to parse vorbis comments of " + file.uri + ": " + e2.message)
} catch (e2: VorbisCommentReaderException) {
- Log.d(TAG, "Unable to parse vorbis comments of " + file.uri + ": " + e2.message)
+ Logd(TAG, "Unable to parse vorbis comments of " + file.uri + ": " + e2.message)
}
} catch (e: ID3ReaderException) {
- Log.d(TAG, "Unable to parse ID3 of " + file.uri + ": " + e.message)
+ Logd(TAG, "Unable to parse ID3 of " + file.uri + ": " + e.message)
try {
context.contentResolver.openInputStream(file.uri).use { inputStream ->
@@ -209,9 +209,9 @@ object LocalFeedUpdater {
item.setDescriptionIfLonger(reader.description)
}
} catch (e2: IOException) {
- Log.d(TAG, "Unable to parse vorbis comments of " + file.uri + ": " + e2.message)
+ Logd(TAG, "Unable to parse vorbis comments of " + file.uri + ": " + e2.message)
} catch (e2: VorbisCommentReaderException) {
- Log.d(TAG, "Unable to parse vorbis comments of " + file.uri + ": " + e2.message)
+ Logd(TAG, "Unable to parse vorbis comments of " + file.uri + ": " + e2.message)
}
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ChapterReader.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ChapterReader.kt
index e56ba036..2d33abef 100644
--- a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ChapterReader.kt
+++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ChapterReader.kt
@@ -4,6 +4,7 @@ import android.util.Log
import ac.mdiq.podcini.storage.model.feed.Chapter
import ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage.Companion.makeUrl
import ac.mdiq.podcini.feed.parser.media.id3.model.FrameHeader
+import ac.mdiq.podcini.util.Logd
import org.apache.commons.io.input.CountingInputStream
import java.io.IOException
import java.net.URLDecoder
@@ -18,9 +19,9 @@ class ChapterReader(input: CountingInputStream?) : ID3Reader(input!!) {
@Throws(IOException::class, ID3ReaderException::class)
override fun readFrame(frameHeader: FrameHeader) {
if (FRAME_ID_CHAPTER == frameHeader.id) {
- Log.d(TAG, "Handling frame: $frameHeader")
+ Logd(TAG, "Handling frame: $frameHeader")
val chapter = readChapter(frameHeader)
- Log.d(TAG, "Chapter done: $chapter")
+ Logd(TAG, "Chapter done: $chapter")
chapters.add(chapter)
} else {
super.readFrame(frameHeader)
@@ -48,12 +49,12 @@ class ChapterReader(input: CountingInputStream?) : ID3Reader(input!!) {
@Throws(IOException::class, ID3ReaderException::class)
fun readChapterSubFrame(frameHeader: FrameHeader, chapter: Chapter) {
- Log.d(TAG, "Handling subframe: $frameHeader")
+ Logd(TAG, "Handling subframe: $frameHeader")
val frameStartPosition = position
when (frameHeader.id) {
FRAME_ID_TITLE -> {
chapter.title = readEncodingAndString(frameHeader.size)
- Log.d(TAG, "Found title: " + chapter.title)
+ Logd(TAG, "Found title: " + chapter.title)
}
FRAME_ID_LINK -> {
readEncodingAndString(frameHeader.size) // skip description
@@ -61,7 +62,7 @@ class ChapterReader(input: CountingInputStream?) : ID3Reader(input!!) {
try {
val decodedLink = URLDecoder.decode(url, "ISO-8859-1")
chapter.link = decodedLink
- Log.d(TAG, "Found link: " + chapter.link)
+ Logd(TAG, "Found link: " + chapter.link)
} catch (iae: IllegalArgumentException) {
Log.w(TAG, "Bad URL found in ID3 data")
}
@@ -71,10 +72,10 @@ class ChapterReader(input: CountingInputStream?) : ID3Reader(input!!) {
val mime = readIsoStringNullTerminated(frameHeader.size)
val type = readByte()
val description = readEncodedString(encoding.toInt(), frameHeader.size)
- Log.d(TAG, "Found apic: $mime,$description")
+ Logd(TAG, "Found apic: $mime,$description")
if (MIME_IMAGE_URL == mime) {
val link = readIsoStringNullTerminated(frameHeader.size)
- Log.d(TAG, "Link: $link")
+ Logd(TAG, "Link: $link")
if (chapter.imageUrl.isNullOrEmpty() || type.toInt() == IMAGE_TYPE_COVER) chapter.imageUrl = link
} else {
val alreadyConsumed = position - frameStartPosition
@@ -82,7 +83,7 @@ class ChapterReader(input: CountingInputStream?) : ID3Reader(input!!) {
if (chapter.imageUrl.isNullOrEmpty() || type.toInt() == IMAGE_TYPE_COVER) chapter.imageUrl = makeUrl(position, rawImageDataLength)
}
}
- else -> Log.d(TAG, "Unknown chapter sub-frame.")
+ else -> Logd(TAG, "Unknown chapter sub-frame.")
}
// Skip garbage to fill frame completely
// This also asserts that we are not reading too many bytes from this frame.
diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ID3Reader.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ID3Reader.kt
index 2e38d1b9..75d1f0f4 100644
--- a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ID3Reader.kt
+++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ID3Reader.kt
@@ -3,6 +3,7 @@ package ac.mdiq.podcini.feed.parser.media.id3
import android.util.Log
import ac.mdiq.podcini.feed.parser.media.id3.model.FrameHeader
import ac.mdiq.podcini.feed.parser.media.id3.model.TagHeader
+import ac.mdiq.podcini.util.Logd
import org.apache.commons.io.IOUtils
import org.apache.commons.io.input.CountingInputStream
import java.io.ByteArrayOutputStream
@@ -25,7 +26,7 @@ open class ID3Reader(private val inputStream: CountingInputStream) {
while (position < tagContentStartPosition + tagHeader!!.size) {
val frameHeader = readFrameHeader()
if (frameHeader.id[0] < '0' || frameHeader.id[0] > 'z') {
- Log.d(TAG, "Stopping because of invalid frame: $frameHeader")
+ Logd(TAG, "Stopping because of invalid frame: $frameHeader")
return
}
readFrame(frameHeader)
@@ -34,7 +35,7 @@ open class ID3Reader(private val inputStream: CountingInputStream) {
@Throws(IOException::class, ID3ReaderException::class)
protected open fun readFrame(frameHeader: FrameHeader) {
- Log.d(TAG, "Skipping frame: " + frameHeader.id + ", size: " + frameHeader.size)
+ Logd(TAG, "Skipping frame: " + frameHeader.id + ", size: " + frameHeader.size)
skipBytes(frameHeader.size)
}
diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentReader.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentReader.kt
index 2c813f8a..01b37ae8 100644
--- a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentReader.kt
+++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentReader.kt
@@ -1,5 +1,6 @@
package ac.mdiq.podcini.feed.parser.media.vorbis
+import ac.mdiq.podcini.util.Logd
import android.util.Log
import org.apache.commons.io.EndianUtils
import org.apache.commons.io.IOUtils
@@ -17,12 +18,12 @@ abstract class VorbisCommentReader internal constructor(private val input: Input
findOggPage()
findCommentHeader()
val commentHeader = readCommentHeader()
- Log.d(TAG, commentHeader.toString())
+ Logd(TAG, commentHeader.toString())
for (i in 0 until commentHeader.userCommentLength) {
readUserComment()
}
} catch (e: IOException) {
- Log.d(TAG, "Vorbis parser: " + e.message)
+ Logd(TAG, "Vorbis parser: " + e.message)
}
}
@@ -54,7 +55,7 @@ abstract class VorbisCommentReader internal constructor(private val input: Input
}
val key = readContentVectorKey(vectorLength)!!.lowercase()
val shouldReadValue = handles(key)
- Log.d(TAG, "key=$key, length=$vectorLength, handles=$shouldReadValue")
+ Logd(TAG, "key=$key, length=$vectorLength, handles=$shouldReadValue")
if (shouldReadValue) {
val value = readUtf8String(vectorLength - key.length - 1)
onContentVectorValue(key, value)
diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DateUtils.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DateUtils.kt
index 14b3b18e..14fbb48e 100644
--- a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DateUtils.kt
+++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DateUtils.kt
@@ -1,5 +1,6 @@
package ac.mdiq.podcini.feed.parser.util
+import ac.mdiq.podcini.util.Logd
import android.util.Log
import org.apache.commons.lang3.StringUtils
import java.text.ParsePosition
@@ -98,7 +99,7 @@ object DateUtils {
// if date string starts with a weekday, try parsing date string without it
if (date.matches("^\\w+, .*$".toRegex())) return parse(date.substring(date.indexOf(',') + 1))
- Log.d(TAG, "Could not parse date string \"$input\" [$date]")
+ Logd(TAG, "Could not parse date string \"$input\" [$date]")
return null
}
diff --git a/app/src/main/java/ac/mdiq/podcini/feed/util/PlaybackSpeedUtils.kt b/app/src/main/java/ac/mdiq/podcini/feed/util/PlaybackSpeedUtils.kt
index 5ace8f92..1e594c70 100644
--- a/app/src/main/java/ac/mdiq/podcini/feed/util/PlaybackSpeedUtils.kt
+++ b/app/src/main/java/ac/mdiq/podcini/feed/util/PlaybackSpeedUtils.kt
@@ -7,6 +7,7 @@ import ac.mdiq.podcini.storage.model.feed.FeedPreferences
import ac.mdiq.podcini.storage.model.playback.MediaType
import ac.mdiq.podcini.storage.model.playback.Playable
import ac.mdiq.podcini.preferences.UserPreferences
+import ac.mdiq.podcini.util.Logd
/**
* Utility class to use the appropriate playback speed based on [PlaybackPreferences]
@@ -32,8 +33,8 @@ object PlaybackSpeedUtils {
val feed = item.feed
if (feed?.preferences != null) {
playbackSpeed = feed.preferences!!.feedPlaybackSpeed
- Log.d(TAG, "using feed speed $playbackSpeed")
- } else Log.d(TAG, "Can not get feed specific playback speed: $feed")
+ Logd(TAG, "using feed speed $playbackSpeed")
+ } else Logd(TAG, "Can not get feed specific playback speed: $feed")
}
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/net/common/UrlChecker.kt b/app/src/main/java/ac/mdiq/podcini/net/common/UrlChecker.kt
index 2aba6649..8f581485 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/common/UrlChecker.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/common/UrlChecker.kt
@@ -1,5 +1,6 @@
package ac.mdiq.podcini.net.common
+import ac.mdiq.podcini.util.Logd
import android.net.Uri
import android.util.Log
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
@@ -29,23 +30,23 @@ object UrlChecker {
val lowerCaseUrl = url.lowercase() // protocol names are case insensitive
when {
lowerCaseUrl.startsWith("feed://") -> {
- Log.d(TAG, "Replacing feed:// with http://")
+ Logd(TAG, "Replacing feed:// with http://")
return prepareUrl(url.substring("feed://".length))
}
lowerCaseUrl.startsWith("pcast://") -> {
- Log.d(TAG, "Removing pcast://")
+ Logd(TAG, "Removing pcast://")
return prepareUrl(url.substring("pcast://".length))
}
lowerCaseUrl.startsWith("pcast:") -> {
- Log.d(TAG, "Removing pcast:")
+ Logd(TAG, "Removing pcast:")
return prepareUrl(url.substring("pcast:".length))
}
lowerCaseUrl.startsWith("itpc") -> {
- Log.d(TAG, "Replacing itpc:// with http://")
+ Logd(TAG, "Replacing itpc:// with http://")
return prepareUrl(url.substring("itpc://".length))
}
lowerCaseUrl.startsWith(AP_SUBSCRIBE) -> {
- Log.d(TAG, "Removing podcini-subscribe://")
+ Logd(TAG, "Removing podcini-subscribe://")
return prepareUrl(url.substring(AP_SUBSCRIBE.length))
}
// lowerCaseUrl.contains(AP_SUBSCRIBE_DEEPLINK) -> {
@@ -58,7 +59,7 @@ object UrlChecker {
// }
// }
!(lowerCaseUrl.startsWith("http://") || lowerCaseUrl.startsWith("https://")) -> {
- Log.d(TAG, "Adding http:// at the beginning of the URL")
+ Logd(TAG, "Adding http:// at the beginning of the URL")
return "http://$url"
}
else -> return url
diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/CombinedSearcher.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/CombinedSearcher.kt
index bed41b5a..a1d756b7 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/discovery/CombinedSearcher.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/CombinedSearcher.kt
@@ -1,5 +1,6 @@
package ac.mdiq.podcini.net.discovery
+import ac.mdiq.podcini.util.Logd
import android.text.TextUtils
import android.util.Log
import io.reactivex.Single
@@ -27,7 +28,7 @@ class CombinedSearcher : PodcastSearcher {
singleResults[i] = e
latch.countDown()
}, { throwable: Throwable? ->
- Log.d(TAG, Log.getStackTraceString(throwable))
+ Logd(TAG, Log.getStackTraceString(throwable))
latch.countDown()
}
))
diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/FyydPodcastSearcher.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/FyydPodcastSearcher.kt
index 861091de..32b7b0f9 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/discovery/FyydPodcastSearcher.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/FyydPodcastSearcher.kt
@@ -12,8 +12,7 @@ class FyydPodcastSearcher : PodcastSearcher {
override fun search(query: String): Single?> {
return Single.create { subscriber: SingleEmitter?> ->
- val response = client.searchPodcasts(
- query, 10)
+ val response = client.searchPodcasts(query, 10)
.subscribeOn(Schedulers.io())
.blockingGet()
val searchResults = ArrayList()
diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesTopListLoader.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesTopListLoader.kt
index 0f88bf39..adc13366 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesTopListLoader.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesTopListLoader.kt
@@ -6,6 +6,7 @@ import android.content.Context
import android.util.Log
import ac.mdiq.podcini.net.download.service.PodciniHttpClient.getHttpClient
import ac.mdiq.podcini.storage.model.feed.Feed
+import ac.mdiq.podcini.util.Logd
import okhttp3.CacheControl
import okhttp3.OkHttpClient
import okhttp3.Request
@@ -36,7 +37,7 @@ class ItunesTopListLoader(private val context: Context) {
@Throws(IOException::class)
private fun getTopListFeed(client: OkHttpClient?, country: String): String {
val url = "https://itunes.apple.com/%s/rss/toppodcasts/limit=$NUM_LOADED/explicit=true/json"
- Log.d(TAG, "Feed URL " + String.format(url, country))
+ Logd(TAG, "Feed URL " + String.format(url, country))
val httpReq: Request.Builder = Request.Builder()
.cacheControl(CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build())
.url(String.format(url, country))
diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearcherRegistry.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearcherRegistry.kt
index 5b0cd507..1a92568c 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearcherRegistry.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearcherRegistry.kt
@@ -26,6 +26,14 @@ object PodcastSearcherRegistry {
return Single.just(url)
}
+// fun lookupUrlCo(url: String): String {
+// for (searchProviderInfo in searchProviders) {
+// if (searchProviderInfo.searcher.javaClass != CombinedSearcher::class.java && searchProviderInfo.searcher.urlNeedsLookup(url))
+// return searchProviderInfo.searcher.lookupUrlCo(url)
+// }
+// return url
+// }
+
fun urlNeedsLookup(url: String): Boolean {
for (searchProviderInfo in searchProviders) {
if (searchProviderInfo.searcher.javaClass != CombinedSearcher::class.java && searchProviderInfo.searcher.urlNeedsLookup(url)) return true
diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/ConnectionStateMonitor.kt b/app/src/main/java/ac/mdiq/podcini/net/download/ConnectionStateMonitor.kt
index 70558136..0e5eecf7 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/download/ConnectionStateMonitor.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/download/ConnectionStateMonitor.kt
@@ -1,5 +1,6 @@
package ac.mdiq.podcini.net.download
+import ac.mdiq.podcini.util.Logd
import android.content.Context
import android.net.ConnectivityManager
import android.net.ConnectivityManager.OnNetworkActiveListener
@@ -17,7 +18,7 @@ class ConnectionStateMonitor
.build()
@UnstableApi override fun onNetworkActive() {
- Log.d(TAG, "ConnectionStateMonitor::onNetworkActive network connection changed")
+ Logd(TAG, "ConnectionStateMonitor::onNetworkActive network connection changed")
NetworkConnectionChangeHandler.networkChangedDetected()
}
diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/FeedUpdateManager.kt b/app/src/main/java/ac/mdiq/podcini/net/download/FeedUpdateManager.kt
index 4782f137..96dc2d2f 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/download/FeedUpdateManager.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/download/FeedUpdateManager.kt
@@ -15,6 +15,7 @@ import ac.mdiq.podcini.util.NetworkUtils.networkAvailable
import ac.mdiq.podcini.util.event.MessageEvent
import ac.mdiq.podcini.storage.model.feed.Feed
import ac.mdiq.podcini.preferences.UserPreferences
+import ac.mdiq.podcini.util.Logd
import org.greenrobot.eventbus.EventBus
import java.util.concurrent.TimeUnit
@@ -68,7 +69,7 @@ object FeedUpdateManager {
@JvmStatic
@JvmOverloads
fun runOnceOrAsk(context: Context, feed: Feed? = null) {
- Log.d(TAG, "Run auto update immediately in background.")
+ Logd(TAG, "Run auto update immediately in background.")
when {
feed != null && feed.isLocalFeed -> runOnce(context, feed)
!networkAvailable() -> EventBus.getDefault().post(MessageEvent(context.getString(R.string.download_error_no_connection)))
diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/NetworkConnectionChangeHandler.kt b/app/src/main/java/ac/mdiq/podcini/net/download/NetworkConnectionChangeHandler.kt
index 70342cef..ebb02991 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/download/NetworkConnectionChangeHandler.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/download/NetworkConnectionChangeHandler.kt
@@ -7,6 +7,7 @@ import ac.mdiq.podcini.storage.DBTasks
import ac.mdiq.podcini.util.NetworkUtils.isAutoDownloadAllowed
import ac.mdiq.podcini.util.NetworkUtils.isNetworkRestricted
import ac.mdiq.podcini.net.download.serviceinterface.DownloadServiceInterface
+import ac.mdiq.podcini.util.Logd
@UnstableApi
object NetworkConnectionChangeHandler {
@@ -21,7 +22,7 @@ object NetworkConnectionChangeHandler {
@JvmStatic
fun networkChangedDetected() {
if (isAutoDownloadAllowed) {
- Log.d(TAG, "auto-dl network available, starting auto-download")
+ Logd(TAG, "auto-dl network available, starting auto-download")
DBTasks.autodownloadUndownloadedItems(context)
} else { // if new network is Wi-Fi, finish ongoing downloads,
// otherwise cancel all downloads
diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/BasicAuthorizationInterceptor.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/BasicAuthorizationInterceptor.kt
index 554d7eba..e1f1499f 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/download/service/BasicAuthorizationInterceptor.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/BasicAuthorizationInterceptor.kt
@@ -6,6 +6,7 @@ import ac.mdiq.podcini.net.download.service.HttpCredentialEncoder.encode
import ac.mdiq.podcini.storage.DBReader
import ac.mdiq.podcini.util.URIUtil
import ac.mdiq.podcini.net.download.serviceinterface.DownloadRequest
+import ac.mdiq.podcini.util.Logd
import okhttp3.Interceptor
import okhttp3.Interceptor.Chain
import okhttp3.Request
@@ -47,24 +48,24 @@ class BasicAuthorizationInterceptor : Interceptor {
} else userInfo = DBReader.getImageAuthentication(request.url.toString())
if (userInfo.isEmpty()) {
- Log.d(TAG, "no credentials for '" + request.url + "'")
+ Logd(TAG, "no credentials for '" + request.url + "'")
return response
}
if (!userInfo.contains(":")) {
- Log.d(TAG, "Invalid credentials for '" + request.url + "'")
+ Logd(TAG, "Invalid credentials for '" + request.url + "'")
return response
}
val username = userInfo.substring(0, userInfo.indexOf(':'))
val password = userInfo.substring(userInfo.indexOf(':') + 1)
- Log.d(TAG, "Authorization failed, re-trying with ISO-8859-1 encoded credentials")
+ Logd(TAG, "Authorization failed, re-trying with ISO-8859-1 encoded credentials")
newRequest.header(HEADER_AUTHORIZATION, encode(username, password, "ISO-8859-1"))
response = chain.proceed(newRequest.build())
if (response.code != HttpURLConnection.HTTP_UNAUTHORIZED) return response
- Log.d(TAG, "Authorization failed, re-trying with UTF-8 encoded credentials")
+ Logd(TAG, "Authorization failed, re-trying with UTF-8 encoded credentials")
newRequest.header(HEADER_AUTHORIZATION, encode(username, password, "UTF-8"))
return chain.proceed(newRequest.build())
}
diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/FeedUpdateWorker.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/FeedUpdateWorker.kt
index 6787c063..080fa887 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/download/service/FeedUpdateWorker.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/FeedUpdateWorker.kt
@@ -28,6 +28,7 @@ import ac.mdiq.podcini.ui.utils.NotificationUtils
import ac.mdiq.podcini.storage.model.download.DownloadError
import ac.mdiq.podcini.storage.model.download.DownloadResult
import ac.mdiq.podcini.storage.model.feed.Feed
+import ac.mdiq.podcini.util.Logd
import android.os.Build
import java.util.*
@@ -54,7 +55,7 @@ class FeedUpdateWorker(context: Context, params: WorkerParameters) : Worker(cont
toUpdate.shuffle() // If the worker gets cancelled early, every feed has a chance to be updated
} else {
val feed = DBReader.getFeed(feedId) ?: return Result.success()
- Log.d(TAG, "doWork feed.download_url: ${feed.download_url}")
+ Logd(TAG, "doWork feed.download_url: ${feed.download_url}")
if (!feed.isLocalFeed) allAreLocal = false
toUpdate = ArrayList()
toUpdate.add(feed) // Needs to be updatable, so no singletonList
@@ -63,7 +64,7 @@ class FeedUpdateWorker(context: Context, params: WorkerParameters) : Worker(cont
if (!inputData.getBoolean(FeedUpdateManager.EXTRA_EVEN_ON_MOBILE, false) && !allAreLocal) {
if (!NetworkUtils.networkAvailable() || !NetworkUtils.isFeedRefreshAllowed) {
- Log.d(TAG, "Blocking automatic update")
+ Logd(TAG, "Blocking automatic update")
return Result.retry()
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/PodciniHttpClient.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/PodciniHttpClient.kt
index c9301e08..21d5cab8 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/download/service/PodciniHttpClient.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/PodciniHttpClient.kt
@@ -3,6 +3,7 @@ package ac.mdiq.podcini.net.download.service
import android.util.Log
import ac.mdiq.podcini.storage.model.download.ProxyConfig
import ac.mdiq.podcini.net.ssl.SslClientSetup
+import ac.mdiq.podcini.util.Logd
import okhttp3.*
import okhttp3.Credentials.basic
import okhttp3.OkHttpClient.Builder
@@ -50,7 +51,7 @@ object PodciniHttpClient {
*/
@JvmStatic
fun newBuilder(): Builder {
- Log.d(TAG, "Creating new instance of HTTP client")
+ Logd(TAG, "Creating new instance of HTTP client")
System.setProperty("http.maxConnections", MAX_CONNECTIONS.toString())
diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/handler/FeedParserTask.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/handler/FeedParserTask.kt
index a6133805..649cced5 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/download/service/handler/FeedParserTask.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/handler/FeedParserTask.kt
@@ -10,6 +10,7 @@ import ac.mdiq.podcini.storage.model.feed.FeedPreferences
import ac.mdiq.podcini.storage.model.feed.VolumeAdaptionSetting
import ac.mdiq.podcini.net.download.serviceinterface.DownloadRequest
import ac.mdiq.podcini.feed.parser.UnsupportedFeedtypeException
+import ac.mdiq.podcini.util.Logd
import org.xml.sax.SAXException
import java.io.File
import java.io.IOException
@@ -44,7 +45,7 @@ class FeedParserTask(private val request: DownloadRequest) : Callable = getFeedListDownloadUrls()
@@ -104,11 +105,11 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
val queuedRemovedFeeds: MutableList = synchronizationQueueStorage.queuedRemovedFeeds
var queuedAddedFeeds: List = synchronizationQueueStorage.queuedAddedFeeds
- Log.d(TAG, "Downloaded subscription changes: $subscriptionChanges")
+ Logd(TAG, "Downloaded subscription changes: $subscriptionChanges")
if (subscriptionChanges != null) {
for (downloadUrl in subscriptionChanges.added) {
if (!downloadUrl.startsWith("http")) { // Also matches https
- Log.d(TAG, "Skipping url: $downloadUrl")
+ Logd(TAG, "Skipping url: $downloadUrl")
continue
}
if (!containsUrl(localSubscriptions, downloadUrl) && !queuedRemovedFeeds.contains(downloadUrl)) {
@@ -125,7 +126,7 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
}
if (lastSync == 0L) {
- Log.d(TAG, "First sync. Adding all local subscriptions.")
+ Logd(TAG, "First sync. Adding all local subscriptions.")
queuedAddedFeeds = localSubscriptions.toMutableList()
queuedAddedFeeds.removeAll(subscriptionChanges.added)
queuedRemovedFeeds.removeAll(subscriptionChanges.removed)
@@ -133,8 +134,8 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
}
if (queuedAddedFeeds.isNotEmpty() || queuedRemovedFeeds.size > 0) {
- Log.d(TAG, "Added: " + StringUtils.join(queuedAddedFeeds, ", "))
- Log.d(TAG, "Removed: " + StringUtils.join(queuedRemovedFeeds, ", "))
+ Logd(TAG, "Added: " + StringUtils.join(queuedAddedFeeds, ", "))
+ Logd(TAG, "Removed: " + StringUtils.join(queuedRemovedFeeds, ", "))
LockingAsyncExecutor.lock.lock()
try {
@@ -149,7 +150,7 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
}
private fun waitForDownloadServiceCompleted() {
- Log.d(TAG, "waitForDownloadServiceCompleted called")
+ Logd(TAG, "waitForDownloadServiceCompleted called")
EventBus.getDefault().postSticky(SyncServiceEvent(R.string.sync_status_wait_for_downloads))
try {
while (true) {
@@ -179,7 +180,7 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
if (lastSync == 0L) {
EventBus.getDefault().postSticky(SyncServiceEvent(R.string.sync_status_upload_played))
val readItems = getEpisodes(0, Int.MAX_VALUE, FeedItemFilter(FeedItemFilter.PLAYED), SortOrder.DATE_NEW_OLD)
- Log.d(TAG, "First sync. Upload state for all " + readItems.size + " played episodes")
+ Logd(TAG, "First sync. Upload state for all " + readItems.size + " played episodes")
for (item in readItems) {
val media = item.media ?: continue
val played = EpisodeAction.Builder(item, EpisodeAction.PLAY)
@@ -194,10 +195,10 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
if (queuedEpisodeActions.isNotEmpty()) {
LockingAsyncExecutor.lock.lock()
try {
- Log.d(TAG, "Uploading ${queuedEpisodeActions.size} actions: ${StringUtils.join(queuedEpisodeActions, ", ")}")
+ Logd(TAG, "Uploading ${queuedEpisodeActions.size} actions: ${StringUtils.join(queuedEpisodeActions, ", ")}")
val postResponse = syncServiceImpl.uploadEpisodeActions(queuedEpisodeActions)
newTimeStamp = postResponse?.timestamp?:0L
- Log.d(TAG, "Upload episode response: $postResponse")
+ Logd(TAG, "Upload episode response: $postResponse")
synchronizationQueueStorage.clearEpisodeActionQueue()
} finally {
LockingAsyncExecutor.lock.unlock()
@@ -208,7 +209,7 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
@UnstableApi @Throws(SyncServiceException::class)
private fun syncEpisodeActions(syncServiceImpl: ISyncService) {
- Log.d(TAG, "syncEpisodeActions called")
+ Logd(TAG, "syncEpisodeActions called")
var (lastSync, newTimeStamp) = getEpisodeActions(syncServiceImpl)
// upload local actions
@@ -230,18 +231,18 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
var idRemove = 0L
feedItem.media!!.setPosition(action.position * 1000)
if (hasAlmostEnded(feedItem.media!!)) {
- Log.d(TAG, "Marking as played: $action")
+ Logd(TAG, "Marking as played: $action")
feedItem.setPlayed(true)
feedItem.media!!.setPosition(0)
idRemove = feedItem.id
- } else Log.d(TAG, "Setting position: $action")
+ } else Logd(TAG, "Setting position: $action")
return Pair(idRemove, feedItem)
}
@UnstableApi @Synchronized
fun processEpisodeActions(remoteActions: List) {
- Log.d(TAG, "Processing " + remoteActions.size + " actions")
+ Logd(TAG, "Processing " + remoteActions.size + " actions")
if (remoteActions.isEmpty()) return
val playActionsToUpdate = getRemoteActionsOverridingLocalActions(remoteActions, synchronizationQueueStorage.queuedEpisodeActions)
@@ -264,11 +265,11 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
}
protected fun updateErrorNotification(exception: Exception) {
- Log.d(TAG, "Posting sync error notification")
+ Logd(TAG, "Posting sync error notification")
val description = ("${applicationContext.getString(R.string.gpodnetsync_error_descr)}${exception.message}")
if (!gpodnetNotificationsEnabled()) {
- Log.d(TAG, "Skipping sync error notification because of user setting")
+ Logd(TAG, "Skipping sync error notification because of user setting")
return
}
if (EventBus.getDefault().hasSubscriberForEvent(MessageEvent::class.java)) {
diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/GpodnetService.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/GpodnetService.kt
index febf0ffa..74ec6d61 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/GpodnetService.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/GpodnetService.kt
@@ -10,6 +10,7 @@ import ac.mdiq.podcini.net.sync.gpoddernet.model.GpodnetEpisodeActionPostRespons
import ac.mdiq.podcini.net.sync.gpoddernet.model.GpodnetPodcast
import ac.mdiq.podcini.net.sync.gpoddernet.model.GpodnetUploadChangesResponse
import ac.mdiq.podcini.net.sync.model.*
+import ac.mdiq.podcini.util.Logd
import android.util.Log
import okhttp3.*
import okhttp3.Credentials.basic
@@ -278,7 +279,7 @@ class GpodnetService(private val httpClient: OkHttpClient, baseHosturl: String?,
@Throws(SyncServiceException::class)
private fun uploadEpisodeActionsPartial(episodeActions: List?, from: Int, to: Int): UploadChangesResponse {
try {
- Log.d(TAG, "Uploading partial actions " + from + " to " + to + " of " + episodeActions!!.size)
+ Logd(TAG, "Uploading partial actions " + from + " to " + to + " of " + episodeActions!!.size)
val url = URI(baseScheme, null, baseHost, basePort,
String.format("/api/2/episodes/%s.json", username), null, null).toURL()
@@ -424,7 +425,7 @@ class GpodnetService(private val httpClient: OkHttpClient, baseHosturl: String?,
} else {
if (BuildConfig.DEBUG) {
try {
- Log.d(TAG, response.body!!.string())
+ Logd(TAG, response.body!!.string())
} catch (e: IOException) {
e.printStackTrace()
}
diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/wifi/WifiSyncService.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/wifi/WifiSyncService.kt
index 51e1d717..bd643f06 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/sync/wifi/WifiSyncService.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/sync/wifi/WifiSyncService.kt
@@ -15,6 +15,7 @@ import ac.mdiq.podcini.storage.model.feed.FeedItem
import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
import ac.mdiq.podcini.storage.model.feed.SortOrder
import ac.mdiq.podcini.util.FeedItemUtil.hasAlmostEnded
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.SyncServiceEvent
import android.content.Context
import android.util.Log
@@ -38,7 +39,7 @@ import kotlin.math.min
var loginFail = false
override fun doWork(): Result {
- Log.d(TAG, "doWork() called")
+ Logd(TAG, "doWork() called")
SynchronizationSettings.updateLastSynchronizationAttempt()
setCurrentlyActive(true)
@@ -107,7 +108,7 @@ import kotlin.math.min
private var socket: Socket? = null
@OptIn(UnstableApi::class) override fun login() {
- Log.d(TAG, "serverIp: $hostIp serverPort: $hostPort $isGuest")
+ Logd(TAG, "serverIp: $hostIp serverPort: $hostPort $isGuest")
EventBus.getDefault().post(SyncServiceEvent(R.string.sync_status_in_progress, "2"))
if (!isPortInUse(hostPort)) {
if (isGuest) {
@@ -134,7 +135,7 @@ import kotlin.math.min
try {
socket = serverSocket!!.accept()
while (true) {
- Log.d(TAG, "waiting for guest message")
+ Logd(TAG, "waiting for guest message")
try {
receiveFromPeer()
sendToPeer("Hello", "Hello, Client")
@@ -191,30 +192,24 @@ import kotlin.math.min
val messageData = parts[1]
// Process the message based on the type
when (messageType) {
- "Hello" -> Log.d(TAG, "Received Hello message: $messageData")
+ "Hello" -> Logd(TAG, "Received Hello message: $messageData")
"EpisodeActions" -> {
val remoteActions = mutableListOf()
val jsonArray = JSONArray(messageData)
for (i in 0 until jsonArray.length()) {
val jsonAction = jsonArray.getJSONObject(i)
-// TODO: this conversion shouldn't be needed, check about the uploader
-// val timeStr = jsonAction.getString("timestamp")
-// val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US)
-// val date = format.parse(timeStr)
-// jsonAction.put("timestamp", date?.time?:0L)
-
- Log.d(TAG, "Received EpisodeActions message: $i $jsonAction")
+ Logd(TAG, "Received EpisodeActions message: $i $jsonAction")
val action = readFromJsonObject(jsonAction)
if (action != null) remoteActions.add(action)
}
processEpisodeActions(remoteActions)
}
"AllSent" -> {
- Log.d(TAG, "Received AllSent message: $messageData")
+ Logd(TAG, "Received AllSent message: $messageData")
return true
}
- else -> Log.d(TAG, "Received unknown message: $messageData")
+ else -> Logd(TAG, "Received unknown message: $messageData")
}
}
}
@@ -223,19 +218,19 @@ import kotlin.math.min
@Throws(SyncServiceException::class)
override fun getSubscriptionChanges(lastSync: Long): SubscriptionChanges? {
- Log.d(TAG, "getSubscriptionChanges does nothing")
+ Logd(TAG, "getSubscriptionChanges does nothing")
return null
}
@Throws(SyncServiceException::class)
override fun uploadSubscriptionChanges(added: List, removed: List): UploadChangesResponse? {
- Log.d(TAG, "uploadSubscriptionChanges does nothing")
+ Logd(TAG, "uploadSubscriptionChanges does nothing")
return null
}
@Throws(SyncServiceException::class)
override fun getEpisodeActionChanges(timestamp: Long): EpisodeActionChanges? {
- Log.d(TAG, "getEpisodeActionChanges does nothing")
+ Logd(TAG, "getEpisodeActionChanges does nothing")
return null
}
@@ -243,7 +238,7 @@ import kotlin.math.min
var newTimeStamp = newTimeStamp_
EventBus.getDefault().postSticky(SyncServiceEvent(R.string.sync_status_episodes_upload))
val queuedEpisodeActions: MutableList = synchronizationQueueStorage.queuedEpisodeActions
- Log.d(TAG, "pushEpisodeActions queuedEpisodeActions: ${queuedEpisodeActions.size}")
+ Logd(TAG, "pushEpisodeActions queuedEpisodeActions: ${queuedEpisodeActions.size}")
if (lastSync == 0L) {
EventBus.getDefault().postSticky(SyncServiceEvent(R.string.sync_status_upload_played))
@@ -253,7 +248,7 @@ import kotlin.math.min
val comItems = mutableSetOf()
comItems.addAll(pausedItems)
comItems.addAll(readItems)
- Log.d(TAG, "First sync. Upload state for all " + comItems.size + " played episodes")
+ Logd(TAG, "First sync. Upload state for all " + comItems.size + " played episodes")
for (item in comItems) {
val media = item.media ?: continue
val played = EpisodeAction.Builder(item, EpisodeAction.PLAY)
@@ -268,10 +263,10 @@ import kotlin.math.min
if (queuedEpisodeActions.isNotEmpty()) {
LockingAsyncExecutor.lock.lock()
try {
- Log.d(TAG, "Uploading ${queuedEpisodeActions.size} actions: ${StringUtils.join(queuedEpisodeActions, ", ")}")
+ Logd(TAG, "Uploading ${queuedEpisodeActions.size} actions: ${StringUtils.join(queuedEpisodeActions, ", ")}")
val postResponse = uploadEpisodeActions(queuedEpisodeActions)
newTimeStamp = postResponse.timestamp
- Log.d(TAG, "Upload episode response: $postResponse")
+ Logd(TAG, "Upload episode response: $postResponse")
synchronizationQueueStorage.clearEpisodeActionQueue()
} finally {
LockingAsyncExecutor.lock.unlock()
@@ -301,7 +296,7 @@ import kotlin.math.min
val episodeAction = queuedEpisodeActions[i]
val obj = episodeAction.writeToJsonObject()
if (obj != null) {
- Log.d(TAG, "sending EpisodeAction: $obj")
+ Logd(TAG, "sending EpisodeAction: $obj")
list.put(obj)
}
}
@@ -325,18 +320,18 @@ import kotlin.math.min
}
feedItem.media = getFeedMedia(feedItem.media!!.id)
var idRemove = 0L
- Log.d(TAG, "processEpisodeAction ${feedItem.media!!.getLastPlayedTime()} ${(action.timestamp?.time?:0L)} ${action.position} ${feedItem.title}")
+ Logd(TAG, "processEpisodeAction ${feedItem.media!!.getLastPlayedTime()} ${(action.timestamp?.time?:0L)} ${action.position} ${feedItem.title}")
if (feedItem.media!!.getLastPlayedTime() < (action.timestamp?.time?:0L)) {
feedItem.media!!.setPosition(action.position * 1000)
feedItem.media!!.setLastPlayedTime(action.timestamp!!.time)
if (hasAlmostEnded(feedItem.media!!)) {
- Log.d(TAG, "Marking as played")
+ Logd(TAG, "Marking as played")
feedItem.setPlayed(true)
feedItem.media!!.setPosition(0)
idRemove = feedItem.id
- } else Log.d(TAG, "Setting position")
+ } else Logd(TAG, "Setting position")
persistFeedMediaPlaybackInfo(feedItem.media)
- } else Log.d(TAG, "local is newer, no change")
+ } else Logd(TAG, "local is newer, no change")
return Pair(idRemove, feedItem)
}
diff --git a/app/src/main/java/ac/mdiq/podcini/playback/PlaybackController.kt b/app/src/main/java/ac/mdiq/podcini/playback/PlaybackController.kt
index a151a2de..a5e5cd48 100644
--- a/app/src/main/java/ac/mdiq/podcini/playback/PlaybackController.kt
+++ b/app/src/main/java/ac/mdiq/podcini/playback/PlaybackController.kt
@@ -40,7 +40,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
private var initialized = false
private var eventsRegistered = false
- private var loadedFeedMedia: Long = -1
+ private var loadedFeedMediaId: Long = -1
val position: Int
get() = playbackService?.currentPosition ?: getMedia()?.getPosition() ?: Playable.INVALID_TIME
@@ -114,7 +114,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
// ignore
}
unbind()
- media = null
+// media = null
released = true
if (eventsRegistered) {
@@ -235,8 +235,9 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
}
private fun checkMediaInfoLoaded() {
- if (!mediaInfoLoaded || loadedFeedMedia != PlaybackPreferences.currentlyPlayingFeedMediaId) {
- loadedFeedMedia = PlaybackPreferences.currentlyPlayingFeedMediaId
+ if (!mediaInfoLoaded || loadedFeedMediaId != PlaybackPreferences.currentlyPlayingFeedMediaId) {
+ loadedFeedMediaId = PlaybackPreferences.currentlyPlayingFeedMediaId
+ Logd(TAG, "checkMediaInfoLoaded: $loadedFeedMediaId")
loadMediaInfo()
}
mediaInfoLoaded = true
diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/LocalMediaPlayer.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/LocalMediaPlayer.kt
index b0503545..6607f3af 100644
--- a/app/src/main/java/ac/mdiq/podcini/playback/service/LocalMediaPlayer.kt
+++ b/app/src/main/java/ac/mdiq/podcini/playback/service/LocalMediaPlayer.kt
@@ -48,12 +48,11 @@ import androidx.media3.extractor.DefaultExtractorsFactory
import androidx.media3.extractor.mp3.Mp3Extractor
import androidx.media3.ui.DefaultTrackNameProvider
import androidx.media3.ui.TrackNameProvider
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import java.io.File
import java.io.IOException
+import java.lang.Runnable
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
@@ -83,8 +82,8 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
private var isShutDown = false
private var seekLatch: CountDownLatch? = null
- private val bufferUpdateInterval = 5L
- private val bufferingUpdateDisposable: Disposable
+ private val bufferUpdateInterval = 5000L
+// private val bufferingUpdateDisposable: Disposable
private var mediaSource: MediaSource? = null
private var playbackParameters: PlaybackParameters
@@ -125,7 +124,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
}
private fun release() {
- bufferingUpdateDisposable.dispose()
+// bufferingUpdateDisposable.dispose()
// exoplayerListener = null
exoPlayer?.stop()
@@ -670,11 +669,20 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
createStaticPlayer(context)
}
playbackParameters = exoPlayer!!.playbackParameters
- bufferingUpdateDisposable = Observable.interval(bufferUpdateInterval, TimeUnit.SECONDS)
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe {
- bufferingUpdateListener?.accept(exoPlayer!!.bufferedPercentage)
+// bufferingUpdateDisposable = Observable.interval(bufferUpdateInterval, TimeUnit.SECONDS)
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe {
+// bufferingUpdateListener?.accept(exoPlayer!!.bufferedPercentage)
+// }
+ val scope = CoroutineScope(Dispatchers.Main)
+ scope.launch {
+ while (true) {
+ delay(bufferUpdateInterval)
+ withContext(Dispatchers.Main) {
+ bufferingUpdateListener?.accept(exoPlayer!!.bufferedPercentage)
+ }
}
+ }
}
override fun endPlayback(hasEnded: Boolean, wasSkipped: Boolean, shouldContinue: Boolean, toStoppedState: Boolean) {
diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackService.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackService.kt
index 10e99de3..eb57e70b 100644
--- a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackService.kt
+++ b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackService.kt
@@ -4,8 +4,8 @@ import ac.mdiq.podcini.R
import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
import ac.mdiq.podcini.playback.PlaybackServiceStarter
import ac.mdiq.podcini.playback.base.MediaPlayerBase
-import ac.mdiq.podcini.playback.base.MediaPlayerBase.MediaPlayerInfo
import ac.mdiq.podcini.playback.base.MediaPlayerBase.MediaPlayerCallback
+import ac.mdiq.podcini.playback.base.MediaPlayerBase.MediaPlayerInfo
import ac.mdiq.podcini.playback.base.PlayerStatus
import ac.mdiq.podcini.playback.cast.CastPsmp
import ac.mdiq.podcini.playback.cast.CastStateListener
@@ -91,10 +91,10 @@ import androidx.media3.session.SessionResult
import androidx.work.impl.utils.futures.SettableFuture
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -108,7 +108,8 @@ import kotlin.math.max
@UnstableApi
class PlaybackService : MediaSessionService() {
private var mediaPlayer: MediaPlayerBase? = null
- private var positionEventTimer: Disposable? = null
+
+ val scope = CoroutineScope(Dispatchers.Main)
private lateinit var customMediaNotificationProvider: CustomMediaNotificationProvider
private val notificationCustomButtons = NotificationCustomButton.entries.map { command -> command.commandButton }
@@ -261,7 +262,6 @@ class PlaybackService : MediaSessionService() {
currentMediaType = MediaType.UNKNOWN
castStateListener.destroy()
-// cancelPositionObserver()
LocalMediaPlayer.cleanup()
mediaSession?.run {
player.release()
@@ -367,139 +367,6 @@ class PlaybackService : MediaSessionService() {
return mediaSession
}
-// private fun loadQueueForMediaSession() {
-// Single.create { emitter: SingleEmitter?> ->
-// val queueItems: MutableList = ArrayList()
-// for (feedItem in DBReader.getQueue()) {
-// if (feedItem.media != null) {
-// val mediaDescription = feedItem.media!!.mediaItem.description
-// queueItems.add(MediaSessionCompat.QueueItem(mediaDescription, feedItem.id))
-// }
-// }
-// emitter.onSuccess(queueItems)
-// }
-// .subscribeOn(Schedulers.io())
-// .observeOn(AndroidSchedulers.mainThread())
-// .subscribe({
-//// mediaSession?.setQueue(queueItems)
-// },
-// { obj: Throwable -> obj.printStackTrace() })
-// }
-
-// private fun createBrowsableMediaItem(@StringRes title: Int, @DrawableRes icon: Int, numEpisodes: Int): MediaItem {
-// val uri = Uri.Builder()
-// .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
-// .authority(resources.getResourcePackageName(icon))
-// .appendPath(resources.getResourceTypeName(icon))
-// .appendPath(resources.getResourceEntryName(icon))
-// .build()
-//
-// val description = MediaDescription.Builder()
-// .setIconUri(uri)
-// .setMediaId(resources.getString(title))
-// .setTitle(resources.getString(title))
-// .setSubtitle(resources.getQuantityString(R.plurals.num_episodes, numEpisodes, numEpisodes))
-// .build()
-// return MediaItem(description, MediaItem.FLAG_BROWSABLE)
-// }
-
-// private fun createBrowsableMediaItemForFeed(feed: Feed): MediaItem {
-// val builder = MediaDescription.Builder()
-// .setMediaId("FeedId:" + feed.id)
-// .setTitle(feed.title)
-// .setDescription(feed.description)
-// .setSubtitle(feed.getCustomTitle())
-// if (feed.imageUrl != null) {
-// builder.setIconUri(Uri.parse(feed.imageUrl))
-// }
-// if (feed.link != null) {
-// builder.setMediaUri(Uri.parse(feed.link))
-// }
-// val description = builder.build()
-// return MediaItem(description, MediaItem.FLAG_BROWSABLE)
-// }
-
-// override fun onLoadChildren(parentId: String, result: Result>) {
-// Log.d(TAG, "OnLoadChildren: parentMediaId=$parentId")
-// result.detach()
-//
-// Completable.create { emitter: CompletableEmitter ->
-// result.sendResult(loadChildrenSynchronous(parentId))
-// emitter.onComplete()
-// }
-// .subscribeOn(Schedulers.io())
-// .observeOn(AndroidSchedulers.mainThread())
-// .subscribe(
-// {}, { e: Throwable ->
-// e.printStackTrace()
-// result.sendResult(null)
-// })
-// }
-
-// private fun loadChildrenSynchronous(parentId: String): List? {
-// val mediaItems: MutableList = ArrayList()
-// if (parentId == resources.getString(R.string.app_name)) {
-// val currentlyPlaying = currentPlayerStatus.toLong()
-// if (currentlyPlaying == PlaybackPreferences.PLAYER_STATUS_PLAYING.toLong()
-// || currentlyPlaying == PlaybackPreferences.PLAYER_STATUS_PAUSED.toLong()) {
-// mediaItems.add(createBrowsableMediaItem(R.string.current_playing_episode, R.drawable.ic_play_48dp, 1))
-// }
-// mediaItems.add(createBrowsableMediaItem(R.string.queue_label, R.drawable.ic_playlist_play_black,
-// DBReader.getTotalEpisodeCount(FeedItemFilter(FeedItemFilter.QUEUED))))
-// mediaItems.add(createBrowsableMediaItem(R.string.downloads_label, R.drawable.ic_download_black,
-// DBReader.getTotalEpisodeCount(FeedItemFilter(FeedItemFilter.DOWNLOADED))))
-// mediaItems.add(createBrowsableMediaItem(R.string.episodes_label, R.drawable.ic_feed_black,
-// DBReader.getTotalEpisodeCount(FeedItemFilter(FeedItemFilter.UNPLAYED))))
-// val feeds = DBReader.getFeedList()
-// for (feed in feeds) {
-// mediaItems.add(createBrowsableMediaItemForFeed(feed))
-// }
-// return mediaItems
-// }
-//
-// val feedItems: List
-// when {
-// parentId == resources.getString(R.string.queue_label) -> {
-// feedItems = DBReader.getQueue()
-// }
-// parentId == resources.getString(R.string.downloads_label) -> {
-// feedItems = DBReader.getEpisodes(0, MAX_ANDROID_AUTO_EPISODES_PER_FEED,
-// FeedItemFilter(FeedItemFilter.DOWNLOADED), downloadsSortedOrder)
-// }
-// parentId == resources.getString(R.string.episodes_label) -> {
-// feedItems = DBReader.getEpisodes(0, MAX_ANDROID_AUTO_EPISODES_PER_FEED,
-// FeedItemFilter(FeedItemFilter.UNPLAYED), allEpisodesSortOrder)
-// }
-// parentId.startsWith("FeedId:") -> {
-// val feedId = parentId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1].toLong()
-// val feed = DBReader.getFeed(feedId)
-// feedItems = if (feed != null) DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(), feed.sortOrder) else listOf()
-// }
-// parentId == getString(R.string.current_playing_episode) -> {
-// val playable = createInstanceFromPreferences(this)
-// if (playable is FeedMedia) {
-// feedItems = listOf(playable.item)
-// } else {
-// return null
-// }
-// }
-// else -> {
-// Log.e(TAG, "Parent ID not found: $parentId")
-// return null
-// }
-// }
-// var count = 0
-// for (feedItem in feedItems) {
-// if (feedItem?.media != null) {
-// mediaItems.add(feedItem.media!!.mediaItem)
-// if (++count >= MAX_ANDROID_AUTO_EPISODES_PER_FEED) {
-// break
-// }
-// }
-// }
-// return mediaItems
-// }
-
override fun onBind(intent: Intent?): IBinder? {
Logd(TAG, "Received onBind event")
return if (intent?.action != null && TextUtils.equals(intent.action, SERVICE_INTERFACE)) {
@@ -544,23 +411,37 @@ class PlaybackService : MediaSessionService() {
val allowStreamAlways = intent.getBooleanExtra(PlaybackServiceConstants.EXTRA_ALLOW_STREAM_ALWAYS, false)
sendNotificationBroadcast(PlaybackServiceConstants.NOTIFICATION_TYPE_RELOAD, 0)
if (allowStreamAlways) isAllowMobileStreaming = true
- Observable.fromCallable {
- if (playable is FeedMedia) return@fromCallable DBReader.getFeedMedia(playable.id)
- else return@fromCallable playable
+
+// Observable.fromCallable {
+// if (playable is FeedMedia) return@fromCallable DBReader.getFeedMedia(playable.id)
+// else return@fromCallable playable
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { loadedPlayable: Playable? -> startPlaying(loadedPlayable, allowStreamThisTime) },
+// { error: Throwable ->
+// Logd(TAG, "Playable was not found. Stopping service.")
+// error.printStackTrace()
+// })
+
+ scope.launch {
+ try {
+ val loadedPlayable = withContext(Dispatchers.IO) {
+ if (playable is FeedMedia) DBReader.getFeedMedia(playable.id)
+ else playable
+ }
+ withContext(Dispatchers.Main) {
+ startPlaying(loadedPlayable, allowStreamThisTime)
+ }
+ } catch (e: Throwable) {
+ Logd(TAG, "Playable was not found. Stopping service.")
+ e.printStackTrace()
+ }
}
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { loadedPlayable: Playable? -> startPlaying(loadedPlayable, allowStreamThisTime) },
- { error: Throwable ->
- Logd(TAG, "Playable was not found. Stopping service.")
- error.printStackTrace()
- })
return START_NOT_STICKY
}
- else -> {
-// mediaSession?.controller?.transportControls?.sendCustomAction(customAction, null)
- }
+ else -> {}
}
}
@@ -724,15 +605,28 @@ class PlaybackService : MediaSessionService() {
}
private fun startPlayingFromPreferences() {
- Observable.fromCallable { createInstanceFromPreferences(applicationContext) }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { playable: Playable? -> startPlaying(playable, false) },
- { error: Throwable ->
- Logd(TAG, "Playable was not loaded from preferences. Stopping service.")
- error.printStackTrace()
- })
+// Observable.fromCallable { createInstanceFromPreferences(applicationContext) }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { playable: Playable? -> startPlaying(playable, false) },
+// { error: Throwable ->
+// Logd(TAG, "Playable was not loaded from preferences. Stopping service.")
+// error.printStackTrace()
+// })
+ scope.launch {
+ try {
+ val playable = withContext(Dispatchers.IO) {
+ createInstanceFromPreferences(applicationContext)
+ }
+ withContext(Dispatchers.Main) {
+ startPlaying(playable, false)
+ }
+ } catch (e: Throwable) {
+ Logd(TAG, "Playable was not loaded from preferences. Stopping service.")
+ e.printStackTrace()
+ }
+ }
}
private fun startPlaying(playable: Playable?, allowStreamThisTime: Boolean) {
@@ -750,7 +644,6 @@ class PlaybackService : MediaSessionService() {
mediaPlayer?.playMediaObject(playable, stream, startWhenPrepared = true, true)
recreateMediaSessionIfNeeded()
-// updateNotificationAndMediaSession(playable)
addPlayableToQueue(playable)
// EventBus.getDefault().post(PlaybackServiceEvent(PlaybackServiceEvent.Action.SERVICE_RESTARTED))
}
@@ -767,10 +660,8 @@ class PlaybackService : MediaSessionService() {
fun notifyVideoSurfaceAbandoned() {
mediaPlayer?.pause(abandonFocus = true, reinit = false)
mediaPlayer?.resetVideoSurface()
-// updateNotificationAndMediaSession(playable)
}
- // TODO: positionEventTimer also monitors position, should be combined?
private val taskManagerCallback: PSTMCallback = object : PSTMCallback {
override fun positionSaverTick() {
if (currentPosition != previousPosition) {
@@ -789,7 +680,6 @@ class PlaybackService : MediaSessionService() {
override fun onChapterLoaded(media: Playable?) {
sendNotificationBroadcast(PlaybackServiceConstants.NOTIFICATION_TYPE_RELOAD, 0)
-// updateMediaSession(MediaPlayerBase.status)
}
}
@@ -797,29 +687,24 @@ class PlaybackService : MediaSessionService() {
override fun statusChanged(newInfo: MediaPlayerInfo?) {
currentMediaType = mediaPlayer?.getCurrentMediaType() ?: MediaType.UNKNOWN
Logd(TAG, "statusChanged called ${newInfo?.playerStatus}")
-// updateMediaSession(newInfo?.playerStatus)
if (newInfo != null) {
when (newInfo.playerStatus) {
- PlayerStatus.INITIALIZED -> {
+ PlayerStatus.INITIALIZED ->
if (mediaPlayer != null) writeMediaPlaying(mediaPlayer!!.playerInfo.playable, mediaPlayer!!.playerInfo.playerStatus, currentitem)
-// updateNotificationAndMediaSession(newInfo.playable)
- }
PlayerStatus.PREPARED -> {
if (mediaPlayer != null) writeMediaPlaying(mediaPlayer!!.playerInfo.playable, mediaPlayer!!.playerInfo.playerStatus, currentitem)
taskManager.startChapterLoader(newInfo.playable!!)
}
PlayerStatus.PAUSED -> {
-// updateNotificationAndMediaSession(newInfo.playable)
-// cancelPositionObserver()
if (mediaPlayer != null) writePlayerStatus(MediaPlayerBase.status)
}
PlayerStatus.STOPPED -> {}
PlayerStatus.PLAYING -> {
- if (mediaPlayer != null) writePlayerStatus(MediaPlayerBase.status)
+ if (mediaPlayer != null) {
+ writePlayerStatus(MediaPlayerBase.status)
+ }
saveCurrentPosition(true, null, Playable.INVALID_TIME)
recreateMediaSessionIfNeeded()
-// updateNotificationAndMediaSession(newInfo.playable)
-// setupPositionObserver()
// set sleep timer if auto-enabled
var autoEnableByTime = true
val fromSetting = autoEnableFrom()
@@ -857,7 +742,6 @@ class PlaybackService : MediaSessionService() {
override fun onMediaChanged(reloadUI: Boolean) {
Logd(TAG, "reloadUI callback reached")
if (reloadUI) sendNotificationBroadcast(PlaybackServiceConstants.NOTIFICATION_TYPE_RELOAD, 0)
-// updateNotificationAndMediaSession(this@PlaybackService.playable)
}
override fun onPostPlayback(media: Playable?, ended: Boolean, skipped: Boolean, playingNext: Boolean) {
@@ -874,7 +758,6 @@ class PlaybackService : MediaSessionService() {
override fun onPlaybackPause(playable: Playable?, position: Int) {
taskManager.cancelPositionSaver()
-// cancelPositionObserver()
saveCurrentPosition(position == Playable.INVALID_TIME || playable == null, playable, position)
taskManager.cancelWidgetUpdater()
if (playable != null) {
@@ -917,7 +800,6 @@ class PlaybackService : MediaSessionService() {
// Playable is being streamed and does not have a duration specified in the feed
playable.setDuration(mediaPlayer!!.getDuration())
DBWriter.persistFeedMedia(playable as FeedMedia)
-// updateNotificationAndMediaSession(playable)
}
}
}
@@ -942,7 +824,7 @@ class PlaybackService : MediaSessionService() {
}
private fun getNextInQueue(currentMedia: Playable?): Playable? {
- Logd(TAG, "getNextInQueue currentMedia: ${currentMedia?.getEpisodeTitle()}")
+ Logd(TAG, "*** expensive call getNextInQueue currentMedia: ${currentMedia?.getEpisodeTitle()}")
if (currentMedia !is FeedMedia) {
Logd(TAG, "getNextInQueue(), but playable not an instance of FeedMedia, so not proceeding")
writeNoMediaPlaying()
@@ -966,7 +848,6 @@ class PlaybackService : MediaSessionService() {
if (!isFollowQueue) {
Logd(TAG, "getNextInQueue(), but follow queue is not enabled.")
writeMediaPlaying(nextItem.media, PlayerStatus.STOPPED, currentitem)
-// updateNotificationAndMediaSession(nextItem.media)
return null
}
@@ -975,6 +856,7 @@ class PlaybackService : MediaSessionService() {
writeNoMediaPlaying()
return null
}
+ EventBus.getDefault().post(StartPlayEvent(nextItem))
return nextItem.media
}
@@ -986,7 +868,6 @@ class PlaybackService : MediaSessionService() {
clearCurrentlyPlayingTemporaryPlaybackSpeed()
if (stopPlaying) {
taskManager.cancelPositionSaver()
-// cancelPositionObserver()
}
if (mediaType == null) {
sendNotificationBroadcast(PlaybackServiceConstants.NOTIFICATION_TYPE_PLAYBACK_END, 0)
@@ -1070,7 +951,6 @@ class PlaybackService : MediaSessionService() {
DBWriter.deleteFeedMediaOfItem(this@PlaybackService, media.id)
Logd(TAG, "Episode Deleted")
}
-// notifyChildrenChanged(getString(R.string.queue_label))
}
}
@@ -1119,76 +999,6 @@ class PlaybackService : MediaSessionService() {
}
}
- /**
- * Updates the Media Session for the corresponding status.
- */
-// private fun updateMediaSession(playerStatus: PlayerStatus?) {
-// val sessionState = PlaybackStateCompat.Builder()
-// val state = if (playerStatus != null) {
-// when (playerStatus) {
-// PlayerStatus.PLAYING -> PlaybackStateCompat.STATE_PLAYING
-// PlayerStatus.FALLBACK -> PlaybackStateCompat.STATE_PLAYING
-// PlayerStatus.PREPARED, PlayerStatus.PAUSED -> PlaybackStateCompat.STATE_PAUSED
-// PlayerStatus.STOPPED -> PlaybackStateCompat.STATE_STOPPED
-// PlayerStatus.SEEKING -> PlaybackStateCompat.STATE_FAST_FORWARDING
-// PlayerStatus.PREPARING, PlayerStatus.INITIALIZING -> PlaybackStateCompat.STATE_CONNECTING
-// PlayerStatus.ERROR -> PlaybackStateCompat.STATE_ERROR
-// PlayerStatus.INITIALIZED, PlayerStatus.INDETERMINATE -> PlaybackStateCompat.STATE_NONE
-// }
-// } else {
-// PlaybackStateCompat.STATE_NONE
-// }
-//
-// sessionState.setState(state, currentPosition.toLong(), currentPlaybackSpeed)
-// val capabilities = (PlaybackStateCompat.ACTION_PLAY
-// or PlaybackStateCompat.ACTION_PLAY_PAUSE
-// or PlaybackStateCompat.ACTION_REWIND
-// or PlaybackStateCompat.ACTION_PAUSE
-// or PlaybackStateCompat.ACTION_FAST_FORWARD
-// or PlaybackStateCompat.ACTION_SEEK_TO
-// or PlaybackStateCompat.ACTION_SET_PLAYBACK_SPEED)
-//
-// sessionState.setActions(capabilities)
-
- // On Android Auto, custom actions are added in the following order around the play button, if no default
- // actions are present: Near left, near right, far left, far right, additional actions panel
-// val rewindBuilder = PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_REWIND, getString(R.string.rewind_label), R.drawable.ic_notification_fast_rewind)
-// WearMediaSession.addWearExtrasToAction(rewindBuilder)
-//// sessionState.addCustomAction(rewindBuilder.build())
-
-// val fastForwardBuilder = PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_FAST_FORWARD, getString(R.string.fast_forward_label), R.drawable.ic_notification_fast_forward)
-// WearMediaSession.addWearExtrasToAction(fastForwardBuilder)
-// sessionState.addCustomAction(fastForwardBuilder.build())
-
-// if (showPlaybackSpeedOnFullNotification())
-// sessionState.addCustomAction(PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED,
-// getString(R.string.playback_speed), R.drawable.ic_notification_playback_speed).build())
-
-// if (showNextChapterOnFullNotification()) {
-// if (!playable?.getChapters().isNullOrEmpty())
-// sessionState.addCustomAction(PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_NEXT_CHAPTER,
-// getString(R.string.next_chapter), R.drawable.ic_notification_next_chapter).build())
-// }
-
-// if (showSkipOnFullNotification())
-// sessionState.addCustomAction(PlaybackStateCompat.CustomAction.Builder(CUSTOM_ACTION_SKIP_TO_NEXT,
-// getString(R.string.skip_episode_label), R.drawable.ic_notification_skip).build())
-
-
-// if (mediaSession != null) {
-// WearMediaSession.mediaSessionSetExtraForWear(mediaSession!!)
-//// mediaSession!!.setPlaybackState(sessionState.build())
-// }
-// }
-
-// private fun updateMediaSessionMetadata(p: Playable?) {
-// if (p == null || mediaSession == null) return
-//
-// // TODO: what's this?
-// mediaSession!!.setSessionActivity(
-// PendingIntent.getActivity(this, R.id.pending_intent_player_activity, getPlayerActivityIntent(this), FLAG_IMMUTABLE))
-// }
-
/**
* Persists the current position and last played time of the media file.
*
@@ -1485,30 +1295,10 @@ class PlaybackService : MediaSessionService() {
mediaPlayer?.setAudioTrack(track)
}
-// private fun setupPositionObserver() {
-// positionEventTimer?.dispose()
-//
-// Log.d(TAG, "Setting up position observer")
-// positionEventTimer = Observable.interval(POSITION_EVENT_INTERVAL, TimeUnit.SECONDS)
-// .observeOn(AndroidSchedulers.mainThread())
-//// .takeWhile { currentPosition != previousPosition }
-// .subscribe {
-// Log.d(TAG, "positionEventTimer currentPosition: $currentPosition, currentPlaybackSpeed: $currentPlaybackSpeed")
-// EventBus.getDefault().post(PlaybackPositionEvent(currentPosition, duration))
-// previousPosition = currentPosition
-// skipEndingIfNecessary()
-// }
-// }
-//
-// private fun cancelPositionObserver() {
-// positionEventTimer?.dispose()
-// }
-
private fun addPlayableToQueue(playable: Playable?) {
if (playable is FeedMedia) {
val itemId = playable.item?.id ?: return
DBWriter.addQueueItem(this, false, true, itemId)
-// notifyChildrenChanged(getString(R.string.queue_label))
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceTaskManager.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceTaskManager.kt
index 7196cd6f..561d849e 100644
--- a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceTaskManager.kt
+++ b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceTaskManager.kt
@@ -1,26 +1,25 @@
package ac.mdiq.podcini.playback.service
+import ac.mdiq.podcini.preferences.SleepTimerPreferences
+import ac.mdiq.podcini.storage.model.playback.Playable
+import ac.mdiq.podcini.ui.widget.WidgetUpdater
+import ac.mdiq.podcini.ui.widget.WidgetUpdater.WidgetState
+import ac.mdiq.podcini.util.ChapterUtils
+import ac.mdiq.podcini.util.Logd
+import ac.mdiq.podcini.util.event.playback.SleepTimerUpdatedEvent
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.os.Vibrator
import android.util.Log
-import ac.mdiq.podcini.preferences.SleepTimerPreferences
-import ac.mdiq.podcini.util.ChapterUtils
-import ac.mdiq.podcini.ui.widget.WidgetUpdater
-import ac.mdiq.podcini.ui.widget.WidgetUpdater.WidgetState
-import ac.mdiq.podcini.util.event.playback.SleepTimerUpdatedEvent
-import ac.mdiq.podcini.storage.model.playback.Playable
-import io.reactivex.Completable
-import io.reactivex.CompletableEmitter
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.TimeUnit
-import kotlin.concurrent.Volatile
/**
* Manages the background tasks of PlaybackSerivce, i.e.
@@ -38,11 +37,40 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
private var widgetUpdaterFuture: ScheduledFuture<*>? = null
private var sleepTimerFuture: ScheduledFuture<*>? = null
- @Volatile
- private var chapterLoaderFuture: Disposable? = null
+// @Volatile
+// private var chapterLoaderFuture: Disposable? = null
private var sleepTimer: SleepTimer? = null
+ /**
+ * Returns true if the sleep timer is currently active.
+ */
+ @get:Synchronized
+ val isSleepTimerActive: Boolean
+ get() = (sleepTimer != null && sleepTimerFuture != null && !sleepTimerFuture!!.isCancelled
+ && !sleepTimerFuture!!.isDone) && sleepTimer!!.getWaitingTime() > 0
+
+ /**
+ * Returns the current sleep timer time or 0 if the sleep timer is not active.
+ */
+ @get:Synchronized
+ val sleepTimerTimeLeft: Long
+ get() = if (isSleepTimerActive) sleepTimer!!.getWaitingTime() else 0
+
+ /**
+ * Returns true if the widget updater is currently running.
+ */
+ @get:Synchronized
+ val isWidgetUpdaterActive: Boolean
+ get() = widgetUpdaterFuture != null && !widgetUpdaterFuture!!.isCancelled && !widgetUpdaterFuture!!.isDone
+
+ /**
+ * Returns true if the position saver is currently running.
+ */
+ @get:Synchronized
+ val isPositionSaverActive: Boolean
+ get() = positionSaverFuture != null && !positionSaverFuture!!.isCancelled && !positionSaverFuture!!.isDone
+
/**
* Sets up a new PSTM. This method will also start the queue loader task.
*
@@ -67,17 +95,10 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
positionSaver = useMainThreadIfNecessary(positionSaver)
positionSaverFuture = schedExecutor.scheduleWithFixedDelay(positionSaver, POSITION_SAVER_WAITING_INTERVAL.toLong(),
POSITION_SAVER_WAITING_INTERVAL.toLong(), TimeUnit.MILLISECONDS)
- Log.d(TAG, "Started PositionSaver")
- } else Log.d(TAG, "Call to startPositionSaver was ignored.")
+ Logd(TAG, "Started PositionSaver")
+ } else Logd(TAG, "Call to startPositionSaver was ignored.")
}
- @get:Synchronized
- val isPositionSaverActive: Boolean
- /**
- * Returns true if the position saver is currently running.
- */
- get() = positionSaverFuture != null && !positionSaverFuture!!.isCancelled && !positionSaverFuture!!.isDone
-
/**
* Cancels the position saver. If the position saver is not running, nothing will happen.
*/
@@ -85,7 +106,7 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
fun cancelPositionSaver() {
if (isPositionSaverActive) {
positionSaverFuture!!.cancel(false)
- Log.d(TAG, "Cancelled PositionSaver")
+ Logd(TAG, "Cancelled PositionSaver")
}
}
@@ -99,8 +120,8 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
widgetUpdater = useMainThreadIfNecessary(widgetUpdater)
widgetUpdaterFuture = schedExecutor.scheduleWithFixedDelay(widgetUpdater, WIDGET_UPDATER_NOTIFICATION_INTERVAL.toLong(),
WIDGET_UPDATER_NOTIFICATION_INTERVAL.toLong(), TimeUnit.MILLISECONDS)
- Log.d(TAG, "Started WidgetUpdater")
- } else Log.d(TAG, "Call to startWidgetUpdater was ignored.")
+ Logd(TAG, "Started WidgetUpdater")
+ }
}
/**
@@ -110,7 +131,7 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
fun requestWidgetUpdate() {
val state = callback.requestWidgetState()
if (!schedExecutor.isShutdown) schedExecutor.execute { WidgetUpdater.updateWidget(context, state) }
- else Log.d(TAG, "Call to requestWidgetUpdate was ignored.")
+ else Logd(TAG, "Call to requestWidgetUpdate was ignored.")
}
/**
@@ -124,28 +145,20 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
fun setSleepTimer(waitingTime: Long) {
require(waitingTime > 0) { "Waiting time <= 0" }
- Log.d(TAG, "Setting sleep timer to $waitingTime milliseconds")
+ Logd(TAG, "Setting sleep timer to $waitingTime milliseconds")
if (isSleepTimerActive) sleepTimerFuture!!.cancel(true)
sleepTimer = SleepTimer(waitingTime)
sleepTimerFuture = schedExecutor.schedule(sleepTimer, 0, TimeUnit.MILLISECONDS)
EventBus.getDefault().post(SleepTimerUpdatedEvent.justEnabled(waitingTime))
}
- @get:Synchronized
- val isSleepTimerActive: Boolean
- /**
- * Returns true if the sleep timer is currently active.
- */
- get() = (sleepTimer != null && sleepTimerFuture != null && !sleepTimerFuture!!.isCancelled
- && !sleepTimerFuture!!.isDone) && sleepTimer!!.getWaitingTime() > 0
-
/**
* Disables the sleep timer. If the sleep timer is not active, nothing will happen.
*/
@Synchronized
fun disableSleepTimer() {
if (isSleepTimerActive) {
- Log.d(TAG, "Disabling sleep timer")
+ Logd(TAG, "Disabling sleep timer")
sleepTimer!!.cancel()
}
}
@@ -156,25 +169,11 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
@Synchronized
fun restartSleepTimer() {
if (isSleepTimerActive) {
- Log.d(TAG, "Restarting sleep timer")
+ Logd(TAG, "Restarting sleep timer")
sleepTimer!!.restart()
}
}
- @get:Synchronized
- val sleepTimerTimeLeft: Long
- /**
- * Returns the current sleep timer time or 0 if the sleep timer is not active.
- */
- get() = if (isSleepTimerActive) sleepTimer!!.getWaitingTime() else 0
-
- @get:Synchronized
- val isWidgetUpdaterActive: Boolean
- /**
- * Returns true if the widget updater is currently running.
- */
- get() = widgetUpdaterFuture != null && !widgetUpdaterFuture!!.isCancelled && !widgetUpdaterFuture!!.isDone
-
/**
* Cancels the widget updater. If the widget updater is not running, nothing will happen.
*/
@@ -182,7 +181,7 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
fun cancelWidgetUpdater() {
if (isWidgetUpdaterActive) {
widgetUpdaterFuture!!.cancel(false)
- Log.d(TAG, "Cancelled WidgetUpdater")
+ Logd(TAG, "Cancelled WidgetUpdater")
}
}
@@ -193,24 +192,35 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
*/
@Synchronized
fun startChapterLoader(media: Playable) {
- chapterLoaderFuture?.dispose()
- chapterLoaderFuture = null
+// chapterLoaderFuture?.dispose()
+// chapterLoaderFuture = null
if (!media.chaptersLoaded()) {
- chapterLoaderFuture = Completable.create { emitter: CompletableEmitter ->
- ChapterUtils.loadChapters(media, context, false)
- emitter.onComplete()
+// chapterLoaderFuture = Completable.create { emitter: CompletableEmitter ->
+// ChapterUtils.loadChapters(media, context, false)
+// emitter.onComplete()
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ callback.onChapterLoaded(media) },
+// { throwable: Throwable? ->
+// Logd(TAG, "Error loading chapters: " + Log.getStackTraceString(throwable))
+// })
+
+ val scope = CoroutineScope(Dispatchers.Main)
+ scope.launch(Dispatchers.IO) {
+ try {
+ ChapterUtils.loadChapters(media, context, false)
+ withContext(Dispatchers.Main) {
+ callback.onChapterLoaded(media)
+ }
+ } catch (e: Throwable) {
+ Log.d(TAG, "Error loading chapters: ${Log.getStackTraceString(e)}")
+ }
}
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ callback.onChapterLoaded(media) },
- { throwable: Throwable? ->
- Log.d(TAG, "Error loading chapters: " + Log.getStackTraceString(throwable))
- })
}
}
-
/**
* Cancels all tasks. The PSTM will be in the initial state after execution of this method.
*/
@@ -220,8 +230,8 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
cancelWidgetUpdater()
disableSleepTimer()
- chapterLoaderFuture?.dispose()
- chapterLoaderFuture = null
+// chapterLoaderFuture?.dispose()
+// chapterLoaderFuture = null
}
/**
@@ -251,14 +261,14 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
private var shakeListener: ShakeListener? = null
override fun run() {
- Log.d(TAG, "Starting")
+ Logd(TAG, "Starting SleepTimer")
var lastTick = System.currentTimeMillis()
EventBus.getDefault().post(SleepTimerUpdatedEvent.updated(timeLeft))
while (timeLeft > 0) {
try {
Thread.sleep(UPDATE_INTERVAL)
} catch (e: InterruptedException) {
- Log.d(TAG, "Thread was interrupted while waiting")
+ Logd(TAG, "Thread was interrupted while waiting")
e.printStackTrace()
break
}
@@ -269,7 +279,7 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
EventBus.getDefault().post(SleepTimerUpdatedEvent.updated(timeLeft))
if (timeLeft < NOTIFICATION_THRESHOLD) {
- Log.d(TAG, "Sleep timer is about to expire")
+ Logd(TAG, "Sleep timer is about to expire")
if (SleepTimerPreferences.vibrate() && !hasVibrated) {
val v = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
if (v != null) {
@@ -280,7 +290,7 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb
if (shakeListener == null && SleepTimerPreferences.shakeToReset()) shakeListener = ShakeListener(context, this)
}
if (timeLeft <= 0) {
- Log.d(TAG, "Sleep timer expired")
+ Logd(TAG, "Sleep timer expired")
shakeListener?.pause()
shakeListener = null
diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/QuickSettingsTileService.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/QuickSettingsTileService.kt
index 6ddf4569..a7cf44d2 100644
--- a/app/src/main/java/ac/mdiq/podcini/playback/service/QuickSettingsTileService.kt
+++ b/app/src/main/java/ac/mdiq/podcini/playback/service/QuickSettingsTileService.kt
@@ -12,6 +12,7 @@ import androidx.annotation.RequiresApi
import androidx.media3.common.util.UnstableApi
import ac.mdiq.podcini.preferences.PlaybackPreferences
import ac.mdiq.podcini.receiver.MediaButtonReceiver
+import ac.mdiq.podcini.util.Logd
@UnstableApi
@RequiresApi(api = Build.VERSION_CODES.N)
@@ -43,7 +44,7 @@ class QuickSettingsTileService : TileService() {
fun updateTile() {
val qsTile = qsTile
- if (qsTile == null) Log.d(TAG, "Ignored call to update QS tile: getQsTile() returned null.")
+ if (qsTile == null) Logd(TAG, "Ignored call to update QS tile: getQsTile() returned null.")
else {
val isPlaying = (PlaybackService.isRunning && PlaybackPreferences.currentPlayerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING)
qsTile.state = if (isPlaying) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/ShakeListener.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/ShakeListener.kt
index 45686e5a..07db4ca8 100644
--- a/app/src/main/java/ac/mdiq/podcini/playback/service/ShakeListener.kt
+++ b/app/src/main/java/ac/mdiq/podcini/playback/service/ShakeListener.kt
@@ -7,6 +7,7 @@ import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.util.Log
import ac.mdiq.podcini.playback.service.PlaybackServiceTaskManager.SleepTimer
+import ac.mdiq.podcini.util.Logd
import kotlin.math.sqrt
internal class ShakeListener(private val mContext: Context, private val mSleepTimer: SleepTimer) : SensorEventListener {
@@ -42,7 +43,7 @@ internal class ShakeListener(private val mContext: Context, private val mSleepTi
val gForce = sqrt((gX * gX + gY * gY + gZ * gZ).toDouble())
if (gForce > 2.25) {
- Log.d(TAG, "Detected shake $gForce")
+ Logd(TAG, "Detected shake $gForce")
mSleepTimer.restart()
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt b/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt
index 9f0735d6..7af03f16 100644
--- a/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt
+++ b/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt
@@ -7,6 +7,7 @@ import ac.mdiq.podcini.storage.model.feed.FeedMedia
import ac.mdiq.podcini.storage.model.feed.FeedPreferences
import ac.mdiq.podcini.storage.model.playback.MediaType
import ac.mdiq.podcini.storage.model.playback.Playable
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.PlayerStatusEvent
import android.content.Context
import android.content.SharedPreferences
@@ -133,7 +134,7 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen
@JvmStatic
fun writeMediaPlaying(playable: Playable?, playerStatus: PlayerStatus, item: FeedItem? = null) {
- Log.d(TAG, "Writing playback preferences")
+ Logd(TAG, "Writing playback preferences ${playable?.getIdentifier()}")
val editor = prefs.edit()
if (playable == null) {
@@ -159,7 +160,7 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen
@JvmStatic
fun writePlayerStatus(playerStatus: PlayerStatus) {
- Log.d(TAG, "Writing player status playback preferences")
+ Logd(TAG, "Writing player status playback preferences")
val editor = prefs.edit()
editor.putInt(PREF_CURRENT_PLAYER_STATUS, getCurrentPlayerStatusAsInt(playerStatus))
@@ -191,7 +192,7 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen
@JvmStatic
fun createInstanceFromPreferences(context: Context): Playable? {
val currentlyPlayingMedia = currentlyPlayingMediaType
- Log.d(TAG, "currentlyPlayingMedia: $currentlyPlayingMedia")
+ Logd(TAG, "currentlyPlayingMedia: $currentlyPlayingMedia")
if (currentlyPlayingMedia != NO_MEDIA_PLAYING) {
val prefs = PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
return createInstanceFromPreferences(currentlyPlayingMedia.toInt(), prefs)
diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/SleepTimerPreferences.kt b/app/src/main/java/ac/mdiq/podcini/preferences/SleepTimerPreferences.kt
index bb1024de..107cadb8 100644
--- a/app/src/main/java/ac/mdiq/podcini/preferences/SleepTimerPreferences.kt
+++ b/app/src/main/java/ac/mdiq/podcini/preferences/SleepTimerPreferences.kt
@@ -1,5 +1,6 @@
package ac.mdiq.podcini.preferences
+import ac.mdiq.podcini.util.Logd
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
@@ -30,7 +31,7 @@ object SleepTimerPreferences {
*/
@JvmStatic
fun init(context: Context) {
- Log.d(TAG, "Creating new instance of SleepTimerPreferences")
+ Logd(TAG, "Creating new instance of SleepTimerPreferences")
prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
}
diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt b/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt
index 1a66a696..925979c5 100644
--- a/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt
+++ b/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt
@@ -6,6 +6,7 @@ import ac.mdiq.podcini.storage.model.feed.FeedPreferences.NewEpisodesAction
import ac.mdiq.podcini.storage.model.feed.SortOrder
import ac.mdiq.podcini.storage.model.feed.SubscriptionsFilter
import ac.mdiq.podcini.storage.model.playback.MediaType
+import ac.mdiq.podcini.util.Logd
import android.content.Context
import android.content.SharedPreferences
import android.os.Build
@@ -145,7 +146,7 @@ object UserPreferences {
*/
@JvmStatic
fun init(context: Context) {
- Log.d(TAG, "Creating new instance of UserPreferences")
+ Logd(TAG, "Creating new instance of UserPreferences")
UserPreferences.context = context.applicationContext
prefs = PreferenceManager.getDefaultSharedPreferences(context)
@@ -697,11 +698,11 @@ object UserPreferences {
fun getDataFolder(type: String?): File? {
var dataFolder = getTypeDir(prefs.getString(PREF_DATA_FOLDER, null), type)
if (dataFolder == null || !dataFolder.canWrite()) {
- Log.d(TAG, "User data folder not writable or not set. Trying default.")
+ Logd(TAG, "User data folder not writable or not set. Trying default.")
dataFolder = context.getExternalFilesDir(type)
}
if (dataFolder == null || !dataFolder.canWrite()) {
- Log.d(TAG, "Default data folder not available or not writable. Falling back to internal memory.")
+ Logd(TAG, "Default data folder not available or not writable. Falling back to internal memory.")
dataFolder = getTypeDir(context.filesDir.absolutePath, type)
}
return dataFolder
@@ -727,7 +728,7 @@ object UserPreferences {
@JvmStatic
fun setDataFolder(dir: String) {
- Log.d(TAG, "setDataFolder(dir: $dir)")
+ Logd(TAG, "setDataFolder(dir: $dir)")
prefs.edit().putString(PREF_DATA_FOLDER, dir).apply()
}
@@ -743,7 +744,7 @@ object UserPreferences {
Log.e(TAG, "Could not create .nomedia file")
e.printStackTrace()
}
- Log.d(TAG, ".nomedia file created")
+ Logd(TAG, ".nomedia file created")
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/AutoDownloadPreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/AutoDownloadPreferencesFragment.kt
index 05b27d76..6e9b6a11 100644
--- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/AutoDownloadPreferencesFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/AutoDownloadPreferencesFragment.kt
@@ -19,6 +19,7 @@ import ac.mdiq.podcini.preferences.UserPreferences.autodownloadSelectedNetworks
import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownload
import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownloadWifiFilter
import ac.mdiq.podcini.preferences.UserPreferences.setAutodownloadSelectedNetworks
+import ac.mdiq.podcini.util.Logd
import java.util.*
class AutoDownloadPreferencesFragment : PreferenceFragmentCompat() {
@@ -95,7 +96,7 @@ class AutoDownloadPreferencesFragment : PreferenceFragmentCompat() {
val key = preference.getKey()
val prefValuesList: MutableList = ArrayList(listOf(*autodownloadSelectedNetworks))
val newValue = preference.isChecked
- Log.d(TAG, "Selected network $key. New state: $newValue")
+ Logd(TAG, "Selected network $key. New state: $newValue")
val index = prefValuesList.indexOf(key)
when {
diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/WifiAuthenticationFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/WifiAuthenticationFragment.kt
index 17478f34..ed306c6f 100644
--- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/WifiAuthenticationFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/WifiAuthenticationFragment.kt
@@ -6,6 +6,7 @@ import ac.mdiq.podcini.net.sync.SynchronizationCredentials
import ac.mdiq.podcini.net.sync.SynchronizationSettings.setWifiSyncEnabled
import ac.mdiq.podcini.net.sync.wifi.WifiSyncService.Companion.hostPort
import ac.mdiq.podcini.net.sync.wifi.WifiSyncService.Companion.startInstantSync
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.SyncServiceEvent
import android.app.Dialog
import android.content.Context.WIFI_SERVICE
@@ -76,7 +77,7 @@ import java.util.*
if (d != null) {
val confirmButton = d.getButton(Dialog.BUTTON_POSITIVE) as Button
confirmButton.setOnClickListener {
- Log.d(TAG, "confirm button pressed")
+ Logd(TAG, "confirm button pressed")
if (isGuest == null) {
Toast.makeText(requireContext(), R.string.host_or_guest, Toast.LENGTH_LONG).show()
return@setOnClickListener
@@ -107,7 +108,7 @@ import java.util.*
binding!!.progressBar.progress = event.message.toInt()
}
else -> {
- Log.d(TAG, "Sync result unknow ${event.messageResId}")
+ Logd(TAG, "Sync result unknow ${event.messageResId}")
// Toast.makeText(context, "Sync result unknow ${event.messageResId}", Toast.LENGTH_LONG).show()
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/ConnectivityActionReceiver.kt b/app/src/main/java/ac/mdiq/podcini/receiver/ConnectivityActionReceiver.kt
index f14eb4fe..428c6cb0 100644
--- a/app/src/main/java/ac/mdiq/podcini/receiver/ConnectivityActionReceiver.kt
+++ b/app/src/main/java/ac/mdiq/podcini/receiver/ConnectivityActionReceiver.kt
@@ -9,11 +9,12 @@ import android.util.Log
import androidx.media3.common.util.UnstableApi
import ac.mdiq.podcini.util.config.ClientConfigurator
import ac.mdiq.podcini.net.download.NetworkConnectionChangeHandler.networkChangedDetected
+import ac.mdiq.podcini.util.Logd
class ConnectivityActionReceiver : BroadcastReceiver() {
@UnstableApi override fun onReceive(context: Context, intent: Intent) {
if (TextUtils.equals(intent.action, ConnectivityManager.CONNECTIVITY_ACTION)) {
- Log.d(TAG, "Received intent")
+ Logd(TAG, "Received intent")
ClientConfigurator.initialize(context)
networkChangedDetected()
diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/FeedUpdateReceiver.kt b/app/src/main/java/ac/mdiq/podcini/receiver/FeedUpdateReceiver.kt
index 953ef206..40d2eb0d 100644
--- a/app/src/main/java/ac/mdiq/podcini/receiver/FeedUpdateReceiver.kt
+++ b/app/src/main/java/ac/mdiq/podcini/receiver/FeedUpdateReceiver.kt
@@ -7,6 +7,7 @@ import android.util.Log
import androidx.media3.common.util.UnstableApi
import ac.mdiq.podcini.util.config.ClientConfigurator
import ac.mdiq.podcini.net.download.FeedUpdateManager
+import ac.mdiq.podcini.util.Logd
/**
* Refreshes all feeds when it receives an intent
@@ -14,7 +15,7 @@ import ac.mdiq.podcini.net.download.FeedUpdateManager
class FeedUpdateReceiver : BroadcastReceiver() {
@UnstableApi
override fun onReceive(context: Context, intent: Intent) {
- Log.d(TAG, "Received intent")
+ Logd(TAG, "Received intent")
ClientConfigurator.initialize(context)
FeedUpdateManager.runOnce(context)
diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/MediaButtonReceiver.kt b/app/src/main/java/ac/mdiq/podcini/receiver/MediaButtonReceiver.kt
index a7c220b1..a894d96d 100644
--- a/app/src/main/java/ac/mdiq/podcini/receiver/MediaButtonReceiver.kt
+++ b/app/src/main/java/ac/mdiq/podcini/receiver/MediaButtonReceiver.kt
@@ -1,5 +1,6 @@
package ac.mdiq.podcini.receiver
+import ac.mdiq.podcini.util.Logd
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
@@ -17,7 +18,7 @@ import ac.mdiq.podcini.util.config.ClientConfigurator
class MediaButtonReceiver : BroadcastReceiver() {
@UnstableApi
override fun onReceive(context: Context, intent: Intent) {
- Log.d(TAG, "Received intent")
+ Logd(TAG, "Received intent")
if (intent.extras == null) return
val event = intent.extras!![Intent.EXTRA_KEY_EVENT] as? KeyEvent
diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/PlayerWidget.kt b/app/src/main/java/ac/mdiq/podcini/receiver/PlayerWidget.kt
index 0e0b0953..2af3dbf7 100644
--- a/app/src/main/java/ac/mdiq/podcini/receiver/PlayerWidget.kt
+++ b/app/src/main/java/ac/mdiq/podcini/receiver/PlayerWidget.kt
@@ -9,19 +9,20 @@ import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import ac.mdiq.podcini.ui.widget.WidgetUpdaterWorker
+import ac.mdiq.podcini.util.Logd
import java.util.concurrent.TimeUnit
class PlayerWidget : AppWidgetProvider() {
override fun onEnabled(context: Context) {
super.onEnabled(context)
- Log.d(TAG, "Widget enabled")
+ Logd(TAG, "Widget enabled")
setEnabled(context, true)
WidgetUpdaterWorker.enqueueWork(context)
scheduleWorkaround(context)
}
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
- Log.d(TAG, "onUpdate() called with: context = [$context], appWidgetManager = [$appWidgetManager], appWidgetIds = [${appWidgetIds.contentToString()}]")
+ Logd(TAG, "onUpdate() called with: context = [$context], appWidgetManager = [$appWidgetManager], appWidgetIds = [${appWidgetIds.contentToString()}]")
WidgetUpdaterWorker.enqueueWork(context)
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
@@ -33,12 +34,12 @@ class PlayerWidget : AppWidgetProvider() {
override fun onDisabled(context: Context) {
super.onDisabled(context)
- Log.d(TAG, "Widget disabled")
+ Logd(TAG, "Widget disabled")
setEnabled(context, false)
}
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
- Log.d(TAG, "OnDeleted")
+ Logd(TAG, "OnDeleted")
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
for (appWidgetId in appWidgetIds) {
prefs.edit().remove(KEY_WIDGET_COLOR + appWidgetId).apply()
diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/PowerConnectionReceiver.kt b/app/src/main/java/ac/mdiq/podcini/receiver/PowerConnectionReceiver.kt
index 2bc6bfd3..0a6b1920 100644
--- a/app/src/main/java/ac/mdiq/podcini/receiver/PowerConnectionReceiver.kt
+++ b/app/src/main/java/ac/mdiq/podcini/receiver/PowerConnectionReceiver.kt
@@ -9,6 +9,7 @@ import ac.mdiq.podcini.util.config.ClientConfigurator
import ac.mdiq.podcini.storage.DBTasks
import ac.mdiq.podcini.net.download.serviceinterface.DownloadServiceInterface
import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownloadOnBattery
+import ac.mdiq.podcini.util.Logd
// modified from http://developer.android.com/training/monitoring-device-state/battery-monitoring.html
// and ConnectivityActionReceiver.java
@@ -19,11 +20,11 @@ class PowerConnectionReceiver : BroadcastReceiver() {
@UnstableApi override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
- Log.d(TAG, "charging intent: $action")
+ Logd(TAG, "charging intent: $action")
ClientConfigurator.initialize(context)
if (Intent.ACTION_POWER_CONNECTED == action) {
- Log.d(TAG, "charging, starting auto-download")
+ Logd(TAG, "charging, starting auto-download")
// we're plugged in, this is a great time to auto-download if everything else is
// right. So, even if the user allows auto-dl on battery, let's still start
// downloading now. They shouldn't mind.
@@ -33,9 +34,9 @@ class PowerConnectionReceiver : BroadcastReceiver() {
} else {
// if we're not supposed to be auto-downloading when we're not charging, stop it
if (!isEnableAutodownloadOnBattery) {
- Log.d(TAG, "not charging anymore, canceling auto-download")
+ Logd(TAG, "not charging anymore, canceling auto-download")
DownloadServiceInterface.get()?.cancelAll(context)
- } else Log.d(TAG, "not charging anymore, but the user allows auto-download when on battery so we'll keep going")
+ } else Logd(TAG, "not charging anymore, but the user allows auto-download when on battery so we'll keep going")
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/SPAReceiver.kt b/app/src/main/java/ac/mdiq/podcini/receiver/SPAReceiver.kt
index b5ee92ec..629270d1 100644
--- a/app/src/main/java/ac/mdiq/podcini/receiver/SPAReceiver.kt
+++ b/app/src/main/java/ac/mdiq/podcini/receiver/SPAReceiver.kt
@@ -12,6 +12,7 @@ import ac.mdiq.podcini.util.config.ClientConfigurator
import ac.mdiq.podcini.storage.DBTasks
import ac.mdiq.podcini.net.download.FeedUpdateManager.runOnce
import ac.mdiq.podcini.storage.model.feed.Feed
+import ac.mdiq.podcini.util.Logd
/**
* Receives intents from Podcini Single Purpose apps
@@ -20,7 +21,7 @@ class SPAReceiver : BroadcastReceiver() {
@UnstableApi override fun onReceive(context: Context, intent: Intent) {
if (!TextUtils.equals(intent.action, ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) return
- Log.d(TAG, "Received SP_APPS_QUERY_RESPONSE")
+ Logd(TAG, "Received SP_APPS_QUERY_RESPONSE")
if (!intent.hasExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA)) {
Log.e(TAG, "Received invalid SP_APPS_QUERY_RESPONSE: Contains no extra")
return
@@ -30,7 +31,7 @@ class SPAReceiver : BroadcastReceiver() {
Log.e(TAG, "Received invalid SP_APPS_QUERY_REPSONSE: extra was null")
return
}
- Log.d(TAG, "Received feeds list: " + feedUrls.contentToString())
+ Logd(TAG, "Received feeds list: " + feedUrls.contentToString())
ClientConfigurator.initialize(context)
for (url in feedUrls) {
val feed = Feed(url, null, "Unknown podcast")
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/AutomaticDownloadAlgorithm.kt b/app/src/main/java/ac/mdiq/podcini/storage/AutomaticDownloadAlgorithm.kt
index 9750c4d4..d05ade94 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/AutomaticDownloadAlgorithm.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/AutomaticDownloadAlgorithm.kt
@@ -18,6 +18,7 @@ import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.preferences.UserPreferences.episodeCacheSize
import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownload
import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownloadOnBattery
+import ac.mdiq.podcini.util.Logd
/**
* Implements the automatic download algorithm used by Podcini. This class assumes that
@@ -42,17 +43,17 @@ open class AutomaticDownloadAlgorithm {
// true if we should auto download based on power status
val powerShouldAutoDl = (deviceCharging(context) || isEnableAutodownloadOnBattery)
- Log.d(TAG, "prepare autoDownloadUndownloadedItems $networkShouldAutoDl $powerShouldAutoDl")
+ Logd(TAG, "prepare autoDownloadUndownloadedItems $networkShouldAutoDl $powerShouldAutoDl")
// we should only auto download if both network AND power are happy
if (networkShouldAutoDl && powerShouldAutoDl) {
- Log.d(TAG, "Performing auto-dl of undownloaded episodes")
+ Logd(TAG, "Performing auto-dl of undownloaded episodes")
val candidates: MutableList
val queue = getQueue()
val newItems = getEpisodes(0, Int.MAX_VALUE, FeedItemFilter(FeedItemFilter.NEW), SortOrder.DATE_NEW_OLD)
- Log.d(TAG, "newItems: ${newItems.size}")
+ Logd(TAG, "newItems: ${newItems.size}")
candidates = ArrayList(queue.size + newItems.size)
candidates.addAll(queue)
for (newItem in newItems) {
@@ -80,14 +81,14 @@ open class AutomaticDownloadAlgorithm {
val itemsToDownload: List = candidates.subList(0, episodeSpaceLeft)
if (itemsToDownload.isNotEmpty()) {
- Log.d(TAG, "Enqueueing " + itemsToDownload.size + " items for download")
+ Logd(TAG, "Enqueueing " + itemsToDownload.size + " items for download")
for (episode in itemsToDownload) {
DownloadServiceInterface.get()?.download(context, episode)
}
}
}
- else Log.d(TAG, "not auto downloaded networkShouldAutoDl: $networkShouldAutoDl powerShouldAutoDl $powerShouldAutoDl")
+ else Logd(TAG, "not auto downloaded networkShouldAutoDl: $networkShouldAutoDl powerShouldAutoDl $powerShouldAutoDl")
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt b/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt
index d902f353..505992f4 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt
@@ -19,7 +19,6 @@ import ac.mdiq.podcini.util.comparator.DownloadResultComparator
import ac.mdiq.podcini.util.comparator.PlaybackCompletionDateComparator
import android.database.Cursor
import android.util.Log
-import androidx.collection.ArrayMap
import kotlin.math.min
@@ -30,8 +29,9 @@ import kotlin.math.min
*/
object DBReader {
private const val TAG = "DBReader"
- private var feeds: MutableList = mutableListOf()
- private var tags: MutableList = mutableListOf()
+ private val feeds: MutableList = mutableListOf()
+ private val feedIndex: MutableMap = mutableMapOf()
+ private val tags: MutableList = mutableListOf()
private val feedListLock = Any()
/**
@@ -61,11 +61,12 @@ object DBReader {
fun updateFeedList(adapter: PodDBAdapter) {
synchronized(feedListLock) {
adapter.allFeedsCursor.use { cursor ->
-// feeds = ArrayList(cursor.count)
feeds.clear()
+ feedIndex.clear()
while (cursor.moveToNext()) {
val feed = extractFeedFromCursorRow(cursor)
feeds.add(feed)
+ feedIndex[feed.id] = feed
}
buildTags()
}
@@ -110,21 +111,18 @@ object DBReader {
* @param items the FeedItems who should have other data loaded
*/
fun loadAdditionalFeedItemListData(items: List) {
- loadTagsOfFeedItemList(items)
-
- synchronized(feedListLock) {
- loadFeedDataOfFeedItemList(items)
- }
- }
-
- private fun loadTagsOfFeedItemList(items: List) {
- val favoriteIds = getFavoriteIDList()
- val queueIds = getQueueIDList()
+ Logd(TAG, "loadAdditionalFeedItemListData called with items.size: ${items.size}")
+ val favoriteIds = getFavoriteIDSet()
+ val queueIds = getQueueIDSet()
for (item in items) {
if (favoriteIds.contains(item.id)) item.addTag(FeedItem.TAG_FAVORITE)
if (queueIds.contains(item.id)) item.addTag(FeedItem.TAG_QUEUE)
}
+
+ synchronized(feedListLock) {
+ loadFeedDataOfFeedItemList(items)
+ }
}
/**
@@ -136,11 +134,12 @@ object DBReader {
*/
private fun loadFeedDataOfFeedItemList(items: List) {
Logd(TAG, "loadFeedDataOfFeedItemList called")
- val feedIndex: MutableMap = ArrayMap(feeds.size)
- val feedsCopy = ArrayList(feeds)
- for (feed in feedsCopy) {
- feedIndex[feed.id] = feed
- }
+// feedIndex is now a static member
+// val feedIndex: MutableMap = ArrayMap(feeds.size)
+// val feedsCopy = ArrayList(feeds)
+// for (feed in feedsCopy) {
+// feedIndex[feed.id] = feed
+// }
for (item in items) {
var feed = feedIndex[item.feedId]
if (feed == null) {
@@ -168,9 +167,9 @@ object DBReader {
return getFeedItemList(feed, filter, SortOrder.DATE_NEW_OLD)
}
- fun getFeedItemList(feed: Feed?, filter: FeedItemFilter?, sortOrder: SortOrder?): List {
-// Log.d(TAG, "getFeedItemList() called with: feed = [$feed]")
-
+ fun getFeedItemList(feed: Feed?, filter_: FeedItemFilter?, sortOrder: SortOrder?): List {
+ val filter = filter_ ?: unfiltered()
+ Logd(TAG, "getFeedItemList() called with: ${feed?.title}")
val adapter = getInstance()
adapter.open()
try {
@@ -240,8 +239,6 @@ object DBReader {
@JvmStatic
fun getQueueIDList(): LongList {
Logd(TAG, "getQueueIDList() called")
-// printStackTrace()
-
val adapter = getInstance()
adapter.open()
try {
@@ -251,21 +248,39 @@ object DBReader {
}
}
- private fun getQueueIDList(adapter: PodDBAdapter?): LongList {
- adapter?.queueIDCursor?.use { cursor ->
+ private fun getQueueIDList(adapter: PodDBAdapter): LongList {
+ adapter.queueIDCursor.use { cursor ->
val queueIds = LongList(cursor.count)
while (cursor.moveToNext()) {
queueIds.add(cursor.getLong(0))
}
return queueIds
}
- return LongList()
+// return LongList()
+ }
+
+ @JvmStatic
+ fun getQueueIDSet(): HashSet {
+ Logd(TAG, "getQueueIDSet() called")
+ val adapter = getInstance()
+ adapter.open()
+ try {
+ adapter.queueIDCursor.use { cursor ->
+ val queueIds = HashSet(cursor.count)
+ while (cursor.moveToNext()) {
+ queueIds.add(cursor.getLong(0))
+ }
+ return queueIds
+ }
+// return HashSet()
+ } finally {
+ adapter.close()
+ }
}
@JvmStatic
fun getQueue(): List {
Logd(TAG, "getQueue() called")
-
val adapter = getInstance()
adapter.open()
try {
@@ -275,14 +290,13 @@ object DBReader {
}
}
- private fun getFavoriteIDList(): LongList {
- Logd(TAG, "getFavoriteIDList() called")
-
+ private fun getFavoriteIDSet(): HashSet {
+ Logd(TAG, "getFavoriteIDSet() called")
val adapter = getInstance()
adapter.open()
try {
adapter.getFavoritesIdsCursor(0, Int.MAX_VALUE).use { cursor ->
- val favoriteIDs = LongList(cursor.count)
+ val favoriteIDs = HashSet(cursor.count)
while (cursor.moveToNext()) {
favoriteIDs.add(cursor.getLong(0))
}
@@ -300,7 +314,8 @@ object DBReader {
* @param filter The filter describing which episodes to filter out.
*/
@JvmStatic
- fun getEpisodes(offset: Int, limit: Int, filter: FeedItemFilter?, sortOrder: SortOrder?): List {
+ fun getEpisodes(offset: Int, limit: Int, filter_: FeedItemFilter?, sortOrder: SortOrder?): List {
+ val filter = filter_ ?: unfiltered()
Logd(TAG, "getEpisodes called with: offset=$offset, limit=$limit")
val adapter = getInstance()
adapter.open()
@@ -316,7 +331,8 @@ object DBReader {
}
@JvmStatic
- fun getTotalEpisodeCount(filter: FeedItemFilter?): Int {
+ fun getTotalEpisodeCount(filter_: FeedItemFilter?): Int {
+ val filter = filter_ ?: unfiltered()
Logd(TAG, "getTotalEpisodeCount called")
val adapter = getInstance()
adapter.open()
@@ -481,11 +497,11 @@ object DBReader {
}
}
- private fun getFeedItem(itemId: Long, adapter: PodDBAdapter?): FeedItem? {
+ private fun getFeedItem(itemId: Long, adapter: PodDBAdapter): FeedItem? {
Logd(TAG, "Loading feeditem with id $itemId")
var item: FeedItem? = null
- adapter?.getFeedItemCursor(itemId.toString())?.use { cursor ->
+ adapter.getFeedItemCursor(itemId.toString()).use { cursor ->
if (cursor.moveToNext()) {
val list = extractItemlistFromCursor(adapter, cursor)
if (list.isNotEmpty()) {
@@ -495,7 +511,7 @@ object DBReader {
}
return item
}
- return null
+// return null
}
/**
@@ -525,12 +541,13 @@ object DBReader {
* @return The FeedItem next in queue or null if the FeedItem could not be found.
*/
fun getNextInQueue(item: FeedItem): FeedItem? {
- Logd(TAG, "getNextInQueue() called with: itemId = [${item.id}]")
+ Logd(TAG, "*** expensive call getNextInQueue() with: itemId = [${item.id}]")
val adapter = getInstance()
adapter.open()
try {
var nextItem: FeedItem? = null
try {
+// TODO: these calls are expensive
adapter.getNextInQueue(item).use { cursor ->
val list = extractItemlistFromCursor(adapter, cursor)
if (list.isNotEmpty()) {
@@ -571,14 +588,14 @@ object DBReader {
* @return The FeedItem or null if the FeedItem could not be found.
* Does NOT load additional attributes like feed or queue state.
*/
- private fun getFeedItemByGuidOrEpisodeUrl(guid: String?, episodeUrl: String, adapter: PodDBAdapter?): FeedItem? {
- adapter?.getFeedItemCursor(guid, episodeUrl)?.use { cursor ->
+ private fun getFeedItemByGuidOrEpisodeUrl(guid: String?, episodeUrl: String, adapter: PodDBAdapter): FeedItem? {
+ adapter.getFeedItemCursor(guid, episodeUrl).use { cursor ->
if (!cursor.moveToNext()) return null
val list = extractItemlistFromCursor(adapter, cursor)
if (list.isNotEmpty()) return list[0]
return null
}
- return null
+// return null
}
/**
@@ -598,9 +615,9 @@ object DBReader {
}
}
- private fun getImageAuthentication(imageUrl: String, adapter: PodDBAdapter?): String {
- var credentials = ""
- adapter?.getImageAuthenticationCursor(imageUrl)?.use { cursor ->
+ private fun getImageAuthentication(imageUrl: String, adapter: PodDBAdapter): String {
+ var credentials: String
+ adapter.getImageAuthenticationCursor(imageUrl).use { cursor ->
if (cursor.moveToFirst()) {
val username = cursor.getString(0)
val password = cursor.getString(1)
@@ -646,10 +663,10 @@ object DBReader {
if (cursor.moveToFirst()) {
val indexDescription = cursor.getColumnIndex(PodDBAdapter.KEY_DESCRIPTION)
val description = cursor.getString(indexDescription)
- item.setDescriptionIfLonger(description)
+ item.setDescription(description)
val indexTranscript = cursor.getColumnIndex(PodDBAdapter.KEY_TRANSCRIPT)
val transcript = cursor.getString(indexTranscript)
- item.setTranscriptIfLonger(transcript)
+ item.setTranscript(transcript)
}
}
} finally {
@@ -681,8 +698,8 @@ object DBReader {
}
}
- private fun loadChaptersOfFeedItem(adapter: PodDBAdapter?, item: FeedItem): List? {
- adapter?.getSimpleChaptersOfFeedItemCursor(item)?.use { cursor ->
+ private fun loadChaptersOfFeedItem(adapter: PodDBAdapter, item: FeedItem): List? {
+ adapter.getSimpleChaptersOfFeedItemCursor(item).use { cursor ->
val chaptersCount = cursor.count
if (chaptersCount == 0) {
item.chapters = null
@@ -694,7 +711,7 @@ object DBReader {
}
return chapters
}
- return null
+// return null
}
/**
@@ -827,7 +844,7 @@ object DBReader {
val adapter = getInstance()
adapter.open()
- val feedCounters: Map = adapter.getFeedCounters(feedCounterSetting)
+ val feedCounters: Map = adapter.getFeedEpisodesCounters(feedCounterSetting)
// getFeedList(adapter)
// TODO:
@@ -901,16 +918,19 @@ object DBReader {
}
val queueSize = adapter.queueSize
+// getting all items, not only new ones
val numNewItems = getTotalEpisodeCount(FeedItemFilter(FeedItemFilter.NEW))
val numDownloadedItems = getTotalEpisodeCount(FeedItemFilter(FeedItemFilter.DOWNLOADED))
-
+ val numItems = getTotalEpisodeCount(unfiltered())
+ val numFeeds = feeds.size
val items: MutableList = ArrayList()
for (feed in feeds) {
val counter = if (feedCounters.containsKey(feed.id)) feedCounters[feed.id]!! else 0
val drawerItem = FeedDrawerItem(feed, feed.id, counter)
items.add(drawerItem)
}
- val result = NavDrawerData(items, queueSize, numNewItems, numDownloadedItems, feedCounters, EpisodeCleanupAlgorithmFactory.build().getReclaimableItems())
+ val result = NavDrawerData(items, queueSize, numNewItems, numDownloadedItems, feedCounters,
+ EpisodeCleanupAlgorithmFactory.build().getReclaimableItems(), numItems, numFeeds)
adapter.close()
return result
}
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt b/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt
index c26ceff1..05604ef3 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt
@@ -16,6 +16,7 @@ import ac.mdiq.podcini.storage.model.download.DownloadResult
import ac.mdiq.podcini.storage.model.feed.Feed
import ac.mdiq.podcini.storage.model.feed.FeedItem
import ac.mdiq.podcini.storage.model.feed.FeedMedia
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.comparator.FeedItemPubdateComparator
import ac.mdiq.podcini.util.event.FeedItemEvent.Companion.updated
import ac.mdiq.podcini.util.event.FeedListUpdateEvent
@@ -105,7 +106,7 @@ import java.util.concurrent.*
*/
@UnstableApi @JvmStatic
fun autodownloadUndownloadedItems(context: Context): Future<*> {
- Log.d(TAG, "autodownloadUndownloadedItems")
+ Logd(TAG, "autodownloadUndownloadedItems")
return autodownloadExec.submit(downloadAlgorithm.autoDownloadUndownloadedItems(context))
}
@@ -190,7 +191,7 @@ import java.util.concurrent.*
@JvmStatic
@Synchronized
fun updateFeed(context: Context, newFeed: Feed, removeUnlistedItems: Boolean): Feed? {
- Log.d(TAG, "updateFeed called")
+ Logd(TAG, "updateFeed called")
var resultFeed: Feed?
val unlistedItems: MutableList = ArrayList()
@@ -200,24 +201,24 @@ import java.util.concurrent.*
// Look up feed in the feedslist
val savedFeed = searchFeedByIdentifyingValueOrID(newFeed)
if (savedFeed == null) {
- Log.d(TAG, "Found no existing Feed with title " + newFeed.title + ". Adding as new one.")
+ Logd(TAG, "Found no existing Feed with title " + newFeed.title + ". Adding as new one.")
resultFeed = newFeed
} else {
- Log.d(TAG, "Feed with title " + newFeed.title + " already exists. Syncing new with existing one.")
+ Logd(TAG, "Feed with title " + newFeed.title + " already exists. Syncing new with existing one.")
newFeed.items.sortWith(FeedItemPubdateComparator())
if (newFeed.pageNr == savedFeed.pageNr) {
if (savedFeed.compareWithOther(newFeed)) {
- Log.d(TAG, "Feed has updated attribute values. Updating old feed's attributes")
+ Logd(TAG, "Feed has updated attribute values. Updating old feed's attributes")
savedFeed.updateFromOther(newFeed)
}
} else {
- Log.d(TAG, "New feed has a higher page number.")
+ Logd(TAG, "New feed has a higher page number.")
savedFeed.nextPageLink = newFeed.nextPageLink
}
if (savedFeed.preferences != null && savedFeed.preferences!!.compareWithOther(newFeed.preferences)) {
- Log.d(TAG, "Feed has updated preferences. Updating old feed's preferences")
+ Logd(TAG, "Feed has updated preferences. Updating old feed's preferences")
savedFeed.preferences!!.updateFromOther(newFeed.preferences)
}
@@ -249,7 +250,7 @@ import java.util.concurrent.*
if (!newFeed.isLocalFeed && oldItem == null) {
oldItem = searchFeedItemGuessDuplicate(savedFeed.items, item)
if (oldItem != null) {
- Log.d(TAG, "Repaired duplicate: $oldItem, $item")
+ Logd(TAG, "Repaired duplicate: $oldItem, $item")
DBWriter.addDownloadStatus(DownloadResult(savedFeed,
item.title?:"", DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE, false,
"""
@@ -279,7 +280,7 @@ import java.util.concurrent.*
if (oldItem != null) {
oldItem.updateFromOther(item)
} else {
- Log.d(TAG, "Found new item: " + item.title)
+ Logd(TAG, "Found new item: " + item.title)
item.feed = savedFeed
if (idx >= savedFeed.items.size) savedFeed.items.add(item)
@@ -287,7 +288,7 @@ import java.util.concurrent.*
val pubDate = item.getPubDate()
if (pubDate == null || priorMostRecentDate == null || priorMostRecentDate.before(pubDate) || priorMostRecentDate == pubDate) {
- Log.d(TAG, "Marking item published on $pubDate new, prior most recent date = $priorMostRecentDate")
+ Logd(TAG, "Marking item published on $pubDate new, prior most recent date = $priorMostRecentDate")
item.setNew()
}
}
@@ -357,7 +358,7 @@ import java.util.concurrent.*
*/
@JvmStatic
fun searchFeedItems(feedID: Long, query: String): FutureTask> {
- Log.d(TAG, "searchFeedItems called")
+ Logd(TAG, "searchFeedItems called")
return FutureTask(object : QueryTask>() {
override fun execute(adapter: PodDBAdapter?) {
val searchResult = adapter?.searchItems(feedID, query)
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/DBWriter.kt b/app/src/main/java/ac/mdiq/podcini/storage/DBWriter.kt
index c1e393c1..a4a66277 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/DBWriter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/DBWriter.kt
@@ -43,6 +43,7 @@ import ac.mdiq.podcini.preferences.UserPreferences.enqueueLocation
import ac.mdiq.podcini.preferences.UserPreferences.isQueueKeepSorted
import ac.mdiq.podcini.preferences.UserPreferences.queueKeepSortedOrder
import ac.mdiq.podcini.preferences.UserPreferences.shouldDeleteRemoveFromQueue
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.showStackTrace
import org.greenrobot.eventbus.EventBus
import java.io.File
@@ -98,7 +99,7 @@ import java.util.concurrent.TimeUnit
*/
@JvmStatic
fun deleteFeedMediaOfItem(context: Context, mediaId: Long): Future<*> {
- Log.d(TAG, "deleteFeedMediaOfItem called")
+ Logd(TAG, "deleteFeedMediaOfItem called")
return runOnDbThread {
val media = getFeedMedia(mediaId)
if (media != null) {
@@ -208,7 +209,7 @@ import java.util.concurrent.TimeUnit
* Deleting media also removes the download log entries.
*/
fun deleteFeedItems(context: Context, items: List): Future<*> {
- Log.d(TAG, "deleteFeedItems called")
+ Logd(TAG, "deleteFeedItems called")
return runOnDbThread { deleteFeedItemsSynchronous(context, items) }
}
@@ -295,7 +296,7 @@ import java.util.concurrent.TimeUnit
fun addItemToPlaybackHistory(media: FeedMedia?, date: Date? = Date()): Future<*> {
return runOnDbThread {
if (media != null) {
- Log.d(TAG, "Adding item to playback history")
+ Logd(TAG, "Adding item to playback history")
media.setPlaybackCompletionDate(date)
val adapter = getInstance()
@@ -313,7 +314,7 @@ import java.util.concurrent.TimeUnit
* @param status The DownloadStatus object.
*/
fun addDownloadStatus(status: DownloadResult?): Future<*> {
- Log.d(TAG, "addDownloadStatus called")
+ Logd(TAG, "addDownloadStatus called")
return runOnDbThread {
if (status != null) {
val adapter = getInstance()
@@ -336,7 +337,7 @@ import java.util.concurrent.TimeUnit
* @throws IndexOutOfBoundsException if index < 0 || index >= queue.size()
*/
@UnstableApi fun addQueueItemAt(context: Context, itemId: Long, index: Int, performAutoDownload: Boolean): Future<*> {
- Log.d(TAG, "addQueueItemAt called")
+ Logd(TAG, "addQueueItemAt called")
return runOnDbThread {
val adapter = getInstance()
adapter.open()
@@ -366,7 +367,7 @@ import java.util.concurrent.TimeUnit
}
fun addQueueItem(context: Context, markAsUnplayed: Boolean, vararg items: FeedItem): Future<*> {
- Log.d(TAG, "addQueueItem called")
+ Logd(TAG, "addQueueItem called")
val itemIds = LongList(items.size)
for (item in items) {
if (!item.hasMedia()) continue
@@ -398,7 +399,7 @@ import java.util.concurrent.TimeUnit
* @param itemIds IDs of the FeedItem objects that should be added to the queue.
*/
@UnstableApi fun addQueueItem(context: Context, performAutoDownload: Boolean, markAsUnplayed: Boolean, vararg itemIds: Long): Future<*> {
- Log.d(TAG, "addQueueItem(context ...) called")
+ Logd(TAG, "addQueueItem(context ...) called")
return runOnDbThread {
if (itemIds.isEmpty()) return@runOnDbThread
@@ -500,7 +501,7 @@ import java.util.concurrent.TimeUnit
}
@UnstableApi private fun removeQueueItemSynchronous(context: Context, performAutoDownload: Boolean, vararg itemIds: Long) {
- Log.d(TAG, "removeQueueItemSynchronous called $itemIds")
+ Logd(TAG, "removeQueueItemSynchronous called $itemIds")
if (itemIds.isEmpty()) return
showStackTrace()
@@ -515,7 +516,7 @@ import java.util.concurrent.TimeUnit
val position = indexInItemList(queue, itemId)
if (position >= 0) {
val item = getFeedItem(itemId)
- Log.d(TAG, "removing item from queue: ${item?.title}")
+ Logd(TAG, "removing item from queue: ${item?.title}")
if (item == null) {
Log.e(TAG, "removeQueueItem - item in queue but somehow cannot be loaded. Item ignored. It should never happen. id:$itemId")
continue
@@ -776,7 +777,7 @@ import java.util.concurrent.TimeUnit
* @param media The FeedMedia object.
*/
fun persistFeedMedia(media: FeedMedia): Future<*> {
- Log.d(TAG, "persistFeedMedia called")
+ Logd(TAG, "persistFeedMedia called")
return runOnDbThread {
val adapter = getInstance()
adapter.open()
@@ -792,7 +793,7 @@ import java.util.concurrent.TimeUnit
*/
@JvmStatic
fun persistFeedMediaPlaybackInfo(media: FeedMedia?): Future<*> {
- Log.d(TAG, "persistFeedMediaPlaybackInfo called")
+ Logd(TAG, "persistFeedMediaPlaybackInfo called")
return runOnDbThread {
if (media != null) {
val adapter = getInstance()
@@ -811,7 +812,7 @@ import java.util.concurrent.TimeUnit
*/
@JvmStatic
fun persistFeedItem(item: FeedItem?): Future<*> {
- Log.d(TAG, "persistFeedItem called")
+ Logd(TAG, "persistFeedItem called")
return runOnDbThread {
if (item != null) {
val adapter = getInstance()
@@ -827,7 +828,7 @@ import java.util.concurrent.TimeUnit
* Updates download URL of a feed
*/
fun updateFeedDownloadURL(original: String, updated: String): Future<*> {
- Log.d(TAG, "updateFeedDownloadURL(original: $original, updated: $updated)")
+ Logd(TAG, "updateFeedDownloadURL(original: $original, updated: $updated)")
return runOnDbThread {
val adapter = getInstance()
adapter.open()
@@ -856,7 +857,7 @@ import java.util.concurrent.TimeUnit
}
private fun indexInItemList(items: List, itemId: Long): Int {
- Log.d(TAG, "indexInItemList called")
+ Logd(TAG, "indexInItemList called")
for (i in items.indices) {
val item = items[i]
if (item?.id == itemId) return i
@@ -921,7 +922,7 @@ import java.util.concurrent.TimeUnit
* @param filterValues Values that represent properties to filter by
*/
fun persistFeedItemsFilter(feedId: Long, filterValues: Set): Future<*> {
- Log.d(TAG, "persistFeedItemsFilter() called with: feedId = [$feedId], filterValues = [$filterValues]")
+ Logd(TAG, "persistFeedItemsFilter() called with: feedId = [$feedId], filterValues = [$filterValues]")
return runOnDbThread {
val adapter = getInstance()
adapter.open()
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/DatabaseTransporter.kt b/app/src/main/java/ac/mdiq/podcini/storage/DatabaseTransporter.kt
index 93c930b8..3dce3789 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/DatabaseTransporter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/DatabaseTransporter.kt
@@ -9,6 +9,7 @@ import android.os.ParcelFileDescriptor
import android.text.format.Formatter
import android.util.Log
import ac.mdiq.podcini.storage.database.PodDBAdapter
+import ac.mdiq.podcini.util.Logd
import org.apache.commons.io.FileUtils
import org.apache.commons.io.IOUtils
import java.io.FileInputStream
@@ -39,7 +40,7 @@ object DatabaseTransporter {
try {
pfd.close()
} catch (e: IOException) {
- Log.d(TAG, "Unable to close ParcelFileDescriptor")
+ Logd(TAG, "Unable to close ParcelFileDescriptor")
}
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/NavDrawerData.kt b/app/src/main/java/ac/mdiq/podcini/storage/NavDrawerData.kt
index 0eb75f49..1ab8192d 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/NavDrawerData.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/NavDrawerData.kt
@@ -7,8 +7,10 @@ class NavDrawerData(@JvmField val items: List,
@JvmField val numNewItems: Int,
val numDownloadedItems: Int,
val feedCounters: Map,
- val reclaimableSpace: Int
-) {
+ val reclaimableSpace: Int,
+ @JvmField val numItems: Int,
+ @JvmField val numFeeds: Int) {
+
class FeedDrawerItem(val feed: Feed, val id: Long, val counter: Int) {
var layer: Int = 0
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/backup/OpmlBackupAgent.kt b/app/src/main/java/ac/mdiq/podcini/storage/backup/OpmlBackupAgent.kt
index e85a9450..051584bf 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/backup/OpmlBackupAgent.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/backup/OpmlBackupAgent.kt
@@ -13,6 +13,7 @@ import ac.mdiq.podcini.storage.DBReader.getFeedList
import ac.mdiq.podcini.storage.DBTasks.updateFeed
import ac.mdiq.podcini.net.download.FeedUpdateManager.runOnce
import ac.mdiq.podcini.storage.model.feed.Feed
+import ac.mdiq.podcini.util.Logd
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
import org.apache.commons.io.IOUtils
@@ -40,7 +41,7 @@ class OpmlBackupAgent : BackupAgentHelper() {
private var mChecksum: ByteArray = byteArrayOf()
override fun performBackup(oldState: ParcelFileDescriptor, data: BackupDataOutput, newState: ParcelFileDescriptor) {
- Log.d(TAG, "Performing backup")
+ Logd(TAG, "Performing backup")
val byteStream = ByteArrayOutputStream()
var digester: MessageDigest? = null
var writer: Writer
@@ -59,7 +60,7 @@ class OpmlBackupAgent : BackupAgentHelper() {
// Compare checksum of new and old file to see if we need to perform a backup at all
if (digester != null) {
val newChecksum = digester.digest()
- Log.d(TAG, "New checksum: " + BigInteger(1, newChecksum).toString(16))
+ Logd(TAG, "New checksum: " + BigInteger(1, newChecksum).toString(16))
// Get the old checksum
if (oldState != null) {
@@ -69,10 +70,10 @@ class OpmlBackupAgent : BackupAgentHelper() {
if (len != -1) {
val oldChecksum = ByteArray(len)
IOUtils.read(inState, oldChecksum, 0, len)
- Log.d(TAG, "Old checksum: " + BigInteger(1, oldChecksum).toString(16))
+ Logd(TAG, "Old checksum: " + BigInteger(1, oldChecksum).toString(16))
if (oldChecksum.contentEquals(newChecksum)) {
- Log.d(TAG, "Checksums are the same; won't backup")
+ Logd(TAG, "Checksums are the same; won't backup")
return
}
}
@@ -81,7 +82,7 @@ class OpmlBackupAgent : BackupAgentHelper() {
writeNewStateDescription(newState, newChecksum)
}
- Log.d(TAG, "Backing up OPML")
+ Logd(TAG, "Backing up OPML")
val bytes = byteStream.toByteArray()
data.writeEntityHeader(OPML_ENTITY_KEY, bytes.size)
data.writeEntityData(bytes, bytes.size)
@@ -93,10 +94,10 @@ class OpmlBackupAgent : BackupAgentHelper() {
}
@OptIn(UnstableApi::class) override fun restoreEntity(data: BackupDataInputStream) {
- Log.d(TAG, "Backup restore")
+ Logd(TAG, "Backup restore")
if (OPML_ENTITY_KEY != data.key) {
- Log.d(TAG, "Unknown entity key: " + data.key)
+ Logd(TAG, "Unknown entity key: " + data.key)
return
}
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/database/DBUpgrader.kt b/app/src/main/java/ac/mdiq/podcini/storage/database/DBUpgrader.kt
index 25d9b295..9fe691e0 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/database/DBUpgrader.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/database/DBUpgrader.kt
@@ -6,6 +6,7 @@ import android.media.MediaMetadataRetriever
import android.util.Log
import ac.mdiq.podcini.storage.model.feed.FeedItem
import ac.mdiq.podcini.storage.model.feed.FeedPreferences
+import ac.mdiq.podcini.util.Logd
internal object DBUpgrader {
/**
@@ -155,7 +156,7 @@ internal object DBUpgrader {
+ PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_POSITION + " = 0 AND " // not partially played
+ PodDBAdapter.TABLE_NAME_QUEUE + "." + PodDBAdapter.KEY_ID + " IS NULL") // not in queue
val sql = ("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + " SET " + PodDBAdapter.KEY_READ + "=" + FeedItem.NEW + " WHERE " + PodDBAdapter.KEY_ID + " IN (" + selectNew + ")")
- Log.d("Migration", "SQL: $sql")
+ Logd("Migration", "SQL: $sql")
db.execSQL(sql)
}
if (oldVersion <= 17) {
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt b/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt
index 6bf33248..80024641 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt
@@ -14,6 +14,7 @@ import ac.mdiq.podcini.storage.model.feed.*
import ac.mdiq.podcini.storage.model.feed.SortOrder.Companion.toCodeString
import ac.mdiq.podcini.storage.database.mapper.FeedItemFilterQuery.generateFrom
import ac.mdiq.podcini.storage.database.mapper.FeedItemSortQuery.generateFrom
+import ac.mdiq.podcini.util.Logd
import org.apache.commons.io.FileUtils
import java.io.File
import java.io.IOException
@@ -77,20 +78,17 @@ class PodDBAdapter private constructor() {
values.put(KEY_IS_PAGED, feed.isPaged)
values.put(KEY_NEXT_PAGE_LINK, feed.nextPageLink)
- if (!feed.itemFilter?.values.isNullOrEmpty()) {
- values.put(KEY_HIDE, TextUtils.join(",", feed.itemFilter!!.values))
- } else {
- values.put(KEY_HIDE, "")
- }
- values.put(KEY_SORT_ORDER, toCodeString(
- feed.sortOrder))
+ if (!feed.itemFilter?.values.isNullOrEmpty()) values.put(KEY_HIDE, TextUtils.join(",", feed.itemFilter!!.values))
+ else values.put(KEY_HIDE, "")
+
+ values.put(KEY_SORT_ORDER, toCodeString(feed.sortOrder))
values.put(KEY_LAST_UPDATE_FAILED, feed.hasLastUpdateFailed())
if (feed.id == 0L) {
// Create new entry
- Log.d(this.toString(), "Inserting new Feed into db")
+ Logd(this.toString(), "Inserting new Feed into db")
feed.id = db.insert(TABLE_NAME_FEEDS, null, values)
} else {
- Log.d(this.toString(), "Updating existing Feed in db")
+ Logd(this.toString(), "Updating existing Feed in db")
db.update(TABLE_NAME_FEEDS, values, "$KEY_ID=?", arrayOf(feed.id.toString()))
}
return feed.id
@@ -120,7 +118,7 @@ class PodDBAdapter private constructor() {
fun setFeedItemFilter(feedId: Long, filterValues: Set?) {
val valuesList = TextUtils.join(",", filterValues!!)
- Log.d(TAG, String.format(Locale.US, "setFeedItemFilter() called with: feedId = [%d], filterValues = [%s]", feedId, valuesList))
+ Logd(TAG, String.format(Locale.US, "setFeedItemFilter() called with: feedId = [%d], filterValues = [%s]", feedId, valuesList))
val values = ContentValues()
values.put(KEY_HIDE, valuesList)
db.update(TABLE_NAME_FEEDS, values, "$KEY_ID=?", arrayOf(feedId.toString()))
@@ -419,7 +417,7 @@ class PodDBAdapter private constructor() {
fun addFavoriteItem(item: FeedItem) {
// don't add an item that's already there...
if (isItemInFavorites(item)) {
- Log.d(TAG, "item already in favorites")
+ Logd(TAG, "item already in favorites")
return
}
val values = ContentValues()
@@ -570,7 +568,7 @@ class PodDBAdapter private constructor() {
* @param feed The feed you want to get the FeedItems from.
* @return The cursor of the query
*/
- fun getItemsOfFeedCursor(feed: Feed, filter: FeedItemFilter?): Cursor {
+ fun getItemsOfFeedCursor(feed: Feed, filter: FeedItemFilter): Cursor {
val filterQuery = generateFrom(filter!!)
val whereClauseAnd = if ("" == filterQuery) "" else " AND $filterQuery"
val query = ("$SELECT_FEED_ITEMS_AND_MEDIA WHERE $TABLE_NAME_FEED_ITEMS.$KEY_FEED=${feed.id}$whereClauseAnd")
@@ -649,7 +647,7 @@ class PodDBAdapter private constructor() {
db.execSQL(sql)
}
- fun getEpisodesCursor(offset: Int, limit: Int, filter: FeedItemFilter?, sortOrder: SortOrder?): Cursor {
+ fun getEpisodesCursor(offset: Int, limit: Int, filter: FeedItemFilter, sortOrder: SortOrder?): Cursor {
val orderByQuery = generateFrom(sortOrder)
val filterQuery = generateFrom(filter!!)
val whereClause = if ("" == filterQuery) "" else " WHERE $filterQuery"
@@ -657,7 +655,7 @@ class PodDBAdapter private constructor() {
return db.rawQuery(query, null)
}
- fun getEpisodeCountCursor(filter: FeedItemFilter?): Cursor {
+ fun getEpisodeCountCursor(filter: FeedItemFilter): Cursor {
val filterQuery = generateFrom(filter!!)
val whereClause = if ("" == filterQuery) "" else " WHERE $filterQuery"
val query = ("SELECT count($TABLE_NAME_FEED_ITEMS.$KEY_ID) FROM $TABLE_NAME_FEED_ITEMS$JOIN_FEED_ITEM_AND_MEDIA$whereClause")
@@ -787,9 +785,9 @@ class PodDBAdapter private constructor() {
return result
}
- fun getFeedCounters(setting: FeedCounter?, vararg feedIds: Long): Map {
+ fun getFeedEpisodesCounters(setting: FeedCounter?, vararg feedIds: Long): Map {
val whereRead = when (setting) {
-// FeedCounter.SHOW_NEW -> KEY_READ + "=" + FeedItem.NEW
+ FeedCounter.SHOW_NEW -> KEY_READ + "=" + FeedItem.NEW
FeedCounter.SHOW_UNPLAYED -> ("(" + KEY_READ + "=" + FeedItem.NEW + " OR " + KEY_READ + "=" + FeedItem.UNPLAYED + ")")
FeedCounter.SHOW_DOWNLOADED -> "$KEY_DOWNLOADED=1"
FeedCounter.SHOW_DOWNLOADED_UNPLAYED -> ("(" + KEY_READ + "=" + FeedItem.NEW
@@ -798,10 +796,10 @@ class PodDBAdapter private constructor() {
FeedCounter.SHOW_NONE -> return HashMap()
else -> return HashMap()
}
- return conditionalFeedCounterRead(whereRead, *feedIds)
+ return conditionalFeedEpisodesCounterRead(whereRead, *feedIds)
}
- private fun conditionalFeedCounterRead(whereRead: String, vararg feedIds: Long): Map {
+ private fun conditionalFeedEpisodesCounterRead(whereRead: String, vararg feedIds: Long): Map {
var limitFeeds = ""
if (feedIds.isNotEmpty()) {
// work around TextUtils.join wanting only boxed items
@@ -833,7 +831,7 @@ class PodDBAdapter private constructor() {
fun getPlayedEpisodesCounters(vararg feedIds: Long): Map {
val whereRead = KEY_READ + "=" + FeedItem.PLAYED
- return conditionalFeedCounterRead(whereRead, *feedIds)
+ return conditionalFeedEpisodesCounterRead(whereRead, *feedIds)
}
val mostRecentItemDates: Map
@@ -968,9 +966,9 @@ class PodDBAdapter private constructor() {
val backupFile = File(backupFolder, "CorruptedDatabaseBackup.db")
try {
FileUtils.copyFile(dbPath, backupFile)
- Log.d(TAG, "Dumped database to " + backupFile.path)
+ Logd(TAG, "Dumped database to " + backupFile.path)
} catch (e: IOException) {
- Log.d(TAG, Log.getStackTraceString(e))
+ Logd(TAG, Log.getStackTraceString(e))
}
DefaultDatabaseErrorHandler().onCorruption(db) // This deletes the database
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/export/favorites/FavoritesWriter.kt b/app/src/main/java/ac/mdiq/podcini/storage/export/favorites/FavoritesWriter.kt
index c3f21311..8ccf2797 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/export/favorites/FavoritesWriter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/export/favorites/FavoritesWriter.kt
@@ -8,6 +8,7 @@ import ac.mdiq.podcini.storage.model.feed.Feed
import ac.mdiq.podcini.storage.model.feed.FeedItem
import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
import ac.mdiq.podcini.storage.model.feed.SortOrder
+import ac.mdiq.podcini.util.Logd
import org.apache.commons.io.IOUtils
import java.io.IOException
import java.io.Writer
@@ -17,7 +18,7 @@ import java.util.*
class FavoritesWriter : ExportWriter {
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
override fun writeDocument(feeds: List?, writer: Writer?, context: Context) {
- Log.d(TAG, "Starting to write document")
+ Logd(TAG, "Starting to write document")
val templateStream = context!!.assets.open("html-export-template.html")
var template = IOUtils.toString(templateStream, UTF_8)
@@ -50,7 +51,7 @@ class FavoritesWriter : ExportWriter {
writer.append(templateParts[1])
- Log.d(TAG, "Finished writing document")
+ Logd(TAG, "Finished writing document")
}
/**
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/export/html/HtmlWriter.kt b/app/src/main/java/ac/mdiq/podcini/storage/export/html/HtmlWriter.kt
index 1850e379..9d6f7ea1 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/export/html/HtmlWriter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/export/html/HtmlWriter.kt
@@ -4,6 +4,7 @@ import android.content.Context
import android.util.Log
import ac.mdiq.podcini.storage.export.ExportWriter
import ac.mdiq.podcini.storage.model.feed.Feed
+import ac.mdiq.podcini.util.Logd
import org.apache.commons.io.IOUtils
import java.io.IOException
import java.io.Writer
@@ -16,7 +17,7 @@ class HtmlWriter : ExportWriter {
*/
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
override fun writeDocument(feeds: List?, writer: Writer?, context: Context) {
- Log.d(TAG, "Starting to write document")
+ Logd(TAG, "Starting to write document")
val templateStream = context!!.assets.open("html-export-template.html")
var template = IOUtils.toString(templateStream, "UTF-8")
@@ -36,7 +37,7 @@ class HtmlWriter : ExportWriter {
writer.append("\">Feed
\n")
}
writer.append(templateParts[1])
- Log.d(TAG, "Finished writing document")
+ Logd(TAG, "Finished writing document")
}
override fun fileExtension(): String {
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlWriter.kt b/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlWriter.kt
index fe5fa60f..7d36d0eb 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlWriter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlWriter.kt
@@ -7,6 +7,7 @@ import ac.mdiq.podcini.storage.export.CommonSymbols
import ac.mdiq.podcini.storage.export.ExportWriter
import ac.mdiq.podcini.util.DateFormatter.formatRfc822Date
import ac.mdiq.podcini.storage.model.feed.Feed
+import ac.mdiq.podcini.util.Logd
import java.io.IOException
import java.io.Writer
import java.util.*
@@ -19,7 +20,7 @@ class OpmlWriter : ExportWriter {
*/
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
override fun writeDocument(feeds: List?, writer: Writer?, context: Context) {
- Log.d(TAG, "Starting to write document")
+ Logd(TAG, "Starting to write document")
val xs = Xml.newSerializer()
xs.setFeature(CommonSymbols.XML_FEATURE_INDENT_OUTPUT, true)
xs.setOutput(writer)
@@ -50,7 +51,7 @@ class OpmlWriter : ExportWriter {
xs.endTag(null, CommonSymbols.BODY)
xs.endTag(null, OpmlSymbols.OPML)
xs.endDocument()
- Log.d(TAG, "Finished writing document")
+ Logd(TAG, "Finished writing document")
}
override fun fileExtension(): String {
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedCounter.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedCounter.kt
index b83ceaa5..bb09bcbf 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedCounter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedCounter.kt
@@ -1,7 +1,7 @@
package ac.mdiq.podcini.storage.model.feed
enum class FeedCounter(val id: Int) {
-// SHOW_NEW(1),
+ SHOW_NEW(1),
SHOW_UNPLAYED(2),
SHOW_NONE(3),
SHOW_DOWNLOADED(4),
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItem.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItem.kt
index 5bead939..5bcddf9f 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItem.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItem.kt
@@ -221,6 +221,14 @@ class FeedItem : FeedComponent, Serializable {
val isInProgress: Boolean
get() = (media != null && media!!.isInProgress)
+ fun setDescription(newDescription: String?) {
+ this.description = newDescription
+ }
+
+ fun setTranscript(newTranscript: String?) {
+ this.transcript = newTranscript
+ }
+
/**
* Updates this item's description property if the given argument is longer than the already stored description
* @param newDescription The new item description, content:encoded, itunes:description, etc.
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/ItemActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/ItemActionButton.kt
index dc0cf5b2..8eb334e8 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/ItemActionButton.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/ItemActionButton.kt
@@ -11,7 +11,7 @@ import android.widget.ImageView
import androidx.media3.common.util.UnstableApi
abstract class ItemActionButton internal constructor(@JvmField var item: FeedItem) {
- val TAG = this::class.simpleName
+ val TAG = this::class.simpleName ?: "ItemActionButton"
abstract fun getLabel(): Int
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayActionButton.kt
index c361a2b6..f3b38af4 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayActionButton.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayActionButton.kt
@@ -32,10 +32,10 @@ class PlayActionButton(item: FeedItem) : ItemActionButton(item) {
return
}
- EventBus.getDefault().post(StartPlayEvent(item))
PlaybackServiceStarter(context, media)
.callEvenIfRunning(true)
.start()
+ EventBus.getDefault().post(StartPlayEvent(item))
if (media.getMediaType() == MediaType.VIDEO) context.startActivity(getPlayerActivityIntent(context, MediaType.VIDEO))
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/StreamActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/StreamActionButton.kt
index 4ff3b8d5..6392c015 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/StreamActionButton.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/StreamActionButton.kt
@@ -36,11 +36,11 @@ class StreamActionButton(item: FeedItem) : ItemActionButton(item) {
return
}
- EventBus.getDefault().post(StartPlayEvent(item))
PlaybackServiceStarter(context, media)
.shouldStreamThisTime(true)
.callEvenIfRunning(true)
.start()
+ EventBus.getDefault().post(StartPlayEvent(item))
if (media.getMediaType() == MediaType.VIDEO) context.startActivity(getPlayerActivityIntent(context, MediaType.VIDEO))
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/TTSActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/TTSActionButton.kt
index 9276ee5a..86f0132d 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/TTSActionButton.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/TTSActionButton.kt
@@ -11,6 +11,7 @@ import ac.mdiq.podcini.storage.model.feed.FeedMedia
import ac.mdiq.podcini.ui.fragment.FeedItemlistFragment.Companion.tts
import ac.mdiq.podcini.ui.fragment.FeedItemlistFragment.Companion.ttsReady
import ac.mdiq.podcini.ui.fragment.FeedItemlistFragment.Companion.ttsWorking
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.NetworkUtils.fetchHtmlSource
import ac.mdiq.podcini.util.event.FeedItemEvent.Companion.updated
import android.content.Context
@@ -44,7 +45,7 @@ class TTSActionButton(item: FeedItem) : ItemActionButton(item) {
}
@OptIn(UnstableApi::class) override fun onClick(context: Context) {
- Log.d("TTSActionButton", "onClick called")
+ Logd("TTSActionButton", "onClick called")
if (item.link.isNullOrEmpty()) {
Toast.makeText(context, R.string.episode_has_no_content, Toast.LENGTH_LONG).show()
return
@@ -61,7 +62,7 @@ class TTSActionButton(item: FeedItem) : ItemActionButton(item) {
readerText = article.textContent
item.setTranscriptIfLonger(article.contentWithDocumentsCharsetOrUtf8)
persistFeedItem(item)
- Log.d(TAG, "readability4J: ${readerText?.substring(max(0, readerText!!.length-100), readerText!!.length)}")
+ Logd(TAG, "readability4J: ${readerText?.substring(max(0, readerText!!.length-100), readerText!!.length)}")
}
} else readerText = HtmlCompat.fromHtml(item.transcript!!, HtmlCompat.FROM_HTML_MODE_COMPACT).toString()
processing = 0.1f
@@ -87,7 +88,7 @@ class TTSActionButton(item: FeedItem) : ItemActionButton(item) {
override fun onStart(utteranceId: String?) {}
override fun onDone(utteranceId: String?) {
j++
- Log.d(TAG, "onDone ${mediaFile.length()} $utteranceId")
+ Logd(TAG, "onDone ${mediaFile.length()} $utteranceId")
}
@Deprecated("Deprecated in Java")
override fun onError(utteranceId: String) {
@@ -100,20 +101,20 @@ class TTSActionButton(item: FeedItem) : ItemActionButton(item) {
}
})
- Log.d(TAG, "readerText: ${readerText?.length}")
+ Logd(TAG, "readerText: ${readerText?.length}")
var startIndex = 0
var i = 0
val parts = mutableListOf()
val chunkLength = getMaxSpeechInputLength()
var status = TextToSpeech.ERROR
while (startIndex < readerText!!.length) {
- Log.d(TAG, "working on chunk $i $startIndex")
+ Logd(TAG, "working on chunk $i $startIndex")
val endIndex = minOf(startIndex + chunkLength, readerText!!.length)
val chunk = readerText!!.substring(startIndex, endIndex)
val tempFile = File.createTempFile("tts_temp_${i}_", ".wav")
parts.add(tempFile.absolutePath)
status = tts?.synthesizeToFile(chunk, null, tempFile, tempFile.absolutePath) ?: 0
- Log.d(TAG, "status: $status chunk: ${chunk.substring(0, min(80, chunk.length))}")
+ Logd(TAG, "status: $status chunk: ${chunk.substring(0, min(80, chunk.length))}")
if (status == TextToSpeech.ERROR) {
withContext(Dispatchers.Main) { Toast.makeText(context, "Error generating audio file $tempFile.absolutePath", Toast.LENGTH_LONG).show() }
break
@@ -138,7 +139,7 @@ class TTSActionButton(item: FeedItem) : ItemActionButton(item) {
// }
// }
val mFilename = mediaFile.absolutePath
- Log.d(TAG, "saving TTS to file $mFilename")
+ Logd(TAG, "saving TTS to file $mFilename")
val media = FeedMedia(item, null, 0, "audio/*")
media.setFile_url(mFilename)
media.setDownloaded(true)
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedItemMenuHandler.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedItemMenuHandler.kt
index 33d07b3a..95f6a909 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedItemMenuHandler.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedItemMenuHandler.kt
@@ -186,7 +186,7 @@ object FeedItemMenuHandler {
shareDialog.show((fragment.requireActivity().supportFragmentManager), "ShareEpisodeDialog")
}
else -> {
- Log.d(TAG, "Unknown menuItemId: $menuItemId")
+ Logd(TAG, "Unknown menuItemId: $menuItemId")
return false
}
}
@@ -204,7 +204,7 @@ object FeedItemMenuHandler {
fun markReadWithUndo(fragment: Fragment, item: FeedItem?, playState: Int, showSnackbar: Boolean) {
if (item == null) return
- Log.d(TAG, "markReadWithUndo(" + item.id + ")")
+ Logd(TAG, "markReadWithUndo(" + item.id + ")")
// we're marking it as unplayed since the user didn't actually play it
// but they don't want it considered 'NEW' anymore
DBWriter.markItemPlayed(playState, item.id)
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/BugReportActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/BugReportActivity.kt
index 993acff4..f2d7fb9a 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/activity/BugReportActivity.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/BugReportActivity.kt
@@ -5,6 +5,7 @@ import ac.mdiq.podcini.databinding.BugReportBinding
import ac.mdiq.podcini.preferences.ThemeSwitcher.getTheme
import ac.mdiq.podcini.preferences.UserPreferences.getDataFolder
import ac.mdiq.podcini.util.IntentUtils.openInBrowser
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.error.CrashReportWriter
import android.content.ClipData
import android.content.ClipboardManager
@@ -43,7 +44,7 @@ class BugReportActivity : AppCompatActivity() {
try {
val crashFile = CrashReportWriter.file
if (crashFile.exists()) stacktrace = IOUtils.toString(FileInputStream(crashFile), Charset.forName("UTF-8"))
- else Log.d(TAG, stacktrace)
+ else Logd(TAG, stacktrace)
} catch (e: IOException) {
e.printStackTrace()
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt
index 4daed4ef..e94aba42 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt
@@ -277,8 +277,14 @@ class MainActivity : CastEnabledActivity() {
override fun onStateChanged(view: View, state: Int) {
Logd(TAG, "bottomSheet onStateChanged $state")
when (state) {
- BottomSheetBehavior.STATE_COLLAPSED -> onSlide(view,0.0f)
+ BottomSheetBehavior.STATE_COLLAPSED -> {
+ audioPlayerFragment.isCollapsed = true
+// audioPlayerFragment.updateUi()
+ onSlide(view,0.0f)
+ }
BottomSheetBehavior.STATE_EXPANDED -> {
+ audioPlayerFragment.isCollapsed = false
+// audioPlayerFragment.updateUi()
audioPlayerFragment.initDetailedView()
onSlide(view, 1.0f)
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt
index d19325af..e4dad2d1 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt
@@ -28,10 +28,10 @@ import coil.imageLoader
import coil.request.ErrorResult
import coil.request.ImageRequest
import coil.request.SuccessResult
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
// TODO: need to enable
class SelectSubscriptionActivity : AppCompatActivity() {
@@ -41,7 +41,8 @@ class SelectSubscriptionActivity : AppCompatActivity() {
@Volatile
private var listItems: List = listOf()
- private var disposable: Disposable? = null
+ val scope = CoroutineScope(Dispatchers.Main)
+// private var disposable: Disposable? = null
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(ThemeSwitcher.getTranslucentTheme(this))
@@ -100,22 +101,6 @@ class SelectSubscriptionActivity : AppCompatActivity() {
private fun getBitmapFromUrl(feed: Feed) {
val iconSize = (128 * resources.displayMetrics.density).toInt()
-
-// if (!feed.imageUrl.isNullOrBlank()) Glide.with(this)
-// .asBitmap()
-// .load(feed.imageUrl)
-// .apply(RequestOptions.overrideOf(iconSize, iconSize))
-// .listener(object : RequestListener {
-// @UnstableApi override fun onLoadFailed(e: GlideException?, model: Any?, target: Target, isFirstResource: Boolean): Boolean {
-// addShortcut(feed, null)
-// return true
-// }
-// @UnstableApi override fun onResourceReady(resource: Bitmap, model: Any, target: Target, dataSource: DataSource, isFirstResource: Boolean): Boolean {
-// addShortcut(feed, resource)
-// return true
-// }
-// }).submit()
-
val request = ImageRequest.Builder(this)
.data(feed.imageUrl)
.setHeader("User-Agent", "Mozilla/5.0")
@@ -134,24 +119,45 @@ class SelectSubscriptionActivity : AppCompatActivity() {
}
private fun loadSubscriptions() {
- disposable?.dispose()
+// disposable?.dispose()
- disposable = Observable.fromCallable {
- val data: NavDrawerData = DBReader.getNavDrawerData(UserPreferences.subscriptionsFilter)
- getFeedItems(data.items, ArrayList())
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { result: List ->
+// disposable = Observable.fromCallable {
+// val data: NavDrawerData = DBReader.getNavDrawerData(UserPreferences.subscriptionsFilter)
+// getFeedItems(data.items, ArrayList())
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { result: List ->
+// listItems = result
+// val titles = ArrayList()
+// for (feed in result) {
+// if (feed.title != null) titles.add(feed.title!!)
+// }
+// val adapter: ArrayAdapter = ArrayAdapter(this, R.layout.simple_list_item_multiple_choice_on_start, titles)
+// binding.list.adapter = adapter
+// }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+
+ scope.launch {
+ try {
+ val result = withContext(Dispatchers.IO) {
+ val data: NavDrawerData = DBReader.getNavDrawerData(UserPreferences.subscriptionsFilter)
+ getFeedItems(data.items, ArrayList())
+ }
+ withContext(Dispatchers.Main) {
listItems = result
val titles = ArrayList()
for (feed in result) {
if (feed.title != null) titles.add(feed.title!!)
}
- val adapter: ArrayAdapter = ArrayAdapter(this, R.layout.simple_list_item_multiple_choice_on_start, titles)
+ val adapter: ArrayAdapter = ArrayAdapter(this@SelectSubscriptionActivity, R.layout.simple_list_item_multiple_choice_on_start, titles)
binding.list.adapter = adapter
- }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
+
}
override fun onDestroy() {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/CoverLoader.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/CoverLoader.kt
index 5752f014..627251e4 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/CoverLoader.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/CoverLoader.kt
@@ -2,12 +2,10 @@ package ac.mdiq.podcini.ui.adapter
import ac.mdiq.podcini.R
import ac.mdiq.podcini.ui.activity.MainActivity
-import ac.mdiq.podcini.util.Logd
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.ImageView
import android.widget.TextView
-import coil.Coil
import coil.ImageLoader
import coil.imageLoader
import coil.request.ErrorResult
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/NavListAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/NavListAdapter.kt
index a2c4f000..d191d240 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/NavListAdapter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/NavListAdapter.kt
@@ -6,12 +6,11 @@ import ac.mdiq.podcini.databinding.NavSectionItemBinding
import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.preferences.UserPreferences.episodeCacheSize
import ac.mdiq.podcini.preferences.UserPreferences.hiddenDrawerItems
-import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownload
-import ac.mdiq.podcini.preferences.UserPreferences.subscriptionsFilter
import ac.mdiq.podcini.storage.NavDrawerData.FeedDrawerItem
import ac.mdiq.podcini.ui.activity.PreferenceActivity
import ac.mdiq.podcini.ui.fragment.*
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
+import ac.mdiq.podcini.util.Logd
import android.app.Activity
import android.content.DialogInterface
import android.content.Intent
@@ -22,14 +21,12 @@ import android.view.ContextMenu.ContextMenuInfo
import android.view.View.OnCreateContextMenuListener
import android.widget.ImageView
import android.widget.LinearLayout
-import android.widget.RelativeLayout
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
-import coil.load
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.apache.commons.lang3.ArrayUtils
import java.lang.ref.WeakReference
@@ -48,7 +45,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
private val titles: Array = context.resources.getStringArray(R.array.nav_drawer_titles)
private val activity = WeakReference(context)
@JvmField
- var showSubscriptionList: Boolean = true
+ var showSubscriptionList: Boolean = false
init {
loadItems()
@@ -65,16 +62,6 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
val newTags: MutableList = ArrayList(listOf(*NavDrawerFragment.NAV_DRAWER_TAGS))
val hiddenFragments = hiddenDrawerItems
newTags.removeAll(hiddenFragments)
-
- if (newTags.contains(SUBSCRIPTION_LIST_TAG)) {
- // we never want SUBSCRIPTION_LIST_TAG to be in 'tags'
- // since it doesn't actually correspond to a position in the list, but is
- // a placeholder that indicates if we should show the subscription list in the
- // nav drawer at all.
- showSubscriptionList = true
- newTags.remove(SUBSCRIPTION_LIST_TAG)
- } else showSubscriptionList = false
-
fragmentTags.clear()
fragmentTags.addAll(newTags)
notifyDataSetChanged()
@@ -104,15 +91,12 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
}
override fun getItemCount(): Int {
- var baseCount = subscriptionOffset
- if (showSubscriptionList) baseCount += itemAccess.count
- return baseCount
+ return subscriptionOffset
}
override fun getItemId(position: Int): Long {
val viewType = getItemViewType(position)
return when (viewType) {
- VIEW_TYPE_SUBSCRIPTION -> itemAccess.getItem(position - subscriptionOffset)?.id?:0
VIEW_TYPE_NAV -> (-abs(fragmentTags[position].hashCode().toLong().toDouble()) - 1).toLong() // Folder IDs are >0
else -> 0
}
@@ -122,7 +106,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
return when {
0 <= position && position < fragmentTags.size -> VIEW_TYPE_NAV
position < subscriptionOffset -> VIEW_TYPE_SECTION_DIVIDER
- else -> VIEW_TYPE_SUBSCRIPTION
+ else -> 0
}
}
@@ -133,8 +117,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
val inflater = LayoutInflater.from(activity.get())
return when (viewType) {
VIEW_TYPE_NAV -> NavHolder(inflater.inflate(R.layout.nav_listitem, parent, false))
- VIEW_TYPE_SECTION_DIVIDER -> DividerHolder(inflater.inflate(R.layout.nav_section_item, parent, false))
- else -> FeedHolder(inflater.inflate(R.layout.nav_listitem, parent, false))
+ else -> DividerHolder(inflater.inflate(R.layout.nav_section_item, parent, false))
}
}
@@ -144,16 +127,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
holder.itemView.setOnCreateContextMenuListener(null)
when (viewType) {
VIEW_TYPE_NAV -> bindNavView(getLabel(fragmentTags[position]), position, holder as NavHolder)
- VIEW_TYPE_SECTION_DIVIDER -> bindSectionDivider(holder as DividerHolder)
- else -> {
- val itemPos = position - subscriptionOffset
- val item = itemAccess.getItem(itemPos)
- if (item != null) {
- bindListItem(item, holder as FeedHolder)
- bindFeedView(item, holder)
- }
- holder.itemView.setOnCreateContextMenuListener(itemAccess)
- }
+ else -> bindSectionDivider(holder as DividerHolder)
}
if (viewType != VIEW_TYPE_SECTION_DIVIDER) {
holder.itemView.isSelected = itemAccess.isSelected(position)
@@ -179,32 +153,34 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
holder.count.isClickable = false
val tag = fragmentTags[position]
- when {
- tag == QueueFragment.TAG -> {
+ when (tag) {
+ SubscriptionFragment.TAG -> {
+ val sum = itemAccess.numberOfFeeds
+ if (sum > 0) {
+ holder.count.text = NumberFormat.getInstance().format(sum.toLong())
+ holder.count.visibility = View.VISIBLE
+ }
+ }
+ QueueFragment.TAG -> {
val queueSize = itemAccess.queueSize
if (queueSize > 0) {
holder.count.text = NumberFormat.getInstance().format(queueSize.toLong())
holder.count.visibility = View.VISIBLE
}
}
-// tag == InboxFragment.TAG -> {
-// val unreadItems = itemAccess.numberOfNewItems
-// if (unreadItems > 0) {
-// holder.count.text = NumberFormat.getInstance().format(unreadItems.toLong())
-// holder.count.visibility = View.VISIBLE
-// }
-// }
- tag == SubscriptionFragment.TAG -> {
- val sum = itemAccess.feedCounterSum
- if (sum > 0) {
- holder.count.text = NumberFormat.getInstance().format(sum.toLong())
+ AllEpisodesFragment.TAG -> {
+ val numEpisodes = itemAccess.numberOfItems
+ if (numEpisodes > 0) {
+ holder.count.text = NumberFormat.getInstance().format(numEpisodes.toLong())
holder.count.visibility = View.VISIBLE
}
}
- tag == DownloadsFragment.TAG && isEnableAutodownload -> {
+ DownloadsFragment.TAG -> {
val epCacheSize = episodeCacheSize
// don't count episodes that can be reclaimed
val spaceUsed = (itemAccess.numberOfDownloadedItems - itemAccess.reclaimableItems)
+ holder.count.text = NumberFormat.getInstance().format(spaceUsed.toLong())
+ holder.count.visibility = View.VISIBLE
if (epCacheSize in 1..spaceUsed) {
holder.count.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_disc_alert, 0)
holder.count.visibility = View.VISIBLE
@@ -224,72 +200,15 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
}
}
+ Logd("NavListAdapter", "bindNavView getting drawable for: ${fragmentTags[position]}")
holder.image.setImageResource(getDrawable(fragmentTags[position]))
}
private fun bindSectionDivider(holder: DividerHolder) {
-// val context = activity.get() ?: return
-
- if (subscriptionsFilter.isEnabled && showSubscriptionList) {
- holder.itemView.isEnabled = true
- holder.feedsFilteredMsg.visibility = View.VISIBLE
- } else {
- holder.itemView.isEnabled = false
- holder.feedsFilteredMsg.visibility = View.GONE
- }
+ holder.itemView.isEnabled = false
+ holder.feedsFilteredMsg.visibility = View.GONE
}
- private fun bindListItem(item: FeedDrawerItem, holder: FeedHolder) {
- if (item.counter > 0) {
- holder.count.visibility = View.VISIBLE
- holder.count.text = NumberFormat.getInstance().format(item.counter.toLong())
- } else holder.count.visibility = View.GONE
-
- holder.title.text = item.title
- val padding = (activity.get()!!.resources.getDimension(R.dimen.thumbnail_length_navlist) / 2).toInt()
- holder.itemView.setPadding(item.layer * padding, 0, 0, 0)
- }
-
- private fun bindFeedView(drawerItem: FeedDrawerItem, holder: FeedHolder) {
- val feed = drawerItem.feed
- val context = activity.get() ?: return
-
-// if (!feed.imageUrl.isNullOrBlank()) Glide.with(context)
-// .load(feed.imageUrl)
-// .apply(RequestOptions()
-// .placeholder(R.color.light_gray)
-// .error(R.color.light_gray)
-// .transform(FitCenter(),
-// RoundedCorners((4 * context.resources.displayMetrics.density).toInt()))
-// .dontAnimate())
-// .into(holder.image)
-
- holder.image.load(feed.imageUrl) {
- placeholder(R.color.light_gray)
- error(R.mipmap.ic_launcher)
- }
-
- if (feed.hasLastUpdateFailed()) {
- val p = holder.title.layoutParams as RelativeLayout.LayoutParams
- p.addRule(RelativeLayout.LEFT_OF, R.id.itxtvFailure)
- holder.failure.visibility = View.VISIBLE
- } else {
- val p = holder.title.layoutParams as RelativeLayout.LayoutParams
- p.addRule(RelativeLayout.LEFT_OF, R.id.txtvCount)
- holder.failure.visibility = View.GONE
- }
- }
-
-// private fun bindTagView(tag: TagDrawerItem, holder: FeedHolder) {
-// val context = activity.get() ?: return
-// if (tag.isOpen) {
-// holder.count.visibility = View.GONE
-// }
-// Glide.with(context).clear(holder.image)
-// holder.image.setImageResource(R.drawable.ic_tag)
-// holder.failure.visibility = View.GONE
-// }
-
open class Holder(itemView: View) : RecyclerView.ViewHolder(itemView)
internal class DividerHolder(itemView: View) : Holder(itemView) {
@@ -304,14 +223,6 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
val count: TextView = binding.txtvCount
}
- internal class FeedHolder(itemView: View) : Holder(itemView) {
- val binding = NavListitemBinding.bind(itemView)
- val image: ImageView = binding.imgvCover
- val title: TextView = binding.txtvTitle
- val failure: ImageView = binding.itxtvFailure
- val count: TextView = binding.txtvCount
- }
-
interface ItemAccess : OnCreateContextMenuListener {
val count: Int
@@ -323,12 +234,16 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
val numberOfNewItems: Int
+ val numberOfItems: Int
+
val numberOfDownloadedItems: Int
val reclaimableItems: Int
val feedCounterSum: Int
+ val numberOfFeeds: Int
+
fun onItemClick(position: Int)
fun onItemLongClick(position: Int): Boolean
@@ -339,12 +254,5 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
companion object {
const val VIEW_TYPE_NAV: Int = 0
const val VIEW_TYPE_SECTION_DIVIDER: Int = 1
- private const val VIEW_TYPE_SUBSCRIPTION = 2
-
- /**
- * a tag used as a placeholder to indicate if the subscription list should be displayed or not
- * This tag doesn't correspond to any specific activity.
- */
- const val SUBSCRIPTION_LIST_TAG: String = "SubscriptionList"
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/QueueRecyclerAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/QueueRecyclerAdapter.kt
index c42bd814..25b709a4 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/QueueRecyclerAdapter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/QueueRecyclerAdapter.kt
@@ -12,6 +12,7 @@ import ac.mdiq.podcini.R
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions
import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
+import ac.mdiq.podcini.util.Logd
/**
* List adapter for the queue.
@@ -45,7 +46,7 @@ open class QueueRecyclerAdapter(mainActivity: MainActivity, private val swipeAct
val isLtr = holder.itemView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
val factor = (if (isLtr) 1 else -1).toFloat()
if (factor * event.x < factor * 0.5 * v1.width) swipeActions.startDrag(holder)
- else Log.d(TAG, "Ignoring drag in right half of the image")
+ else Logd(TAG, "Ignoring drag in right half of the image")
}
false
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/RemoveFeedDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/RemoveFeedDialog.kt
index fa1ea5f6..4c0e49fe 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/RemoveFeedDialog.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/RemoveFeedDialog.kt
@@ -10,9 +10,10 @@ import android.content.DialogInterface
import android.util.Log
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
-import io.reactivex.Completable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
object RemoveFeedDialog {
private const val TAG = "RemoveFeedDialog"
@@ -41,21 +42,39 @@ object RemoveFeedDialog {
progressDialog.setCancelable(false)
progressDialog.show()
- Completable.fromAction {
- for (feed in feeds) {
- DBWriter.deleteFeed(context, feed.id).get()
- }
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- {
+// Completable.fromAction {
+// for (feed in feeds) {
+// DBWriter.deleteFeed(context, feed.id).get()
+// }
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// {
+// Logd(TAG, "Feed(s) deleted")
+// progressDialog.dismiss()
+// }, { error: Throwable? ->
+// Log.e(TAG, Log.getStackTraceString(error))
+// progressDialog.dismiss()
+// })
+
+ val scope = CoroutineScope(Dispatchers.Main)
+ scope.launch {
+ try {
+ withContext(Dispatchers.IO) {
+ for (feed in feeds) {
+ DBWriter.deleteFeed(context, feed.id).get()
+ }
+ }
+ withContext(Dispatchers.Main) {
Logd(TAG, "Feed(s) deleted")
progressDialog.dismiss()
- }, { error: Throwable? ->
- Log.e(TAG, Log.getStackTraceString(error))
- progressDialog.dismiss()
- })
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ withContext(Dispatchers.Main) { progressDialog.dismiss() }
+ }
+ }
}
}
dialog.createNewDialog().show()
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt
index 6c5ef6dd..d64ea332 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt
@@ -19,9 +19,10 @@ import androidx.fragment.app.DialogFragment
import androidx.media3.common.util.UnstableApi
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import java.io.Serializable
@@ -87,18 +88,33 @@ class TagSettingsDialog : DialogFragment() {
}
private fun loadTags() {
- Observable.fromCallable {
- DBReader.getTags()
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { result: List ->
+// Observable.fromCallable {
+// DBReader.getTags()
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { result: List ->
+// val acAdapter = ArrayAdapter(requireContext(), R.layout.single_tag_text_view, result)
+// binding.newTagEditText.setAdapter(acAdapter)
+// }, { error: Throwable? ->
+// Log.e(TAG, Log.getStackTraceString(error))
+// })
+
+ val scope = CoroutineScope(Dispatchers.Main)
+ scope.launch {
+ try {
+ val result = withContext(Dispatchers.IO) {
+ DBReader.getTags()
+ }
+ withContext(Dispatchers.Main) {
val acAdapter = ArrayAdapter(requireContext(), R.layout.single_tag_text_view, result)
binding.newTagEditText.setAdapter(acAdapter)
- }, { error: Throwable? ->
- Log.e(TAG, Log.getStackTraceString(error))
- })
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
}
private fun addTag(name: String) {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/AddFeedFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/AddFeedFragment.kt
index e2eabe44..0433b877 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/AddFeedFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/AddFeedFragment.kt
@@ -10,6 +10,7 @@ import ac.mdiq.podcini.storage.model.feed.Feed
import ac.mdiq.podcini.storage.model.feed.SortOrder
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.activity.OpmlImportActivity
+import ac.mdiq.podcini.util.Logd
import android.content.*
import android.net.Uri
import android.os.Bundle
@@ -26,9 +27,10 @@ import androidx.fragment.app.Fragment
import androidx.media3.common.util.UnstableApi
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/**
* Provides actions for adding new podcast subscriptions.
@@ -52,7 +54,7 @@ class AddFeedFragment : Fragment() {
_binding = AddfeedBinding.inflate(inflater)
activity = getActivity() as? MainActivity
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
displayUpArrow = parentFragmentManager.backStackEntryCount != 0
if (savedInstanceState != null) displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW)
@@ -162,18 +164,36 @@ class AddFeedFragment : Fragment() {
@UnstableApi private fun addLocalFolderResult(uri: Uri?) {
if (uri == null) return
- Observable.fromCallable { addLocalFolder(uri) }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { feed: Feed ->
- val fragment: Fragment = FeedItemlistFragment.newInstance(feed.id)
- (getActivity() as MainActivity).loadChildFragment(fragment)
- }, { error: Throwable ->
- Log.e(TAG, Log.getStackTraceString(error))
- (getActivity() as MainActivity)
- .showSnackbarAbovePlayer(error.localizedMessage, Snackbar.LENGTH_LONG)
- })
+// Observable.fromCallable { addLocalFolder(uri) }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { feed: Feed ->
+// val fragment: Fragment = FeedItemlistFragment.newInstance(feed.id)
+// (getActivity() as MainActivity).loadChildFragment(fragment)
+// }, { error: Throwable ->
+// Log.e(TAG, Log.getStackTraceString(error))
+// (getActivity() as MainActivity)
+// .showSnackbarAbovePlayer(error.localizedMessage, Snackbar.LENGTH_LONG)
+// })
+
+ val scope = CoroutineScope(Dispatchers.Main)
+ scope.launch {
+ try {
+ val feed = withContext(Dispatchers.IO) {
+ addLocalFolder(uri)
+ }
+ withContext(Dispatchers.Main) {
+ if (feed != null) {
+ val fragment: Fragment = FeedItemlistFragment.newInstance(feed.id)
+ (getActivity() as MainActivity).loadChildFragment(fragment)
+ }
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ (getActivity() as MainActivity).showSnackbarAbovePlayer(e.localizedMessage, Snackbar.LENGTH_LONG)
+ }
+ }
}
@UnstableApi private fun addLocalFolder(uri: Uri): Feed? {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/AllEpisodesFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/AllEpisodesFragment.kt
index 427b35ca..1f70bc39 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/AllEpisodesFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/AllEpisodesFragment.kt
@@ -10,9 +10,9 @@ import ac.mdiq.podcini.storage.model.feed.SortOrder
import ac.mdiq.podcini.ui.dialog.AllEpisodesFilterDialog
import ac.mdiq.podcini.ui.dialog.AllEpisodesFilterDialog.AllEpisodesFilterChangedEvent
import ac.mdiq.podcini.ui.dialog.ItemSortDialog
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.FeedListUpdateEvent
import android.os.Bundle
-import android.util.Log
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
@@ -27,9 +27,10 @@ import org.greenrobot.eventbus.Subscribe
* Shows all episodes (possibly filtered by user).
*/
class AllEpisodesFragment : BaseEpisodesListFragment() {
+
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val root = super.onCreateView(inflater, container, savedInstanceState)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
toolbar.inflateMenu(R.menu.episodes)
toolbar.setTitle(R.string.episodes_label)
@@ -128,7 +129,7 @@ class AllEpisodesFragment : BaseEpisodesListFragment() {
}
companion object {
- const val TAG: String = "EpisodesFragment"
+ const val TAG: String = "AllEpisodesFragment"
const val PREF_NAME: String = "PrefAllEpisodesFragment"
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt
index 881c0c6b..c79d4d3c 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt
@@ -64,11 +64,8 @@ import coil.request.ImageRequest
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.elevation.SurfaceColors
-import io.reactivex.Maybe
-import io.reactivex.MaybeEmitter
-import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -97,8 +94,9 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
private lateinit var cardViewSeek: CardView
private lateinit var txtvSeek: TextView
+ val scope = CoroutineScope(Dispatchers.Main)
private var controller: PlaybackController? = null
- private var disposable: Disposable? = null
+// private var disposable: Disposable? = null
private var seekedToChapterStart = false
private var currentChapterIndex = -1
private var duration = 0
@@ -106,6 +104,8 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
private var currentMedia: Playable? = null
private var currentitem: FeedItem? = null
+ var isCollapsed = true
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
_binding = AudioplayerFragmentBinding.inflate(inflater)
@@ -163,6 +163,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
_binding = null
controller?.release()
controller = null
+ scope.cancel()
EventBus.getDefault().unregister(this)
Logd(TAG, "Fragment destroyed")
}
@@ -192,32 +193,55 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
(activity as MainActivity).bottomSheet.state = BottomSheetBehavior.STATE_EXPANDED
}
- private fun loadMediaInfo(includingChapters: Boolean) {
- Logd(TAG, "loadMediaInfo called")
+// private fun loadMediaInfo0(includingChapters: Boolean) {
+// Logd(TAG, "loadMediaInfo called")
+//
+// val theMedia = controller?.getMedia() ?: return
+// Logd(TAG, "loadMediaInfo $theMedia")
+//
+// if (currentMedia == null || theMedia.getIdentifier() != currentMedia?.getIdentifier()) {
+// Logd(TAG, "loadMediaInfo loading details")
+// disposable?.dispose()
+// disposable = Maybe.create { emitter: MaybeEmitter ->
+// val media: Playable? = theMedia
+// if (media != null) {
+// if (includingChapters) ChapterUtils.loadChapters(media, requireContext(), false)
+// emitter.onSuccess(media)
+// } else emitter.onComplete()
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ media: Playable ->
+// currentMedia = media
+// updateUi(media)
+// playerFragment1?.updateUi(media)
+// playerFragment2?.updateUi(media)
+// if (!includingChapters) loadMediaInfo(true)
+// }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) },
+// { updateUi(null) })
+// }
+// }
+ fun loadMediaInfo(includingChapters: Boolean) {
val theMedia = controller?.getMedia() ?: return
- Logd(TAG, "loadMediaInfo $theMedia")
-
- if (currentMedia == null || theMedia.getIdentifier() != currentMedia?.getIdentifier()) {
- Logd(TAG, "loadMediaInfo loading details")
- disposable?.dispose()
- disposable = Maybe.create { emitter: MaybeEmitter ->
- val media: Playable? = theMedia
- if (media != null) {
- if (includingChapters) ChapterUtils.loadChapters(media, requireContext(), false)
- emitter.onSuccess(media)
- } else emitter.onComplete()
+ if (currentMedia == null || theMedia.getIdentifier() != currentMedia?.getIdentifier() || (includingChapters && !theMedia.chaptersLoaded())) {
+ Logd(TAG, "loadMediaInfo loading details ${theMedia.getIdentifier()} chapter: $includingChapters")
+ scope.launch {
+ val media: Playable = withContext(Dispatchers.IO) {
+ theMedia.apply {
+ if (includingChapters) ChapterUtils.loadChapters(this, requireContext(), false)
+ }
+ }
+ currentMedia = media
+ updateUi()
+ playerFragment1?.updateUi(currentMedia)
+ playerFragment2?.updateUi(currentMedia)
+ if (!includingChapters) loadMediaInfo(true)
+ }.invokeOnCompletion { throwable ->
+ if (throwable!= null) {
+ Log.e(TAG, Log.getStackTraceString(throwable))
+ }
}
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ media: Playable ->
- currentMedia = media
- updateUi(media)
- playerFragment1?.updateUi(media)
- playerFragment2?.updateUi(media)
- if (!includingChapters) loadMediaInfo(true)
- }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) },
- { updateUi(null) })
}
}
@@ -240,10 +264,10 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
}
}
- private fun updateUi(media: Playable?) {
+ fun updateUi() {
Logd(TAG, "updateUi called")
- setChapterDividers(media)
- setupOptionsMenu(media)
+ setChapterDividers(currentMedia)
+ setupOptionsMenu(currentMedia)
}
@Subscribe(threadMode = ThreadMode.MAIN)
@@ -265,7 +289,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
override fun onStop() {
super.onStop()
// progressIndicator.visibility = View.GONE // Controller released; we will not receive buffering updates
- disposable?.dispose()
+// disposable?.dispose()
}
// @Subscribe(threadMode = ThreadMode.MAIN)
@@ -328,7 +352,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
txtvSeek.text = controller!!.getMedia()?.getChapters()?.get(newChapterIndex)?.title ?: ("\n${Converter.getDurationStringLong(position)}")
} else txtvSeek.text = Converter.getDurationStringLong(position)
}
- duration != controller!!.duration -> updateUi(controller!!.getMedia())
+ duration != controller!!.duration -> updateUi()
}
}
@@ -695,7 +719,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
(activity as MainActivity).setPlayerVisible(true)
onPositionObserverUpdate(PlaybackPositionEvent(media.getPosition(), media.getDuration()))
- val imgLoc = ImageResourceUtils.getEpisodeListImageLocation(media) + "sdfsdf"
+ val imgLoc = ImageResourceUtils.getEpisodeListImageLocation(media)
val imgLocFB = ImageResourceUtils.getFallbackImageLocation(media)
val imageLoader = imgvCover.context.imageLoader
val imageRequest = ImageRequest.Builder(requireContext())
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/BaseEpisodesListFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/BaseEpisodesListFragment.kt
index db0a31a7..e5101c46 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/BaseEpisodesListFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/BaseEpisodesListFragment.kt
@@ -39,11 +39,7 @@ import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.snackbar.Snackbar
import com.leinardi.android.speeddial.SpeedDialActionItem
import com.leinardi.android.speeddial.SpeedDialView
-import io.reactivex.Completable
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -62,6 +58,8 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
var _binding: BaseEpisodesListFragmentBinding? = null
protected val binding get() = _binding!!
+ val scope = CoroutineScope(Dispatchers.Main)
+
lateinit var recyclerView: EpisodeItemListRecyclerView
lateinit var emptyView: EmptyViewHandler
lateinit var speedDialView: SpeedDialView
@@ -77,7 +75,7 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
@JvmField
var episodes: MutableList = ArrayList()
- protected var disposable: Disposable? = null
+// protected var disposable: Disposable? = null
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
@@ -202,7 +200,7 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
override fun onStop() {
super.onStop()
- disposable?.dispose()
+// disposable?.dispose()
}
@UnstableApi override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -242,68 +240,115 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
@UnstableApi private fun performMultiSelectAction(actionItemId: Int) {
val handler = EpisodeMultiSelectActionHandler((activity as MainActivity), actionItemId)
- Completable.fromAction {
- handler.handleAction(listAdapter.selectedItems.filterIsInstance())
- if (listAdapter.shouldSelectLazyLoadedItems()) {
- var applyPage = page + 1
- var nextPage: List
- do {
- nextPage = loadMoreData(applyPage)
- handler.handleAction(nextPage)
- applyPage++
- } while (nextPage.size == EPISODES_PER_PAGE)
+// Completable.fromAction {
+// handler.handleAction(listAdapter.selectedItems.filterIsInstance())
+// if (listAdapter.shouldSelectLazyLoadedItems()) {
+// var applyPage = page + 1
+// var nextPage: List
+// do {
+// nextPage = loadMoreData(applyPage)
+// handler.handleAction(nextPage)
+// applyPage++
+// } while (nextPage.size == EPISODES_PER_PAGE)
+// }
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ listAdapter.endSelectMode() },
+// { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+
+ scope.launch {
+ try {
+ withContext(Dispatchers.IO) {
+ handler.handleAction(listAdapter.selectedItems.filterIsInstance())
+ if (listAdapter.shouldSelectLazyLoadedItems()) {
+ var applyPage = page + 1
+ var nextPage: List
+ do {
+ nextPage = loadMoreData(applyPage)
+ handler.handleAction(nextPage)
+ applyPage++
+ } while (nextPage.size == EPISODES_PER_PAGE)
+ }
+ withContext(Dispatchers.Main) {
+ listAdapter.endSelectMode()
+ }
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
}
}
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ listAdapter.endSelectMode() },
- { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
}
private fun setupLoadMoreScrollListener() {
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(view: RecyclerView, deltaX: Int, deltaY: Int) {
super.onScrolled(view, deltaX, deltaY)
+ Logd(TAG, "addOnScrollListener called isLoadingMore:$isLoadingMore hasMoreItems:$hasMoreItems ${recyclerView.isScrolledToBottom}")
if (!isLoadingMore && hasMoreItems && recyclerView.isScrolledToBottom) {
/* The end of the list has been reached. Load more data. */
page++
loadMoreItems()
- isLoadingMore = true
+// isLoadingMore = true
}
}
})
}
private fun loadMoreItems() {
- disposable?.dispose()
+// disposable?.dispose()
+ Logd(TAG, "loadMoreItems() called $page")
isLoadingMore = true
listAdapter.setDummyViews(1)
listAdapter.notifyItemInserted(listAdapter.itemCount - 1)
- disposable = Observable.fromCallable { loadMoreData(page) }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ data: List ->
- if (data.size < EPISODES_PER_PAGE) hasMoreItems = false
- Logd(TAG, "loadMoreItems $page ${data.size}")
- episodes.addAll(data)
- listAdapter.setDummyViews(0)
- listAdapter.updateItems(episodes)
- if (listAdapter.shouldSelectLazyLoadedItems()) listAdapter.setSelected(episodes.size - data.size, episodes.size, true)
+// disposable = Observable.fromCallable { loadMoreData(page) }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ data: List ->
+// if (data.size < EPISODES_PER_PAGE) hasMoreItems = false
+// Logd(TAG, "loadMoreItems $page ${data.size}")
+// episodes.addAll(data)
+// listAdapter.setDummyViews(0)
+// listAdapter.updateItems(episodes)
+// if (listAdapter.shouldSelectLazyLoadedItems()) listAdapter.setSelected(episodes.size - data.size, episodes.size, true)
+//
+// }, { error: Throwable? ->
+// listAdapter.setDummyViews(0)
+// listAdapter.updateItems(emptyList())
+// Log.e(TAG, Log.getStackTraceString(error))
+// }, {
+// // Make sure to not always load 2 pages at once
+// recyclerView.post { isLoadingMore = false }
+// })
- }, { error: Throwable? ->
+ scope.launch {
+ try {
+ val data = withContext(Dispatchers.IO) {
+ loadMoreData(page)
+ }
+ withContext(Dispatchers.Main) {
+ if (data.size < EPISODES_PER_PAGE) hasMoreItems = false
+ Logd(TAG, "loadMoreItems $page ${data.size}")
+ episodes.addAll(data)
+ listAdapter.setDummyViews(0)
+ listAdapter.updateItems(episodes)
+ if (listAdapter.shouldSelectLazyLoadedItems()) listAdapter.setSelected(episodes.size - data.size, episodes.size, true)
+ }
+ } catch (e: Throwable) {
listAdapter.setDummyViews(0)
listAdapter.updateItems(emptyList())
- Log.e(TAG, Log.getStackTraceString(error))
- }, {
- // Make sure to not always load 2 pages at once
- recyclerView.post { isLoadingMore = false }
- })
+ Log.e(TAG, Log.getStackTraceString(e))
+ } finally {
+ withContext(Dispatchers.Main) { recyclerView.post { isLoadingMore = false } }
+ }
+ }
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
+ scope.cancel()
EventBus.getDefault().unregister(this)
listAdapter.endSelectMode()
}
@@ -319,7 +364,7 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: FeedItemEvent) {
- Log.d(TAG, "onEventMainThread() called with FeedItemEvent event = [$event]")
+ Logd(TAG, "onEventMainThread() called with FeedItemEvent event = [$event]")
for (item in event.items) {
val pos: Int = FeedItemUtil.indexOfItemWithId(episodes, item.id)
if (pos >= 0) {
@@ -338,7 +383,7 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
if (currentPlaying != null && currentPlaying!!.isCurrentlyPlayingItem)
currentPlaying!!.notifyPlaybackPositionUpdated(event)
else {
- Log.d(TAG, "onEventMainThread() search list")
+ Logd(TAG, "onEventMainThread() search list")
for (i in 0 until listAdapter.itemCount) {
val holder: EpisodeItemViewHolder? = recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
if (holder != null && holder.isCurrentlyPlayingItem) {
@@ -395,15 +440,37 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
}
fun loadItems() {
- disposable?.dispose()
+ Logd(TAG, "loadItems() called")
+// disposable?.dispose()
- disposable = Observable.fromCallable {
- Pair(loadData().toMutableList(), loadTotalItemCount())
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { data: Pair, Int> ->
+// disposable = Observable.fromCallable {
+// Pair(loadData().toMutableList(), loadTotalItemCount())
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { data: Pair, Int> ->
+// val restoreScrollPosition = episodes.isEmpty()
+// episodes = data.first
+// hasMoreItems = !(page == 1 && episodes.size < EPISODES_PER_PAGE)
+// progressBar.visibility = View.GONE
+// listAdapter.setDummyViews(0)
+// listAdapter.updateItems(episodes)
+// listAdapter.setTotalNumberOfItems(data.second)
+// if (restoreScrollPosition) recyclerView.restoreScrollPosition(getPrefName())
+// updateToolbar()
+// }, { error: Throwable? ->
+// listAdapter.setDummyViews(0)
+// listAdapter.updateItems(emptyList())
+// Log.e(TAG, Log.getStackTraceString(error))
+// })
+
+ scope.launch {
+ try {
+ val data = withContext(Dispatchers.IO) {
+ Pair(loadData().toMutableList(), loadTotalItemCount())
+ }
+ withContext(Dispatchers.Main) {
val restoreScrollPosition = episodes.isEmpty()
episodes = data.first
hasMoreItems = !(page == 1 && episodes.size < EPISODES_PER_PAGE)
@@ -413,11 +480,14 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
listAdapter.setTotalNumberOfItems(data.second)
if (restoreScrollPosition) recyclerView.restoreScrollPosition(getPrefName())
updateToolbar()
- }, { error: Throwable? ->
- listAdapter.setDummyViews(0)
- listAdapter.updateItems(emptyList())
- Log.e(TAG, Log.getStackTraceString(error))
- })
+ }
+ } catch (e: Throwable) {
+ listAdapter.setDummyViews(0)
+ listAdapter.updateItems(emptyList())
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
+
}
protected abstract fun loadData(): List
@@ -446,7 +516,7 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
}
companion object {
- const val TAG: String = "EpisodesListFragment"
+ const val TAG: String = "BaseEpisodesListFragment"
private const val KEY_UP_ARROW = "up_arrow"
const val EPISODES_PER_PAGE: Int = 150
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt
index 0187ebd3..8a398c06 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt
@@ -9,6 +9,7 @@ import ac.mdiq.podcini.net.discovery.PodcastSearchResult
import ac.mdiq.podcini.storage.DBReader
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.adapter.OnlineFeedsAdapter
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.DiscoveryDefaultUpdateEvent
import android.content.Context
import android.content.DialogInterface
@@ -29,10 +30,7 @@ import androidx.media3.common.util.UnstableApi
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textfield.MaterialAutoCompleteTextView
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import java.util.*
@@ -61,7 +59,9 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
*/
private var searchResults: List? = null
private var topList: List? = null
- private var disposable: Disposable? = null
+
+ val scope = CoroutineScope(Dispatchers.Main)
+// private var disposable: Disposable? = null
private var countryCode: String? = "US"
private var hidden = false
private var needsConfirm = false
@@ -101,7 +101,7 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
_binding = FragmentItunesSearchBinding.inflate(inflater)
// val root = inflater.inflate(R.layout.fragment_itunes_search, container, false)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
gridView = binding.gridView
adapter = OnlineFeedsAdapter(requireActivity(), ArrayList())
gridView.setAdapter(adapter)
@@ -135,13 +135,14 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
override fun onDestroy() {
super.onDestroy()
_binding = null
- disposable?.dispose()
+ scope.cancel()
+// disposable?.dispose()
adapter = null
}
private fun loadToplist(country: String?) {
- disposable?.dispose()
+// disposable?.dispose()
gridView.visibility = View.GONE
txtvError.visibility = View.GONE
@@ -175,23 +176,44 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
val loader = ItunesTopListLoader(requireContext())
- disposable = Observable.fromCallable { loader.loadToplist(country?:"",
- NUM_OF_TOP_PODCASTS, DBReader.getFeedList()) }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { podcasts: List? ->
+// disposable = Observable.fromCallable { loader.loadToplist(country?:"",
+// NUM_OF_TOP_PODCASTS, DBReader.getFeedList()) }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { podcasts: List? ->
+// progressBar.visibility = View.GONE
+// topList = podcasts
+// updateData(topList)
+// }, { error: Throwable ->
+// Log.e(TAG, Log.getStackTraceString(error))
+// progressBar.visibility = View.GONE
+// txtvError.text = error.message
+// txtvError.visibility = View.VISIBLE
+// butRetry.setOnClickListener { loadToplist(country) }
+// butRetry.visibility = View.VISIBLE
+// })
+
+ scope.launch {
+ try {
+ val podcasts = withContext(Dispatchers.IO) {
+ loader.loadToplist(country?:"", NUM_OF_TOP_PODCASTS, DBReader.getFeedList())
+ }
+ withContext(Dispatchers.Main) {
progressBar.visibility = View.GONE
topList = podcasts
updateData(topList)
- }, { error: Throwable ->
- Log.e(TAG, Log.getStackTraceString(error))
- progressBar.visibility = View.GONE
- txtvError.text = error.message
- txtvError.visibility = View.VISIBLE
- butRetry.setOnClickListener { loadToplist(country) }
- butRetry.visibility = View.VISIBLE
- })
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ progressBar.visibility = View.GONE
+ txtvError.text = e.message
+ txtvError.visibility = View.VISIBLE
+ butRetry.setOnClickListener { loadToplist(country) }
+ butRetry.visibility = View.VISIBLE
+ }
+ }
+
}
override fun onMenuItemClick(item: MenuItem): Boolean {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/DownloadLogFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/DownloadLogFragment.kt
index 147a8f80..8f50e93c 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/DownloadLogFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/DownloadLogFragment.kt
@@ -8,6 +8,7 @@ import ac.mdiq.podcini.storage.model.download.DownloadResult
import ac.mdiq.podcini.ui.adapter.DownloadLogAdapter
import ac.mdiq.podcini.ui.dialog.DownloadLogDetailsDialog
import ac.mdiq.podcini.ui.view.EmptyViewHandler
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.DownloadLogEvent
import android.os.Bundle
import android.util.Log
@@ -17,10 +18,7 @@ import android.widget.AdapterView.OnItemClickListener
import androidx.appcompat.widget.Toolbar
import androidx.media3.common.util.UnstableApi
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@@ -34,15 +32,17 @@ class DownloadLogFragment : BottomSheetDialogFragment(), OnItemClickListener, To
private lateinit var adapter: DownloadLogAdapter
private var downloadLog: List = ArrayList()
- private var disposable: Disposable? = null
+// private var disposable: Disposable? = null
+ val scope = CoroutineScope(Dispatchers.Main)
override fun onStop() {
super.onStop()
- disposable?.dispose()
+ scope.cancel()
+// disposable?.dispose()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
_binding = DownloadLogFragmentBinding.inflate(inflater)
binding.toolbar.inflateMenu(R.menu.download_log)
binding.toolbar.setOnMenuItemClickListener(this)
@@ -95,17 +95,31 @@ class DownloadLogFragment : BottomSheetDialogFragment(), OnItemClickListener, To
}
private fun loadDownloadLog() {
- disposable?.dispose()
+// disposable?.dispose()
- disposable = Observable.fromCallable { DBReader.getDownloadLog() }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ result: List? ->
- if (result != null) {
+// disposable = Observable.fromCallable { DBReader.getDownloadLog() }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ result: List? ->
+// if (result != null) {
+// downloadLog = result
+// adapter.setDownloadLog(downloadLog)
+// }
+// }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+
+ scope.launch {
+ try {
+ val result = withContext(Dispatchers.IO) {
+ DBReader.getDownloadLog()
+ }
+ withContext(Dispatchers.Main) {
downloadLog = result
adapter.setDownloadLog(downloadLog)
}
- }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
}
companion object {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt
index 1d75cdd4..952497dc 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt
@@ -41,10 +41,10 @@ import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.snackbar.Snackbar
import com.leinardi.android.speeddial.SpeedDialActionItem
import com.leinardi.android.speeddial.SpeedDialView
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -69,7 +69,7 @@ class DownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeListener, To
private lateinit var progressBar: ProgressBar
private lateinit var emptyView: EmptyViewHandler
- private var disposable: Disposable? = null
+// private var disposable: Disposable? = null
private var displayUpArrow = false
private var currentPlaying: EpisodeItemViewHolder? = null
@@ -166,7 +166,7 @@ class DownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeListener, To
adapter.endSelectMode()
toolbar.setOnMenuItemClickListener(null)
toolbar.setOnLongClickListener(null)
- disposable?.dispose()
+// disposable?.dispose()
super.onDestroyView()
}
@@ -303,39 +303,72 @@ class DownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeListener, To
}
private fun loadItems() {
- disposable?.dispose()
+// disposable?.dispose()
emptyView.hide()
- disposable = Observable.fromCallable {
- val sortOrder: SortOrder? = UserPreferences.downloadsSortedOrder
- val downloadedItems: List = DBReader.getEpisodes(0, Int.MAX_VALUE,
- FeedItemFilter(FeedItemFilter.DOWNLOADED), sortOrder)
+// disposable = Observable.fromCallable {
+// val sortOrder: SortOrder? = UserPreferences.downloadsSortedOrder
+// val downloadedItems: List = DBReader.getEpisodes(0, Int.MAX_VALUE,
+// FeedItemFilter(FeedItemFilter.DOWNLOADED), sortOrder)
+//
+// val mediaUrls: MutableList = ArrayList()
+// if (runningDownloads.isEmpty()) return@fromCallable downloadedItems
+//
+// for (url in runningDownloads) {
+// if (FeedItemUtil.indexOfItemWithDownloadUrl(downloadedItems, url) != -1) continue // Already in list
+// mediaUrls.add(url)
+// }
+// val currentDownloads: MutableList = DBReader.getFeedItemsWithUrl(mediaUrls).toMutableList()
+// currentDownloads.addAll(downloadedItems)
+// currentDownloads
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { result: List ->
+// items = result.toMutableList()
+// adapter.setDummyViews(0)
+// progressBar.visibility = View.GONE
+// adapter.updateItems(result)
+// refreshInfoBar()
+// }, { error: Throwable? ->
+// adapter.setDummyViews(0)
+// adapter.updateItems(emptyList())
+// Log.e(TAG, Log.getStackTraceString(error))
+// })
- val mediaUrls: MutableList = ArrayList()
- if (runningDownloads.isEmpty()) return@fromCallable downloadedItems
-
- for (url in runningDownloads) {
- if (FeedItemUtil.indexOfItemWithDownloadUrl(downloadedItems, url) != -1) continue // Already in list
- mediaUrls.add(url)
- }
- val currentDownloads: MutableList = DBReader.getFeedItemsWithUrl(mediaUrls).toMutableList()
- currentDownloads.addAll(downloadedItems)
- currentDownloads
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { result: List ->
+ val scope = CoroutineScope(Dispatchers.Main)
+ scope.launch {
+ try {
+ val result = withContext(Dispatchers.IO) {
+ val sortOrder: SortOrder? = UserPreferences.downloadsSortedOrder
+ val downloadedItems: List = DBReader.getEpisodes(0, Int.MAX_VALUE, FeedItemFilter(FeedItemFilter.DOWNLOADED), sortOrder)
+ val mediaUrls: MutableList = ArrayList()
+ if (runningDownloads.isEmpty()) {
+ downloadedItems
+ } else {
+ for (url in runningDownloads) {
+ if (FeedItemUtil.indexOfItemWithDownloadUrl(downloadedItems, url) != -1) continue
+ mediaUrls.add(url)
+ }
+ val currentDownloads: MutableList = DBReader.getFeedItemsWithUrl(mediaUrls).toMutableList()
+ currentDownloads.addAll(downloadedItems)
+ currentDownloads
+ }
+ }
+ withContext(Dispatchers.Main) {
items = result.toMutableList()
adapter.setDummyViews(0)
progressBar.visibility = View.GONE
adapter.updateItems(result)
refreshInfoBar()
- }, { error: Throwable? ->
- adapter.setDummyViews(0)
- adapter.updateItems(emptyList())
- Log.e(TAG, Log.getStackTraceString(error))
- })
+ }
+ } catch (e: Throwable) {
+ adapter.setDummyViews(0)
+ adapter.updateItems(emptyList())
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
}
private fun refreshInfoBar() {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodeHomeFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodeHomeFragment.kt
index 48700ec3..a468a52b 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodeHomeFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodeHomeFragment.kt
@@ -5,6 +5,7 @@ import ac.mdiq.podcini.databinding.EpisodeHomeFragmentBinding
import ac.mdiq.podcini.storage.DBWriter.persistFeedItem
import ac.mdiq.podcini.storage.model.feed.FeedItem
import ac.mdiq.podcini.ui.utils.ShownotesCleaner
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.NetworkUtils.fetchHtmlSource
import android.content.Context
import android.os.Bundle
@@ -57,7 +58,7 @@ class EpisodeHomeFragment : Fragment() {
super.onCreateView(inflater, container, savedInstanceState)
_binding = EpisodeHomeFragmentBinding.inflate(inflater, container, false)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
toolbar = binding.toolbar
toolbar.title = ""
@@ -74,7 +75,7 @@ class EpisodeHomeFragment : Fragment() {
webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
val isEmpty = view?.title.isNullOrEmpty() && view?.contentDescription.isNullOrEmpty()
- if (isEmpty) Log.d(TAG, "content is empty")
+ if (isEmpty) Logd(TAG, "content is empty")
}
}
}
@@ -127,7 +128,7 @@ class EpisodeHomeFragment : Fragment() {
}
private fun initializeTTS(context: Context) {
- Log.d(TAG, "starting TTS")
+ Logd(TAG, "starting TTS")
if (tts == null) {
tts = TextToSpeech(context) { status: Int ->
if (status == TextToSpeech.SUCCESS) {
@@ -142,7 +143,7 @@ class EpisodeHomeFragment : Fragment() {
}
ttsReady = true
// semaphore.release()
- Log.d(TAG, "TTS init success")
+ Logd(TAG, "TTS init success")
} else {
Log.w(TAG, "TTS init failed")
requireActivity().runOnUiThread {Toast.makeText(context, R.string.tts_init_failed, Toast.LENGTH_LONG).show() }
@@ -154,7 +155,7 @@ class EpisodeHomeFragment : Fragment() {
private fun showWebContent() {
if (!currentItem?.link.isNullOrEmpty()) {
binding.webView.settings.javaScriptEnabled = jsEnabled
- Log.d(TAG, "currentItem!!.link ${currentItem!!.link}")
+ Logd(TAG, "currentItem!!.link ${currentItem!!.link}")
binding.webView.loadUrl(currentItem!!.link!!)
binding.readerView.visibility = View.GONE
binding.webView.visibility = View.VISIBLE
@@ -169,7 +170,7 @@ class EpisodeHomeFragment : Fragment() {
private val menuProvider = object: MenuProvider {
override fun onPrepareMenu(menu: Menu) {
// super.onPrepareMenu(menu)
- Log.d(TAG, "onPrepareMenu called")
+ Logd(TAG, "onPrepareMenu called")
val textSpeech = menu.findItem(R.id.text_speech)
textSpeech?.isVisible = readMode && tts != null
if (textSpeech?.isVisible == true) {
@@ -187,18 +188,18 @@ class EpisodeHomeFragment : Fragment() {
@OptIn(UnstableApi::class) override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
when (menuItem.itemId) {
R.id.switch_home -> {
- Log.d(TAG, "switch_home selected")
+ Logd(TAG, "switch_home selected")
switchMode()
return true
}
R.id.switchJS -> {
- Log.d(TAG, "switchJS selected")
+ Logd(TAG, "switchJS selected")
jsEnabled = !jsEnabled
showWebContent()
return true
}
R.id.text_speech -> {
- Log.d(TAG, "text_speech selected: $readerText")
+ Logd(TAG, "text_speech selected: $readerText")
if (tts != null) {
if (tts!!.isSpeaking) tts?.stop()
if (!ttsPlaying) {
@@ -255,7 +256,7 @@ class EpisodeHomeFragment : Fragment() {
@OptIn(UnstableApi::class) override fun onDestroyView() {
super.onDestroyView()
- Log.d(TAG, "onDestroyView")
+ Logd(TAG, "onDestroyView")
cleatWebview(binding.webView)
cleatWebview(binding.readerView)
_binding = null
@@ -267,7 +268,7 @@ class EpisodeHomeFragment : Fragment() {
@UnstableApi private fun updateAppearance() {
if (currentItem == null) {
- Log.d(TAG, "updateAppearance currentItem is null")
+ Logd(TAG, "updateAppearance currentItem is null")
return
}
// onPrepareOptionsMenu(toolbar.menu)
@@ -284,7 +285,7 @@ class EpisodeHomeFragment : Fragment() {
@JvmStatic
fun newInstance(item: FeedItem): EpisodeHomeFragment {
val fragment = EpisodeHomeFragment()
- Log.d(TAG, "item.itemIdentifier ${item.itemIdentifier}")
+ Logd(TAG, "item.itemIdentifier ${item.itemIdentifier}")
if (item.itemIdentifier != currentItem?.itemIdentifier) {
currentItem = item
} else {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt
index e7f41828..f6f61867 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt
@@ -51,10 +51,10 @@ import com.skydoves.balloon.ArrowOrientation
import com.skydoves.balloon.ArrowOrientationRules
import com.skydoves.balloon.Balloon
import com.skydoves.balloon.BalloonAnimation
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -93,7 +93,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
private var actionButton1: ItemActionButton? = null
private var actionButton2: ItemActionButton? = null
- private var disposable: Disposable? = null
+// private var disposable: Disposable? = null
private var controller: PlaybackController? = null
override fun onCreate(savedInstanceState: Bundle?) {
@@ -258,7 +258,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
_binding = null
EventBus.getDefault().unregister(this)
controller?.release()
- disposable?.dispose()
+// disposable?.dispose()
root.removeView(webvDescription)
webvDescription.clearHistory()
webvDescription.clearCache(true)
@@ -411,33 +411,51 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
load()
}
+// @UnstableApi private fun load0() {
+// disposable?.dispose()
+// if (!itemsLoaded) progbarLoading.visibility = View.VISIBLE
+//
+// Logd(TAG, "load() called")
+// disposable = Observable.fromCallable { this.loadInBackground() }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ result: FeedItem? ->
+// progbarLoading.visibility = View.GONE
+// item = result
+// onFragmentLoaded()
+// itemsLoaded = true
+// },
+// { error: Throwable? ->
+// Log.e(TAG, Log.getStackTraceString(error))
+// })
+// }
+
@UnstableApi private fun load() {
- disposable?.dispose()
if (!itemsLoaded) progbarLoading.visibility = View.VISIBLE
Logd(TAG, "load() called")
- disposable = Observable.fromCallable { this.loadInBackground() }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ result: FeedItem? ->
- progbarLoading.visibility = View.GONE
- item = result
- onFragmentLoaded()
- itemsLoaded = true
- },
- { error: Throwable? ->
- Log.e(TAG, Log.getStackTraceString(error))
- })
- }
-
- private fun loadInBackground(): FeedItem? {
- val feedItem = item
- if (feedItem != null) {
- val duration = feedItem.media?.getDuration()?: Int.MAX_VALUE
- DBReader.loadTextDetailsOfFeedItem(feedItem)
- webviewData = ShownotesCleaner(requireContext(), feedItem.description?:"", duration).processShownotes()
+ val scope = CoroutineScope(Dispatchers.Main)
+ scope.launch {
+ try {
+ val result = withContext(Dispatchers.IO) {
+ val feedItem = item
+ if (feedItem != null) {
+ val duration = feedItem.media?.getDuration()?: Int.MAX_VALUE
+ if (feedItem.description == null || feedItem.transcript == null) DBReader.loadTextDetailsOfFeedItem(feedItem)
+ webviewData = ShownotesCleaner(requireContext(), feedItem.description?:"", duration).processShownotes()
+ }
+ feedItem
+ }
+ withContext(Dispatchers.Main) {
+ progbarLoading.visibility = View.GONE
+ item = result
+ onFragmentLoaded()
+ itemsLoaded = true
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
}
- return feedItem
}
fun setItem(item_: FeedItem) {
@@ -446,15 +464,11 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
companion object {
private const val TAG = "EpisodeInfoFragment"
- private const val ARG_FEEDITEM = "feeditem"
@JvmStatic
fun newInstance(item: FeedItem): EpisodeInfoFragment {
val fragment = EpisodeInfoFragment()
fragment.setItem(item)
-// val args = Bundle()
-// args.putSerializable(ARG_FEEDITEM, item)
-// fragment.arguments = args
return fragment
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt
index 3fbafc1e..0874ec38 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt
@@ -3,7 +3,6 @@ package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
import ac.mdiq.podcini.databinding.FeedinfoBinding
import ac.mdiq.podcini.net.discovery.CombinedSearcher
-import ac.mdiq.podcini.storage.DBReader
import ac.mdiq.podcini.storage.DBTasks
import ac.mdiq.podcini.storage.model.feed.Feed
import ac.mdiq.podcini.storage.model.feed.FeedFunding
@@ -13,6 +12,7 @@ import ac.mdiq.podcini.ui.statistics.StatisticsFragment
import ac.mdiq.podcini.ui.statistics.feed.FeedStatisticsFragment
import ac.mdiq.podcini.ui.view.ToolbarIconTintManager
import ac.mdiq.podcini.util.IntentUtils
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.ShareUtils
import ac.mdiq.podcini.util.syndication.HtmlToPlainText
import android.R.string
@@ -44,12 +44,10 @@ import com.google.android.material.appbar.CollapsingToolbarLayout
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
-import io.reactivex.Completable
-import io.reactivex.Maybe
-import io.reactivex.MaybeEmitter
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.apache.commons.lang3.StringUtils
/**
@@ -57,14 +55,10 @@ import org.apache.commons.lang3.StringUtils
*/
@UnstableApi
class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
- private val addLocalFolderLauncher = registerForActivityResult(AddLocalFolder()) { uri: Uri? -> this.addLocalFolderResult(uri) }
-
private var _binding: FeedinfoBinding? = null
private val binding get() = _binding!!
private var feed: Feed? = null
- private var disposable: Disposable? = null
-
private lateinit var imgvCover: ImageView
private lateinit var txtvTitle: TextView
private lateinit var txtvDescription: TextView
@@ -77,6 +71,10 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
private lateinit var header: View
private lateinit var toolbar: MaterialToolbar
+ private val addLocalFolderLauncher = registerForActivityResult(AddLocalFolder()) {
+ uri: Uri? -> this.addLocalFolderResult(uri)
+ }
+
private val copyUrlToClipboard = View.OnClickListener {
if (feed != null && feed!!.download_url != null) {
val url: String = feed!!.download_url!!
@@ -90,7 +88,7 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FeedinfoBinding.inflate(inflater)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
toolbar = binding.toolbar
toolbar.title = ""
toolbar.inflateMenu(R.menu.feedinfo)
@@ -134,7 +132,8 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
txtvUrl.setOnClickListener(copyUrlToClipboard)
- val feedId = requireArguments().getLong(EXTRA_FEED_ID)
+// val feedId = requireArguments().getLong(EXTRA_FEED_ID)
+ val feedId = feed!!.id
parentFragmentManager.beginTransaction().replace(R.id.statisticsFragmentContainer,
FeedStatisticsFragment.newInstance(feedId, false), "feed_statistics_fragment")
.commitAllowingStateLoss()
@@ -144,24 +143,10 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
(activity as MainActivity).loadChildFragment(fragment, TransitionEffect.SLIDE)
}
+ showFeed()
return binding.root
}
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- val feedId = requireArguments().getLong(EXTRA_FEED_ID)
- disposable = Maybe.create { emitter: MaybeEmitter ->
- val feed: Feed? = DBReader.getFeed(feedId)
- if (feed != null) emitter.onSuccess(feed)
- else emitter.onComplete()
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ result: Feed? ->
- feed = result
- showFeed()
- }, { error: Throwable? -> Log.d(TAG, Log.getStackTraceString(error)) }, {})
- }
-
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
val horizontalSpacing = resources.getDimension(R.dimen.additional_horizontal_spacing).toInt()
@@ -171,28 +156,11 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
private fun showFeed() {
if (feed == null) return
- Log.d(TAG, "Language is " + feed!!.language)
- Log.d(TAG, "Author is " + feed!!.author)
- Log.d(TAG, "URL is " + feed!!.download_url)
-// if (!feed?.imageUrl.isNullOrBlank()) {
-// Glide.with(this)
-// .load(feed!!.imageUrl)
-// .apply(RequestOptions()
-// .placeholder(R.color.light_gray)
-// .error(R.color.light_gray)
-// .fitCenter()
-// .dontAnimate())
-// .into(imgvCover)
-// Glide.with(this)
-// .load(feed!!.imageUrl)
-// .apply(RequestOptions()
-// .placeholder(R.color.image_readability_tint)
-// .error(R.color.image_readability_tint)
-// .transform(FastBlurTransformation())
-// .dontAnimate())
-// .into(imgvBackground)
-// }
+ Logd(TAG, "Language is " + feed!!.language)
+ Logd(TAG, "Author is " + feed!!.author)
+ Logd(TAG, "URL is " + feed!!.download_url)
+// TODO: need to generate blurred image for background
imgvCover.load(feed!!.imageUrl) {
placeholder(R.color.light_gray)
error(R.mipmap.ic_launcher)
@@ -244,18 +212,21 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
refreshToolbarState()
}
+ fun setFeed(feed_: Feed) {
+ feed = feed_
+ }
+
override fun onDestroyView() {
super.onDestroyView()
_binding = null
- disposable?.dispose()
+ feed = null
}
private fun refreshToolbarState() {
toolbar.menu?.findItem(R.id.reconnect_local_folder)?.setVisible(feed != null && feed!!.isLocalFeed)
toolbar.menu?.findItem(R.id.share_item)?.setVisible(feed != null && !feed!!.isLocalFeed)
toolbar.menu?.findItem(R.id.visit_website_item)
- ?.setVisible(feed != null && feed!!.link != null && IntentUtils.isCallable(requireContext(),
- Intent(Intent.ACTION_VIEW, Uri.parse(feed!!.link))))
+ ?.setVisible(feed != null && feed!!.link != null && IntentUtils.isCallable(requireContext(), Intent(Intent.ACTION_VIEW, Uri.parse(feed!!.link))))
toolbar.menu?.findItem(R.id.edit_feed_url_item)?.setVisible(feed != null && !feed!!.isLocalFeed)
}
@@ -302,18 +273,37 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
@UnstableApi private fun reconnectLocalFolder(uri: Uri) {
if (feed == null) return
- Completable.fromAction {
- requireActivity().contentResolver
- .takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
- val documentFile = DocumentFile.fromTreeUri(requireContext(), uri)
- requireNotNull(documentFile) { "Unable to retrieve document tree" }
- feed!!.download_url = Feed.PREFIX_LOCAL_FOLDER + uri.toString()
- DBTasks.updateFeed(requireContext(), feed!!, true)
+// Completable.fromAction {
+// requireActivity().contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+// val documentFile = DocumentFile.fromTreeUri(requireContext(), uri)
+// requireNotNull(documentFile) { "Unable to retrieve document tree" }
+// feed!!.download_url = Feed.PREFIX_LOCAL_FOLDER + uri.toString()
+// DBTasks.updateFeed(requireContext(), feed!!, true)
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ (activity as MainActivity).showSnackbarAbovePlayer(string.ok, Snackbar.LENGTH_SHORT) },
+// { error: Throwable -> (activity as MainActivity).showSnackbarAbovePlayer(error.localizedMessage, Snackbar.LENGTH_LONG) })
+
+ val scope = CoroutineScope(Dispatchers.Main)
+ scope.launch {
+ try {
+ withContext(Dispatchers.IO) {
+ requireActivity().contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ val documentFile = DocumentFile.fromTreeUri(requireContext(), uri)
+ requireNotNull(documentFile) { "Unable to retrieve document tree" }
+ feed!!.download_url = Feed.PREFIX_LOCAL_FOLDER + uri.toString()
+ DBTasks.updateFeed(requireContext(), feed!!, true)
+ }
+ withContext(Dispatchers.Main) {
+ (activity as MainActivity).showSnackbarAbovePlayer(string.ok, Snackbar.LENGTH_SHORT)
+ }
+ } catch (e: Throwable) {
+ withContext(Dispatchers.Main) {
+ (activity as MainActivity).showSnackbarAbovePlayer(e.localizedMessage, Snackbar.LENGTH_LONG)
+ }
+ }
}
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ (activity as MainActivity).showSnackbarAbovePlayer(string.ok, Snackbar.LENGTH_SHORT) },
- { error: Throwable -> (activity as MainActivity).showSnackbarAbovePlayer(error.localizedMessage, Snackbar.LENGTH_LONG) })
}
private class AddLocalFolder : ActivityResultContracts.OpenDocumentTree() {
@@ -323,13 +313,11 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
companion object {
- private const val EXTRA_FEED_ID = "ac.mdiq.podcini.extra.feedId"
private const val TAG = "FeedInfoActivity"
+
fun newInstance(feed: Feed): FeedInfoFragment {
val fragment = FeedInfoFragment()
- val arguments = Bundle()
- arguments.putLong(EXTRA_FEED_ID, feed.id)
- fragment.arguments = arguments
+ fragment.setFeed(feed)
return fragment
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedItemlistFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedItemlistFragment.kt
index eecc335e..10ae2286 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedItemlistFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedItemlistFragment.kt
@@ -47,19 +47,12 @@ import com.google.android.material.snackbar.Snackbar
import com.joanzapata.iconify.Iconify
import com.leinardi.android.speeddial.SpeedDialActionItem
import com.leinardi.android.speeddial.SpeedDialView
-import io.reactivex.Maybe
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.*
import org.apache.commons.lang3.StringUtils
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
-import java.util.concurrent.Callable
import java.util.concurrent.ExecutionException
import java.util.concurrent.Semaphore
@@ -84,9 +77,10 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
private var headerCreated = false
private var feedID: Long = 0
private var feed: Feed? = null
- private var disposable: Disposable? = null
+// private var disposable: Disposable? = null
private val ioScope = CoroutineScope(Dispatchers.IO)
+ private val scope = CoroutineScope(Dispatchers.Main)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -217,7 +211,9 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
_binding = null
_speedDialBinding = null
EventBus.getDefault().unregister(this)
- disposable?.dispose()
+// disposable?.dispose()
+ ioScope.cancel()
+ scope.cancel()
adapter.endSelectMode()
tts?.stop()
@@ -483,20 +479,33 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
}
private fun showErrorDetails() {
- Maybe.fromCallable(
- Callable {
+// Maybe.fromCallable(
+// Callable {
+// val feedDownloadLog: List = DBReader.getFeedDownloadLog(feedID)
+// if (feedDownloadLog.isEmpty() || feedDownloadLog[0].isSuccessful) return@Callable null
+// feedDownloadLog[0]
+// })
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { downloadStatus: DownloadResult ->
+// DownloadLogDetailsDialog(requireContext(), downloadStatus).show()
+// },
+// { error: Throwable -> error.printStackTrace() },
+// { DownloadLogFragment().show(childFragmentManager, null) })
+
+ scope.launch {
+ val downloadResult = withContext(Dispatchers.IO) {
val feedDownloadLog: List = DBReader.getFeedDownloadLog(feedID)
- if (feedDownloadLog.isEmpty() || feedDownloadLog[0].isSuccessful) return@Callable null
- feedDownloadLog[0]
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { downloadStatus: DownloadResult ->
- DownloadLogDetailsDialog(requireContext(), downloadStatus).show()
- },
- { error: Throwable -> error.printStackTrace() },
- { DownloadLogFragment().show(childFragmentManager, null) })
+ if (feedDownloadLog.isEmpty() || feedDownloadLog[0].isSuccessful) null else feedDownloadLog[0]
+ }
+ withContext(Dispatchers.Main) {
+ if (downloadResult != null) DownloadLogDetailsDialog(requireContext(), downloadResult).show()
+ else DownloadLogFragment().show(childFragmentManager, null)
+ }
+ }.invokeOnCompletion { throwable ->
+ throwable?.printStackTrace()
+ }
}
@UnstableApi private fun showFeedInfo() {
@@ -508,19 +517,6 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
private fun loadFeedImage() {
if (!feed?.imageUrl.isNullOrBlank()) {
-// binding.imgvBackground.load(feed!!.imageUrl) {
-// placeholder(R.color.image_readability_tint)
-// error(R.color.image_readability_tint)
-// }
-// Glide.with(this)
-// .load(feed!!.imageUrl)
-// .apply(RequestOptions()
-// .placeholder(R.color.image_readability_tint)
-// .error(R.color.image_readability_tint)
-// .transform(FastBlurTransformation())
-// .dontAnimate())
-// .into(binding.imgvBackground)
-
binding.header.imgvCover.load(feed!!.imageUrl) {
placeholder(R.color.light_gray)
error(R.mipmap.ic_launcher)
@@ -529,17 +525,54 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
}
@UnstableApi private fun loadItems() {
- disposable?.dispose()
- disposable = Observable.fromCallable { this.loadData() }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { result: Feed? ->
- feed = result
- Logd(TAG, "loadItems subscribe called ${feed?.title}")
- if (feed != null) {
+// disposable?.dispose()
+// disposable = Observable.fromCallable { this.loadData() }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { result: Feed? ->
+// feed = result
+// Logd(TAG, "loadItems subscribe called ${feed?.title}")
+// if (feed != null) {
+// var hasNonMediaItems = false
+// for (item in feed!!.items) {
+// if (item.media == null) {
+// hasNonMediaItems = true
+// break
+// }
+// }
+// if (hasNonMediaItems) {
+// ioScope.launch {
+// if (!ttsReady) {
+// initializeTTS(requireContext())
+// semaphore.acquire()
+// }
+// }
+// }
+// }
+// swipeActions.setFilter(feed?.itemFilter)
+// refreshHeaderView()
+// binding.progressBar.visibility = View.GONE
+// adapter.setDummyViews(0)
+// if (feed != null) adapter.updateItems(feed!!.items)
+// binding.header.counts.text = (feed?.items?.size?:0).toString()
+// updateToolbar()
+// }, { error: Throwable? ->
+// feed = null
+// refreshHeaderView()
+// adapter.setDummyViews(0)
+// adapter.updateItems(emptyList())
+// updateToolbar()
+// Log.e(TAG, Log.getStackTraceString(error))
+// })
+
+ scope.launch {
+ try {
+ feed = withContext(Dispatchers.IO) {
+ val feed_ = loadData()
+ if (feed_ != null) {
var hasNonMediaItems = false
- for (item in feed!!.items) {
+ for (item in feed_!!.items) {
if (item.media == null) {
hasNonMediaItems = true
break
@@ -554,6 +587,10 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
}
}
}
+ feed_
+ }
+ withContext(Dispatchers.Main) {
+ Logd(TAG, "loadItems subscribe called ${feed?.title}")
swipeActions.setFilter(feed?.itemFilter)
refreshHeaderView()
binding.progressBar.visibility = View.GONE
@@ -561,14 +598,16 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
if (feed != null) adapter.updateItems(feed!!.items)
binding.header.counts.text = (feed?.items?.size?:0).toString()
updateToolbar()
- }, { error: Throwable? ->
- feed = null
- refreshHeaderView()
- adapter.setDummyViews(0)
- adapter.updateItems(emptyList())
- updateToolbar()
- Log.e(TAG, Log.getStackTraceString(error))
- })
+ }
+ } catch (e: Throwable) {
+ feed = null
+ refreshHeaderView()
+ adapter.setDummyViews(0)
+ adapter.updateItems(emptyList())
+ updateToolbar()
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
}
private fun loadData(): Feed? {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedSettingsFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedSettingsFragment.kt
index f3151ded..b1371a79 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedSettingsFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedSettingsFragment.kt
@@ -16,6 +16,7 @@ import ac.mdiq.podcini.ui.dialog.AuthenticationDialog
import ac.mdiq.podcini.ui.dialog.EpisodeFilterDialog
import ac.mdiq.podcini.ui.dialog.FeedPreferenceSkipDialog
import ac.mdiq.podcini.ui.dialog.TagSettingsDialog
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.settings.SkipIntroEndingChangedEvent
import ac.mdiq.podcini.util.event.settings.SpeedPresetChangedEvent
import ac.mdiq.podcini.util.event.settings.VolumeAdaptionChangedEvent
@@ -40,12 +41,7 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import io.reactivex.Maybe
-import io.reactivex.MaybeEmitter
-import io.reactivex.MaybeOnSubscribe
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import java.util.*
import java.util.concurrent.ExecutionException
@@ -54,13 +50,14 @@ class FeedSettingsFragment : Fragment() {
private var _binding: FeedsettingsBinding? = null
private val binding get() = _binding!!
- private var disposable: Disposable? = null
+ val scope = CoroutineScope(Dispatchers.Main)
+// private var disposable: Disposable? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FeedsettingsBinding.inflate(inflater)
val feedId = requireArguments().getLong(EXTRA_FEED_ID)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
val toolbar = binding.toolbar
toolbar.setNavigationOnClickListener { parentFragmentManager.popBackStack() }
@@ -69,16 +66,31 @@ class FeedSettingsFragment : Fragment() {
.replace(R.id.settings_fragment_container, FeedSettingsPreferenceFragment.newInstance(feedId), "settings_fragment")
.commitAllowingStateLoss()
- disposable = Maybe.create(MaybeOnSubscribe { emitter: MaybeEmitter ->
- val feed = DBReader.getFeed(feedId)
- if (feed != null) emitter.onSuccess(feed)
- else emitter.onComplete()
- } as MaybeOnSubscribe)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ result: Feed -> toolbar.subtitle = result.title },
- { error: Throwable? -> Log.d(TAG, Log.getStackTraceString(error)) },
- {})
+// disposable = Maybe.create(MaybeOnSubscribe { emitter: MaybeEmitter ->
+// val feed = DBReader.getFeed(feedId)
+// if (feed != null) emitter.onSuccess(feed)
+// else emitter.onComplete()
+// } as MaybeOnSubscribe)
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ result: Feed -> toolbar.subtitle = result.title },
+// { error: Throwable? -> Logd(TAG, Log.getStackTraceString(error)) },
+// {})
+
+ scope.launch {
+ val feed = withContext(Dispatchers.IO) {
+ DBReader.getFeed(feedId)
+ }
+ if (feed!= null) {
+ withContext(Dispatchers.Main) {
+ toolbar.subtitle = feed.title
+ }
+ }
+ }.invokeOnCompletion { throwable ->
+ if (throwable!= null) {
+ Logd(TAG, Log.getStackTraceString(throwable))
+ }
+ }
return binding.root
}
@@ -86,12 +98,14 @@ class FeedSettingsFragment : Fragment() {
override fun onDestroyView() {
super.onDestroyView()
_binding = null
- disposable?.dispose()
+ scope.cancel()
+// disposable?.dispose()
}
class FeedSettingsPreferenceFragment : PreferenceFragmentCompat() {
private var feed: Feed? = null
- private var disposable: Disposable? = null
+ val scope = CoroutineScope(Dispatchers.Main)
+// private var disposable: Disposable? = null
private var feedPreferences: FeedPreferences? = null
var notificationPermissionDenied: Boolean = false
@@ -123,46 +137,83 @@ class FeedSettingsFragment : Fragment() {
findPreference(PREF_SCREEN)!!.isVisible = false
val feedId = requireArguments().getLong(EXTRA_FEED_ID)
- disposable = Maybe.create { emitter: MaybeEmitter ->
- val feed = DBReader.getFeed(feedId)
- if (feed != null) emitter.onSuccess(feed)
- else emitter.onComplete()
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ result: Feed? ->
- feed = result
- feedPreferences = feed!!.preferences
+// disposable = Maybe.create { emitter: MaybeEmitter ->
+// val feed = DBReader.getFeed(feedId)
+// if (feed != null) emitter.onSuccess(feed)
+// else emitter.onComplete()
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ result: Feed? ->
+// feed = result
+// feedPreferences = feed!!.preferences
+//
+// setupAutoDownloadGlobalPreference()
+// setupAutoDownloadPreference()
+// setupKeepUpdatedPreference()
+// setupAutoDeletePreference()
+// setupVolumeAdaptationPreferences()
+//// setupNewEpisodesAction()
+// setupAuthentificationPreference()
+// setupEpisodeFilterPreference()
+// setupPlaybackSpeedPreference()
+// setupFeedAutoSkipPreference()
+//// setupEpisodeNotificationPreference()
+// setupTags()
+//
+// updateAutoDeleteSummary()
+// updateVolumeAdaptationValue()
+// updateAutoDownloadEnabled()
+//// updateNewEpisodesAction()
+//
+// if (feed!!.isLocalFeed) {
+// findPreference(PREF_AUTHENTICATION)!!.isVisible = false
+// findPreference(PREF_CATEGORY_AUTO_DOWNLOAD)!!.isVisible = false
+// }
+// findPreference(PREF_SCREEN)!!.isVisible = true
+// }, { error: Throwable? -> Logd(TAG, Log.getStackTraceString(error)) }, {})
- setupAutoDownloadGlobalPreference()
- setupAutoDownloadPreference()
- setupKeepUpdatedPreference()
- setupAutoDeletePreference()
- setupVolumeAdaptationPreferences()
-// setupNewEpisodesAction()
- setupAuthentificationPreference()
- setupEpisodeFilterPreference()
- setupPlaybackSpeedPreference()
- setupFeedAutoSkipPreference()
-// setupEpisodeNotificationPreference()
- setupTags()
+ scope.launch {
+ feed = withContext(Dispatchers.IO) {
+ DBReader.getFeed(feedId)
+ }
+ if (feed!= null) {
+ withContext(Dispatchers.Main) {
+ feedPreferences = feed!!.preferences
- updateAutoDeleteSummary()
- updateVolumeAdaptationValue()
- updateAutoDownloadEnabled()
-// updateNewEpisodesAction()
+ setupAutoDownloadGlobalPreference()
+ setupAutoDownloadPreference()
+ setupKeepUpdatedPreference()
+ setupAutoDeletePreference()
+ setupVolumeAdaptationPreferences()
+ setupAuthentificationPreference()
+ setupEpisodeFilterPreference()
+ setupPlaybackSpeedPreference()
+ setupFeedAutoSkipPreference()
+ setupTags()
- if (feed!!.isLocalFeed) {
- findPreference(PREF_AUTHENTICATION)!!.isVisible = false
- findPreference(PREF_CATEGORY_AUTO_DOWNLOAD)!!.isVisible = false
+ updateAutoDeleteSummary()
+ updateVolumeAdaptationValue()
+ updateAutoDownloadEnabled()
+
+ if (feed!!.isLocalFeed) {
+ findPreference(PREF_AUTHENTICATION)!!.isVisible = false
+ findPreference(PREF_CATEGORY_AUTO_DOWNLOAD)!!.isVisible = false
+ }
+ findPreference(PREF_SCREEN)!!.isVisible = true
}
- findPreference(PREF_SCREEN)!!.isVisible = true
- }, { error: Throwable? -> Log.d(TAG, Log.getStackTraceString(error)) }, {})
+ }
+ }.invokeOnCompletion { throwable ->
+ if (throwable!= null) {
+ Logd(TAG, Log.getStackTraceString(throwable))
+ }
+ }
}
override fun onDestroy() {
super.onDestroy()
- disposable?.dispose()
+ scope.cancel()
+// disposable?.dispose()
}
private fun setupFeedAutoSkipPreference() {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt
index c4eba568..1176e1f2 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt
@@ -6,15 +6,15 @@ import ac.mdiq.podcini.databinding.NavListBinding
import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.storage.DBReader
import ac.mdiq.podcini.storage.NavDrawerData
-import ac.mdiq.podcini.storage.model.feed.Feed
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.activity.PreferenceActivity
-import ac.mdiq.podcini.ui.adapter.NavListAdapter
import ac.mdiq.podcini.ui.activity.appstartintent.MainActivityStarter
-import ac.mdiq.podcini.ui.utils.ThemeUtils
-import ac.mdiq.podcini.ui.dialog.*
-import ac.mdiq.podcini.ui.actions.menuhandler.MenuItemUtils
+import ac.mdiq.podcini.ui.adapter.NavListAdapter
+import ac.mdiq.podcini.ui.dialog.DrawerPreferencesDialog
+import ac.mdiq.podcini.ui.dialog.SubscriptionsFilterDialog
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
+import ac.mdiq.podcini.ui.utils.ThemeUtils
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.FeedListUpdateEvent
import ac.mdiq.podcini.util.event.QueueEvent
import ac.mdiq.podcini.util.event.UnreadItemsUpdateEvent
@@ -28,12 +28,13 @@ import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.util.Log
-import android.view.*
-import android.widget.ProgressBar
+import android.view.ContextMenu
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
import androidx.annotation.OptIn
import androidx.annotation.VisibleForTesting
import androidx.core.graphics.Insets
-import androidx.core.util.Pair
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
@@ -42,10 +43,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.apache.commons.lang3.StringUtils
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@@ -58,19 +56,17 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
private var navDrawerData: NavDrawerData? = null
private var flatItemList: List? = null
- private var contextPressedItem: NavDrawerData.FeedDrawerItem? = null
- private var disposable: Disposable? = null
+ val scope = CoroutineScope(Dispatchers.Main)
private lateinit var navAdapter: NavListAdapter
- private lateinit var progressBar: ProgressBar
-
+
private var openFolders: MutableSet = HashSet()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
_binding = NavListBinding.inflate(inflater)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
setupDrawerRoundBackground(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, insets: WindowInsetsCompat ->
val bars: Insets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
@@ -88,9 +84,8 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
val preferences: SharedPreferences = requireContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
// TODO: what is this?
- openFolders = HashSet(preferences.getStringSet(PREF_OPEN_FOLDERS, HashSet())) // Must not modify
+ openFolders = HashSet(preferences.getStringSet(PREF_OPEN_FOLDERS, HashSet())!!) // Must not modify
- progressBar = binding.progressBar
val navList = binding.navRecycler
navAdapter = NavListAdapter(itemAccess, requireActivity())
navAdapter.setHasStableIds(true)
@@ -129,64 +124,8 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
super.onDestroyView()
_binding = null
EventBus.getDefault().unregister(this)
- disposable?.dispose()
-
- requireContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
- .unregisterOnSharedPreferenceChangeListener(this)
- }
-
- override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
- super.onCreateContextMenu(menu, v, menuInfo)
- val inflater: MenuInflater = requireActivity().menuInflater
- if (contextPressedItem != null) {
- menu.setHeaderTitle(contextPressedItem!!.title)
- inflater.inflate(R.menu.nav_feed_context, menu)
- // episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
- }
- MenuItemUtils.setOnClickListeners(menu
- ) { item: MenuItem -> this.onContextItemSelected(item) }
- }
-
- override fun onContextItemSelected(item: MenuItem): Boolean {
- val pressedItem: NavDrawerData.FeedDrawerItem? = contextPressedItem
- contextPressedItem = null
- if (pressedItem == null) return false
-
- return onFeedContextMenuClicked(pressedItem.feed, item)
- }
-
- @OptIn(UnstableApi::class) private fun onFeedContextMenuClicked(feed: Feed, item: MenuItem): Boolean {
- val itemId = item.itemId
- when (itemId) {
- R.id.edit_tags -> {
- if (feed.preferences != null) TagSettingsDialog.newInstance(listOf(feed.preferences!!)).show(childFragmentManager, TagSettingsDialog.TAG)
- return true
- }
- R.id.rename_item -> {
- RenameItemDialog(activity as Activity, feed).show()
- return true
- }
- R.id.remove_feed -> {
- RemoveFeedDialog.show(requireContext(), feed) {
- if (feed.id.toString() == getLastNavFragment(requireContext())) {
- (activity as MainActivity).loadFragment(UserPreferences.defaultPage, null)
- // Make sure fragment is hidden before actually starting to delete
- requireActivity().supportFragmentManager.executePendingTransactions()
- }
- }
- return true
- }
- else -> return super.onContextItemSelected(item)
- }
- }
-
- private fun onTagContextMenuClicked(drawerItem: NavDrawerData.FeedDrawerItem?, item: MenuItem): Boolean {
- val itemId = item.itemId
- if (itemId == R.id.rename_folder_item) {
- RenameItemDialog(activity as Activity, drawerItem).show()
- return true
- }
- return super.onContextItemSelected(item)
+ scope.cancel()
+ requireContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).unregisterOnSharedPreferenceChangeListener(this)
}
@Subscribe(threadMode = ThreadMode.MAIN)
@@ -194,7 +133,6 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
loadData()
}
-
@Subscribe(threadMode = ThreadMode.MAIN)
fun onFeedListChanged(event: FeedListUpdateEvent?) {
loadData()
@@ -202,7 +140,7 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
@Subscribe(threadMode = ThreadMode.MAIN)
fun onQueueChanged(event: QueueEvent) {
- Log.d(TAG, "onQueueChanged($event)")
+ Logd(TAG, "onQueueChanged($event)")
// we are only interested in the number of queue items, not download status or position
if (event.action == QueueEvent.Action.DELETED_MEDIA || event.action == QueueEvent.Action.SORTED || event.action == QueueEvent.Action.MOVED) return
@@ -245,12 +183,18 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
override val numberOfNewItems: Int
get() = navDrawerData?.numNewItems ?: 0
+ override val numberOfItems: Int
+ get() = navDrawerData?.numItems ?: 0
+
override val numberOfDownloadedItems: Int
get() = navDrawerData?.numDownloadedItems ?: 0
override val reclaimableItems: Int
get() = navDrawerData?.reclaimableSpace ?: 0
+ override val numberOfFeeds: Int
+ get() = navDrawerData?.numFeeds ?: 0
+
override val feedCounterSum: Int
get() {
if (navDrawerData == null) return 0
@@ -297,7 +241,7 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
}
return true
} else {
- contextPressedItem = flatItemList!![position - navAdapter.subscriptionOffset]
+// contextPressedItem = flatItemList!![position - navAdapter.subscriptionOffset]
return false
}
}
@@ -308,22 +252,21 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
}
private fun loadData() {
- disposable = Observable.fromCallable {
- val data: NavDrawerData = DBReader.getNavDrawerData(UserPreferences.subscriptionsFilter)
- Pair(data, makeFlatDrawerData(data.items, 0))
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { result: Pair> ->
+ scope.launch {
+ try {
+ val result = withContext(Dispatchers.IO) {
+ val data: NavDrawerData = DBReader.getNavDrawerData(UserPreferences.subscriptionsFilter)
+ Pair(data, makeFlatDrawerData(data.items, 0))
+ }
+ withContext(Dispatchers.Main) {
navDrawerData = result.first
flatItemList = result.second
navAdapter.notifyDataSetChanged()
- progressBar.visibility = View.GONE // Stays hidden once there is something in the list
- }, { error: Throwable? ->
- Log.e(TAG, Log.getStackTraceString(error))
- progressBar.visibility = View.GONE
- })
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
}
private fun makeFlatDrawerData(items: List, layer: Int): List {
@@ -362,7 +305,7 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
)
fun saveLastNavFragment(context: Context, tag: String?) {
- Log.d(TAG, "saveLastNavFragment(tag: $tag)")
+ Logd(TAG, "saveLastNavFragment(tag: $tag)")
val prefs: SharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
val edit: SharedPreferences.Editor = prefs.edit()
if (tag != null) edit.putString(PREF_LAST_FRAGMENT_TAG, tag)
@@ -374,7 +317,7 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
fun getLastNavFragment(context: Context): String {
val prefs: SharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
val lastFragment: String = prefs.getString(PREF_LAST_FRAGMENT_TAG, SubscriptionFragment.TAG)?:""
- Log.d(TAG, "getLastNavFragment() -> $lastFragment")
+ Logd(TAG, "getLastNavFragment() -> $lastFragment")
return lastFragment
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineFeedViewFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineFeedViewFragment.kt
index 7e310913..64449b51 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineFeedViewFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineFeedViewFragment.kt
@@ -54,12 +54,12 @@ import androidx.media3.common.util.UnstableApi
import coil.load
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
-import io.reactivex.Maybe
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
-import io.reactivex.observers.DisposableMaybeObserver
import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -98,6 +98,8 @@ class OnlineFeedViewFragment : Fragment() {
private var dialog: Dialog? = null
+ val scope = CoroutineScope(Dispatchers.Main)
+
private var download: Disposable? = null
private var parser: Disposable? = null
private var updater: Disposable? = null
@@ -197,6 +199,18 @@ class OnlineFeedViewFragment : Fragment() {
Log.e(TAG, Log.getStackTraceString(error))
}
})
+// scope.launch(Dispatchers.IO) {
+// try {
+// startFeedDownload(url)
+// } catch (e: FeedUrlNotFoundException) {
+// tryToRetrieveFeedUrlBySearch(e)
+// } catch (e: Throwable) {
+// withContext(Dispatchers.Main) {
+// showNoPodcastFoundError()
+// Log.e(TAG, Log.getStackTraceString(e))
+// }
+// }
+// }
}
private fun tryToRetrieveFeedUrlBySearch(error: FeedUrlNotFoundException) {
@@ -269,16 +283,32 @@ class OnlineFeedViewFragment : Fragment() {
.withInitiatedByUser(true)
.build()
- download = Observable.fromCallable {
- feeds = DBReader.getFeedList()
- downloader = HttpDownloader(request)
- downloader?.call()
- downloader?.result
+// download = Observable.fromCallable {
+// feeds = DBReader.getFeedList()
+// downloader = HttpDownloader(request)
+// downloader?.call()
+// downloader?.result
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ status: DownloadResult? -> if (request.destination != null) checkDownloadResult(status, request.destination) },
+// { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+
+ scope.launch {
+ try {
+ val status = withContext(Dispatchers.IO) {
+ feeds = DBReader.getFeedList()
+ downloader = HttpDownloader(request)
+ downloader?.call()
+ downloader?.result
+ }
+ withContext(Dispatchers.Main) {
+ if (request.destination != null) checkDownloadResult(status, request.destination)
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
}
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ status: DownloadResult? -> if (request.destination != null) checkDownloadResult(status, request.destination) },
- { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
}
private fun checkDownloadResult(status: DownloadResult?, destination: String) {
@@ -301,15 +331,30 @@ class OnlineFeedViewFragment : Fragment() {
@UnstableApi @Subscribe
fun onFeedListChanged(event: FeedListUpdateEvent?) {
- updater = Observable.fromCallable { DBReader.getFeedList() }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { feeds: List? ->
+// updater = Observable.fromCallable { DBReader.getFeedList() }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { feeds: List? ->
+// this@OnlineFeedViewFragment.feeds = feeds
+// handleUpdatedFeedStatus()
+// }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) }
+// )
+ scope.launch {
+ try {
+ val feeds = withContext(Dispatchers.IO) {
+ DBReader.getFeedList()
+ }
+ withContext(Dispatchers.Main) {
this@OnlineFeedViewFragment.feeds = feeds
handleUpdatedFeedStatus()
- }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) }
- )
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
+
+
}
@UnstableApi @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
@@ -317,25 +362,40 @@ class OnlineFeedViewFragment : Fragment() {
handleUpdatedFeedStatus()
}
- private fun parseFeed(destination: String) {
+ @OptIn(UnstableApi::class) private fun parseFeed(destination: String) {
Logd(TAG, "Parsing feed")
- parser = Maybe.fromCallable { doParseFeed(destination) }
- .subscribeOn(Schedulers.computation())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(object : DisposableMaybeObserver() {
- @UnstableApi override fun onSuccess(result: FeedHandlerResult) {
- showFeedInformation(result.feed, result.alternateFeedUrls)
+// parser = Maybe.fromCallable { doParseFeed(destination) }
+// .subscribeOn(Schedulers.computation())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribeWith(object : DisposableMaybeObserver() {
+// @UnstableApi override fun onSuccess(result: FeedHandlerResult) {
+// showFeedInformation(result.feed, result.alternateFeedUrls)
+// }
+//
+// override fun onComplete() {
+// // Ignore null result: We showed the discovery dialog.
+// }
+//
+// override fun onError(error: Throwable) {
+// showErrorDialog(error.message, "")
+// Logd(TAG, "Feed parser exception: " + Log.getStackTraceString(error))
+// }
+// })
+ scope.launch {
+ try {
+ val result = withContext(Dispatchers.Default) {
+ doParseFeed(destination)
}
-
- override fun onComplete() {
- // Ignore null result: We showed the discovery dialog.
+ withContext(Dispatchers.Main) {
+ if (result != null) showFeedInformation(result.feed, result.alternateFeedUrls)
}
-
- override fun onError(error: Throwable) {
- showErrorDialog(error.message, "")
- Logd(TAG, "Feed parser exception: " + Log.getStackTraceString(error))
+ } catch (e: Throwable) {
+ withContext(Dispatchers.Main) {
+ showErrorDialog(e.message, "")
+ Logd(TAG, "Feed parser exception: " + Log.getStackTraceString(e))
}
- })
+ }
+ }
}
/**
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt
index c003594f..dc8e92a2 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt
@@ -7,6 +7,7 @@ import ac.mdiq.podcini.net.discovery.PodcastSearcher
import ac.mdiq.podcini.net.discovery.PodcastSearcherRegistry
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.adapter.OnlineFeedsAdapter
+import ac.mdiq.podcini.util.Logd
import android.content.Context
import android.os.Bundle
import android.util.Log
@@ -46,7 +47,7 @@ class OnlineSearchFragment : Fragment() {
super.onCreate(savedInstanceState)
for (info in PodcastSearcherRegistry.searchProviders) {
- Log.d(TAG, "searchProvider: $info")
+ Logd(TAG, "searchProvider: $info")
if (info.searcher.javaClass.getName() == requireArguments().getString(ARG_SEARCHER)) {
searchProvider = info.searcher
break
@@ -58,7 +59,7 @@ class OnlineSearchFragment : Fragment() {
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentItunesSearchBinding.inflate(inflater)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
gridView = binding.gridView
adapter = OnlineFeedsAdapter(requireContext(), ArrayList())
gridView.setAdapter(adapter)
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/PlaybackHistoryFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/PlaybackHistoryFragment.kt
index 2ea8c407..5eaeb2e7 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/PlaybackHistoryFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/PlaybackHistoryFragment.kt
@@ -14,6 +14,7 @@ import ac.mdiq.podcini.storage.DBWriter
import ac.mdiq.podcini.util.event.playback.PlaybackHistoryEvent
import ac.mdiq.podcini.storage.model.feed.FeedItem
import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
+import ac.mdiq.podcini.util.Logd
import android.util.Log
import androidx.annotation.OptIn
import org.greenrobot.eventbus.Subscribe
@@ -30,7 +31,7 @@ class PlaybackHistoryFragment : BaseEpisodesListFragment() {
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val root = super.onCreateView(inflater, container, savedInstanceState)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
toolbar.inflateMenu(R.menu.playback_history)
toolbar.setTitle(R.string.playback_history_label)
updateToolbar()
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/PlayerDetailsFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/PlayerDetailsFragment.kt
index 8144d8d2..a7f69073 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/PlayerDetailsFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/PlayerDetailsFragment.kt
@@ -16,6 +16,7 @@ import ac.mdiq.podcini.ui.utils.ShownotesCleaner
import ac.mdiq.podcini.ui.view.ShownotesWebView
import ac.mdiq.podcini.util.ChapterUtils
import ac.mdiq.podcini.util.DateFormatter
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.NetworkUtils.fetchHtmlSource
import ac.mdiq.podcini.util.event.playback.PlaybackPositionEvent
import android.animation.Animator
@@ -46,12 +47,7 @@ import coil.request.ErrorResult
import coil.request.ImageRequest
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.Snackbar
-import io.reactivex.Maybe
-import io.reactivex.MaybeEmitter
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.*
import net.dankito.readability4j.Readability4J
import org.apache.commons.lang3.StringUtils
import org.greenrobot.eventbus.Subscribe
@@ -61,20 +57,20 @@ import org.greenrobot.eventbus.ThreadMode
* Displays the description of a Playable object in a Webview.
*/
@UnstableApi
-class PlayerDetailsFragment : Fragment() {
+class PlayerDetailsFragment : Fragment() {
private lateinit var shownoteView: ShownotesWebView
private var _binding: PlayerDetailsFragmentBinding? = null
private val binding get() = _binding!!
+ private var prevItem: FeedItem? = null
private var media: Playable? = null
private var item: FeedItem? = null
- private var loadedMediaId: Any? = null
private var displayedChapterIndex = -1
+ val scope = CoroutineScope(Dispatchers.Main)
private var cleanedNotes: String? = null
- private var disposable: Disposable? = null
- private var webViewLoader: Disposable? = null
+// private var webViewLoader: Disposable? = null
private var controller: PlaybackController? = null
internal var showHomeText = false
@@ -82,7 +78,7 @@ class PlayerDetailsFragment : Fragment() {
internal var readerhtml: String? = null
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
_binding = PlayerDetailsFragmentBinding.inflate(inflater)
binding.imgvCover.setOnClickListener { onPlayPause() }
@@ -94,7 +90,7 @@ class PlayerDetailsFragment : Fragment() {
binding.butPrevChapter.setOnClickListener { seekToPrevChapter() }
binding.butNextChapter.setOnClickListener { seekToNextChapter() }
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
shownoteView = binding.webview
shownoteView.setTimecodeSelectedListener { time: Int? -> controller?.seekTo(time!!) }
shownoteView.setPageFinishedListener {
@@ -123,7 +119,7 @@ class PlayerDetailsFragment : Fragment() {
_binding = null
controller?.release()
controller = null
- Log.d(TAG, "Fragment destroyed")
+ Logd(TAG, "Fragment destroyed")
shownoteView.removeAllViews()
shownoteView.destroy()
}
@@ -132,60 +128,85 @@ class PlayerDetailsFragment : Fragment() {
return shownoteView.onContextItemSelected(item)
}
- @UnstableApi private fun load() {
- Log.d(TAG, "load() called")
- webViewLoader?.dispose()
+// @UnstableApi private fun load0() {
+// webViewLoader?.dispose()
+//
+// val context = context ?: return
+// webViewLoader = Maybe.create { emitter: MaybeEmitter ->
+// if (item == null) {
+// media = controller?.getMedia()
+// if (media == null) {
+// emitter.onComplete()
+// return@create
+// }
+// if (media is FeedMedia) {
+// val feedMedia = media as FeedMedia
+// item = feedMedia.item
+// item?.setDescription(null)
+// showHomeText = false
+// homeText = null
+// }
+// }
+// if (item != null) {
+// media = item!!.media
+// if (item!!.description == null) DBReader.loadTextDetailsOfFeedItem(item!!)
+// if (prevItem?.itemIdentifier != item!!.itemIdentifier) cleanedNotes = null
+// if (cleanedNotes == null) {
+// Logd(TAG, "calling load description ${item!!.description==null} ${item!!.title}")
+// val shownotesCleaner = ShownotesCleaner(context, item?.description ?: "", media?.getDuration()?:0)
+// cleanedNotes = shownotesCleaner.processShownotes()
+// }
+// prevItem = item
+// emitter.onSuccess(cleanedNotes?:"")
+// } else emitter.onComplete()
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ data: String? ->
+// Logd(TAG, "subscribe: ${media?.getEpisodeTitle()}")
+// displayMediaInfo(media!!)
+// shownoteView.loadDataWithBaseURL("https://127.0.0.1", data!!, "text/html", "utf-8", "about:blank")
+// Logd(TAG, "Webview loaded")
+// }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+// }
+ private fun load() {
val context = context ?: return
- webViewLoader = Maybe.create { emitter: MaybeEmitter ->
- media = controller?.getMedia()
- if (media == null) {
- emitter.onComplete()
- return@create
- }
- if (media is FeedMedia) {
- val feedMedia = media as FeedMedia
- if (item?.itemIdentifier != feedMedia.item?.itemIdentifier) {
- item = feedMedia.item
- showHomeText = false
- homeText = null
+ scope.launch {
+ withContext(Dispatchers.IO) {
+ if (item == null) {
+ media = controller?.getMedia()
+ if (media != null && media is FeedMedia) {
+ val feedMedia = media as FeedMedia
+ item = feedMedia.item
+ item?.setDescription(null)
+ showHomeText = false
+ homeText = null
+ }
+ }
+ if (item != null) {
+ media = item!!.media
+ if (item!!.description == null) DBReader.loadTextDetailsOfFeedItem(item!!)
+ if (prevItem?.itemIdentifier != item!!.itemIdentifier) cleanedNotes = null
+ if (cleanedNotes == null) {
+ Logd(TAG, "calling load description ${item!!.description==null} ${item!!.title}")
+ val shownotesCleaner = ShownotesCleaner(context, item?.description ?: "", media?.getDuration()?:0)
+ cleanedNotes = shownotesCleaner.processShownotes()
+ }
+ prevItem = item
}
}
-// Log.d(TAG, "webViewLoader ${item?.id} ${cleanedNotes==null} ${item!!.description==null} ${loadedMediaId == null} ${item?.media?.getIdentifier()} ${media?.getIdentifier()}")
- if (item != null) {
- if (cleanedNotes == null || item!!.description == null || loadedMediaId != media?.getIdentifier()) {
- Log.d(TAG, "calling load description ${cleanedNotes==null} ${item!!.description==null} ${item!!.media?.getIdentifier()} ${media?.getIdentifier()}")
-// printStackTrace()
- DBReader.loadTextDetailsOfFeedItem(item!!)
- loadedMediaId = media?.getIdentifier()
- val shownotesCleaner = ShownotesCleaner(context, item?.description ?: "", media?.getDuration()?:0)
- cleanedNotes = shownotesCleaner.processShownotes()
- }
+ withContext(Dispatchers.Main) {
+ Logd(TAG, "subscribe: ${media?.getEpisodeTitle()}")
+ displayMediaInfo(media!!)
+ shownoteView.loadDataWithBaseURL("https://127.0.0.1", cleanedNotes!!, "text/html", "utf-8", "about:blank")
+ Logd(TAG, "Webview loaded")
+ }
+ }.invokeOnCompletion { throwable ->
+ if (throwable!= null) {
+ Log.e(TAG, Log.getStackTraceString(throwable))
}
- emitter.onSuccess(cleanedNotes?:"")
}
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ data: String? ->
- shownoteView.loadDataWithBaseURL("https://127.0.0.1", data!!, "text/html", "utf-8", "about:blank")
- Log.d(TAG, "Webview loaded")
- }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
-
- loadMediaInfo()
- }
-
- @UnstableApi private fun loadMediaInfo() {
- disposable?.dispose()
- disposable = Maybe.create { emitter: MaybeEmitter ->
- media = controller?.getMedia()
- if (media != null) emitter.onSuccess(media!!)
- else emitter.onComplete()
- }.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ media: Playable ->
- this.media = media
- displayMediaInfo(media)
- }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
}
fun buildHomeReaderText() {
@@ -220,27 +241,21 @@ class PlayerDetailsFragment : Fragment() {
}
@UnstableApi private fun displayMediaInfo(media: Playable) {
+ Logd(TAG, "displayMediaInfo ${item?.title} ${media.getEpisodeTitle()}")
val pubDateStr = DateFormatter.formatAbbrev(context, media.getPubDate())
binding.txtvPodcastTitle.text = StringUtils.stripToEmpty(media.getFeedTitle())
- if (item == null || item!!.media?.getIdentifier() != media.getIdentifier()) {
- if (media is FeedMedia) {
- if (item?.itemIdentifier != media.item?.itemIdentifier) {
- item = media.item
- showHomeText = false
- homeText = null
- }
- if (item != null) {
- val openFeed: Intent = MainActivity.getIntentToOpenFeed(requireContext(), item!!.feedId)
- binding.txtvPodcastTitle.setOnClickListener { startActivity(openFeed) }
- }
- } else {
- binding.txtvPodcastTitle.setOnClickListener(null)
+ if (media is FeedMedia) {
+ if (item != null) {
+ val openFeed: Intent = MainActivity.getIntentToOpenFeed(requireContext(), item!!.feedId)
+ binding.txtvPodcastTitle.setOnClickListener { startActivity(openFeed) }
}
+ } else {
+ binding.txtvPodcastTitle.setOnClickListener(null)
}
binding.txtvPodcastTitle.setOnLongClickListener { copyText(media.getFeedTitle()) }
binding.episodeDate.text = StringUtils.stripToEmpty(pubDateStr)
- binding.txtvEpisodeTitle.text = media.getEpisodeTitle()
- binding.txtvEpisodeTitle.setOnLongClickListener { copyText(media.getEpisodeTitle()) }
+ binding.txtvEpisodeTitle.text = item?.title
+ binding.txtvEpisodeTitle.setOnLongClickListener { copyText(item?.title?:"") }
binding.txtvEpisodeTitle.setOnClickListener {
val lines = binding.txtvEpisodeTitle.lineCount
val animUnit = 1500
@@ -300,19 +315,7 @@ class PlayerDetailsFragment : Fragment() {
private fun displayCoverImage() {
if (media == null) return
-// val options: RequestOptions = RequestOptions()
-// .dontAnimate()
-// .transform(FitCenter(), RoundedCorners((16 * resources.displayMetrics.density).toInt()))
-
-// val cover: RequestBuilder = Glide.with(this)
-// .load(media!!.getImageLocation())
-// .error(Glide.with(this)
-// .load(ImageResourceUtils.getFallbackImageLocation(media!!))
-// .apply(options))
-// .apply(options)
-
if (displayedChapterIndex == -1 || media!!.getChapters().isEmpty() || media!!.getChapters()[displayedChapterIndex].imageUrl.isNullOrEmpty()) {
-// cover.into(binding.imgvCover)
val imageLoader = binding.imgvCover.context.imageLoader
val imageRequest = ImageRequest.Builder(requireContext())
.data(media!!.getImageLocation())
@@ -335,12 +338,6 @@ class PlayerDetailsFragment : Fragment() {
} else {
val imgLoc = EmbeddedChapterImage.getModelFor(media!!, displayedChapterIndex)
-// if (imgLoc != null) Glide.with(this)
-// .load(imgLoc)
-// .apply(options)
-// .thumbnail(cover)
-// .error(cover)
-// .into(binding.imgvCover)
val imageLoader = binding.imgvCover.context.imageLoader
val imageRequest = ImageRequest.Builder(requireContext())
.data(imgLoc)
@@ -402,15 +399,15 @@ class PlayerDetailsFragment : Fragment() {
}
@UnstableApi private fun savePreference() {
- Log.d(TAG, "Saving preferences")
+ Logd(TAG, "Saving preferences")
val prefs = requireActivity().getSharedPreferences(PREF, Activity.MODE_PRIVATE)
val editor = prefs.edit()
if (controller?.getMedia() != null) {
- Log.d(TAG, "Saving scroll position: " + binding.itemDescriptionFragment.scrollY)
+ Logd(TAG, "Saving scroll position: " + binding.itemDescriptionFragment.scrollY)
editor.putInt(PREF_SCROLL_Y, binding.itemDescriptionFragment.scrollY)
editor.putString(PREF_PLAYABLE_ID, controller!!.getMedia()!!.getIdentifier().toString())
} else {
- Log.d(TAG, "savePreferences was called while media or webview was null")
+ Logd(TAG, "savePreferences was called while media or webview was null")
editor.putInt(PREF_SCROLL_Y, -1)
editor.putString(PREF_PLAYABLE_ID, "")
}
@@ -420,7 +417,7 @@ class PlayerDetailsFragment : Fragment() {
@UnstableApi private fun restoreFromPreference(): Boolean {
if ((activity as MainActivity).bottomSheet.state != BottomSheetBehavior.STATE_EXPANDED) return false
- Log.d(TAG, "Restoring from preferences")
+ Logd(TAG, "Restoring from preferences")
val activity: Activity? = activity
if (activity != null) {
val prefs = activity.getSharedPreferences(PREF, Activity.MODE_PRIVATE)
@@ -428,11 +425,11 @@ class PlayerDetailsFragment : Fragment() {
val scrollY = prefs.getInt(PREF_SCROLL_Y, -1)
if (scrollY != -1) {
if (id == controller?.getMedia()?.getIdentifier()?.toString()) {
- Log.d(TAG, "Restored scroll Position: $scrollY")
+ Logd(TAG, "Restored scroll Position: $scrollY")
binding.itemDescriptionFragment.scrollTo(binding.itemDescriptionFragment.scrollX, scrollY)
return true
}
- Log.d(TAG, "reset scroll Position: 0")
+ Logd(TAG, "reset scroll Position: 0")
binding.itemDescriptionFragment.scrollTo(0, 0)
return true
@@ -455,7 +452,7 @@ class PlayerDetailsFragment : Fragment() {
}
fun setItem(item_: FeedItem) {
- Log.d(TAG, "setItem ${item_.title}")
+ Logd(TAG, "setItem ${item_.title}")
if (item?.itemIdentifier != item_.itemIdentifier) {
item = item_
showHomeText = false
@@ -491,7 +488,7 @@ class PlayerDetailsFragment : Fragment() {
override fun onStop() {
super.onStop()
- webViewLoader?.dispose()
+// webViewLoader?.dispose()
}
@UnstableApi private fun copyText(text: String): Boolean {
@@ -504,7 +501,7 @@ class PlayerDetailsFragment : Fragment() {
}
companion object {
- private const val TAG = "ItemDescriptionFragment"
+ private const val TAG = "PlayerDetailsFragment"
private const val PREF = "ItemDescriptionFragmentPrefs"
private const val PREF_SCROLL_Y = "prefScrollY"
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt
index 3ebb0460..49790184 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt
@@ -6,27 +6,30 @@ import ac.mdiq.podcini.databinding.MultiSelectSpeedDialBinding
import ac.mdiq.podcini.databinding.QueueFragmentBinding
import ac.mdiq.podcini.feed.util.PlaybackSpeedUtils
import ac.mdiq.podcini.net.download.FeedUpdateManager
-import ac.mdiq.podcini.util.event.playback.PlaybackPositionEvent
import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.storage.DBReader
import ac.mdiq.podcini.storage.DBWriter
-import ac.mdiq.podcini.storage.model.feed.*
+import ac.mdiq.podcini.storage.model.feed.FeedItem
+import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
+import ac.mdiq.podcini.storage.model.feed.SortOrder
+import ac.mdiq.podcini.ui.actions.EpisodeMultiSelectActionHandler
+import ac.mdiq.podcini.ui.actions.menuhandler.FeedItemMenuHandler
+import ac.mdiq.podcini.ui.actions.menuhandler.MenuItemUtils
+import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.adapter.QueueRecyclerAdapter
import ac.mdiq.podcini.ui.adapter.SelectableAdapter
import ac.mdiq.podcini.ui.dialog.ConfirmationDialog
import ac.mdiq.podcini.ui.dialog.ItemSortDialog
-import ac.mdiq.podcini.ui.actions.EpisodeMultiSelectActionHandler
-import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions
-import ac.mdiq.podcini.ui.actions.menuhandler.FeedItemMenuHandler
-import ac.mdiq.podcini.ui.actions.menuhandler.MenuItemUtils
import ac.mdiq.podcini.ui.view.EmptyViewHandler
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
import ac.mdiq.podcini.util.Converter
import ac.mdiq.podcini.util.FeedItemUtil
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.*
+import ac.mdiq.podcini.util.event.playback.PlaybackPositionEvent
import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences
@@ -48,10 +51,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.leinardi.android.speeddial.SpeedDialActionItem
import com.leinardi.android.speeddial.SpeedDialView
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -81,7 +81,8 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
private var recyclerAdapter: QueueRecyclerAdapter? = null
private var currentPlaying: EpisodeItemViewHolder? = null
- private var disposable: Disposable? = null
+ val scope = CoroutineScope(Dispatchers.Main)
+// private var disposable: Disposable? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -93,7 +94,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
super.onCreateView(inflater, container, savedInstanceState)
_binding = QueueFragmentBinding.inflate(inflater)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
toolbar = binding.toolbar
toolbar.setOnMenuItemClickListener(this)
toolbar.setOnLongClickListener {
@@ -194,12 +195,13 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
override fun onStop() {
super.onStop()
- disposable?.dispose()
+ scope.cancel()
+// disposable?.dispose()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: QueueEvent) {
- Log.d(TAG, "onEventMainThread() called with QueueEvent event = [$event]")
+ Logd(TAG, "onEventMainThread() called with QueueEvent event = [$event]")
if (recyclerAdapter == null) {
loadItems(true)
return
@@ -236,7 +238,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: FeedItemEvent) {
- Log.d(TAG, "onEventMainThread() called with FeedItemEvent event = [$event]")
+ Logd(TAG, "onEventMainThread() called with FeedItemEvent event = [$event]")
if (recyclerAdapter == null) {
loadItems(true)
return
@@ -258,7 +260,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: EpisodeDownloadEvent) {
- Log.d(TAG, "onEventMainThread() called with EpisodeDownloadEvent event = [$event]")
+ Logd(TAG, "onEventMainThread() called with EpisodeDownloadEvent event = [$event]")
for (downloadUrl in event.urls) {
val pos: Int = FeedItemUtil.indexOfItemWithDownloadUrl(queue.toList(), downloadUrl)
if (pos >= 0) recyclerAdapter?.notifyItemChangedCompat(pos)
@@ -271,7 +273,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
if (recyclerAdapter != null) {
if (currentPlaying != null && currentPlaying!!.isCurrentlyPlayingItem) currentPlaying!!.notifyPlaybackPositionUpdated(event)
else {
- Log.d(TAG, "onEventMainThread() search list")
+ Logd(TAG, "onEventMainThread() search list")
for (i in 0 until recyclerAdapter!!.itemCount) {
val holder: EpisodeItemViewHolder? = recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
if (holder != null && holder.isCurrentlyPlayingItem) {
@@ -286,7 +288,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
@Subscribe(threadMode = ThreadMode.MAIN)
fun onPlayerStatusChanged(event: PlayerStatusEvent?) {
- Log.d(TAG, "onPlayerStatusChanged() called with event = [$event]")
+ Logd(TAG, "onPlayerStatusChanged() called with event = [$event]")
loadItems(false)
refreshToolbarState()
}
@@ -294,7 +296,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUnreadItemsChanged(event: UnreadItemsUpdateEvent?) {
// Sent when playback position is reset
- Log.d(TAG, "onUnreadItemsChanged() called with event = [$event]")
+ Logd(TAG, "onUnreadItemsChanged() called with event = [$event]")
loadItems(false)
refreshToolbarState()
}
@@ -426,7 +428,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
}
@UnstableApi override fun onContextItemSelected(item: MenuItem): Boolean {
- Log.d(TAG, "onContextItemSelected() called with: item = [$item]")
+ Logd(TAG, "onContextItemSelected() called with: item = [$item]")
if (!isVisible || recyclerAdapter == null) return false
val selectedItem: FeedItem? = recyclerAdapter!!.longPressedItem
@@ -485,22 +487,38 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
}
private fun loadItems(restoreScrollPosition: Boolean) {
- Log.d(TAG, "loadItems() called")
- disposable?.dispose()
+ Logd(TAG, "loadItems() called")
+// disposable?.dispose()
if (queue.isEmpty()) emptyView.hide()
- disposable = Observable.fromCallable { DBReader.getQueue().toMutableList() }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ items: MutableList ->
- queue = items
- progressBar.visibility = View.GONE
- recyclerAdapter?.setDummyViews(0)
- recyclerAdapter?.updateItems(queue)
- if (restoreScrollPosition) recyclerView.restoreScrollPosition(TAG)
- refreshInfoBar()
- }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+// disposable = Observable.fromCallable { DBReader.getQueue().toMutableList() }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ items: MutableList ->
+// queue = items
+// progressBar.visibility = View.GONE
+// recyclerAdapter?.setDummyViews(0)
+// recyclerAdapter?.updateItems(queue)
+// if (restoreScrollPosition) recyclerView.restoreScrollPosition(TAG)
+// refreshInfoBar()
+// }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+
+ scope.launch {
+ try {
+ queue = withContext(Dispatchers.IO) { DBReader.getQueue().toMutableList() }
+ withContext(Dispatchers.Main) {
+ progressBar.visibility = View.GONE
+ recyclerAdapter?.setDummyViews(0)
+ recyclerAdapter?.updateItems(queue)
+ if (restoreScrollPosition) recyclerView.restoreScrollPosition(TAG)
+ refreshInfoBar()
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
+
}
override fun onStartSelectMode() {
@@ -562,7 +580,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
val from = viewHolder.bindingAdapterPosition
val to = target.bindingAdapterPosition
- Log.d(TAG, "move($from, $to) in memory")
+ Logd(TAG, "move($from, $to) in memory")
if (from >= queue.size || to >= queue.size || from < 0 || to < 0) return false
queue.add(to, queue.removeAt(from))
@@ -571,7 +589,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
}
@UnstableApi override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
- disposable?.dispose()
+// disposable?.dispose()
//SwipeActions
super.onSwiped(viewHolder, direction)
@@ -592,7 +610,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
@UnstableApi private fun reallyMoved(from: Int, to: Int) {
// Write drag operation to database
- Log.d(TAG, "Write to database move($from, $to)")
+ Logd(TAG, "Write to database move($from, $to)")
DBWriter.moveQueueItem(from, to, true)
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/QuickFeedDiscoveryFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/QuickFeedDiscoveryFragment.kt
index 1fabf8ae..ad6a9931 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/QuickFeedDiscoveryFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/QuickFeedDiscoveryFragment.kt
@@ -8,6 +8,7 @@ import ac.mdiq.podcini.net.discovery.PodcastSearchResult
import ac.mdiq.podcini.storage.DBReader
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.adapter.FeedDiscoverAdapter
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.DiscoveryDefaultUpdateEvent
import android.content.Context
import android.content.SharedPreferences
@@ -21,10 +22,7 @@ import android.widget.*
import androidx.annotation.OptIn
import androidx.fragment.app.Fragment
import androidx.media3.common.util.UnstableApi
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -34,8 +32,9 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
private var _binding: QuickFeedDiscoveryBinding? = null
private val binding get() = _binding!!
- private var disposable: Disposable? = null
-
+// private var disposable: Disposable? = null
+ val scope = CoroutineScope(Dispatchers.Main)
+
private lateinit var adapter: FeedDiscoverAdapter
private lateinit var discoverGridLayout: GridView
private lateinit var errorTextView: TextView
@@ -47,7 +46,7 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
super.onCreateView(inflater, container, savedInstanceState)
_binding = QuickFeedDiscoveryBinding.inflate(inflater)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
val discoverMore = binding.discoverMore
discoverMore.setOnClickListener { (activity as MainActivity).loadChildFragment(DiscoveryFragment()) }
@@ -84,7 +83,8 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
super.onDestroy()
_binding = null
EventBus.getDefault().unregister(this)
- disposable?.dispose()
+ scope.cancel()
+// disposable?.dispose()
}
@Subscribe(threadMode = ThreadMode.MAIN)
@@ -124,13 +124,37 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
return
}
- disposable = Observable.fromCallable {
- loader.loadToplist(countryCode, NUM_SUGGESTIONS, DBReader.getFeedList())
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { podcasts: List ->
+// disposable = Observable.fromCallable {
+// loader.loadToplist(countryCode, NUM_SUGGESTIONS, DBReader.getFeedList())
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { podcasts: List ->
+// errorView.visibility = View.GONE
+// if (podcasts.isEmpty()) {
+// errorTextView.text = resources.getText(R.string.search_status_no_results)
+// errorView.visibility = View.VISIBLE
+// discoverGridLayout.visibility = View.INVISIBLE
+// } else {
+// discoverGridLayout.visibility = View.VISIBLE
+// adapter.updateData(podcasts)
+// }
+// }, { error: Throwable ->
+// Log.e(TAG, Log.getStackTraceString(error))
+// errorTextView.text = error.localizedMessage
+// errorView.visibility = View.VISIBLE
+// discoverGridLayout.visibility = View.INVISIBLE
+// errorRetry.visibility = View.VISIBLE
+// errorRetry.setOnClickListener { loadToplist() }
+// })
+
+ scope.launch {
+ try {
+ val podcasts = withContext(Dispatchers.IO) {
+ loader.loadToplist(countryCode, NUM_SUGGESTIONS, DBReader.getFeedList())
+ }
+ withContext(Dispatchers.Main) {
errorView.visibility = View.GONE
if (podcasts.isEmpty()) {
errorTextView.text = resources.getText(R.string.search_status_no_results)
@@ -140,14 +164,17 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
discoverGridLayout.visibility = View.VISIBLE
adapter.updateData(podcasts)
}
- }, { error: Throwable ->
- Log.e(TAG, Log.getStackTraceString(error))
- errorTextView.text = error.localizedMessage
- errorView.visibility = View.VISIBLE
- discoverGridLayout.visibility = View.INVISIBLE
- errorRetry.visibility = View.VISIBLE
- errorRetry.setOnClickListener { loadToplist() }
- })
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ errorTextView.text = e.localizedMessage
+ errorView.visibility = View.VISIBLE
+ discoverGridLayout.visibility = View.INVISIBLE
+ errorRetry.visibility = View.VISIBLE
+ errorRetry.setOnClickListener { loadToplist() }
+ }
+ }
+
}
@OptIn(UnstableApi::class) override fun onItemClick(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/SearchFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/SearchFragment.kt
index eb0f4ca5..b3f11149 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/SearchFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/SearchFragment.kt
@@ -5,24 +5,25 @@ import ac.mdiq.podcini.R
import ac.mdiq.podcini.databinding.MultiSelectSpeedDialBinding
import ac.mdiq.podcini.databinding.SearchFragmentBinding
import ac.mdiq.podcini.net.discovery.CombinedSearcher
-import ac.mdiq.podcini.util.event.playback.PlaybackPositionEvent
import ac.mdiq.podcini.storage.FeedSearcher
import ac.mdiq.podcini.storage.model.feed.Feed
import ac.mdiq.podcini.storage.model.feed.FeedItem
-import ac.mdiq.podcini.ui.activity.MainActivity
-import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter
-import ac.mdiq.podcini.ui.adapter.HorizontalFeedListAdapter
-import ac.mdiq.podcini.ui.adapter.SelectableAdapter
import ac.mdiq.podcini.ui.actions.EpisodeMultiSelectActionHandler
import ac.mdiq.podcini.ui.actions.menuhandler.FeedItemMenuHandler
import ac.mdiq.podcini.ui.actions.menuhandler.FeedMenuHandler
import ac.mdiq.podcini.ui.actions.menuhandler.MenuItemUtils
+import ac.mdiq.podcini.ui.activity.MainActivity
+import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter
+import ac.mdiq.podcini.ui.adapter.HorizontalFeedListAdapter
+import ac.mdiq.podcini.ui.adapter.SelectableAdapter
import ac.mdiq.podcini.ui.view.EmptyViewHandler
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
import ac.mdiq.podcini.util.FeedItemUtil
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.*
+import ac.mdiq.podcini.util.event.playback.PlaybackPositionEvent
import android.content.Context
import android.os.Bundle
import android.os.Handler
@@ -42,10 +43,7 @@ import com.google.android.material.chip.Chip
import com.google.android.material.snackbar.Snackbar
import com.leinardi.android.speeddial.SpeedDialActionItem
import com.leinardi.android.speeddial.SpeedDialView
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -70,7 +68,8 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
private var results: MutableList = mutableListOf()
private var currentPlaying: EpisodeItemViewHolder? = null
- private var disposable: Disposable? = null
+ val scope = CoroutineScope(Dispatchers.Main)
+// private var disposable: Disposable? = null
private var lastQueryChange: Long = 0
private var isOtherViewInFoucus = false
@@ -82,13 +81,14 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
override fun onStop() {
super.onStop()
- disposable?.dispose()
+ scope.cancel()
+// disposable?.dispose()
}
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = SearchFragmentBinding.inflate(inflater)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
setupToolbar(binding.toolbar)
speedDialBinding = MultiSelectSpeedDialBinding.bind(binding.root)
progressBar = binding.progressBar
@@ -243,7 +243,7 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: FeedItemEvent) {
- Log.d(TAG, "onEventMainThread() called with: event = [$event]")
+ Logd(TAG, "onEventMainThread() called with: event = [$event]")
var i = 0
val size: Int = event.items.size
@@ -272,7 +272,7 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
if (currentPlaying != null && currentPlaying!!.isCurrentlyPlayingItem)
currentPlaying!!.notifyPlaybackPositionUpdated(event)
else {
- Log.d(TAG, "onEventMainThread() search list")
+ Logd(TAG, "onEventMainThread() search list")
for (i in 0 until adapter.itemCount) {
val holder: EpisodeItemViewHolder? = recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
if (holder != null && holder.isCurrentlyPlayingItem) {
@@ -296,27 +296,50 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
}
@UnstableApi private fun search() {
- disposable?.dispose()
+// disposable?.dispose()
adapterFeeds.setEndButton(R.string.search_online) { this.searchOnline() }
chip.visibility = if ((requireArguments().getLong(ARG_FEED, 0) == 0L)) View.GONE else View.VISIBLE
- disposable = Observable.fromCallable { this.performSearch() }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ results: Pair?, List?> ->
- progressBar.visibility = View.GONE
- if (results.first != null) {
- this.results = results.first!!.toMutableList()
- adapter.updateItems(results.first!!)
+// disposable = Observable.fromCallable { this.performSearch() }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ results: Pair?, List?> ->
+// progressBar.visibility = View.GONE
+// if (results.first != null) {
+// this.results = results.first!!.toMutableList()
+// adapter.updateItems(results.first!!)
+// }
+// if (requireArguments().getLong(ARG_FEED, 0) == 0L) {
+// if (results.second != null) adapterFeeds.updateData(results.second!!.filterNotNull())
+// } else adapterFeeds.updateData(emptyList())
+//
+// if (searchView.query.toString().isEmpty()) emptyViewHandler.setMessage(R.string.type_to_search)
+// else emptyViewHandler.setMessage(getString(R.string.no_results_for_query) + searchView.query)
+//
+// }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+
+ scope.launch {
+ try {
+ val results = withContext(Dispatchers.IO) {
+ performSearch()
}
- if (requireArguments().getLong(ARG_FEED, 0) == 0L) {
- if (results.second != null) adapterFeeds.updateData(results.second!!.filterNotNull())
- } else adapterFeeds.updateData(emptyList())
+ withContext(Dispatchers.Main) {
+ progressBar.visibility = View.GONE
+ if (results.first != null) {
+ this@SearchFragment.results = results.first!!.toMutableList()
+ adapter.updateItems(results.first!!)
+ }
+ if (requireArguments().getLong(ARG_FEED, 0) == 0L) {
+ if (results.second != null) adapterFeeds.updateData(results.second!!.filterNotNull())
+ } else adapterFeeds.updateData(emptyList())
- if (searchView.query.toString().isEmpty()) emptyViewHandler.setMessage(R.string.type_to_search)
- else emptyViewHandler.setMessage(getString(R.string.no_results_for_query) + searchView.query)
-
- }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
+ if (searchView.query.toString().isEmpty()) emptyViewHandler.setMessage(R.string.type_to_search)
+ else emptyViewHandler.setMessage(getString(R.string.no_results_for_query) + searchView.query)
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
}
@UnstableApi private fun performSearch(): Pair?, List?> {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/SubscriptionFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/SubscriptionFragment.kt
index 189b0b58..87022476 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/SubscriptionFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/SubscriptionFragment.kt
@@ -8,16 +8,17 @@ import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.storage.DBReader
import ac.mdiq.podcini.storage.NavDrawerData
import ac.mdiq.podcini.storage.model.feed.Feed
+import ac.mdiq.podcini.ui.actions.FeedMultiSelectActionHandler
+import ac.mdiq.podcini.ui.actions.menuhandler.FeedMenuHandler
+import ac.mdiq.podcini.ui.actions.menuhandler.MenuItemUtils
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.adapter.SelectableAdapter
import ac.mdiq.podcini.ui.adapter.SubscriptionsAdapter
import ac.mdiq.podcini.ui.dialog.FeedSortDialog
import ac.mdiq.podcini.ui.dialog.SubscriptionsFilterDialog
-import ac.mdiq.podcini.ui.actions.FeedMultiSelectActionHandler
-import ac.mdiq.podcini.ui.actions.menuhandler.FeedMenuHandler
-import ac.mdiq.podcini.ui.actions.menuhandler.MenuItemUtils
import ac.mdiq.podcini.ui.view.EmptyViewHandler
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.FeedListUpdateEvent
import ac.mdiq.podcini.util.event.FeedTagsChangedEvent
import ac.mdiq.podcini.util.event.FeedUpdateRunningEvent
@@ -39,10 +40,7 @@ import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.leinardi.android.speeddial.SpeedDialActionItem
import com.leinardi.android.speeddial.SpeedDialView
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@@ -72,7 +70,8 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select
private var displayedFolder: String = ""
private var displayUpArrow = false
- private var disposable: Disposable? = null
+ val scope = CoroutineScope(Dispatchers.Main)
+// private var disposable: Disposable? = null
private var feedList: List = mutableListOf()
private var feedListFiltered: List = mutableListOf()
@@ -86,7 +85,7 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentSubscriptionsBinding.inflate(inflater)
- Log.d(TAG, "fragment onCreateView")
+ Logd(TAG, "fragment onCreateView")
toolbar = binding.toolbar
toolbar.setOnMenuItemClickListener(this)
toolbar.setOnLongClickListener {
@@ -201,7 +200,8 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select
super.onDestroyView()
_binding = null
EventBus.getDefault().unregister(this)
- disposable?.dispose()
+ scope.cancel()
+// disposable?.dispose()
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -272,17 +272,37 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select
}
private fun loadSubscriptions() {
- disposable?.dispose()
+// disposable?.dispose()
emptyView.hide()
- disposable = Observable.fromCallable {
- val data: NavDrawerData = DBReader.getNavDrawerData(UserPreferences.subscriptionsFilter)
- val items: List = data.items
- items
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(
- { result: List ->
+// disposable = Observable.fromCallable {
+// val data: NavDrawerData = DBReader.getNavDrawerData(UserPreferences.subscriptionsFilter)
+// val items: List = data.items
+// items
+// }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(
+// { result: List ->
+// // We have fewer items. This can result in items being selected that are no longer visible.
+// if ( feedListFiltered.size > result.size) subscriptionAdapter.endSelectMode()
+// feedList = result
+// filterOnTag()
+// progressBar.visibility = View.GONE
+// subscriptionAdapter.setItems(feedListFiltered)
+// feedCount.text = feedListFiltered.size.toString() + " / " + feedList.size.toString()
+// emptyView.updateVisibility()
+// }, { error: Throwable? ->
+// Log.e(TAG, Log.getStackTraceString(error))
+// })
+
+ scope.launch {
+ try {
+ val result = withContext(Dispatchers.IO) {
+ val data: NavDrawerData = DBReader.getNavDrawerData(UserPreferences.subscriptionsFilter)
+ val items: List = data.items
+ items
+ }
+ withContext(Dispatchers.Main) {
// We have fewer items. This can result in items being selected that are no longer visible.
if ( feedListFiltered.size > result.size) subscriptionAdapter.endSelectMode()
feedList = result
@@ -291,9 +311,11 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select
subscriptionAdapter.setItems(feedListFiltered)
feedCount.text = feedListFiltered.size.toString() + " / " + feedList.size.toString()
emptyView.updateVisibility()
- }, { error: Throwable? ->
- Log.e(TAG, Log.getStackTraceString(error))
- })
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
if (UserPreferences.subscriptionsFilter.isEnabled) feedsFilteredMsg.visibility = View.VISIBLE
else feedsFilteredMsg.visibility = View.GONE
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/VideoEpisodeFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/VideoEpisodeFragment.kt
index e4034235..6cff0fbc 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/VideoEpisodeFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/VideoEpisodeFragment.kt
@@ -23,6 +23,7 @@ import ac.mdiq.podcini.ui.utils.PictureInPictureUtil
import ac.mdiq.podcini.ui.utils.ShownotesCleaner
import ac.mdiq.podcini.ui.view.ShownotesWebView
import ac.mdiq.podcini.util.Converter.getDurationStringLong
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.TimeSpeedConverter
import ac.mdiq.podcini.util.event.playback.BufferUpdateEvent
import ac.mdiq.podcini.util.event.playback.PlaybackPositionEvent
@@ -41,13 +42,11 @@ import androidx.core.app.ActivityCompat.invalidateOptionsMenu
import androidx.fragment.app.Fragment
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.media3.common.util.UnstableApi
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
+import java.lang.Runnable
@UnstableApi
class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
@@ -63,7 +62,9 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
private var lastScreenTap: Long = 0
private val videoControlsHider = Handler(Looper.getMainLooper())
private var showTimeLeft = false
- private var disposable: Disposable? = null
+
+ val scope = CoroutineScope(Dispatchers.Main)
+// private var disposable: Disposable? = null
private var prog = 0f
private var itemsLoaded = false
@@ -92,7 +93,7 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
@OptIn(UnstableApi::class) private fun newPlaybackController(): PlaybackController {
return object : PlaybackController(requireActivity()) {
override fun updatePlayButtonShowsPlay(showPlay: Boolean) {
- Log.d(TAG, "updatePlayButtonShowsPlay called")
+ Logd(TAG, "updatePlayButtonShowsPlay called")
binding.playButton.setIsShowPlay(showPlay)
if (showPlay) {
(activity as AppCompatActivity).window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
@@ -100,7 +101,7 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
(activity as AppCompatActivity).window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
setupVideoAspectRatio()
if (videoSurfaceCreated && controller != null) {
- Log.d(TAG, "Videosurface already created, setting videosurface now")
+ Logd(TAG, "Videosurface already created, setting videosurface now")
setVideoSurface(binding.videoView.holder)
}
}
@@ -148,7 +149,8 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
_binding = null
controller?.release()
controller = null // prevent leak
- disposable?.dispose()
+ scope.cancel()
+// disposable?.dispose()
}
@Subscribe(threadMode = ThreadMode.MAIN)
@@ -164,10 +166,10 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
private fun setupVideoAspectRatio() {
if (videoSurfaceCreated && controller != null) {
if (videoSize != null && videoSize!!.first > 0 && videoSize!!.second > 0) {
- Log.d(TAG, "Width,height of video: " + videoSize!!.first + ", " + videoSize!!.second)
+ Logd(TAG, "Width,height of video: ${videoSize!!.first}, ${videoSize!!.second}")
val videoWidth = resources.displayMetrics.widthPixels
val videoHeight = (videoWidth.toFloat() / videoSize!!.first * videoSize!!.second).toInt()
- Log.d(TAG, "Width,height of video: " + videoWidth + ", " + videoHeight)
+ Logd(TAG, "Width,height of video: $videoWidth, $videoHeight")
binding.videoView.setVideoSize(videoWidth, videoHeight)
// binding.videoView.setVideoSize(videoSize.first, videoSize.second)
// binding.videoView.setVideoSize(-1, -1)
@@ -175,18 +177,18 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
Log.e(TAG, "Could not determine video size")
val videoWidth = resources.displayMetrics.widthPixels
val videoHeight = (videoWidth.toFloat() / 16 * 9).toInt()
- Log.d(TAG, "Width,height of video: " + videoWidth + ", " + videoHeight)
+ Logd(TAG, "Width,height of video: $videoWidth, $videoHeight")
binding.videoView.setVideoSize(videoWidth, videoHeight)
}
}
}
@OptIn(UnstableApi::class) private fun loadMediaInfo() {
- Log.d(TAG, "loadMediaInfo called")
+ Logd(TAG, "loadMediaInfo called")
if (controller?.getMedia() == null) return
if (MediaPlayerBase.status == PlayerStatus.PLAYING && !controller!!.isPlayingVideoLocally) {
- Log.d(TAG, "Closing, no longer video")
+ Logd(TAG, "Closing, no longer video")
destroyingDueToReload = true
activity?.finish()
MainActivityStarter(requireContext()).withOpenPlayer().start()
@@ -203,27 +205,50 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
}
@UnstableApi private fun load() {
- disposable?.dispose()
- Log.d(TAG, "load() called")
+// disposable?.dispose()
+ Logd(TAG, "load() called")
- disposable = Observable.fromCallable { this.loadInBackground() }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ result: FeedItem? ->
- item = result
- Log.d(TAG, "load() item ${item?.id}")
- if (item != null) {
- val isFav = item!!.isTagged(FeedItem.TAG_FAVORITE)
- if (isFavorite != isFav) {
- isFavorite = isFav
- invalidateOptionsMenu(requireActivity())
- }
+// disposable = Observable.fromCallable { this.loadInBackground() }
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe({ result: FeedItem? ->
+// item = result
+// Logd(TAG, "load() item ${item?.id}")
+// if (item != null) {
+// val isFav = item!!.isTagged(FeedItem.TAG_FAVORITE)
+// if (isFavorite != isFav) {
+// isFavorite = isFav
+// invalidateOptionsMenu(requireActivity())
+// }
+// }
+// onFragmentLoaded()
+// itemsLoaded = true
+// }, { error: Throwable? ->
+// Log.e(TAG, Log.getStackTraceString(error))
+// })
+
+ scope.launch {
+ try {
+ item = withContext(Dispatchers.IO) {
+ loadInBackground()
}
- onFragmentLoaded()
- itemsLoaded = true
- }, { error: Throwable? ->
- Log.e(TAG, Log.getStackTraceString(error))
- })
+ withContext(Dispatchers.Main) {
+ Logd(TAG, "load() item ${item?.id}")
+ if (item != null) {
+ val isFav = item!!.isTagged(FeedItem.TAG_FAVORITE)
+ if (isFavorite != isFav) {
+ isFavorite = isFav
+ invalidateOptionsMenu(requireActivity())
+ }
+ }
+ onFragmentLoaded()
+ itemsLoaded = true
+ }
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
+
}
private fun loadInBackground(): FeedItem? {
@@ -244,7 +269,7 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
@UnstableApi
private fun setupView() {
showTimeLeft = shouldShowRemainingTime()
- Log.d(TAG, "setupView showTimeLeft: $showTimeLeft")
+ Logd(TAG, "setupView showTimeLeft: $showTimeLeft")
binding.durationLabel.setOnClickListener {
showTimeLeft = !showTimeLeft
@@ -262,7 +287,7 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
binding.durationLabel.text = length
setShowRemainTimeSetting(showTimeLeft)
- Log.d("timeleft on click", if (showTimeLeft) "true" else "false")
+ Logd("timeleft on click", if (showTimeLeft) "true" else "false")
}
binding.sbPosition.setOnSeekBarChangeListener(this)
@@ -394,14 +419,14 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
@UnstableApi
override fun surfaceCreated(holder: SurfaceHolder) {
- Log.d(TAG, "Videoview holder created")
+ Logd(TAG, "Videoview holder created")
videoSurfaceCreated = true
if (MediaPlayerBase.status == PlayerStatus.PLAYING) setVideoSurface(holder)
setupVideoAspectRatio()
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
- Log.d(TAG, "Videosurface was destroyed")
+ Logd(TAG, "Videosurface was destroyed")
videoSurfaceCreated = false
if (controller != null && !destroyingDueToReload && !(activity as VideoplayerActivity).switchToAudioOnly)
notifyVideoSurfaceAbandoned()
@@ -441,7 +466,7 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
private val hideVideoControls = Runnable {
if (videoControlsShowing) {
- Log.d(TAG, "Hiding video controls")
+ Logd(TAG, "Hiding video controls")
hideVideoControls(true)
if (videoMode == VideoplayerActivity.VideoMode.FULL_SCREEN_VIEW) (activity as? AppCompatActivity)?.supportActionBar?.hide()
videoControlsShowing = false
@@ -504,7 +529,7 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
}
private fun updateProgressbarPosition(position: Int, duration: Int) {
- Log.d(TAG, "updateProgressbarPosition($position, $duration)")
+ Logd(TAG, "updateProgressbarPosition ($position, $duration)")
val progress = (position.toFloat()) / duration
binding.sbPosition.progress = (progress * binding.sbPosition.max).toInt()
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/view/viewholder/EpisodeItemViewHolder.kt b/app/src/main/java/ac/mdiq/podcini/ui/view/viewholder/EpisodeItemViewHolder.kt
index 7315b1fb..136aa8b3 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/view/viewholder/EpisodeItemViewHolder.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/view/viewholder/EpisodeItemViewHolder.kt
@@ -138,7 +138,7 @@ class EpisodeItemViewHolder(private val activity: MainActivity, parent: ViewGrou
if (coverHolder.visibility == View.VISIBLE) {
val imgLoc = ImageResourceUtils.getEpisodeListImageLocation(item)
- Logd(TAG, "imgLoc $imgLoc ${item.feed?.imageUrl} ${item.title}")
+// Logd(TAG, "imgLoc $imgLoc ${item.feed?.imageUrl} ${item.title}")
if (!imgLoc.isNullOrBlank() && !imgLoc.contains(PREFIX_GENERATIVE_COVER)) CoverLoader(activity)
.withUri(imgLoc)
.withFallbackUri(item.feed?.imageUrl)
diff --git a/app/src/main/java/ac/mdiq/podcini/util/ChapterUtils.kt b/app/src/main/java/ac/mdiq/podcini/util/ChapterUtils.kt
index 8fa46fa8..ae7eff7b 100644
--- a/app/src/main/java/ac/mdiq/podcini/util/ChapterUtils.kt
+++ b/app/src/main/java/ac/mdiq/podcini/util/ChapterUtils.kt
@@ -61,7 +61,7 @@ object ChapterUtils {
val chaptersFromMediaFile = loadChaptersFromMediaFile(playable, context)
val chaptersMergePhase1 = merge(chaptersFromDatabase, chaptersFromMediaFile)
val chapters = merge(chaptersMergePhase1, chaptersFromPodcastIndex)
- Log.d(TAG, "loadChapters chapters size: ${chapters?.size?:0} ${playable.getEpisodeTitle()}")
+ Logd(TAG, "loadChapters chapters size: ${chapters?.size?:0} ${playable.getEpisodeTitle()}")
if (chapters == null) playable.setChapters(listOf()) // Do not try loading again. There are no chapters.
else playable.setChapters(chapters)
diff --git a/app/src/main/java/ac/mdiq/podcini/util/FeedItemPermutors.kt b/app/src/main/java/ac/mdiq/podcini/util/FeedItemPermutors.kt
index 09fceed4..8c951c70 100644
--- a/app/src/main/java/ac/mdiq/podcini/util/FeedItemPermutors.kt
+++ b/app/src/main/java/ac/mdiq/podcini/util/FeedItemPermutors.kt
@@ -97,7 +97,7 @@ object FeedItemPermutors {
}
private fun feedTitle(item: FeedItem?): String {
- Log.d("permutors", "feedTitle ${item?.feed?.title}")
+ Logd("permutors", "feedTitle ${item?.feed?.title}")
return if (item?.feed?.title != null) item.feed!!.title!!.lowercase(Locale.getDefault()) else ""
}
diff --git a/app/src/main/java/ac/mdiq/podcini/util/URIUtil.kt b/app/src/main/java/ac/mdiq/podcini/util/URIUtil.kt
index 48044b97..f2e7e04f 100644
--- a/app/src/main/java/ac/mdiq/podcini/util/URIUtil.kt
+++ b/app/src/main/java/ac/mdiq/podcini/util/URIUtil.kt
@@ -24,10 +24,10 @@ object URIUtil {
val url = URL(source)
return URI(url.protocol, url.userInfo, url.host, url.port, url.path, url.query, url.ref)
} catch (e: MalformedURLException) {
- Log.d(TAG, "source: $source")
+ Logd(TAG, "source: $source")
throw IllegalArgumentException(e)
} catch (e: URISyntaxException) {
- Log.d(TAG, "source: $source")
+ Logd(TAG, "source: $source")
throw IllegalArgumentException(e)
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/util/error/RxJavaErrorHandlerSetup.kt b/app/src/main/java/ac/mdiq/podcini/util/error/RxJavaErrorHandlerSetup.kt
index 58fabefa..165dca98 100644
--- a/app/src/main/java/ac/mdiq/podcini/util/error/RxJavaErrorHandlerSetup.kt
+++ b/app/src/main/java/ac/mdiq/podcini/util/error/RxJavaErrorHandlerSetup.kt
@@ -1,6 +1,7 @@
package ac.mdiq.podcini.util.error
import ac.mdiq.podcini.BuildConfig
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.error.CrashReportWriter.Companion.write
import android.util.Log
import io.reactivex.exceptions.UndeliverableException
@@ -13,7 +14,7 @@ object RxJavaErrorHandlerSetup {
RxJavaPlugins.setErrorHandler { exception: Throwable? ->
if (exception is UndeliverableException) {
// Probably just disposed because the fragment was left
- Log.d(TAG, "Ignored exception: " + Log.getStackTraceString(exception))
+ Logd(TAG, "Ignored exception: " + Log.getStackTraceString(exception))
return@setErrorHandler
}
// Usually, undeliverable exceptions are wrapped in an UndeliverableException.
diff --git a/app/src/main/res/layout/nav_list.xml b/app/src/main/res/layout/nav_list.xml
index 96e5371b..2c328b6f 100644
--- a/app/src/main/res/layout/nav_list.xml
+++ b/app/src/main/res/layout/nav_list.xml
@@ -73,11 +73,4 @@
android:scrollbarStyle="outsideOverlay"
tools:listitem="@layout/nav_listitem" />
-
-
diff --git a/app/src/main/res/menu/episodes.xml b/app/src/main/res/menu/episodes.xml
index 4c8e0dbb..23e166dc 100644
--- a/app/src/main/res/menu/episodes.xml
+++ b/app/src/main/res/menu/episodes.xml
@@ -9,19 +9,6 @@
custom:showAsAction="always"
android:title="@string/search_label"/>
-
-
-
-
+
+
+
+
diff --git a/app/src/play/java/ac/mdiq/podcini/playback/cast/CastPsmp.kt b/app/src/play/java/ac/mdiq/podcini/playback/cast/CastPsmp.kt
index 4a2f2ff5..d61e4c6c 100644
--- a/app/src/play/java/ac/mdiq/podcini/playback/cast/CastPsmp.kt
+++ b/app/src/play/java/ac/mdiq/podcini/playback/cast/CastPsmp.kt
@@ -7,6 +7,7 @@ import ac.mdiq.podcini.storage.model.feed.FeedMedia
import ac.mdiq.podcini.storage.model.playback.MediaType
import ac.mdiq.podcini.storage.model.playback.Playable
import ac.mdiq.podcini.storage.model.playback.RemoteMedia
+import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.PlayerErrorEvent
import ac.mdiq.podcini.util.event.playback.BufferUpdateEvent
import android.annotation.SuppressLint
@@ -107,9 +108,9 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
private fun onRemoteMediaPlayerStatusUpdated() {
val mediaStatus = remoteMediaClient!!.mediaStatus
if (mediaStatus == null) {
- Log.d(TAG, "Received null MediaStatus")
+ Logd(TAG, "Received null MediaStatus")
return
- } else Log.d(TAG, "Received remote status/media update. New state=" + mediaStatus.playerState)
+ } else Logd(TAG, "Received remote status/media update. New state=" + mediaStatus.playerState)
var state = mediaStatus.playerState
val oldState = remoteState
@@ -117,7 +118,7 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
val mediaChanged = !CastUtils.matches(remoteMedia, media)
var stateChanged = state != oldState
if (!mediaChanged && !stateChanged) {
- Log.d(TAG, "Both media and state haven't changed, so nothing to do")
+ Logd(TAG, "Both media and state haven't changed, so nothing to do")
return
}
val currentMedia = if (mediaChanged) localVersion(remoteMedia) else media
@@ -220,7 +221,7 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
}
override fun playMediaObject(playable: Playable, stream: Boolean, startWhenPrepared: Boolean, prepareImmediately: Boolean) {
- Log.d(TAG, "playMediaObject() called")
+ Logd(TAG, "playMediaObject() called")
playMediaObject(playable, false, stream, startWhenPrepared, prepareImmediately)
}
@@ -233,7 +234,7 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
*/
private fun playMediaObject(playable: Playable, forceReset: Boolean, stream: Boolean, startWhenPrepared: Boolean, prepareImmediately: Boolean) {
if (!CastUtils.isCastable(playable, castContext.sessionManager.currentCastSession)) {
- Log.d(TAG, "media provided is not compatible with cast device")
+ Logd(TAG, "media provided is not compatible with cast device")
EventBus.getDefault().post(PlayerErrorEvent("Media not compatible with cast device"))
var nextPlayable: Playable? = playable
do {
@@ -248,7 +249,7 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
if (media != null) {
if (!forceReset && media!!.getIdentifier() == playable.getIdentifier() && status == PlayerStatus.PLAYING) {
// episode is already playing -> ignore method call
- Log.d(TAG, "Method call to playMediaObject was ignored: media file already playing.")
+ Logd(TAG, "Method call to playMediaObject was ignored: media file already playing.")
return
} else {
// set temporarily to pause in order to update list with current position
@@ -287,7 +288,7 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
override fun prepare() {
if (status == PlayerStatus.INITIALIZED) {
- Log.d(TAG, "Preparing media player")
+ Logd(TAG, "Preparing media player")
setPlayerStatus(PlayerStatus.PREPARING, media)
var position = media!!.getPosition()
if (position > 0) position = calculatePositionWithRewind(position, media!!.getLastPlayedTime())
@@ -300,9 +301,9 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
}
override fun reinit() {
- Log.d(TAG, "reinit() called")
+ Logd(TAG, "reinit() called")
if (media != null) playMediaObject(media!!, true, stream = false, startWhenPrepared = startWhenPrepared.get(), prepareImmediately = false)
- else Log.d(TAG, "Call to reinit was ignored: media was null")
+ else Logd(TAG, "Call to reinit was ignored: media was null")
}
override fun seekTo(t: Int) {
@@ -347,7 +348,7 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
}
override fun setVolume(volumeLeft: Float, volumeRight: Float) {
- Log.d(TAG, "Setting the Stream volume on Remote Media Player")
+ Logd(TAG, "Setting the Stream volume on Remote Media Player")
remoteMediaClient!!.setStreamVolume(volumeLeft.toDouble())
}
@@ -398,7 +399,7 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
}
override fun endPlayback(hasEnded: Boolean, wasSkipped: Boolean, shouldContinue: Boolean, toStoppedState: Boolean) {
- Log.d(TAG, "endPlayback() called")
+ Logd(TAG, "endPlayback() called")
val isPlaying = status == PlayerStatus.PLAYING
if (status != PlayerStatus.INDETERMINATE) setPlayerStatus(PlayerStatus.INDETERMINATE, media)
@@ -414,9 +415,9 @@ class CastPsmp(context: Context, callback: MediaPlayerCallback) : MediaPlayerBas
val playNextEpisode = isPlaying && nextMedia != null
when {
- playNextEpisode -> Log.d(TAG, "Playback of next episode will start immediately.")
- nextMedia == null -> Log.d(TAG, "No more episodes available to play")
- else -> Log.d(TAG, "Loading next episode, but not playing automatically.")
+ playNextEpisode -> Logd(TAG, "Playback of next episode will start immediately.")
+ nextMedia == null -> Logd(TAG, "No more episodes available to play")
+ else -> Logd(TAG, "Loading next episode, but not playing automatically.")
}
if (nextMedia != null) {
diff --git a/app/src/test/java/ac/mdiq/podcini/storage/DbCleanupTests.kt b/app/src/test/java/ac/mdiq/podcini/storage/DbCleanupTests.kt
index 2725c133..657edd46 100644
--- a/app/src/test/java/ac/mdiq/podcini/storage/DbCleanupTests.kt
+++ b/app/src/test/java/ac/mdiq/podcini/storage/DbCleanupTests.kt
@@ -61,8 +61,7 @@ open class DbCleanupTests {
adapter.open()
adapter.close()
- val prefEdit = PreferenceManager
- .getDefaultSharedPreferences(context.applicationContext).edit()
+ val prefEdit = PreferenceManager.getDefaultSharedPreferences(context.applicationContext).edit()
prefEdit.putString(UserPreferences.PREF_EPISODE_CACHE_SIZE, EPISODE_CACHE_SIZE.toString())
prefEdit.putString(UserPreferences.PREF_EPISODE_CLEANUP, cleanupAlgorithm.toString())
prefEdit.putBoolean(UserPreferences.PREF_ENABLE_AUTODL, true)
@@ -113,10 +112,7 @@ open class DbCleanupTests {
}
@Throws(IOException::class)
- fun populateItems(numItems: Int, feed: Feed, items: MutableList,
- files: MutableList, itemState: Int, addToQueue: Boolean,
- addToFavorites: Boolean
- ) {
+ fun populateItems(numItems: Int, feed: Feed, items: MutableList, files: MutableList, itemState: Int, addToQueue: Boolean, addToFavorites: Boolean) {
for (i in 0 until numItems) {
val itemDate = Date((numItems - i).toLong())
var playbackCompletionDate: Date? = null
@@ -136,12 +132,8 @@ open class DbCleanupTests {
val adapter = getInstance()
adapter.open()
adapter.setCompleteFeed(feed)
- if (addToQueue) {
- adapter.setQueue(items)
- }
- if (addToFavorites) {
- adapter.setFavorites(items)
- }
+ if (addToQueue) adapter.setQueue(items)
+ if (addToFavorites) adapter.setFavorites(items)
adapter.close()
Assert.assertTrue(feed.id != 0L)
diff --git a/app/src/test/java/ac/mdiq/podcini/storage/DbWriterTest.kt b/app/src/test/java/ac/mdiq/podcini/storage/DbWriterTest.kt
index 0b5fecd5..2993313b 100644
--- a/app/src/test/java/ac/mdiq/podcini/storage/DbWriterTest.kt
+++ b/app/src/test/java/ac/mdiq/podcini/storage/DbWriterTest.kt
@@ -36,6 +36,7 @@ import ac.mdiq.podcini.storage.database.PodDBAdapter.Companion.getInstance
import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.preferences.UserPreferences.enqueueLocation
import ac.mdiq.podcini.preferences.UserPreferences.shouldDeleteRemoveFromQueue
+import ac.mdiq.podcini.util.Logd
import org.awaitility.Awaitility
import org.junit.After
import org.junit.Assert
@@ -465,11 +466,8 @@ class DbWriterTest {
for (i in 0 until feed.items.size) {
val feedItem: FeedItem = feed.items[i]
val c = adapter.getFeedItemCursor(feedItem.id.toString())
- if (i < 2) {
- Assert.assertEquals(0, c.count.toLong())
- } else {
- Assert.assertEquals(1, c.count.toLong())
- }
+ if (i < 2) Assert.assertEquals(0, c.count.toLong())
+ else Assert.assertEquals(1, c.count.toLong())
c.close()
}
adapter.close()
@@ -699,22 +697,16 @@ class DbWriterTest {
// Use array rather than List to make codes more succinct
val itemIds = toItemIds(feed.items).toTypedArray()
- removeQueueItem(context, false,
- itemIds[1], itemIds[3])[TIMEOUT, TimeUnit.SECONDS]
- assertQueueByItemIds("Average case - 2 items removed successfully",
- itemIds[0], itemIds[2])
+ removeQueueItem(context, false, itemIds[1], itemIds[3])[TIMEOUT, TimeUnit.SECONDS]
+ assertQueueByItemIds("Average case - 2 items removed successfully", itemIds[0], itemIds[2])
removeQueueItem(context, false)[TIMEOUT, TimeUnit.SECONDS]
- assertQueueByItemIds("Boundary case - no items supplied. queue should see no change",
- itemIds[0], itemIds[2])
+ assertQueueByItemIds("Boundary case - no items supplied. queue should see no change", itemIds[0], itemIds[2])
- removeQueueItem(context, false,
- itemIds[0], itemIds[4], -1L)[TIMEOUT, TimeUnit.SECONDS]
- assertQueueByItemIds("Boundary case - items not in queue ignored",
- itemIds[2])
+ removeQueueItem(context, false, itemIds[0], itemIds[4], -1L)[TIMEOUT, TimeUnit.SECONDS]
+ assertQueueByItemIds("Boundary case - items not in queue ignored", itemIds[2])
- removeQueueItem(context, false,
- itemIds[2], -1L)[TIMEOUT, TimeUnit.SECONDS]
+ removeQueueItem(context, false, itemIds[2], -1L)[TIMEOUT, TimeUnit.SECONDS]
assertQueueByItemIds("Boundary case - invalid itemIds ignored") // the queue is empty
}
@@ -741,10 +733,9 @@ class DbWriterTest {
}
for (from in 0 until numItems) {
for (to in 0 until numItems) {
- if (from == to) {
- continue
- }
- Log.d(TAG, String.format(Locale.US, "testMoveQueueItem: From=%d, To=%d", from, to))
+ if (from == to) continue
+
+ Logd(TAG, String.format(Locale.US, "testMoveQueueItem: From=%d, To=%d", from, to))
val fromID: Long = feed.items[from].id
adapter = getInstance()
@@ -775,8 +766,7 @@ class DbWriterTest {
val feed = Feed("url", null, "title")
feed.items = mutableListOf()
for (i in 0 until numItems) {
- val item = FeedItem(0, "title $i", "id $i", "link $i",
- Date(), FeedItem.NEW, feed)
+ val item = FeedItem(0, "title $i", "id $i", "link $i", Date(), FeedItem.NEW, feed)
item.setMedia(FeedMedia(item, "", 0, ""))
feed.items.add(item)
}
@@ -807,8 +797,7 @@ class DbWriterTest {
val feed = Feed("url", null, "title")
feed.items = mutableListOf()
for (i in 0 until numItems) {
- val item = FeedItem(0, "title $i", "id $i", "link $i",
- Date(), FeedItem.PLAYED, feed)
+ val item = FeedItem(0, "title $i", "id $i", "link $i", Date(), FeedItem.PLAYED, feed)
item.setMedia(FeedMedia(item, "", 0, ""))
feed.items.add(item)
}
diff --git a/build.gradle b/build.gradle
index ab522b35..ebfc59ae 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ buildscript {
mavenCentral()
gradlePluginPortal()
}
- ext.kotlin_version = '1.9.23'
+ ext.kotlin_version = '1.9.24'
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.android.tools.build:gradle:8.2.2'
diff --git a/changelog.md b/changelog.md
index 138206a8..10e49142 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,15 @@
+## 5.2.0
+
+* suppressed log.d messages in release app (unbelievable incomplete suppression last time)
+* made loadAdditionalFeedItemListData of DBReader a bit more efficient
+* reduced unnecessary loading of media info in AudioPlayer
+* tuned playback controller for efficiency
+* improved player details view and corrected issue of showing wrong info
+* tuned episode info view for efficiency
+* tuned feed info view for start efficiency
+* tuned and slimmed down the drawer: number of Subscriptions now shows the number of subscriptions
+* replaced many RxJava stuff with Kotlin Coroutines
+
## 5.1.0
* properly destroys WebView objects
diff --git a/fastlane/metadata/android/en-US/changelogs/3020143.txt b/fastlane/metadata/android/en-US/changelogs/3020143.txt
new file mode 100644
index 00000000..259bf15d
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/3020143.txt
@@ -0,0 +1,12 @@
+
+Version 5.2.0 brings several changes:
+
+* suppressed log.d messages in release app (unbelievable incomplete suppression last time)
+* made loadAdditionalFeedItemListData of DBReader a bit more efficient
+* reduced unnecessary loading of media info in AudioPlayer
+* tuned playback controller for efficiency
+* improved player details view and corrected issue of showing wrong info
+* tuned episode info view for efficiency
+* tuned feed info view for start efficiency
+* tuned and slimmed down the drawer: number of Subscriptions now shows the number of subscriptions
+* replaced many RxJava stuff with Kotlin Coroutines