diff --git a/README.md b/README.md
index a85af7d1..2d1c42d3 100644
--- a/README.md
+++ b/README.md
@@ -14,13 +14,15 @@ Version 4.1 brings a more convenient player control and tags enhancements, while
## Screenshots
-
+
-
+
-
+
-
+
+
+
## Changelogs
diff --git a/app/build.gradle b/app/build.gradle
index e833e22e..91a6be22 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -149,8 +149,8 @@ android {
// Version code schema (not used):
// "1.2.3-beta4" -> 1020304
// "1.2.3" -> 1020395
- versionCode 3020110
- versionName "4.2.7"
+ versionCode 3020111
+ versionName "4.3.0"
def commit = ""
try {
diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearchResult.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearchResult.kt
index 0ea216e7..adcc9997 100644
--- a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearchResult.kt
+++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearchResult.kt
@@ -4,28 +4,21 @@ import ac.mdiq.podcini.net.sync.gpoddernet.model.GpodnetPodcast
import de.mfietz.fyydlin.SearchHit
import org.json.JSONException
import org.json.JSONObject
+import java.text.SimpleDateFormat
+import java.util.*
class PodcastSearchResult private constructor(
- /**
- * The name of the podcast
- */
val title: String,
- /**
- * URL of the podcast image
- */
val imageUrl: String?,
- /**
- * URL of the podcast feed
- */
val feedUrl: String?,
- /**
- * artistName of the podcast feed
- */
- val author: String?
+ val author: String?,
+ val count: Int?,
+ val update: String?,
+ val source: String
) {
companion object {
fun dummy(): PodcastSearchResult {
- return PodcastSearchResult("", "", "", "")
+ return PodcastSearchResult("", "", "", "", 0, "", "dummy")
}
/**
@@ -39,7 +32,7 @@ class PodcastSearchResult private constructor(
val imageUrl: String? = json.optString("artworkUrl100").takeIf { it.isNotEmpty() }
val feedUrl: String? = json.optString("feedUrl").takeIf { it.isNotEmpty() }
val author: String? = json.optString("artistName").takeIf { it.isNotEmpty() }
- return PodcastSearchResult(title, imageUrl, feedUrl, author)
+ return PodcastSearchResult(title, imageUrl, feedUrl, author, null, null, "Itunes")
}
/**
@@ -71,21 +64,15 @@ class PodcastSearchResult private constructor(
} catch (e: Exception) {
// Some feeds have empty artist
}
- return PodcastSearchResult(title, imageUrl, feedUrl, author)
+ return PodcastSearchResult(title, imageUrl, feedUrl, author, null, null, "Toplist")
}
fun fromFyyd(searchHit: SearchHit): PodcastSearchResult {
- return PodcastSearchResult(searchHit.title,
- searchHit.thumbImageURL,
- searchHit.xmlUrl,
- searchHit.author)
+ return PodcastSearchResult(searchHit.title, searchHit.thumbImageURL, searchHit.xmlUrl, searchHit.author, null, null, "Fyyd")
}
fun fromGpodder(searchHit: GpodnetPodcast): PodcastSearchResult {
- return PodcastSearchResult(searchHit.title,
- searchHit.logoUrl,
- searchHit.url,
- searchHit.author)
+ return PodcastSearchResult(searchHit.title, searchHit.logoUrl, searchHit.url, searchHit.author, null, null, "GPodder")
}
fun fromPodcastIndex(json: JSONObject): PodcastSearchResult {
@@ -93,7 +80,15 @@ class PodcastSearchResult private constructor(
val imageUrl: String? = json.optString("image").takeIf { it.isNotEmpty() }
val feedUrl: String? = json.optString("url").takeIf { it.isNotEmpty() }
val author: String? = json.optString("author").takeIf { it.isNotEmpty() }
- return PodcastSearchResult(title, imageUrl, feedUrl, author)
+ var count: Int? = json.optInt("episodeCount", -1)
+ if (count != null && count < 0) count = null
+ val updateInt: Int = json.optInt("lastUpdateTime", -1)
+ var update: String? = null
+ if (updateInt > 0) {
+ val format = SimpleDateFormat("yyyy-MM-dd", Locale.US)
+ update = format.format(updateInt.toLong() * 1000)
+ }
+ return PodcastSearchResult(title, imageUrl, feedUrl, author, count, update, "PodcastIndex")
}
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt b/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt
index 019bc1fb..44329526 100644
--- a/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt
+++ b/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt
@@ -92,8 +92,7 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen
@JvmStatic
fun init(context: Context) {
instance = PlaybackPreferences()
- prefs = PreferenceManager.getDefaultSharedPreferences(
- context!!)
+ prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs?.registerOnSharedPreferenceChangeListener(instance)
}
@@ -143,10 +142,9 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen
editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA_TYPE, playable.getPlayableType().toLong())
editor.putBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, playable.getMediaType() == MediaType.VIDEO)
if (playable is FeedMedia) {
- val feedMedia = playable
- val itemId = feedMedia.getItem()?.feed?.id
+ val itemId = playable.getItem()?.feed?.id
if (itemId != null) editor.putLong(PREF_CURRENTLY_PLAYING_FEED_ID, itemId)
- editor.putLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, feedMedia.id)
+ editor.putLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, playable.id)
} else {
editor.putLong(PREF_CURRENTLY_PLAYING_FEED_ID, NO_MEDIA_PLAYING)
editor.putLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING)
diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt b/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt
index fef36da6..1f5fe9b5 100644
--- a/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt
+++ b/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt
@@ -1,5 +1,11 @@
package ac.mdiq.podcini.preferences
+import ac.mdiq.podcini.storage.model.download.ProxyConfig
+import ac.mdiq.podcini.storage.model.feed.FeedCounter
+import ac.mdiq.podcini.storage.model.feed.FeedPreferences.NewEpisodesAction
+import ac.mdiq.podcini.storage.model.feed.SortOrder
+import ac.mdiq.podcini.storage.model.feed.SubscriptionsFilter
+import ac.mdiq.podcini.storage.model.playback.MediaType
import android.content.Context
import android.content.SharedPreferences
import android.os.Build
@@ -9,12 +15,6 @@ import android.view.KeyEvent
import androidx.annotation.VisibleForTesting
import androidx.core.app.NotificationCompat
import androidx.preference.PreferenceManager
-import ac.mdiq.podcini.storage.model.download.ProxyConfig
-import ac.mdiq.podcini.storage.model.feed.FeedCounter
-import ac.mdiq.podcini.storage.model.feed.FeedPreferences.NewEpisodesAction
-import ac.mdiq.podcini.storage.model.feed.SortOrder
-import ac.mdiq.podcini.storage.model.feed.SubscriptionsFilter
-import ac.mdiq.podcini.storage.model.playback.MediaType
import org.json.JSONArray
import org.json.JSONException
import java.io.File
@@ -847,7 +847,7 @@ object UserPreferences {
// prefs.edit().putString(PREF_INBOX_SORTED_ORDER, "" + sortOrder!!.code).apply()
// }
- @JvmStatic
+// @JvmStatic
var subscriptionsFilter: SubscriptionsFilter
get() {
val value = prefs.getString(PREF_FILTER_FEED, "")
diff --git a/app/src/main/java/ac/mdiq/podcini/service/playback/ExoPlayerWrapper.kt b/app/src/main/java/ac/mdiq/podcini/service/playback/ExoPlayerWrapper.kt
index f8af723c..89649a83 100644
--- a/app/src/main/java/ac/mdiq/podcini/service/playback/ExoPlayerWrapper.kt
+++ b/app/src/main/java/ac/mdiq/podcini/service/playback/ExoPlayerWrapper.kt
@@ -155,6 +155,7 @@ class ExoPlayerWrapper internal constructor(private val context: Context) {
@Throws(IllegalStateException::class)
fun prepare() {
+ if (mediaSource == null) return
exoPlayer.setMediaSource(mediaSource!!, false)
exoPlayer.prepare()
}
@@ -320,18 +321,12 @@ class ExoPlayerWrapper internal constructor(private val context: Context) {
val videoWidth: Int
get() {
- if (exoPlayer.videoFormat == null) {
- return 0
- }
- return exoPlayer.videoFormat!!.width
+ return exoPlayer.videoFormat?.width ?: 0
}
val videoHeight: Int
get() {
- if (exoPlayer.videoFormat == null) {
- return 0
- }
- return exoPlayer.videoFormat!!.height
+ return exoPlayer.videoFormat?.height ?: 0
}
fun setOnBufferingUpdateListener(bufferingUpdateListener: Consumer?) {
diff --git a/app/src/main/java/ac/mdiq/podcini/service/playback/LocalPSMP.kt b/app/src/main/java/ac/mdiq/podcini/service/playback/LocalPSMP.kt
index b3f140d3..96cd441a 100644
--- a/app/src/main/java/ac/mdiq/podcini/service/playback/LocalPSMP.kt
+++ b/app/src/main/java/ac/mdiq/podcini/service/playback/LocalPSMP.kt
@@ -162,22 +162,27 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia
callback.onMediaChanged(false)
// TODO: speed
setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence)
- if (stream) {
- if (media!!.getStreamUrl() != null) {
- if (playable is FeedMedia && playable.getItem()?.feed?.preferences != null) {
- val preferences = playable.getItem()!!.feed!!.preferences!!
- mediaPlayer?.setDataSource(
- media!!.getStreamUrl()!!,
- preferences.username,
- preferences.password)
- } else {
- mediaPlayer?.setDataSource(media!!.getStreamUrl()!!)
+ when {
+ stream -> {
+ val streamurl = media!!.getStreamUrl()
+ if (streamurl != null) {
+ if (playable is FeedMedia && playable.getItem()?.feed?.preferences != null) {
+ val preferences = playable.getItem()!!.feed!!.preferences!!
+ mediaPlayer?.setDataSource(
+ streamurl,
+ preferences.username,
+ preferences.password)
+ } else {
+ mediaPlayer?.setDataSource(streamurl)
+ }
}
}
- } else if (media!!.getLocalMediaUrl() != null && File(media!!.getLocalMediaUrl()!!).canRead()) {
- mediaPlayer?.setDataSource(media!!.getLocalMediaUrl()!!)
- } else {
- throw IOException("Unable to read local file " + media!!.getLocalMediaUrl())
+ else -> {
+ val localMediaurl = media!!.getLocalMediaUrl()
+ if (localMediaurl != null && File(localMediaurl).canRead()) {
+ mediaPlayer?.setDataSource(localMediaurl)
+ } else throw IOException("Unable to read local file $localMediaurl")
+ }
}
val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
if (uiModeManager.currentModeType != Configuration.UI_MODE_TYPE_CAR) {
diff --git a/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackService.kt b/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackService.kt
index 561fa25a..ec0f2bb0 100644
--- a/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackService.kt
+++ b/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackService.kt
@@ -1,39 +1,19 @@
package ac.mdiq.podcini.service.playback
import ac.mdiq.podcini.R
-import android.Manifest
-import android.annotation.SuppressLint
-import android.app.NotificationManager
-import android.app.PendingIntent
-import android.app.UiModeManager
-import android.bluetooth.BluetoothA2dp
-import android.content.*
-import android.content.pm.PackageManager
-import android.content.res.Configuration
-import android.media.AudioManager
-import android.net.Uri
-import android.os.*
-import android.service.quicksettings.TileService
-import android.support.v4.media.MediaBrowserCompat
-import android.support.v4.media.MediaDescriptionCompat
-import android.support.v4.media.MediaMetadataCompat
-import android.support.v4.media.session.MediaSessionCompat
-import android.support.v4.media.session.PlaybackStateCompat
-import android.text.TextUtils
-import android.util.Log
-import android.util.Pair
-import android.view.KeyEvent
-import android.view.SurfaceHolder
-import android.view.ViewConfiguration
-import android.webkit.URLUtil
-import android.widget.Toast
-import androidx.annotation.DrawableRes
-import androidx.annotation.StringRes
-import androidx.core.app.ActivityCompat
-import androidx.core.app.NotificationCompat
-import androidx.core.app.NotificationManagerCompat
-import androidx.media.MediaBrowserServiceCompat
-import androidx.media3.common.util.UnstableApi
+import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
+import ac.mdiq.podcini.playback.PlayableUtils.saveCurrentPosition
+import ac.mdiq.podcini.playback.PlaybackServiceStarter
+import ac.mdiq.podcini.playback.base.PlaybackServiceMediaPlayer
+import ac.mdiq.podcini.playback.base.PlaybackServiceMediaPlayer.PSMPCallback
+import ac.mdiq.podcini.playback.base.PlaybackServiceMediaPlayer.PSMPInfo
+import ac.mdiq.podcini.playback.base.PlayerStatus
+import ac.mdiq.podcini.playback.cast.CastPsmp
+import ac.mdiq.podcini.playback.cast.CastStateListener
+import ac.mdiq.podcini.playback.event.BufferUpdateEvent
+import ac.mdiq.podcini.playback.event.PlaybackPositionEvent
+import ac.mdiq.podcini.playback.event.PlaybackServiceEvent
+import ac.mdiq.podcini.playback.event.SleepTimerUpdatedEvent
import ac.mdiq.podcini.preferences.PlaybackPreferences
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.clearCurrentlyPlayingTemporaryPlaybackSpeed
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.createInstanceFromPreferences
@@ -49,38 +29,6 @@ import ac.mdiq.podcini.preferences.SleepTimerPreferences.autoEnableFrom
import ac.mdiq.podcini.preferences.SleepTimerPreferences.autoEnableTo
import ac.mdiq.podcini.preferences.SleepTimerPreferences.isInTimeRange
import ac.mdiq.podcini.preferences.SleepTimerPreferences.timerMillis
-import ac.mdiq.podcini.receiver.MediaButtonReceiver
-import ac.mdiq.podcini.service.QuickSettingsTileService
-import ac.mdiq.podcini.service.playback.PlaybackServiceTaskManager.PSTMCallback
-import ac.mdiq.podcini.storage.DBReader
-import ac.mdiq.podcini.storage.DBWriter
-import ac.mdiq.podcini.storage.FeedSearcher
-import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
-import ac.mdiq.podcini.util.ChapterUtils.getCurrentChapterIndex
-import ac.mdiq.podcini.util.FeedItemUtil.hasAlmostEnded
-import ac.mdiq.podcini.util.FeedUtil.shouldAutoDeleteItemsOnThatFeed
-import ac.mdiq.podcini.util.IntentUtils.sendLocalBroadcast
-import ac.mdiq.podcini.util.NetworkUtils.isStreamingAllowed
-import ac.mdiq.podcini.ui.gui.NotificationUtils
-import ac.mdiq.podcini.playback.PlayableUtils.saveCurrentPosition
-import ac.mdiq.podcini.playback.PlaybackServiceStarter
-import ac.mdiq.podcini.ui.widget.WidgetUpdater.WidgetState
-import ac.mdiq.podcini.playback.event.BufferUpdateEvent
-import ac.mdiq.podcini.playback.event.PlaybackPositionEvent
-import ac.mdiq.podcini.playback.event.PlaybackServiceEvent
-import ac.mdiq.podcini.playback.event.SleepTimerUpdatedEvent
-import ac.mdiq.podcini.util.event.settings.SpeedPresetChangedEvent
-import ac.mdiq.podcini.util.event.settings.VolumeAdaptionChangedEvent
-import ac.mdiq.podcini.storage.model.feed.*
-import ac.mdiq.podcini.storage.model.feed.FeedPreferences.AutoDeleteAction
-import ac.mdiq.podcini.storage.model.playback.MediaType
-import ac.mdiq.podcini.storage.model.playback.Playable
-import ac.mdiq.podcini.playback.base.PlaybackServiceMediaPlayer
-import ac.mdiq.podcini.playback.base.PlaybackServiceMediaPlayer.PSMPCallback
-import ac.mdiq.podcini.playback.base.PlaybackServiceMediaPlayer.PSMPInfo
-import ac.mdiq.podcini.playback.base.PlayerStatus
-import ac.mdiq.podcini.playback.cast.CastPsmp
-import ac.mdiq.podcini.playback.cast.CastStateListener
import ac.mdiq.podcini.preferences.UserPreferences.allEpisodesSortOrder
import ac.mdiq.podcini.preferences.UserPreferences.downloadsSortedOrder
import ac.mdiq.podcini.preferences.UserPreferences.fastForwardSecs
@@ -103,10 +51,61 @@ import ac.mdiq.podcini.preferences.UserPreferences.showNextChapterOnFullNotifica
import ac.mdiq.podcini.preferences.UserPreferences.showPlaybackSpeedOnFullNotification
import ac.mdiq.podcini.preferences.UserPreferences.showSkipOnFullNotification
import ac.mdiq.podcini.preferences.UserPreferences.videoPlaybackSpeed
-import ac.mdiq.podcini.service.download.NewEpisodesNotification
+import ac.mdiq.podcini.receiver.MediaButtonReceiver
+import ac.mdiq.podcini.service.QuickSettingsTileService
+import ac.mdiq.podcini.service.playback.PlaybackServiceTaskManager.PSTMCallback
+import ac.mdiq.podcini.storage.DBReader
+import ac.mdiq.podcini.storage.DBWriter
+import ac.mdiq.podcini.storage.FeedSearcher
+import ac.mdiq.podcini.storage.model.feed.*
+import ac.mdiq.podcini.storage.model.feed.FeedPreferences.AutoDeleteAction
+import ac.mdiq.podcini.storage.model.playback.MediaType
+import ac.mdiq.podcini.storage.model.playback.Playable
import ac.mdiq.podcini.ui.appstartintent.MainActivityStarter
import ac.mdiq.podcini.ui.appstartintent.VideoPlayerActivityStarter
+import ac.mdiq.podcini.ui.gui.NotificationUtils
+import ac.mdiq.podcini.ui.widget.WidgetUpdater.WidgetState
+import ac.mdiq.podcini.util.ChapterUtils.getCurrentChapterIndex
+import ac.mdiq.podcini.util.FeedItemUtil.hasAlmostEnded
+import ac.mdiq.podcini.util.FeedUtil.shouldAutoDeleteItemsOnThatFeed
+import ac.mdiq.podcini.util.IntentUtils.sendLocalBroadcast
+import ac.mdiq.podcini.util.NetworkUtils.isStreamingAllowed
+import ac.mdiq.podcini.util.event.settings.SpeedPresetChangedEvent
+import ac.mdiq.podcini.util.event.settings.VolumeAdaptionChangedEvent
+import android.Manifest
+import android.annotation.SuppressLint
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.UiModeManager
+import android.bluetooth.BluetoothA2dp
+import android.content.*
+import android.content.pm.PackageManager
+import android.content.res.Configuration
+import android.media.AudioManager
+import android.net.Uri
+import android.os.*
import android.os.Build.VERSION_CODES
+import android.service.quicksettings.TileService
+import android.support.v4.media.MediaBrowserCompat
+import android.support.v4.media.MediaDescriptionCompat
+import android.support.v4.media.MediaMetadataCompat
+import android.support.v4.media.session.MediaSessionCompat
+import android.support.v4.media.session.PlaybackStateCompat
+import android.text.TextUtils
+import android.util.Log
+import android.util.Pair
+import android.view.KeyEvent
+import android.view.SurfaceHolder
+import android.view.ViewConfiguration
+import android.webkit.URLUtil
+import android.widget.Toast
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import androidx.core.app.ActivityCompat
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import androidx.media.MediaBrowserServiceCompat
+import androidx.media3.common.util.UnstableApi
import io.reactivex.*
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -389,28 +388,35 @@ class PlaybackService : MediaBrowserServiceCompat() {
}
val feedItems: List
- if (parentId == resources.getString(R.string.queue_label)) {
- feedItems = DBReader.getQueue()
- } else if (parentId == resources.getString(R.string.downloads_label)) {
- feedItems = DBReader.getEpisodes(0, MAX_ANDROID_AUTO_EPISODES_PER_FEED,
- FeedItemFilter(FeedItemFilter.DOWNLOADED), downloadsSortedOrder)
- } else if (parentId == resources.getString(R.string.episodes_label)) {
- feedItems = DBReader.getEpisodes(0, MAX_ANDROID_AUTO_EPISODES_PER_FEED,
- FeedItemFilter(FeedItemFilter.UNPLAYED), allEpisodesSortOrder)
- } else if (parentId.startsWith("FeedId:")) {
- val feedId = parentId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1].toLong()
- val feed = DBReader.getFeed(feedId)
- feedItems = DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(), feed!!.sortOrder)
- } else if (parentId == getString(R.string.current_playing_episode)) {
- val playable = createInstanceFromPreferences(this)
- if (playable is FeedMedia) {
- feedItems = listOf(playable.getItem())
- } else {
+ when {
+ parentId == resources.getString(R.string.queue_label) -> {
+ feedItems = DBReader.getQueue()
+ }
+ parentId == resources.getString(R.string.downloads_label) -> {
+ feedItems = DBReader.getEpisodes(0, MAX_ANDROID_AUTO_EPISODES_PER_FEED,
+ FeedItemFilter(FeedItemFilter.DOWNLOADED), downloadsSortedOrder)
+ }
+ parentId == resources.getString(R.string.episodes_label) -> {
+ feedItems = DBReader.getEpisodes(0, MAX_ANDROID_AUTO_EPISODES_PER_FEED,
+ FeedItemFilter(FeedItemFilter.UNPLAYED), allEpisodesSortOrder)
+ }
+ parentId.startsWith("FeedId:") -> {
+ val feedId = parentId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1].toLong()
+ val feed = DBReader.getFeed(feedId)
+ feedItems = if (feed != null) DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(), feed.sortOrder) else listOf()
+ }
+ parentId == getString(R.string.current_playing_episode) -> {
+ val playable = createInstanceFromPreferences(this)
+ if (playable is FeedMedia) {
+ feedItems = listOf(playable.getItem())
+ } else {
+ return null
+ }
+ }
+ else -> {
+ Log.e(TAG, "Parent ID not found: $parentId")
return null
}
- } else {
- Log.e(TAG, "Parent ID not found: $parentId")
- return null
}
var count = 0
for (feedItem in feedItems) {
@@ -510,7 +516,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
return
}
- val preferences = playable.getItem()!!.feed?.preferences
+ val preferences = playable.getItem()?.feed?.preferences
val skipIntro = preferences?.feedSkipIntro ?: 0
val context = applicationContext
@@ -725,12 +731,12 @@ class PlaybackService : MediaBrowserServiceCompat() {
}
private fun startPlaying(playable: Playable?, allowStreamThisTime: Boolean) {
- val localFeed = URLUtil.isContentUrl(playable!!.getStreamUrl())
+ if (playable == null) return
+
+ val localFeed = URLUtil.isContentUrl(playable.getStreamUrl())
val stream = !playable.localFileAvailable() || localFeed
if (stream && !localFeed && !isStreamingAllowed && !allowStreamThisTime) {
- displayStreamingNotAllowedNotification(
- PlaybackServiceStarter(this, playable)
- .intent)
+ displayStreamingNotAllowedNotification(PlaybackServiceStarter(this, playable).intent)
writeNoMediaPlaying()
stateManager.stopService()
return
@@ -784,60 +790,63 @@ class PlaybackService : MediaBrowserServiceCompat() {
override fun statusChanged(newInfo: PSMPInfo?) {
currentMediaType = mediaPlayer?.getCurrentMediaType() ?: MediaType.UNKNOWN
- updateMediaSession(newInfo!!.playerStatus)
- when (newInfo.playerStatus) {
- PlayerStatus.INITIALIZED -> {
- if (mediaPlayer != null) {
- writeMediaPlaying(mediaPlayer!!.pSMPInfo.playable, mediaPlayer!!.pSMPInfo.playerStatus)
+ updateMediaSession(newInfo?.playerStatus)
+ if (newInfo != null) {
+ when (newInfo.playerStatus) {
+ PlayerStatus.INITIALIZED -> {
+ if (mediaPlayer != null) {
+ writeMediaPlaying(mediaPlayer!!.pSMPInfo.playable, mediaPlayer!!.pSMPInfo.playerStatus)
+ }
+ updateNotificationAndMediaSession(newInfo.playable)
}
- updateNotificationAndMediaSession(newInfo.playable)
- }
- PlayerStatus.PREPARED -> {
- if (mediaPlayer != null) {
- writeMediaPlaying(mediaPlayer!!.pSMPInfo.playable, mediaPlayer!!.pSMPInfo.playerStatus)
+ PlayerStatus.PREPARED -> {
+ if (mediaPlayer != null) {
+ writeMediaPlaying(mediaPlayer!!.pSMPInfo.playable, mediaPlayer!!.pSMPInfo.playerStatus)
+ }
+ taskManager.startChapterLoader(newInfo.playable!!)
}
- taskManager.startChapterLoader(newInfo.playable!!)
- }
- PlayerStatus.PAUSED -> {
- updateNotificationAndMediaSession(newInfo.playable)
- if (!isCasting) {
- stateManager.stopForeground(!isPersistNotify)
- }
- cancelPositionObserver()
- if (mediaPlayer != null) writePlayerStatus(mediaPlayer!!.playerStatus)
- }
- PlayerStatus.STOPPED -> {}
- PlayerStatus.PLAYING -> {
- if (mediaPlayer != null) writePlayerStatus(mediaPlayer!!.playerStatus)
- saveCurrentPosition(true, null, Playable.INVALID_TIME)
- recreateMediaSessionIfNeeded()
- updateNotificationAndMediaSession(newInfo.playable)
- setupPositionObserver()
- stateManager.validStartCommandWasReceived()
- stateManager.startForeground(R.id.notification_playing, notificationBuilder.build())
- // set sleep timer if auto-enabled
- var autoEnableByTime = true
- val fromSetting = autoEnableFrom()
- val toSetting = autoEnableTo()
- if (fromSetting != toSetting) {
- val now: Calendar = GregorianCalendar()
- now.timeInMillis = System.currentTimeMillis()
- val currentHour = now[Calendar.HOUR_OF_DAY]
- autoEnableByTime = isInTimeRange(fromSetting, toSetting, currentHour)
+ PlayerStatus.PAUSED -> {
+ updateNotificationAndMediaSession(newInfo.playable)
+ if (!isCasting) {
+ stateManager.stopForeground(!isPersistNotify)
+ }
+ cancelPositionObserver()
+ if (mediaPlayer != null) writePlayerStatus(mediaPlayer!!.playerStatus)
}
+ PlayerStatus.STOPPED -> {}
+ PlayerStatus.PLAYING -> {
+ if (mediaPlayer != null) writePlayerStatus(mediaPlayer!!.playerStatus)
+ saveCurrentPosition(true, null, Playable.INVALID_TIME)
+ recreateMediaSessionIfNeeded()
+ updateNotificationAndMediaSession(newInfo.playable)
+ setupPositionObserver()
+ stateManager.validStartCommandWasReceived()
+ stateManager.startForeground(R.id.notification_playing, notificationBuilder.build())
+ // set sleep timer if auto-enabled
+ var autoEnableByTime = true
+ val fromSetting = autoEnableFrom()
+ val toSetting = autoEnableTo()
+ if (fromSetting != toSetting) {
+ val now: Calendar = GregorianCalendar()
+ now.timeInMillis = System.currentTimeMillis()
+ val currentHour = now[Calendar.HOUR_OF_DAY]
+ autoEnableByTime = isInTimeRange(fromSetting, toSetting, currentHour)
+ }
- if (newInfo.oldPlayerStatus != null && newInfo.oldPlayerStatus != PlayerStatus.SEEKING && autoEnable() && autoEnableByTime && !sleepTimerActive()) {
- setSleepTimer(timerMillis())
- EventBus.getDefault().post(ac.mdiq.podcini.util.event.MessageEvent(getString(R.string.sleep_timer_enabled_label),
- { disableSleepTimer() }, getString(R.string.undo)))
+ if (newInfo.oldPlayerStatus != null && newInfo.oldPlayerStatus != PlayerStatus.SEEKING && autoEnable() && autoEnableByTime && !sleepTimerActive()) {
+ setSleepTimer(timerMillis())
+ EventBus.getDefault()
+ .post(ac.mdiq.podcini.util.event.MessageEvent(getString(R.string.sleep_timer_enabled_label),
+ { disableSleepTimer() }, getString(R.string.undo)))
+ }
+ loadQueueForMediaSession()
}
- loadQueueForMediaSession()
+ PlayerStatus.ERROR -> {
+ writeNoMediaPlaying()
+ stateManager.stopService()
+ }
+ else -> {}
}
- PlayerStatus.ERROR -> {
- writeNoMediaPlaying()
- stateManager.stopService()
- }
- else -> {}
}
if (Build.VERSION.SDK_INT >= VERSION_CODES.N) {
TileService.requestListeningState(applicationContext,
@@ -1059,7 +1068,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
}
var autoSkipped = false
- if (autoSkippedFeedMediaId != null && autoSkippedFeedMediaId == item!!.identifyingValue) {
+ if (autoSkippedFeedMediaId != null && autoSkippedFeedMediaId == item?.identifyingValue) {
autoSkippedFeedMediaId = null
autoSkipped = true
}
@@ -1136,7 +1145,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
toast.show()
this.autoSkippedFeedMediaId = feedMedia.getItem()!!.identifyingValue
- mediaPlayer!!.skip()
+ mediaPlayer?.skip()
}
}
@@ -1201,7 +1210,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
}
if (showNextChapterOnFullNotification()) {
- if (playable != null && playable!!.getChapters().isNotEmpty()) {
+ if (!playable?.getChapters().isNullOrEmpty()) {
sessionState.addCustomAction(
PlaybackStateCompat.CustomAction.Builder(
CUSTOM_ACTION_NEXT_CHAPTER,
@@ -1220,9 +1229,10 @@ class PlaybackService : MediaBrowserServiceCompat() {
)
}
- WearMediaSession.mediaSessionSetExtraForWear(mediaSession!!)
-
- mediaSession!!.setPlaybackState(sessionState.build())
+ if (mediaSession != null) {
+ WearMediaSession.mediaSessionSetExtraForWear(mediaSession!!)
+ mediaSession!!.setPlaybackState(sessionState.build())
+ }
}
private fun updateNotificationAndMediaSession(p: Playable?) {
@@ -1252,9 +1262,9 @@ class PlaybackService : MediaBrowserServiceCompat() {
val m = p
if (m.getItem() != null) {
val item = m.getItem()
- if (item!!.imageUrl != null) {
+ if (item?.imageUrl != null) {
iconUri = item.imageUrl
- } else if (item.feed != null) {
+ } else if (item?.feed != null) {
iconUri = item.feed!!.imageUrl
}
}
@@ -1289,9 +1299,8 @@ class PlaybackService : MediaBrowserServiceCompat() {
@Synchronized
private fun setupNotification(playable: Playable?) {
Log.d(TAG, "setupNotification")
- if (playableIconLoaderThread != null) {
- playableIconLoaderThread!!.interrupt()
- }
+ playableIconLoaderThread?.interrupt()
+
if (playable == null || mediaPlayer == null) {
Log.d(TAG, "setupNotification: playable=$playable")
Log.d(TAG, "setupNotification: mediaPlayer=$mediaPlayer")
@@ -1303,7 +1312,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
val playerStatus = mediaPlayer!!.playerStatus
notificationBuilder.setPlayable(playable)
- notificationBuilder.setMediaSessionToken(mediaSession!!.sessionToken)
+ if (mediaSession != null) notificationBuilder.setMediaSessionToken(mediaSession!!.sessionToken)
notificationBuilder.playerStatus = playerStatus
notificationBuilder.updatePosition(currentPosition, currentPlaybackSpeed)
@@ -1332,7 +1341,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
updateMediaSessionMetadata(playable)
}
}
- playableIconLoaderThread!!.start()
+ playableIconLoaderThread?.start()
}
}
@@ -1358,7 +1367,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
duration = playable?.getDuration() ?: Playable.INVALID_TIME
}
if (position != Playable.INVALID_TIME && duration != Playable.INVALID_TIME && playable != null) {
- Log.d(TAG, "Saving current position to $position")
+ Log.d(TAG, "Saving current position to $position $duration")
saveCurrentPosition(playable, position, System.currentTimeMillis())
}
}
@@ -1373,11 +1382,11 @@ class PlaybackService : MediaBrowserServiceCompat() {
private fun bluetoothNotifyChange(info: PSMPInfo?, whatChanged: String) {
var isPlaying = false
- if (info!!.playerStatus == PlayerStatus.PLAYING) {
+ if (info?.playerStatus == PlayerStatus.PLAYING) {
isPlaying = true
}
- if (info.playable != null) {
+ if (info?.playable != null) {
val i = Intent(whatChanged)
i.putExtra("id", 1L)
i.putExtra("artist", "")
@@ -1476,7 +1485,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
Log.d(TAG, "pauseIfPauseOnDisconnect()")
transientPause = (mediaPlayer?.playerStatus == PlayerStatus.PLAYING)
if (isPauseOnHeadsetDisconnect && !isCasting) {
- mediaPlayer!!.pause(!isPersistNotify, false)
+ mediaPlayer?.pause(!isPersistNotify, false)
}
}
@@ -1598,7 +1607,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
var isStartWhenPrepared: Boolean
get() = mediaPlayer?.isStartWhenPrepared() ?: false
set(s) {
- if (mediaPlayer != null) mediaPlayer!!.setStartWhenPrepared(s)
+ mediaPlayer?.setStartWhenPrepared(s)
}
fun seekTo(t: Int) {
@@ -1646,7 +1655,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
get() = mediaPlayer?.isStreaming() ?: false
val videoSize: Pair?
- get() = mediaPlayer!!.getVideoSize()
+ get() = mediaPlayer?.getVideoSize()
private fun setupPositionObserver() {
positionEventTimer?.dispose()
@@ -1656,8 +1665,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
Log.d(TAG, "notificationBuilder.updatePosition currentPosition: $currentPosition, currentPlaybackSpeed: $currentPlaybackSpeed")
- EventBus.getDefault().post(PlaybackPositionEvent(currentPosition,
- duration))
+ EventBus.getDefault().post(PlaybackPositionEvent(currentPosition, duration))
// TODO: why set SDK_INT < 29
if (Build.VERSION.SDK_INT < 29) {
notificationBuilder.updatePosition(currentPosition, currentPlaybackSpeed)
@@ -1674,7 +1682,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
private fun addPlayableToQueue(playable: Playable?) {
if (playable is FeedMedia) {
- val itemId = playable.getItem()!!.id
+ val itemId = playable.getItem()?.id ?: return
DBWriter.addQueueItem(this, false, true, itemId)
notifyChildrenChanged(getString(R.string.queue_label))
}
@@ -1857,9 +1865,6 @@ class PlaybackService : MediaBrowserServiceCompat() {
}
companion object {
- /**
- * Logging tag
- */
private const val TAG = "PlaybackService"
// TODO: need to experiment this value
diff --git a/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackServiceNotificationBuilder.kt b/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackServiceNotificationBuilder.kt
index 79c5de95..8362e219 100644
--- a/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackServiceNotificationBuilder.kt
+++ b/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackServiceNotificationBuilder.kt
@@ -65,12 +65,16 @@ class PlaybackServiceNotificationBuilder(private val context: Context) {
try {
cachedIcon = Glide.with(context)
.asBitmap()
- .load(playable!!.getImageLocation())
+ .load(playable?.getImageLocation())
.apply(options)
.submit(iconSize, iconSize)
.get()
} catch (e: ExecutionException) {
try {
+ if (playable == null) {
+ Log.e(TAG, "playable is null")
+ return
+ }
cachedIcon = Glide.with(context)
.asBitmap()
.load(ImageResourceUtils.getFallbackImageLocation(playable!!))
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt b/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt
index 3f0895f8..3a00af15 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt
@@ -867,7 +867,7 @@ object DBReader {
// getFeedList(adapter)
// TODO:
- if (false || subscriptionsFilter != null) {
+ if (false && subscriptionsFilter != null) {
feeds = subscriptionsFilter.filter(feeds, feedCounters as Map).toMutableList()
}
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt b/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt
index c7bd0379..6d0ae10c 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt
@@ -58,9 +58,9 @@ class PodDBAdapter private constructor() {
*
* @return the id of the entry
*/
- private fun setFeed(feed: Feed?): Long {
+ private fun setFeed(feed: Feed): Long {
val values = ContentValues()
- values.put(KEY_TITLE, feed!!.feedTitle)
+ values.put(KEY_TITLE, feed.feedTitle)
values.put(KEY_LINK, feed.link)
values.put(KEY_DESCRIPTION, feed.description)
values.put(KEY_PAYMENT_LINK, FeedFunding.getPaymentLinksAsString(feed.paymentLinks))
@@ -77,7 +77,7 @@ class PodDBAdapter private constructor() {
values.put(KEY_IS_PAGED, feed.isPaged)
values.put(KEY_NEXT_PAGE_LINK, feed.nextPageLink)
- if (feed.itemFilter != null && feed.itemFilter!!.values.isNotEmpty()) {
+ if (!feed.itemFilter?.values.isNullOrEmpty()) {
values.put(KEY_HIDE, TextUtils.join(",", feed.itemFilter!!.values))
} else {
values.put(KEY_HIDE, "")
@@ -97,8 +97,9 @@ class PodDBAdapter private constructor() {
return feed.id
}
- fun setFeedPreferences(prefs: FeedPreferences?) {
- require(prefs!!.feedID != 0L) { "Feed ID of preference must not be null" }
+ fun setFeedPreferences(prefs: FeedPreferences) {
+ require(prefs.feedID != 0L) { "Feed ID of preference must not be null" }
+
val values = ContentValues()
values.put(KEY_AUTO_DOWNLOAD_ENABLED, prefs.autoDownload)
values.put(KEY_KEEP_UPDATED, prefs.keepUpdated)
@@ -223,7 +224,7 @@ class PodDBAdapter private constructor() {
}
}
if (feed.preferences != null) {
- setFeedPreferences(feed.preferences)
+ setFeedPreferences(feed.preferences!!)
}
}
db.setTransactionSuccessful()
@@ -293,10 +294,10 @@ class PodDBAdapter private constructor() {
}
values.put(KEY_PUBDATE, item.getPubDate()!!.time)
values.put(KEY_PAYMENT_LINK, item.paymentLink)
- if (saveFeed && item.feed != null) {
- setFeed(item.feed)
+ if (item.feed != null) {
+ if (saveFeed) setFeed(item.feed!!)
+ values.put(KEY_FEED, item.feed!!.id)
}
- values.put(KEY_FEED, item.feed!!.id)
if (item.isNew) {
values.put(KEY_READ, FeedItem.NEW)
} else if (item.isPlayed()) {
@@ -1091,7 +1092,7 @@ class PodDBAdapter private constructor() {
Log.e(TAG, "Database corrupted: " + db.path)
val dbPath = File(db.path)
- val backupFolder = context!!.getExternalFilesDir(null)
+ val backupFolder = context.getExternalFilesDir(null)
val backupFile = File(backupFolder, "CorruptedDatabaseBackup.db")
try {
FileUtils.copyFile(dbPath, backupFile)
diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/playback/RemoteMedia.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/playback/RemoteMedia.kt
index 8d3a0d99..64dca8d5 100644
--- a/app/src/main/java/ac/mdiq/podcini/storage/model/playback/RemoteMedia.kt
+++ b/app/src/main/java/ac/mdiq/podcini/storage/model/playback/RemoteMedia.kt
@@ -74,6 +74,8 @@ class RemoteMedia : Playable {
this.mimeType = item.media!!.mime_type
this.pubDate = item.pubDate
this.description = item.description
+
+ this.duration = item.media?.getDuration() ?: 0
}
fun getEpisodeIdentifier(): String? {
@@ -159,7 +161,7 @@ class RemoteMedia : Playable {
}
override fun getStreamUrl(): String? {
- return downloadUrl
+ return streamUrl
}
override fun getLocalMediaUrl(): String? {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt
index 6f8dba45..bb2af131 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt
@@ -1,6 +1,5 @@
package ac.mdiq.podcini.ui.activity
-//import ac.mdiq.podcini.ui.home.HomeFragment
import ac.mdiq.podcini.R
import ac.mdiq.podcini.databinding.MainActivityBinding
import ac.mdiq.podcini.net.download.FeedUpdateManager
@@ -43,7 +42,6 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import android.widget.EditText
-import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.core.graphics.Insets
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/OnlineFeedViewActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/OnlineFeedViewActivity.kt
index e624f074..eea23b5b 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/activity/OnlineFeedViewActivity.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/OnlineFeedViewActivity.kt
@@ -26,7 +26,7 @@ import com.bumptech.glide.request.RequestOptions
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.ui.adapter.FeedItemlistDescriptionAdapter
+import ac.mdiq.podcini.ui.adapter.OnlineItemDescriptionAdapter
import ac.mdiq.podcini.feed.FeedUrlNotFoundException
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.currentlyPlayingMediaType
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.writeNoMediaPlaying
@@ -103,29 +103,33 @@ class OnlineFeedViewActivity : AppCompatActivity() {
private var parser: Disposable? = null
private var updater: Disposable? = null
- private lateinit var headerBinding: OnlinefeedviewHeaderBinding
- private lateinit var viewBinding: OnlinefeedviewActivityBinding
+ private lateinit var hBinding: OnlinefeedviewHeaderBinding
+ private lateinit var binding: OnlinefeedviewActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(getTranslucentTheme(this))
super.onCreate(savedInstanceState)
- viewBinding = OnlinefeedviewActivityBinding.inflate(layoutInflater)
- setContentView(viewBinding.root)
+ binding = OnlinefeedviewActivityBinding.inflate(layoutInflater)
+ setContentView(binding.root)
- viewBinding.transparentBackground.setOnClickListener { finish() }
- viewBinding.closeButton.setOnClickListener { finish() }
- viewBinding.card.setOnClickListener(null)
- viewBinding.card.setCardBackgroundColor(getColorFromAttr(this, R.attr.colorSurface))
- headerBinding = OnlinefeedviewHeaderBinding.inflate(layoutInflater)
+ binding.transparentBackground.setOnClickListener { finish() }
+ binding.closeButton.setOnClickListener { finish() }
+ binding.card.setOnClickListener(null)
+ binding.card.setCardBackgroundColor(getColorFromAttr(this, R.attr.colorSurface))
+ hBinding = OnlinefeedviewHeaderBinding.inflate(layoutInflater)
var feedUrl: String? = null
- if (intent.hasExtra(ARG_FEEDURL)) {
- feedUrl = intent.getStringExtra(ARG_FEEDURL)
- } else if (TextUtils.equals(intent.action, Intent.ACTION_SEND)) {
- feedUrl = intent.getStringExtra(Intent.EXTRA_TEXT)
- } else if (TextUtils.equals(intent.action, Intent.ACTION_VIEW)) {
- feedUrl = intent.dataString
+ when {
+ intent.hasExtra(ARG_FEEDURL) -> {
+ feedUrl = intent.getStringExtra(ARG_FEEDURL)
+ }
+ TextUtils.equals(intent.action, Intent.ACTION_SEND) -> {
+ feedUrl = intent.getStringExtra(Intent.EXTRA_TEXT)
+ }
+ TextUtils.equals(intent.action, Intent.ACTION_VIEW) -> {
+ feedUrl = intent.dataString
+ }
}
if (feedUrl == null) {
@@ -164,8 +168,8 @@ class OnlineFeedViewActivity : AppCompatActivity() {
* Displays a progress indicator.
*/
private fun setLoadingLayout() {
- viewBinding.progressBar.visibility = View.VISIBLE
- viewBinding.feedDisplayContainer.visibility = View.GONE
+ binding.progressBar.visibility = View.VISIBLE
+ binding.feedDisplayContainer.visibility = View.GONE
}
override fun onStart() {
@@ -388,18 +392,18 @@ class OnlineFeedViewActivity : AppCompatActivity() {
* This method is executed on the GUI thread.
*/
@UnstableApi private fun showFeedInformation(feed: Feed, alternateFeedUrls: Map) {
- viewBinding.progressBar.visibility = View.GONE
- viewBinding.feedDisplayContainer.visibility = View.VISIBLE
+ binding.progressBar.visibility = View.GONE
+ binding.feedDisplayContainer.visibility = View.VISIBLE
if (isFeedFoundBySearch) {
val resId = R.string.no_feed_url_podcast_found_by_search
- Snackbar.make(viewBinding.root, resId, Snackbar.LENGTH_LONG).show()
+ Snackbar.make(binding.root, resId, Snackbar.LENGTH_LONG).show()
}
- viewBinding.backgroundImage.colorFilter = LightingColorFilter(-0x7d7d7e, 0x000000)
+ binding.backgroundImage.colorFilter = LightingColorFilter(-0x7d7d7e, 0x000000)
- viewBinding.listView.addHeaderView(headerBinding.root)
- viewBinding.listView.setSelector(android.R.color.transparent)
- viewBinding.listView.adapter = FeedItemlistDescriptionAdapter(this, 0, feed.items)
+ binding.listView.addHeaderView(hBinding.root)
+ binding.listView.setSelector(android.R.color.transparent)
+ binding.listView.adapter = OnlineItemDescriptionAdapter(this, 0, feed.items)
if (StringUtils.isNotBlank(feed.imageUrl)) {
Glide.with(this)
@@ -409,7 +413,7 @@ class OnlineFeedViewActivity : AppCompatActivity() {
.error(R.color.light_gray)
.fitCenter()
.dontAnimate())
- .into(viewBinding.coverImage)
+ .into(binding.coverImage)
Glide.with(this)
.load(feed.imageUrl)
.apply(RequestOptions()
@@ -417,14 +421,14 @@ class OnlineFeedViewActivity : AppCompatActivity() {
.error(R.color.image_readability_tint)
.transform(FastBlurTransformation())
.dontAnimate())
- .into(viewBinding.backgroundImage)
+ .into(binding.backgroundImage)
}
- viewBinding.titleLabel.text = feed.title
- viewBinding.authorLabel.text = feed.author
- headerBinding.txtvDescription.text = HtmlToPlainText.getPlainText(feed.description?:"")
+ binding.titleLabel.text = feed.title
+ binding.authorLabel.text = feed.author
+ hBinding.txtvDescription.text = HtmlToPlainText.getPlainText(feed.description?:"")
- viewBinding.subscribeButton.setOnClickListener {
+ binding.subscribeButton.setOnClickListener {
if (feedInFeedlist()) {
openFeed()
} else {
@@ -434,29 +438,29 @@ class OnlineFeedViewActivity : AppCompatActivity() {
}
}
- viewBinding.stopPreviewButton.setOnClickListener {
+ binding.stopPreviewButton.setOnClickListener {
writeNoMediaPlaying()
sendLocalBroadcast(this, PlaybackServiceInterface.ACTION_SHUTDOWN_PLAYBACK_SERVICE)
}
if (isEnableAutodownload) {
val preferences = getSharedPreferences(PREFS, MODE_PRIVATE)
- viewBinding.autoDownloadCheckBox.isChecked = preferences.getBoolean(PREF_LAST_AUTO_DOWNLOAD, true)
+ binding.autoDownloadCheckBox.isChecked = preferences.getBoolean(PREF_LAST_AUTO_DOWNLOAD, true)
}
- headerBinding.txtvDescription.maxLines = DESCRIPTION_MAX_LINES_COLLAPSED
- headerBinding.txtvDescription.setOnClickListener {
- if (headerBinding.txtvDescription.maxLines > DESCRIPTION_MAX_LINES_COLLAPSED) {
- headerBinding.txtvDescription.maxLines = DESCRIPTION_MAX_LINES_COLLAPSED
+ hBinding.txtvDescription.maxLines = DESCRIPTION_MAX_LINES_COLLAPSED
+ hBinding.txtvDescription.setOnClickListener {
+ if (hBinding.txtvDescription.maxLines > DESCRIPTION_MAX_LINES_COLLAPSED) {
+ hBinding.txtvDescription.maxLines = DESCRIPTION_MAX_LINES_COLLAPSED
} else {
- headerBinding.txtvDescription.maxLines = 2000
+ hBinding.txtvDescription.maxLines = 2000
}
}
if (alternateFeedUrls.isEmpty()) {
- viewBinding.alternateUrlsSpinner.visibility = View.GONE
+ binding.alternateUrlsSpinner.visibility = View.GONE
} else {
- viewBinding.alternateUrlsSpinner.visibility = View.VISIBLE
+ binding.alternateUrlsSpinner.visibility = View.VISIBLE
val alternateUrlsList: MutableList = ArrayList()
val alternateUrlsTitleList: MutableList = ArrayList()
@@ -479,8 +483,8 @@ class OnlineFeedViewActivity : AppCompatActivity() {
}
adapter.setDropDownViewResource(R.layout.alternate_urls_dropdown_item)
- viewBinding.alternateUrlsSpinner.adapter = adapter
- viewBinding.alternateUrlsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ binding.alternateUrlsSpinner.adapter = adapter
+ binding.alternateUrlsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
selectedDownloadUrl = alternateUrlsList[position]
}
@@ -507,11 +511,11 @@ class OnlineFeedViewActivity : AppCompatActivity() {
if (dli == null || selectedDownloadUrl == null) return
if (dli.isDownloadingEpisode(selectedDownloadUrl!!)) {
- viewBinding.subscribeButton.isEnabled = false
- viewBinding.subscribeButton.setText(R.string.subscribing_label)
+ binding.subscribeButton.isEnabled = false
+ binding.subscribeButton.setText(R.string.subscribing_label)
} else if (feedInFeedlist()) {
- viewBinding.subscribeButton.isEnabled = true
- viewBinding.subscribeButton.setText(R.string.open_podcast)
+ binding.subscribeButton.isEnabled = true
+ binding.subscribeButton.setText(R.string.open_podcast)
if (didPressSubscribe) {
didPressSubscribe = false
@@ -519,7 +523,7 @@ class OnlineFeedViewActivity : AppCompatActivity() {
val feedPreferences = feed1.preferences
if (feedPreferences != null) {
if (isEnableAutodownload) {
- val autoDownload = viewBinding.autoDownloadCheckBox.isChecked
+ val autoDownload = binding.autoDownloadCheckBox.isChecked
feedPreferences.autoDownload = autoDownload
val preferences = getSharedPreferences(PREFS, MODE_PRIVATE)
@@ -536,10 +540,10 @@ class OnlineFeedViewActivity : AppCompatActivity() {
openFeed()
}
} else {
- viewBinding.subscribeButton.isEnabled = true
- viewBinding.subscribeButton.setText(R.string.subscribe_label)
+ binding.subscribeButton.isEnabled = true
+ binding.subscribeButton.setText(R.string.subscribe_label)
if (isEnableAutodownload) {
- viewBinding.autoDownloadCheckBox.visibility = View.VISIBLE
+ binding.autoDownloadCheckBox.visibility = View.VISIBLE
}
}
}
@@ -617,7 +621,7 @@ class OnlineFeedViewActivity : AppCompatActivity() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun playbackStateChanged(event: PlayerStatusEvent?) {
val isPlayingPreview = currentlyPlayingMediaType == RemoteMedia.PLAYABLE_TYPE_REMOTE_MEDIA.toLong()
- viewBinding.stopPreviewButton.visibility = if (isPlayingPreview) View.VISIBLE else View.GONE
+ binding.stopPreviewButton.visibility = if (isPlayingPreview) View.VISIBLE else View.GONE
}
/**
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/itunes/ItunesAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt
similarity index 55%
rename from app/src/main/java/ac/mdiq/podcini/ui/adapter/itunes/ItunesAdapter.kt
rename to app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt
index b8669d55..499b3866 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/itunes/ItunesAdapter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt
@@ -1,5 +1,8 @@
-package ac.mdiq.podcini.ui.adapter.itunes
+package ac.mdiq.podcini.ui.adapter
+import ac.mdiq.podcini.R
+import ac.mdiq.podcini.databinding.OnlinePodcastListitemBinding
+import ac.mdiq.podcini.net.discovery.PodcastSearchResult
import ac.mdiq.podcini.ui.activity.MainActivity
import android.content.Context
import android.view.View
@@ -7,40 +10,27 @@ import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.TextView
+import androidx.media3.common.util.UnstableApi
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.FitCenter
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
-import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.ItunesPodcastListitemBinding
-import ac.mdiq.podcini.net.discovery.PodcastSearchResult
-import androidx.media3.common.util.UnstableApi
-class ItunesAdapter(
- /**
- * Related Context
- */
- private val context: Context, objects: List
-) : ArrayAdapter(context, 0, objects) {
- /**
- * List holding the podcasts found in the search
- */
+class OnlineFeedsAdapter(private val context: Context, objects: List) :
+ ArrayAdapter(context, 0, objects) {
+
+// List holding the podcasts found in the search
private val data: List = objects
@UnstableApi override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- //Current podcast
val podcast: PodcastSearchResult = data[position]
-
- //ViewHolder
val viewHolder: PodcastViewHolder
-
- //Resulting view
val view: View
//Handle view holder stuff
if (convertView == null) {
- view = (context as MainActivity).layoutInflater.inflate(R.layout.itunes_podcast_listitem, parent, false)
+ view = (context as MainActivity).layoutInflater.inflate(R.layout.online_podcast_listitem, parent, false)
viewHolder = PodcastViewHolder(view)
view.tag = viewHolder
} else {
@@ -50,15 +40,28 @@ class ItunesAdapter(
// Set the title
viewHolder.titleView.text = podcast.title
- if (podcast.author != null && podcast.author.trim { it <= ' ' }.isNotEmpty()) {
- viewHolder.authorView.text = podcast.author
- viewHolder.authorView.visibility = View.VISIBLE
- } else if (podcast.feedUrl != null && !podcast.feedUrl.contains("itunes.apple.com")) {
- viewHolder.authorView.text = podcast.feedUrl
- viewHolder.authorView.visibility = View.VISIBLE
- } else {
- viewHolder.authorView.visibility = View.GONE
+ when {
+ !podcast.author.isNullOrBlank() -> {
+ viewHolder.authorView.text = podcast.author.trim { it <= ' ' }
+ viewHolder.authorView.visibility = View.VISIBLE
+ }
+ podcast.feedUrl != null && !podcast.feedUrl.contains("itunes.apple.com") -> {
+ viewHolder.authorView.text = podcast.feedUrl
+ viewHolder.authorView.visibility = View.VISIBLE
+ }
+ else -> {
+ viewHolder.authorView.visibility = View.INVISIBLE
+ }
}
+ viewHolder.source.text = podcast.source + ": " + podcast.feedUrl
+ if (podcast.count != null) {
+ viewHolder.countView.text = podcast.count.toString() + " episodes"
+ viewHolder.countView.visibility = View.VISIBLE
+ } else viewHolder.countView.visibility = View.INVISIBLE
+ if (podcast.update != null) {
+ viewHolder.updateView.text = podcast.update
+ viewHolder.updateView.visibility = View.VISIBLE
+ } else viewHolder.updateView.visibility = View.INVISIBLE
//Update the empty imageView with the image from the feed
Glide.with(context)
@@ -71,25 +74,22 @@ class ItunesAdapter(
.dontAnimate())
.into(viewHolder.coverView)
- //Feed the grid view
return view
}
- /**
- * View holder object for the GridView
- */
internal class PodcastViewHolder(view: View) {
- val binding = ItunesPodcastListitemBinding.bind(view)
- /**
- * ImageView holding the Podcast image
- */
+ val binding = OnlinePodcastListitemBinding.bind(view)
+
val coverView: ImageView = binding.imgvCover
- /**
- * TextView holding the Podcast title
- */
val titleView: TextView = binding.txtvTitle
val authorView: TextView = binding.txtvAuthor
+
+ val countView: TextView = binding.count
+
+ val updateView: TextView = binding.update
+
+ val source: TextView = binding.source
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/FeedItemlistDescriptionAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineItemDescriptionAdapter.kt
similarity index 64%
rename from app/src/main/java/ac/mdiq/podcini/ui/adapter/FeedItemlistDescriptionAdapter.kt
rename to app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineItemDescriptionAdapter.kt
index 51ea1062..fd742f5b 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/FeedItemlistDescriptionAdapter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineItemDescriptionAdapter.kt
@@ -1,7 +1,7 @@
package ac.mdiq.podcini.ui.adapter
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.ItemdescriptionListitemBinding
+import ac.mdiq.podcini.databinding.OnlineItemDescriptionBinding
import ac.mdiq.podcini.service.playback.PlaybackService.Companion.getPlayerActivityIntent
import ac.mdiq.podcini.util.DateFormatter.formatAbbrev
import ac.mdiq.podcini.util.NetworkUtils.isStreamingAllowed
@@ -24,8 +24,8 @@ import androidx.media3.common.util.UnstableApi
/**
* List adapter for showing a list of FeedItems with their title and description.
*/
-class FeedItemlistDescriptionAdapter(context: Context, resource: Int, objects: List?) :
- ArrayAdapter(context, resource, objects!!) {
+class OnlineItemDescriptionAdapter(context: Context, resource: Int, items: List) :
+ ArrayAdapter(context, resource, items) {
@UnstableApi override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
val holder: Holder
@@ -36,8 +36,8 @@ class FeedItemlistDescriptionAdapter(context: Context, resource: Int, objects: L
if (convertView == null) {
holder = Holder()
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
- convertView = inflater.inflate(R.layout.itemdescription_listitem, parent, false)
- val binding = ItemdescriptionListitemBinding.bind(convertView)
+ convertView = inflater.inflate(R.layout.online_item_description, parent, false)
+ val binding = OnlineItemDescriptionBinding.bind(convertView)
holder.title = binding.txtvTitle
holder.pubDate = binding.txtvPubDate
holder.description = binding.txtvDescription
@@ -48,22 +48,21 @@ class FeedItemlistDescriptionAdapter(context: Context, resource: Int, objects: L
holder = convertView.tag as Holder
}
- holder.title!!.text = item!!.title
- holder.pubDate!!.text = formatAbbrev(context, item.pubDate)
+ holder.title.text = item!!.title
+ holder.pubDate.text = formatAbbrev(context, item.pubDate)
if (item.description != null) {
val description = HtmlToPlainText.getPlainText(item.description!!)
.replace("\n".toRegex(), " ")
.replace("\\s+".toRegex(), " ")
.trim { it <= ' ' }
- holder.description!!.text = description
- holder.description!!.maxLines = MAX_LINES_COLLAPSED
+ holder.description.text = description
+ holder.description.maxLines = MAX_LINES_COLLAPSED
}
- holder.description!!.tag = false
- holder.preview!!.visibility = View.GONE
- holder.preview!!.setOnClickListener {
- if (item.media == null) {
- return@setOnClickListener
- }
+ holder.description.tag = false
+ holder.preview.visibility = View.GONE
+ holder.preview.setOnClickListener {
+ if (item.media == null) return@setOnClickListener
+
val playable: Playable = RemoteMedia(item)
if (!isStreamingAllowed) {
StreamingConfirmationDialog(context, playable).show()
@@ -78,26 +77,26 @@ class FeedItemlistDescriptionAdapter(context: Context, resource: Int, objects: L
}
}
convertView!!.setOnClickListener {
- if (holder.description!!.tag == true) {
- holder.description!!.maxLines = MAX_LINES_COLLAPSED
- holder.preview!!.visibility = View.GONE
- holder.description!!.tag = false
+ if (holder.description.tag == true) {
+ holder.description.maxLines = MAX_LINES_COLLAPSED
+ holder.preview.visibility = View.GONE
+ holder.description.tag = false
} else {
- holder.description!!.maxLines = 30
- holder.description!!.tag = true
+ holder.description.maxLines = 30
+ holder.description.tag = true
- holder.preview!!.visibility = if (item.media != null) View.VISIBLE else View.GONE
- holder.preview!!.setText(R.string.preview_episode)
+ holder.preview.visibility = if (item.media != null) View.VISIBLE else View.GONE
+ holder.preview.setText(R.string.preview_episode)
}
}
return convertView
}
internal class Holder {
- var title: TextView? = null
- var pubDate: TextView? = null
- var description: TextView? = null
- var preview: Button? = null
+ lateinit var title: TextView
+ lateinit var pubDate: TextView
+ lateinit var description: TextView
+ lateinit var preview: Button
}
companion object {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsRecyclerAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsRecyclerAdapter.kt
index a6461a53..494b1f45 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsRecyclerAdapter.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsRecyclerAdapter.kt
@@ -178,13 +178,14 @@ open class SubscriptionsRecyclerAdapter(mainActivity: MainActivity) :
title.text = drawerItem.title
producer.text = drawerItem.producer
coverImage.contentDescription = drawerItem.title
+
if (drawerItem.counter > 0) {
// TODO: need to use more specific number
count.text = NumberFormat.getInstance().format(drawerItem.counter.toLong()) + " episodes"
// count.text = NumberFormat.getInstance().format(drawerItem.feed.items.size.toLong()) + " episodes"
count.visibility = View.VISIBLE
} else {
- count.visibility = View.GONE
+ count.visibility = View.VISIBLE
}
val mainActRef = mainActivityRef.get() ?: return
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemFilterDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemFilterDialog.kt
index b7ad6d45..4dec699c 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemFilterDialog.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemFilterDialog.kt
@@ -18,6 +18,8 @@ import ac.mdiq.podcini.databinding.FilterDialogBinding
import ac.mdiq.podcini.feed.FeedItemFilterGroup
import ac.mdiq.podcini.databinding.FilterDialogRowBinding
import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
+import ac.mdiq.podcini.ui.fragment.ItemDescriptionFragment
+import android.util.Log
abstract class ItemFilterDialog : BottomSheetDialogFragment() {
private lateinit var rows: LinearLayout
@@ -27,6 +29,7 @@ abstract class ItemFilterDialog : BottomSheetDialogFragment() {
val binding = FilterDialogBinding.bind(layout)
rows = binding.filterRows
val filter = requireArguments().getSerializable(ARGUMENT_FILTER) as FeedItemFilter?
+ Log.d("ItemFilterDialog", "fragment onCreateView")
//add filter rows
for (item in FeedItemFilterGroup.entries) {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemSortDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemSortDialog.kt
index c689ef99..11cad4c1 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemSortDialog.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemSortDialog.kt
@@ -18,19 +18,19 @@ import ac.mdiq.podcini.databinding.SortDialogItemBinding
import ac.mdiq.podcini.storage.model.feed.SortOrder
open class ItemSortDialog : BottomSheetDialogFragment() {
- protected lateinit var viewBinding: SortDialogBinding
+ protected lateinit var binding: SortDialogBinding
protected var sortOrder: SortOrder? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- viewBinding = SortDialogBinding.inflate(inflater)
+ binding = SortDialogBinding.inflate(inflater)
populateList()
- viewBinding.keepSortedCheckbox.setOnCheckedChangeListener { _: CompoundButton?, _: Boolean -> this@ItemSortDialog.onSelectionChanged() }
- return viewBinding.root
+ binding.keepSortedCheckbox.setOnCheckedChangeListener { _: CompoundButton?, _: Boolean -> this@ItemSortDialog.onSelectionChanged() }
+ return binding.root
}
private fun populateList() {
- viewBinding.gridLayout.removeAllViews()
+ binding.gridLayout.removeAllViews()
onAddItem(R.string.episode_title, SortOrder.EPISODE_TITLE_A_Z, SortOrder.EPISODE_TITLE_Z_A, true)
onAddItem(R.string.feed_title, SortOrder.FEED_TITLE_A_Z, SortOrder.FEED_TITLE_Z_A, true)
onAddItem(R.string.duration, SortOrder.DURATION_SHORT_LONG, SortOrder.DURATION_LONG_SHORT, true)
@@ -43,7 +43,7 @@ open class ItemSortDialog : BottomSheetDialogFragment() {
protected open fun onAddItem(title: Int, ascending: SortOrder, descending: SortOrder, ascendingIsDefault: Boolean) {
if (sortOrder == ascending || sortOrder == descending) {
- val item = SortDialogItemActiveBinding.inflate(layoutInflater, viewBinding.gridLayout, false)
+ val item = SortDialogItemActiveBinding.inflate(layoutInflater, binding.gridLayout, false)
val other: SortOrder
when {
ascending == descending -> {
@@ -64,17 +64,17 @@ open class ItemSortDialog : BottomSheetDialogFragment() {
populateList()
onSelectionChanged()
}
- viewBinding.gridLayout.addView(item.root)
+ binding.gridLayout.addView(item.root)
} else {
val item = SortDialogItemBinding.inflate(
- layoutInflater, viewBinding.gridLayout, false)
+ layoutInflater, binding.gridLayout, false)
item.button.setText(title)
item.button.setOnClickListener {
sortOrder = if (ascendingIsDefault) ascending else descending
populateList()
onSelectionChanged()
}
- viewBinding.gridLayout.addView(item.root)
+ binding.gridLayout.addView(item.root)
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/SwipeActionsDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/SwipeActionsDialog.kt
index e253feb9..b262960c 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/SwipeActionsDialog.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/SwipeActionsDialog.kt
@@ -68,22 +68,22 @@ class SwipeActionsDialog(private val context: Context, private val tag: String)
}
builder.setTitle(context.getString(R.string.swipeactions_label) + " - " + forFragment)
- val viewBinding = SwipeactionsDialogBinding.inflate(LayoutInflater.from(context))
- builder.setView(viewBinding.root)
+ val binding = SwipeactionsDialogBinding.inflate(LayoutInflater.from(context))
+ builder.setView(binding.root)
- viewBinding.enableSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
- viewBinding.actionLeftContainer.root.alpha = if (b) 1.0f else 0.4f
- viewBinding.actionRightContainer.root.alpha = if (b) 1.0f else 0.4f
+ binding.enableSwitch.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean ->
+ binding.actionLeftContainer.root.alpha = if (b) 1.0f else 0.4f
+ binding.actionRightContainer.root.alpha = if (b) 1.0f else 0.4f
}
- viewBinding.enableSwitch.isChecked = isSwipeActionEnabled(context, tag)
+ binding.enableSwitch.isChecked = isSwipeActionEnabled(context, tag)
- setupSwipeDirectionView(viewBinding.actionLeftContainer, LEFT)
- setupSwipeDirectionView(viewBinding.actionRightContainer, RIGHT)
+ setupSwipeDirectionView(binding.actionLeftContainer, LEFT)
+ setupSwipeDirectionView(binding.actionRightContainer, RIGHT)
builder.setPositiveButton(R.string.confirm_label) { _: DialogInterface?, _: Int ->
savePrefs(tag, rightAction!!.getId(), leftAction!!.getId())
- saveActionsEnabledPrefs(viewBinding.enableSwitch.isChecked)
+ saveActionsEnabledPrefs(binding.enableSwitch.isChecked)
prefsChanged.onCall()
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt
index 721cd495..ec15e45f 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt
@@ -227,9 +227,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUnreadItemsUpdate(event: UnreadItemsUpdateEvent?) {
- if (controller == null) {
- return
- }
+ if (controller == null) return
updatePosition(PlaybackPositionEvent(controller!!.position, controller!!.duration))
}
@@ -243,13 +241,11 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
private fun setupLengthTextView() {
showTimeLeft = UserPreferences.shouldShowRemainingTime()
txtvLength.setOnClickListener(View.OnClickListener {
- if (controller == null) {
- return@OnClickListener
- }
+ if (controller == null) return@OnClickListener
+
showTimeLeft = !showTimeLeft
UserPreferences.setShowRemainTimeSetting(showTimeLeft)
- updatePosition(PlaybackPositionEvent(controller!!.position,
- controller!!.duration))
+ updatePosition(PlaybackPositionEvent(controller!!.position, controller!!.duration))
})
}
@@ -302,9 +298,8 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
private fun updateUi(media: Playable?) {
if (controller != null) duration = controller!!.duration
- if (media == null) {
- return
- }
+ if (media == null) return
+
episodeTitle.text = media.getEpisodeTitle()
updatePosition(PlaybackPositionEvent(media.getPosition(), media.getDuration()))
updatePlaybackSpeedButton(SpeedChangedEvent(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media)))
@@ -340,14 +335,19 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
@Subscribe(threadMode = ThreadMode.MAIN)
@Suppress("unused")
fun bufferUpdate(event: BufferUpdateEvent) {
- if (event.hasStarted()) {
- progressIndicator.visibility = View.VISIBLE
- } else if (event.hasEnded()) {
- progressIndicator.visibility = View.GONE
- } else if (controller != null && controller!!.isStreaming) {
- sbPosition.setSecondaryProgress((event.progress * sbPosition.max).toInt())
- } else {
- sbPosition.setSecondaryProgress(0)
+ when {
+ event.hasStarted() -> {
+ progressIndicator.visibility = View.VISIBLE
+ }
+ event.hasEnded() -> {
+ progressIndicator.visibility = View.GONE
+ }
+ controller != null && controller!!.isStreaming -> {
+ sbPosition.setSecondaryProgress((event.progress * sbPosition.max).toInt())
+ }
+ else -> {
+ sbPosition.setSecondaryProgress(0)
+ }
}
}
@@ -363,7 +363,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
currentChapterIndex = ChapterUtils.getCurrentChapterIndex(controller!!.getMedia(), currentPosition)
// Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
if (currentPosition == Playable.INVALID_TIME || duration == Playable.INVALID_TIME) {
- Log.w(TAG, "Could not react to position observer update because of invalid time")
+ Log.w(TAG, "Could not react to position observer update because of invalid time $currentPosition $duration")
return
}
txtvPosition.text = Converter.getDurationStringLong(currentPosition)
@@ -373,14 +373,14 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
if (showTimeLeft) {
txtvLength.setContentDescription(getString(R.string.remaining_time,
Converter.getDurationStringLocalized(requireContext(), remainingTime.toLong())))
- txtvLength.text = (if ((remainingTime > 0)) "-" else "") + Converter.getDurationStringLong(remainingTime)
+ txtvLength.text = (if (remainingTime > 0) "-" else "") + Converter.getDurationStringLong(remainingTime)
} else {
txtvLength.setContentDescription(getString(R.string.chapter_duration,
Converter.getDurationStringLocalized(requireContext(), duration.toLong())))
txtvLength.text = Converter.getDurationStringLong(duration)
}
- if (!sbPosition.isPressed) {
+ if (!sbPosition.isPressed && event.duration > 0) {
val progress: Float = (event.position.toFloat()) / event.duration
sbPosition.progress = (progress * sbPosition.max).toInt()
}
@@ -508,7 +508,6 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
Log.d(TAG, "getItem($position)")
return when (position) {
-// TODO: cover page is not very useful
FIRST_PAGE -> ItemDescriptionFragment()
SECOND_PAGE -> CoverFragment()
else -> ItemDescriptionFragment()
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/CompletedDownloadsFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/CompletedDownloadsFragment.kt
index 09cd4e21..0bda171c 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/CompletedDownloadsFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/CompletedDownloadsFragment.kt
@@ -1,48 +1,47 @@
package ac.mdiq.podcini.ui.fragment
-import ac.mdiq.podcini.ui.activity.MainActivity
-import android.os.Bundle
-import android.util.Log
-import android.view.*
-import android.widget.ProgressBar
-import androidx.appcompat.widget.Toolbar
-import androidx.fragment.app.Fragment
-import androidx.media3.common.util.UnstableApi
-import com.google.android.material.appbar.MaterialToolbar
-import com.google.android.material.snackbar.Snackbar
-import com.leinardi.android.speeddial.SpeedDialActionItem
-import com.leinardi.android.speeddial.SpeedDialView
import ac.mdiq.podcini.R
import ac.mdiq.podcini.databinding.MultiSelectSpeedDialBinding
import ac.mdiq.podcini.databinding.SimpleListFragmentBinding
-import ac.mdiq.podcini.feed.util.PlaybackSpeedUtils
-import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter
-import ac.mdiq.podcini.ui.adapter.SelectableAdapter
-import ac.mdiq.podcini.ui.adapter.actionbutton.DeleteActionButton
-import ac.mdiq.podcini.ui.menuhandler.MenuItemUtils
-import ac.mdiq.podcini.storage.DBReader
-import ac.mdiq.podcini.util.FeedItemUtil
import ac.mdiq.podcini.net.download.FeedUpdateManager
-import ac.mdiq.podcini.ui.dialog.ItemSortDialog
-import ac.mdiq.podcini.util.event.EpisodeDownloadEvent
+import ac.mdiq.podcini.net.download.serviceinterface.DownloadServiceInterface
import ac.mdiq.podcini.playback.event.PlaybackPositionEvent
-import ac.mdiq.podcini.ui.fragment.actions.EpisodeMultiSelectActionHandler
-import ac.mdiq.podcini.ui.fragment.swipeactions.SwipeActions
-import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler
+import ac.mdiq.podcini.preferences.UserPreferences
+import ac.mdiq.podcini.storage.DBReader
import ac.mdiq.podcini.storage.model.feed.FeedItem
import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
import ac.mdiq.podcini.storage.model.feed.SortOrder
-import ac.mdiq.podcini.net.download.serviceinterface.DownloadServiceInterface
-import ac.mdiq.podcini.preferences.UserPreferences
+import ac.mdiq.podcini.ui.activity.MainActivity
+import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter
+import ac.mdiq.podcini.ui.adapter.SelectableAdapter
+import ac.mdiq.podcini.ui.adapter.actionbutton.DeleteActionButton
+import ac.mdiq.podcini.ui.dialog.ItemSortDialog
+import ac.mdiq.podcini.ui.fragment.actions.EpisodeMultiSelectActionHandler
+import ac.mdiq.podcini.ui.fragment.swipeactions.SwipeActions
+import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler
+import ac.mdiq.podcini.ui.menuhandler.MenuItemUtils
import ac.mdiq.podcini.ui.view.EmptyViewHandler
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
-import ac.mdiq.podcini.util.Converter
+import ac.mdiq.podcini.util.FeedItemUtil
+import ac.mdiq.podcini.util.event.EpisodeDownloadEvent
import ac.mdiq.podcini.util.event.FeedItemEvent
+import ac.mdiq.podcini.util.event.SwipeActionsChangedEvent
+import android.os.Bundle
+import android.util.Log
+import android.view.*
+import android.widget.ProgressBar
import android.widget.TextView
+import androidx.appcompat.widget.Toolbar
+import androidx.fragment.app.Fragment
+import androidx.media3.common.util.UnstableApi
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator
+import com.google.android.material.appbar.MaterialToolbar
+import com.google.android.material.snackbar.Snackbar
+import com.leinardi.android.speeddial.SpeedDialActionItem
+import com.leinardi.android.speeddial.SpeedDialView
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
@@ -51,8 +50,6 @@ import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.*
-import kotlin.collections.ArrayList
-import kotlin.collections.HashSet
/**
* Displays all completed downloads and provides a button to delete them.
@@ -61,6 +58,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
private var runningDownloads: Set? = HashSet()
private var items: MutableList = mutableListOf()
+ private lateinit var binding: SimpleListFragmentBinding
private lateinit var infoBar: TextView
private lateinit var adapter: CompletedDownloadsListAdapter
private lateinit var toolbar: MaterialToolbar
@@ -77,7 +75,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- val binding = SimpleListFragmentBinding.inflate(inflater)
+ binding = SimpleListFragmentBinding.inflate(inflater)
Log.d(TAG, "fragment onCreateView")
toolbar = binding.toolbar
@@ -101,9 +99,17 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
adapter.setOnSelectModeListener(this)
recyclerView.adapter = adapter
recyclerView.addOnScrollListener(LiftOnScrollListener(binding.appbar))
+
swipeActions = SwipeActions(this, TAG).attachTo(recyclerView)
swipeActions.setFilter(FeedItemFilter(FeedItemFilter.DOWNLOADED))
+ if (swipeActions.actions?.left != null) {
+ binding.leftActionIcon.setImageResource(swipeActions.actions!!.left!!.getActionIcon())
+ }
+ if (swipeActions.actions?.right != null) {
+ binding.rightActionIcon.setImageResource(swipeActions.actions!!.right!!.getActionIcon())
+ }
+
val animator: RecyclerView.ItemAnimator? = recyclerView.itemAnimator
if (animator is SimpleItemAnimator) {
animator.supportsChangeAnimations = false
@@ -291,6 +297,16 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
loadItems()
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onSwipeActionsChanged(event: SwipeActionsChangedEvent?) {
+ if (swipeActions.actions?.left != null) {
+ binding.leftActionIcon.setImageResource(swipeActions.actions!!.left!!.getActionIcon())
+ }
+ if (swipeActions.actions?.right != null) {
+ binding.rightActionIcon.setImageResource(swipeActions.actions!!.right!!.getActionIcon())
+ }
+ }
+
private fun loadItems() {
disposable?.dispose()
@@ -337,7 +353,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
for (item in items) {
sizeMB += item.media?.size?:0
}
- info += " • " + getString(R.string.size) + " : " + (sizeMB / 1000000) + " MB"
+ info += " • " + (sizeMB / 1000000) + " MB"
}
infoBar.text = info
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt
index a0654084..d38a1c1e 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt
@@ -8,7 +8,7 @@ import ac.mdiq.podcini.net.discovery.ItunesTopListLoader
import ac.mdiq.podcini.net.discovery.PodcastSearchResult
import ac.mdiq.podcini.storage.DBReader
import ac.mdiq.podcini.ui.activity.OnlineFeedViewActivity
-import ac.mdiq.podcini.ui.adapter.itunes.ItunesAdapter
+import ac.mdiq.podcini.ui.adapter.OnlineFeedsAdapter
import ac.mdiq.podcini.util.event.DiscoveryDefaultUpdateEvent
import android.content.Context
import android.content.DialogInterface
@@ -50,7 +50,7 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
/**
* Adapter responsible with the search results.
*/
- private var adapter: ItunesAdapter? = null
+ private var adapter: OnlineFeedsAdapter? = null
/**
* List of podcasts retreived from the search.
@@ -99,7 +99,7 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
Log.d(TAG, "fragment onCreateView")
gridView = viewBinding.gridView
- adapter = ItunesAdapter(requireActivity(), ArrayList())
+ adapter = OnlineFeedsAdapter(requireActivity(), ArrayList())
gridView.setAdapter(adapter)
toolbar = viewBinding.toolbar
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodesListFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodesListFragment.kt
index e6eb518f..d4836059 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodesListFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/EpisodesListFragment.kt
@@ -58,6 +58,7 @@ abstract class EpisodesListFragment : Fragment(), SelectableAdapter.OnSelectMode
protected var hasMoreItems: Boolean = false
private var displayUpArrow = false
+ lateinit var binding: EpisodesListFragmentBinding
lateinit var recyclerView: EpisodeItemListRecyclerView
lateinit var emptyView: EmptyViewHandler
lateinit var speedDialView: SpeedDialView
@@ -73,6 +74,122 @@ abstract class EpisodesListFragment : Fragment(), SelectableAdapter.OnSelectMode
protected var disposable: Disposable? = null
protected lateinit var txtvInformation: TextView
+ @UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ super.onCreateView(inflater, container, savedInstanceState)
+
+ binding = EpisodesListFragmentBinding.inflate(inflater)
+ Log.d(TAG, "fragment onCreateView")
+
+ txtvInformation = binding.txtvInformation
+ toolbar = binding.toolbar
+ toolbar.setOnMenuItemClickListener(this)
+ toolbar.setOnLongClickListener {
+ recyclerView.scrollToPosition(5)
+ recyclerView.post { recyclerView.smoothScrollToPosition(0) }
+ false
+ }
+ displayUpArrow = parentFragmentManager.backStackEntryCount != 0
+ if (savedInstanceState != null) {
+ displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW)
+ }
+ (activity as MainActivity).setupToolbarToggle(toolbar, displayUpArrow)
+
+ recyclerView = binding.recyclerView
+ recyclerView.setRecycledViewPool((activity as MainActivity).recycledViewPool)
+ setupLoadMoreScrollListener()
+ recyclerView.addOnScrollListener(LiftOnScrollListener(binding.appbar))
+
+ swipeActions = SwipeActions(this, getFragmentTag()).attachTo(recyclerView)
+ swipeActions.setFilter(getFilter())
+
+ if (swipeActions.actions?.left != null) {
+ binding.leftActionIcon.setImageResource(swipeActions.actions!!.left!!.getActionIcon())
+ }
+ if (swipeActions.actions?.right != null) {
+ binding.rightActionIcon.setImageResource(swipeActions.actions!!.right!!.getActionIcon())
+ }
+
+ val animator: RecyclerView.ItemAnimator? = recyclerView.itemAnimator
+ if (animator is SimpleItemAnimator) {
+ animator.supportsChangeAnimations = false
+ }
+
+ swipeRefreshLayout = binding.swipeRefresh
+ swipeRefreshLayout.setDistanceToTriggerSync(resources.getInteger(R.integer.swipe_refresh_distance))
+ swipeRefreshLayout.setOnRefreshListener {
+ FeedUpdateManager.runOnceOrAsk(requireContext())
+ }
+
+ listAdapter = object : EpisodeItemListAdapter(activity as MainActivity) {
+ override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
+ super.onCreateContextMenu(menu, v, menuInfo)
+// if (!inActionMode()) {
+// menu.findItem(R.id.multi_select).setVisible(true)
+// }
+ MenuItemUtils.setOnClickListeners(menu
+ ) { item: MenuItem ->
+ this@EpisodesListFragment.onContextItemSelected(item)
+ }
+ }
+ }
+ listAdapter.setOnSelectModeListener(this)
+ recyclerView.adapter = listAdapter
+ progressBar = binding.progressBar
+ progressBar.visibility = View.VISIBLE
+
+ emptyView = EmptyViewHandler(requireContext())
+ emptyView.attachToRecyclerView(recyclerView)
+ emptyView.setIcon(R.drawable.ic_feed)
+ emptyView.setTitle(R.string.no_all_episodes_head_label)
+ emptyView.setMessage(R.string.no_all_episodes_label)
+ emptyView.updateAdapter(listAdapter)
+ emptyView.hide()
+
+ val multiSelectDial = MultiSelectSpeedDialBinding.bind(binding.root)
+ speedDialView = multiSelectDial.fabSD
+ speedDialView.overlayLayout = multiSelectDial.fabSDOverlay
+ speedDialView.inflate(R.menu.episodes_apply_action_speeddial)
+ speedDialView.setOnChangeListener(object : SpeedDialView.OnChangeListener {
+ override fun onMainActionSelected(): Boolean {
+ return false
+ }
+
+ override fun onToggleChanged(open: Boolean) {
+ if (open && listAdapter.selectedCount == 0) {
+ (activity as MainActivity).showSnackbarAbovePlayer(R.string.no_items_selected,
+ Snackbar.LENGTH_SHORT)
+ speedDialView.close()
+ }
+ }
+ })
+ speedDialView.setOnActionSelectedListener { actionItem: SpeedDialActionItem ->
+ var confirmationString = 0
+ if (listAdapter.selectedItems.size >= 25 || listAdapter.shouldSelectLazyLoadedItems()) {
+ // Should ask for confirmation
+ if (actionItem.id == R.id.mark_read_batch) {
+ confirmationString = R.string.multi_select_mark_played_confirmation
+ } else if (actionItem.id == R.id.mark_unread_batch) {
+ confirmationString = R.string.multi_select_mark_unplayed_confirmation
+ }
+ }
+ if (confirmationString == 0) {
+ performMultiSelectAction(actionItem.id)
+ } else {
+ object : ConfirmationDialog(activity as MainActivity, R.string.multi_select, confirmationString) {
+ override fun onConfirmButtonPressed(dialog: DialogInterface) {
+ performMultiSelectAction(actionItem.id)
+ }
+ }.createNewDialog().show()
+ }
+ true
+ }
+
+ EventBus.getDefault().register(this)
+ loadItems()
+
+ return binding.root
+ }
+
override fun onResume() {
super.onResume()
registerForContextMenu(recyclerView)
@@ -126,115 +243,6 @@ abstract class EpisodesListFragment : Fragment(), SelectableAdapter.OnSelectMode
}
}
- @UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- super.onCreateView(inflater, container, savedInstanceState)
-
- val viewBinding = EpisodesListFragmentBinding.inflate(inflater)
- Log.d(TAG, "fragment onCreateView")
-
- txtvInformation = viewBinding.txtvInformation
- toolbar = viewBinding.toolbar
- toolbar.setOnMenuItemClickListener(this)
- toolbar.setOnLongClickListener {
- recyclerView.scrollToPosition(5)
- recyclerView.post { recyclerView.smoothScrollToPosition(0) }
- false
- }
- displayUpArrow = parentFragmentManager.backStackEntryCount != 0
- if (savedInstanceState != null) {
- displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW)
- }
- (activity as MainActivity).setupToolbarToggle(toolbar, displayUpArrow)
-
- recyclerView = viewBinding.recyclerView
- recyclerView.setRecycledViewPool((activity as MainActivity).recycledViewPool)
- setupLoadMoreScrollListener()
- recyclerView.addOnScrollListener(LiftOnScrollListener(viewBinding.appbar))
-
- swipeActions = SwipeActions(this, getFragmentTag()).attachTo(recyclerView)
- swipeActions.setFilter(getFilter())
-
- val animator: RecyclerView.ItemAnimator? = recyclerView.itemAnimator
- if (animator is SimpleItemAnimator) {
- animator.supportsChangeAnimations = false
- }
-
- swipeRefreshLayout = viewBinding.swipeRefresh
- swipeRefreshLayout.setDistanceToTriggerSync(resources.getInteger(R.integer.swipe_refresh_distance))
- swipeRefreshLayout.setOnRefreshListener {
- FeedUpdateManager.runOnceOrAsk(requireContext())
- }
-
- listAdapter = object : EpisodeItemListAdapter(activity as MainActivity) {
- override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
- super.onCreateContextMenu(menu, v, menuInfo)
-// if (!inActionMode()) {
-// menu.findItem(R.id.multi_select).setVisible(true)
-// }
- MenuItemUtils.setOnClickListeners(menu
- ) { item: MenuItem ->
- this@EpisodesListFragment.onContextItemSelected(item)
- }
- }
- }
- listAdapter.setOnSelectModeListener(this)
- recyclerView.adapter = listAdapter
- progressBar = viewBinding.progressBar
- progressBar.visibility = View.VISIBLE
-
- emptyView = EmptyViewHandler(requireContext())
- emptyView.attachToRecyclerView(recyclerView)
- emptyView.setIcon(R.drawable.ic_feed)
- emptyView.setTitle(R.string.no_all_episodes_head_label)
- emptyView.setMessage(R.string.no_all_episodes_label)
- emptyView.updateAdapter(listAdapter)
- emptyView.hide()
-
- val multiSelectDial = MultiSelectSpeedDialBinding.bind(viewBinding.root)
- speedDialView = multiSelectDial.fabSD
- speedDialView.overlayLayout = multiSelectDial.fabSDOverlay
- speedDialView.inflate(R.menu.episodes_apply_action_speeddial)
- speedDialView.setOnChangeListener(object : SpeedDialView.OnChangeListener {
- override fun onMainActionSelected(): Boolean {
- return false
- }
-
- override fun onToggleChanged(open: Boolean) {
- if (open && listAdapter.selectedCount == 0) {
- (activity as MainActivity).showSnackbarAbovePlayer(R.string.no_items_selected,
- Snackbar.LENGTH_SHORT)
- speedDialView.close()
- }
- }
- })
- speedDialView.setOnActionSelectedListener { actionItem: SpeedDialActionItem ->
- var confirmationString = 0
- if (listAdapter.selectedItems.size >= 25 || listAdapter.shouldSelectLazyLoadedItems()) {
- // Should ask for confirmation
- if (actionItem.id == R.id.mark_read_batch) {
- confirmationString = R.string.multi_select_mark_played_confirmation
- } else if (actionItem.id == R.id.mark_unread_batch) {
- confirmationString = R.string.multi_select_mark_unplayed_confirmation
- }
- }
- if (confirmationString == 0) {
- performMultiSelectAction(actionItem.id)
- } else {
- object : ConfirmationDialog(activity as MainActivity, R.string.multi_select, confirmationString) {
- override fun onConfirmButtonPressed(dialog: DialogInterface) {
- performMultiSelectAction(actionItem.id)
- }
- }.createNewDialog().show()
- }
- true
- }
-
- EventBus.getDefault().register(this)
- loadItems()
-
- return viewBinding.root
- }
-
@UnstableApi private fun performMultiSelectAction(actionItemId: Int) {
val handler = EpisodeMultiSelectActionHandler((activity as MainActivity), actionItemId)
Completable.fromAction {
@@ -379,6 +387,16 @@ abstract class EpisodesListFragment : Fragment(), SelectableAdapter.OnSelectMode
loadItems()
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onSwipeActionsChanged(event: SwipeActionsChangedEvent?) {
+ if (swipeActions.actions?.left != null) {
+ binding.leftActionIcon.setImageResource(swipeActions.actions!!.left!!.getActionIcon())
+ }
+ if (swipeActions.actions?.right != null) {
+ binding.rightActionIcon.setImageResource(swipeActions.actions!!.right!!.getActionIcon())
+ }
+ }
+
fun loadItems() {
disposable?.dispose()
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ExternalPlayerFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ExternalPlayerFragment.kt
index 3f4a1337..0f8bbb66 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ExternalPlayerFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ExternalPlayerFragment.kt
@@ -240,7 +240,7 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
if (showTimeLeft) {
txtvLength.setContentDescription(getString(R.string.remaining_time,
Converter.getDurationStringLocalized(requireContext(), remainingTime.toLong())))
- txtvLength.text = (if ((remainingTime > 0)) "-" else "") + Converter.getDurationStringLong(remainingTime)
+ txtvLength.text = (if (remainingTime > 0) "-" else "") + Converter.getDurationStringLong(remainingTime)
} else {
txtvLength.setContentDescription(getString(R.string.chapter_duration,
Converter.getDurationStringLocalized(requireContext(), duration.toLong())))
@@ -289,9 +289,7 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
}
disposable?.dispose()
- disposable = Maybe.fromCallable {
- controller?.getMedia()
- }
+ disposable = Maybe.fromCallable { controller?.getMedia() }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ media: Playable? -> this.updateUi(media) },
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedItemlistFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedItemlistFragment.kt
index 430cf898..b8e82dca 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedItemlistFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/FeedItemlistFragment.kt
@@ -115,7 +115,15 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
adapter = FeedItemListAdapter(activity as MainActivity)
adapter.setOnSelectModeListener(this)
binding.recyclerView.adapter = adapter
+
swipeActions = SwipeActions(this, TAG).attachTo(binding.recyclerView)
+ if (swipeActions.actions?.left != null) {
+ binding.header.leftActionIcon.setImageResource(swipeActions.actions!!.left!!.getActionIcon())
+ }
+ if (swipeActions.actions?.right != null) {
+ binding.header.rightActionIcon.setImageResource(swipeActions.actions!!.right!!.getActionIcon())
+ }
+
binding.progressBar.visibility = View.VISIBLE
val iconTintManager: ToolbarIconTintManager = object : ToolbarIconTintManager(
@@ -399,6 +407,16 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
}
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onSwipeActionsChanged(event: SwipeActionsChangedEvent?) {
+ if (swipeActions.actions?.left != null) {
+ binding.header.leftActionIcon.setImageResource(swipeActions.actions!!.left!!.getActionIcon())
+ }
+ if (swipeActions.actions?.right != null) {
+ binding.header.rightActionIcon.setImageResource(swipeActions.actions!!.right!!.getActionIcon())
+ }
+ }
+
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: FeedUpdateRunningEvent) {
nextPageLoader.setLoadingState(event.isFeedUpdateRunning)
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemDescriptionFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemDescriptionFragment.kt
index a3362364..bbf4ecb3 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemDescriptionFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemDescriptionFragment.kt
@@ -33,7 +33,7 @@ class ItemDescriptionFragment : Fragment() {
private var controller: PlaybackController? = null
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- Log.d(TAG, "Creating view")
+ Log.d(TAG, "fragment onCreateView")
val binding = ItemDescriptionFragmentBinding.inflate(inflater)
Log.d(TAG, "fragment onCreateView")
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemFragment.kt
index e5bfd60f..7c6dc89d 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemFragment.kt
@@ -326,9 +326,8 @@ class ItemFragment : Fragment() {
}
@OptIn(UnstableApi::class) private fun openPodcast() {
- if (item == null) {
- return
- }
+ if (item == null) return
+
val fragment: Fragment = FeedItemlistFragment.newInstance(item!!.feedId)
(activity as MainActivity).loadChildFragment(fragment)
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPageFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPageFragment.kt
index e2732c24..c4b129fd 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPageFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPageFragment.kt
@@ -145,9 +145,8 @@ class ItemPageFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
@UnstableApi private fun openPodcast() {
- if (item == null) {
- return
- }
+ if (item == null) return
+
val fragment: Fragment = FeedItemlistFragment.newInstance(item!!.feedId)
(activity as MainActivity).loadChildFragment(fragment)
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPagerFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPagerFragment.kt
index a8c1104c..2dcd0de9 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPagerFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPagerFragment.kt
@@ -162,9 +162,8 @@ class ItemPagerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
@UnstableApi private fun openPodcast() {
- if (item == null) {
- return
- }
+ if (item == null) return
+
val fragment: Fragment = FeedItemlistFragment.newInstance(item!!.feedId)
(activity as MainActivity).loadChildFragment(fragment)
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt
index 9106ff2b..c1671a73 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt
@@ -65,7 +65,6 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
): View {
super.onCreateView(inflater, container, savedInstanceState)
val binding = NavListBinding.inflate(inflater)
-// val root: View = inflater.inflate(R.layout.nav_list, container, false)
Log.d(TAG, "fragment onCreateView")
setupDrawerRoundBackground(binding.root)
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt
index 7c5fec45..549a031c 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt
@@ -18,21 +18,17 @@ import com.google.android.material.appbar.MaterialToolbar
import ac.mdiq.podcini.R
import ac.mdiq.podcini.databinding.FragmentItunesSearchBinding
import ac.mdiq.podcini.ui.activity.OnlineFeedViewActivity
-import ac.mdiq.podcini.ui.adapter.itunes.ItunesAdapter
+import ac.mdiq.podcini.ui.adapter.OnlineFeedsAdapter
import ac.mdiq.podcini.net.discovery.PodcastSearchResult
import ac.mdiq.podcini.net.discovery.PodcastSearcher
import ac.mdiq.podcini.net.discovery.PodcastSearcherRegistry
import io.reactivex.disposables.Disposable
-class OnlineSearchFragment
-/**
- * Constructor
- */
- : Fragment() {
+class OnlineSearchFragment : Fragment() {
/**
* Adapter responsible with the search results
*/
- private var adapter: ItunesAdapter? = null
+ private var adapter: OnlineFeedsAdapter? = null
private var searchProvider: PodcastSearcher? = null
private lateinit var gridView: GridView
@@ -63,13 +59,11 @@ class OnlineSearchFragment
}
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- // Inflate the layout for this fragment
val binding = FragmentItunesSearchBinding.inflate(inflater)
-// val root: View = inflater.inflate(R.layout.fragment_itunes_search, container, false)
Log.d(TAG, "fragment onCreateView")
gridView = binding.gridView
- adapter = ItunesAdapter(requireContext(), ArrayList())
+ adapter = OnlineFeedsAdapter(requireContext(), ArrayList())
gridView.setAdapter(adapter)
//Show information about the podcast when the list item is clicked
@@ -121,24 +115,26 @@ class OnlineSearchFragment
toolbar.setNavigationOnClickListener { parentFragmentManager.popBackStack() }
val searchItem: MenuItem = toolbar.menu.findItem(R.id.action_search)
- val sv = searchItem.actionView as SearchView?
- sv!!.queryHint = getString(R.string.search_podcast_hint)
- sv.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
- override fun onQueryTextSubmit(s: String): Boolean {
- sv.clearFocus()
- search(s)
- return true
- }
+ val sv = searchItem.actionView as? SearchView
+ if (sv != null) {
+ sv.queryHint = getString(R.string.search_podcast_hint)
+ sv.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(s: String): Boolean {
+ sv.clearFocus()
+ search(s)
+ return true
+ }
- override fun onQueryTextChange(s: String): Boolean {
- return false
- }
- })
- sv.setOnQueryTextFocusChangeListener(View.OnFocusChangeListener { view: View, hasFocus: Boolean ->
- if (hasFocus) {
- showInputMethod(view.findFocus())
- }
- })
+ override fun onQueryTextChange(s: String): Boolean {
+ return false
+ }
+ })
+ sv.setOnQueryTextFocusChangeListener(View.OnFocusChangeListener { view: View, hasFocus: Boolean ->
+ if (hasFocus) {
+ showInputMethod(view.findFocus())
+ }
+ })
+ }
searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
return true
@@ -152,7 +148,7 @@ class OnlineSearchFragment
searchItem.expandActionView()
if (requireArguments().getString(ARG_QUERY, null) != null) {
- sv.setQuery(requireArguments().getString(ARG_QUERY, null), true)
+ sv?.setQuery(requireArguments().getString(ARG_QUERY, null), true)
}
}
@@ -167,8 +163,8 @@ class OnlineSearchFragment
adapter?.clear()
if (searchResults != null) adapter?.addAll(searchResults!!)
adapter?.notifyDataSetInvalidated()
- gridView.visibility = if (searchResults!!.isNotEmpty()) View.VISIBLE else View.GONE
- txtvEmpty.visibility = if (searchResults!!.isEmpty()) View.VISIBLE else View.GONE
+ gridView.visibility = if (!searchResults.isNullOrEmpty()) View.VISIBLE else View.GONE
+ txtvEmpty.visibility = if (searchResults.isNullOrEmpty()) View.VISIBLE else View.GONE
txtvEmpty.text = getString(R.string.no_results_for_query) + query
}, { error: Throwable ->
Log.e(TAG, Log.getStackTraceString(error))
@@ -194,7 +190,7 @@ class OnlineSearchFragment
}
companion object {
- private const val TAG = "FyydSearchFragment"
+ private const val TAG = "OnlineSearchFragment"
private const val ARG_SEARCHER = "searcher"
private const val ARG_QUERY = "query"
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt
index 94e66f56..7adb2884 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt
@@ -64,6 +64,7 @@ import java.util.*
*/
class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAdapter.OnSelectModeListener {
+ private lateinit var binding: QueueFragmentBinding
private lateinit var infoBar: TextView
private lateinit var recyclerView: EpisodeItemListRecyclerView
private lateinit var emptyView: EmptyViewHandler
@@ -88,7 +89,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
- val binding = QueueFragmentBinding.inflate(inflater)
+ binding = QueueFragmentBinding.inflate(inflater)
Log.d(TAG, "fragment onCreateView")
toolbar = binding.toolbar
@@ -122,6 +123,13 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
swipeActions.setFilter(FeedItemFilter(FeedItemFilter.QUEUED))
swipeActions.attachTo(recyclerView)
+ if (swipeActions.actions?.left != null) {
+ binding.leftActionIcon.setImageResource(swipeActions.actions!!.left!!.getActionIcon())
+ }
+ if (swipeActions.actions?.right != null) {
+ binding.rightActionIcon.setImageResource(swipeActions.actions!!.right!!.getActionIcon())
+ }
+
recyclerAdapter = object : QueueRecyclerAdapter(activity as MainActivity, swipeActions) {
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
super.onCreateContextMenu(menu, v, menuInfo)
@@ -288,6 +296,16 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
refreshToolbarState()
}
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onSwipeActionsChanged(event: SwipeActionsChangedEvent?) {
+ if (swipeActions.actions?.left != null) {
+ binding.leftActionIcon.setImageResource(swipeActions.actions!!.left!!.getActionIcon())
+ }
+ if (swipeActions.actions?.right != null) {
+ binding.rightActionIcon.setImageResource(swipeActions.actions!!.right!!.getActionIcon())
+ }
+ }
+
@Subscribe(threadMode = ThreadMode.MAIN)
fun onKeyUp(event: KeyEvent) {
if (!isAdded || !isVisible || !isMenuVisible) {
@@ -456,7 +474,6 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
}
}
info += " • "
- info += getString(R.string.time_left_label)
info += Converter.getDurationStringLocalized(requireActivity(), timeLeft)
}
infoBar.text = info
@@ -503,10 +520,10 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
sortOrder = UserPreferences.queueKeepSortedOrder
}
val view: View = super.onCreateView(inflater, container, savedInstanceState)!!
- viewBinding.keepSortedCheckbox.visibility = View.VISIBLE
- viewBinding.keepSortedCheckbox.setChecked(UserPreferences.isQueueKeepSorted)
+ binding.keepSortedCheckbox.visibility = View.VISIBLE
+ binding.keepSortedCheckbox.setChecked(UserPreferences.isQueueKeepSorted)
// Disable until something gets selected
- viewBinding.keepSortedCheckbox.setEnabled(UserPreferences.isQueueKeepSorted)
+ binding.keepSortedCheckbox.setEnabled(UserPreferences.isQueueKeepSorted)
return view
}
@@ -518,11 +535,11 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
@UnstableApi override fun onSelectionChanged() {
super.onSelectionChanged()
- viewBinding.keepSortedCheckbox.setEnabled(sortOrder != SortOrder.RANDOM)
+ binding.keepSortedCheckbox.setEnabled(sortOrder != SortOrder.RANDOM)
if (sortOrder == SortOrder.RANDOM) {
- viewBinding.keepSortedCheckbox.setChecked(false)
+ binding.keepSortedCheckbox.setChecked(false)
}
- UserPreferences.isQueueKeepSorted = viewBinding.keepSortedCheckbox.isChecked
+ UserPreferences.isQueueKeepSorted = binding.keepSortedCheckbox.isChecked
UserPreferences.queueKeepSortedOrder = sortOrder
DBWriter.reorderQueue(sortOrder, true)
}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/preferences/SwipePreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/preferences/SwipePreferencesFragment.kt
index a7fdb527..5cef542f 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/preferences/SwipePreferencesFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/preferences/SwipePreferencesFragment.kt
@@ -19,13 +19,6 @@ class SwipePreferencesFragment : PreferenceFragmentCompat() {
})
true
}
-// findPreference(PREF_SWIPE_INBOX)?.onPreferenceClickListener =
-// Preference.OnPreferenceClickListener {
-// SwipeActionsDialog(requireContext(), InboxFragment.TAG).show (object : SwipeActionsDialog.Callback {
-// override fun onCall() {}
-// })
-// true
-// }
findPreference(PREF_SWIPE_EPISODES)?.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
SwipeActionsDialog(requireContext(), AllEpisodesFragment.TAG).show (object : SwipeActionsDialog.Callback {
@@ -63,7 +56,6 @@ class SwipePreferencesFragment : PreferenceFragmentCompat() {
companion object {
private const val PREF_SWIPE_QUEUE = "prefSwipeQueue"
-// private const val PREF_SWIPE_INBOX = "prefSwipeInbox"
// private const val PREF_SWIPE_STATISTICS = "prefSwipeStatistics"
private const val PREF_SWIPE_EPISODES = "prefSwipeEpisodes"
private const val PREF_SWIPE_DOWNLOADS = "prefSwipeDownloads"
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/preferences/UserInterfacePreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/preferences/UserInterfacePreferencesFragment.kt
index 27f186d3..69e9353b 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/preferences/UserInterfacePreferencesFragment.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/preferences/UserInterfacePreferencesFragment.kt
@@ -64,11 +64,11 @@ class UserInterfacePreferencesFragment : PreferenceFragmentCompat() {
showFullNotificationButtonsDialog()
true
}
- findPreference(UserPreferences.PREF_FILTER_FEED)?.onPreferenceClickListener =
- (Preference.OnPreferenceClickListener {
- SubscriptionsFilterDialog().show(childFragmentManager, "filter")
- true
- })
+// findPreference(UserPreferences.PREF_FILTER_FEED)?.onPreferenceClickListener =
+// (Preference.OnPreferenceClickListener {
+// SubscriptionsFilterDialog().show(childFragmentManager, "filter")
+// true
+// })
findPreference(UserPreferences.PREF_DRAWER_FEED_ORDER)?.onPreferenceClickListener =
(Preference.OnPreferenceClickListener {
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/NoActionSwipeAction.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/NoActionSwipeAction.kt
new file mode 100644
index 00000000..d893e07f
--- /dev/null
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/NoActionSwipeAction.kt
@@ -0,0 +1,35 @@
+package ac.mdiq.podcini.ui.fragment.swipeactions
+
+import android.content.Context
+import androidx.fragment.app.Fragment
+import androidx.media3.common.util.UnstableApi
+import ac.mdiq.podcini.R
+import ac.mdiq.podcini.storage.DBWriter
+import ac.mdiq.podcini.storage.model.feed.FeedItem
+import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
+import ac.mdiq.podcini.ui.view.LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary
+
+class NoActionSwipeAction : SwipeAction {
+ override fun getId(): String {
+ return SwipeAction.NO_ACTION
+ }
+
+ override fun getActionIcon(): Int {
+ return R.drawable.ic_questionmark
+ }
+
+ override fun getActionColor(): Int {
+ return R.attr.icon_red
+ }
+
+ override fun getTitle(context: Context): String {
+ return context.getString(R.string.no_action_label)
+ }
+
+ @UnstableApi override fun performAction(item: FeedItem, fragment: Fragment, filter: FeedItemFilter) {
+ }
+
+ override fun willRemove(filter: FeedItemFilter, item: FeedItem): Boolean {
+ return false
+ }
+}
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/SwipeAction.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/SwipeAction.kt
index b631bb3f..e52250bb 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/SwipeAction.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/SwipeAction.kt
@@ -24,6 +24,8 @@ interface SwipeAction {
fun willRemove(filter: FeedItemFilter, item: FeedItem): Boolean
companion object {
+ const val NO_ACTION: String = "NO_ACTION"
+
const val ADD_TO_QUEUE: String = "ADD_TO_QUEUE"
const val START_DOWNLOAD: String = "START_DOWNLOAD"
const val MARK_FAV: String = "MARK_FAV"
diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/SwipeActions.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/SwipeActions.kt
index 1c6af85c..5c5baec3 100644
--- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/SwipeActions.kt
+++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/swipeactions/SwipeActions.kt
@@ -17,7 +17,10 @@ import ac.mdiq.podcini.ui.fragment.*
import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
import ac.mdiq.podcini.ui.common.ThemeUtils.getColorFromAttr
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
+import ac.mdiq.podcini.util.event.PlayerStatusEvent
+import ac.mdiq.podcini.util.event.SwipeActionsChangedEvent
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
+import org.greenrobot.eventbus.EventBus
import java.util.*
import kotlin.math.max
import kotlin.math.min
@@ -25,6 +28,7 @@ import kotlin.math.sin
open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private val tag: String) :
ItemTouchHelper.SimpleCallback(dragDirs, ItemTouchHelper.RIGHT or ItemTouchHelper.LEFT), LifecycleObserver {
+
private var filter: FeedItemFilter? = null
var actions: Actions? = null
@@ -73,6 +77,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
SwipeActionsDialog(fragment.requireContext(), tag).show(object : SwipeActionsDialog.Callback {
override fun onCall() {
this@SwipeActions.reloadPreference()
+ EventBus.getDefault().post(SwipeActionsChangedEvent())
}
})
return
@@ -147,7 +152,6 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
max(0.5, displacementPercentage.toDouble()).toFloat()))
builder.create().decorate()
-
super.onChildDraw(c, recyclerView, viewHolder, dx, dy, actionState, isCurrentlyActive)
}
@@ -202,7 +206,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
}
fun hasActions(): Boolean {
- return right != null && left != null
+ return right != null && left != null && right!!.getId() != SwipeAction.NO_ACTION && left!!.getId() != SwipeAction.NO_ACTION
}
}
@@ -213,7 +217,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
@JvmField
val swipeActions: List = Collections.unmodifiableList(
- listOf(AddToQueueSwipeAction(), StartDownloadSwipeAction(), MarkFavoriteSwipeAction(),
+ listOf(NoActionSwipeAction(), AddToQueueSwipeAction(), StartDownloadSwipeAction(), MarkFavoriteSwipeAction(),
TogglePlaybackStateSwipeAction(), RemoveFromQueueSwipeAction(),
DeleteSwipeAction(), RemoveFromHistorySwipeAction())
)
@@ -225,19 +229,18 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
return Actions(prefsString)
}
- private fun getPrefs(context: Context, tag: String): Actions {
+ fun getPrefs(context: Context, tag: String): Actions {
return getPrefs(context, tag, "")
}
@JvmStatic
fun getPrefsWithDefaults(context: Context, tag: String): Actions {
val defaultActions = when (tag) {
-// InboxFragment.TAG -> SwipeAction.ADD_TO_QUEUE + "," + SwipeAction.REMOVE_FROM_INBOX
- QueueFragment.TAG -> SwipeAction.REMOVE_FROM_QUEUE + "," + SwipeAction.REMOVE_FROM_QUEUE
- CompletedDownloadsFragment.TAG -> SwipeAction.DELETE + "," + SwipeAction.DELETE
- PlaybackHistoryFragment.TAG -> SwipeAction.REMOVE_FROM_HISTORY + "," + SwipeAction.REMOVE_FROM_HISTORY
- AllEpisodesFragment.TAG -> SwipeAction.MARK_FAV + "," + SwipeAction.START_DOWNLOAD
- else -> SwipeAction.MARK_FAV + "," + SwipeAction.START_DOWNLOAD
+ QueueFragment.TAG -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
+ CompletedDownloadsFragment.TAG -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
+ PlaybackHistoryFragment.TAG -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
+ AllEpisodesFragment.TAG -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
+ else -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
}
return getPrefs(context, tag, defaultActions)
}
diff --git a/app/src/main/java/ac/mdiq/podcini/util/ChapterUtils.kt b/app/src/main/java/ac/mdiq/podcini/util/ChapterUtils.kt
index 4ea3ed63..4efb6f88 100644
--- a/app/src/main/java/ac/mdiq/podcini/util/ChapterUtils.kt
+++ b/app/src/main/java/ac/mdiq/podcini/util/ChapterUtils.kt
@@ -118,21 +118,23 @@ object ChapterUtils {
if (playable.getLocalMediaUrl() == null) {
throw IOException("No local url")
}
- val source = File(playable.getLocalMediaUrl()?:"")
+ val source = File(playable.getLocalMediaUrl() ?: "")
if (!source.exists()) {
throw IOException("Local file does not exist")
}
return CountingInputStream(BufferedInputStream(FileInputStream(source)))
- } else if (playable.getStreamUrl() != null && playable.getStreamUrl()!!.startsWith(ContentResolver.SCHEME_CONTENT)) {
- val uri = Uri.parse(playable.getStreamUrl())
- return CountingInputStream(BufferedInputStream(context.contentResolver.openInputStream(uri)))
} else {
- val request: Request = Builder().url(playable.getStreamUrl()?:"").build()
- val response = getHttpClient().newCall(request).execute()
- if (response.body == null) {
- throw IOException("Body is null")
+ val streamurl = playable.getStreamUrl()
+ if (streamurl != null && streamurl.startsWith(ContentResolver.SCHEME_CONTENT)) {
+ val uri = Uri.parse(streamurl)
+ return CountingInputStream(BufferedInputStream(context.contentResolver.openInputStream(uri)))
+ } else {
+ if (streamurl.isNullOrEmpty()) throw IOException("stream url is null of empty")
+ val request: Request = Builder().url(streamurl).build()
+ val response = getHttpClient().newCall(request).execute()
+ if (response.body == null) throw IOException("Body is null")
+ return CountingInputStream(BufferedInputStream(response.body!!.byteStream()))
}
- return CountingInputStream(BufferedInputStream(response.body!!.byteStream()))
}
}
diff --git a/app/src/main/java/ac/mdiq/podcini/util/event/SwipeActionsChangedEvent.kt b/app/src/main/java/ac/mdiq/podcini/util/event/SwipeActionsChangedEvent.kt
new file mode 100644
index 00000000..94e89048
--- /dev/null
+++ b/app/src/main/java/ac/mdiq/podcini/util/event/SwipeActionsChangedEvent.kt
@@ -0,0 +1,3 @@
+package ac.mdiq.podcini.util.event
+
+class SwipeActionsChangedEvent
diff --git a/app/src/main/res/drawable/baseline_arrow_left_alt_24.xml b/app/src/main/res/drawable/baseline_arrow_left_alt_24.xml
new file mode 100644
index 00000000..f44b1280
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_arrow_left_alt_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_arrow_right_alt_24.xml b/app/src/main/res/drawable/baseline_arrow_right_alt_24.xml
new file mode 100644
index 00000000..04dc4f99
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_arrow_right_alt_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_arrow_upward_24.xml b/app/src/main/res/drawable/baseline_arrow_upward_24.xml
index 2b2c71a3..32bad393 100644
--- a/app/src/main/res/drawable/baseline_arrow_upward_24.xml
+++ b/app/src/main/res/drawable/baseline_arrow_upward_24.xml
@@ -1,5 +1,6 @@
-
+
diff --git a/app/src/main/res/layout/episodes_list_fragment.xml b/app/src/main/res/layout/episodes_list_fragment.xml
index e0596601..748ff25f 100644
--- a/app/src/main/res/layout/episodes_list_fragment.xml
+++ b/app/src/main/res/layout/episodes_list_fragment.xml
@@ -20,18 +20,60 @@
app:navigationContentDescription="@string/toolbar_back_button_content_description"
app:navigationIcon="?homeAsUpIndicator" />
-
+ android:orientation="horizontal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/feeditem_page_fragment.xml b/app/src/main/res/layout/feeditem_page_fragment.xml
index 1a0c6c89..0ab96a57 100644
--- a/app/src/main/res/layout/feeditem_page_fragment.xml
+++ b/app/src/main/res/layout/feeditem_page_fragment.xml
@@ -21,7 +21,6 @@
android:id="@+id/fragment_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:foreground="?android:windowContentOverlay"
- />
+ android:foreground="?android:windowContentOverlay"/>
diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml
index 01717b8e..247820cf 100644
--- a/app/src/main/res/layout/feeditemlist_header.xml
+++ b/app/src/main/res/layout/feeditemlist_header.xml
@@ -152,18 +152,61 @@
tools:visibility="visible"
tools:text="(!) Last refresh failed" />
-
+ android:orientation="horizontal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tools:listitem="@layout/online_podcast_listitem" />
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/itemdescription_listitem.xml b/app/src/main/res/layout/online_item_description.xml
similarity index 97%
rename from app/src/main/res/layout/itemdescription_listitem.xml
rename to app/src/main/res/layout/online_item_description.xml
index 04d35fb2..205fa38a 100644
--- a/app/src/main/res/layout/itemdescription_listitem.xml
+++ b/app/src/main/res/layout/online_item_description.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/itemdescription_listitem"
+ android:id="@+id/online_item_description"
android:orientation="vertical"
android:paddingHorizontal="20dp"
android:paddingVertical="16dp">
diff --git a/app/src/main/res/layout/online_podcast_listitem.xml b/app/src/main/res/layout/online_podcast_listitem.xml
new file mode 100644
index 00000000..c4b69b1e
--- /dev/null
+++ b/app/src/main/res/layout/online_podcast_listitem.xml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/onlinefeedview_activity.xml b/app/src/main/res/layout/onlinefeedview_activity.xml
index 88b87da1..09d2ce03 100644
--- a/app/src/main/res/layout/onlinefeedview_activity.xml
+++ b/app/src/main/res/layout/onlinefeedview_activity.xml
@@ -161,7 +161,6 @@
android:text="@string/stop_preview"
android:visibility="gone"
tools:visibility="visible" />
-
-
+ android:orientation="horizontal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/simple_list_fragment.xml b/app/src/main/res/layout/simple_list_fragment.xml
index 6678590d..1888422a 100644
--- a/app/src/main/res/layout/simple_list_fragment.xml
+++ b/app/src/main/res/layout/simple_list_fragment.xml
@@ -19,17 +19,58 @@
app:navigationContentDescription="@string/toolbar_back_button_content_description"
app:navigationIcon="?homeAsUpIndicator" />
-
+ android:orientation="horizontal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index a99151ac..c7cae491 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -45,7 +45,7 @@
-
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 1c0a5045..1af6847d 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -10,7 +10,7 @@
14sp
16sp
20sp
- 56dp
+ 65dp
56dp
92dp
132dp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4e074370..fda2d144 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -217,6 +217,8 @@
- %d downloaded episodes deleted.
+ No action
+
Removed from inbox
Mark as played
Toggle played state
diff --git a/app/src/main/res/xml/preferences_swipe.xml b/app/src/main/res/xml/preferences_swipe.xml
index 04231189..43bef5ab 100644
--- a/app/src/main/res/xml/preferences_swipe.xml
+++ b/app/src/main/res/xml/preferences_swipe.xml
@@ -5,10 +5,6 @@
android:key="prefSwipeQueue"
android:title="@string/queue_label"/>
-
-
-
-
@@ -21,12 +17,12 @@
android:key="prefSwipeHistory"
android:title="@string/playback_history_label"/>
-
+
+
+
-
+
+
+
diff --git a/app/src/main/res/xml/preferences_user_interface.xml b/app/src/main/res/xml/preferences_user_interface.xml
index 44c32604..b6afa89a 100644
--- a/app/src/main/res/xml/preferences_user_interface.xml
+++ b/app/src/main/res/xml/preferences_user_interface.xml
@@ -45,10 +45,10 @@
android:key="prefDrawerFeedIndicator"
android:summary="@string/pref_nav_drawer_feed_counter_sum"
android:defaultValue="1"/>
-
+
+
+
+
diff --git a/changelog.md b/changelog.md
index 7fddde42..03b2000e 100644
--- a/changelog.md
+++ b/changelog.md
@@ -93,4 +93,15 @@
* renewed PodcastIndex API keys
* added share notes menu option in episode view
* press on title area of an episode now opens the episode info faster and more economically - without horizontal swipe
-* press on the icon of an episode opens the episode info the original way - with horizontal swipe
\ No newline at end of file
+* press on the icon of an episode opens the episode info the original way - with horizontal swipe
+
+## 4.3.0
+
+* added more info about feeds in the online search view
+* fixed bug of preview not playing
+* disabled feed filters setting in preference
+* "open feed" is an action item on audio player top bar
+* added swipe action telltales in all episode lists
+* added NO_ACTION swipe action
+* all default swipe actions are set to NO_ACTION
+* cleaned up swipe preferences ui: statistics and individual subs removed
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/3020111.txt b/fastlane/metadata/android/en-US/changelogs/3020111.txt
new file mode 100644
index 00000000..9e5b4d0c
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/3020111.txt
@@ -0,0 +1,11 @@
+
+Version 4.3.0 brings several changes:
+
+* added more info about feeds in the online search view
+* fixed bug of preview not playing
+* disabled feed filters setting in preference
+* "open feed" is an action item on audio player top bar
+* added swipe action telltales in all episode lists
+* added NO_ACTION swipe action
+* all default swipe actions are set to NO_ACTION
+* cleaned up swipe preferences ui: statistics and individual subs removed
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/10_player.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/10_player.jpg
deleted file mode 100644
index ec3dc6a5..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/10_player.jpg and /dev/null differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1_drawer.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/1_drawer.jpg
index b7fa0f56..fa57ef74 100644
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/1_drawer.jpg and b/fastlane/metadata/android/en-US/images/phoneScreenshots/1_drawer.jpg differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2_setting.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/2_setting.jpg
index a3804756..733c1859 100644
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/2_setting.jpg and b/fastlane/metadata/android/en-US/images/phoneScreenshots/2_setting.jpg differ
diff --git a/images/3_setting.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/2_setting1.jpg
similarity index 100%
rename from images/3_setting.jpg
rename to fastlane/metadata/android/en-US/images/phoneScreenshots/2_setting1.jpg
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/3_setting.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/3_setting.jpg
deleted file mode 100644
index ffcfe8e6..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/3_setting.jpg and /dev/null differ
diff --git a/images/4_subscriptions.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/3_subscriptions.jpg
similarity index 100%
rename from images/4_subscriptions.jpg
rename to fastlane/metadata/android/en-US/images/phoneScreenshots/3_subscriptions.jpg
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/4_queue.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/4_queue.jpg
new file mode 100644
index 00000000..49305f1b
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/4_queue.jpg differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/4_subscriptions.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/4_subscriptions.jpg
deleted file mode 100644
index 88dfd336..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/4_subscriptions.jpg and /dev/null differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/5_podcast.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/5_podcast.jpg
new file mode 100644
index 00000000..74959cc5
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/5_podcast.jpg differ
diff --git a/images/7_podcast.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/5_podcast1.jpg
similarity index 100%
rename from images/7_podcast.jpg
rename to fastlane/metadata/android/en-US/images/phoneScreenshots/5_podcast1.jpg
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/5_queue.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/5_queue.jpg
deleted file mode 100644
index 55893b4d..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/5_queue.jpg and /dev/null differ
diff --git a/images/8_episode.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/6_episode.jpg
similarity index 100%
rename from images/8_episode.jpg
rename to fastlane/metadata/android/en-US/images/phoneScreenshots/6_episode.jpg
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/6_podcast.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/6_podcast.jpg
deleted file mode 100644
index 53b150de..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/6_podcast.jpg and /dev/null differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/7_podcast.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/7_podcast.jpg
deleted file mode 100644
index b9788611..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/7_podcast.jpg and /dev/null differ
diff --git a/images/9_speed.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/7_speed.jpg
similarity index 100%
rename from images/9_speed.jpg
rename to fastlane/metadata/android/en-US/images/phoneScreenshots/7_speed.jpg
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/8_episode.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/8_episode.jpg
deleted file mode 100644
index f8e81f9c..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/8_episode.jpg and /dev/null differ
diff --git a/images/10_player.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/8_player.jpg
similarity index 100%
rename from images/10_player.jpg
rename to fastlane/metadata/android/en-US/images/phoneScreenshots/8_player.jpg
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/91_feed_search.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/91_feed_search.jpg
new file mode 100644
index 00000000..6af26191
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/91_feed_search.jpg differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/9_speed.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/9_speed.jpg
deleted file mode 100644
index 0d372337..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/9_speed.jpg and /dev/null differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/9_swipe_setting.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/9_swipe_setting.jpg
new file mode 100644
index 00000000..fac5b83a
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/9_swipe_setting.jpg differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/9_swipe_setting1.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/9_swipe_setting1.jpg
new file mode 100644
index 00000000..24e666a9
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/9_swipe_setting1.jpg differ
diff --git a/images/1_drawer1.jpg b/images/1_drawer.jpg
similarity index 100%
rename from images/1_drawer1.jpg
rename to images/1_drawer.jpg
diff --git a/images/2_setting1.jpg b/images/2_setting1.jpg
new file mode 100644
index 00000000..0797edc4
Binary files /dev/null and b/images/2_setting1.jpg differ
diff --git a/images/3_subscriptions.jpg b/images/3_subscriptions.jpg
new file mode 100644
index 00000000..255d2e46
Binary files /dev/null and b/images/3_subscriptions.jpg differ
diff --git a/images/4_queue.jpg b/images/4_queue.jpg
new file mode 100644
index 00000000..49305f1b
Binary files /dev/null and b/images/4_queue.jpg differ
diff --git a/images/5_podcast.jpg b/images/5_podcast.jpg
new file mode 100644
index 00000000..74959cc5
Binary files /dev/null and b/images/5_podcast.jpg differ
diff --git a/images/5_podcast1.jpg b/images/5_podcast1.jpg
new file mode 100644
index 00000000..3b6a1f16
Binary files /dev/null and b/images/5_podcast1.jpg differ
diff --git a/images/5_queue.jpg b/images/5_queue.jpg
deleted file mode 100644
index 7163713a..00000000
Binary files a/images/5_queue.jpg and /dev/null differ
diff --git a/images/6_episode.jpg b/images/6_episode.jpg
new file mode 100644
index 00000000..900a7f5a
Binary files /dev/null and b/images/6_episode.jpg differ
diff --git a/images/6_podcast.jpg b/images/6_podcast.jpg
deleted file mode 100644
index ccf0dbbd..00000000
Binary files a/images/6_podcast.jpg and /dev/null differ
diff --git a/images/7_speed.jpg b/images/7_speed.jpg
new file mode 100644
index 00000000..597d145a
Binary files /dev/null and b/images/7_speed.jpg differ
diff --git a/images/8_player.jpg b/images/8_player.jpg
new file mode 100644
index 00000000..5de97d4e
Binary files /dev/null and b/images/8_player.jpg differ
diff --git a/images/91_feed_search.jpg b/images/91_feed_search.jpg
new file mode 100644
index 00000000..6af26191
Binary files /dev/null and b/images/91_feed_search.jpg differ
diff --git a/images/9_swipe_setting.jpg b/images/9_swipe_setting.jpg
new file mode 100644
index 00000000..fac5b83a
Binary files /dev/null and b/images/9_swipe_setting.jpg differ
diff --git a/images/9_swipe_setting1.jpg b/images/9_swipe_setting1.jpg
new file mode 100644
index 00000000..24e666a9
Binary files /dev/null and b/images/9_swipe_setting1.jpg differ