4.4.1 commit
This commit is contained in:
parent
c3f70fd1d4
commit
e08d508c41
|
@ -149,8 +149,8 @@ android {
|
|||
// Version code schema (not used):
|
||||
// "1.2.3-beta4" -> 1020304
|
||||
// "1.2.3" -> 1020395
|
||||
versionCode 3020116
|
||||
versionName "4.4.0"
|
||||
versionCode 3020117
|
||||
versionName "4.4.1"
|
||||
|
||||
def commit = ""
|
||||
try {
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
android:name="android.hardware.touchscreen"
|
||||
android:required="false"/>
|
||||
|
||||
<!-- this is now taken out from application -->
|
||||
<!-- android:usesCleartextTraffic="true"-->
|
||||
|
||||
<application
|
||||
android:name="ac.mdiq.podcini.PodciniApp"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
|
@ -38,7 +41,6 @@
|
|||
android:backupAgent=".storage.backup.OpmlBackupAgent"
|
||||
android:restoreAnyVersion="true"
|
||||
android:theme="@style/Theme.Podcini.Splash"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:supportsRtl="true"
|
||||
android:logo="@mipmap/ic_launcher"
|
||||
android:resizeableActivity="true"
|
||||
|
|
|
@ -3,17 +3,16 @@ package ac.mdiq.podcini.net.discovery
|
|||
import io.reactivex.Single
|
||||
|
||||
object PodcastSearcherRegistry {
|
||||
@Suppress("UNNECESSARY_SAFE_CALL")
|
||||
@get:Synchronized
|
||||
var searchProviders: MutableList<SearcherInfo> = mutableListOf()
|
||||
get() {
|
||||
if (field.isEmpty()) {
|
||||
field = ArrayList()
|
||||
field?.add(SearcherInfo(CombinedSearcher(), 1.0f))
|
||||
field?.add(SearcherInfo(GpodnetPodcastSearcher(), 0.0f))
|
||||
field?.add(SearcherInfo(FyydPodcastSearcher(), 1.0f))
|
||||
field?.add(SearcherInfo(ItunesPodcastSearcher(), 1.0f))
|
||||
field?.add(SearcherInfo(PodcastIndexPodcastSearcher(), 1.0f))
|
||||
field.add(SearcherInfo(CombinedSearcher(), 1.0f))
|
||||
field.add(SearcherInfo(GpodnetPodcastSearcher(), 0.0f))
|
||||
field.add(SearcherInfo(FyydPodcastSearcher(), 1.0f))
|
||||
field.add(SearcherInfo(ItunesPodcastSearcher(), 1.0f))
|
||||
field.add(SearcherInfo(PodcastIndexPodcastSearcher(), 1.0f))
|
||||
}
|
||||
return field
|
||||
}
|
||||
|
|
|
@ -67,9 +67,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
|
|||
|
||||
@Synchronized
|
||||
private fun initServiceRunning() {
|
||||
if (initialized) {
|
||||
return
|
||||
}
|
||||
if (initialized) return
|
||||
initialized = true
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
|
@ -171,7 +169,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
|
|||
|
||||
private val statusUpdate: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
// Log.d(TAG, "Received statusUpdate Intent.")
|
||||
Log.d(TAG, "Received statusUpdate Intent.")
|
||||
if (playbackService != null) {
|
||||
val info = playbackService!!.pSMPInfo
|
||||
status = info.playerStatus
|
||||
|
@ -271,7 +269,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
|
|||
PlaybackServiceStarter(activity, media!!)
|
||||
.callEvenIfRunning(true)
|
||||
.start()
|
||||
Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!")
|
||||
Log.w(TAG, "playbackservice was null, restarted!")
|
||||
// return
|
||||
}
|
||||
when (status) {
|
||||
|
|
|
@ -84,88 +84,101 @@ class HttpDownloader(request: DownloadRequest) : Downloader(request) {
|
|||
isGzip = TextUtils.equals(contentEncodingHeader.lowercase(Locale.getDefault()), "gzip")
|
||||
}
|
||||
|
||||
Log.d(TAG, "Response code is " + response.code)
|
||||
if (!response.isSuccessful && response.code == HttpURLConnection.HTTP_NOT_MODIFIED) {
|
||||
Log.d(TAG, "Feed '" + downloadRequest.source + "' not modified since last update, Download canceled")
|
||||
onCancelled()
|
||||
return
|
||||
} else if (!response.isSuccessful || response.body == null) {
|
||||
callOnFailByResponseCode(response)
|
||||
return
|
||||
} else if (downloadRequest.feedfileType == FeedMedia.FEEDFILETYPE_FEEDMEDIA && isContentTypeTextAndSmallerThan100kb(response)) {
|
||||
onFail(DownloadError.ERROR_FILE_TYPE, null)
|
||||
return
|
||||
}
|
||||
checkIfRedirect(response)
|
||||
|
||||
connection = BufferedInputStream(responseBody!!.byteStream())
|
||||
|
||||
val contentRangeHeader = if ((fileExists)) response.header("Content-Range") else null
|
||||
if (fileExists && response.code == HttpURLConnection.HTTP_PARTIAL && !contentRangeHeader.isNullOrEmpty()) {
|
||||
val start = contentRangeHeader.substring("bytes ".length, contentRangeHeader.indexOf("-"))
|
||||
downloadRequest.soFar = start.toLong()
|
||||
Log.d(TAG, "Starting download at position " + downloadRequest.soFar)
|
||||
|
||||
out = RandomAccessFile(destination, "rw")
|
||||
out.seek(downloadRequest.soFar)
|
||||
} else {
|
||||
var success = destination.delete()
|
||||
success = success or destination.createNewFile()
|
||||
if (!success) {
|
||||
throw IOException("Unable to recreate partially downloaded file")
|
||||
}
|
||||
out = RandomAccessFile(destination, "rw")
|
||||
}
|
||||
|
||||
val buffer = ByteArray(BUFFER_SIZE)
|
||||
var count = 0
|
||||
downloadRequest.setStatusMsg(R.string.download_running)
|
||||
Log.d(TAG, "Getting size of download")
|
||||
downloadRequest.size = responseBody.contentLength() + downloadRequest.soFar
|
||||
Log.d(TAG, "Size is " + downloadRequest.size)
|
||||
if (downloadRequest.size < 0) {
|
||||
downloadRequest.size = DownloadResult.SIZE_UNKNOWN.toLong()
|
||||
}
|
||||
|
||||
val freeSpace = freeSpaceAvailable
|
||||
Log.d(TAG, "Free space is $freeSpace")
|
||||
if (downloadRequest.size != DownloadResult.SIZE_UNKNOWN.toLong() && downloadRequest.size > freeSpace) {
|
||||
onFail(DownloadError.ERROR_NOT_ENOUGH_SPACE, null)
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "Starting download")
|
||||
try {
|
||||
while (!cancelled && (connection.read(buffer).also { count = it }) != -1) {
|
||||
// Log.d(TAG,"buffer: $buffer")
|
||||
out.write(buffer, 0, count)
|
||||
downloadRequest.soFar += count
|
||||
val progressPercent = (100.0 * downloadRequest.soFar / downloadRequest.size).toInt()
|
||||
downloadRequest.progressPercent = progressPercent
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
}
|
||||
if (cancelled) {
|
||||
onCancelled()
|
||||
} else {
|
||||
// check if size specified in the response header is the same as the size of the
|
||||
// written file. This check cannot be made if compression was used
|
||||
if (!isGzip && downloadRequest.size != DownloadResult.SIZE_UNKNOWN.toLong() && downloadRequest.soFar != downloadRequest.size) {
|
||||
onFail(DownloadError.ERROR_IO_WRONG_SIZE, "Download completed but size: "
|
||||
+ downloadRequest.soFar + " does not equal expected size " + downloadRequest.size)
|
||||
return
|
||||
} else if (downloadRequest.size > 0 && downloadRequest.soFar == 0L) {
|
||||
onFail(DownloadError.ERROR_IO_ERROR, "Download completed, but nothing was read")
|
||||
Log.d(TAG, "Response code is " + response.code)// check if size specified in the response header is the same as the size of the
|
||||
// written file. This check cannot be made if compression was used
|
||||
// Log.d(TAG,"buffer: $buffer")
|
||||
when {
|
||||
!response.isSuccessful && response.code == HttpURLConnection.HTTP_NOT_MODIFIED -> {
|
||||
Log.d(TAG, "Feed '" + downloadRequest.source + "' not modified since last update, Download canceled")
|
||||
onCancelled()
|
||||
return
|
||||
}
|
||||
val lastModified = response.header("Last-Modified")
|
||||
if (lastModified != null) {
|
||||
downloadRequest.setLastModified(lastModified)
|
||||
} else {
|
||||
downloadRequest.setLastModified(response.header("ETag"))
|
||||
!response.isSuccessful || response.body == null -> {
|
||||
callOnFailByResponseCode(response)
|
||||
return
|
||||
}
|
||||
downloadRequest.feedfileType == FeedMedia.FEEDFILETYPE_FEEDMEDIA && isContentTypeTextAndSmallerThan100kb(response) -> {
|
||||
onFail(DownloadError.ERROR_FILE_TYPE, null)
|
||||
return
|
||||
}
|
||||
else -> {
|
||||
checkIfRedirect(response)
|
||||
|
||||
connection = BufferedInputStream(responseBody!!.byteStream())
|
||||
|
||||
val contentRangeHeader = if ((fileExists)) response.header("Content-Range") else null
|
||||
if (fileExists && response.code == HttpURLConnection.HTTP_PARTIAL && !contentRangeHeader.isNullOrEmpty()) {
|
||||
val start = contentRangeHeader.substring("bytes ".length, contentRangeHeader.indexOf("-"))
|
||||
downloadRequest.soFar = start.toLong()
|
||||
Log.d(TAG, "Starting download at position " + downloadRequest.soFar)
|
||||
|
||||
out = RandomAccessFile(destination, "rw")
|
||||
out.seek(downloadRequest.soFar)
|
||||
} else {
|
||||
var success = destination.delete()
|
||||
success = success or destination.createNewFile()
|
||||
if (!success) {
|
||||
throw IOException("Unable to recreate partially downloaded file")
|
||||
}
|
||||
out = RandomAccessFile(destination, "rw")
|
||||
}
|
||||
|
||||
val buffer = ByteArray(BUFFER_SIZE)
|
||||
var count = 0
|
||||
downloadRequest.setStatusMsg(R.string.download_running)
|
||||
Log.d(TAG, "Getting size of download")
|
||||
downloadRequest.size = responseBody.contentLength() + downloadRequest.soFar
|
||||
Log.d(TAG, "Size is " + downloadRequest.size)
|
||||
if (downloadRequest.size < 0) {
|
||||
downloadRequest.size = DownloadResult.SIZE_UNKNOWN.toLong()
|
||||
}
|
||||
|
||||
val freeSpace = freeSpaceAvailable
|
||||
Log.d(TAG, "Free space is $freeSpace")
|
||||
if (downloadRequest.size != DownloadResult.SIZE_UNKNOWN.toLong() && downloadRequest.size > freeSpace) {
|
||||
onFail(DownloadError.ERROR_NOT_ENOUGH_SPACE, null)
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "Starting download")
|
||||
try {
|
||||
while (!cancelled && (connection.read(buffer).also { count = it }) != -1) {
|
||||
// Log.d(TAG,"buffer: $buffer")
|
||||
out.write(buffer, 0, count)
|
||||
downloadRequest.soFar += count
|
||||
val progressPercent = (100.0 * downloadRequest.soFar / downloadRequest.size).toInt()
|
||||
downloadRequest.progressPercent = progressPercent
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
}
|
||||
if (cancelled) {
|
||||
onCancelled()
|
||||
} else {
|
||||
// check if size specified in the response header is the same as the size of the
|
||||
// written file. This check cannot be made if compression was used
|
||||
when {
|
||||
!isGzip && downloadRequest.size != DownloadResult.SIZE_UNKNOWN.toLong() && downloadRequest.soFar != downloadRequest.size -> {
|
||||
onFail(DownloadError.ERROR_IO_WRONG_SIZE, "Download completed but size: "
|
||||
+ downloadRequest.soFar + " does not equal expected size " + downloadRequest.size)
|
||||
return
|
||||
}
|
||||
downloadRequest.size > 0 && downloadRequest.soFar == 0L -> {
|
||||
onFail(DownloadError.ERROR_IO_ERROR, "Download completed, but nothing was read")
|
||||
return
|
||||
}
|
||||
else -> {
|
||||
val lastModified = response.header("Last-Modified")
|
||||
if (lastModified != null) {
|
||||
downloadRequest.setLastModified(lastModified)
|
||||
} else {
|
||||
downloadRequest.setLastModified(response.header("ETag"))
|
||||
}
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onSuccess()
|
||||
}
|
||||
} catch (e: IllegalArgumentException) {
|
||||
e.printStackTrace()
|
||||
|
|
|
@ -139,12 +139,13 @@ class NewEpisodesNotification {
|
|||
private fun loadIcon(context: Context, feed: Feed): Bitmap? {
|
||||
val iconSize = (128 * context.resources.displayMetrics.density).toInt()
|
||||
return try {
|
||||
Glide.with(context)
|
||||
if (!feed.imageUrl.isNullOrBlank()) Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(feed.imageUrl)
|
||||
.apply(RequestOptions().centerCrop())
|
||||
.submit(iconSize, iconSize)
|
||||
.get()
|
||||
else null
|
||||
} catch (tr: Throwable) {
|
||||
null
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ class PlaybackServiceNotificationBuilder(private val context: Context) {
|
|||
val options = RequestOptions().centerCrop()
|
||||
try {
|
||||
var imgLoc = playable?.getImageLocation()
|
||||
if (imgLoc != null) {
|
||||
if (!imgLoc.isNullOrBlank()) {
|
||||
cachedIcon = Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(imgLoc)
|
||||
|
@ -73,7 +73,7 @@ class PlaybackServiceNotificationBuilder(private val context: Context) {
|
|||
.get()
|
||||
} else if (playable != null) {
|
||||
imgLoc = ImageResourceUtils.getFallbackImageLocation(playable!!)
|
||||
if (imgLoc != null) {
|
||||
if (!imgLoc.isNullOrBlank()) {
|
||||
cachedIcon = Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(imgLoc)
|
||||
|
@ -92,8 +92,7 @@ class PlaybackServiceNotificationBuilder(private val context: Context) {
|
|||
private val defaultIcon: Bitmap?
|
||||
get() {
|
||||
if (Companion.defaultIcon == null) {
|
||||
Companion.defaultIcon = getBitmap(
|
||||
context, R.mipmap.ic_launcher)
|
||||
Companion.defaultIcon = getBitmap(context, R.mipmap.ic_launcher)
|
||||
}
|
||||
return Companion.defaultIcon
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.*
|
|||
class RemoteMedia : Playable {
|
||||
private var itemIdentifier: String? = null
|
||||
private val downloadUrl: String? = null
|
||||
private val imageUrl: String? = null
|
||||
private val imageUrl: String?
|
||||
private val notes: String? = null
|
||||
|
||||
private val streamUrl: String?
|
||||
|
@ -52,6 +52,7 @@ class RemoteMedia : Playable {
|
|||
this.episodeLink = episodeLink
|
||||
this.feedAuthor = feedAuthor
|
||||
this.imageLocation = imageUrl
|
||||
this.imageUrl = imageUrl
|
||||
this.feedLink = feedLink
|
||||
this.mimeType = mimeType
|
||||
this.pubDate = pubDate
|
||||
|
@ -67,9 +68,11 @@ class RemoteMedia : Playable {
|
|||
this.episodeLink = item.link
|
||||
this.feedAuthor = item.feed?.author
|
||||
if (!item.imageUrl.isNullOrEmpty()) {
|
||||
this.imageLocation = item.imageUrl
|
||||
this.imageLocation = item.imageLocation
|
||||
this.imageUrl = item.imageUrl
|
||||
} else {
|
||||
this.imageLocation = item.feed?.imageUrl
|
||||
this.imageUrl = item.feed?.imageUrl
|
||||
}
|
||||
this.feedLink = item.feed?.link
|
||||
this.mimeType = item.media?.mime_type
|
||||
|
@ -181,7 +184,7 @@ class RemoteMedia : Playable {
|
|||
}
|
||||
|
||||
override fun getImageLocation(): String? {
|
||||
return imageUrl
|
||||
return imageLocation
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
|
|
|
@ -176,12 +176,9 @@ class OnlineFeedViewActivity : AppCompatActivity() {
|
|||
super.onStop()
|
||||
isPaused = true
|
||||
EventBus.getDefault().unregister(this)
|
||||
if (downloader != null && !downloader!!.isFinished) {
|
||||
downloader!!.cancel()
|
||||
}
|
||||
if (dialog != null && dialog!!.isShowing) {
|
||||
dialog!!.dismiss()
|
||||
}
|
||||
if (downloader != null && !downloader!!.isFinished) downloader!!.cancel()
|
||||
|
||||
if (dialog != null && dialog!!.isShowing) dialog!!.dismiss()
|
||||
}
|
||||
|
||||
public override fun onDestroy() {
|
||||
|
@ -329,7 +326,6 @@ class OnlineFeedViewActivity : AppCompatActivity() {
|
|||
.subscribeOn(Schedulers.computation())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeWith(object : DisposableMaybeObserver<FeedHandlerResult?>() {
|
||||
|
||||
@UnstableApi override fun onSuccess(result: FeedHandlerResult) {
|
||||
showFeedInformation(result.feed, result.alternateFeedUrls)
|
||||
}
|
||||
|
@ -398,7 +394,7 @@ class OnlineFeedViewActivity : AppCompatActivity() {
|
|||
|
||||
binding.episodeLabel.setOnClickListener { showEpisodes(feed.items)}
|
||||
|
||||
if (StringUtils.isNotBlank(feed.imageUrl)) {
|
||||
if (!feed.imageUrl.isNullOrBlank()) {
|
||||
Glide.with(this)
|
||||
.load(feed.imageUrl)
|
||||
.apply(RequestOptions()
|
||||
|
@ -499,40 +495,44 @@ class OnlineFeedViewActivity : AppCompatActivity() {
|
|||
val dli = DownloadServiceInterface.get()
|
||||
if (dli == null || selectedDownloadUrl == null) return
|
||||
|
||||
if (dli.isDownloadingEpisode(selectedDownloadUrl!!)) {
|
||||
binding.subscribeButton.isEnabled = false
|
||||
binding.subscribeButton.setText(R.string.subscribing_label)
|
||||
} else if (feedInFeedlist()) {
|
||||
binding.subscribeButton.isEnabled = true
|
||||
binding.subscribeButton.setText(R.string.open_podcast)
|
||||
if (didPressSubscribe) {
|
||||
didPressSubscribe = false
|
||||
|
||||
val feed1 = DBReader.getFeed(feedId)?: return
|
||||
val feedPreferences = feed1.preferences
|
||||
if (feedPreferences != null) {
|
||||
if (isEnableAutodownload) {
|
||||
val autoDownload = binding.autoDownloadCheckBox.isChecked
|
||||
feedPreferences.autoDownload = autoDownload
|
||||
|
||||
val preferences = getSharedPreferences(PREFS, MODE_PRIVATE)
|
||||
val editor = preferences.edit()
|
||||
editor.putBoolean(PREF_LAST_AUTO_DOWNLOAD, autoDownload)
|
||||
editor.apply()
|
||||
}
|
||||
if (username != null) {
|
||||
feedPreferences.username = username
|
||||
feedPreferences.password = password
|
||||
}
|
||||
DBWriter.setFeedPreferences(feedPreferences)
|
||||
}
|
||||
openFeed()
|
||||
when {
|
||||
dli.isDownloadingEpisode(selectedDownloadUrl!!) -> {
|
||||
binding.subscribeButton.isEnabled = false
|
||||
binding.subscribeButton.setText(R.string.subscribing_label)
|
||||
}
|
||||
} else {
|
||||
binding.subscribeButton.isEnabled = true
|
||||
binding.subscribeButton.setText(R.string.subscribe_label)
|
||||
if (isEnableAutodownload) {
|
||||
binding.autoDownloadCheckBox.visibility = View.VISIBLE
|
||||
feedInFeedlist() -> {
|
||||
binding.subscribeButton.isEnabled = true
|
||||
binding.subscribeButton.setText(R.string.open)
|
||||
if (didPressSubscribe) {
|
||||
didPressSubscribe = false
|
||||
|
||||
val feed1 = DBReader.getFeed(feedId)?: return
|
||||
val feedPreferences = feed1.preferences
|
||||
if (feedPreferences != null) {
|
||||
if (isEnableAutodownload) {
|
||||
val autoDownload = binding.autoDownloadCheckBox.isChecked
|
||||
feedPreferences.autoDownload = autoDownload
|
||||
|
||||
val preferences = getSharedPreferences(PREFS, MODE_PRIVATE)
|
||||
val editor = preferences.edit()
|
||||
editor.putBoolean(PREF_LAST_AUTO_DOWNLOAD, autoDownload)
|
||||
editor.apply()
|
||||
}
|
||||
if (username != null) {
|
||||
feedPreferences.username = username
|
||||
feedPreferences.password = password
|
||||
}
|
||||
DBWriter.setFeedPreferences(feedPreferences)
|
||||
}
|
||||
openFeed()
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
binding.subscribeButton.isEnabled = true
|
||||
binding.subscribeButton.setText(R.string.subscribe_label)
|
||||
if (isEnableAutodownload) {
|
||||
binding.autoDownloadCheckBox.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -579,9 +579,7 @@ class OnlineFeedViewActivity : AppCompatActivity() {
|
|||
setResult(RESULT_ERROR)
|
||||
finish()
|
||||
}
|
||||
if (dialog != null && dialog!!.isShowing) {
|
||||
dialog!!.dismiss()
|
||||
}
|
||||
if (dialog != null && dialog!!.isShowing) dialog!!.dismiss()
|
||||
dialog = builder.show()
|
||||
}
|
||||
}
|
||||
|
@ -615,17 +613,13 @@ class OnlineFeedViewActivity : AppCompatActivity() {
|
|||
val urlsMap: Map<String, String>
|
||||
try {
|
||||
urlsMap = fd.findLinks(feedFile, baseUrl)
|
||||
if (urlsMap.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
if (urlsMap.isEmpty()) return false
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
|
||||
if (isPaused || isFinishing) {
|
||||
return false
|
||||
}
|
||||
if (isPaused || isFinishing) return false
|
||||
|
||||
val titles: MutableList<String?> = ArrayList()
|
||||
|
||||
|
@ -657,9 +651,7 @@ class OnlineFeedViewActivity : AppCompatActivity() {
|
|||
.setAdapter(adapter, onClickListener)
|
||||
|
||||
runOnUiThread {
|
||||
if (dialog != null && dialog!!.isShowing) {
|
||||
dialog!!.dismiss()
|
||||
}
|
||||
if (dialog != null && dialog!!.isShowing) dialog!!.dismiss()
|
||||
dialog = ab.show()
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -106,7 +106,7 @@ class SelectSubscriptionActivity : AppCompatActivity() {
|
|||
|
||||
private fun getBitmapFromUrl(feed: Feed) {
|
||||
val iconSize = (128 * resources.displayMetrics.density).toInt()
|
||||
Glide.with(this)
|
||||
if (!feed.imageUrl.isNullOrBlank()) Glide.with(this)
|
||||
.asBitmap()
|
||||
.load(feed.imageUrl)
|
||||
.apply(RequestOptions.overrideOf(iconSize, iconSize))
|
||||
|
|
|
@ -89,12 +89,15 @@ class ChaptersListAdapter(private val context: Context, private val callback: Ca
|
|||
if (sc.imageUrl.isNullOrEmpty()) {
|
||||
Glide.with(context).clear(holder.image)
|
||||
} else {
|
||||
if (media != null) Glide.with(context)
|
||||
.load(EmbeddedChapterImage.getModelFor(media!!, position))
|
||||
.apply(RequestOptions()
|
||||
.dontAnimate()
|
||||
.transform(FitCenter(), RoundedCorners((4 * context.resources.displayMetrics.density).toInt())))
|
||||
.into(holder.image)
|
||||
if (media != null) {
|
||||
val imgUrl = EmbeddedChapterImage.getModelFor(media!!,position)
|
||||
if (imgUrl != null) Glide.with(context)
|
||||
.load(imgUrl)
|
||||
.apply(RequestOptions()
|
||||
.dontAnimate()
|
||||
.transform(FitCenter(), RoundedCorners((4 * context.resources.displayMetrics.density).toInt())))
|
||||
.into(holder.image)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
holder.image.visibility = View.GONE
|
||||
|
|
|
@ -77,7 +77,7 @@ class CoverLoader(activity: MainActivity) {
|
|||
.load(uri)
|
||||
.apply(options)
|
||||
|
||||
if (fallbackUri != null) {
|
||||
if (!fallbackUri.isNullOrBlank()) {
|
||||
builder = builder.error(Glide.with(imgvCover!!)
|
||||
.`as`(Drawable::class.java)
|
||||
.load(fallbackUri)
|
||||
|
|
|
@ -53,7 +53,7 @@ class FeedDiscoverAdapter(mainActivity: MainActivity) : BaseAdapter() {
|
|||
val podcast: PodcastSearchResult? = getItem(position)
|
||||
holder.imageView!!.contentDescription = podcast?.title
|
||||
|
||||
Glide.with(mainActivityRef.get()!!)
|
||||
if (!podcast?.imageUrl.isNullOrBlank()) Glide.with(mainActivityRef.get()!!)
|
||||
.load(podcast?.imageUrl)
|
||||
.apply(RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
|
|
|
@ -77,7 +77,7 @@ open class HorizontalFeedListAdapter(mainActivity: MainActivity) :
|
|||
false
|
||||
}
|
||||
|
||||
Glide.with(mainActivityRef.get()!!)
|
||||
if (!podcast.imageUrl.isNullOrBlank()) Glide.with(mainActivityRef.get()!!)
|
||||
.load(podcast.imageUrl)
|
||||
.apply(RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
|
|
|
@ -287,7 +287,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
|
|||
val feed = drawerItem.feed
|
||||
val context = activity.get() ?: return
|
||||
|
||||
Glide.with(context)
|
||||
if (!feed.imageUrl.isNullOrBlank()) Glide.with(context)
|
||||
.load(feed.imageUrl)
|
||||
.apply(RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
|
|
|
@ -64,7 +64,7 @@ class OnlineFeedsAdapter(private val context: Context, objects: List<PodcastSear
|
|||
} else viewHolder.updateView.visibility = View.INVISIBLE
|
||||
|
||||
//Update the empty imageView with the image from the feed
|
||||
Glide.with(context)
|
||||
if (!podcast.imageUrl.isNullOrBlank()) Glide.with(context)
|
||||
.load(podcast.imageUrl)
|
||||
.apply(RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
|
|
|
@ -27,7 +27,7 @@ class SimpleIconListAdapter<T : SimpleIconListAdapter.ListItem>(private val cont
|
|||
val binding = SimpleIconListItemBinding.bind(view!!)
|
||||
binding.title.text = item.title
|
||||
binding.subtitle.text = item.subtitle
|
||||
Glide.with(context)
|
||||
if (item.imageUrl.isNotBlank()) Glide.with(context)
|
||||
.load(item.imageUrl)
|
||||
.apply(RequestOptions()
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
|
|
|
@ -8,6 +8,7 @@ import ac.mdiq.podcini.storage.DBTasks
|
|||
import ac.mdiq.podcini.playback.PlaybackServiceStarter
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.storage.model.playback.MediaType
|
||||
import android.util.Log
|
||||
|
||||
class PlayActionButton(item: FeedItem) : ItemActionButton(item) {
|
||||
override fun getLabel(): Int {
|
||||
|
@ -18,6 +19,7 @@ class PlayActionButton(item: FeedItem) : ItemActionButton(item) {
|
|||
}
|
||||
@UnstableApi override fun onClick(context: Context) {
|
||||
val media = item.media ?: return
|
||||
Log.d("PlayActionButton", "onClick called")
|
||||
if (!media.fileExists()) {
|
||||
DBTasks.notifyMissingFeedMediaFile(context, media)
|
||||
return
|
||||
|
|
|
@ -121,8 +121,7 @@ class SwipeActionsDialog(private val context: Context, private val tag: String)
|
|||
|
||||
for (i in keys.indices) {
|
||||
val action = keys[i]
|
||||
val item = SwipeactionsPickerItemBinding.inflate(LayoutInflater.from(
|
||||
context))
|
||||
val item = SwipeactionsPickerItemBinding.inflate(LayoutInflater.from(context))
|
||||
item.swipeActionLabel.text = action.getTitle(context)
|
||||
|
||||
val icon = DrawableCompat.wrap(AppCompatResources.getDrawable(context, action.getActionIcon())!!)
|
||||
|
|
|
@ -71,6 +71,8 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
|
|||
lateinit var listAdapter: EpisodeItemListAdapter
|
||||
protected lateinit var txtvInformation: TextView
|
||||
|
||||
private var currentPlaying: EpisodeItemViewHolder? = null
|
||||
|
||||
@JvmField
|
||||
var episodes: MutableList<FeedItem> = ArrayList()
|
||||
|
||||
|
@ -327,7 +329,7 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
|
|||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: FeedItemEvent) {
|
||||
Log.d(TAG, "onEventMainThread() called with: event = [$event]")
|
||||
Log.d(TAG, "onEventMainThread() called with FeedItemEvent event = [$event]")
|
||||
for (item in event.items) {
|
||||
val pos: Int = FeedItemUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
|
@ -344,11 +346,19 @@ abstract class BaseEpisodesListFragment : Fragment(), SelectableAdapter.OnSelect
|
|||
|
||||
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: PlaybackPositionEvent) {
|
||||
for (i in 0 until listAdapter.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? = recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
// Log.d(TAG, "onEventMainThread() called with PlaybackPositionEvent event = [$event]")
|
||||
if (currentPlaying != null && currentPlaying!!.isCurrentlyPlayingItem)
|
||||
currentPlaying!!.notifyPlaybackPositionUpdated(event)
|
||||
else {
|
||||
Log.d(TAG, "onEventMainThread() search list")
|
||||
for (i in 0 until listAdapter.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? =
|
||||
recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
currentPlaying = holder
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
|
|||
|
||||
private var disposable: Disposable? = null
|
||||
private var displayUpArrow = false
|
||||
|
||||
private var currentPlaying: EpisodeItemViewHolder? = null
|
||||
|
||||
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
|
@ -272,12 +272,19 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
|
|||
|
||||
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: PlaybackPositionEvent) {
|
||||
// if (event == null) return
|
||||
for (i in 0 until adapter.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? = recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
// Log.d(TAG, "onEventMainThread() called with PlaybackPositionEvent event = [$event]")
|
||||
if (currentPlaying != null && currentPlaying!!.isCurrentlyPlayingItem)
|
||||
currentPlaying!!.notifyPlaybackPositionUpdated(event)
|
||||
else {
|
||||
Log.d(TAG, "onEventMainThread() search list")
|
||||
for (i in 0 until adapter.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? =
|
||||
recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
currentPlaying = holder
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
refreshInfoBar()
|
||||
|
|
|
@ -35,6 +35,7 @@ import android.view.LayoutInflater
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
|
@ -189,7 +190,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
val balloon: Balloon = Balloon.Builder(requireContext())
|
||||
.setArrowOrientation(ArrowOrientation.TOP)
|
||||
.setArrowOrientationRules(ArrowOrientationRules.ALIGN_FIXED)
|
||||
.setArrowPosition(0.25f + (if ((isLocaleRtl xor offerStreaming)) 0f else 0.5f))
|
||||
.setArrowPosition(0.25f + (if (isLocaleRtl xor offerStreaming) 0f else 0.5f))
|
||||
.setWidthRatio(1.0f)
|
||||
.setMarginLeft(8)
|
||||
.setMarginRight(8)
|
||||
|
@ -199,10 +200,10 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
.setDismissWhenTouchOutside(true)
|
||||
.setLifecycleOwner(this)
|
||||
.build()
|
||||
val binding_ = PopupBubbleViewBinding.bind(balloon.getContentView())
|
||||
val positiveButton = binding_.balloonButtonPositive
|
||||
val negativeButton = binding_.balloonButtonNegative
|
||||
val message: TextView = binding_.balloonMessage
|
||||
val ballonView = balloon.getContentView()
|
||||
val positiveButton = ballonView.findViewById(R.id.balloon_button_positive) as Button
|
||||
val negativeButton = ballonView.findViewById(R.id.balloon_button_negative) as Button
|
||||
val message: TextView = ballonView.findViewById(R.id.balloon_message) as TextView
|
||||
message.setText(if (offerStreaming) R.string.on_demand_config_stream_text
|
||||
else R.string.on_demand_config_download_text)
|
||||
positiveButton.setOnClickListener {
|
||||
|
@ -297,13 +298,15 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
RoundedCorners((8 * resources.displayMetrics.density).toInt()))
|
||||
.dontAnimate()
|
||||
|
||||
Glide.with(this)
|
||||
.load(item!!.imageLocation)
|
||||
.error(Glide.with(this)
|
||||
.load(ImageResourceUtils.getFallbackImageLocation(item!!))
|
||||
.apply(options))
|
||||
.apply(options)
|
||||
.into(imgvCover)
|
||||
val imgLocFB = ImageResourceUtils.getFallbackImageLocation(item!!)
|
||||
if (!item!!.imageLocation.isNullOrBlank() || !imgLocFB.isNullOrBlank())
|
||||
Glide.with(this)
|
||||
.load(item!!.imageLocation)
|
||||
.error(Glide.with(this)
|
||||
.load(imgLocFB)
|
||||
.apply(options))
|
||||
.apply(options)
|
||||
.into(imgvCover)
|
||||
updateButtons()
|
||||
}
|
||||
|
||||
|
@ -398,15 +401,9 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
|
||||
@UnstableApi @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: EpisodeDownloadEvent) {
|
||||
if (item == null || item!!.media == null) {
|
||||
return
|
||||
}
|
||||
if (!event.urls.contains(item!!.media!!.download_url)) {
|
||||
return
|
||||
}
|
||||
if (itemsLoaded && activity != null) {
|
||||
updateButtons()
|
||||
}
|
||||
if (item == null || item!!.media == null) return
|
||||
if (!event.urls.contains(item!!.media!!.download_url)) return
|
||||
if (itemsLoaded && activity != null) updateButtons()
|
||||
}
|
||||
|
||||
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
package ac.mdiq.podcini.ui.fragment
|
||||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.allEpisodesSortOrder
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.prefFilterAllEpisodes
|
||||
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.dialog.AllEpisodesFilterDialog
|
||||
import ac.mdiq.podcini.ui.dialog.AllEpisodesFilterDialog.AllEpisodesFilterChangedEvent
|
||||
import ac.mdiq.podcini.ui.dialog.ItemSortDialog
|
||||
import ac.mdiq.podcini.util.event.FeedListUpdateEvent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
|
@ -18,8 +12,6 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import kotlin.math.min
|
||||
|
||||
|
@ -49,6 +41,7 @@ class EpisodesListFragment : BaseEpisodesListFragment() {
|
|||
}
|
||||
|
||||
override fun loadData(): List<FeedItem> {
|
||||
if (episodeList.isEmpty()) return listOf()
|
||||
return episodeList.subList(0, min(episodeList.size-1, page * EPISODES_PER_PAGE))
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,8 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
|
||||
private var showTimeLeft = false
|
||||
|
||||
private var currentMedia: Playable? = null
|
||||
|
||||
private var controller: PlaybackController? = null
|
||||
private var disposable: Disposable? = null
|
||||
|
||||
|
@ -192,6 +194,7 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
}
|
||||
|
||||
override fun loadMediaInfo() {
|
||||
Log.d(TAG, "setupPlaybackController loadMediaInfo called")
|
||||
this@ExternalPlayerFragment.loadMediaInfo()
|
||||
}
|
||||
|
||||
|
@ -284,19 +287,24 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
|
||||
@UnstableApi
|
||||
private fun loadMediaInfo() {
|
||||
Log.d(TAG, "Loading media info")
|
||||
Log.d(TAG, "loadMediaInfo called")
|
||||
if (controller == null) {
|
||||
Log.w(TAG, "loadMediaInfo was called while PlaybackController was null!")
|
||||
return
|
||||
}
|
||||
|
||||
disposable?.dispose()
|
||||
disposable = Maybe.fromCallable<Playable?> { controller?.getMedia() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ media: Playable? -> this.updateUi(media) },
|
||||
{ error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) },
|
||||
{ (activity as MainActivity).setPlayerVisible(false) })
|
||||
val theMedia = controller?.getMedia()
|
||||
if (currentMedia == null || theMedia?.getIdentifier() != currentMedia?.getIdentifier()) {
|
||||
Log.d(TAG, "reloading media info")
|
||||
disposable?.dispose()
|
||||
disposable = Maybe.fromCallable<Playable?> { theMedia }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ media: Playable? ->
|
||||
currentMedia = media
|
||||
this.updateUi(media) },
|
||||
{ error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) },
|
||||
{ (activity as MainActivity).setPlayerVisible(false) })
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class) override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
|
@ -354,9 +362,8 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
|
||||
@UnstableApi
|
||||
private fun updateUi(media: Playable?) {
|
||||
if (media == null) {
|
||||
return
|
||||
}
|
||||
if (media == null) return
|
||||
|
||||
episodeTitle.text = media.getEpisodeTitle()
|
||||
(activity as MainActivity).setPlayerVisible(true)
|
||||
onPositionObserverUpdate(PlaybackPositionEvent(media.getPosition(), media.getDuration()))
|
||||
|
@ -367,13 +374,19 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
.fitCenter()
|
||||
.dontAnimate()
|
||||
|
||||
Glide.with(this)
|
||||
.load(getEpisodeListImageLocation(media))
|
||||
.error(Glide.with(this)
|
||||
.load(getFallbackImageLocation(media))
|
||||
.apply(options))
|
||||
.apply(options)
|
||||
.into(imgvCover)
|
||||
val imgLoc = getEpisodeListImageLocation(media)
|
||||
val imgLocFB = getFallbackImageLocation(media)
|
||||
if (!imgLoc.isNullOrBlank())
|
||||
Glide.with(this)
|
||||
.load(imgLoc)
|
||||
.apply(options)
|
||||
.into(imgvCover)
|
||||
else if (!imgLocFB.isNullOrBlank())
|
||||
Glide.with(this)
|
||||
.load(imgLocFB)
|
||||
.apply(options)
|
||||
.into(imgvCover)
|
||||
else imgvCover.setImageResource(R.mipmap.ic_launcher)
|
||||
|
||||
if (controller?.isPlayingVideoLocally == true) {
|
||||
(activity as MainActivity).bottomSheet.setLocked(true)
|
||||
|
|
|
@ -186,22 +186,24 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
Log.d(TAG, "Language is " + feed!!.language)
|
||||
Log.d(TAG, "Author is " + feed!!.author)
|
||||
Log.d(TAG, "URL is " + feed!!.download_url)
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
txtvTitle.text = feed!!.title
|
||||
txtvTitle.setMaxLines(6)
|
||||
|
|
|
@ -77,7 +77,9 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
private lateinit var adapter: FeedItemListAdapter
|
||||
private lateinit var swipeActions: SwipeActions
|
||||
private lateinit var nextPageLoader: MoreContentListFooterUtil
|
||||
|
||||
|
||||
private var currentPlaying: EpisodeItemViewHolder? = null
|
||||
|
||||
private var displayUpArrow = false
|
||||
private var headerCreated = false
|
||||
private var feedID: Long = 0
|
||||
|
@ -314,7 +316,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: FeedItemEvent) {
|
||||
Log.d(TAG, "onEventMainThread() called with: event = [$event]")
|
||||
Log.d(TAG, "onEventMainThread() called with FeedItemEvent event = [$event]")
|
||||
if (feed == null || feed!!.items.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
@ -334,7 +336,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: EpisodeDownloadEvent) {
|
||||
Log.d(TAG, "onEventMainThread() called with: event = [$event]")
|
||||
Log.d(TAG, "onEventMainThread() called with EpisodeDownloadEvent event = [$event]")
|
||||
if (feed == null || feed!!.items.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
@ -348,13 +350,19 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
|
||||
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: PlaybackPositionEvent) {
|
||||
Log.d(TAG, "onEventMainThread() called with: event = [$event]")
|
||||
for (i in 0 until adapter.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? =
|
||||
binding.recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
// Log.d(TAG, "onEventMainThread() called with PlaybackPositionEvent event = [$event]")
|
||||
if (currentPlaying != null && currentPlaying!!.isCurrentlyPlayingItem)
|
||||
currentPlaying!!.notifyPlaybackPositionUpdated(event)
|
||||
else {
|
||||
Log.d(TAG, "onEventMainThread() search list")
|
||||
for (i in 0 until adapter.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? =
|
||||
binding.recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
currentPlaying = holder
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -521,24 +529,25 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
}
|
||||
|
||||
private fun loadFeedImage() {
|
||||
if (feed == null) return
|
||||
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)
|
||||
if (!feed?.imageUrl.isNullOrBlank()) {
|
||||
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)
|
||||
|
||||
Glide.with(this)
|
||||
.load(feed!!.imageUrl)
|
||||
.apply(RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(binding.header.imgvCover)
|
||||
Glide.with(this)
|
||||
.load(feed!!.imageUrl)
|
||||
.apply(RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
.error(R.color.light_gray)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(binding.header.imgvCover)
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableApi private fun loadItems() {
|
||||
|
@ -657,7 +666,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val TAG: String = "ItemlistFragment"
|
||||
const val TAG: String = "FeedItemlistFragment"
|
||||
private const val ARGUMENT_FEED_ID = "argument.ac.mdiq.podcini.feed_id"
|
||||
private const val KEY_UP_ARROW = "up_arrow"
|
||||
|
||||
|
|
|
@ -98,8 +98,7 @@ class OnlineSearchFragment : Fragment() {
|
|||
firstVisibleItem: Int,
|
||||
visibleItemCount: Int,
|
||||
totalItemCount: Int
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
})
|
||||
return binding.root
|
||||
}
|
||||
|
|
|
@ -279,8 +279,9 @@ class PlayerDetailsFragment : Fragment() {
|
|||
if (displayedChapterIndex == -1 || media!!.getChapters().isEmpty() || media!!.getChapters()[displayedChapterIndex].imageUrl.isNullOrEmpty()) {
|
||||
cover.into(binding.imgvCover)
|
||||
} else {
|
||||
Glide.with(this)
|
||||
.load(EmbeddedChapterImage.getModelFor(media!!, displayedChapterIndex))
|
||||
val imgLoc = EmbeddedChapterImage.getModelFor(media!!, displayedChapterIndex)
|
||||
if (imgLoc != null) Glide.with(this)
|
||||
.load(imgLoc)
|
||||
.apply(options)
|
||||
.thumbnail(cover)
|
||||
.error(cover)
|
||||
|
|
|
@ -81,6 +81,8 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
|
|||
private var queue: MutableList<FeedItem> = mutableListOf()
|
||||
|
||||
private var recyclerAdapter: QueueRecyclerAdapter? = null
|
||||
private var currentPlaying: EpisodeItemViewHolder? = null
|
||||
|
||||
private var disposable: Disposable? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -205,7 +207,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
|
|||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: QueueEvent) {
|
||||
Log.d(TAG, "onEventMainThread() called with: event = [$event]")
|
||||
Log.d(TAG, "onEventMainThread() called with QueueEvent event = [$event]")
|
||||
if (recyclerAdapter == null) {
|
||||
loadItems(true)
|
||||
return
|
||||
|
@ -242,7 +244,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
|
|||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: FeedItemEvent) {
|
||||
Log.d(TAG, "onEventMainThread() called with: event = [$event]")
|
||||
Log.d(TAG, "onEventMainThread() called with FeedItemEvent event = [$event]")
|
||||
if (recyclerAdapter == null) {
|
||||
loadItems(true)
|
||||
return
|
||||
|
@ -264,6 +266,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]")
|
||||
for (downloadUrl in event.urls) {
|
||||
val pos: Int = FeedItemUtil.indexOfItemWithDownloadUrl(queue.toList(), downloadUrl)
|
||||
if (pos >= 0) {
|
||||
|
@ -274,12 +277,20 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
|
|||
|
||||
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: PlaybackPositionEvent) {
|
||||
// Log.d(TAG, "onEventMainThread() called with PlaybackPositionEvent event = [$event]")
|
||||
if (recyclerAdapter != null) {
|
||||
for (i in 0 until recyclerAdapter!!.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? = recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
if (currentPlaying != null && currentPlaying!!.isCurrentlyPlayingItem)
|
||||
currentPlaying!!.notifyPlaybackPositionUpdated(event)
|
||||
else {
|
||||
Log.d(TAG, "onEventMainThread() search list")
|
||||
for (i in 0 until recyclerAdapter!!.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? =
|
||||
recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
currentPlaying = holder
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -287,6 +298,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
|
|||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onPlayerStatusChanged(event: PlayerStatusEvent?) {
|
||||
Log.d(TAG, "onPlayerStatusChanged() called with event = [$event]")
|
||||
loadItems(false)
|
||||
refreshToolbarState()
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
|
|||
private lateinit var automaticSearchDebouncer: Handler
|
||||
|
||||
private var results: MutableList<FeedItem> = mutableListOf()
|
||||
private var currentPlaying: EpisodeItemViewHolder? = null
|
||||
|
||||
private var disposable: Disposable? = null
|
||||
private var lastQueryChange: Long = 0
|
||||
|
@ -291,12 +292,18 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
|
|||
|
||||
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: PlaybackPositionEvent) {
|
||||
for (i in 0 until adapter.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? =
|
||||
recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
if (currentPlaying != null && currentPlaying!!.isCurrentlyPlayingItem)
|
||||
currentPlaying!!.notifyPlaybackPositionUpdated(event)
|
||||
else {
|
||||
Log.d(FeedItemlistFragment.TAG, "onEventMainThread() search list")
|
||||
for (i in 0 until adapter.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? =
|
||||
recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
currentPlaying = holder
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ abstract class StatisticsListAdapter protected constructor(@JvmField protected v
|
|||
} else {
|
||||
val holder = h as StatisticsHolder
|
||||
val statsItem = statisticsData!![position - 1]
|
||||
Glide.with(context)
|
||||
if (!statsItem.feed.imageUrl.isNullOrBlank()) Glide.with(context)
|
||||
.load(statsItem.feed.imageUrl)
|
||||
.apply(RequestOptions()
|
||||
.placeholder(R.color.light_gray)
|
||||
|
|
|
@ -120,12 +120,14 @@ class EpisodeItemViewHolder(private val activity: MainActivity, parent: ViewGrou
|
|||
}
|
||||
|
||||
if (coverHolder.visibility == View.VISIBLE) {
|
||||
CoverLoader(activity)
|
||||
.withUri(ImageResourceUtils.getEpisodeListImageLocation(item))
|
||||
val imgLoc = ImageResourceUtils.getEpisodeListImageLocation(item)
|
||||
if (!imgLoc.isNullOrBlank()) CoverLoader(activity)
|
||||
.withUri(imgLoc)
|
||||
.withFallbackUri(item.feed?.imageUrl)
|
||||
.withPlaceholderView(placeholder)
|
||||
.withCoverView(cover)
|
||||
.load()
|
||||
else cover.setImageResource(R.mipmap.ic_launcher)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -187,6 +187,7 @@
|
|||
<string name="filtered_label">Filtered</string>
|
||||
<string name="refresh_failed_msg">{fa-exclamation-circle} Last refresh failed. Tap to view details.</string>
|
||||
<string name="open_podcast">Open podcast</string>
|
||||
<string name="open">Open</string>
|
||||
<string name="please_wait_for_data">Please wait until the data is loaded</string>
|
||||
<string name="updates_disabled_label">Updates disabled</string>
|
||||
<plurals name="updated_feeds_batch_label">
|
||||
|
|
11
changelog.md
11
changelog.md
|
@ -155,4 +155,13 @@
|
|||
* revamped online feed view activity
|
||||
* episodes (50 most recent) of any online feed can be viewed and played (streamed) directly without subscribing to the feed
|
||||
* bug fixes on passing Glide with null addresses
|
||||
* null safety enhancements in code
|
||||
* null safety enhancements in code
|
||||
|
||||
## 4.4.1
|
||||
|
||||
* fixed bug of app crash on stream episode customization
|
||||
* disabled usesCleartextTraffic, connection to http sites appear OK, report if you find an issue
|
||||
* enforced non-null load location for most Glide calls
|
||||
* avoided redundant media loadings and ui updates when a new audio starts
|
||||
* eliminated frequent list search during audio play, a serious energy waste
|
||||
* icons in online episode list, when unavailable, are set to app logo
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
Version 4.4.1 brings several changes:
|
||||
|
||||
* fixed bug of app crash on stream episode customization
|
||||
* disabled usesCleartextTraffic, connection to http sites appear OK, report if you find an issue
|
||||
* enforced non-null load location for most Glide calls
|
||||
* avoided redundant media loadings and ui updates when a new audio starts
|
||||
* eliminated frequent list search during audio play, a serious energy waste
|
||||
* icons in online episode list, when unavailable, are set to app logo
|
Loading…
Reference in New Issue