6.13.2 commit
This commit is contained in:
parent
fc902569cd
commit
6c86c2ee48
|
@ -31,8 +31,8 @@ android {
|
|||
// testApplicationId "ac.mdiq.podcini.tests"
|
||||
// testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
versionCode 3020288
|
||||
versionName "6.13.1"
|
||||
versionCode 3020289
|
||||
versionName "6.13.2"
|
||||
|
||||
applicationId "ac.mdiq.podcini.R"
|
||||
def commit = ""
|
||||
|
@ -167,6 +167,13 @@ android {
|
|||
androidResources {
|
||||
additionalParameters "--no-version-vectors"
|
||||
}
|
||||
|
||||
dependenciesInfo {
|
||||
// Disables dependency metadata when building APKs.
|
||||
includeInApk = false
|
||||
// Disables dependency metadata when building Android App Bundles.
|
||||
includeInBundle = false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
|
@ -7,12 +7,15 @@ import ac.mdiq.podcini.net.sync.SynchronizationSettings.isProviderConnected
|
|||
import ac.mdiq.podcini.net.sync.model.EpisodeAction
|
||||
import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
|
||||
import ac.mdiq.podcini.net.utils.NetworkUtils.isAllowMobileEpisodeDownload
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.storage.database.Episodes
|
||||
import ac.mdiq.podcini.storage.database.LogsAndStats
|
||||
import ac.mdiq.podcini.storage.database.Queues
|
||||
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.upsertBlk
|
||||
import ac.mdiq.podcini.storage.model.DownloadResult
|
||||
import ac.mdiq.podcini.storage.model.Episode
|
||||
|
@ -70,7 +73,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() {
|
|||
WorkManager.getInstance(context).enqueueUniqueWork(item.media!!.downloadUrl!!, ExistingWorkPolicy.KEEP, workRequest.build())
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class) override fun cancel(context: Context, media: EpisodeMedia) {
|
||||
override fun cancel(context: Context, media: EpisodeMedia) {
|
||||
Logd(TAG, "starting cancel")
|
||||
// This needs to be done here, not in the worker. Reason: The worker might or might not be running.
|
||||
val item_ = media.episodeOrFetch()
|
||||
|
@ -84,7 +87,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() {
|
|||
workInfoList.forEach { workInfo ->
|
||||
if (workInfo.tags.contains(WORK_DATA_WAS_QUEUED)) {
|
||||
val item_ = media.episodeOrFetch()
|
||||
if (item_ != null) Queues.removeFromQueue(item_)
|
||||
if (item_ != null) runOnIOScope { removeFromQueueSync(curQueue, item_) }
|
||||
}
|
||||
}
|
||||
WorkManager.getInstance(context).cancelAllWorkByTag(tag)
|
||||
|
|
|
@ -18,6 +18,7 @@ import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueStorage
|
|||
import ac.mdiq.podcini.net.utils.NetworkUtils.isAllowMobileFor
|
||||
import ac.mdiq.podcini.net.utils.NetworkUtils.setAllowMobileFor
|
||||
import ac.mdiq.podcini.net.utils.UrlChecker.containsUrl
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.storage.database.Episodes.getEpisodeByGuidOrUrl
|
||||
|
@ -26,7 +27,7 @@ import ac.mdiq.podcini.storage.database.Feeds.deleteFeedSync
|
|||
import ac.mdiq.podcini.storage.database.Feeds.getFeedList
|
||||
import ac.mdiq.podcini.storage.database.Feeds.getFeedListDownloadUrls
|
||||
import ac.mdiq.podcini.storage.database.Feeds.updateFeed
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromQueue
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromQueueSync
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.upsert
|
||||
import ac.mdiq.podcini.storage.model.Episode
|
||||
|
@ -289,8 +290,10 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
|
|||
// if (result.first != null) queueToBeRemoved.add(result.second)
|
||||
updatedItems.add(result.second)
|
||||
}
|
||||
removeFromQueue(*updatedItems.toTypedArray())
|
||||
// removeFromQueue(*updatedItems.toTypedArray())
|
||||
|
||||
runOnIOScope {
|
||||
removeFromQueueSync(curQueue, *updatedItems.toTypedArray())
|
||||
for (episode in updatedItems) {
|
||||
upsert(episode) {}
|
||||
}
|
||||
|
|
|
@ -34,14 +34,16 @@ import ac.mdiq.podcini.preferences.UserPreferences.rewindSecs
|
|||
import ac.mdiq.podcini.receiver.MediaButtonReceiver
|
||||
import ac.mdiq.podcini.storage.database.Episodes.deleteMediaSync
|
||||
import ac.mdiq.podcini.storage.database.Episodes.getEpisodeByGuidOrUrl
|
||||
import ac.mdiq.podcini.storage.database.Episodes.setCompletionDate
|
||||
import ac.mdiq.podcini.storage.database.Episodes.prefDeleteRemovesFromQueue
|
||||
import ac.mdiq.podcini.storage.database.Episodes.prefRemoveFromQueueMarkedPlayed
|
||||
import ac.mdiq.podcini.storage.database.Episodes.setPlayStateSync
|
||||
import ac.mdiq.podcini.storage.database.Episodes.shouldDeleteRemoveFromQueue
|
||||
import ac.mdiq.podcini.storage.database.Feeds.shouldAutoDeleteItem
|
||||
import ac.mdiq.podcini.storage.database.Feeds.allowForAutoDelete
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromAllQueuesSync
|
||||
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.upsert
|
||||
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
|
||||
|
@ -218,7 +220,9 @@ class PlaybackService : MediaLibraryService() {
|
|||
// sound is about to change, eg. bluetooth -> speaker
|
||||
Log.d(TAG, "audioBecomingNoisy onReceive called with action: ${intent.action}")
|
||||
Logd(TAG, "Pausing playback because audio is becoming noisy")
|
||||
pauseIfPauseOnDisconnect()
|
||||
// pauseIfPauseOnDisconnect()
|
||||
transientPause = (MediaPlayerBase.status == PlayerStatus.PLAYING || MediaPlayerBase.status == PlayerStatus.FALLBACK)
|
||||
if (isPauseOnHeadsetDisconnect && !isCasting) mPlayer?.pause(!isPersistNotify, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,6 +275,9 @@ class PlaybackService : MediaLibraryService() {
|
|||
list
|
||||
}
|
||||
|
||||
val shouldSkipKeepEpisode by lazy { appPrefs.getBoolean(UserPreferences.Prefs.prefSkipKeepsEpisode.name, true) }
|
||||
val shouldKeepSuperEpisode by lazy { appPrefs.getBoolean(UserPreferences.Prefs.prefFavoriteKeepsEpisode.name, true) }
|
||||
|
||||
private val mediaPlayerCallback: MediaPlayerCallback = object : MediaPlayerCallback {
|
||||
override fun statusChanged(newInfo: MediaPlayerInfo?) {
|
||||
currentMediaType = mPlayer?.mediaType ?: MediaType.UNKNOWN
|
||||
|
@ -354,35 +361,31 @@ class PlaybackService : MediaLibraryService() {
|
|||
}
|
||||
}
|
||||
if (item != null) {
|
||||
// fun shouldSkipKeepEpisode(): Boolean {
|
||||
// return appPrefs.getBoolean(UserPreferences.Prefs.prefSkipKeepsEpisode.name, true)
|
||||
// }
|
||||
// fun shouldFavoriteKeepEpisode(): Boolean {
|
||||
// return appPrefs.getBoolean(UserPreferences.Prefs.prefFavoriteKeepsEpisode.name, true)
|
||||
// }
|
||||
runOnIOScope {
|
||||
val shouldSkipKeepEpisode = appPrefs.getBoolean(UserPreferences.Prefs.prefSkipKeepsEpisode.name, true)
|
||||
val shouldFavoriteKeepEpisode = appPrefs.getBoolean(UserPreferences.Prefs.prefFavoriteKeepsEpisode.name, true)
|
||||
if (ended || smartMarkAsPlayed || autoSkipped || (skipped && !shouldSkipKeepEpisode)) {
|
||||
Logd(TAG, "onPostPlayback ended: $ended smartMarkAsPlayed: $smartMarkAsPlayed autoSkipped: $autoSkipped skipped: $skipped")
|
||||
// only mark the item as played if we're not keeping it anyways
|
||||
item = setPlayStateSync(PlayState.PLAYED.code, ended || (skipped && smartMarkAsPlayed), item!!)
|
||||
item = setPlayStateSync(PlayState.PLAYED.code, item!!, ended || (skipped && smartMarkAsPlayed), false)
|
||||
if (playable is EpisodeMedia && (ended || skipped || playingNext)) {
|
||||
item = upsert(item!!) { it.media?.playbackCompletionDate = Date() }
|
||||
EventFlow.postEvent(FlowEvent.HistoryEvent())
|
||||
}
|
||||
val action = item?.feed?.preferences?.autoDeleteAction
|
||||
val shouldAutoDelete = (action == AutoDeleteAction.ALWAYS ||
|
||||
(action == AutoDeleteAction.GLOBAL && item?.feed != null && shouldAutoDeleteItem(item!!.feed!!)))
|
||||
if (playable is EpisodeMedia && shouldAutoDelete && (item?.isSUPER != true || !shouldFavoriteKeepEpisode)) {
|
||||
(action == AutoDeleteAction.GLOBAL && item?.feed != null && allowForAutoDelete(item!!.feed!!)))
|
||||
val isItemdeletable = (!shouldKeepSuperEpisode || (item?.isSUPER != true && item?.playState != PlayState.AGAIN.code && item?.playState != PlayState.FOREVER.code))
|
||||
if (playable is EpisodeMedia && shouldAutoDelete && isItemdeletable) {
|
||||
if (playable.localFileAvailable()) item = deleteMediaSync(this@PlaybackService, item!!)
|
||||
if (shouldDeleteRemoveFromQueue()) removeFromQueueSync(null, item!!)
|
||||
if (prefDeleteRemovesFromQueue) removeFromQueueSync(null, item!!)
|
||||
} else if (prefRemoveFromQueueMarkedPlayed) removeFromAllQueuesSync(item!!)
|
||||
}
|
||||
}
|
||||
if (playable is EpisodeMedia && (ended || skipped || playingNext)) setCompletionDate(item!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlaybackStart(playable: Playable, position: Int) {
|
||||
Logd(TAG, "onPlaybackStart position: $position")
|
||||
val delayInterval = positionUpdateInterval(playable.getDuration())
|
||||
Logd(TAG, "onPlaybackStart position: $position delayInterval: $delayInterval")
|
||||
taskManager.startWidgetUpdater(delayInterval)
|
||||
// if (position != Playable.INVALID_TIME) playable.setPosition(position + (delayInterval/2).toInt())
|
||||
if (position != Playable.INVALID_TIME) playable.setPosition(position)
|
||||
|
@ -453,7 +456,7 @@ class PlaybackService : MediaLibraryService() {
|
|||
writeNoMediaPlaying()
|
||||
return null
|
||||
}
|
||||
// EventFlow.postEvent(FlowEvent.PlayEvent(nextItem))
|
||||
EventFlow.postEvent(FlowEvent.PlayEvent(nextItem))
|
||||
return if (nextItem.media == null) null else unmanaged(nextItem.media!!)
|
||||
}
|
||||
override fun findMedia(url: String): Playable? {
|
||||
|
@ -1183,11 +1186,11 @@ class PlaybackService : MediaLibraryService() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun pauseIfPauseOnDisconnect() {
|
||||
Logd(TAG, "pauseIfPauseOnDisconnect()")
|
||||
transientPause = (MediaPlayerBase.status == PlayerStatus.PLAYING || MediaPlayerBase.status == PlayerStatus.FALLBACK)
|
||||
if (isPauseOnHeadsetDisconnect && !isCasting) mPlayer?.pause(!isPersistNotify, false)
|
||||
}
|
||||
// private fun pauseIfPauseOnDisconnect() {
|
||||
// Logd(TAG, "pauseIfPauseOnDisconnect()")
|
||||
// transientPause = (MediaPlayerBase.status == PlayerStatus.PLAYING || MediaPlayerBase.status == PlayerStatus.FALLBACK)
|
||||
// if (isPauseOnHeadsetDisconnect && !isCasting) mPlayer?.pause(!isPersistNotify, false)
|
||||
// }
|
||||
|
||||
/**
|
||||
* @param bluetooth true if the event for unpausing came from bluetooth
|
||||
|
@ -1318,9 +1321,6 @@ class PlaybackService : MediaLibraryService() {
|
|||
if (!isPositionSaverActive) {
|
||||
var positionSaver = Runnable { callback.positionSaverTick() }
|
||||
positionSaver = useMainThreadIfNecessary(positionSaver)
|
||||
// val delayInterval = positionUpdateInterval(duration)
|
||||
// positionSaverFuture = schedExecutor.scheduleWithFixedDelay(
|
||||
// positionSaver, POSITION_SAVER_WAITING_INTERVAL.toLong(), POSITION_SAVER_WAITING_INTERVAL.toLong(), TimeUnit.MILLISECONDS)
|
||||
positionSaverFuture = schedExecutor.scheduleWithFixedDelay(positionSaver, delayInterval, delayInterval, TimeUnit.MILLISECONDS)
|
||||
Logd(TAG, "Started PositionSaver")
|
||||
} else Logd(TAG, "Call to startPositionSaver was ignored.")
|
||||
|
@ -1493,7 +1493,6 @@ class PlaybackService : MediaLibraryService() {
|
|||
Logd(TAG, "Sleep timer expired")
|
||||
shakeListener?.pause()
|
||||
shakeListener = null
|
||||
|
||||
hasVibrated = false
|
||||
}
|
||||
}
|
||||
|
@ -1547,7 +1546,6 @@ class PlaybackService : MediaLibraryService() {
|
|||
val gX = event.values[0] / SensorManager.GRAVITY_EARTH
|
||||
val gY = event.values[1] / SensorManager.GRAVITY_EARTH
|
||||
val gZ = event.values[2] / SensorManager.GRAVITY_EARTH
|
||||
|
||||
val gForce = sqrt((gX * gX + gY * gY + gZ * gZ).toDouble())
|
||||
if (gForce > 2.25) {
|
||||
Logd(TAG, "Detected shake $gForce")
|
||||
|
@ -1562,13 +1560,12 @@ class PlaybackService : MediaLibraryService() {
|
|||
private const val SCHED_EX_POOL_SIZE = 2
|
||||
|
||||
private const val SLEEP_TIMER_UPDATE_INTERVAL = 10000L // in millisoconds
|
||||
const val POSITION_SAVER_WAITING_INTERVAL: Int = 5000 // in millisoconds
|
||||
// const val WIDGET_UPDATER_NOTIFICATION_INTERVAL: Int = 5000 // in millisoconds
|
||||
const val MIN_POSITION_SAVER_INTERVAL: Int = 5000 // in millisoconds
|
||||
const val NOTIFICATION_THRESHOLD: Long = 10000 // in millisoconds
|
||||
|
||||
fun positionUpdateInterval(duration: Int): Long {
|
||||
return if (prefAdaptiveProgressUpdate) max(POSITION_SAVER_WAITING_INTERVAL, duration/50).toLong()
|
||||
else POSITION_SAVER_WAITING_INTERVAL.toLong()
|
||||
return if (prefAdaptiveProgressUpdate) max(MIN_POSITION_SAVER_INTERVAL, duration/50).toLong()
|
||||
else MIN_POSITION_SAVER_INTERVAL.toLong()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1622,23 +1619,17 @@ class PlaybackService : MediaLibraryService() {
|
|||
/**
|
||||
* @return `true` if notifications are persistent, `false` otherwise
|
||||
*/
|
||||
val isPersistNotify: Boolean
|
||||
get() = appPrefs.getBoolean(UserPreferences.Prefs.prefPersistNotify.name, true)
|
||||
val isPersistNotify: Boolean by lazy { appPrefs.getBoolean(UserPreferences.Prefs.prefPersistNotify.name, true) }
|
||||
|
||||
val isPauseOnHeadsetDisconnect: Boolean
|
||||
get() = appPrefs.getBoolean(UserPreferences.Prefs.prefPauseOnHeadsetDisconnect.name, true)
|
||||
val isPauseOnHeadsetDisconnect: Boolean by lazy { appPrefs.getBoolean(UserPreferences.Prefs.prefPauseOnHeadsetDisconnect.name, true) }
|
||||
|
||||
val isUnpauseOnHeadsetReconnect: Boolean
|
||||
get() = appPrefs.getBoolean(UserPreferences.Prefs.prefUnpauseOnHeadsetReconnect.name, true)
|
||||
val isUnpauseOnHeadsetReconnect: Boolean by lazy { appPrefs.getBoolean(UserPreferences.Prefs.prefUnpauseOnHeadsetReconnect.name, true) }
|
||||
|
||||
val isUnpauseOnBluetoothReconnect: Boolean
|
||||
get() = appPrefs.getBoolean(UserPreferences.Prefs.prefUnpauseOnBluetoothReconnect.name, false)
|
||||
val isUnpauseOnBluetoothReconnect: Boolean by lazy { appPrefs.getBoolean(UserPreferences.Prefs.prefUnpauseOnBluetoothReconnect.name, false) }
|
||||
|
||||
val hardwareForwardButton: Int
|
||||
get() = appPrefs.getString(UserPreferences.Prefs.prefHardwareForwardButton.name, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD.toString())!!.toInt()
|
||||
val hardwareForwardButton: Int by lazy { appPrefs.getString(UserPreferences.Prefs.prefHardwareForwardButton.name, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD.toString())!!.toInt() }
|
||||
|
||||
val hardwarePreviousButton: Int
|
||||
get() = appPrefs.getString(UserPreferences.Prefs.prefHardwarePreviousButton.name, KeyEvent.KEYCODE_MEDIA_REWIND.toString())!!.toInt()
|
||||
val hardwarePreviousButton: Int by lazy { appPrefs.getString(UserPreferences.Prefs.prefHardwarePreviousButton.name, KeyEvent.KEYCODE_MEDIA_REWIND.toString())!!.toInt() }
|
||||
|
||||
/**
|
||||
* Set to true to enable Continuous Playback
|
||||
|
|
|
@ -311,7 +311,8 @@ object UserPreferences {
|
|||
prefFavoriteKeepsEpisode,
|
||||
prefAutoDelete,
|
||||
prefAutoDeleteLocal,
|
||||
prefSmartMarkAsPlayedSecs,
|
||||
// prefSmartMarkAsPlayedSecs,
|
||||
// prefSmartMarkAsPlayedPercent,
|
||||
prefPlaybackSpeedArray,
|
||||
prefFallbackSpeed,
|
||||
prefPauseForFocusLoss,
|
||||
|
|
|
@ -36,7 +36,7 @@ class PlaybackPreferencesFragment : PreferenceFragmentCompat() {
|
|||
addPreferencesFromResource(R.xml.preferences_playback)
|
||||
|
||||
setupPlaybackScreen()
|
||||
buildSmartMarkAsPlayedPreference()
|
||||
// buildSmartMarkAsPlayedPreference()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
@ -111,27 +111,27 @@ class PlaybackPreferencesFragment : PreferenceFragmentCompat() {
|
|||
return findPreference<T>(key) ?: throw IllegalArgumentException("Preference with key '$key' is not found")
|
||||
}
|
||||
|
||||
private fun buildSmartMarkAsPlayedPreference() {
|
||||
val res = requireActivity().resources
|
||||
|
||||
val pref = findPreference<ListPreference>(UserPreferences.Prefs.prefSmartMarkAsPlayedSecs.name)
|
||||
val values = res.getStringArray(R.array.smart_mark_as_played_values)
|
||||
val entries = arrayOfNulls<String>(values.size)
|
||||
for (x in values.indices) {
|
||||
if (x == 0) {
|
||||
entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled)
|
||||
} else {
|
||||
var v = values[x].toInt()
|
||||
if (v < 60) {
|
||||
entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v)
|
||||
} else {
|
||||
v /= 60
|
||||
entries[x] = res.getQuantityString(R.plurals.time_minutes_quantified, v, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
pref!!.entries = entries
|
||||
}
|
||||
// private fun buildSmartMarkAsPlayedPreference() {
|
||||
// val res = requireActivity().resources
|
||||
//
|
||||
// val pref = findPreference<ListPreference>(UserPreferences.Prefs.prefSmartMarkAsPlayedSecs.name)
|
||||
// val values = res.getStringArray(R.array.smart_mark_as_played_values)
|
||||
// val entries = arrayOfNulls<String>(values.size)
|
||||
// for (x in values.indices) {
|
||||
// if (x == 0) {
|
||||
// entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled)
|
||||
// } else {
|
||||
// var v = values[x].toInt()
|
||||
// if (v < 60) {
|
||||
// entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v)
|
||||
// } else {
|
||||
// v /= 60
|
||||
// entries[x] = res.getQuantityString(R.plurals.time_minutes_quantified, v, v)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// pref!!.entries = entries
|
||||
// }
|
||||
|
||||
@UnstableApi
|
||||
class EditFallbackSpeedDialog(activity: Activity) {
|
||||
|
|
|
@ -96,21 +96,22 @@ object Episodes {
|
|||
}
|
||||
|
||||
// @JvmStatic is needed because some Runnable blocks call this
|
||||
@OptIn(UnstableApi::class) @JvmStatic
|
||||
@JvmStatic
|
||||
fun deleteEpisodeMedia(context: Context, episode: Episode) : Job {
|
||||
Logd(TAG, "deleteMediaOfEpisode called ${episode.title}")
|
||||
return runOnIOScope {
|
||||
if (episode.media == null) return@runOnIOScope
|
||||
val episode_ = deleteMediaSync(context, episode)
|
||||
if (shouldDeleteRemoveFromQueue()) removeFromQueueSync(null, episode_)
|
||||
if (prefDeleteRemovesFromQueue) removeFromQueueSync(null, episode_)
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldDeleteRemoveFromQueue(): Boolean {
|
||||
return appPrefs.getBoolean(Prefs.prefDeleteRemovesFromQueue.name, false)
|
||||
}
|
||||
val prefDeleteRemovesFromQueue: Boolean
|
||||
get() = appPrefs.getBoolean(Prefs.prefDeleteRemovesFromQueue.name, false)
|
||||
// fun shouldDeleteRemoveFromQueue(): Boolean {
|
||||
// return appPrefs.getBoolean(Prefs.prefDeleteRemovesFromQueue.name, false)
|
||||
// }
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
fun deleteMediaSync(context: Context, episode: Episode): Episode {
|
||||
Logd(TAG, "deleteMediaSync called")
|
||||
val media = episode.media ?: return episode
|
||||
|
@ -176,6 +177,7 @@ object Episodes {
|
|||
}
|
||||
|
||||
/**
|
||||
* This is used when the episodes are not listed with the feed.
|
||||
* Remove the listed episodes and their EpisodeMedia entries.
|
||||
* Deleting media also removes the download log entries.
|
||||
*/
|
||||
|
@ -210,31 +212,6 @@ object Episodes {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will set the playback completion date to the current date regardless of the current value.
|
||||
* @param episode Episode that should be added to the playback history.
|
||||
* @param date PlaybackCompletionDate for `media`
|
||||
*/
|
||||
fun setCompletionDate(episode: Episode, date: Date? = Date()) : Job {
|
||||
Logd(TAG, "setCompletionDate called played: ${episode.playState}")
|
||||
return runOnIOScope {
|
||||
val episode_ = realm.query(Episode::class).query("id == $0", episode.id).first().find()
|
||||
if (episode_ != null) {
|
||||
upsert(episode_) { it.media?.playbackCompletionDate = date }
|
||||
EventFlow.postEvent(FlowEvent.HistoryEvent())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @JvmStatic
|
||||
// fun setFavorite(episode: Episode, stat: Boolean?) : Job {
|
||||
// Logd(TAG, "setFavorite called $stat")
|
||||
// return runOnIOScope {
|
||||
// val result = upsert(episode) { it.rating = if (stat ?: !it.isFavorite) Episode.Rating.FAVORITE.code else Episode.Rating.NEUTRAL.code }
|
||||
// EventFlow.postEvent(FlowEvent.RatingEvent(result, result.rating))
|
||||
// }
|
||||
// }
|
||||
|
||||
fun setRating(episode: Episode, rating: Int) : Job {
|
||||
Logd(TAG, "setRating called $rating")
|
||||
return runOnIOScope {
|
||||
|
@ -254,13 +231,12 @@ object Episodes {
|
|||
Logd(TAG, "setPlayState called")
|
||||
return runOnIOScope {
|
||||
for (episode in episodes) {
|
||||
setPlayStateSync(played, resetMediaPosition, episode)
|
||||
setPlayStateSync(played, episode, resetMediaPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
suspend fun setPlayStateSync(played: Int, resetMediaPosition: Boolean, episode: Episode) : Episode {
|
||||
suspend fun setPlayStateSync(played: Int, episode: Episode, resetMediaPosition: Boolean, removeFromQueue: Boolean = true) : Episode {
|
||||
Logd(TAG, "setPlayStateSync called played: $played resetMediaPosition: $resetMediaPosition ${episode.title}")
|
||||
var episode_ = episode
|
||||
if (!episode.isManaged()) episode_ = realm.query(Episode::class).query("id == $0", episode.id).first().find() ?: episode
|
||||
|
@ -273,15 +249,18 @@ object Episodes {
|
|||
if (resetMediaPosition) it.media?.setPosition(0)
|
||||
}
|
||||
Logd(TAG, "setPlayStateSync played0: ${result.playState}")
|
||||
if (played == PlayState.PLAYED.code && shouldMarkedPlayedRemoveFromQueues()) removeFromAllQueuesSync(result)
|
||||
if (removeFromQueue && played == PlayState.PLAYED.code && prefRemoveFromQueueMarkedPlayed) removeFromAllQueuesSync(result)
|
||||
Logd(TAG, "setPlayStateSync played1: ${result.playState}")
|
||||
EventFlow.postEvent(FlowEvent.EpisodePlayedEvent(result))
|
||||
return result
|
||||
}
|
||||
|
||||
private fun shouldMarkedPlayedRemoveFromQueues(): Boolean {
|
||||
return appPrefs.getBoolean(Prefs.prefRemoveFromQueueMarkedPlayed.name, true)
|
||||
}
|
||||
val prefRemoveFromQueueMarkedPlayed: Boolean
|
||||
get() = appPrefs.getBoolean(Prefs.prefRemoveFromQueueMarkedPlayed.name, true)
|
||||
|
||||
// fun shouldMarkedPlayedRemoveFromQueues(): Boolean {
|
||||
// return appPrefs.getBoolean(Prefs.prefRemoveFromQueueMarkedPlayed.name, true)
|
||||
// }
|
||||
|
||||
fun episodeFromStreamInfoItem(item: StreamInfoItem): Episode {
|
||||
val e = Episode()
|
||||
|
|
|
@ -435,7 +435,7 @@ object Feeds {
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun shouldAutoDeleteItem(feed: Feed): Boolean {
|
||||
fun allowForAutoDelete(feed: Feed): Boolean {
|
||||
if (!isAutoDelete) return false
|
||||
return !feed.isLocalFeed || isAutoDeleteLocal
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import ac.mdiq.podcini.playback.base.InTheatre.curQueue
|
|||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.storage.database.Episodes.setPlayState
|
||||
import ac.mdiq.podcini.storage.database.Episodes.setPlayStateSync
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.upsert
|
||||
|
@ -14,14 +13,10 @@ import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
|
|||
import ac.mdiq.podcini.storage.model.*
|
||||
import ac.mdiq.podcini.storage.utils.EpisodeUtil.indexOfItemWithId
|
||||
import ac.mdiq.podcini.storage.utils.EpisodesPermutors.getPermutor
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.util.Log
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.Job
|
||||
import java.util.*
|
||||
|
@ -91,10 +86,9 @@ object Queues {
|
|||
/**
|
||||
* Appends Episode objects to the end of the queue. The 'read'-attribute of all episodes will be set to true.
|
||||
* If a Episode is already in the queue, the Episode will not change its position in the queue.
|
||||
* @param markAsUnplayed true if the episodes should be marked as unplayed when enqueueing
|
||||
* @param episodes the Episode objects that should be added to the queue.
|
||||
*/
|
||||
@UnstableApi @JvmStatic @Synchronized
|
||||
@JvmStatic @Synchronized
|
||||
fun addToQueue(vararg episodes: Episode) : Job {
|
||||
Logd(TAG, "addToQueue( ... ) called")
|
||||
return runOnIOScope {
|
||||
|
@ -130,7 +124,6 @@ object Queues {
|
|||
it.update()
|
||||
}
|
||||
for (event in events) EventFlow.postEvent(event)
|
||||
|
||||
setPlayState(PlayState.INQUEUE.code, false, *setInQueue.toTypedArray())
|
||||
// if (performAutoDownload) autodownloadEpisodeMedia(context)
|
||||
}
|
||||
|
@ -199,16 +192,15 @@ object Queues {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a Episode object from the queue.
|
||||
* @param episodes FeedItems that should be removed.
|
||||
*/
|
||||
@OptIn(UnstableApi::class) @JvmStatic
|
||||
fun removeFromQueue(vararg episodes: Episode) : Job {
|
||||
return runOnIOScope { removeFromQueueSync(curQueue, *episodes) }
|
||||
}
|
||||
// /**
|
||||
// * Removes a Episode object from the queue.
|
||||
// * @param episodes FeedItems that should be removed.
|
||||
// */
|
||||
// @JvmStatic
|
||||
// fun removeFromQueue(vararg episodes: Episode) : Job {
|
||||
// return runOnIOScope { removeFromQueueSync(curQueue, *episodes) }
|
||||
// }
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
fun removeFromAllQueuesSync(vararg episodes: Episode) {
|
||||
Logd(TAG, "removeFromAllQueuesSync called ")
|
||||
val queues = realm.query(PlayQueue::class).find()
|
||||
|
@ -239,7 +231,7 @@ object Queues {
|
|||
if (indexOfItemWithId(eList, episode.id) >= 0) {
|
||||
Logd(TAG, "removing from queue: ${episode.id} ${episode.title}")
|
||||
indicesToRemove.add(i)
|
||||
if (episode.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, episode)
|
||||
// if (setState && episode.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, episode)
|
||||
if (queue.id == curQueue.id) events.add(FlowEvent.QueueEvent.removed(episode))
|
||||
}
|
||||
}
|
||||
|
@ -316,9 +308,9 @@ object Queues {
|
|||
* false if the caller wants to avoid unexpected updates of the GUI.
|
||||
* @throws IndexOutOfBoundsException if (to < 0 || to >= queue.size()) || (from < 0 || from >= queue.size())
|
||||
*/
|
||||
fun moveInQueue(from: Int, to: Int, broadcastUpdate: Boolean) : Job {
|
||||
return runOnIOScope { moveInQueueSync(from, to, broadcastUpdate) }
|
||||
}
|
||||
// fun moveInQueue(from: Int, to: Int, broadcastUpdate: Boolean) : Job {
|
||||
// return runOnIOScope { moveInQueueSync(from, to, broadcastUpdate) }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Changes the position of a Episode in the queue.
|
||||
|
|
|
@ -80,6 +80,8 @@ class EpisodeFilter(vararg properties_: String) : Serializable {
|
|||
if (properties.contains(States.inProgress.name)) stateQuerys.add(" playState == ${PlayState.INPROGRESS.code} ")
|
||||
if (properties.contains(States.skipped.name)) stateQuerys.add(" playState == ${PlayState.SKIPPED.code} ")
|
||||
if (properties.contains(States.played.name)) stateQuerys.add(" playState == ${PlayState.PLAYED.code} ")
|
||||
if (properties.contains(States.again.name)) stateQuerys.add(" playState == ${PlayState.AGAIN.code} ")
|
||||
if (properties.contains(States.forever.name)) stateQuerys.add(" playState == ${PlayState.FOREVER.code} ")
|
||||
if (properties.contains(States.ignored.name)) stateQuerys.add(" playState == ${PlayState.IGNORED.code} ")
|
||||
if (stateQuerys.isNotEmpty()) {
|
||||
val query = StringBuilder(" (" + stateQuerys[0])
|
||||
|
@ -147,6 +149,8 @@ class EpisodeFilter(vararg properties_: String) : Serializable {
|
|||
inProgress,
|
||||
skipped,
|
||||
played,
|
||||
again,
|
||||
forever,
|
||||
ignored,
|
||||
has_chapters,
|
||||
no_chapters,
|
||||
|
@ -197,6 +201,8 @@ class EpisodeFilter(vararg properties_: String) : Serializable {
|
|||
ItemProperties(R.string.in_progress, States.inProgress.name),
|
||||
ItemProperties(R.string.skipped, States.skipped.name),
|
||||
ItemProperties(R.string.played, States.played.name),
|
||||
ItemProperties(R.string.again, States.again.name),
|
||||
ItemProperties(R.string.forever, States.forever.name),
|
||||
ItemProperties(R.string.ignored, States.ignored.name),
|
||||
),
|
||||
OPINION(R.string.has_comments, ItemProperties(R.string.yes, States.has_comments.name), ItemProperties(R.string.no, States.no_comments.name)),
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
package ac.mdiq.podcini.storage.utils
|
||||
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.Prefs.prefSmartMarkAsPlayedSecs
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.storage.model.Episode
|
||||
import ac.mdiq.podcini.storage.model.Playable
|
||||
|
||||
object EpisodeUtil {
|
||||
private val TAG: String = EpisodeUtil::class.simpleName ?: "Anonymous"
|
||||
val smartMarkAsPlayedSecs: Int
|
||||
get() = appPrefs.getString(UserPreferences.Prefs.prefSmartMarkAsPlayedSecs.name, "30")!!.toInt()
|
||||
// val smartMarkAsPlayedSecs: Int
|
||||
// get() = appPrefs.getString(UserPreferences.Prefs.prefSmartMarkAsPlayedSecs.name, "30")!!.toInt()
|
||||
|
||||
private val smartMarkAsPlayedPercent: Int = 95
|
||||
|
||||
@JvmStatic
|
||||
fun indexOfItemWithId(episodes: List<Episode?>, id: Long): Int {
|
||||
|
@ -36,6 +35,6 @@ object EpisodeUtil {
|
|||
|
||||
@JvmStatic
|
||||
fun hasAlmostEnded(media: Playable): Boolean {
|
||||
return media.getDuration() > 0 && media.getPosition() >= media.getDuration() - smartMarkAsPlayedSecs * 1000
|
||||
return media.getDuration() > 0 && media.getPosition() >= media.getDuration() * smartMarkAsPlayedPercent * 0.01
|
||||
}
|
||||
}
|
||||
|
|
|
@ -250,7 +250,7 @@ class PlayActionButton(item: Episode) : EpisodeActionButton(item) {
|
|||
} else {
|
||||
PlaybackService.clearCurTempSpeed()
|
||||
PlaybackServiceStarter(context, media).callEvenIfRunning(true).start()
|
||||
item = runBlocking { setPlayStateSync(PlayState.INPROGRESS.code, false, item) }
|
||||
if (item.playState < PlayState.INPROGRESS.code) item = runBlocking { setPlayStateSync(PlayState.INPROGRESS.code, item, false) }
|
||||
EventFlow.postEvent(FlowEvent.PlayEvent(item))
|
||||
}
|
||||
playVideoIfNeeded(context, media)
|
||||
|
@ -425,7 +425,7 @@ class StreamActionButton(item: Episode) : EpisodeActionButton(item) {
|
|||
if (media !is EpisodeMedia || !InTheatre.isCurMedia(media)) PlaybackService.clearCurTempSpeed()
|
||||
PlaybackServiceStarter(context, media).shouldStreamThisTime(true).callEvenIfRunning(true).start()
|
||||
if (media is EpisodeMedia && media.episode != null) {
|
||||
val item = runBlocking { setPlayStateSync(PlayState.INPROGRESS.code, false, media.episode!!) }
|
||||
val item = runBlocking { setPlayStateSync(PlayState.INPROGRESS.code, media.episode!!, false) }
|
||||
EventFlow.postEvent(FlowEvent.PlayEvent(item))
|
||||
}
|
||||
playVideoIfNeeded(context, media)
|
||||
|
@ -591,7 +591,7 @@ class PlayLocalActionButton(item: Episode) : EpisodeActionButton(item) {
|
|||
} else {
|
||||
PlaybackService.clearCurTempSpeed()
|
||||
PlaybackServiceStarter(context, media).callEvenIfRunning(true).start()
|
||||
item = runBlocking { setPlayStateSync(PlayState.INPROGRESS.code, false, item) }
|
||||
item = runBlocking { setPlayStateSync(PlayState.INPROGRESS.code, item, false) }
|
||||
EventFlow.postEvent(FlowEvent.PlayEvent(item))
|
||||
}
|
||||
if (media.getMediaType() == MediaType.VIDEO) context.startActivity(getPlayerActivityIntent(context,
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
package ac.mdiq.podcini.ui.actions
|
||||
|
||||
//import ac.mdiq.podcini.ui.dialog.SwipeActionsDialog
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
|
||||
import ac.mdiq.podcini.storage.database.Episodes.deleteMediaSync
|
||||
import ac.mdiq.podcini.storage.database.Episodes.setPlayState
|
||||
import ac.mdiq.podcini.storage.database.Episodes.shouldDeleteRemoveFromQueue
|
||||
import ac.mdiq.podcini.storage.database.Feeds.shouldAutoDeleteItem
|
||||
import ac.mdiq.podcini.storage.database.Episodes.setPlayStateSync
|
||||
import ac.mdiq.podcini.storage.database.Queues.addToQueue
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromQueue
|
||||
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.upsert
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
|
||||
import ac.mdiq.podcini.storage.model.Episode
|
||||
import ac.mdiq.podcini.storage.model.EpisodeFilter
|
||||
import ac.mdiq.podcini.storage.model.EpisodeMedia
|
||||
import ac.mdiq.podcini.storage.model.PlayState
|
||||
import ac.mdiq.podcini.storage.utils.EpisodeUtil
|
||||
import ac.mdiq.podcini.storage.utils.EpisodeUtil.hasAlmostEnded
|
||||
import ac.mdiq.podcini.ui.actions.SwipeAction.ActionTypes
|
||||
import ac.mdiq.podcini.ui.actions.SwipeAction.ActionTypes.NO_ACTION
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
|
@ -56,10 +52,8 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.media3.common.util.UnstableApi
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
import kotlin.math.ceil
|
||||
|
||||
open class SwipeActions(private val fragment: Fragment, private val tag: String) : DefaultLifecycleObserver {
|
||||
|
||||
|
@ -202,8 +196,15 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
|
|||
return context.getString(R.string.delete_episode_label)
|
||||
}
|
||||
@UnstableApi
|
||||
override fun performAction(item: Episode, fragment: Fragment, filter: EpisodeFilter) {
|
||||
override fun performAction(item_: Episode, fragment: Fragment, filter: EpisodeFilter) {
|
||||
var item = item_
|
||||
if (!item.isDownloaded && item.feed?.isLocalFeed != true) return
|
||||
val media = item.media
|
||||
if (media != null) {
|
||||
val almostEnded = hasAlmostEnded(media)
|
||||
if (almostEnded && item.playState < PlayState.PLAYED.code) item = runBlocking { setPlayStateSync(PlayState.PLAYED.code, item, almostEnded, false) }
|
||||
if (almostEnded) item = upsertBlk(item) { it.media?.playbackCompletionDate = Date() }
|
||||
}
|
||||
deleteEpisodesWarnLocal(fragment.requireContext(), listOf(item))
|
||||
}
|
||||
override fun willRemove(filter: EpisodeFilter, item: Episode): Boolean {
|
||||
|
@ -314,9 +315,18 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
|
|||
return context.getString(R.string.remove_from_queue_label)
|
||||
}
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun performAction(item: Episode, fragment: Fragment, filter: EpisodeFilter) {
|
||||
val position: Int = curQueue.episodes.indexOf(item)
|
||||
removeFromQueue(item)
|
||||
override fun performAction(item_: Episode, fragment: Fragment, filter: EpisodeFilter) {
|
||||
val position: Int = curQueue.episodes.indexOf(item_)
|
||||
var item = item_
|
||||
val media = item.media
|
||||
if (media != null) {
|
||||
val almostEnded = hasAlmostEnded(media)
|
||||
if (almostEnded && item.playState < PlayState.PLAYED.code) item = runBlocking { setPlayStateSync(PlayState.PLAYED.code, item, almostEnded, false) }
|
||||
if (almostEnded) item = upsertBlk(item) { it.media?.playbackCompletionDate = Date() }
|
||||
}
|
||||
if (item.playState < PlayState.SKIPPED.code) item = runBlocking { setPlayStateSync(PlayState.SKIPPED.code, item, false, false) }
|
||||
// removeFromQueue(item)
|
||||
runOnIOScope { removeFromQueueSync(curQueue, item) }
|
||||
if (willRemove(filter, item)) {
|
||||
(fragment.requireActivity() as MainActivity).showSnackbarAbovePlayer(fragment.resources.getQuantityString(R.plurals.removed_from_queue_batch_label, 1, 1), Snackbar.LENGTH_LONG)
|
||||
.setAction(fragment.getString(R.string.undo)) {
|
||||
|
@ -426,15 +436,15 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
|
|||
}
|
||||
(fragment.view as? ViewGroup)?.addView(composeView)
|
||||
}
|
||||
private fun delayedExecution(item: Episode, fragment: Fragment, duration: Float) = runBlocking {
|
||||
delay(ceil((duration * 1.05f).toDouble()).toLong())
|
||||
val media: EpisodeMedia? = item.media
|
||||
val shouldAutoDelete = if (item.feed == null) false else shouldAutoDeleteItem(item.feed!!)
|
||||
if (media != null && EpisodeUtil.hasAlmostEnded(media) && shouldAutoDelete) {
|
||||
// deleteMediaOfEpisode(fragment.requireContext(), item)
|
||||
val item_ = deleteMediaSync(fragment.requireContext(), item)
|
||||
if (shouldDeleteRemoveFromQueue()) removeFromQueueSync(null, item_) }
|
||||
}
|
||||
// private fun delayedExecution(item: Episode, fragment: Fragment, duration: Float) = runBlocking {
|
||||
// delay(ceil((duration * 1.05f).toDouble()).toLong())
|
||||
// val media: EpisodeMedia? = item.media
|
||||
// val shouldAutoDelete = if (item.feed == null) false else shouldAutoDeleteItem(item.feed!!)
|
||||
// if (media != null && EpisodeUtil.hasAlmostEnded(media) && shouldAutoDelete) {
|
||||
//// deleteMediaOfEpisode(fragment.requireContext(), item)
|
||||
// val item_ = deleteMediaSync(fragment.requireContext(), item)
|
||||
// if (prefDeleteRemovesFromQueue) removeFromQueueSync(null, item_) }
|
||||
// }
|
||||
}
|
||||
|
||||
class ShelveSwipeAction : SwipeAction {
|
||||
|
|
|
@ -12,19 +12,23 @@ import ac.mdiq.podcini.playback.base.InTheatre
|
|||
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
|
||||
import ac.mdiq.podcini.playback.base.MediaPlayerBase.Companion.status
|
||||
import ac.mdiq.podcini.storage.database.Episodes
|
||||
import ac.mdiq.podcini.storage.database.Episodes.deleteEpisodeMedia
|
||||
import ac.mdiq.podcini.storage.database.Episodes.deleteMediaSync
|
||||
import ac.mdiq.podcini.storage.database.Episodes.episodeFromStreamInfo
|
||||
import ac.mdiq.podcini.storage.database.Episodes.prefDeleteRemovesFromQueue
|
||||
import ac.mdiq.podcini.storage.database.Episodes.prefRemoveFromQueueMarkedPlayed
|
||||
import ac.mdiq.podcini.storage.database.Episodes.setPlayState
|
||||
import ac.mdiq.podcini.storage.database.Episodes.setPlayStateSync
|
||||
import ac.mdiq.podcini.storage.database.Episodes.shouldDeleteRemoveFromQueue
|
||||
import ac.mdiq.podcini.storage.database.Feeds.addToMiscSyndicate
|
||||
import ac.mdiq.podcini.storage.database.Feeds.addToYoutubeSyndicate
|
||||
import ac.mdiq.podcini.storage.database.Feeds.shouldAutoDeleteItem
|
||||
import ac.mdiq.podcini.storage.database.Feeds.allowForAutoDelete
|
||||
import ac.mdiq.podcini.storage.database.Queues
|
||||
import ac.mdiq.podcini.storage.database.Queues.addToQueueSync
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromAllQueuesQuiet
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromQueue
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromAllQueuesSync
|
||||
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.upsert
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
|
||||
import ac.mdiq.podcini.storage.model.*
|
||||
|
@ -40,7 +44,6 @@ import ac.mdiq.podcini.ui.actions.SwipeAction
|
|||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.fragment.EpisodeInfoFragment
|
||||
import ac.mdiq.podcini.ui.fragment.FeedInfoFragment
|
||||
import ac.mdiq.podcini.ui.utils.LocalDeleteModal
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
|
@ -66,14 +69,12 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.AddCircle
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
|
@ -261,13 +262,9 @@ fun PlayStateDialog(selected: List<Episode>, onDismissRequest: () -> Unit) {
|
|||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(4.dp)
|
||||
.clickable {
|
||||
for (item in selected) {
|
||||
var item_ = runBlocking { setPlayStateSync(state.code, false, item) }
|
||||
val media: EpisodeMedia? = item_.media
|
||||
val shouldAutoDelete = if (item_.feed == null) false else shouldAutoDeleteItem(item_.feed!!)
|
||||
if (media != null && hasAlmostEnded(media) && shouldAutoDelete) {
|
||||
item_ = deleteMediaSync(context, item_)
|
||||
if (shouldDeleteRemoveFromQueue()) removeFromQueueSync(null, item_)
|
||||
}
|
||||
var media: EpisodeMedia? = item.media
|
||||
val hasAlmostEnded = if (media != null) hasAlmostEnded(media) else false
|
||||
var item_ = runBlocking { setPlayStateSync(state.code, item, hasAlmostEnded, false) }
|
||||
when (state) {
|
||||
PlayState.UNPLAYED -> {
|
||||
if (isProviderConnected && item_.feed?.isLocalFeed != true && item_.media != null) {
|
||||
|
@ -276,6 +273,13 @@ fun PlayStateDialog(selected: List<Episode>, onDismissRequest: () -> Unit) {
|
|||
}
|
||||
}
|
||||
PlayState.PLAYED -> {
|
||||
if (hasAlmostEnded) item_ = upsertBlk(item_) { it.media?.playbackCompletionDate = Date() }
|
||||
val shouldAutoDelete = if (item_.feed == null) false else allowForAutoDelete(item_.feed!!)
|
||||
media = item_.media
|
||||
if (media != null && hasAlmostEnded && shouldAutoDelete) {
|
||||
item_ = deleteMediaSync(context, item_)
|
||||
if (prefDeleteRemovesFromQueue) removeFromQueueSync(null, item_)
|
||||
} else if (prefRemoveFromQueueMarkedPlayed) removeFromAllQueuesSync(item_)
|
||||
if (item_.feed?.isLocalFeed != true && (isProviderConnected || wifiSyncEnabledKey)) {
|
||||
val media_: EpisodeMedia? = item_.media
|
||||
// not all items have media, Gpodder only cares about those that do
|
||||
|
@ -516,7 +520,20 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: MutableList<EpisodeVM>, feed:
|
|||
isExpanded = false
|
||||
selectMode = false
|
||||
Logd(TAG, "ic_delete: ${selected.size}")
|
||||
LocalDeleteModal.deleteEpisodesWarnLocal(activity, selected)
|
||||
runOnIOScope {
|
||||
for (item_ in selected) {
|
||||
var item = item_
|
||||
if (!item.isDownloaded && item.feed?.isLocalFeed != true) continue
|
||||
val media = item.media
|
||||
if (media != null) {
|
||||
val almostEnded = hasAlmostEnded(media)
|
||||
if (almostEnded && item.playState < PlayState.PLAYED.code) item = setPlayStateSync(PlayState.PLAYED.code, item, almostEnded, false)
|
||||
if (almostEnded) item = upsert(item) { it.media?.playbackCompletionDate = Date() }
|
||||
deleteEpisodeMedia(activity, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
// LocalDeleteModal.deleteEpisodesWarnLocal(activity, selected)
|
||||
}, verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(imageVector = ImageVector.vectorResource(id = R.drawable.ic_delete), "Delete media")
|
||||
Text(stringResource(id = R.string.delete_episode_label)) } },
|
||||
|
@ -527,9 +544,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: MutableList<EpisodeVM>, feed:
|
|||
selectMode = false
|
||||
Logd(TAG, "ic_download: ${selected.size}")
|
||||
for (episode in selected) {
|
||||
if (episode.media != null && episode.feed != null && !episode.feed!!.isLocalFeed) DownloadServiceInterface
|
||||
.get()
|
||||
?.download(activity, episode)
|
||||
if (episode.media != null && episode.feed != null && !episode.feed!!.isLocalFeed) DownloadServiceInterface.get()?.download(activity, episode)
|
||||
}
|
||||
}, verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(imageVector = ImageVector.vectorResource(id = R.drawable.ic_download), "Download")
|
||||
|
@ -551,7 +566,20 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: MutableList<EpisodeVM>, feed:
|
|||
isExpanded = false
|
||||
selectMode = false
|
||||
Logd(TAG, "ic_playlist_remove: ${selected.size}")
|
||||
removeFromQueue(*selected.toTypedArray())
|
||||
runOnIOScope {
|
||||
for (item_ in selected) {
|
||||
var item = item_
|
||||
val media = item.media
|
||||
if (media != null) {
|
||||
val almostEnded = hasAlmostEnded(media)
|
||||
if (almostEnded && item.playState < PlayState.PLAYED.code) item = setPlayStateSync(PlayState.PLAYED.code, item, almostEnded, false)
|
||||
if (almostEnded) item = upsert(item) { it.media?.playbackCompletionDate = Date() }
|
||||
}
|
||||
if (item.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, item)
|
||||
}
|
||||
removeFromQueueSync(curQueue, *selected.toTypedArray())
|
||||
// removeFromQueue(*selected.toTypedArray())
|
||||
}
|
||||
}, verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(imageVector = ImageVector.vectorResource(id = R.drawable.ic_playlist_remove), "Remove from active queue")
|
||||
Text(stringResource(id = R.string.remove_from_queue_label)) } },
|
||||
|
|
|
@ -217,8 +217,7 @@ class AudioPlayerFragment : Fragment() {
|
|||
}))
|
||||
Spacer(Modifier.weight(0.1f))
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_playback_speed), tint = textColor,
|
||||
contentDescription = "speed",
|
||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_playback_speed), tint = textColor, contentDescription = "speed",
|
||||
modifier = Modifier.width(43.dp).height(43.dp).clickable(onClick = {
|
||||
VariableSpeedDialog.newInstance(booleanArrayOf(true, true, true), null)?.show(childFragmentManager, null)
|
||||
}))
|
||||
|
@ -555,7 +554,6 @@ class AudioPlayerFragment : Fragment() {
|
|||
private fun updatePlaybackSpeedButton(event: FlowEvent.SpeedChangedEvent) {
|
||||
val speedStr: String = DecimalFormat("0.00").format(event.newSpeed.toDouble())
|
||||
txtvPlaybackSpeed = speedStr
|
||||
// binding.butPlaybackSpeed.setSpeed(event.newSpeed) TODO
|
||||
}
|
||||
|
||||
@UnstableApi
|
||||
|
@ -594,6 +592,7 @@ class AudioPlayerFragment : Fragment() {
|
|||
fun updateUi(media: Playable) {
|
||||
Logd(TAG, "updateUi called $media")
|
||||
titleText = media.getEpisodeTitle()
|
||||
txtvPlaybackSpeed = DecimalFormat("0.00").format(curSpeedFB.toDouble())
|
||||
if (prevMedia?.getIdentifier() != media.getIdentifier()) imgLoc = ImageResourceUtils.getEpisodeListImageLocation(media)
|
||||
if (isPlayingVideoLocally && (curMedia as? EpisodeMedia)?.episode?.feed?.preferences?.videoModePolicy != VideoMode.AUDIO_ONLY) {
|
||||
// (activity as MainActivity).bottomSheet.setLocked(true)
|
||||
|
@ -803,8 +802,6 @@ class AudioPlayerFragment : Fragment() {
|
|||
fun loadMediaInfo() {
|
||||
Logd(TAG, "loadMediaInfo() curMedia: ${curMedia?.getIdentifier()}")
|
||||
val actMain = (activity as MainActivity)
|
||||
var i = 0
|
||||
// while (curMedia == null && i++ < 6) runBlocking { delay(500) }
|
||||
if (curMedia == null) {
|
||||
if (actMain.isPlayerVisible()) actMain.setPlayerVisible(false)
|
||||
return
|
||||
|
|
|
@ -13,7 +13,6 @@ import ac.mdiq.podcini.playback.service.PlaybackService.Companion.seekTo
|
|||
import ac.mdiq.podcini.preferences.UsageStatistics
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.storage.database.Queues.addToQueue
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromQueue
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.unmanaged
|
||||
|
@ -222,10 +221,10 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}))
|
||||
if (episode?.media != null && !inQueue) {
|
||||
Spacer(modifier = Modifier.weight(0.2f))
|
||||
val inQueueIconRes = if (inQueue) R.drawable.ic_playlist_play else R.drawable.ic_playlist_remove
|
||||
val inQueueIconRes = R.drawable.ic_playlist_remove
|
||||
Icon(imageVector = ImageVector.vectorResource(inQueueIconRes), tint = MaterialTheme.colorScheme.tertiary, contentDescription = "inQueue",
|
||||
modifier = Modifier.background(MaterialTheme.colorScheme.tertiaryContainer).width(24.dp).height(24.dp).clickable(onClick = {
|
||||
if (inQueue) removeFromQueue(episode!!) else addToQueue(episode!!)
|
||||
addToQueue(episode!!)
|
||||
}))
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(0.2f))
|
||||
|
|
|
@ -14,7 +14,7 @@ import ac.mdiq.podcini.preferences.UserPreferences
|
|||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.storage.database.Queues.clearQueue
|
||||
import ac.mdiq.podcini.storage.database.Queues.isQueueKeepSorted
|
||||
import ac.mdiq.podcini.storage.database.Queues.moveInQueue
|
||||
import ac.mdiq.podcini.storage.database.Queues.moveInQueueSync
|
||||
import ac.mdiq.podcini.storage.database.Queues.queueKeepSortedOrder
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
|
||||
|
@ -212,7 +212,10 @@ import kotlin.math.max
|
|||
else rightActionState.value.performAction(episode, this@QueuesFragment, swipeActions.filter ?: EpisodeFilter())
|
||||
}
|
||||
EpisodeLazyColumn(activity as MainActivity, vms = vms,
|
||||
isDraggable = dragDropEnabled, dragCB = { iFrom, iTo -> moveInQueue(iFrom, iTo, true) },
|
||||
isDraggable = dragDropEnabled, dragCB = { iFrom, iTo ->
|
||||
// moveInQueue(iFrom, iTo, true)
|
||||
runOnIOScope { moveInQueueSync(iFrom, iTo, true) }
|
||||
},
|
||||
leftSwipeCB = { leftCB(it) }, rightSwipeCB = { rightCB(it) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -401,8 +401,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">علم بذكاء أنها انتهت</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">ابقي الحلقات التي يتم تخطيها</string>
|
||||
<string name="pref_skip_keeps_episodes_title">الاحتفاظ بالحلقات التي تم تخطيها</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">تعليم الحلقة كمفضلة يبقيها على الجهاز</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">الاحتفاظ بالحلقات المفضلة</string>
|
||||
|
||||
|
||||
<string name="playback_pref">تشغيل</string>
|
||||
<string name="playback_pref_sum">تحكم سماعة الأذن, وقت التقدم, لائحة الاستماع</string>
|
||||
<string name="downloads_pref">تنزيلات</string>
|
||||
|
|
|
@ -351,8 +351,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Marcat intel·ligent d\'episodis reproduïts</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Mantenir episodis quan són omesos</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Mantenir episodis omesos</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Mantenir els episodis quan s\'han marcat com a preferits</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Mantenir episodis preferits</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Reproducció</string>
|
||||
<string name="playback_pref_sum">Controls d\'auriculars, Intervals d\'avançada, Cua</string>
|
||||
<string name="downloads_pref">Baixades</string>
|
||||
|
|
|
@ -392,8 +392,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Chytré označování jako poslechnuté</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Neodstraňovat epizody při jejich přeskočení</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Ponechat přeskočené epizody</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Ponechat epizody označené jako oblíbené.</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Ponechat oblíbené epizody</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Přehrávání</string>
|
||||
<string name="playback_pref_sum">Ovládání tlačítky sluchátek, přeskakování, fronta</string>
|
||||
<string name="downloads_pref">Stahování</string>
|
||||
|
|
|
@ -367,8 +367,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Smart markering som afspillet</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Behold afsnit når de bliver sprunget over</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Behold oversprungne afsnit</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Behold afsnit, når de er markeret som favorit</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Behold favoritafsnit</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Afspilning</string>
|
||||
<string name="playback_pref_sum">Hovedtelefonstyring, overspringsintervaller, kø</string>
|
||||
<string name="downloads_pref">Overførsler</string>
|
||||
|
|
|
@ -371,8 +371,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Intelligentes \"als abgespielt markieren\"</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Episoden behalten, wenn sie übersprungen werden</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Übersprungene Episoden behalten</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Episoden nicht löschen, wenn sie als Favorit markiert wurden</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Favorisierte Episoden nicht löschen</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Wiedergabe</string>
|
||||
<string name="playback_pref_sum">Kopfhörersteuerung, Sprungintervall, Warteschlange</string>
|
||||
<string name="downloads_pref">Downloads</string>
|
||||
|
|
|
@ -382,8 +382,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Marcado inteligente como reproducido</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Conservar los episodios cuando son saltados</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Conservar episodios saltados</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Conservar los episodios cuando se marcan como favoritos</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Conservar episodios favoritos</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Reproducción</string>
|
||||
<string name="playback_pref_sum">Control de auriculares, Saltar intervalos, Cola</string>
|
||||
<string name="downloads_pref">Descargas</string>
|
||||
|
|
|
@ -339,8 +339,8 @@
|
|||
<string name="pref_smart_mark_as_played_sum">Erreproduzitutako saioak markatu nahiz bukatzeko segundo batzuk falta</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Saioak gorde jaustean</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Mantendu saltatutako saioak</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Mantendu gogoko gisa markatutako saioak</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Mantendu gogoko saioak</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Erreprodukzioa</string>
|
||||
<string name="playback_pref_sum">Aurikularren kontrolak, saltatu tarteak, ilara</string>
|
||||
<string name="downloads_pref">Deskargak</string>
|
||||
|
|
|
@ -355,8 +355,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">علامت گذاری هوشمند به پخش شده</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">نگه داشتن قسمتها هنگام پریدن از رویشان</string>
|
||||
<string name="pref_skip_keeps_episodes_title">نگهداری قسمتهای پریده</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">نگه داری قسمتها هنکامی که علامت محبوب خوردهاند</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">نگه داری قسمتهای محبوب</string>
|
||||
|
||||
|
||||
<string name="playback_pref">پخش</string>
|
||||
<string name="playback_pref_sum">کنترل هدفون ، رد کردن فواصل ، صف</string>
|
||||
<string name="downloads_pref">بارگیریها</string>
|
||||
|
|
|
@ -346,8 +346,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Älykäs toistetuksi merkitseminen</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Säilytä jaksot, kun ne ohitetaan</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Säilytä ohitetut jaksot</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Säilytä suosikeiksi merkityt jaksot</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Säilytä suosikkijaksot</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Toisto</string>
|
||||
<string name="playback_pref_sum">Kuulokkeiden ohjaimet, ohitusaikavälit, jono</string>
|
||||
<string name="downloads_pref">Lataukset</string>
|
||||
|
|
|
@ -383,8 +383,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Marquer comme lu intelligemment</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Garder les épisodes quand ils sont passés</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Garder les épisodes passés</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Garder les épisodes marqués comme favoris</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Garder les épisodes favoris</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Lecture</string>
|
||||
<string name="playback_pref_sum">Contrôles du casque, durée des sauts, liste de lecture</string>
|
||||
<string name="downloads_pref">Téléchargements</string>
|
||||
|
|
|
@ -366,8 +366,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Marcado intelixente como escoitado</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Manter os episodios cando son omitidos</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Manter episodios omitidos</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Manter episodios cando están marcados como favoritos</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Manter episodios favoritos</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Reprodución</string>
|
||||
<string name="playback_pref_sum">Control de auriculares, Intervalos de salto, Cola</string>
|
||||
<string name="downloads_pref">Descargas</string>
|
||||
|
|
|
@ -282,8 +282,8 @@
|
|||
<string name="pref_auto_delete_sum">Hapus episode ketika pemutaran selesai</string>
|
||||
<string name="pref_smart_mark_as_played_sum">Tandai episode sebagai telah diputar jika kurang dari beberapa detik waktu masih tersisa</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Simpan episode ketika dilewatkan</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Simpan episode saat difavoritkan</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Simpan episode favorit</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Pemutaran</string>
|
||||
<string name="playback_pref_sum">Kontrol headphone, Jangka waktu lewati, Antrean</string>
|
||||
<string name="downloads_pref_sum">Waktu pembaharuan, Jaringan seluler, Unduh otomatis, Hapus otomatis</string>
|
||||
|
|
|
@ -383,8 +383,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Marcatura intelligente</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Mantiene gli episodi nella coda quando vengono saltati</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Manteni gli episodi saltati</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Mantiene gli episodi se sono segnati come preferiti</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Mantieni episodi preferiti</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Riproduzione</string>
|
||||
<string name="playback_pref_sum">Controllo cuffie, salto intervalli, coda</string>
|
||||
<string name="downloads_pref">Download</string>
|
||||
|
|
|
@ -391,8 +391,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">סימון חכם כנוגנו</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">להשאיר פרקים למרות שדילגת עליהם</string>
|
||||
<string name="pref_skip_keeps_episodes_title">להשאיר פרקים שדולגו</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">להשאיר פרקים כשהם מסומנים כמועדפים</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">להשאיר פרקים מועדפים</string>
|
||||
|
||||
|
||||
<string name="playback_pref">ניגון</string>
|
||||
<string name="playback_pref_sum">שליטה דרך האוזניות, מרחקי דילוג, תור</string>
|
||||
<string name="downloads_pref">הורדות</string>
|
||||
|
|
|
@ -336,8 +336,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">똑똑하게 재생한 것으로 표시</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">에피소드를 넘겼을 경우에도 유지</string>
|
||||
<string name="pref_skip_keeps_episodes_title">넘긴 에피소드 유지</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">즐겨 찾기로 표시한 에피소드를 유지합니다</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">즐겨 찾기 에피소드 유지</string>
|
||||
|
||||
|
||||
<string name="playback_pref">재생</string>
|
||||
<string name="playback_pref_sum">헤드폰 조작, 구간 넘기기, 대기열</string>
|
||||
<string name="downloads_pref">다운로드</string>
|
||||
|
|
|
@ -343,8 +343,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Smart markering som avspilt</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Behold episoder når de hoppes over</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Behold episoder som er hoppet over</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Behold episoder når de er merket som favoritt</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Behold favorittepisoder</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Avspilling</string>
|
||||
<string name="playback_pref_sum">Hodetelefon-kontroller, spole-intervaller, kø</string>
|
||||
<string name="downloads_pref">Nedlastinger</string>
|
||||
|
|
|
@ -344,8 +344,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Slim markeren als afgespeeld</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Bewaar afleveringen wanneer ze worden overgeslagen</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Overgeslagen afleveringen behouden</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Afleveringen bewaren als ze als favoriet gemarkeerd zijn</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Favoriete afleveringen bewaren</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Afspelen</string>
|
||||
<string name="playback_pref_sum">Onderbreken, afspelen, wachtrij</string>
|
||||
<string name="downloads_pref">Downloads</string>
|
||||
|
|
|
@ -368,8 +368,8 @@
|
|||
<string name="pref_smart_mark_as_played_sum">Oznacz odcinek jako odtworzony, jeśli do końca pozostało mniej niż określona ilość czasu</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Zachowuje pominięte odcinki w kolejce</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Zachowaj pominięte odcinki</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Zachowaj odcinki gdy są oznaczone jako ulubione</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Zachowaj ulubione odcinki</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Odtwarzanie</string>
|
||||
<string name="playback_pref_sum">Kontrola za pomocą słuchawek, Pomijanie, Kolejka</string>
|
||||
<string name="downloads_pref">Pobrane</string>
|
||||
|
|
|
@ -363,8 +363,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Marcação inteligente quando reproduzido</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Mantém os episódios quando eles forem pulados</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Manter episódios ignorados</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Manter os episódios quando eles estiverem marcados como favoritos</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Manter episódios favoritos</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Reprodução</string>
|
||||
<string name="playback_pref_sum">Controles de fone de ouvido, intervalos para saltar, Fila</string>
|
||||
<string name="downloads_pref">Downloads</string>
|
||||
|
|
|
@ -382,8 +382,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Marcar como reproduzido (inteligente)</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Manter episódios mesmo se tiverem sido ignorados</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Manter episódios ignorados</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Manter episódios se forem assinalados como favoritos</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Manter episódios favoritos</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Reprodução</string>
|
||||
<string name="playback_pref_sum">Controlo com auscultador, intervalos e fila</string>
|
||||
<string name="downloads_pref">Descargas</string>
|
||||
|
|
|
@ -379,8 +379,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Marchează inteligent ca fiind redate</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Păstrează episoade când acestea sunt sărite</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Păstrează episoadele sărite</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Păstrează episoadele când sunt marcate ca favorite</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Păstrează episoadele favorite</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Ascultare</string>
|
||||
<string name="playback_pref_sum">Controlul căștilor, Sari peste un interval de timp, Coadă</string>
|
||||
<string name="downloads_pref">Descărcări</string>
|
||||
|
|
|
@ -372,8 +372,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Отметка «Прослушанное» до окончания</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Сохранять выпуски, которые были пропущены</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Сохранять пропущенные выпуски</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Хранить выпуски, добавленные в избранное</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Хранить избранные выпуски</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Воспроизведение</string>
|
||||
<string name="playback_pref_sum">Кнопки гарнитуры, шаг перемотки, очередь</string>
|
||||
<string name="downloads_pref">Загрузки</string>
|
||||
|
|
|
@ -391,8 +391,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Inteligentné označovanie ako vypočuté</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Neodstraňovať epizódy pri ich preskočení</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Nemazať preskočené epizódy</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Ponechať epizódy, ktoré sú označené ako obľúbené</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Ponechať obľúbené epizódy</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Prehrávanie</string>
|
||||
<string name="playback_pref_sum">Ovládanie tlačidlami slúchadiel, preskakovanie, poradie</string>
|
||||
<string name="downloads_pref">Sťahovanie</string>
|
||||
|
|
|
@ -367,8 +367,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Smart markera som spelad</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Ta inte bort episoder när de hoppas över</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Behåll överhoppade episoder</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Behåll episoder när de är favoritmarkerade</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Behåll favoritepisoder</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Uppspelning</string>
|
||||
<string name="playback_pref_sum">Hörlurskontroller, Överhoppningsintervaller, Kö</string>
|
||||
<string name="downloads_pref">Nedladdningar</string>
|
||||
|
|
|
@ -353,8 +353,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Oynatıldı olarak işaretle</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Bölümler atlandığında tutmaya devam et</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Atlanan bölümleri sakla</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Bölümler favori olarak işaretlendiğinde tut</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Favori bölümleri tut</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Çalma</string>
|
||||
<string name="playback_pref_sum">Kulaklık kontrolleri, Atlama aralığı ve Kuyruk ayarları</string>
|
||||
<string name="downloads_pref">İndirilenler</string>
|
||||
|
|
|
@ -391,8 +391,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">Розумне позначення прослуханих епізодів</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Зберігати пропущені епізоди при програванні </string>
|
||||
<string name="pref_skip_keeps_episodes_title">Зберігати пропущені епізоди</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Зберігати епізоди що помічені як улюблені</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Зберігати улюблені епізоди</string>
|
||||
|
||||
|
||||
<string name="playback_pref">Відтворення</string>
|
||||
<string name="playback_pref_sum">Керування навушниками, Пропуск інтервалів, Черга</string>
|
||||
<string name="downloads_pref">Завантаження</string>
|
||||
|
|
|
@ -359,8 +359,8 @@
|
|||
<string name="pref_smart_mark_as_played_title">智能标记为已播放</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">当剧集被跳过时保留它们</string>
|
||||
<string name="pref_skip_keeps_episodes_title">保留跳过的节目</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">标记节目为收藏时保留节目</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">保留收藏的节目</string>
|
||||
|
||||
|
||||
<string name="playback_pref">播放</string>
|
||||
<string name="playback_pref_sum">耳机控制、跳过间隔、排队</string>
|
||||
<string name="downloads_pref">下载</string>
|
||||
|
|
|
@ -323,6 +323,8 @@
|
|||
<string name="in_progress">In progress</string>
|
||||
<string name="skipped">Skipped</string>
|
||||
<string name="played">Played</string>
|
||||
<string name="again">Again</string>
|
||||
<string name="forever">Forever</string>
|
||||
<string name="ignored">Ignored</string>
|
||||
<string name="remove_from_favorite_label">Remove from favorites</string>
|
||||
<string name="visit_website_label">Visit website</string>
|
||||
|
@ -499,8 +501,9 @@
|
|||
<string name="pref_smart_mark_as_played_title">Smart mark as played</string>
|
||||
<string name="pref_skip_keeps_episodes_sum">Keep episodes when they are skipped</string>
|
||||
<string name="pref_skip_keeps_episodes_title">Keep skipped episodes</string>
|
||||
<string name="pref_favorite_keeps_episodes_sum">Keep episodes when they are marked favorite</string>
|
||||
<string name="pref_favorite_keeps_episodes_title">Keep favorite episodes</string>
|
||||
|
||||
<string name="pref_keeps_important_episodes_sum">Keep episodes when they are marked Super or set as Again or Forever.</string>
|
||||
<string name="pref_keeps_important_episodes_title">Keep important episodes</string>
|
||||
<string name="playback_pref">Playback</string>
|
||||
<string name="playback_pref_sum">Headphone controls, Skip intervals, Queue</string>
|
||||
<string name="downloads_pref">Downloads</string>
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
android:key="prefFavoriteKeepsEpisode"
|
||||
android:summary="@string/pref_favorite_keeps_episodes_sum"
|
||||
android:title="@string/pref_favorite_keeps_episodes_title"/>
|
||||
android:summary="@string/pref_keeps_important_episodes_sum"
|
||||
android:title="@string/pref_keeps_important_episodes_title"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
|
|
|
@ -114,13 +114,13 @@
|
|||
android:key="prefFollowQueue"
|
||||
android:summary="@string/pref_followQueue_sum"
|
||||
android:title="@string/pref_followQueue_title"/>
|
||||
<ac.mdiq.podcini.preferences.MaterialListPreference
|
||||
android:defaultValue="30"
|
||||
android:entries="@array/smart_mark_as_played_values"
|
||||
android:entryValues="@array/smart_mark_as_played_values"
|
||||
android:key="prefSmartMarkAsPlayedSecs"
|
||||
android:summary="@string/pref_smart_mark_as_played_sum"
|
||||
android:title="@string/pref_smart_mark_as_played_title"/>
|
||||
<!-- <ac.mdiq.podcini.preferences.MaterialListPreference-->
|
||||
<!-- android:defaultValue="30"-->
|
||||
<!-- android:entries="@array/smart_mark_as_played_values"-->
|
||||
<!-- android:entryValues="@array/smart_mark_as_played_values"-->
|
||||
<!-- android:key="prefSmartMarkAsPlayedSecs"-->
|
||||
<!-- android:summary="@string/pref_smart_mark_as_played_sum"-->
|
||||
<!-- android:title="@string/pref_smart_mark_as_played_title"/>-->
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:enabled="true"
|
||||
|
|
11
changelog.md
11
changelog.md
|
@ -1,3 +1,14 @@
|
|||
# 6.13.2
|
||||
|
||||
* replaced the setting of prefSmartMarkAsPlayedSecs by an adaptive internal val smartMarkAsPlayedPercent = 95
|
||||
* if the episode is played to over 95% of its duration, it's considered played
|
||||
* reworked the chain actions of set play state, remove from queue, and delete media
|
||||
* fixed the issue of fully played episode being marked as Skipped
|
||||
* fixed speed indicator not updating issue in PlayerUI
|
||||
* added Again and Forever states to episode filter
|
||||
* in Settings, "Keep favorite episode" is changed to "Keep important episodes", and it applies to episodes set as Super, Again, or Forever
|
||||
* some reduction in access to Preferences files for improved efficiency
|
||||
|
||||
# 6.13.1
|
||||
|
||||
* fixed the misbehavior (from 6.13.0) of rewind/forward/progress in PlayerUI
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
Version 6.13.1
|
||||
|
||||
* replaced the setting of prefSmartMarkAsPlayedSecs by an adaptive internal val smartMarkAsPlayedPercent = 95
|
||||
* if the episode is played to over 95% of its duration, it's considered played
|
||||
* reworked the chain actions of set play state, remove from queue, and delete media
|
||||
* fixed the issue of fully played episode being marked as Skipped
|
||||
* fixed speed indicator not updating issue in PlayerUI
|
||||
* added Again and Forever states to episode filter
|
||||
* in Settings, "Keep favorite episode" is changed to "Keep important episodes", and it applies to episodes set as Super, Again, or Forever
|
||||
* some reduction in access to Preferences files for improved efficiency
|
Loading…
Reference in New Issue