6.1.4 commit
This commit is contained in:
parent
fab805b3f1
commit
08dfdf8bb1
|
@ -126,8 +126,8 @@ android {
|
|||
buildConfig true
|
||||
}
|
||||
defaultConfig {
|
||||
versionCode 3020217
|
||||
versionName "6.1.3"
|
||||
versionCode 3020218
|
||||
versionName "6.1.4"
|
||||
|
||||
applicationId "ac.mdiq.podcini.R"
|
||||
def commit = ""
|
||||
|
|
|
@ -221,7 +221,7 @@ abstract class MediaPlayerBase protected constructor(protected val context: Cont
|
|||
*
|
||||
* @return a Future, just for the purpose of tracking its execution.
|
||||
*/
|
||||
protected abstract fun endPlayback(hasEnded: Boolean, wasSkipped: Boolean, shouldContinue: Boolean, toStoppedState: Boolean)
|
||||
internal abstract fun endPlayback(hasEnded: Boolean, wasSkipped: Boolean, shouldContinue: Boolean, toStoppedState: Boolean)
|
||||
|
||||
/**
|
||||
* @return `true` if the WifiLock feature should be used, `false` otherwise.
|
||||
|
|
|
@ -6,6 +6,7 @@ import ac.mdiq.podcini.net.utils.NetworkUtils.isAllowMobileStreaming
|
|||
import ac.mdiq.podcini.net.utils.NetworkUtils.isStreamingAllowed
|
||||
import ac.mdiq.podcini.playback.PlaybackServiceStarter
|
||||
import ac.mdiq.podcini.playback.base.InTheatre
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curEpisode
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curMedia
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curState
|
||||
|
@ -37,8 +38,8 @@ import ac.mdiq.podcini.storage.database.Episodes.shouldDeleteRemoveFromQueue
|
|||
import ac.mdiq.podcini.storage.database.Feeds.shouldAutoDeleteItem
|
||||
import ac.mdiq.podcini.storage.database.Queues.addToQueue
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromQueueSync
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.unmanaged
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
|
||||
import ac.mdiq.podcini.storage.model.*
|
||||
import ac.mdiq.podcini.storage.model.CurrentState.Companion.NO_MEDIA_PLAYING
|
||||
|
@ -81,7 +82,6 @@ import androidx.work.impl.utils.futures.SettableFuture
|
|||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import io.realm.kotlin.ext.isManaged
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import java.util.*
|
||||
|
@ -361,8 +361,17 @@ class PlaybackService : MediaSessionService() {
|
|||
writeNoMediaPlaying()
|
||||
return null
|
||||
}
|
||||
val nextItem = getNextInQueue(item)
|
||||
if (nextItem?.media == null) {
|
||||
// val nextItem = getNextInQueue(item)
|
||||
if (curQueue.episodes.isEmpty()) {
|
||||
Logd(TAG, "getNextInQueue queue is empty")
|
||||
writeNoMediaPlaying()
|
||||
return null
|
||||
}
|
||||
val i = curQueue.episodes.indexOf(item)
|
||||
var j = 0
|
||||
if (i >= 0 && i < curQueue.episodes.size-1) j = i+1
|
||||
val nextItem = unmanaged(curQueue.episodes[j])
|
||||
if (nextItem.media == null) {
|
||||
Logd(TAG, "getNextInQueue nextItem: $nextItem media is null")
|
||||
writeNoMediaPlaying()
|
||||
return null
|
||||
|
@ -384,17 +393,17 @@ class PlaybackService : MediaSessionService() {
|
|||
return nextItem.media
|
||||
}
|
||||
|
||||
private fun getNextInQueue(episode: Episode): Episode? {
|
||||
Logd(TAG, "getNextInQueue() with: itemId ${episode.id}")
|
||||
if (curQueue.episodes.isEmpty()) return null
|
||||
|
||||
val i = curQueue.episodes.indexOf(episode)
|
||||
var j = 0
|
||||
if (i >= 0 && i < curQueue.episodes.size-1) j = i+1
|
||||
|
||||
val itemNew = curQueue.episodes[j]
|
||||
return if (itemNew.isManaged()) realm.copyFromRealm(itemNew) else itemNew
|
||||
}
|
||||
// private fun getNextInQueue(episode: Episode): Episode? {
|
||||
// Logd(TAG, "getNextInQueue() with: itemId ${episode.id}")
|
||||
// if (curQueue.episodes.isEmpty()) return null
|
||||
//
|
||||
// val i = curQueue.episodes.indexOf(episode)
|
||||
// var j = 0
|
||||
// if (i >= 0 && i < curQueue.episodes.size-1) j = i+1
|
||||
//
|
||||
// val itemNew = curQueue.episodes[j]
|
||||
// return unmanaged(itemNew)
|
||||
// }
|
||||
|
||||
override fun findMedia(url: String): Playable? {
|
||||
val item = getEpisodeByGuidOrUrl(null, url)
|
||||
|
@ -918,6 +927,7 @@ class PlaybackService : MediaSessionService() {
|
|||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: ${event.TAG}")
|
||||
when (event) {
|
||||
is FlowEvent.QueueEvent -> onQueueEvent(event)
|
||||
is FlowEvent.PlayerErrorEvent -> onPlayerError(event)
|
||||
is FlowEvent.BufferUpdateEvent -> onBufferUpdate(event)
|
||||
is FlowEvent.SleepTimerUpdatedEvent -> onSleepTimerUpdate(event)
|
||||
|
@ -925,12 +935,53 @@ class PlaybackService : MediaSessionService() {
|
|||
is FlowEvent.FeedPrefsChangeEvent -> onFeedPrefsChanged(event)
|
||||
// is FlowEvent.SkipIntroEndingChangedEvent -> skipIntroEndingPresetChanged(event)
|
||||
is FlowEvent.PlayEvent -> currentitem = event.episode
|
||||
is FlowEvent.EpisodeMediaEvent -> onEpisodeMediaEvent(event)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onEpisodeMediaEvent(event: FlowEvent.EpisodeMediaEvent) {
|
||||
if (event.action == FlowEvent.EpisodeMediaEvent.Action.REMOVED) {
|
||||
for (e in event.episodes) {
|
||||
if (e.id == curEpisode?.id) {
|
||||
curEpisode = unmanaged(e)
|
||||
curMedia = curEpisode!!.media
|
||||
mPlayer?.endPlayback(hasEnded = false, wasSkipped = true, shouldContinue = true, toStoppedState = true)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onQueueEvent(event: FlowEvent.QueueEvent) {
|
||||
if (event.action == FlowEvent.QueueEvent.Action.REMOVED) {
|
||||
for (e in event.episodes) {
|
||||
if (e.id == curEpisode?.id) {
|
||||
mPlayer?.endPlayback(hasEnded = false, wasSkipped = true, shouldContinue = true, toStoppedState = true)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private fun onVolumeAdaptionChanged(event: FlowEvent.VolumeAdaptionChangedEvent) {
|
||||
// if (mPlayer != null) updateVolumeIfNecessary(mPlayer!!, event.feedId, event.volumeAdaptionSetting)
|
||||
// }
|
||||
|
||||
private fun onFeedPrefsChanged(event: FlowEvent.FeedPrefsChangeEvent) {
|
||||
val item = (curMedia as? EpisodeMedia)?.episode ?: currentitem
|
||||
if (item?.feed?.id == event.feed.id) {
|
||||
item.feed = null
|
||||
// seems no need to pause??
|
||||
// if (MediaPlayerBase.status == PlayerStatus.PLAYING) {
|
||||
// mPlayer?.pause(abandonFocus = false, reinit = false)
|
||||
// mPlayer?.resume()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
private fun onPlayerError(event: FlowEvent.PlayerErrorEvent) {
|
||||
if (MediaPlayerBase.status == PlayerStatus.PLAYING || MediaPlayerBase.status == PlayerStatus.FALLBACK)
|
||||
mPlayer!!.pause(abandonFocus = true, reinit = false)
|
||||
|
@ -1062,22 +1113,6 @@ class PlaybackService : MediaSessionService() {
|
|||
}
|
||||
}
|
||||
|
||||
// private fun onVolumeAdaptionChanged(event: FlowEvent.VolumeAdaptionChangedEvent) {
|
||||
// if (mPlayer != null) updateVolumeIfNecessary(mPlayer!!, event.feedId, event.volumeAdaptionSetting)
|
||||
// }
|
||||
|
||||
private fun onFeedPrefsChanged(event: FlowEvent.FeedPrefsChangeEvent) {
|
||||
val item = (curMedia as? EpisodeMedia)?.episode ?: currentitem
|
||||
if (item?.feed?.id == event.feed.id) {
|
||||
item.feed = null
|
||||
// seems no need to pause??
|
||||
// if (MediaPlayerBase.status == PlayerStatus.PLAYING) {
|
||||
// mPlayer?.pause(abandonFocus = false, reinit = false)
|
||||
// mPlayer?.resume()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
enum class NotificationCustomButton(val customAction: String, val commandButton: CommandButton) {
|
||||
SKIP(
|
||||
customAction = CUSTOM_COMMAND_SKIP_ACTION_ID,
|
||||
|
|
|
@ -164,7 +164,7 @@ object Episodes {
|
|||
val action = EpisodeAction.Builder(episode, EpisodeAction.DELETE).currentTimestamp().build()
|
||||
SynchronizationQueueSink.enqueueEpisodeActionIfSyncActive(context, action)
|
||||
}
|
||||
EventFlow.postEvent(FlowEvent.EpisodeEvent.updated(episode))
|
||||
EventFlow.postEvent(FlowEvent.EpisodeMediaEvent.removed(episode))
|
||||
}
|
||||
return episode
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ object Episodes {
|
|||
if (episode != null) {
|
||||
episode.media = media
|
||||
episode = upsert(episode) {}
|
||||
EventFlow.postEvent(FlowEvent.EpisodeEvent.updated(episode))
|
||||
EventFlow.postEvent(FlowEvent.EpisodeMediaEvent.updated(episode))
|
||||
} else Log.e(TAG, "persistEpisodeMedia media.episode is null")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -344,7 +344,7 @@ class EpisodeMedia: EmbeddedRealmObject, Playable {
|
|||
hasEmbeddedPicture = false
|
||||
}
|
||||
}
|
||||
upsertBlk(episode!!) {}
|
||||
if (episode != null) upsertBlk(episode!!) {}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
|
|
@ -22,6 +22,7 @@ import android.app.Activity
|
|||
import android.content.DialogInterface
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.RadioButton
|
||||
import androidx.annotation.PluralsRes
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
|
@ -118,6 +119,8 @@ class EpisodeMultiSelectHandler(private val activity: MainActivity, private val
|
|||
fun show() {
|
||||
val activity = activityRef.get() ?: return
|
||||
val binding = SelectQueueDialogBinding.inflate(LayoutInflater.from(activity))
|
||||
binding.removeCheckbox.visibility = View.VISIBLE
|
||||
|
||||
val queues = realm.query(PlayQueue::class).find()
|
||||
for (i in queues.indices) {
|
||||
val radioButton = RadioButton(activity)
|
||||
|
@ -137,21 +140,23 @@ class EpisodeMultiSelectHandler(private val activity: MainActivity, private val
|
|||
.setTitle(R.string.put_in_queue_label)
|
||||
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
|
||||
val queues = realm.query(PlayQueue::class).find()
|
||||
val toRemove = mutableSetOf<Long>()
|
||||
val toRemoveCur = mutableListOf<Episode>()
|
||||
items.forEach { e ->
|
||||
if (curQueue.isInQueue(e)) toRemoveCur.add(e)
|
||||
}
|
||||
items.forEach { e ->
|
||||
for (q in queues) {
|
||||
if (q.isInQueue(e)) {
|
||||
toRemove.add(e.id)
|
||||
break
|
||||
if (binding.removeCheckbox.isChecked) {
|
||||
val toRemove = mutableSetOf<Long>()
|
||||
val toRemoveCur = mutableListOf<Episode>()
|
||||
items.forEach { e ->
|
||||
if (curQueue.isInQueue(e)) toRemoveCur.add(e)
|
||||
}
|
||||
items.forEach { e ->
|
||||
for (q in queues) {
|
||||
if (q.isInQueue(e)) {
|
||||
toRemove.add(e.id)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toRemove.isNotEmpty()) runBlocking { removeFromAllQueuesQuiet(toRemove.toList()) }
|
||||
if (toRemoveCur.isNotEmpty()) EventFlow.postEvent(FlowEvent.QueueEvent.removed(toRemoveCur))
|
||||
}
|
||||
if (toRemove.isNotEmpty()) runBlocking { removeFromAllQueuesQuiet(toRemove.toList()) }
|
||||
if (toRemoveCur.isNotEmpty()) EventFlow.postEvent(FlowEvent.QueueEvent.removed(toRemoveCur))
|
||||
items.forEach { e ->
|
||||
runBlocking { addToQueueSync(false, e, toQueue) }
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ class PlayActionButton(item: Episode) : EpisodeActionButton(item) {
|
|||
episode.media?.downloaded = false
|
||||
episode.media?.fileUrl = null
|
||||
upsertBlk(episode) {}
|
||||
EventFlow.postEvent(FlowEvent.EpisodeEvent.updated(episode))
|
||||
EventFlow.postEvent(FlowEvent.EpisodeMediaEvent.removed(episode))
|
||||
}
|
||||
EventFlow.postEvent(FlowEvent.MessageEvent(context.getString(R.string.error_file_not_found)))
|
||||
}
|
||||
|
|
|
@ -279,6 +279,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
|
|||
override fun onResume() {
|
||||
Logd(TAG, "onResume() isCollapsed: $isCollapsed")
|
||||
super.onResume()
|
||||
loadMediaInfo(false)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
|
|
@ -329,11 +329,30 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
for (item in event.episodes) {
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
episodes.removeAt(pos)
|
||||
if (getFilter().matches(item)) {
|
||||
episodes.add(pos, item)
|
||||
episodes[pos] = item
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
} else adapter.notifyItemRemoved(pos)
|
||||
} else {
|
||||
episodes.removeAt(pos)
|
||||
adapter.notifyItemRemoved(pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onEpisodeMediaEvent(event: FlowEvent.EpisodeMediaEvent) {
|
||||
// Logd(TAG, "onEventMainThread() called with ${event.TAG}")
|
||||
for (item in event.episodes) {
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
episodes[pos] = unmanaged(episodes[pos])
|
||||
episodes[pos].media = item.media
|
||||
if (getFilter().matches(item)) {
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
} else {
|
||||
// episodes.removeAt(pos)
|
||||
// adapter.notifyItemRemoved(pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -387,6 +406,7 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
is FlowEvent.FeedListEvent, is FlowEvent.EpisodePlayedEvent, is FlowEvent.PlayerSettingsEvent, is FlowEvent.FavoritesEvent -> loadItems()
|
||||
is FlowEvent.PlaybackPositionEvent -> onPlaybackPositionEvent(event)
|
||||
is FlowEvent.EpisodeEvent -> onEpisodeEvent(event)
|
||||
is FlowEvent.EpisodeMediaEvent -> onEpisodeMediaEvent(event)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,6 +218,7 @@ import java.util.*
|
|||
Logd(TAG, "Received event: ${event.TAG}")
|
||||
when (event) {
|
||||
is FlowEvent.EpisodeEvent -> onEpisodeEvent(event)
|
||||
is FlowEvent.EpisodeMediaEvent -> onEpisodeMediaEvent(event)
|
||||
is FlowEvent.PlaybackPositionEvent -> onPlaybackPositionEvent(event)
|
||||
is FlowEvent.FavoritesEvent -> onFavoriteEvent(event)
|
||||
is FlowEvent.PlayerSettingsEvent -> loadItems()
|
||||
|
@ -290,12 +291,28 @@ import java.util.*
|
|||
if (pos >= 0) {
|
||||
episodes.removeAt(pos)
|
||||
val media = item.media
|
||||
if (media != null && media.downloaded) {
|
||||
episodes.add(pos, item)
|
||||
// adapter.notifyItemChangedCompat(pos)
|
||||
} else {
|
||||
// adapter.notifyItemRemoved(pos)
|
||||
}
|
||||
if (media != null && media.downloaded) episodes.add(pos, item)
|
||||
}
|
||||
}
|
||||
// have to do this as adapter.notifyItemRemoved(pos) when pos == 0 causes crash
|
||||
if (size > 0) {
|
||||
// adapter.setDummyViews(0)
|
||||
adapter.updateItems(episodes)
|
||||
}
|
||||
refreshInfoBar()
|
||||
}
|
||||
|
||||
private fun onEpisodeMediaEvent(event: FlowEvent.EpisodeMediaEvent) {
|
||||
// Logd(TAG, "onEpisodeEvent() called with ${event.TAG}")
|
||||
var i = 0
|
||||
val size: Int = event.episodes.size
|
||||
while (i < size) {
|
||||
val item: Episode = event.episodes[i++]
|
||||
val pos = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
episodes.removeAt(pos)
|
||||
val media = item.media
|
||||
if (media != null && media.downloaded) episodes.add(pos, item)
|
||||
}
|
||||
}
|
||||
// have to do this as adapter.notifyItemRemoved(pos) when pos == 0 causes crash
|
||||
|
|
|
@ -335,6 +335,7 @@ import java.util.concurrent.Semaphore
|
|||
|
||||
var i = 0
|
||||
val size: Int = event.episodes.size
|
||||
val poses: MutableList<Int> = mutableListOf()
|
||||
while (i < size) {
|
||||
val item = event.episodes[i++]
|
||||
if (item.feedId != feed!!.id) continue
|
||||
|
@ -342,9 +343,43 @@ import java.util.concurrent.Semaphore
|
|||
if (pos >= 0) {
|
||||
Logd(TAG, "episode event: ${item.title} ${item.playState} ${item.isDownloaded}")
|
||||
episodes[pos] = item
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
poses.add(pos)
|
||||
}
|
||||
}
|
||||
if (poses.size == 1) {
|
||||
if (filterOutEpisode(episodes[poses[0]])) adapter.updateItems(episodes)
|
||||
else adapter.notifyItemChangedCompat(poses[0])
|
||||
} else if (poses.size > 1) {
|
||||
redoFilter()
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onEpisodeMediaEvent(event: FlowEvent.EpisodeMediaEvent) {
|
||||
// Logd(TAG, "onEpisodeEvent() called with ${event.TAG}")
|
||||
if (feed == null || episodes.isEmpty()) return
|
||||
|
||||
var i = 0
|
||||
val size: Int = event.episodes.size
|
||||
val poses: MutableList<Int> = mutableListOf()
|
||||
while (i < size) {
|
||||
val item = event.episodes[i++]
|
||||
if (item.feedId != feed!!.id) continue
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
Logd(TAG, "episode event: ${item.title} ${item.playState} ${item.isDownloaded}")
|
||||
episodes[pos] = unmanaged(episodes[pos])
|
||||
episodes[pos].media = item.media
|
||||
poses.add(pos)
|
||||
}
|
||||
}
|
||||
if (poses.size == 1) {
|
||||
if (filterOutEpisode(episodes[poses[0]])) adapter.updateItems(episodes)
|
||||
else adapter.notifyItemChangedCompat(poses[0])
|
||||
} else if (poses.size > 1) {
|
||||
redoFilter()
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onQueueEvent(event: FlowEvent.QueueEvent) {
|
||||
|
@ -363,7 +398,10 @@ import java.util.concurrent.Semaphore
|
|||
Logd(TAG, "onPlayEvent ${event.episode.title}")
|
||||
if (feed != null) {
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, event.episode.id)
|
||||
if (pos >= 0) adapter.notifyItemChangedCompat(pos)
|
||||
if (pos >= 0) {
|
||||
if (filterOutEpisode(event.episode)) adapter.updateItems(episodes)
|
||||
else adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,15 +411,11 @@ import java.util.concurrent.Semaphore
|
|||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
Logd(TAG, "played item: ${item.title} ${item.playState}")
|
||||
if (enableFilter && ((feed!!.episodeFilter.showUnplayed && item.isPlayed()) || feed!!.episodeFilter.showPlayed && !item.isPlayed())) {
|
||||
episodes.removeAt(pos)
|
||||
adapter.updateItems(episodes)
|
||||
} else {
|
||||
if (filterOutEpisode(item)) adapter.updateItems(episodes)
|
||||
else {
|
||||
episodes[pos] = item
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
// episodes[pos].playState = item.playState
|
||||
// adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,8 +425,8 @@ import java.util.concurrent.Semaphore
|
|||
if (pos >= 0) {
|
||||
episodes[pos] = unmanaged(episodes[pos])
|
||||
episodes[pos].isFavorite = item.isFavorite
|
||||
// episodes[pos] = item
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
if (filterOutEpisode(item)) adapter.updateItems(episodes)
|
||||
else adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,7 +438,8 @@ import java.util.concurrent.Semaphore
|
|||
val pos: Int = EpisodeUtil.indexOfItemWithDownloadUrl(episodes, downloadUrl)
|
||||
if (pos >= 0) {
|
||||
// TODO: need a better way
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
if (filterOutEpisode(episodes[pos])) adapter.updateItems(episodes)
|
||||
else adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -445,6 +480,7 @@ import java.util.concurrent.Semaphore
|
|||
is FlowEvent.PlaybackPositionEvent -> onPlaybackPositionEvent(event)
|
||||
is FlowEvent.FeedPrefsChangeEvent -> if (feed?.id == event.feed.id) loadItems()
|
||||
is FlowEvent.EpisodeEvent -> onEpisodeEvent(event)
|
||||
is FlowEvent.EpisodeMediaEvent -> onEpisodeMediaEvent(event)
|
||||
is FlowEvent.PlayerSettingsEvent -> loadItems()
|
||||
is FlowEvent.EpisodePlayedEvent -> onEpisodePlayedEvent(event)
|
||||
is FlowEvent.FeedListEvent -> if (feed != null && event.contains(feed!!)) loadItems()
|
||||
|
@ -614,6 +650,22 @@ import java.util.concurrent.Semaphore
|
|||
while (loadItemsRunning) Thread.sleep(50)
|
||||
}
|
||||
|
||||
private fun filterOutEpisode(episode: Episode): Boolean {
|
||||
if (enableFilter && !feed?.preferences?.filterString.isNullOrEmpty() && !feed!!.episodeFilter.matches(episode)) {
|
||||
episodes.remove(episode)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun redoFilter() {
|
||||
if (enableFilter && !feed?.preferences?.filterString.isNullOrEmpty()) {
|
||||
val episodes_ = episodes.toList()
|
||||
episodes.clear()
|
||||
episodes.addAll(episodes_.filter { feed!!.episodeFilter.matches(it) })
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableApi
|
||||
private fun loadItems() {
|
||||
if (!loadItemsRunning) {
|
||||
|
|
|
@ -355,7 +355,7 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
private fun setupAutoDownloadGlobalPreference() {
|
||||
if (!isEnableAutodownload) {
|
||||
if (!isEnableAutodownload || feedPrefs?.autoDownload != true) {
|
||||
val autodl = findPreference<SwitchPreferenceCompat>(Prefs.autoDownload.name)
|
||||
autodl!!.isChecked = false
|
||||
autodl.isEnabled = false
|
||||
|
|
|
@ -228,6 +228,7 @@ import java.util.*
|
|||
when (event) {
|
||||
is FlowEvent.QueueEvent -> onQueueEvent(event)
|
||||
is FlowEvent.EpisodeEvent -> onEpisodeEvent(event)
|
||||
is FlowEvent.EpisodeMediaEvent -> onEpisodeMediaEvent(event)
|
||||
is FlowEvent.FavoritesEvent -> onFavoriteEvent(event)
|
||||
is FlowEvent.PlayEvent -> onPlayEvent(event)
|
||||
is FlowEvent.PlaybackPositionEvent -> onPlaybackPositionEvent(event)
|
||||
|
@ -320,15 +321,45 @@ import java.util.*
|
|||
}
|
||||
var i = 0
|
||||
val size: Int = event.episodes.size
|
||||
val poses: MutableList<Int> = mutableListOf()
|
||||
while (i < size) {
|
||||
val item: Episode = event.episodes[i++]
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(queueItems, item.id)
|
||||
if (pos >= 0) {
|
||||
queueItems[pos] = item
|
||||
adapter?.notifyItemChangedCompat(pos)
|
||||
refreshInfoBar()
|
||||
poses.add(pos)
|
||||
}
|
||||
}
|
||||
if (poses.isNotEmpty()) {
|
||||
if (poses.size == 1) adapter?.notifyItemChangedCompat(poses[0])
|
||||
else adapter?.notifyDataSetChanged()
|
||||
refreshInfoBar()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onEpisodeMediaEvent(event: FlowEvent.EpisodeMediaEvent) {
|
||||
// Logd(TAG, "onEventMainThread() called with ${event.TAG}")
|
||||
if (adapter == null) {
|
||||
loadItems(true)
|
||||
return
|
||||
}
|
||||
var i = 0
|
||||
val size: Int = event.episodes.size
|
||||
val poses: MutableList<Int> = mutableListOf()
|
||||
while (i < size) {
|
||||
val item: Episode = event.episodes[i++]
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(queueItems, item.id)
|
||||
if (pos >= 0) {
|
||||
queueItems[pos] = unmanaged(queueItems[pos])
|
||||
queueItems[pos].media = item.media
|
||||
poses.add(pos)
|
||||
}
|
||||
}
|
||||
if (poses.isNotEmpty()) {
|
||||
if (poses.size == 1) adapter?.notifyItemChangedCompat(poses[0])
|
||||
else adapter?.notifyDataSetChanged()
|
||||
refreshInfoBar()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onPlayEvent(event: FlowEvent.PlayEvent) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import ac.mdiq.podcini.storage.model.Episode
|
|||
import ac.mdiq.podcini.storage.model.Playable
|
||||
import ac.mdiq.podcini.storage.model.EpisodeSortOrder
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.FlowEvent.FeedListEvent.Action
|
||||
import android.content.Context
|
||||
import android.view.KeyEvent
|
||||
import androidx.core.util.Consumer
|
||||
|
@ -173,6 +174,24 @@ sealed class FlowEvent {
|
|||
}
|
||||
}
|
||||
|
||||
data class EpisodeMediaEvent(val action: Action, val episodes: List<Episode>) : FlowEvent() {
|
||||
enum class Action { ADDED, REMOVED, UPDATED, ERROR, UNKNOWN }
|
||||
companion object {
|
||||
fun added(vararg episodes: Episode): EpisodeMediaEvent {
|
||||
return EpisodeMediaEvent(Action.ADDED, listOf(*episodes))
|
||||
}
|
||||
fun updated(episodes: List<Episode>): EpisodeMediaEvent {
|
||||
return EpisodeMediaEvent(Action.UPDATED, episodes)
|
||||
}
|
||||
fun updated(vararg episodes: Episode): EpisodeMediaEvent {
|
||||
return EpisodeMediaEvent(Action.UPDATED, listOf(*episodes))
|
||||
}
|
||||
fun removed(vararg episodes: Episode): EpisodeMediaEvent {
|
||||
return EpisodeMediaEvent(Action.REMOVED, listOf(*episodes))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class FeedTagsChangedEvent(val dummy: Unit = Unit) : FlowEvent()
|
||||
|
||||
data class FeedUpdatingEvent(val isRunning: Boolean) : FlowEvent()
|
||||
|
|
|
@ -11,7 +11,15 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp">
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/remove_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:checked="true"
|
||||
android:visibility="gone"
|
||||
android:text="@string/remove_from_other_queues" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -146,7 +146,8 @@
|
|||
<string name="feed_auto_download_newer">Newest unplayed</string>
|
||||
<string name="feed_auto_download_older">Oldest unplayed</string>
|
||||
|
||||
<string name="put_in_queue_label">Put in queue</string>
|
||||
<string name="put_in_queue_label">Add to queue...</string>
|
||||
<string name="remove_from_other_queues">Remove from other queues</string>
|
||||
|
||||
<string name="feed_new_episodes_action_nothing">Nothing</string>
|
||||
<string name="episode_cleanup_never">Never</string>
|
||||
|
@ -262,12 +263,12 @@
|
|||
<item quantity="one">%d episode marked as unplayed.</item>
|
||||
<item quantity="other">%d episodes marked as unplayed.</item>
|
||||
</plurals>
|
||||
<string name="add_to_queue_label">Add to queue</string>
|
||||
<string name="add_to_queue_label">Add to active queue</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d episode added to queue.</item>
|
||||
<item quantity="other">%d episodes added to queue.</item>
|
||||
</plurals>
|
||||
<string name="remove_from_queue_label">Remove from queue</string>
|
||||
<string name="remove_from_queue_label">Remove from active queue</string>
|
||||
<plurals name="removed_from_queue_batch_label">
|
||||
<item quantity="one">%d episode removed from queue.</item>
|
||||
<item quantity="other">%d episodes removed from queue.</item>
|
||||
|
|
11
changelog.md
11
changelog.md
|
@ -1,3 +1,14 @@
|
|||
# 6.1.4
|
||||
|
||||
* fixed issue of "mark excluded episodes played" checkbox not being reflected from the setting
|
||||
* in FeedSetting, fixed issue of auto-download options being enabled even if auto-download is not enabled
|
||||
* "Put in queue" changed to "Add to queue..." and added checkbox for removing from other queues
|
||||
* refined some handling on events
|
||||
* fixed issue of deleted episodes not being correctly handled in some lists
|
||||
* fixed issue of current media kept being played when removed or when removed from queue
|
||||
* in FeedEpisodes view, fixed (mostly) issue of not being promptly filtered when an episode state changes
|
||||
* when screen is turned back on during playback, PlayerUI is promptly updated
|
||||
|
||||
# 6.1.3
|
||||
|
||||
* added feed setting in the header of FeedInfo view
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
Version 6.1.4 brings several changes:
|
||||
|
||||
* fixed issue of "mark excluded episodes played" checkbox not being reflected from the setting
|
||||
* in FeedSetting, fixed issue of auto-download options being enabled even if auto-download is not enabled
|
||||
* "Put in queue" changed to "Add to queue..." and added checkbox for removing from other queues
|
||||
* refined some handling on events
|
||||
* fixed issue of deleted episodes not being correctly handled in some lists
|
||||
* fixed issue of current media kept being played when removed or when removed from queue
|
||||
* in FeedEpisodes view, fixed (mostly) issue of not being promptly filtered when an episode state changes
|
||||
* when screen is turned back on during playback, PlayerUI is promptly updated
|
Loading…
Reference in New Issue