From 0c801717ac6fd8d4c7a82dac958855d855da15d6 Mon Sep 17 00:00:00 2001
From: Xilin Jia <6257601+XilinJia@users.noreply.github.com>
Date: Tue, 22 Oct 2024 18:40:35 +0100
Subject: [PATCH] 6.12.0 commit
---
README.md | 2 +-
app/build.gradle | 4 +-
.../service/playback/MediaPlayerBaseTest.kt | 2 +-
.../service/playback/TaskManagerTest.kt | 2 +-
.../kotlin/ac/test/podcini/ui/UITestUtils.kt | 3 +-
.../service/DownloadServiceInterfaceImpl.kt | 2 +-
.../mdiq/podcini/net/feed/LocalFeedUpdater.kt | 2 +-
.../mdiq/podcini/playback/base/InTheatre.kt | 6 +-
.../playback/service/PlaybackService.kt | 4 +-
.../storage/algorithms/AutoCleanups.kt | 3 +-
.../mdiq/podcini/storage/database/Episodes.kt | 8 +-
.../ac/mdiq/podcini/storage/database/Feeds.kt | 3 +-
.../podcini/storage/database/LogsAndStats.kt | 2 +-
.../mdiq/podcini/storage/database/Queues.kt | 33 ++++--
.../mdiq/podcini/storage/database/RealmDB.kt | 20 +++-
.../ac/mdiq/podcini/storage/model/Episode.kt | 21 +---
.../podcini/storage/model/EpisodeFilter.kt | 20 ++--
.../ac/mdiq/podcini/storage/model/Feed.kt | 2 +-
.../mdiq/podcini/storage/model/PlayState.kt | 23 ++++
.../podcini/ui/actions/EpisodeActionButton.kt | 54 ++++-----
.../ac/mdiq/podcini/ui/actions/SwipeAction.kt | 1 +
.../mdiq/podcini/ui/actions/SwipeActions.kt | 67 ++++-------
.../mdiq/podcini/ui/activity/MainActivity.kt | 4 +
.../ac/mdiq/podcini/ui/compose/EpisodesVM.kt | 104 +++++++++++++++---
.../ui/fragment/AudioPlayerFragment.kt | 31 ++++--
.../ui/fragment/BaseEpisodesFragment.kt | 13 ++-
.../podcini/ui/fragment/DownloadsFragment.kt | 17 +--
.../ui/fragment/EpisodeInfoFragment.kt | 79 ++++++-------
.../ui/fragment/FeedEpisodesFragment.kt | 81 +++++++++-----
.../podcini/ui/fragment/FeedInfoFragment.kt | 38 ++++---
.../mdiq/podcini/ui/fragment/LogsFragment.kt | 25 +++--
.../podcini/ui/fragment/NavDrawerFragment.kt | 28 +++--
.../podcini/ui/fragment/OnlineFeedFragment.kt | 6 +-
.../podcini/ui/fragment/QueuesFragment.kt | 6 +-
.../ui/fragment/QuickDiscoveryFragment.kt | 13 ++-
.../ui/fragment/SearchResultsFragment.kt | 6 +-
.../ui/fragment/SubscriptionsFragment.kt | 33 +++---
.../ui/statistics/StatisticsFragment.kt | 2 +-
.../main/res/drawable/baseline_build_24.xml | 5 +
.../drawable/baseline_download_done_24.xml | 7 ++
.../res/drawable/baseline_fiber_new_24.xml | 5 +
.../res/drawable/baseline_local_play_24.xml | 5 +
.../res/drawable/baseline_new_label_24.xml | 5 +
.../baseline_play_circle_outline_24.xml | 5 +
.../drawable/baseline_play_disabled_24.xml | 5 +
.../drawable/baseline_visibility_off_24.xml | 5 +
.../res/drawable/baseline_watch_later_24.xml | 5 +
app/src/main/res/layout/addfeed.xml | 26 ++---
.../layout/base_episodes_list_fragment.xml | 36 ------
...info_fragment.xml => compose_fragment.xml} | 13 +--
.../main/res/layout/downloads_fragment.xml | 35 ------
.../res/layout/feed_item_list_fragment.xml | 35 ------
app/src/main/res/layout/feedinfo.xml | 35 ------
.../res/layout/fragment_search_results.xml | 35 ------
app/src/main/res/layout/logs_fragment.xml | 22 ----
app/src/main/res/layout/nav_list.xml | 16 ---
.../res/layout/online_feedview_fragment.xml | 33 ------
app/src/main/res/layout/queue_fragment.xml | 36 ------
app/src/main/res/layout/search_fragment.xml | 24 ++--
.../menu/episodes_apply_action_speeddial.xml | 45 --------
app/src/main/res/menu/feed_episodes.xml | 12 +-
.../main/res/menu/feeditemlist_context.xml | 59 ----------
.../res/menu/multi_select_context_popup.xml | 11 --
.../main/res/menu/multi_select_options.xml | 18 ---
app/src/main/res/menu/queue_context.xml | 16 ---
app/src/main/res/values-ar/strings.xml | 29 +----
app/src/main/res/values-ast/strings.xml | 6 +-
app/src/main/res/values-br/strings.xml | 28 ++---
app/src/main/res/values-ca/strings.xml | 21 +---
app/src/main/res/values-cs/strings.xml | 26 ++---
app/src/main/res/values-da/strings.xml | 21 +---
app/src/main/res/values-de/strings.xml | 21 +---
app/src/main/res/values-es/strings.xml | 23 +---
app/src/main/res/values-et/strings.xml | 16 +--
app/src/main/res/values-eu/strings.xml | 21 +---
app/src/main/res/values-fa/strings.xml | 21 +---
app/src/main/res/values-fi/strings.xml | 21 +---
app/src/main/res/values-fr/strings.xml | 23 +---
app/src/main/res/values-gl/strings.xml | 20 +---
app/src/main/res/values-hu/strings.xml | 21 +---
app/src/main/res/values-in/strings.xml | 19 +---
app/src/main/res/values-it/strings.xml | 23 +---
app/src/main/res/values-iw/strings.xml | 25 +----
app/src/main/res/values-ja/strings.xml | 18 +--
app/src/main/res/values-ko/strings.xml | 19 +---
app/src/main/res/values-lt/strings.xml | 21 +---
app/src/main/res/values-nb/strings.xml | 21 +---
app/src/main/res/values-nl/strings.xml | 21 +---
app/src/main/res/values-pl/strings.xml | 25 +----
app/src/main/res/values-pt-rBR/strings.xml | 23 +---
app/src/main/res/values-pt/strings.xml | 23 +---
app/src/main/res/values-ro/strings.xml | 23 +---
app/src/main/res/values-ru/strings.xml | 25 +----
app/src/main/res/values-sk/strings.xml | 25 +----
app/src/main/res/values-sl/strings.xml | 21 +---
app/src/main/res/values-sv/strings.xml | 21 +---
app/src/main/res/values-tr/strings.xml | 21 +---
app/src/main/res/values-uk/strings.xml | 25 +----
app/src/main/res/values-zh-rCN/strings.xml | 19 +---
app/src/main/res/values-zh-rTW/strings.xml | 11 +-
app/src/main/res/values/strings.xml | 18 +--
.../ac/mdiq/podcini/feed/FeedItemMother.kt | 2 +-
.../ac/mdiq/podcini/storage/DbCleanupTests.kt | 10 +-
.../storage/DbNullCleanupAlgorithmTest.kt | 2 +-
.../DbPlayQueueCleanupAlgorithmTest.kt | 2 +-
.../ac/mdiq/podcini/storage/DbTasksTest.kt | 14 +--
.../ac/mdiq/podcini/storage/DbWriterTest.kt | 36 +++---
.../storage/EpisodeDuplicateGuesserTest.kt | 2 +-
.../ExceptFavoriteCleanupAlgorithmTest.kt | 6 +-
.../ItemEnqueuePositionCalculatorTest.kt | 2 +-
changelog.md | 15 +++
.../android/en-US/changelogs/3020278.txt | 14 +++
112 files changed, 791 insertions(+), 1403 deletions(-)
create mode 100644 app/src/main/kotlin/ac/mdiq/podcini/storage/model/PlayState.kt
create mode 100644 app/src/main/res/drawable/baseline_build_24.xml
create mode 100644 app/src/main/res/drawable/baseline_download_done_24.xml
create mode 100644 app/src/main/res/drawable/baseline_fiber_new_24.xml
create mode 100644 app/src/main/res/drawable/baseline_local_play_24.xml
create mode 100644 app/src/main/res/drawable/baseline_new_label_24.xml
create mode 100644 app/src/main/res/drawable/baseline_play_circle_outline_24.xml
create mode 100644 app/src/main/res/drawable/baseline_play_disabled_24.xml
create mode 100644 app/src/main/res/drawable/baseline_visibility_off_24.xml
create mode 100644 app/src/main/res/drawable/baseline_watch_later_24.xml
delete mode 100644 app/src/main/res/layout/base_episodes_list_fragment.xml
rename app/src/main/res/layout/{episode_info_fragment.xml => compose_fragment.xml} (72%)
delete mode 100644 app/src/main/res/layout/downloads_fragment.xml
delete mode 100644 app/src/main/res/layout/feed_item_list_fragment.xml
delete mode 100644 app/src/main/res/layout/feedinfo.xml
delete mode 100644 app/src/main/res/layout/fragment_search_results.xml
delete mode 100644 app/src/main/res/layout/logs_fragment.xml
delete mode 100644 app/src/main/res/layout/nav_list.xml
delete mode 100644 app/src/main/res/layout/online_feedview_fragment.xml
delete mode 100644 app/src/main/res/layout/queue_fragment.xml
delete mode 100644 app/src/main/res/menu/episodes_apply_action_speeddial.xml
delete mode 100644 app/src/main/res/menu/feeditemlist_context.xml
delete mode 100644 app/src/main/res/menu/multi_select_context_popup.xml
delete mode 100644 app/src/main/res/menu/multi_select_options.xml
delete mode 100644 app/src/main/res/menu/queue_context.xml
create mode 100644 fastlane/metadata/android/en-US/changelogs/3020278.txt
diff --git a/README.md b/README.md
index 5f535bbd..aa98a063 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ An open source podcast instrument, attuned to Puccini ![Puccini](./images/Puccin
[](https://www.amazon.com/%E8%B4%BE%E8%A5%BF%E6%9E%97-Podcini-R/dp/B0D9WR8P13)
#### Podcini.R 6.10 allows creating synthetic podcast and shelving any episdes to any synthetic podcasts
-#### Podcini.R version 6.5 as a major step forward brings YouTube contents in the app. Channels can be searched, received from share, subscribed. Since 6.6, podcasts, playlists as well as single media from Youtube and YT Music can be shared to Podcini. For more see the Youtube section below or the changelogs
+#### Podcini.R version 6.5 as a major step forward brings YouTube contents in the app. Channels can be searched, received from share, subscribed. Podcasts, playlists as well as single media from Youtube and YT Music can be shared to Podcini. For more see the Youtube section below or the changelogs
That means finally: [Nessun dorma](https://www.youtube.com/watch?v=cWc7vYjgnTs)
#### For Podcini to show up on car's HUD with Android Auto, please read AnroidAuto.md for instructions.
#### If you need to cast to an external speaker, you should install the "play" apk, not the "free" apk, that's about the difference between the two.
diff --git a/app/build.gradle b/app/build.gradle
index ef76a654..c073e74e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -31,8 +31,8 @@ android {
testApplicationId "ac.mdiq.podcini.tests"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- versionCode 3020277
- versionName "6.11.7"
+ versionCode 3020278
+ versionName "6.12.0"
applicationId "ac.mdiq.podcini.R"
def commit = ""
diff --git a/app/src/androidTest/kotlin/ac/test/podcini/service/playback/MediaPlayerBaseTest.kt b/app/src/androidTest/kotlin/ac/test/podcini/service/playback/MediaPlayerBaseTest.kt
index 9be520eb..749b2fbf 100644
--- a/app/src/androidTest/kotlin/ac/test/podcini/service/playback/MediaPlayerBaseTest.kt
+++ b/app/src/androidTest/kotlin/ac/test/podcini/service/playback/MediaPlayerBaseTest.kt
@@ -106,7 +106,7 @@ class MediaPlayerBaseTest {
VolumeAdaptionSetting.OFF, null, null)
f.preferences = prefs
f.episodes.clear()
- val i = Episode(0, "t", "i", "l", Date(), Episode.PlayState.UNPLAYED.code, f)
+ val i = Episode(0, "t", "i", "l", Date(), PlayState.UNPLAYED.code, f)
f.episodes.add(i)
val media = EpisodeMedia(0, i, 0, 0, 0, "audio/wav", fileUrl, downloadUrl, fileUrl != null, null, 0, 0)
i.setMedia(media)
diff --git a/app/src/androidTest/kotlin/ac/test/podcini/service/playback/TaskManagerTest.kt b/app/src/androidTest/kotlin/ac/test/podcini/service/playback/TaskManagerTest.kt
index c4ea6406..b048fef6 100644
--- a/app/src/androidTest/kotlin/ac/test/podcini/service/playback/TaskManagerTest.kt
+++ b/app/src/androidTest/kotlin/ac/test/podcini/service/playback/TaskManagerTest.kt
@@ -65,7 +65,7 @@ class TaskManagerTest {
val f = Feed(0, null, "title", "link", "d", null, null, null, null, "id", null, "null", "url")
f.episodes.clear()
for (i in 0 until NUM_ITEMS) {
- f.episodes.add(Episode(0, pref + i, pref + i, "link", Date(), Episode.PlayState.PLAYED.code, f))
+ f.episodes.add(Episode(0, pref + i, pref + i, "link", Date(), PlayState.PLAYED.code, f))
}
// val adapter = getInstance()
// adapter.open()
diff --git a/app/src/androidTest/kotlin/ac/test/podcini/ui/UITestUtils.kt b/app/src/androidTest/kotlin/ac/test/podcini/ui/UITestUtils.kt
index e8be5fc3..9d776275 100644
--- a/app/src/androidTest/kotlin/ac/test/podcini/ui/UITestUtils.kt
+++ b/app/src/androidTest/kotlin/ac/test/podcini/ui/UITestUtils.kt
@@ -3,6 +3,7 @@ package de.test.podcini.ui
import ac.mdiq.podcini.storage.model.Feed
import ac.mdiq.podcini.storage.model.Episode
import ac.mdiq.podcini.storage.model.EpisodeMedia
+import ac.mdiq.podcini.storage.model.PlayState
import ac.mdiq.podcini.util.EventFlow
import ac.mdiq.podcini.util.FlowEvent
import android.content.Context
@@ -113,7 +114,7 @@ class UITestUtils(private val context: Context) {
val items: MutableList = ArrayList()
for (j in 0 until NUM_ITEMS_PER_FEED) {
val item = Episode(j.toLong(), "Feed " + (i + 1) + ": Item " + (j + 1), "item$j",
- "http://example.com/feed$i/item/$j", Date(), Episode.PlayState.UNPLAYED.code, feed)
+ "http://example.com/feed$i/item/$j", Date(), PlayState.UNPLAYED.code, feed)
items.add(item)
if (!hostTextOnlyFeeds) {
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt b/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt
index 5c3a1960..e696bb1b 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt
@@ -362,7 +362,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() {
.addTag(WORK_TAG_EPISODE_URL + item.media!!.downloadUrl)
if (enqueueDownloadedEpisodes()) {
if (item.feed?.preferences?.queue != null)
- runBlocking { Queues.addToQueueSync(false, item, item.feed?.preferences?.queue) }
+ runBlocking { Queues.addToQueueSync(item, item.feed?.preferences?.queue) }
workRequest.addTag(WORK_DATA_WAS_QUEUED)
}
workRequest.setInputData(Data.Builder().putLong(WORK_DATA_MEDIA_ID, item.media!!.id).build())
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/net/feed/LocalFeedUpdater.kt b/app/src/main/kotlin/ac/mdiq/podcini/net/feed/LocalFeedUpdater.kt
index ebabf73d..aa89b6c7 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/net/feed/LocalFeedUpdater.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/net/feed/LocalFeedUpdater.kt
@@ -121,7 +121,7 @@ object LocalFeedUpdater {
}
private fun createFeedItem(feed: Feed, file: FastDocumentFile, context: Context): Episode {
- val item = Episode(0L, file.name, UUID.randomUUID().toString(), file.name, Date(file.lastModified), Episode.PlayState.UNPLAYED.code, feed)
+ val item = Episode(0L, file.name, UUID.randomUUID().toString(), file.name, Date(file.lastModified), PlayState.UNPLAYED.code, feed)
item.disableAutoDownload()
val size = file.length
val media = EpisodeMedia(0, item, 0, 0, size, file.type,
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/playback/base/InTheatre.kt b/app/src/main/kotlin/ac/mdiq/podcini/playback/base/InTheatre.kt
index c200519e..68df9b7f 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/playback/base/InTheatre.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/playback/base/InTheatre.kt
@@ -82,9 +82,7 @@ object InTheatre {
}
upsert(curQueue_) {}
}
- upsert(curQueue) {
- it.update()
- }
+ upsert(curQueue) { it.update() }
}
Logd(TAG, "starting curState")
@@ -135,10 +133,12 @@ object InTheatre {
val type = curState.curMediaType.toInt()
if (type == EpisodeMedia.PLAYABLE_TYPE_FEEDMEDIA) {
val mediaId = curState.curMediaId
+ Logd(TAG, "loadPlayableFromPreferences getting mediaId: $mediaId")
if (mediaId != 0L) {
curMedia = getEpisodeMedia(mediaId)
if (curEpisode != null) curEpisode = (curMedia as EpisodeMedia).episodeOrFetch()
}
+ Logd(TAG, "loadPlayableFromPreferences: curMedia: ${curMedia?.getIdentifier()}")
} else Log.e(TAG, "Could not restore Playable object from preferences")
}
}
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt b/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt
index a4885558..567fdfb5 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt
@@ -393,7 +393,7 @@ class PlaybackService : MediaLibraryService() {
if (ended || smartMarkAsPlayed || autoSkipped || (skipped && !shouldSkipKeepEpisode())) {
Logd(TAG, "onPostPlayback ended: $ended smartMarkAsPlayed: $smartMarkAsPlayed autoSkipped: $autoSkipped skipped: $skipped")
// only mark the item as played if we're not keeping it anyways
- item = setPlayStateSync(Episode.PlayState.PLAYED.code, ended || (skipped && smartMarkAsPlayed), item!!)
+ item = setPlayStateSync(PlayState.PLAYED.code, ended || (skipped && smartMarkAsPlayed), item!!)
val action = item?.feed?.preferences?.autoDeleteAction
val shouldAutoDelete = (action == AutoDeleteAction.ALWAYS ||
(action == AutoDeleteAction.GLOBAL && item?.feed != null && shouldAutoDeleteItem(item!!.feed!!)))
@@ -1189,7 +1189,7 @@ class PlaybackService : MediaLibraryService() {
if (media != null) {
media.setPosition(position)
media.setLastPlayedTime(System.currentTimeMillis())
- if (it.isNew) it.playState = Episode.PlayState.UNPLAYED.code
+ if (it.isNew) it.playState = PlayState.UNPLAYED.code
if (media.startPosition >= 0 && media.getPosition() > media.startPosition)
media.playedDuration = (media.playedDurationWhenStarted + media.getPosition() - media.startPosition)
}
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/algorithms/AutoCleanups.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/algorithms/AutoCleanups.kt
index c5029cd8..57d311ba 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/storage/algorithms/AutoCleanups.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/algorithms/AutoCleanups.kt
@@ -12,6 +12,7 @@ import ac.mdiq.podcini.storage.database.Queues.getInQueueEpisodeIds
import ac.mdiq.podcini.storage.model.Episode
import ac.mdiq.podcini.storage.model.EpisodeFilter
import ac.mdiq.podcini.storage.model.EpisodeSortOrder
+import ac.mdiq.podcini.storage.model.PlayState
import ac.mdiq.podcini.util.Logd
import android.content.Context
import android.util.Log
@@ -182,7 +183,7 @@ object AutoCleanups {
val idsInQueues = getInQueueEpisodeIds()
val mostRecentDateForDeletion = calcMostRecentDateForDeletion(Date())
for (item in downloadedItems) {
- if (item.media != null && item.media!!.downloaded && !idsInQueues.contains(item.id) && item.isPlayed() && !item.isFavorite) {
+ if (item.media != null && item.media!!.downloaded && !idsInQueues.contains(item.id) && item.playState >= PlayState.PLAYED.code && !item.isFavorite) {
val media = item.media
// make sure this candidate was played at least the proper amount of days prior to now
if (media?.playbackCompletionDate != null && media.playbackCompletionDate!!.before(mostRecentDateForDeletion)) candidates.add(item)
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Episodes.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Episodes.kt
index 8843dea3..fd3bcf38 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Episodes.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Episodes.kt
@@ -18,11 +18,7 @@ import ac.mdiq.podcini.storage.database.RealmDB.realm
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
import ac.mdiq.podcini.storage.database.RealmDB.upsert
import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
-import ac.mdiq.podcini.storage.model.Episode
-import ac.mdiq.podcini.storage.model.Episode.PlayState
-import ac.mdiq.podcini.storage.model.EpisodeFilter
-import ac.mdiq.podcini.storage.model.EpisodeMedia
-import ac.mdiq.podcini.storage.model.EpisodeSortOrder
+import ac.mdiq.podcini.storage.model.*
import ac.mdiq.podcini.storage.utils.EpisodesPermutors.getPermutor
import ac.mdiq.podcini.storage.utils.FilesUtils.getMediafilename
import ac.mdiq.podcini.util.EventFlow
@@ -287,7 +283,7 @@ object Episodes {
var episode_ = episode
if (!episode.isManaged()) episode_ = realm.query(Episode::class).query("id == $0", episode.id).first().find() ?: episode
val result = upsert(episode_) {
- if (played >= PlayState.NEW.code && played <= PlayState.BUILDING.code) it.playState = played
+ if (played != PlayState.UNSPECIFIED.code) it.playState = played
else {
if (it.playState == PlayState.PLAYED.code) it.playState = PlayState.UNPLAYED.code
else it.playState = PlayState.PLAYED.code
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Feeds.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Feeds.kt
index 647a3219..6f0bd98a 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Feeds.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Feeds.kt
@@ -287,6 +287,7 @@ object Feeds {
episode.feed = savedFeed
episode.id = idLong++
episode.feedId = savedFeed.id
+ episode.playState = PlayState.NEW.code
if (episode.media != null) {
episode.media!!.id = episode.id
if (!savedFeed.hasVideoMedia && episode.media!!.getMediaType() == MediaType.VIDEO) savedFeed.hasVideoMedia = true
@@ -300,7 +301,7 @@ object Feeds {
episode.setNew()
if (savedFeed.preferences?.autoAddNewToQueue == true) {
val q = savedFeed.preferences?.queue
- if (q != null) runOnIOScope { addToQueueSync(false, episode, q) }
+ if (q != null) runOnIOScope { addToQueueSync(episode, q) }
}
}
}
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/LogsAndStats.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/LogsAndStats.kt
index bf384659..e398969b 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/LogsAndStats.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/LogsAndStats.kt
@@ -56,7 +56,7 @@ object LogsAndStats {
feedTotalTime += m.duration
if (m.lastPlayedTime in timeFilterFrom.. 0 && m.playedDuration > 0) || m.episodeOrFetch()?.playState == Episode.PlayState.PLAYED.code || m.position > 0) {
+ if ((m.playbackCompletionTime > 0 && m.playedDuration > 0) || m.episodeOrFetch()?.playState == PlayState.PLAYED.code || m.position > 0) {
episodesStarted += 1
feedPlayedTime += m.duration
}
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Queues.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Queues.kt
index 31c8eb6a..52683d0a 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Queues.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Queues.kt
@@ -6,6 +6,7 @@ import ac.mdiq.podcini.playback.base.InTheatre.curQueue
import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
import ac.mdiq.podcini.storage.database.Episodes.setPlayState
+import ac.mdiq.podcini.storage.database.Episodes.setPlayStateSync
import ac.mdiq.podcini.storage.database.RealmDB.realm
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
import ac.mdiq.podcini.storage.database.RealmDB.upsert
@@ -77,9 +78,9 @@ object Queues {
appPrefs.edit().putString(UserPreferences.Prefs.prefEnqueueLocation.name, location.name).apply()
}
- fun queueFromName(name: String): PlayQueue? {
- return realm.query(PlayQueue::class).query("name == $0", name).first().find()
- }
+// fun queueFromName(name: String): PlayQueue? {
+// return realm.query(PlayQueue::class).query("name == $0", name).first().find()
+// }
fun getInQueueEpisodeIds(): Set {
Logd(TAG, "getQueueIDList() called")
@@ -98,13 +99,13 @@ object Queues {
* @param episodes the Episode objects that should be added to the queue.
*/
@UnstableApi @JvmStatic @Synchronized
- fun addToQueue(markAsUnplayed: Boolean, vararg episodes: Episode) : Job {
+ fun addToQueue(vararg episodes: Episode) : Job {
Logd(TAG, "addToQueue( ... ) called")
return runOnIOScope {
if (episodes.isEmpty()) return@runOnIOScope
var queueModified = false
- val markAsUnplayeds = mutableListOf()
+ val setInQueue = mutableListOf()
val events: MutableList = ArrayList()
val updatedItems: MutableList = ArrayList()
val positionCalculator = EnqueuePositionPolicy(enqueueLocation)
@@ -121,7 +122,7 @@ object Queues {
updatedItems.add(episode)
qItems.add(insertPosition, episode)
queueModified = true
- if (episode.isNew) markAsUnplayeds.add(episode)
+ if (episode.playState < PlayState.INQUEUE.code) setInQueue.add(episode)
insertPosition++
}
if (queueModified) {
@@ -134,13 +135,13 @@ object Queues {
}
for (event in events) EventFlow.postEvent(event)
- if (markAsUnplayed && markAsUnplayeds.size > 0) setPlayState(Episode.PlayState.UNPLAYED.code, false, *markAsUnplayeds.toTypedArray())
+ setPlayState(PlayState.INQUEUE.code, false, *setInQueue.toTypedArray())
// if (performAutoDownload) autodownloadEpisodeMedia(context)
}
}
}
- suspend fun addToQueueSync(markAsUnplayed: Boolean, episode: Episode, queue_: PlayQueue? = null) {
+ suspend fun addToQueueSync(episode: Episode, queue_: PlayQueue? = null) {
Logd(TAG, "addToQueueSync( ... ) called")
val queue = queue_ ?: curQueue
if (queue.episodeIds.contains(episode.id)) return
@@ -157,7 +158,7 @@ object Queues {
}
if (queue.id == curQueue.id) curQueue = queueNew
- if (markAsUnplayed && episode.isNew) setPlayState(Episode.PlayState.UNPLAYED.code, false, episode)
+ if (episode.playState < PlayState.INQUEUE.code) setPlayState(PlayState.INQUEUE.code, false, episode)
if (queue.id == curQueue.id) EventFlow.postEvent(FlowEvent.QueueEvent.added(episode, insertPosition))
// if (performAutoDownload) autodownloadEpisodeMedia(context)
}
@@ -194,6 +195,9 @@ object Queues {
it.episodeIds.clear()
it.update()
}
+ for (e in curQueue.episodes) {
+ if (e.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, e)
+ }
curQueue.episodes.clear()
EventFlow.postEvent(FlowEvent.QueueEvent.cleared())
}
@@ -230,7 +234,7 @@ object Queues {
var queue = queue_ ?: curQueue
if (queue.size() == 0) return
- val events: MutableList = ArrayList()
+ val events: MutableList = mutableListOf()
val indicesToRemove: MutableList = mutableListOf()
val qItems = queue.episodes.toMutableList()
val eList = episodes.toList()
@@ -239,6 +243,7 @@ object Queues {
if (indexOfItemWithId(eList, episode.id) >= 0) {
Logd(TAG, "removing from queue: ${episode.id} ${episode.title}")
indicesToRemove.add(i)
+ if (episode.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, episode)
if (queue.id == curQueue.id) events.add(FlowEvent.QueueEvent.removed(episode))
}
}
@@ -270,6 +275,10 @@ object Queues {
if (q.size() == 0 || q.id == curQueue.id) continue
idsInQueuesToRemove = q.episodeIds.intersect(episodeIds.toSet()).toMutableSet()
if (idsInQueuesToRemove.isNotEmpty()) {
+ val eList = realm.query(Episode::class).query("id IN $0", idsInQueuesToRemove).find()
+ for (e in eList) {
+ if (e.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, e)
+ }
upsert(q) {
it.idsBinList.removeAll(idsInQueuesToRemove)
it.idsBinList.addAll(idsInQueuesToRemove)
@@ -288,6 +297,10 @@ object Queues {
}
idsInQueuesToRemove = q.episodeIds.intersect(episodeIds.toSet()).toMutableSet()
if (idsInQueuesToRemove.isNotEmpty()) {
+ val eList = realm.query(Episode::class).query("id IN $0", idsInQueuesToRemove).find()
+ for (e in eList) {
+ if (e.playState < PlayState.SKIPPED.code) setPlayState(PlayState.SKIPPED.code, false, e)
+ }
curQueue = upsert(q) {
it.idsBinList.removeAll(idsInQueuesToRemove)
it.idsBinList.addAll(idsInQueuesToRemove)
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/RealmDB.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/RealmDB.kt
index e6ac311a..7e751b6f 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/RealmDB.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/RealmDB.kt
@@ -40,7 +40,7 @@ object RealmDB {
SubscriptionLog::class,
Chapter::class))
.name("Podcini.realm")
- .schemaVersion(27)
+ .schemaVersion(28)
.migration({ mContext ->
val oldRealm = mContext.oldRealm // old realm using the previous schema
val newRealm = mContext.newRealm // new realm using the new schema
@@ -104,8 +104,22 @@ object RealmDB {
// )
// }
}
- })
- .build()
+ if (oldRealm.schemaVersion() < 28) {
+ Logd(TAG, "migrating DB from below 27")
+ mContext.enumerate(className = "Episode") { oldObject: DynamicRealmObject, newObject: DynamicMutableRealmObject? ->
+ newObject?.run {
+ if (oldObject.getValue(fieldName = "playState") == 1L) {
+ set("playState", 10L)
+ } else {
+ val media = oldObject.getObject(propertyName = "media")
+ var position = 0L
+ if (media != null) position = media.getValue(propertyName = "position", Long::class) ?: 0
+ if (position > 0) set("playState", 5L)
+ }
+ }
+ }
+ }
+ }).build()
realm = Realm.open(config)
}
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Episode.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Episode.kt
index f289ae98..750aebdd 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Episode.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Episode.kt
@@ -86,7 +86,7 @@ class Episode : RealmObject {
var rating: Int = Rating.UNRATED.code
@Ignore
- var isFavorite: Boolean = (rating == 2)
+ var isFavorite: Boolean = (rating == Rating.FAVORITE.code)
private set
var comment: String = ""
@@ -142,7 +142,7 @@ class Episode : RealmObject {
val isRemote = mutableStateOf(false)
constructor() {
- this.playState = PlayState.UNPLAYED.code
+ this.playState = PlayState.NEW.code
}
/**
@@ -313,19 +313,10 @@ class Episode : RealmObject {
return result
}
- fun shiftRating(): Int {
- val nr = rating + 1
- return if (nr <= Rating.FAVORITE.code) nr else Rating.TRASH.code
- }
-
- enum class PlayState(val code: Int) {
- UNSPECIFIED(-2),
- NEW(-1),
- UNPLAYED(0),
- PLAYED(1),
- BUILDING(2),
- ABANDONED(3)
- }
+// fun shiftRating(): Int {
+// val nr = rating + 1
+// return if (nr <= Rating.FAVORITE.code) nr else Rating.TRASH.code
+// }
companion object {
val TAG: String = Episode::class.simpleName ?: "Anonymous"
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeFilter.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeFilter.kt
index 305c7561..cf6af9f1 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeFilter.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeFilter.kt
@@ -38,8 +38,8 @@ class EpisodeFilter(vararg properties: String) : Serializable {
fun matches(item: Episode): Boolean {
when {
showNew && !item.isNew -> return false
- showPlayed && !item.isPlayed() -> return false
- showUnplayed && item.isPlayed() -> return false
+ showPlayed && item.playState < PlayState.PLAYED.code -> return false
+ showUnplayed && item.playState >= PlayState.PLAYED.code -> return false
showPaused && !item.isInProgress -> return false
showNotPaused && item.isInProgress -> return false
showDownloaded && !item.isDownloaded -> return false
@@ -58,18 +58,18 @@ class EpisodeFilter(vararg properties: String) : Serializable {
// filter on queues does not have a query string so it's not applied on query results, need to filter separately
fun matchesForQueues(item: Episode): Boolean {
- when {
- showQueued && !inAnyQueue(item) -> return false
- showNotQueued && inAnyQueue(item) -> return false
- else -> return true
- }
+ return when {
+ showQueued && !inAnyQueue(item) -> false
+ showNotQueued && inAnyQueue(item) -> false
+ else -> true
+ }
}
fun queryString(): String {
val statements: MutableList = ArrayList()
when {
- showPlayed -> statements.add("playState == 1 ")
- showUnplayed -> statements.add(" playState != 1 ") // Match "New" items (read = -1) as well
+ showPlayed -> statements.add("playState >= ${PlayState.PLAYED.code}")
+ showUnplayed -> statements.add(" playState < ${PlayState.PLAYED.code}> ") // Match "New" items (read = -1) as well
showNew -> statements.add("playState == -1 ")
}
when {
@@ -127,8 +127,8 @@ class EpisodeFilter(vararg properties: String) : Serializable {
auto_downloadable,
not_auto_downloadable
}
- companion object {
+ companion object {
@JvmStatic
fun unfiltered(): EpisodeFilter {
return EpisodeFilter("")
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Feed.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Feed.kt
index c14331d6..7f044050 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Feed.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Feed.kt
@@ -283,7 +283,7 @@ class Feed : RealmObject {
}
fun getVirtualQueueItems(): List {
- var qString = "feedId == $id AND playState != ${Episode.PlayState.PLAYED.code}"
+ var qString = "feedId == $id AND playState != ${PlayState.PLAYED.code}"
// TODO: perhaps need to set prefStreamOverDownload for youtube feeds
if (type != FeedType.YOUTUBE.name && preferences?.prefStreamOverDownload != true) qString += " AND media.downloaded == true"
val eList_ = realm.query(Episode::class, qString).find().toMutableList()
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/PlayState.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/PlayState.kt
new file mode 100644
index 00000000..6f7776ff
--- /dev/null
+++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/PlayState.kt
@@ -0,0 +1,23 @@
+package ac.mdiq.podcini.storage.model
+
+import ac.mdiq.podcini.R
+
+enum class PlayState(val code: Int, val res: Int, val userSet: Boolean) {
+ UNSPECIFIED(-10, R.drawable.ic_questionmark, false),
+ BUILDING(-2, R.drawable.baseline_build_24, false),
+ NEW(-1, R.drawable.baseline_fiber_new_24, false),
+ UNPLAYED(0, R.drawable.baseline_new_label_24, true),
+ LATER(1, R.drawable.baseline_watch_later_24, true),
+ SOON(2, R.drawable.baseline_local_play_24, true),
+ INQUEUE(3, R.drawable.ic_playlist_play_black, false),
+ INPROGRESS(5, R.drawable.baseline_play_circle_outline_24, false),
+ SKIPPED(6, R.drawable.ic_skip_24dp, true),
+ PLAYED(10, R.drawable.ic_mark_played, true), // was 1
+ IGNORED(20, R.drawable.baseline_visibility_off_24, true);
+
+ companion object {
+ fun fromCode(code: Int): PlayState {
+ return enumValues().firstOrNull { it.code == code } ?: UNSPECIFIED
+ }
+ }
+}
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/EpisodeActionButton.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/EpisodeActionButton.kt
index 6f06addb..6fbab966 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/EpisodeActionButton.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/EpisodeActionButton.kt
@@ -5,16 +5,16 @@ import ac.mdiq.podcini.net.download.service.DownloadServiceInterface
import ac.mdiq.podcini.net.utils.NetworkUtils
import ac.mdiq.podcini.playback.PlaybackServiceStarter
import ac.mdiq.podcini.playback.base.InTheatre
-import ac.mdiq.podcini.preferences.UserPreferences.isStreamOverDownload
import ac.mdiq.podcini.playback.base.InTheatre.isCurrentlyPlaying
import ac.mdiq.podcini.playback.base.VideoMode
import ac.mdiq.podcini.playback.service.PlaybackService
import ac.mdiq.podcini.playback.service.PlaybackService.Companion.getPlayerActivityIntent
import ac.mdiq.podcini.preferences.UsageStatistics
import ac.mdiq.podcini.preferences.UserPreferences
+import ac.mdiq.podcini.preferences.UserPreferences.isStreamOverDownload
import ac.mdiq.podcini.preferences.UserPreferences.videoPlayMode
import ac.mdiq.podcini.receiver.MediaButtonReceiver
-import ac.mdiq.podcini.storage.database.Episodes
+import ac.mdiq.podcini.storage.database.Episodes.setPlayStateSync
import ac.mdiq.podcini.storage.database.RealmDB
import ac.mdiq.podcini.storage.model.*
import ac.mdiq.podcini.storage.utils.AudioMediaTools
@@ -36,15 +36,19 @@ import android.widget.Toast
import androidx.annotation.DrawableRes
import androidx.annotation.OptIn
import androidx.annotation.StringRes
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.*
-import androidx.compose.runtime.*
+import androidx.compose.material3.Card
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
@@ -153,7 +157,7 @@ abstract class EpisodeActionButton internal constructor(@JvmField var item: Epis
class VisitWebsiteActionButton(item: Episode) : EpisodeActionButton(item) {
override val visibility: Boolean
- get() = if (item.link.isNullOrEmpty()) false else true
+ get() = !item.link.isNullOrEmpty()
override fun getLabel(): Int {
return R.string.visit_website_label
@@ -222,6 +226,7 @@ class PlayActionButton(item: Episode) : EpisodeActionButton(item) {
} else {
PlaybackService.clearCurTempSpeed()
PlaybackServiceStarter(context, media).callEvenIfRunning(true).start()
+ item = runBlocking { setPlayStateSync(PlayState.INPROGRESS.code, false, item) }
EventFlow.postEvent(FlowEvent.PlayEvent(item))
}
playVideoIfNeeded(context, media)
@@ -253,8 +258,7 @@ class DeleteActionButton(item: Episode) : EpisodeActionButton(item) {
override val visibility: Boolean
get() {
- if (item.media != null && (item.media!!.downloaded || item.feed?.isLocalFeed == true)) return true
- return false
+ return item.media != null && (item.media!!.downloaded || item.feed?.isLocalFeed == true)
}
override fun getLabel(): Int {
@@ -291,7 +295,7 @@ class PauseActionButton(item: Episode) : EpisodeActionButton(item) {
class DownloadActionButton(item: Episode) : EpisodeActionButton(item) {
override val visibility: Boolean
- get() = if (item.feed?.isLocalFeed == true) false else true
+ get() = item.feed?.isLocalFeed != true
override fun getLabel(): Int {
return R.string.download_label
@@ -371,7 +375,10 @@ class StreamActionButton(item: Episode) : EpisodeActionButton(item) {
fun stream(context: Context, media: Playable) {
if (media !is EpisodeMedia || !InTheatre.isCurMedia(media)) PlaybackService.clearCurTempSpeed()
PlaybackServiceStarter(context, media).shouldStreamThisTime(true).callEvenIfRunning(true).start()
- if (media is EpisodeMedia && media.episode != null) EventFlow.postEvent(FlowEvent.PlayEvent(media.episode!!))
+ if (media is EpisodeMedia && media.episode != null) {
+ val item = runBlocking { setPlayStateSync(PlayState.INPROGRESS.code, false, media.episode!!) }
+ EventFlow.postEvent(FlowEvent.PlayEvent(item))
+ }
playVideoIfNeeded(context, media)
}
}
@@ -382,7 +389,7 @@ class TTSActionButton(item: Episode) : EpisodeActionButton(item) {
private var readerText: String? = null
override val visibility: Boolean
- get() = if (item.link.isNullOrEmpty()) false else true
+ get() = !item.link.isNullOrEmpty()
override fun getLabel(): Int {
return R.string.TTS_label
@@ -535,6 +542,7 @@ class PlayLocalActionButton(item: Episode) : EpisodeActionButton(item) {
} else {
PlaybackService.clearCurTempSpeed()
PlaybackServiceStarter(context, media).callEvenIfRunning(true).start()
+ item = runBlocking { setPlayStateSync(PlayState.INPROGRESS.code, false, item) }
EventFlow.postEvent(FlowEvent.PlayEvent(item))
}
if (media.getMediaType() == MediaType.VIDEO) context.startActivity(getPlayerActivityIntent(context,
@@ -542,23 +550,3 @@ class PlayLocalActionButton(item: Episode) : EpisodeActionButton(item) {
actionState.value = getLabel()
}
}
-
-class MarkAsPlayedActionButton(item: Episode) : EpisodeActionButton(item) {
- override val visibility: Boolean
- get() = if (item.isPlayed()) false else true
-
- override fun getLabel(): Int {
- return (if (item.media != null) R.string.mark_read_label else R.string.mark_read_no_media_label)
- }
-
- override fun getDrawable(): Int {
- return R.drawable.ic_check
- }
-
- @UnstableApi
- override fun onClick(context: Context) {
- if (!item.isPlayed()) Episodes.setPlayState(Episode.PlayState.PLAYED.code, true, item)
- actionState.value = getLabel()
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/SwipeAction.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/SwipeAction.kt
index bc8dc597..391421b7 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/SwipeAction.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/SwipeAction.kt
@@ -29,6 +29,7 @@ interface SwipeAction {
START_DOWNLOAD,
MARK_FAV,
TOGGLE_PLAYED,
+ SET_PLAY_STATE,
REMOVE_FROM_QUEUE,
DELETE,
REMOVE_FROM_HISTORY
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/SwipeActions.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/SwipeActions.kt
index 6e4ab9e4..7eee1fd7 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/SwipeActions.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/SwipeActions.kt
@@ -1,10 +1,10 @@
package ac.mdiq.podcini.ui.actions
+//import ac.mdiq.podcini.ui.dialog.SwipeActionsDialog
import ac.mdiq.podcini.R
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
import ac.mdiq.podcini.storage.database.Episodes.deleteMediaSync
import ac.mdiq.podcini.storage.database.Episodes.setPlayState
-import ac.mdiq.podcini.storage.database.Episodes.setPlayStateSync
import ac.mdiq.podcini.storage.database.Episodes.shouldDeleteRemoveFromQueue
import ac.mdiq.podcini.storage.database.Feeds.shouldAutoDeleteItem
import ac.mdiq.podcini.storage.database.Queues.addToQueue
@@ -16,21 +16,20 @@ import ac.mdiq.podcini.storage.database.RealmDB.upsert
import ac.mdiq.podcini.storage.model.Episode
import ac.mdiq.podcini.storage.model.EpisodeFilter
import ac.mdiq.podcini.storage.model.EpisodeMedia
+import ac.mdiq.podcini.storage.model.PlayState
import ac.mdiq.podcini.storage.utils.EpisodeUtil
-import ac.mdiq.podcini.ui.actions.SwipeAction.ActionTypes.NO_ACTION
import ac.mdiq.podcini.ui.actions.SwipeAction.ActionTypes
+import ac.mdiq.podcini.ui.actions.SwipeAction.ActionTypes.NO_ACTION
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.compose.ChooseRatingDialog
import ac.mdiq.podcini.ui.compose.CustomTheme
+import ac.mdiq.podcini.ui.compose.PlayStateDialog
import ac.mdiq.podcini.ui.fragment.*
-//import ac.mdiq.podcini.ui.dialog.SwipeActionsDialog
import ac.mdiq.podcini.ui.utils.LocalDeleteModal.deleteEpisodesWarnLocal
import ac.mdiq.podcini.util.EventFlow
import ac.mdiq.podcini.util.FlowEvent
-import ac.mdiq.podcini.util.Logd
import android.content.Context
import android.content.SharedPreferences
-import android.os.Handler
import android.util.TypedValue
import android.view.ViewGroup
import androidx.annotation.OptIn
@@ -47,7 +46,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextAlign
@@ -147,7 +145,7 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
@OptIn(UnstableApi::class)
override fun performAction(item: Episode, fragment: Fragment, filter: EpisodeFilter) {
- addToQueue( true, item)
+ addToQueue(item)
}
override fun willRemove(filter: EpisodeFilter, item: Episode): Boolean {
@@ -398,7 +396,7 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
fun addToQueueAt(episode: Episode, index: Int) : Job {
return runOnIOScope {
if (curQueue.episodeIds.contains(episode.id)) return@runOnIOScope
- if (episode.isNew) setPlayState(Episode.PlayState.UNPLAYED.code, false, episode)
+ if (episode.isNew) setPlayState(PlayState.UNPLAYED.code, false, episode)
curQueue = upsert(curQueue) {
it.episodeIds.add(index, episode.id)
it.update()
@@ -438,9 +436,9 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
}
}
- class TogglePlaybackStateSwipeAction : SwipeAction {
+ class SetPlaybackStateSwipeAction : SwipeAction {
override fun getId(): String {
- return ActionTypes.TOGGLE_PLAYED.name
+ return ActionTypes.SET_PLAY_STATE.name
}
override fun getActionIcon(): Int {
@@ -452,45 +450,22 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
}
override fun getTitle(context: Context): String {
- return context.getString(R.string.toggle_played_label)
+ return context.getString(R.string.set_play_state_label)
}
override fun performAction(item: Episode, fragment: Fragment, filter: EpisodeFilter) {
- val newState = if (item.playState == Episode.PlayState.UNPLAYED.code) Episode.PlayState.PLAYED.code else Episode.PlayState.UNPLAYED.code
-
- Logd("TogglePlaybackStateSwipeAction", "performAction( ${item.id} )")
- // we're marking it as unplayed since the user didn't actually play it
- // but they don't want it considered 'NEW' anymore
- var item = runBlocking { setPlayStateSync(newState, false, item) }
-
- val h = Handler(fragment.requireContext().mainLooper)
- val r = Runnable {
- val media: EpisodeMedia? = item.media
- val shouldAutoDelete = if (item.feed == null) false else shouldAutoDeleteItem(item.feed!!)
- if (media != null && EpisodeUtil.hasAlmostEnded(media) && shouldAutoDelete) {
- item = deleteMediaSync(fragment.requireContext(), item)
- if (shouldDeleteRemoveFromQueue()) removeFromQueueSync(null, item) }
- }
- val playStateStringRes: Int = when (newState) {
- Episode.PlayState.UNPLAYED.code -> if (item.playState == Episode.PlayState.NEW.code) R.string.removed_inbox_label //was new
- else R.string.marked_as_unplayed_label //was played
- Episode.PlayState.PLAYED.code -> R.string.marked_as_played_label
- else -> if (item.playState == Episode.PlayState.NEW.code) R.string.removed_inbox_label
- else R.string.marked_as_unplayed_label
- }
- val duration: Int = Snackbar.LENGTH_LONG
-
- if (willRemove(filter, item)) {
- (fragment.activity as MainActivity).showSnackbarAbovePlayer(
- playStateStringRes, duration)
- .setAction(fragment.getString(R.string.undo)) {
- setPlayState(item.playState, false, item)
- // don't forget to cancel the thing that's going to remove the media
- h.removeCallbacks(r)
+ var showPlayStateDialog by mutableStateOf(true)
+ val composeView = ComposeView(fragment.requireContext()).apply {
+ setContent {
+ CustomTheme(fragment.requireContext()) {
+ if (showPlayStateDialog) PlayStateDialog(listOf(item)) {
+ showPlayStateDialog = false
+ (fragment.view as? ViewGroup)?.removeView(this@apply)
+ }
}
+ }
}
-
- h.postDelayed(r, ceil((duration * 1.05f).toDouble()).toLong())
+ (fragment.view as? ViewGroup)?.addView(composeView)
}
private fun delayedExecution(item: Episode, fragment: Fragment, duration: Float) = runBlocking {
@@ -504,7 +479,7 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
}
override fun willRemove(filter: EpisodeFilter, item: Episode): Boolean {
- return if (item.playState == Episode.PlayState.NEW.code) filter.showPlayed || filter.showNew
+ return if (item.playState == PlayState.NEW.code) filter.showPlayed || filter.showNew
else filter.showUnplayed || filter.showPlayed || filter.showNew
}
}
@@ -523,7 +498,7 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
val swipeActions: List = listOf(
NoActionSwipeAction(), ComboSwipeAction(), AddToQueueSwipeAction(),
StartDownloadSwipeAction(), SetRatingSwipeAction(),
- TogglePlaybackStateSwipeAction(), RemoveFromQueueSwipeAction(),
+ SetPlaybackStateSwipeAction(), RemoveFromQueueSwipeAction(),
DeleteSwipeAction(), RemoveFromHistorySwipeAction())
private fun getPrefs(tag: String, defaultActions: String): Actions {
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/MainActivity.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/MainActivity.kt
index 4107c485..71918cc9 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/MainActivity.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/MainActivity.kt
@@ -633,6 +633,10 @@ class MainActivity : CastEnabledActivity() {
}
}
+ fun openDrawer() {
+ drawerLayout?.openDrawer(navDrawer)
+ }
+
private var eventSink: Job? = null
private var eventStickySink: Job? = null
private fun cancelFlowEvents() {
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/compose/EpisodesVM.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/compose/EpisodesVM.kt
index 84cb9584..7e96cf8a 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/compose/EpisodesVM.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/compose/EpisodesVM.kt
@@ -3,18 +3,27 @@ package ac.mdiq.podcini.ui.compose
import ac.mdiq.podcini.R
import ac.mdiq.podcini.net.download.DownloadStatus
import ac.mdiq.podcini.net.download.service.DownloadServiceInterface
+import ac.mdiq.podcini.net.sync.SynchronizationSettings.isProviderConnected
+import ac.mdiq.podcini.net.sync.SynchronizationSettings.wifiSyncEnabledKey
+import ac.mdiq.podcini.net.sync.model.EpisodeAction
+import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
import ac.mdiq.podcini.playback.base.InTheatre
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
import ac.mdiq.podcini.playback.base.MediaPlayerBase.Companion.status
import ac.mdiq.podcini.storage.database.Episodes
+import ac.mdiq.podcini.storage.database.Episodes.deleteMediaSync
import ac.mdiq.podcini.storage.database.Episodes.episodeFromStreamInfo
import ac.mdiq.podcini.storage.database.Episodes.setPlayState
+import ac.mdiq.podcini.storage.database.Episodes.setPlayStateSync
+import ac.mdiq.podcini.storage.database.Episodes.shouldDeleteRemoveFromQueue
import ac.mdiq.podcini.storage.database.Feeds.addToMiscSyndicate
import ac.mdiq.podcini.storage.database.Feeds.addToYoutubeSyndicate
+import ac.mdiq.podcini.storage.database.Feeds.shouldAutoDeleteItem
import ac.mdiq.podcini.storage.database.Queues
import ac.mdiq.podcini.storage.database.Queues.addToQueueSync
import ac.mdiq.podcini.storage.database.Queues.removeFromAllQueuesQuiet
import ac.mdiq.podcini.storage.database.Queues.removeFromQueue
+import ac.mdiq.podcini.storage.database.Queues.removeFromQueueSync
import ac.mdiq.podcini.storage.database.RealmDB.realm
import ac.mdiq.podcini.storage.database.RealmDB.upsert
import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
@@ -22,6 +31,7 @@ import ac.mdiq.podcini.storage.model.*
import ac.mdiq.podcini.storage.model.Feed.Companion.MAX_SYNTHETIC_ID
import ac.mdiq.podcini.storage.model.Feed.Companion.newId
import ac.mdiq.podcini.storage.utils.DurationConverter
+import ac.mdiq.podcini.storage.utils.EpisodeUtil.hasAlmostEnded
import ac.mdiq.podcini.storage.utils.ImageResourceUtils
import ac.mdiq.podcini.ui.actions.EpisodeActionButton
import ac.mdiq.podcini.ui.actions.EpisodeActionButton.Companion.forItem
@@ -121,7 +131,7 @@ var queueChanged by mutableIntStateOf(0)
@Stable
class EpisodeVM(var episode: Episode) {
var positionState by mutableStateOf(episode.media?.position?:0)
- var playedState by mutableStateOf(episode.isPlayed())
+ var playedState by mutableIntStateOf(episode.playState)
var isPlayingState by mutableStateOf(false)
var ratingState by mutableIntStateOf(episode.rating)
var inProgressState by mutableStateOf(episode.isInProgress)
@@ -157,9 +167,9 @@ class EpisodeVM(var episode: Episode) {
Logd("EpisodeVM", "episodeMonitor UpdatedObject ${changes.obj.title} ${changes.changedFields.joinToString()}")
if (episode.id == changes.obj.id) {
withContext(Dispatchers.Main) {
- playedState = changes.obj.isPlayed()
+ playedState = changes.obj.playState
ratingState = changes.obj.rating
-// episode = changes.obj // direct assignment doesn't update member like media??
+ episode = changes.obj // direct assignment doesn't update member like media??
}
Logd("EpisodeVM", "episodeMonitor $playedState $playedState ")
} else Logd("EpisodeVM", "episodeMonitor index out bound")
@@ -183,7 +193,7 @@ class EpisodeVM(var episode: Episode) {
positionState = changes.obj.media?.position ?: 0
inProgressState = changes.obj.isInProgress
Logd("EpisodeVM", "mediaMonitor $positionState $inProgressState ${episode.title}")
-// episode = changes.obj
+ episode = changes.obj
// Logd("EpisodeVM", "mediaMonitor downloaded: ${changes.obj.media?.downloaded} ${episode.media?.downloaded}")
}
} else Logd("EpisodeVM", "mediaMonitor index out bound")
@@ -231,6 +241,61 @@ fun ChooseRatingDialog(selected: List, onDismissRequest: () -> Unit) {
}
}
+@Composable
+fun PlayStateDialog(selected: List, onDismissRequest: () -> Unit) {
+ val context = LocalContext.current
+ Dialog(onDismissRequest = onDismissRequest) {
+ Surface(shape = RoundedCornerShape(16.dp)) {
+ Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
+ for (state in PlayState.entries) {
+ if (state.userSet) {
+ Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(4.dp)
+ .clickable {
+ for (item in selected) {
+ var item_ = runBlocking { setPlayStateSync(state.code, false, item) }
+ val media: EpisodeMedia? = item_.media
+ val shouldAutoDelete = if (item_.feed == null) false else shouldAutoDeleteItem(item_.feed!!)
+ if (media != null && hasAlmostEnded(media) && shouldAutoDelete) {
+ item_ = deleteMediaSync(context, item_)
+ if (shouldDeleteRemoveFromQueue()) removeFromQueueSync(null, item_)
+ }
+ when (state) {
+ PlayState.UNPLAYED -> {
+ if (isProviderConnected && item_?.feed?.isLocalFeed != true && item_?.media != null) {
+ val actionNew: EpisodeAction = EpisodeAction.Builder(item_!!, EpisodeAction.NEW).currentTimestamp().build()
+ SynchronizationQueueSink.enqueueEpisodeActionIfSyncActive(context, actionNew)
+ }
+ }
+ PlayState.PLAYED -> {
+ if (item_?.feed?.isLocalFeed != true && (isProviderConnected || wifiSyncEnabledKey)) {
+ val media: EpisodeMedia? = item_?.media
+ // not all items have media, Gpodder only cares about those that do
+ if (isProviderConnected && media != null) {
+ val actionPlay: EpisodeAction = EpisodeAction.Builder(item_!!, EpisodeAction.PLAY)
+ .currentTimestamp()
+ .started(media.getDuration() / 1000)
+ .position(media.getDuration() / 1000)
+ .total(media.getDuration() / 1000)
+ .build()
+ SynchronizationQueueSink.enqueueEpisodeActionIfSyncActive(context, actionPlay)
+ }
+ }
+ }
+ else -> {}
+ }
+ }
+ onDismissRequest()
+ }) {
+ Icon(imageVector = ImageVector.vectorResource(id = state.res), "")
+ Text(state.name, Modifier.padding(start = 4.dp))
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
@Composable
fun PutToQueueDialog(selected: List, onDismissRequest: () -> Unit) {
val queues = realm.query(PlayQueue::class).find()
@@ -271,7 +336,7 @@ fun PutToQueueDialog(selected: List, onDismissRequest: () -> Unit) {
if (toRemoveCur.isNotEmpty()) EventFlow.postEvent(FlowEvent.QueueEvent.removed(toRemoveCur))
}
selected.forEach { e ->
- runBlocking { addToQueueSync(false, e, toQueue) }
+ runBlocking { addToQueueSync(e, toQueue) }
}
onDismissRequest()
}) {
@@ -366,6 +431,9 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List, feed: Feed?
var showChooseRatingDialog by remember { mutableStateOf(false) }
if (showChooseRatingDialog) ChooseRatingDialog(selected) { showChooseRatingDialog = false }
+ var showPlayStateDialog by remember { mutableStateOf(false) }
+ if (showPlayStateDialog) PlayStateDialog(selected) { showPlayStateDialog = false }
+
var showPutToQueueDialog by remember { mutableStateOf(false) }
if (showPutToQueueDialog) PutToQueueDialog(selected) { showPutToQueueDialog = false }
@@ -460,13 +528,14 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List, feed: Feed?
{ Row(modifier = Modifier
.padding(horizontal = 16.dp)
.clickable {
+ showPlayStateDialog = true
isExpanded = false
selectMode = false
Logd(TAG, "ic_mark_played: ${selected.size}")
- setPlayState(Episode.PlayState.UNSPECIFIED.code, false, *selected.toTypedArray())
+// setPlayState(PlayState.UNSPECIFIED.code, false, *selected.toTypedArray())
}, verticalAlignment = Alignment.CenterVertically) {
Icon(imageVector = ImageVector.vectorResource(id = R.drawable.ic_mark_played), "Toggle played state")
- Text(stringResource(id = R.string.toggle_played_label)) } },
+ Text(stringResource(id = R.string.set_play_state_label)) } },
{ Row(modifier = Modifier
.padding(horizontal = 16.dp)
.clickable {
@@ -483,7 +552,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List, feed: Feed?
isExpanded = false
selectMode = false
Logd(TAG, "ic_playlist_play: ${selected.size}")
- Queues.addToQueue(true, *selected.toTypedArray())
+ Queues.addToQueue(*selected.toTypedArray())
}, verticalAlignment = Alignment.CenterVertically) {
Icon(imageVector = ImageVector.vectorResource(id = R.drawable.ic_playlist_play), "Add to active queue")
Text(stringResource(id = R.string.add_to_queue_label)) } },
@@ -520,8 +589,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List, feed: Feed?
)
if (selected.isNotEmpty() && selected[0].isRemote.value)
options.add {
- Row(modifier = Modifier
- .padding(horizontal = 16.dp)
+ Row(modifier = Modifier.padding(horizontal = 16.dp)
.clickable {
isExpanded = false
selectMode = false
@@ -594,7 +662,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List, feed: Feed?
ConstraintLayout(modifier = Modifier.width(56.dp).height(56.dp)) {
val (imgvCover, checkMark) = createRefs()
val imgLoc = remember(vm) { ImageResourceUtils.getEpisodeListImageLocation(vm.episode) }
- Logd(TAG, "imgLoc: $imgLoc")
+// Logd(TAG, "imgLoc: $imgLoc")
AsyncImage(model = ImageRequest.Builder(context).data(imgLoc)
.memoryCachePolicy(CachePolicy.ENABLED).placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher).build(),
contentDescription = "imgvCover",
@@ -609,8 +677,8 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List, feed: Feed?
if (selectMode) toggleSelected()
else if (vm.episode.feed != null) activity.loadChildFragment(FeedInfoFragment.newInstance(vm.episode.feed!!))
}))
- val alpha = if (vm.playedState) 1.0f else 0f
- if (vm.playedState) Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_check), tint = textColor, contentDescription = "played_mark",
+ val alpha = if (vm.playedState >= PlayState.SKIPPED.code) 1.0f else 0f
+ if (vm.playedState >= PlayState.SKIPPED.code) Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_check), tint = textColor, contentDescription = "played_mark",
modifier = Modifier.background(Color.Green).alpha(alpha)
.constrainAs(checkMark) {
bottom.linkTo(parent.bottom)
@@ -640,14 +708,16 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List, feed: Feed?
vms[index].inQueueState = curQueue.contains(vms[index].episode)
}
Row(verticalAlignment = Alignment.CenterVertically) {
- Logd(TAG, "info row")
- if (vm.episode.media?.getMediaType() == MediaType.VIDEO)
- Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_videocam), tint = textColor, contentDescription = "isVideo", modifier = Modifier.width(14.dp).height(14.dp))
+// Logd(TAG, "info row")
val ratingIconRes = Rating.fromCode(vm.ratingState).res
if (vm.ratingState != Rating.UNRATED.code)
Icon(imageVector = ImageVector.vectorResource(ratingIconRes), tint = MaterialTheme.colorScheme.tertiary, contentDescription = "rating", modifier = Modifier.background(MaterialTheme.colorScheme.tertiaryContainer).width(14.dp).height(14.dp))
+ val playStateRes = PlayState.fromCode(vm.playedState).res
+ Icon(imageVector = ImageVector.vectorResource(playStateRes), tint = textColor, contentDescription = "playState", modifier = Modifier.width(14.dp).height(14.dp))
if (vm.inQueueState)
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_playlist_play), tint = textColor, contentDescription = "ivInPlaylist", modifier = Modifier.width(14.dp).height(14.dp))
+ if (vm.episode.media?.getMediaType() == MediaType.VIDEO)
+ Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_videocam), tint = textColor, contentDescription = "isVideo", modifier = Modifier.width(14.dp).height(14.dp))
val curContext = LocalContext.current
val dur = remember { vm.episode.media?.getDuration() ?: 0 }
val durText = remember { DurationConverter.getDurationStringLong(dur) }
@@ -681,7 +751,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List, feed: Feed?
detectTapGestures(onLongPress = { vms[index].showAltActionsDialog = true },
onTap = { vms[index].actionButton.onClick(activity) })
}, ) {
- Logd(TAG, "button box")
+// Logd(TAG, "button box")
vm.actionRes = vm.actionButton.getDrawable()
Icon(imageVector = ImageVector.vectorResource(vm.actionRes), tint = textColor, contentDescription = null, modifier = Modifier.width(28.dp).height(32.dp))
if (isDownloading() && vm.dlPercent >= 0) CircularProgressIndicator(progress = { 0.01f * vm.dlPercent },
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt
index 51c7cf83..bf4ddf0d 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt
@@ -6,6 +6,8 @@ import ac.mdiq.podcini.playback.PlaybackServiceStarter
import ac.mdiq.podcini.playback.ServiceStatusHandler
import ac.mdiq.podcini.playback.base.InTheatre.curEpisode
import ac.mdiq.podcini.playback.base.InTheatre.curMedia
+import ac.mdiq.podcini.playback.base.InTheatre.curQueue
+import ac.mdiq.podcini.playback.base.InTheatre.isCurrentlyPlaying
import ac.mdiq.podcini.playback.base.MediaPlayerBase.Companion.status
import ac.mdiq.podcini.playback.base.PlayerStatus
import ac.mdiq.podcini.playback.base.VideoMode
@@ -85,11 +87,8 @@ import coil.request.CachePolicy
import coil.request.ImageRequest
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.Snackbar
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
+import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collectLatest
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
import net.dankito.readability4j.Readability4J
import org.apache.commons.lang3.StringUtils
import java.text.DecimalFormat
@@ -108,6 +107,7 @@ class AudioPlayerFragment : Fragment() {
private var prevItem: Episode? = null
private var currentItem: Episode? = null
+ private var playButInit = false
private var isShowPlay: Boolean = true
private var showTimeLeft = false
@@ -166,7 +166,10 @@ class AudioPlayerFragment : Fragment() {
}
}
}
- (activity as MainActivity).setPlayerVisible(false)
+ Logd(TAG, "curMedia: ${curMedia?.getIdentifier()}")
+ (activity as MainActivity).setPlayerVisible(curMedia != null)
+ if (curMedia != null) updateUi(curMedia!!)
+// if (curMedia is EpisodeMedia) setIsShowPlay(isCurrentlyPlaying(curMedia as EpisodeMedia))
return composeView
}
@@ -188,7 +191,7 @@ class AudioPlayerFragment : Fragment() {
if (curMedia == null) return
if (playbackService == null) PlaybackServiceStarter(requireContext(), curMedia!!).start()
}
- val imgLoc_ = remember(currentItem) { imgLoc }
+ val imgLoc_ = remember(currentMedia) { imgLoc }
AsyncImage(model = ImageRequest.Builder(context).data(imgLoc_)
.memoryCachePolicy(CachePolicy.ENABLED).placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher).build(),
contentDescription = "imgvCover",
@@ -502,9 +505,15 @@ class AudioPlayerFragment : Fragment() {
txtvPlaybackSpeed = speedStr
// binding.butPlaybackSpeed.setSpeed(event.newSpeed) TODO
}
+
@UnstableApi
fun onPositionUpdate(event: FlowEvent.PlaybackPositionEvent) {
Logd(TAG, "onPositionUpdate")
+ if (!playButInit && playButRes == R.drawable.ic_play_48dp && curMedia is EpisodeMedia) {
+ playButRes = R.drawable.ic_pause
+ playButInit = true
+ }
+
if (curMedia?.getIdentifier() != event.media?.getIdentifier() || controller == null || curPositionFB == Playable.INVALID_TIME || curDurationFB == Playable.INVALID_TIME) return
val converter = TimeSpeedConverter(curSpeedFB)
currentPosition = converter.convert(event.position)
@@ -520,6 +529,7 @@ class AudioPlayerFragment : Fragment() {
sliderValue = event.position.toFloat()
}
+
private fun onPlaybackServiceChanged(event: FlowEvent.PlaybackServiceEvent) {
when (event.action) {
FlowEvent.PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN -> (activity as MainActivity).setPlayerVisible(false)
@@ -527,6 +537,7 @@ class AudioPlayerFragment : Fragment() {
// PlaybackServiceEvent.Action.SERVICE_RESTARTED -> (activity as MainActivity).setPlayerVisible(true)
}
}
+
@UnstableApi
fun updateUi(media: Playable) {
Logd(TAG, "updateUi called $media")
@@ -578,7 +589,8 @@ class AudioPlayerFragment : Fragment() {
withContext(Dispatchers.Main) {
Logd(TAG, "subscribe: ${currentMedia?.getEpisodeTitle()}")
displayMediaInfo(currentMedia!!)
-// shownoteView.loadDataWithBaseURL("https://127.0.0.1", cleanedNotes?:"No notes", "text/html", "utf-8", "about:blank")
+ (activity as MainActivity).setPlayerVisible(curMedia != null)
+ // shownoteView.loadDataWithBaseURL("https://127.0.0.1", cleanedNotes?:"No notes", "text/html", "utf-8", "about:blank")
Logd(TAG, "Webview loaded")
}
}.invokeOnCompletion { throwable ->
@@ -738,7 +750,10 @@ class AudioPlayerFragment : Fragment() {
private var loadItemsRunning = false
fun loadMediaInfo() {
+ Logd(TAG, "loadMediaInfo() curMedia: ${curMedia?.getIdentifier()}")
val actMain = (activity as MainActivity)
+ var i = 0
+ while (curMedia == null && i++ < 6) runBlocking { delay(500) }
if (curMedia == null) {
if (actMain.isPlayerVisible()) actMain.setPlayerVisible(false)
return
@@ -747,6 +762,7 @@ class AudioPlayerFragment : Fragment() {
loadItemsRunning = true
if (!actMain.isPlayerVisible()) actMain.setPlayerVisible(true)
val curMediaChanged = currentMedia == null || curMedia?.getIdentifier() != currentMedia?.getIdentifier()
+ if (curMedia?.getIdentifier() != currentMedia?.getIdentifier()) updateUi(curMedia!!)
if (!isCollapsed && curMediaChanged) {
updateDetails()
Logd(TAG, "loadMediaInfo loading details ${curMedia?.getIdentifier()}")
@@ -761,7 +777,6 @@ class AudioPlayerFragment : Fragment() {
if (item != null) setItem(item)
setChapterDividers()
sleepTimerActive = isSleepTimerActive()
- if (currentMedia != null) updateUi(currentMedia!!)
// TODO: disable for now
// if (!includingChapters) loadMediaInfo(true)
}.invokeOnCompletion { throwable ->
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/BaseEpisodesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/BaseEpisodesFragment.kt
index db1785ae..ebd45a98 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/BaseEpisodesFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/BaseEpisodesFragment.kt
@@ -1,7 +1,7 @@
package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.BaseEpisodesListFragmentBinding
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
import ac.mdiq.podcini.net.download.DownloadStatus
import ac.mdiq.podcini.storage.model.Episode
import ac.mdiq.podcini.storage.model.EpisodeFilter
@@ -10,7 +10,10 @@ import ac.mdiq.podcini.ui.actions.SwipeAction
import ac.mdiq.podcini.ui.actions.SwipeActions
import ac.mdiq.podcini.ui.actions.SwipeActions.NoActionSwipeAction
import ac.mdiq.podcini.ui.activity.MainActivity
-import ac.mdiq.podcini.ui.compose.*
+import ac.mdiq.podcini.ui.compose.CustomTheme
+import ac.mdiq.podcini.ui.compose.EpisodeLazyColumn
+import ac.mdiq.podcini.ui.compose.EpisodeVM
+import ac.mdiq.podcini.ui.compose.InforBar
import ac.mdiq.podcini.ui.utils.EmptyViewHandler
import ac.mdiq.podcini.util.EventFlow
import ac.mdiq.podcini.util.FlowEvent
@@ -42,7 +45,7 @@ abstract class BaseEpisodesFragment : Fragment(), Toolbar.OnMenuItemClickListene
protected var page: Int = 1
private var displayUpArrow = false
- var _binding: BaseEpisodesListFragmentBinding? = null
+ var _binding: ComposeFragmentBinding? = null
protected val binding get() = _binding!!
protected var infoBarText = mutableStateOf("")
@@ -59,7 +62,7 @@ abstract class BaseEpisodesFragment : Fragment(), Toolbar.OnMenuItemClickListene
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
- _binding = BaseEpisodesListFragmentBinding.inflate(inflater)
+ _binding = ComposeFragmentBinding.inflate(inflater)
Logd(TAG, "fragment onCreateView")
toolbar = binding.toolbar
@@ -79,7 +82,7 @@ abstract class BaseEpisodesFragment : Fragment(), Toolbar.OnMenuItemClickListene
swipeActions = SwipeActions(this, TAG)
lifecycle.addObserver(swipeActions)
- binding.lazyColumn.setContent {
+ binding.mainView.setContent {
CustomTheme(requireContext()) {
Column {
InforBar(infoBarText, leftAction = leftActionState, rightAction = rightActionState, actionConfig = {swipeActions.showDialog()})
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt
index 3c936069..03a9267b 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt
@@ -1,7 +1,7 @@
package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.DownloadsFragmentBinding
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
import ac.mdiq.podcini.net.download.service.DownloadServiceInterface
import ac.mdiq.podcini.preferences.UserPreferences
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
@@ -20,7 +20,10 @@ import ac.mdiq.podcini.ui.actions.SwipeAction
import ac.mdiq.podcini.ui.actions.SwipeActions
import ac.mdiq.podcini.ui.actions.SwipeActions.NoActionSwipeAction
import ac.mdiq.podcini.ui.activity.MainActivity
-import ac.mdiq.podcini.ui.compose.*
+import ac.mdiq.podcini.ui.compose.CustomTheme
+import ac.mdiq.podcini.ui.compose.EpisodeLazyColumn
+import ac.mdiq.podcini.ui.compose.EpisodeVM
+import ac.mdiq.podcini.ui.compose.InforBar
import ac.mdiq.podcini.ui.dialog.EpisodeFilterDialog
import ac.mdiq.podcini.ui.dialog.EpisodeSortDialog
import ac.mdiq.podcini.ui.dialog.SwitchQueueDialog
@@ -37,7 +40,8 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import androidx.compose.foundation.layout.Column
-import androidx.compose.runtime.*
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.util.UnstableApi
@@ -56,7 +60,7 @@ import java.util.*
*/
@UnstableApi class DownloadsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
- private var _binding: DownloadsFragmentBinding? = null
+ private var _binding: ComposeFragmentBinding? = null
private val binding get() = _binding!!
private var runningDownloads: Set = HashSet()
@@ -74,7 +78,7 @@ import java.util.*
private var displayUpArrow = false
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- _binding = DownloadsFragmentBinding.inflate(inflater)
+ _binding = ComposeFragmentBinding.inflate(inflater)
Logd(TAG, "fragment onCreateView")
toolbar = binding.toolbar
@@ -88,12 +92,11 @@ import java.util.*
// }
displayUpArrow = parentFragmentManager.backStackEntryCount != 0
if (savedInstanceState != null) displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW)
-
(activity as MainActivity).setupToolbarToggle(toolbar, displayUpArrow)
swipeActions = SwipeActions(this, TAG)
swipeActions.setFilter(EpisodeFilter(EpisodeFilter.States.downloaded.name))
- binding.lazyColumn.setContent {
+ binding.mainView.setContent {
CustomTheme(requireContext()) {
Column {
InforBar(infoBarText, leftAction = leftActionState, rightAction = rightActionState, actionConfig = {swipeActions.showDialog()})
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt
index 578304b7..02d6b540 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt
@@ -1,14 +1,10 @@
package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
import ac.mdiq.podcini.databinding.EpisodeHomeFragmentBinding
-import ac.mdiq.podcini.databinding.EpisodeInfoFragmentBinding
import ac.mdiq.podcini.net.download.service.DownloadServiceInterface
import ac.mdiq.podcini.net.download.service.PodciniHttpClient.getHttpClient
-import ac.mdiq.podcini.net.sync.SynchronizationSettings.isProviderConnected
-import ac.mdiq.podcini.net.sync.SynchronizationSettings.wifiSyncEnabledKey
-import ac.mdiq.podcini.net.sync.model.EpisodeAction
-import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
import ac.mdiq.podcini.net.utils.NetworkUtils.fetchHtmlSource
import ac.mdiq.podcini.net.utils.NetworkUtils.isEpisodeHeadDownloadAllowed
import ac.mdiq.podcini.playback.base.InTheatre
@@ -16,7 +12,6 @@ import ac.mdiq.podcini.playback.base.InTheatre.curQueue
import ac.mdiq.podcini.playback.service.PlaybackService.Companion.seekTo
import ac.mdiq.podcini.preferences.UsageStatistics
import ac.mdiq.podcini.preferences.UserPreferences
-import ac.mdiq.podcini.storage.database.Episodes.setPlayState
import ac.mdiq.podcini.storage.database.Queues.addToQueue
import ac.mdiq.podcini.storage.database.Queues.removeFromQueue
import ac.mdiq.podcini.storage.database.RealmDB.realm
@@ -24,18 +19,12 @@ import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
import ac.mdiq.podcini.storage.database.RealmDB.unmanaged
import ac.mdiq.podcini.storage.database.RealmDB.upsert
import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
-import ac.mdiq.podcini.storage.model.Episode
-import ac.mdiq.podcini.storage.model.EpisodeMedia
-import ac.mdiq.podcini.storage.model.Feed
-import ac.mdiq.podcini.storage.model.Rating
+import ac.mdiq.podcini.storage.model.*
import ac.mdiq.podcini.storage.utils.DurationConverter
import ac.mdiq.podcini.storage.utils.ImageResourceUtils
import ac.mdiq.podcini.ui.actions.*
import ac.mdiq.podcini.ui.activity.MainActivity
-import ac.mdiq.podcini.ui.compose.ChaptersDialog
-import ac.mdiq.podcini.ui.compose.ChooseRatingDialog
-import ac.mdiq.podcini.ui.compose.CustomTheme
-import ac.mdiq.podcini.ui.compose.LargeTextEditingDialog
+import ac.mdiq.podcini.ui.compose.*
import ac.mdiq.podcini.ui.dialog.ShareDialog
import ac.mdiq.podcini.ui.utils.ShownotesCleaner
import ac.mdiq.podcini.ui.utils.ThemeUtils
@@ -109,7 +98,7 @@ import java.util.*
*/
@UnstableApi
class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
- private var _binding: EpisodeInfoFragmentBinding? = null
+ private var _binding: ComposeFragmentBinding? = null
private val binding get() = _binding!!
private var homeFragment: EpisodeHomeFragment? = null
@@ -126,7 +115,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
private var hasMedia by mutableStateOf(true)
var rating by mutableStateOf(episode?.rating ?: Rating.UNRATED.code)
private var inQueue by mutableStateOf(if (episode != null) curQueue.contains(episode!!) else false)
- var isPlayed by mutableStateOf(episode?.isPlayed() ?: false)
+ var isPlayed by mutableIntStateOf(episode?.playState ?: PlayState.UNSPECIFIED.code)
private var webviewData by mutableStateOf("")
@@ -141,7 +130,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
- _binding = EpisodeInfoFragmentBinding.inflate(inflater, container, false)
+ _binding = ComposeFragmentBinding.inflate(inflater, container, false)
Logd(TAG, "fragment onCreateView")
toolbar = binding.toolbar
@@ -150,7 +139,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
toolbar.setNavigationOnClickListener { parentFragmentManager.popBackStack() }
toolbar.setOnMenuItemClickListener(this)
- binding.composeView.setContent{
+ binding.mainView.setContent{
CustomTheme(requireContext()) {
MainView()
}
@@ -188,6 +177,9 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
var showChaptersDialog by remember { mutableStateOf(false) }
if (showChaptersDialog && episode?.media != null) ChaptersDialog(media = episode!!.media!!, onDismissRequest = {showChaptersDialog = false})
+ var showPlayStateDialog by remember { mutableStateOf(false) }
+ if (showPlayStateDialog) PlayStateDialog(listOf(episode!!)) { showPlayStateDialog = false }
+
Column {
Row(modifier = Modifier.padding(start = 16.dp, end = 16.dp), verticalAlignment = Alignment.CenterVertically) {
val imgLoc = if (episode != null) ImageResourceUtils.getEpisodeListImageLocation(episode!!) else null
@@ -200,39 +192,40 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
Row(modifier = Modifier.padding(top = 4.dp), verticalAlignment = Alignment.CenterVertically) {
Spacer(modifier = Modifier.weight(0.4f))
- val playedIconRes = if (!isPlayed) R.drawable.ic_mark_unplayed else R.drawable.ic_mark_played
+ val playedIconRes = PlayState.fromCode(isPlayed).res
Icon(imageVector = ImageVector.vectorResource(playedIconRes), tint = MaterialTheme.colorScheme.tertiary, contentDescription = "isPlayed",
modifier = Modifier.background(MaterialTheme.colorScheme.tertiaryContainer).width(24.dp).height(24.dp)
.clickable(onClick = {
- if (isPlayed) {
- setPlayState(Episode.PlayState.UNPLAYED.code, false, episode!!)
- if (isProviderConnected && episode?.feed?.isLocalFeed != true && episode?.media != null) {
- val actionNew: EpisodeAction = EpisodeAction.Builder(episode!!, EpisodeAction.NEW).currentTimestamp().build()
- SynchronizationQueueSink.enqueueEpisodeActionIfSyncActive(requireContext(), actionNew)
- }
- } else {
- setPlayState(Episode.PlayState.PLAYED.code, true, episode!!)
- if (episode?.feed?.isLocalFeed != true && (isProviderConnected || wifiSyncEnabledKey)) {
- val media: EpisodeMedia? = episode?.media
- // not all items have media, Gpodder only cares about those that do
- if (isProviderConnected && media != null) {
- val actionPlay: EpisodeAction = EpisodeAction.Builder(episode!!, EpisodeAction.PLAY)
- .currentTimestamp()
- .started(media.getDuration() / 1000)
- .position(media.getDuration() / 1000)
- .total(media.getDuration() / 1000)
- .build()
- SynchronizationQueueSink.enqueueEpisodeActionIfSyncActive(requireContext(), actionPlay)
- }
- }
- }
+ showPlayStateDialog = true
+// if (isPlayed) {
+// setPlayState(PlayState.UNPLAYED.code, false, episode!!)
+// if (isProviderConnected && episode?.feed?.isLocalFeed != true && episode?.media != null) {
+// val actionNew: EpisodeAction = EpisodeAction.Builder(episode!!, EpisodeAction.NEW).currentTimestamp().build()
+// SynchronizationQueueSink.enqueueEpisodeActionIfSyncActive(requireContext(), actionNew)
+// }
+// } else {
+// setPlayState(PlayState.PLAYED.code, true, episode!!)
+// if (episode?.feed?.isLocalFeed != true && (isProviderConnected || wifiSyncEnabledKey)) {
+// val media: EpisodeMedia? = episode?.media
+// // not all items have media, Gpodder only cares about those that do
+// if (isProviderConnected && media != null) {
+// val actionPlay: EpisodeAction = EpisodeAction.Builder(episode!!, EpisodeAction.PLAY)
+// .currentTimestamp()
+// .started(media.getDuration() / 1000)
+// .position(media.getDuration() / 1000)
+// .total(media.getDuration() / 1000)
+// .build()
+// SynchronizationQueueSink.enqueueEpisodeActionIfSyncActive(requireContext(), actionPlay)
+// }
+// }
+// }
}))
if (episode?.media != null) {
Spacer(modifier = Modifier.weight(0.2f))
val inQueueIconRes = if (inQueue) R.drawable.ic_playlist_play else R.drawable.ic_playlist_remove
Icon(imageVector = ImageVector.vectorResource(inQueueIconRes), tint = MaterialTheme.colorScheme.tertiary, contentDescription = "inQueue",
modifier = Modifier.background(MaterialTheme.colorScheme.tertiaryContainer).width(24.dp).height(24.dp).clickable(onClick = {
- if (inQueue) removeFromQueue(episode!!) else addToQueue(true, episode!!)
+ if (inQueue) removeFromQueue(episode!!) else addToQueue(episode!!)
}))
}
Spacer(modifier = Modifier.weight(0.2f))
@@ -625,7 +618,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
if (episode != null) {
rating = episode!!.rating
inQueue = curQueue.contains(episode!!)
- isPlayed = episode!!.isPlayed()
+ isPlayed = episode!!.playState
}
onFragmentLoaded()
itemLoaded = true
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt
index cf4e3c87..be7ddd51 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt
@@ -1,7 +1,7 @@
package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.FeedItemListFragmentBinding
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
import ac.mdiq.podcini.net.download.DownloadStatus
import ac.mdiq.podcini.net.feed.FeedUpdateManager
import ac.mdiq.podcini.preferences.UserPreferences
@@ -10,11 +10,8 @@ import ac.mdiq.podcini.storage.database.RealmDB.realm
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
import ac.mdiq.podcini.storage.database.RealmDB.upsert
import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
-import ac.mdiq.podcini.storage.model.Episode
-import ac.mdiq.podcini.storage.model.EpisodeFilter
-import ac.mdiq.podcini.storage.model.EpisodeSortOrder
+import ac.mdiq.podcini.storage.model.*
import ac.mdiq.podcini.storage.model.EpisodeSortOrder.Companion.fromCode
-import ac.mdiq.podcini.storage.model.Feed
import ac.mdiq.podcini.storage.utils.EpisodesPermutors.getPermutor
import ac.mdiq.podcini.ui.actions.SwipeAction
import ac.mdiq.podcini.ui.actions.SwipeActions
@@ -36,7 +33,10 @@ import android.view.*
import android.widget.Toast
import androidx.annotation.OptIn
import androidx.appcompat.widget.Toolbar
-import androidx.compose.foundation.*
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
@@ -55,6 +55,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
+import androidx.constraintlayout.compose.Dimension
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.util.UnstableApi
@@ -72,7 +73,7 @@ import java.util.concurrent.Semaphore
*/
@UnstableApi class FeedEpisodesFragment : Fragment(), Toolbar.OnMenuItemClickListener {
- private var _binding: FeedItemListFragmentBinding? = null
+ private var _binding: ComposeFragmentBinding? = null
private val binding get() = _binding!!
private lateinit var swipeActions: SwipeActions
@@ -87,6 +88,7 @@ import java.util.concurrent.Semaphore
private var headerCreated = false
private var feedID: Long = 0
private var feed by mutableStateOf(null)
+ var rating by mutableStateOf(Rating.UNRATED.code)
private val episodes = mutableStateListOf()
private val vms = mutableStateListOf()
@@ -112,7 +114,7 @@ import java.util.concurrent.Semaphore
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
Logd(TAG, "fragment onCreateView")
- _binding = FeedItemListFragmentBinding.inflate(inflater)
+ _binding = ComposeFragmentBinding.inflate(inflater)
binding.toolbar.inflateMenu(R.menu.feed_episodes)
binding.toolbar.setOnMenuItemClickListener(this)
@@ -169,7 +171,7 @@ import java.util.concurrent.Semaphore
requireActivity().supportFragmentManager.executePendingTransactions()
}
Column {
- FeedEpisodesHeader(activity = (activity as MainActivity), feed = feed, filterButColor = filterButColor.value, filterClickCB = {filterClick()}, filterLongClickCB = {filterLongClick()})
+ FeedEpisodesHeader(activity = (activity as MainActivity), filterButColor = filterButColor.value, filterClickCB = {filterClick()}, filterLongClickCB = {filterLongClick()})
InforBar(infoBarText, leftAction = leftActionState, rightAction = rightActionState, actionConfig = {
swipeActions.showDialog()
})
@@ -225,8 +227,14 @@ import java.util.concurrent.Semaphore
@kotlin.OptIn(ExperimentalFoundationApi::class)
@Composable
- fun FeedEpisodesHeader(activity: MainActivity, feed: Feed?, filterButColor: Color, filterClickCB: ()->Unit, filterLongClickCB: ()->Unit) {
+ fun FeedEpisodesHeader(activity: MainActivity, filterButColor: Color, filterClickCB: ()->Unit, filterLongClickCB: ()->Unit) {
val textColor = MaterialTheme.colorScheme.onSurface
+ var showChooseRatingDialog by remember { mutableStateOf(false) }
+ if (showChooseRatingDialog) ChooseRatingDialog(listOf(feed!!)) {
+ showChooseRatingDialog = false
+ feed = realm.query(Feed::class).query("id == $0", feed!!.id).first().find()!!
+ rating = feed!!.rating
+ }
ConstraintLayout(modifier = Modifier.fillMaxWidth().height(120.dp)) {
val (bgImage, bgColor, controlRow, image1, image2, imgvCover, taColumn) = createRefs()
AsyncImage(model = feed?.imageUrl?:"", contentDescription = "bgImage", contentScale = ContentScale.FillBounds,
@@ -238,7 +246,7 @@ import java.util.concurrent.Semaphore
start.linkTo(parent.start)
end.linkTo(parent.end)
})
- Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface.copy(alpha = 0.7f))
+ Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface.copy(alpha = 0.75f))
.constrainAs(bgColor) {
bottom.linkTo(parent.bottom)
top.linkTo(parent.top)
@@ -249,20 +257,30 @@ import java.util.concurrent.Semaphore
.constrainAs(controlRow) {
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
+ width = Dimension.fillToConstraints
}, verticalAlignment = Alignment.CenterVertically) {
Spacer(modifier = Modifier.weight(0.7f))
+ val ratingIconRes = Rating.fromCode(rating).res
+ Icon(imageVector = ImageVector.vectorResource(ratingIconRes), tint = MaterialTheme.colorScheme.tertiary, contentDescription = "rating",
+ modifier = Modifier.background(MaterialTheme.colorScheme.tertiaryContainer).width(30.dp).height(30.dp).clickable(onClick = {
+ showChooseRatingDialog = true
+ }))
+ Spacer(modifier = Modifier.weight(0.2f))
+ Icon(imageVector = ImageVector.vectorResource(R.drawable.arrows_sort), tint = textColor, contentDescription = "butSort",
+ modifier = Modifier.width(40.dp).height(40.dp).padding(3.dp).clickable(onClick = { SingleFeedSortDialog(feed).show(childFragmentManager, "SortDialog") }))
+ Spacer(modifier = Modifier.width(15.dp))
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_filter_white), tint = if (filterButColor == Color.White) textColor else filterButColor, contentDescription = "butFilter",
modifier = Modifier.width(40.dp).height(40.dp).padding(3.dp).combinedClickable(onClick = filterClickCB, onLongClick = filterLongClickCB))
Spacer(modifier = Modifier.width(15.dp))
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_settings_white), tint = textColor, contentDescription = "butShowSettings",
modifier = Modifier.width(40.dp).height(40.dp).padding(3.dp).clickable(onClick = {
if (feed != null) {
- val fragment = FeedSettingsFragment.newInstance(feed)
+ val fragment = FeedSettingsFragment.newInstance(feed!!)
activity.loadChildFragment(fragment, TransitionEffect.SLIDE)
}
}))
- Spacer(modifier = Modifier.weight(0.5f))
- Text(episodes.size.toString() + " / " + feed?.episodes?.size?.toString(), textAlign = TextAlign.Center, color = Color.White, style = MaterialTheme.typography.bodyLarge)
+ Spacer(modifier = Modifier.weight(0.4f))
+ Text(episodes.size.toString() + " / " + feed?.episodes?.size?.toString(), textAlign = TextAlign.End, color = textColor, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyLarge)
}
// Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_rounded_corner_left), contentDescription = "left_corner",
// Modifier.width(12.dp).height(12.dp).constrainAs(image1) {
@@ -274,21 +292,23 @@ import java.util.concurrent.Semaphore
// bottom.linkTo(parent.bottom)
// end.linkTo(parent.end)
// })
- AsyncImage(model = feed?.imageUrl?:"", contentDescription = "imgvCover", error = painterResource(R.mipmap.ic_launcher),
- modifier = Modifier.width(120.dp).height(120.dp).padding(start = 16.dp, end = 16.dp, bottom = 12.dp).constrainAs(imgvCover) {
- bottom.linkTo(parent.bottom)
- start.linkTo(parent.start)
- }.clickable(onClick = {
- if (feed != null) {
- val fragment = FeedInfoFragment.newInstance(feed)
- activity.loadChildFragment(fragment, TransitionEffect.SLIDE)
- }
- }))
- Column(Modifier.fillMaxWidth().constrainAs(taColumn) {
- top.linkTo(imgvCover.top)
- start.linkTo(imgvCover.end) }) {
- Text(feed?.title?:"", color = textColor, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.fillMaxWidth(), maxLines = 2, overflow = TextOverflow.Ellipsis)
- Text(feed?.author?:"", color = textColor, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.fillMaxWidth(), maxLines = 1, overflow = TextOverflow.Ellipsis)
+ Row(verticalAlignment = Alignment.Top, modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp).constrainAs(imgvCover) {
+ top.linkTo(parent.top)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ width = Dimension.fillToConstraints
+ }) {
+ AsyncImage(model = feed?.imageUrl ?: "", contentDescription = "imgvCover", error = painterResource(R.mipmap.ic_launcher),
+ modifier = Modifier.width(100.dp).height(100.dp).padding(start = 16.dp, end = 16.dp).clickable(onClick = {
+ if (feed != null) {
+ val fragment = FeedInfoFragment.newInstance(feed!!)
+ activity.loadChildFragment(fragment, TransitionEffect.SLIDE)
+ }
+ }))
+ Column(Modifier.padding(top = 10.dp)) {
+ Text(feed?.title ?: "", color = textColor, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.fillMaxWidth(), maxLines = 2, overflow = TextOverflow.Ellipsis)
+ Text(feed?.author ?: "", color = textColor, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.fillMaxWidth(), maxLines = 1, overflow = TextOverflow.Ellipsis)
+ }
}
}
}
@@ -386,7 +406,7 @@ import java.util.concurrent.Semaphore
} catch (e: InterruptedException) { throw RuntimeException(e) }
}.start()
}
- R.id.sort_items -> SingleFeedSortDialog(feed).show(childFragmentManager, "SortDialog")
+// R.id.sort_items -> SingleFeedSortDialog(feed).show(childFragmentManager, "SortDialog")
// R.id.filter_items -> {}
// R.id.settings -> {
// if (feed != null) {
@@ -651,6 +671,7 @@ import java.util.concurrent.Semaphore
}
withContext(Dispatchers.Main) {
Logd(TAG, "loadItems subscribe called ${feed?.title}")
+ rating = feed?.rating ?: Rating.UNRATED.code
swipeActions.setFilter(feed?.episodeFilter)
refreshHeaderView()
// if (feed != null) {
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt
index cd9ecee7..2327dfbd 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt
@@ -1,8 +1,8 @@
package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
import ac.mdiq.podcini.databinding.EditTextDialogBinding
-import ac.mdiq.podcini.databinding.FeedinfoBinding
import ac.mdiq.podcini.net.feed.FeedUpdateManager.runOnce
import ac.mdiq.podcini.net.feed.discovery.CombinedSearcher
import ac.mdiq.podcini.net.utils.HtmlToPlainText
@@ -42,8 +42,11 @@ import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar
-import androidx.compose.foundation.*
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
@@ -62,6 +65,7 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
+import androidx.constraintlayout.compose.Dimension
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment
import androidx.fragment.compose.AndroidFragment
@@ -80,7 +84,7 @@ import java.util.concurrent.ExecutionException
@UnstableApi
class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
- private var _binding: FeedinfoBinding? = null
+ private var _binding: ComposeFragmentBinding? = null
private val binding get() = _binding!!
private lateinit var feed: Feed
@@ -96,7 +100,7 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- _binding = FeedinfoBinding.inflate(inflater)
+ _binding = ComposeFragmentBinding.inflate(inflater)
Logd(TAG, "fragment onCreateView")
toolbar = binding.toolbar
toolbar.title = ""
@@ -108,7 +112,7 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
txtvAuthor = feed.author ?: ""
txtvUrl = feed.downloadUrl
- binding.mainUI.setContent {
+ binding.mainView.setContent {
CustomTheme(requireContext()) {
if (showRemoveFeedDialog) RemoveFeedDialog(listOf(feed), onDismissRequest = {showRemoveFeedDialog = false}) {
(activity as MainActivity).loadFragment(UserPreferences.defaultPage, null)
@@ -200,21 +204,23 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
// bottom.linkTo(parent.bottom)
// end.linkTo(parent.end)
// })
- AsyncImage(model = feed.imageUrl?:"", contentDescription = "imgvCover", error = painterResource(R.mipmap.ic_launcher),
- modifier = Modifier.width(120.dp).height(120.dp).padding(start = 16.dp, end = 16.dp, bottom = 12.dp).constrainAs(imgvCover) {
- bottom.linkTo(parent.bottom)
- start.linkTo(parent.start)
- }.clickable(onClick = {
+ Row(verticalAlignment = Alignment.Top, modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp).constrainAs(imgvCover) {
+ top.linkTo(parent.top)
+ start.linkTo(parent.start)
+ end.linkTo(parent.end)
+ width = Dimension.fillToConstraints
+ }) {
+ AsyncImage(model = feed.imageUrl ?: "", contentDescription = "imgvCover", error = painterResource(R.mipmap.ic_launcher),
+ modifier = Modifier.width(100.dp).height(100.dp).padding(start = 16.dp, end = 16.dp).clickable(onClick = {
// if (feed != null) {
// val fragment = FeedInfoFragment.newInstance(feed)
// (activity as MainActivity).loadChildFragment(fragment, TransitionEffect.SLIDE)
// }
- }))
- Column(Modifier.constrainAs(taColumn) {
- top.linkTo(imgvCover.top)
- start.linkTo(imgvCover.end) }) {
- Text(feed.title ?:"", color = textColor, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.fillMaxWidth(), maxLines = 2, overflow = TextOverflow.Ellipsis)
- Text(text = txtvAuthor, color = textColor, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.fillMaxWidth(), maxLines = 1, overflow = TextOverflow.Ellipsis)
+ }))
+ Column(Modifier.padding(top = 10.dp)) {
+ Text(feed.title ?: "", color = textColor, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.fillMaxWidth(), maxLines = 2, overflow = TextOverflow.Ellipsis)
+ Text(text = txtvAuthor, color = textColor, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.fillMaxWidth(), maxLines = 1, overflow = TextOverflow.Ellipsis)
+ }
}
}
}
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/LogsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/LogsFragment.kt
index 5a2f6c5f..09229034 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/LogsFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/LogsFragment.kt
@@ -1,9 +1,8 @@
package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.LogsFragmentBinding
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
import ac.mdiq.podcini.net.feed.FeedUpdateManager
-import ac.mdiq.podcini.storage.database.Episodes.getEpisodeByGuidOrUrl
import ac.mdiq.podcini.storage.database.Feeds.getFeed
import ac.mdiq.podcini.storage.database.Feeds.getFeedByTitleAndAuthor
import ac.mdiq.podcini.storage.database.RealmDB.realm
@@ -14,8 +13,8 @@ import ac.mdiq.podcini.storage.utils.DownloadResultComparator
import ac.mdiq.podcini.ui.actions.DownloadActionButton
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.activity.ShareReceiverActivity.Companion.receiveShared
-import ac.mdiq.podcini.ui.compose.CustomTheme
import ac.mdiq.podcini.ui.compose.ConfirmAddYoutubeEpisode
+import ac.mdiq.podcini.ui.compose.CustomTheme
import ac.mdiq.podcini.util.EventFlow
import ac.mdiq.podcini.util.FlowEvent
import ac.mdiq.podcini.util.Logd
@@ -51,7 +50,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextOverflow
@@ -66,23 +64,26 @@ import kotlinx.coroutines.withContext
import java.util.*
class LogsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
- private var _binding: LogsFragmentBinding? = null
+ private var _binding: ComposeFragmentBinding? = null
private val binding get() = _binding!!
private val shareLogs = mutableStateListOf()
private val subscriptionLogs = mutableStateListOf()
private val downloadLogs = mutableStateListOf()
-// private var showShared by mutableStateOf(true)
-// private var showSubscription by mutableStateOf(false)
+ private var displayUpArrow = false
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
Logd(TAG, "fragment onCreateView")
- _binding = LogsFragmentBinding.inflate(inflater)
+ _binding = ComposeFragmentBinding.inflate(inflater)
binding.toolbar.inflateMenu(R.menu.logs)
binding.toolbar.setOnMenuItemClickListener(this)
- binding.lazyColumn.setContent {
+ displayUpArrow = parentFragmentManager.backStackEntryCount != 0
+ if (savedInstanceState != null) displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW)
+ (activity as MainActivity).setupToolbarToggle(binding.toolbar, displayUpArrow)
+
+ binding.mainView.setContent {
CustomTheme(requireContext()) {
when {
downloadLogs.isNotEmpty() -> DownloadLogView()
@@ -95,6 +96,11 @@ class LogsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
return binding.root
}
+ override fun onSaveInstanceState(outState: Bundle) {
+ outState.putBoolean(KEY_UP_ARROW, displayUpArrow)
+ super.onSaveInstanceState(outState)
+ }
+
override fun onDestroyView() {
Logd(TAG, "onDestroyView")
_binding = null
@@ -489,5 +495,6 @@ class LogsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
companion object {
val TAG: String = LogsFragment::class.simpleName ?: "Anonymous"
+ private const val KEY_UP_ARROW = "up_arrow"
}
}
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt
index 205495b4..bf2abb40 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt
@@ -1,8 +1,6 @@
package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.NavListBinding
-import ac.mdiq.podcini.playback.base.InTheatre.curQueue
import ac.mdiq.podcini.preferences.UserPreferences.hiddenDrawerItems
import ac.mdiq.podcini.storage.database.Episodes.getEpisodesCount
import ac.mdiq.podcini.storage.database.Feeds.getFeedCount
@@ -42,6 +40,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
@@ -57,30 +56,30 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
import io.realm.kotlin.query.Sort
-import kotlinx.coroutines.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import kotlin.math.max
class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
val TAG = this::class.simpleName ?: "Anonymous"
-
- private var _binding: NavListBinding? = null
- private val binding get() = _binding!!
private val feeds = mutableStateListOf()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
- _binding = NavListBinding.inflate(inflater)
checkHiddenItems()
getRecentPodcasts()
- binding.mainView.setContent {
- CustomTheme(requireContext()) {
- MainView()
+ val composeView = ComposeView(requireContext()).apply {
+ setContent {
+ CustomTheme(requireContext()) {
+ MainView()
+ }
}
}
Logd(TAG, "fragment onCreateView")
- setupDrawerRoundBackground(binding.root)
- ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, insets: WindowInsetsCompat ->
+ setupDrawerRoundBackground(composeView)
+ ViewCompat.setOnApplyWindowInsetsListener(composeView) { view: View, insets: WindowInsetsCompat ->
val bars: Insets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
view.setPadding(bars.left, bars.top, bars.right, 0)
var navigationBarHeight = 0f
@@ -94,7 +93,7 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
insets
}
prefs!!.registerOnSharedPreferenceChangeListener(this)
- return binding.root
+ return composeView
}
private fun checkHiddenItems() {
@@ -171,7 +170,6 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
override fun onDestroyView() {
Logd(TAG, "onDestroyView")
- _binding = null
prefs!!.unregisterOnSharedPreferenceChangeListener(this)
super.onDestroyView()
}
@@ -239,7 +237,7 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
}
fun getLastNavFragment(): String {
- val lastFragment: String = prefs!!.getString(PREF_LAST_FRAGMENT_TAG, SubscriptionsFragment.TAG)?:""
+ val lastFragment: String = prefs?.getString(PREF_LAST_FRAGMENT_TAG, SubscriptionsFragment.TAG)?:""
return lastFragment
}
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineFeedFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineFeedFragment.kt
index c0ba7767..96636898 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineFeedFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineFeedFragment.kt
@@ -1,7 +1,7 @@
package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.OnlineFeedviewFragmentBinding
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
import ac.mdiq.podcini.net.download.service.DownloadServiceInterface
import ac.mdiq.podcini.net.feed.FeedBuilder
import ac.mdiq.podcini.net.feed.FeedUrlNotFoundException
@@ -81,7 +81,7 @@ import kotlin.concurrent.Volatile
*/
@OptIn(UnstableApi::class)
class OnlineFeedFragment : Fragment() {
- private var _binding: OnlineFeedviewFragmentBinding? = null
+ private var _binding: ComposeFragmentBinding? = null
private val binding get() = _binding!!
private var displayUpArrow = false
@@ -124,7 +124,7 @@ class OnlineFeedFragment : Fragment() {
@OptIn(UnstableApi::class) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
Logd(TAG, "fragment onCreateView")
- _binding = OnlineFeedviewFragmentBinding.inflate(layoutInflater)
+ _binding = ComposeFragmentBinding.inflate(layoutInflater)
displayUpArrow = parentFragmentManager.backStackEntryCount != 0
if (savedInstanceState != null) displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW)
(activity as MainActivity).setupToolbarToggle(binding.toolbar, displayUpArrow)
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QueuesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QueuesFragment.kt
index 2e874b3b..a424e76d 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QueuesFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QueuesFragment.kt
@@ -2,7 +2,7 @@ package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
import ac.mdiq.podcini.databinding.CheckboxDoNotShowAgainBinding
-import ac.mdiq.podcini.databinding.QueueFragmentBinding
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
import ac.mdiq.podcini.net.download.DownloadStatus
import ac.mdiq.podcini.net.feed.FeedUpdateManager
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
@@ -85,7 +85,7 @@ import kotlin.math.max
@UnstableApi class QueuesFragment : Fragment(), Toolbar.OnMenuItemClickListener {
- private var _binding: QueueFragmentBinding? = null
+ private var _binding: ComposeFragmentBinding? = null
private val binding get() = _binding!!
private lateinit var emptyViewHandler: EmptyViewHandler
@@ -126,7 +126,7 @@ import kotlin.math.max
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
- _binding = QueueFragmentBinding.inflate(inflater)
+ _binding = ComposeFragmentBinding.inflate(inflater)
Logd(TAG, "fragment onCreateView")
toolbar = binding.toolbar
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QuickDiscoveryFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QuickDiscoveryFragment.kt
index b08f2f21..de1d35a6 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QuickDiscoveryFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QuickDiscoveryFragment.kt
@@ -2,7 +2,10 @@ package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.BuildConfig
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.*
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
+import ac.mdiq.podcini.databinding.QuickFeedDiscoveryBinding
+import ac.mdiq.podcini.databinding.QuickFeedDiscoveryItemBinding
+import ac.mdiq.podcini.databinding.SelectCountryDialogBinding
import ac.mdiq.podcini.net.feed.discovery.ItunesTopListLoader
import ac.mdiq.podcini.net.feed.discovery.ItunesTopListLoader.Companion.prefs
import ac.mdiq.podcini.net.feed.discovery.PodcastSearchResult
@@ -10,9 +13,9 @@ import ac.mdiq.podcini.storage.database.Feeds.getFeedList
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.compose.CustomTheme
import ac.mdiq.podcini.ui.compose.OnlineFeedItem
-import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.EventFlow
import ac.mdiq.podcini.util.FlowEvent
+import ac.mdiq.podcini.util.Logd
import android.content.DialogInterface
import android.os.Bundle
import android.util.DisplayMetrics
@@ -24,7 +27,6 @@ import android.view.ViewGroup
import android.widget.*
import androidx.annotation.OptIn
import androidx.appcompat.widget.Toolbar
-import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
@@ -37,7 +39,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
@@ -255,7 +256,7 @@ class QuickDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
* Searches iTunes store for top podcasts and displays results in a list.
*/
class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
- private var _binding: FragmentSearchResultsBinding? = null
+ private var _binding: ComposeFragmentBinding? = null
private val binding get() = _binding!!
private lateinit var toolbar: MaterialToolbar
@@ -295,7 +296,7 @@ class QuickDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
@OptIn(UnstableApi::class) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
// Inflate the layout for this fragment
- _binding = FragmentSearchResultsBinding.inflate(inflater)
+ _binding = ComposeFragmentBinding.inflate(inflater)
Logd(TAG, "fragment onCreateView")
binding.mainView.setContent {
CustomTheme(requireContext()) {
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SearchResultsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SearchResultsFragment.kt
index 1b5a8be2..2b494745 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SearchResultsFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SearchResultsFragment.kt
@@ -1,7 +1,7 @@
package ac.mdiq.podcini.ui.fragment
import ac.mdiq.podcini.R
-import ac.mdiq.podcini.databinding.FragmentSearchResultsBinding
+import ac.mdiq.podcini.databinding.ComposeFragmentBinding
import ac.mdiq.podcini.net.feed.discovery.PodcastSearchResult
import ac.mdiq.podcini.net.feed.discovery.PodcastSearcher
import ac.mdiq.podcini.net.feed.discovery.PodcastSearcherRegistry
@@ -48,7 +48,7 @@ import kotlinx.coroutines.withContext
class SearchResultsFragment : Fragment() {
- private var _binding: FragmentSearchResultsBinding? = null
+ private var _binding: ComposeFragmentBinding? = null
private val binding get() = _binding!!
private var searchProvider: PodcastSearcher? = null
@@ -74,7 +74,7 @@ class SearchResultsFragment : Fragment() {
}
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- _binding = FragmentSearchResultsBinding.inflate(inflater)
+ _binding = ComposeFragmentBinding.inflate(inflater)
Logd(TAG, "fragment onCreateView")
binding.mainView.setContent {
CustomTheme(requireContext()) {
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt
index c0fb25dd..aeb7bd51 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt
@@ -381,7 +381,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
val dir = 1 - 2*feedOrderDir // get from 0, 1 to 1, -1
val comparator: Comparator = when (feedOrder) {
FeedSortOrder.UNPLAYED_NEW_OLD.index -> {
- val queryString = "feedId == $0 AND (playState == ${Episode.PlayState.NEW.code} OR playState == ${Episode.PlayState.UNPLAYED.code})"
+ val queryString = "feedId == $0 AND (playState == ${PlayState.NEW.code} OR playState == ${PlayState.UNPLAYED.code})"
val counterMap: MutableMap = mutableMapOf()
for (f in feedList_) {
val c = realm.query(Episode::class).query(queryString, f.id).count().find()
@@ -403,7 +403,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
}
FeedSortOrder.MOST_PLAYED.index -> {
- val queryString = "feedId == $0 AND playState == ${Episode.PlayState.PLAYED.code}"
+ val queryString = "feedId == $0 AND playState == ${PlayState.PLAYED.code}"
val counterMap: MutableMap = mutableMapOf()
for (f in feedList_) {
val c = realm.query(Episode::class).query(queryString, f.id).count().find()
@@ -436,7 +436,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
FeedSortOrder.LAST_UPDATED_UNPLAYED_NEW_OLD.index -> {
val queryString =
- "feedId == $0 AND (playState == ${Episode.PlayState.NEW.code} OR playState == ${Episode.PlayState.UNPLAYED.code}) SORT(pubDate DESC)"
+ "feedId == $0 AND (playState == ${PlayState.NEW.code} OR playState == ${PlayState.UNPLAYED.code}) SORT(pubDate DESC)"
val counterMap: MutableMap = mutableMapOf()
for (f in feedList_) {
val d = realm.query(Episode::class).query(queryString, f.id).first().find()?.pubDate ?: 0L
@@ -458,7 +458,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
FeedSortOrder.MOST_DOWNLOADED_UNPLAYED.index -> {
val queryString =
- "feedId == $0 AND (playState == ${Episode.PlayState.NEW.code} OR playState == ${Episode.PlayState.UNPLAYED.code}) AND media.downloaded == true"
+ "feedId == $0 AND (playState == ${PlayState.NEW.code} OR playState == ${PlayState.UNPLAYED.code}) AND media.downloaded == true"
val counterMap: MutableMap = mutableMapOf()
for (f in feedList_) {
val c = realm.query(Episode::class).query(queryString, f.id).count().find()
@@ -469,7 +469,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
// doing FEED_ORDER_NEW
else -> {
- val queryString = "feedId == $0 AND playState == ${Episode.PlayState.NEW.code}"
+ val queryString = "feedId == $0 AND playState == ${PlayState.NEW.code}"
val counterMap: MutableMap = mutableMapOf()
for (f in feedList_) {
val c = realm.query(Episode::class).query(queryString, f.id).count().find()
@@ -954,13 +954,13 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
})
)
- if (feed.rating != Rating.UNRATED.code)
- Icon(imageVector = ImageVector.vectorResource(Rating.fromCode(feed.rating).res), tint = MaterialTheme.colorScheme.tertiary,
- contentDescription = "rating",
- modifier = Modifier.background(MaterialTheme.colorScheme.tertiaryContainer).constrainAs(rating) {
- start.linkTo(parent.start)
- centerVerticallyTo(coverImage)
- })
+// if (feed.rating != Rating.UNRATED.code)
+// Icon(imageVector = ImageVector.vectorResource(Rating.fromCode(feed.rating).res), tint = MaterialTheme.colorScheme.tertiary,
+// contentDescription = "rating",
+// modifier = Modifier.background(MaterialTheme.colorScheme.tertiaryContainer).constrainAs(rating) {
+// start.linkTo(parent.start)
+// centerVerticallyTo(coverImage)
+// })
}
val textColor = MaterialTheme.colorScheme.onSurface
Column(Modifier.weight(1f).padding(start = 10.dp).combinedClickable(onClick = {
@@ -984,8 +984,13 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
Logd(TAG, "long clicked: ${feed.title}")
})) {
- Text(feed.title ?: "No title", color = textColor, maxLines = 1, overflow = TextOverflow.Ellipsis,
- style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.Bold))
+ Row {
+ if (feed.rating != Rating.UNRATED.code)
+ Icon(imageVector = ImageVector.vectorResource(Rating.fromCode(feed.rating).res), tint = MaterialTheme.colorScheme.tertiary, contentDescription = "rating",
+ modifier = Modifier.background(MaterialTheme.colorScheme.tertiaryContainer))
+ Text(feed.title ?: "No title", color = textColor, maxLines = 1, overflow = TextOverflow.Ellipsis,
+ style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.Bold))
+ }
Text(feed.author ?: "No author", color = textColor, maxLines = 1, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.bodyMedium)
Row(Modifier.padding(top = 5.dp)) {
val measureString = remember { NumberFormat.getInstance().format(feed.episodes.size.toLong()) + " : " +
diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/StatisticsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/StatisticsFragment.kt
index 06bae5ac..fb383644 100644
--- a/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/StatisticsFragment.kt
+++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/StatisticsFragment.kt
@@ -447,7 +447,7 @@ class StatisticsFragment : Fragment() {
else {
// progress import does not include playedDuration
if (includeMarkedAsPlayed) {
- if (m.playbackCompletionTime > 0 || m.episodeOrFetch()?.playState == Episode.PlayState.PLAYED.code)
+ if (m.playbackCompletionTime > 0 || m.episodeOrFetch()?.playState == PlayState.PLAYED.code)
dur += m.duration
else if (m.position > 0) dur += m.position
} else dur += m.position
diff --git a/app/src/main/res/drawable/baseline_build_24.xml b/app/src/main/res/drawable/baseline_build_24.xml
new file mode 100644
index 00000000..cbc92c8d
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_build_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_download_done_24.xml b/app/src/main/res/drawable/baseline_download_done_24.xml
new file mode 100644
index 00000000..74b5d32e
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_download_done_24.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_fiber_new_24.xml b/app/src/main/res/drawable/baseline_fiber_new_24.xml
new file mode 100644
index 00000000..979c0465
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_fiber_new_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_local_play_24.xml b/app/src/main/res/drawable/baseline_local_play_24.xml
new file mode 100644
index 00000000..e8e09168
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_local_play_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_new_label_24.xml b/app/src/main/res/drawable/baseline_new_label_24.xml
new file mode 100644
index 00000000..3eb7690c
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_new_label_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_play_circle_outline_24.xml b/app/src/main/res/drawable/baseline_play_circle_outline_24.xml
new file mode 100644
index 00000000..b1bdebfe
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_play_circle_outline_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_play_disabled_24.xml b/app/src/main/res/drawable/baseline_play_disabled_24.xml
new file mode 100644
index 00000000..fc25b014
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_play_disabled_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_visibility_off_24.xml b/app/src/main/res/drawable/baseline_visibility_off_24.xml
new file mode 100644
index 00000000..5993ca39
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_visibility_off_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_watch_later_24.xml b/app/src/main/res/drawable/baseline_watch_later_24.xml
new file mode 100644
index 00000000..711969d7
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_watch_later_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml
index d0efb9d0..17a6e5d8 100644
--- a/app/src/main/res/layout/addfeed.xml
+++ b/app/src/main/res/layout/addfeed.xml
@@ -4,26 +4,18 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
-
-
-
-
-
+ android:minHeight="?android:attr/actionBarSize"
+ android:theme="?attr/actionBarTheme"
+ app:title="@string/add_feed_label"
+ app:navigationContentDescription="@string/toolbar_back_button_content_description"
+ app:navigationIcon="?homeAsUpIndicator" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/episode_info_fragment.xml b/app/src/main/res/layout/compose_fragment.xml
similarity index 72%
rename from app/src/main/res/layout/episode_info_fragment.xml
rename to app/src/main/res/layout/compose_fragment.xml
index 179afb08..6305ceed 100644
--- a/app/src/main/res/layout/episode_info_fragment.xml
+++ b/app/src/main/res/layout/compose_fragment.xml
@@ -1,27 +1,24 @@
-
+ android:id="@+id/compose_fragment">
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/downloads_fragment.xml b/app/src/main/res/layout/downloads_fragment.xml
deleted file mode 100644
index 2baf5dc7..00000000
--- a/app/src/main/res/layout/downloads_fragment.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/feed_item_list_fragment.xml b/app/src/main/res/layout/feed_item_list_fragment.xml
deleted file mode 100644
index 4b5533f4..00000000
--- a/app/src/main/res/layout/feed_item_list_fragment.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/feedinfo.xml b/app/src/main/res/layout/feedinfo.xml
deleted file mode 100644
index a2a01973..00000000
--- a/app/src/main/res/layout/feedinfo.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_search_results.xml b/app/src/main/res/layout/fragment_search_results.xml
deleted file mode 100644
index 7f4aaa2c..00000000
--- a/app/src/main/res/layout/fragment_search_results.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/logs_fragment.xml b/app/src/main/res/layout/logs_fragment.xml
deleted file mode 100644
index 8d2f2359..00000000
--- a/app/src/main/res/layout/logs_fragment.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/nav_list.xml b/app/src/main/res/layout/nav_list.xml
deleted file mode 100644
index efd3b5b7..00000000
--- a/app/src/main/res/layout/nav_list.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/online_feedview_fragment.xml b/app/src/main/res/layout/online_feedview_fragment.xml
deleted file mode 100644
index dc052e07..00000000
--- a/app/src/main/res/layout/online_feedview_fragment.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/queue_fragment.xml b/app/src/main/res/layout/queue_fragment.xml
deleted file mode 100644
index 09f13f67..00000000
--- a/app/src/main/res/layout/queue_fragment.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/search_fragment.xml b/app/src/main/res/layout/search_fragment.xml
index 48e719d1..08afe406 100644
--- a/app/src/main/res/layout/search_fragment.xml
+++ b/app/src/main/res/layout/search_fragment.xml
@@ -5,26 +5,18 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
+ android:fitsSystemWindows="true"
android:id="@+id/search_fragment">
-
-
-
-
-
+ android:minHeight="?android:attr/actionBarSize"
+ android:theme="?attr/actionBarTheme"
+ app:title="@string/search_label"
+ app:navigationContentDescription="@string/toolbar_back_button_content_description"
+ app:navigationIcon="?homeAsUpIndicator" />
-
diff --git a/app/src/main/res/menu/feed_episodes.xml b/app/src/main/res/menu/feed_episodes.xml
index d916899b..caf86e97 100644
--- a/app/src/main/res/menu/feed_episodes.xml
+++ b/app/src/main/res/menu/feed_episodes.xml
@@ -8,12 +8,12 @@
android:icon="@drawable/playlist_play"
custom:showAsAction="always"/>
- -
-
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/feeditemlist_context.xml b/app/src/main/res/menu/feeditemlist_context.xml
deleted file mode 100644
index 6a2e27d6..00000000
--- a/app/src/main/res/menu/feeditemlist_context.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/multi_select_context_popup.xml b/app/src/main/res/menu/multi_select_context_popup.xml
deleted file mode 100644
index 730b0101..00000000
--- a/app/src/main/res/menu/multi_select_context_popup.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/multi_select_options.xml b/app/src/main/res/menu/multi_select_options.xml
deleted file mode 100644
index 33755cbb..00000000
--- a/app/src/main/res/menu/multi_select_options.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
diff --git a/app/src/main/res/menu/queue_context.xml b/app/src/main/res/menu/queue_context.xml
deleted file mode 100644
index 522e712e..00000000
--- a/app/src/main/res/menu/queue_context.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 2c7edc35..cbe75c51 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -228,31 +228,14 @@
- تم مسح %d حلقات منزلة.
- تم الإزالة من صندوق الوارد
- علمها كمشغلة
- فعل حالة التشغيل
- تم الاستماع
- لم يتم الاستماع بعد
+
+
+
+
+
علمها كمقروءة
للإنتقال للتوقيتات, يجب أن تشغل الحلقة
-
- - %d حلقة علمت كـ مقروءة.
- - %d حلقة علمت كـ مقروءة.
- - %d حلقتان علمتا كـ مقروءة.
- - %d حلقات علمت كـ مقروءة.
- - %d حلقات علمت كـ مقروءة.
- - %d حلقات علمت كمقروءة.
-
- علمها كغير مشغلة
- علمها كغير مقروءة
-
- - %d حلقة علمت بأنه لم يتم تشغيلها.
- - %d حلقة علمت بأنه لم يتم تشغيلها.
- - %d حلقتان علمتا بأنه لم يتم تشغيلها.
- - %d حلقات علمت بأنه لم يتم تشغيلها.
- - %d حلقة علمت بأنه لم يتم تشغيلها.
- - %d حلقات علمت بأنه لم يتم تشغيلها.
-
+
اضف للائحة الاستماع
- %d حلقة أضيفت إلى لائحة الاستماع.
diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml
index 82576a21..737500e8 100644
--- a/app/src/main/res/values-ast/strings.xml
+++ b/app/src/main/res/values-ast/strings.xml
@@ -104,9 +104,9 @@
Sentir
Desaniciar
Nun ye posible desaniciar el ficheru. Reaniciar el preséu podría ayudar.
- Marcar como «Reprodúxose»
- Marcar como «Ensin reproducir»
- Marcar como «Ensin lleer»
+
+
+
- Amestóse %d episodiu a la cola.
- Amestáronse %d episodios a la cola.
diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml
index b1531dcf..2781ee45 100644
--- a/app/src/main/res/values-br/strings.xml
+++ b/app/src/main/res/values-br/strings.xml
@@ -193,29 +193,15 @@
- Dilamet ez eus bet %d rann pellgarget.
- Tennet eo bet eus ar voest degemer
- Merkañ evel lennet
- Lakaat da gemm stad al lenn
- Lakaet war-well evel lennet
- Lakaet war-well evel lakaet da baouez
+
+
+
+
+
Merkañ evel lennet
Evit kemmañ al lec\'hiadur e rankit lenn ar rann
-
- - %d rann merket evel lennet
- - %d rann merket evel lennet
- - %d rann merket evel lennet
- - %d rann merket evel lennet
- - %d rann merket evel lennet
-
- Merkañ evel anlennet
- Merkañ evel anlennet
-
- - %d rann merket evel anlennet.
- - %d rann merket evel anlennet.
- - %d rann merket evel anlennet.
- - %d rann merket evel anlennet.
- - %d rann merket evel anlennet.
-
+
+
Ouzhpennañ el lost
- %d rann ouzhpennet el lost
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index c35bc16e..7d5f5e6e 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -188,23 +188,14 @@
- %d episodis baixats, suprimits.
- Eliminat de la Safata d\'entrada
- Marca com a reproduït
- Commuta l\'estat de reproducció
- Marca com a reproduït
- Marca com a no reproduït
+
+
+
+
+
Marcar com a llegit
Per a botar a posicions deus reproduir l\'episodi.
-
- - %d episodi marcat com a reproduït.
- - %d episodis marcats com a reproduïts.
-
- Marca com a pendent
- Marcar com a no llegit
-
- - %d episodi marcat com a no llegit.
- - %d episodis marcats com a no llegits.
-
+
Afegeix a la cua
- %d episodi afegit a la cua.
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 085ecbc2..1d457a2e 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -217,27 +217,15 @@
- %d stažených epizod smazáno.
- Odebráno z nových
- Označit jako poslechnuté
- Přepnutí stavu přehrávání
- Označeno jako poslechnuté
- Označeno jako neposlechnuté
+
+
+
+
+
Označit jako poslechnuté
Pro přeskočení na pozice musíte epizodu přehrát
-
- - %d epizoda označena jako přehraná
- - %d epizody označeny jako přehrané
- - %d epizod označeno jako přehrané
- - %d epizod označeno jako přehrané
-
- Označit jako neposlechnuté
- Označit jako nepřečtené
-
- - %d epizoda označena jako neposlechnutá
- - %d epizody označeny jako neposlechnuté
- - %d epizod označeno jako neposlechnuté
- - %d epizod označeno jako neposlechnuté
-
+
+
Přidat do fronty
- %d epizoda přidána do fronty
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 91a39a2a..ba2e4acf 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -199,23 +199,14 @@
- %d overførte afsnit slettet.
- Fjernet fra indbakken
- Markér som afspillet
- Skift afspilningstilstand
- Markér som afspillet
- Markér som uafspillet
+
+
+
+
+
Marker som læst
For at springe til positioner, er du nødt til at afspille afsnittet
-
- - %d afsnit markeret som afspillet.
- - %d afsnit markeret som afspillet.
-
- Markér som uafspillet
- Marker som ulæst
-
- - %d afsnit markeret som uafspillet.
- - %d afsnit markeret som uafspillede.
-
+
Føj til kø
- %d afsnit føjet til køen.
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index d66dbabe..562cbedd 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -203,23 +203,14 @@
- %d heruntergeladene Episoden gelöscht.
- Aus dem Posteingang entfernt
- Als gespielt markieren
- Abgespielt-Zustand umschalten
- Als gespielt markieren
- Als ungespielt markieren
+
+
+
+
+
Als gelesen markieren
Um auf eine Position zu springen, musst du die Episode abspielen
-
- - %d Episode als gespielt markiert.
- - %d Episoden als gespielt markiert.
-
- Als ungespielt markieren
- Als ungelesen markieren
-
- - %d Episode als ungespielt markiert.
- - %d Episoden als ungespielt markiert.
-
+
Zur Warteschlange hinzufügen
- %d Episode zur Warteschlange hinzugefügt.
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index bb6d0964..dadba586 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -211,25 +211,14 @@
- Eliminados %d episodios descargados.
- Borrado de la bandeja de entrada
- Marcar como reproducido
- Cambiar estado de reproducción
- Marcar como reproducido
- Marcar como no reproducido
+
+
+
+
+
Marcar como leído
Para saltar a posiciones, necesitas reproducir el episodio
-
- - %depisodio marcado como reproducido.
- - %depisodios marcados como reproducidos.
- - %depisodios marcados como reproducidos.
-
- Marcar como no reproducido
- Marcar como no leído
-
- - %d episodio marcado como no reproducido.
- - %d episodios marcados como no reproducidos.
- - %d episodios marcados como no reproducidos.
-
+
Añadir a la cola
- %d episodio añadido a la cola.
diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml
index 76bd171e..c9f09d0e 100644
--- a/app/src/main/res/values-et/strings.xml
+++ b/app/src/main/res/values-et/strings.xml
@@ -160,21 +160,11 @@
- 1 allalaaditud saade kustutatud.
- %d allalaaditud saadet kustutatud.
- Märgi kuulatuks
- Märgitud kuulatuks
- Märgitud kui kuulamata
+
+
+
Märgi loetuks
Asukohale hüppamiseks pead saadet esitama
-
- - %d saade märgiti kuulatuks.
- - %d saadet märgiti kuulatuks.
-
- Märgitud kui kuulamata
- Märgi mitteloetuks
-
- - %d saade märgiti kui kuulamata.
- - %d saadet märgiti kui kuulamata.
-
Lisa järjekorda
- %d saade lisati järjekorda.
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index 36053bd2..2a9c4f45 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -187,23 +187,14 @@
- %d deskargatutako kapituluak ezabatu egin dira
- Sarrerako ontzitik kenduta
- Markatu entzundakotzat
- Erreprodukzio-egoera txandakatu
- Entzundakotzat markatua
- Ez entzundakotzat markatua
+
+
+
+
+
Markatu iraurrita gisa
Posizioetara jauzi egiteko, pasartea erreproduzitu behar duzu
-
- - %d saio markatuta ikusita bezala.
- - %d saio markatuta ikusita bezala.
-
- Markatu ez entzundakotzat bezala
- Markatu ez irakurrita bezala
-
- - %d saio markatuta ikusita bezala.
- - %d saio markatuta ez ikusita bezala.
-
+
Gehitu ilaran
- %d saio ilaran gehitua.
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index 95fac2f7..3c0413c5 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -194,23 +194,14 @@
- %dقسمت بار گرفته حذف شد.
- حذف شده از صندوق ورودی
- علامتگذاری بهعنوان پخششده
- وضعیت پخش را تغییر دهید
- علامتگذاری شد بهعنوان پخششده
- علامتگذاری شد بهعنوان پخشنشده
+
+
+
+
+
علامت زدن به عنوان خوانده شده
برای پرش به موقعیتها، میتوانید قسمت را پخش کنید
-
- - %d قسمت بهعنوان پخششده علامتگذاری شد.
- - %d قسمت بهعنوان پخششده علامتگذاری شد.
-
- علامتگذاری بهعنوان پخشنشده
- علامتگذاری بهعنوان نخواندهشده
-
- - %d قسمت بهعنوان پخشنشده علامتگذاری شد.
- - %d قسمت بهعنوان پخشنشده علامتگذاری شد.
-
+
افزودن به صف
- %d قسمت به صف اضافه شد.
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index adadbfd0..83c8bca4 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -187,23 +187,14 @@
- %d ladattua jaksoa poistettu.
- Poistettu saapuneista
- Merkitse toistetuksi
- Vaihda toistettu-tila
- Merkattu toistetuksi
- Merkattu toistamattomaksi
+
+
+
+
+
Merkitse luetuksi
Jaksoa pitää toistaa siirtyäksesi kohtiin
-
- - %d jakso merkitty soitetuksi.
- - %d jaksoa merkitty toistetuksi
-
- Merkitse toistamattomaksi
- Merkitse lukemattomaksi
-
- - %d jakso merkitty soittamattomaksi.
- - %d jaksoa merkitty toistamattomaksi.
-
+
Lisää jonoon
- %d jakso lisätty jonoon.
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 772fb2d8..4bf5625e 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -212,25 +212,14 @@
- %d épisodes téléchargés supprimés.
- Supprimé de la boîte de réception
- Marquer comme lu
- Modifier l\'état de lecture
- Marqué comme lu
- Marqué comme non lu
+
+
+
+
+
Marquer comme lu
Pour changer la position l\'épisode doit être en cours de lecture
-
- - %d épisode marqué comme lu.
- - %d épisodes marqués comme lus.
- - %d épisodes marqués comme lus.
-
- Marquer comme non lu
- Marquer comme non lu
-
- - %d épisode marqué comme non lu.
- - %d épisodes marqués comme non lus.
- - %d épisodes marqués comme non lus.
-
+
Ajouter à la liste de lecture
- %d épisode ajouté à la liste de lecture.
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index fc7c7625..03eeaa03 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -199,23 +199,13 @@
- Eliminados %d episodios descargados.
- Retirado da lista de novidades
- Marcar como reproducido
- Cambiar estado de reprodución
- Marcado como reproducido
- Marcado como non reproducido
+
+
+
+
+
Marcar como lido
Para ir á posición, debes reproducir o episodio
-
- - %d episodio marcado como reproducido.
- - %d episodios marcados como reproducidos.
-
- Marcar como non reproducido
- Marcar como non lido
-
- - %d episodio marcado como non reproducido.
- - %d episodios marcados como non reproducidos.
-
Engadir á cola
- %d episodio engadido a cola.
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 7992398a..1ad65afa 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -175,23 +175,14 @@
- %d letöltött epizód törölve.
- Eltávolítva a beérkezők közül
- Megjelölés lejátszottként
- Lejátszott állapot be/ki
- Megjelölve lejátszottként
- Megjelölve nem lejátszottként
+
+
+
+
+
Megjelölés olvasottként
A pozíciókra ugráshoz le kell játszania az epizódot
-
- - %d epizód megjelölve lejátszottként.
- - %d epizód megjelölve lejátszottként.
-
- Megjelölés nem lejátszottként
- Megjelölés olvasatlanként
-
- - %d epizód megjelölve nem lejátszottként.
- - %d epizód megjelölve nem lejátszottként.
-
+
- %d epizód sorbaállítva.
- %d epizód sorbaállítva.
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index f3a9c63c..7c403883 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -155,21 +155,14 @@
- %depisode terunduh dihapus.
- Dihapus dari kotak masuk
- Tandai diputar
- Aktifkan status diputar
- Ditandai sebagai \'diputar\'
- Ditandai sebagai \'belum diputar\'
+
+
+
+
+
Tandai dibaca
Untuk melompat posisi waktu, Anda perlu memutar episode terlebih dahulu
-
- - %d episode ditandai sebagai telah diputar.
-
- Tandai belum diputar
- Tandai belum dibaca
-
- - %d episode ditandai sebagai belum diputar
-
+
- %d episode ditambahkan ke antrian.
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 72dc7b1c..c90b5888 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -212,25 +212,14 @@
- %d episodi scaricati eliminati.
- Rimosso dall\'inbox
- Segna come riprodotto
- Cambia stato di riproduzione
- Segnato come riprodotto
- Segnato come non riprodotto
+
+
+
+
+
Segna come letto
Per saltare alla posizione devi riprodurre l\'episodio
-
- - %d episodio segnato come riprodotto.
- - %d di episodi segnati come riprodotti.
- - %d episodi segnati come riprodotti.
-
- Segna come non riprodotto
- Segna come non letto
-
- - %d episodio segnato come non riprodotto.
- - %d di episodi segnati come non riprodotti.
- - %d episodi segnati come non riprodotti.
-
+
Aggiungi alla coda
- %d episodio aggiunto alla coda.
diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml
index a50bc7d4..94349bb4 100644
--- a/app/src/main/res/values-iw/strings.xml
+++ b/app/src/main/res/values-iw/strings.xml
@@ -217,27 +217,14 @@
- %d פרקים שהורדו נמחקו.
- הוסר מהדואר הנכנס
- סימון כנצפה
- החלפת מצב נגינה
- סומן כהתנגן
- סומן שלא התנגן
+
+
+
+
+
סימון כנקרא
כדי לקפוץ למיקומים, עליך לנגן את הפרק
-
- - פרק אחד סומן שנוגן.
- - %d פרקים סומנו שנוגנו.
- - %d פרקים סומנו שנוגנו.
- - %d פרקים סומנו שנוגנו.
-
- סימון כלא נוגן
- סימון כלא נקרא
-
- - פרק אחד סומן שטרם נוגן.
- - %d פרקים סומנו שטרם נוגנו.
- - %d פרקים סומנו שטרם נוגנו.
- - %d פרקים סומנו שטרם נוגנו.
-
+
הוספה לתור
- פרק אחד נוסף לתור.
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 7f0abc0f..c10a6fd5 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -147,21 +147,13 @@
- ダウンロードした %d 項目のエピソードが削除されました。
- 受信トレイから取り除きました
- 再生済としてマーク
- 再生状態の切り替え
- 再生済みとマーク済み
- 未再生としてマーク
+
+
+
+
+
既読としてマーク
位置にジャンプするには、エピソードを再生する必要があります
-
- - %d エピソードを再生済にしました。
-
- 未再生としてマーク
- 未読としてマーク
-
- - %d エピソードを未再生にしました。
-
- %d エピソードをキューに追加しました。
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 70e83a69..41f0564c 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -178,21 +178,14 @@
- 다운로드한 %d개 에피소드 삭제함.
- 새로 받음 목록에서 제거함
- 재생했다고 표시
- 재생함 상태 토글
- 재생했다고 표시
- 재생하지 않음으로 표시
+
+
+
+
+
읽었다고 표시
특정 재생 위치로 이동하려면, 에피소드를 재생해야 합니다
-
- - %d개 에피소드를 재생한 것으로 표시했습니다.
-
- 재생하지 않음으로 표시
- 읽지 않음으로 표시
-
- - %d개 에피소드를 재생하지 않은 것으로 표시했습니다.
-
+
대기열에 추가
- %d개 에피소드를 대기열에 추가했습니다.
diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml
index f416df91..ba662b65 100644
--- a/app/src/main/res/values-lt/strings.xml
+++ b/app/src/main/res/values-lt/strings.xml
@@ -151,25 +151,12 @@
- %d atsiųsti epizodai ištrinti.
- %d atsiųsti epizodai ištrinti.
- Pažymėti kaip perklausytą
- Pažymėtas kaip perklausytas
- Pažymėtas kaip neperklausytas
+
+
+
Pažymėti kaip perskaitytą
Norint peršokti į poziciją reikia pradėti epizodo atkūrimą
-
- - %d epizodas pažymėtas kaip perklausytas.
- - %d epizodai pažymėti kaip perklausyti.
- - %d epizodai pažymėti kaip perklausyti.
- - %d epizodai pažymėti kaip perklausyti.
-
- Pažymėti kaip neperklausytą
- Pažymėti kaip neperskaitytą
-
- - %d epizodas pažymėtas kaip neperklausytas.
- - %d epizodai pažymėti kaip neperklausyti.
- - %d epizodai pažymėti kaip neperklausyti.
- - %d epizodai pažymėti kaip neperklausyti.
-
+
- %d epizodas pridėtas į eilę.
- %d epizodai pridėti į eilę.
diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml
index cd4119fc..01f45fca 100644
--- a/app/src/main/res/values-nb/strings.xml
+++ b/app/src/main/res/values-nb/strings.xml
@@ -183,23 +183,14 @@
- %d nedlasted episoder slettet.
- Fjernet fra innboksen
- Marker som avspilt
- Bytte avspilt status
- Marker som avspilt
- Marker som ikke avspilt
+
+
+
+
+
Merk som lest
For å hoppe til posisjoner, må du spille episoden
-
- - %d episode merket som avspilt.
- - %d episoder merket som avspilt.
-
- Marker som ikke avspilt
- Merk som ulest
-
- - %d episode merket som ikke avspilt.
- - %d episoder merket som ikke avspilt.
-
+
Legg til i kø
- %d episode lagt til i køen.
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 668746c7..393c257e 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -193,23 +193,14 @@
- %d gedownloade afleveringen verwijderd.
- Verwijderd uit Postvak IN
- Als afgespeeld markeren
- Afspeelstatus wijzigen
- Gemarkeerd als afgespeeld
- Gemarkeerd als niet-afgespeeld
+
+
+
+
+
Markeren als gelezen
Speel de aflevering af om naar posities te springen
-
- - %d aflevering gemarkeerd als afgespeeld.
- - %d afleveringen gemarkeerd als afgespeeld.
-
- Als niet-afgespeeld markeren
- Markeren als ongelezen
-
- - %d aflevering gemarkeerd als niet-afgespeeld.
- - %d afleveringen gemarkeerd als niet-afgespeeld.
-
+
Toevoegen aan wachtrij
- %d aflevering toegevoegd aan de wachtrij.
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 2cf70c2f..32015d22 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -204,27 +204,14 @@
- Usunięto %d pobranych odcinków.
- Usunięto ze skrzynki odbiorczej
- Oznacz jako odtworzone
- Pokaż status odtworzenia
- Oznaczone jako odtworzone
- Oznaczone jako nieodtworzone
+
+
+
+
+
Oznacz jako przeczytane
Aby skoczyć do konkretnej pozycji, musisz odtworzyć odcinek
-
- - Oznaczono %d odcinek jako odtworzony.
- - Oznaczono %d odcinki(ów) jako odtworzone.
- - Oznaczono %d odcinki(ów) jako odtworzone.
- - Oznaczono %d odcinki(ów) jako odtworzone.
-
- Oznacz jako nieodtworzone
- Oznacz jako nieprzeczytane
-
- - Oznaczono %d odcinek jako nieodtworzony.
- - Oznaczono %d odcinki(ów) jako nieodtworzone.
- - Oznaczono %d odcinki(ów) jako nieodtworzone.
- - Oznaczono %d odcinki(ów) jako nieodtworzone.
-
+
Dodaj do kolejki
- %d odcinek dodano do kolejki.
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 665fe18e..780cabad 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -199,25 +199,14 @@
- %d episódios baixados deletados.
- Removido da caixa de entrada
- Marcar como reproduzido
- Alterar estado de reprodução
- Marcado como reproduzido
- Marcado como não reproduzido
+
+
+
+
+
Marcar como lido
Para pular para as posições, você precisa reproduzir o episódio
-
- - %d episódio marcado como reproduzido.
- - %d episódios marcados como reproduzidos.
- - %d episódios marcados como reproduzidos.
-
- Marcar como não reproduzido
- Marcar como não reproduzido
-
- - %d episódio marcado como não reproduzido.
- - %d episódios marcados como não reproduzidos.
- - %d episódios marcados como não reproduzidos.
-
+
Adicionar à fila
- %d episódio adicionado à fila.
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index cfd024d1..26310d62 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -211,25 +211,14 @@
- %d episódios eliminados
- Removido da caixa de entrada
- Marcar como reproduzido
- Alternar estado de reprodução
- Marcado como reproduzido
- Marcado como não reproduzido
+
+
+
+
+
Marcar como lido
Se quiser ir para uma posição, tem que reproduzir o episódio
-
- - %d episódio marcado como reproduzido
- - %d episódios marcados como reproduzidos
- - %d episódios marcados como reproduzidos
-
- Marcar como não reproduzido
- Marcar como não lido
-
- - %d episódio marcado como não reproduzido
- - %d episódios marcados como não reproduzidos
- - %d episódios marcados como não reproduzidos
-
+
Adicionar à fila
- %d episódio adicionado à fila
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index 68c278cf..a82f18ee 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -208,25 +208,14 @@
- %d de episoade descărcare au fost șterse.
- Eliminat din inbox
- Marchează ca redat
- Comută starea de redare
- Marcat ca redat
- Marcat ca neredat
+
+
+
+
+
Marcați ca citit
Pentru a sări către o poziție, trebuie sa începeți redarea episodului
-
- - Un episod marcat ca redat.
- - %d episoade marcate ca redate.
- - %d de episoade marcate ca redate.
-
- Marchează ca neredat
- Marchează ca necitit.
-
- - Un episod marcat ca neredat.
- - %d episoade marcate ca neredate.
- - %d de episoade marcate ca neredate.
-
+
Adaugă la coadă
- Un episod adăugat la coadă.
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 2cd53cd3..f31fc2b9 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -205,27 +205,14 @@
- %d загруженных выпусков удалёно.
- Убрано из входящих
- Отметить как прослушанное
- Переключить состояние \"прослушано\"
- Отмечено как прослушанное
- Отметить как непрослушанное
+
+
+
+
+
Отметить как прочитанное
Для переходов в выпуске нужно слушать выпуск
-
- - %d выпуск отмечен как прослушанный.
- - %d выпуска отмечены как прослушанные.
- - %d выпусков отмечены как прослушанные.
- - %d выпусков отмечено как прослушанные.
-
- Отметить как непрослушанное
- Отметить как непрочитанное
-
- - %d выпуск отмечен непрослушанный.
- - %d выпуска отмечены непрослушанные.
- - %d выпусков отмечены непрослушанные.
- - %d выпусков отмечено непрослушанные.
-
+
Добавить в очередь
- %d выпуск добавлен в очередь.
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index d818df71..d65494b9 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -217,27 +217,14 @@
- %dstiahnutých epizód zmazaných.
- Odstránené zo schránky
- Označiť ako prehrané
- Prepnúť stav prehratia
- Označené ako prehrané
- Označené ako neprehrané
+
+
+
+
+
Označiť ako prečítané
Preskočenie na určitú pozíciu funguje len pri prehrávaní epizódy.
-
- - %d epizóda bola označená ako prehraná.
- - %d epizódy boli označené ako prehrané.
- - %d epizód bolo označených ako prehrané.
- - %d epizód bolo označených ako prehrané.
-
- Označiť ako neprehrané
- Označiť ako prehrané
-
- - %d epizóda bola označená ako neprehraná.
- - %d epizódy bolo označené ako neprehrané.
- - %d epizód bolo označených ako neprehrané.
- - %d epizód bolo označených ako neprehrané.
-
+
Pridať do poradia
- %d epizóda bola pridaná do poradia
diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml
index 0a1c6339..dfe6c18b 100644
--- a/app/src/main/res/values-sl/strings.xml
+++ b/app/src/main/res/values-sl/strings.xml
@@ -142,25 +142,12 @@
Tok
Briši
Ni bilo mogoče brisati datoteke. Ponovni zagon naprave bi lahko pomagal.
- Označi kot predvajan
- Označi kot predvajano.
- Označi kot ne predvajano.
+
+
+
Označi kot prebrano
Če želite skočiti na to mesto, morate predvajati epizodo
-
- - %d označi kot predvajano.
- - %d označi kot predvajani.
- - %d označi kot predvajano.
- - %d označi kot predvajano.
-
- Označi kot ne predvajano.
- Pusti ne prebrano.
-
- - %d epizodo označi kot ne predvajano.
- - %depizodi označi kot ne predvajani.
- - %d epizode označi kot ne predvajane.
- - %d epizode označi kot ne predvajane.
-
+
- %d epizoda je dodana v čakalno vrsto.
- %d epizodi sta dodani v čakalno vrsto.
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index fe186e31..8d20ad5a 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -199,23 +199,14 @@
- %d nedladdade episoder borttagna.
- Tog bort från inkorg
- Markera som spelad
- Växla spelläge
- Markera som spelad
- Markera som ospelad
+
+
+
+
+
Markera som läst
Spela episoden för att kunna hoppa till olika positioner
-
- - 1%d episod markerad som spelad.
- - %d episoder markerade som spelade.
-
- Markera som ospelad
- Markera som ospelad
-
- - 1%d episod markerad som ospelad.
- - %d episoder markerade som ospelade.
-
+
Lägg till i kön
- 1%d episod tillagd i kön.
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 4eda2a21..131c8984 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -192,23 +192,14 @@
- %d indirilmiş bölüm silindi.
- Gelen kutusundan silindi
- Oynatıldı olarak işaretle
- Oynatma durumunu değiştir
- Çalındı olarak işaretlendi
- Çalınmadı olarak işaretlendi
+
+
+
+
+
Okundu olarak işaretle
Başka bir konuma atlamak için bölümü oynatmanız gerekir.
-
- - %d bölüm oynatıldı olarak işaretlendi.
- - %d bölüm oynatıldı olarak işaretlendi.
-
- Oynatılmadı olarak işaretle
- Okunmadı olarak işaretle
-
- - %d bölüm oynanmamış olarak işaretlendi.
- - %d bölüm oynanmamış olarak işaretlendi.
-
+
Sıraya ekle
- %d bölüm kuyruğa eklendi.
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 92b9b0d0..ee0edc43 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -217,27 +217,14 @@
- %d завантажених епізодів видалено.
- Вилучено з вхідних
- Позначити як відтворений
- Перемикнути стан прослуханості
- Позначено як відтворений
- Позначено як невідтворений
+
+
+
+
+
Позначити як прочитане
Щоб перейти до позиції, потрібно відтворити епізод
-
- - %d епізод помічено як відтворений
- - %d епізоди помічено як відтворені
- - %d епізодів помічено як відтворені
- - %d епізодів помічено як відтворені
-
- Позначити як невідтворений
- Позначити як непрочитане
-
- - %d епізод помічено як невідтворений.
- - %d епізоди помічено як невідтворені.
- - %d епізодів помічено як невідтворені.
- - %d епізодів помічено як невідтворені.
-
+
Додати до черги
- %d епізод додано до черги.
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 0bc3b43f..7c727009 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -194,21 +194,14 @@
- 删除了 %d 个已下载的节目。
- 已从收件箱删除
- 标记已播放
- 切换播放状态
- 标记为已播放
- 标记为未播放
+
+
+
+
+
标记为已读
要跳转到某处,你需要播放这一集
-
- - 已将%d个节目标记为已播放
-
- 标记未播放
- 标为未读
-
- - 已将%d个节目标记为未播放
-
+
加至队列
- 已将%d个节目添加到序列中
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 94d6aae1..3f78856d 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -105,17 +105,10 @@
串流播放
刪除
刪除文件失敗。重啟設備試試看。
- 標記為已播放
+
標示為已讀
若想指定播放位置,請先播放該單集
-
- - 共有 %d 集標示為已播放。
-
- 標記為未播放
- 標示為未讀
-
- - 共有 %d 集標示為未播放。
-
+
- 已將 %d 集加入待播清單。
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a9d19dcc..f53418d5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -270,27 +270,15 @@
My opinion
Cancelled on
- Removed from inbox
- Mark as played
- Toggle played state
- Marked as played
- Marked as unplayed
+ Set played state
+
Mark as read
To jump to positions, you need to play the episode
- %d episode marked as favorite.
- %d episodes marked as favorite.
-
- - %d episode marked as played.
- - %d episodes marked as played.
-
- Mark as unplayed
- Mark as unread
-
- - %d episode marked as unplayed.
- - %d episodes marked as unplayed.
-
+
Shelve to synthetic
Add to active queue
diff --git a/app/src/test/kotlin/ac/mdiq/podcini/feed/FeedItemMother.kt b/app/src/test/kotlin/ac/mdiq/podcini/feed/FeedItemMother.kt
index 10ffe102..7c712ba5 100644
--- a/app/src/test/kotlin/ac/mdiq/podcini/feed/FeedItemMother.kt
+++ b/app/src/test/kotlin/ac/mdiq/podcini/feed/FeedItemMother.kt
@@ -8,7 +8,7 @@ internal object FeedItemMother {
@JvmStatic
fun anyFeedItemWithImage(): Episode {
- val item = Episode(0, "Item", "Item", "url", Date(), Episode.PlayState.PLAYED.code, FeedMother.anyFeed())
+ val item = Episode(0, "Item", "Item", "url", Date(), PlayState.PLAYED.code, FeedMother.anyFeed())
item.imageUrl = (IMAGE_URL)
return item
}
diff --git a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbCleanupTests.kt b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbCleanupTests.kt
index 67296a9d..b6e39254 100644
--- a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbCleanupTests.kt
+++ b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbCleanupTests.kt
@@ -87,7 +87,7 @@ open class DbCleanupTests {
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
val files: MutableList = ArrayList()
- populateItems(numItems, feed, items, files, Episode.PlayState.PLAYED.code, false, false)
+ populateItems(numItems, feed, items, files, PlayState.PLAYED.code, false, false)
performAutoCleanup(context)
for (i in files.indices) {
@@ -104,7 +104,7 @@ open class DbCleanupTests {
for (i in 0 until numItems) {
val itemDate = Date((numItems - i).toLong())
var playbackCompletionDate: Date? = null
- if (itemState == Episode.PlayState.PLAYED.code) {
+ if (itemState == PlayState.PLAYED.code) {
playbackCompletionDate = itemDate
}
val item = Episode(0, "title", "id$i", "link", itemDate, itemState, feed)
@@ -140,7 +140,7 @@ open class DbCleanupTests {
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
val files: MutableList = ArrayList()
- populateItems(numItems, feed, items, files, Episode.PlayState.UNPLAYED.code, false, false)
+ populateItems(numItems, feed, items, files, PlayState.UNPLAYED.code, false, false)
performAutoCleanup(context)
for (file in files) {
@@ -157,7 +157,7 @@ open class DbCleanupTests {
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
val files: MutableList = ArrayList()
- populateItems(numItems, feed, items, files, Episode.PlayState.PLAYED.code, true, false)
+ populateItems(numItems, feed, items, files, PlayState.PLAYED.code, true, false)
performAutoCleanup(context)
for (file in files) {
@@ -198,7 +198,7 @@ open class DbCleanupTests {
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
val files: MutableList = ArrayList()
- populateItems(numItems, feed, items, files, Episode.PlayState.PLAYED.code, false, true)
+ populateItems(numItems, feed, items, files, PlayState.PLAYED.code, false, true)
performAutoCleanup(context)
for (file in files) {
diff --git a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbNullCleanupAlgorithmTest.kt b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbNullCleanupAlgorithmTest.kt
index e90ffdc8..2d18f4d4 100644
--- a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbNullCleanupAlgorithmTest.kt
+++ b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbNullCleanupAlgorithmTest.kt
@@ -81,7 +81,7 @@ class DbNullCleanupAlgorithmTest {
feed.episodes.addAll(items)
val files: MutableList = ArrayList()
for (i in 0 until numItems) {
- val item = Episode(0, "title", "id$i", "link", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "title", "id$i", "link", Date(), PlayState.PLAYED.code, feed)
val f = File(destFolder, "file $i")
Assert.assertTrue(f.createNewFile())
diff --git a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbPlayQueueCleanupAlgorithmTest.kt b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbPlayQueueCleanupAlgorithmTest.kt
index dcdb50aa..ad7eab37 100644
--- a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbPlayQueueCleanupAlgorithmTest.kt
+++ b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbPlayQueueCleanupAlgorithmTest.kt
@@ -33,7 +33,7 @@ class DbPlayQueueCleanupAlgorithmTest : DbCleanupTests() {
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
val files: MutableList = ArrayList()
- populateItems(numItems, feed, items, files, Episode.PlayState.UNPLAYED.code, false, false)
+ populateItems(numItems, feed, items, files, PlayState.UNPLAYED.code, false, false)
performAutoCleanup(context)
for (i in files.indices) {
diff --git a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbTasksTest.kt b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbTasksTest.kt
index 9915895d..784e2f53 100644
--- a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbTasksTest.kt
+++ b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbTasksTest.kt
@@ -61,7 +61,7 @@ class DbTasksTest {
feed.episodes.clear()
for (i in 0 until numItems) {
feed.episodes.add(Episode(0, "item $i", "id $i", "link $i",
- Date(), Episode.PlayState.UNPLAYED.code, feed))
+ Date(), PlayState.UNPLAYED.code, feed))
}
val newFeed = updateFeed(context, feed, false)
@@ -97,7 +97,7 @@ class DbTasksTest {
feed.episodes.clear()
for (i in 0 until numItemsOld) {
feed.episodes.add(Episode(0, "item $i", "id $i", "link $i",
- Date(i.toLong()), Episode.PlayState.PLAYED.code, feed))
+ Date(i.toLong()), PlayState.PLAYED.code, feed))
}
// val adapter = getInstance()
// adapter.open()
@@ -117,7 +117,7 @@ class DbTasksTest {
for (i in numItemsOld until numItemsNew + numItemsOld) {
feed.episodes.add(0, Episode(0, "item $i", "id $i", "link $i",
- Date(i.toLong()), Episode.PlayState.UNPLAYED.code, feed))
+ Date(i.toLong()), PlayState.UNPLAYED.code, feed))
}
val newFeed = updateFeed(context, feed, false)
@@ -134,7 +134,7 @@ class DbTasksTest {
@Test
fun testUpdateFeedMediaUrlResetState() {
val feed = Feed("url", null, "title")
- val item = Episode(0, "item", "id", "link", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "item", "id", "link", Date(), PlayState.PLAYED.code, feed)
feed.episodes.add(item)
// val adapter = getInstance()
@@ -166,7 +166,7 @@ class DbTasksTest {
feed.episodes.clear()
for (i in 0..9) {
feed.episodes.add(
- Episode(0, "item $i", "id $i", "link $i", Date(i.toLong()), Episode.PlayState.PLAYED.code, feed))
+ Episode(0, "item $i", "id $i", "link $i", Date(i.toLong()), PlayState.PLAYED.code, feed))
}
// val adapter = getInstance()
// adapter.open()
@@ -188,7 +188,7 @@ class DbTasksTest {
feed.episodes.clear()
for (i in 0..9) {
val item =
- Episode(0, "item $i", "id $i", "link $i", Date(i.toLong()), Episode.PlayState.PLAYED.code, feed)
+ Episode(0, "item $i", "id $i", "link $i", Date(i.toLong()), PlayState.PLAYED.code, feed)
val media = EpisodeMedia(item, "download url $i", 123, "media/mp3")
item.setMedia(media)
feed.episodes.add(item)
@@ -244,7 +244,7 @@ class DbTasksTest {
val items: MutableList = ArrayList(numFeedItems)
for (i in 1..numFeedItems) {
val item = Episode(0, "item $i of $title", "id$title$i", "link",
- Date(), Episode.PlayState.UNPLAYED.code, feed)
+ Date(), PlayState.UNPLAYED.code, feed)
items.add(item)
}
feed.episodes.addAll(items)
diff --git a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbWriterTest.kt b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbWriterTest.kt
index 4a5cd39f..5b59b566 100644
--- a/app/src/test/kotlin/ac/mdiq/podcini/storage/DbWriterTest.kt
+++ b/app/src/test/kotlin/ac/mdiq/podcini/storage/DbWriterTest.kt
@@ -97,7 +97,7 @@ class DbWriterTest {
val feed = Feed("url", null, "title")
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
- val item = Episode(0, "Item", "Item", "url", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "Item", "Item", "url", Date(), PlayState.PLAYED.code, feed)
items.add(item)
val media = EpisodeMedia(0, item, duration, 1, 1, "mime_type",
"dummy path", "download_url", true, null, 0, 0)
@@ -138,7 +138,7 @@ class DbWriterTest {
val feed = Feed("url", null, "title")
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
- val item = Episode(0, "Item", "Item", "url", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "Item", "Item", "url", Date(), PlayState.PLAYED.code, feed)
var media: EpisodeMedia? = EpisodeMedia(0, item, 1, 1, 1, "mime_type",
dest.absolutePath, "download_url", true, null, 0, 0)
@@ -176,7 +176,7 @@ class DbWriterTest {
val feed = Feed("url", null, "title")
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
- val item = Episode(0, "Item", "Item", "url", Date(), Episode.PlayState.UNPLAYED.code, feed)
+ val item = Episode(0, "Item", "Item", "url", Date(), PlayState.UNPLAYED.code, feed)
var media: EpisodeMedia? = EpisodeMedia(0, item, 1, 1, 1, "mime_type",
dest.absolutePath, "download_url", true, null, 0, 0)
@@ -218,7 +218,7 @@ class DbWriterTest {
val itemFiles: MutableList = ArrayList()
// create items with downloaded media files
for (i in 0..9) {
- val item = Episode(0, "Item $i", "Item$i", "url", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "Item $i", "Item$i", "url", Date(), PlayState.PLAYED.code, feed)
feed.episodes.add(item)
val enc = File(destFolder, "file $i")
@@ -308,7 +308,7 @@ class DbWriterTest {
// create items
for (i in 0..9) {
- val item = Episode(0, "Item $i", "Item$i", "url", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "Item $i", "Item$i", "url", Date(), PlayState.PLAYED.code, feed)
feed.episodes.add(item)
}
@@ -352,7 +352,7 @@ class DbWriterTest {
// create items with downloaded media files
for (i in 0..9) {
- val item = Episode(0, "Item $i", "Item$i", "url", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "Item $i", "Item$i", "url", Date(), PlayState.PLAYED.code, feed)
feed.episodes.add(item)
val enc = File(destFolder, "file $i")
val media = EpisodeMedia(0, item, 1, 1, 1, "mime_type",
@@ -415,7 +415,7 @@ class DbWriterTest {
// create items with downloaded media files
for (i in 0..9) {
- val item = Episode(0, "Item $i", "Item$i", "url", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "Item $i", "Item$i", "url", Date(), PlayState.PLAYED.code, feed)
feed.episodes.add(item)
val enc = File(destFolder, "file $i")
val media = EpisodeMedia(0, item, 1, 1, 1, "mime_type",
@@ -463,7 +463,7 @@ class DbWriterTest {
// create items
for (i in 0..9) {
- val item = Episode(0, "Item $i", "Item$i", "url", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "Item $i", "Item$i", "url", Date(), PlayState.PLAYED.code, feed)
item.setMedia(EpisodeMedia(item, "", 0, ""))
feed.episodes.add(item)
}
@@ -494,7 +494,7 @@ class DbWriterTest {
private fun playbackHistorySetup(playbackCompletionDate: Date?): EpisodeMedia {
val feed = Feed("url", null, "title")
feed.episodes.clear()
- val item = Episode(0, "title", "id", "link", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "title", "id", "link", Date(), PlayState.PLAYED.code, feed)
val media = EpisodeMedia(0, item, 10, 0, 1, "mime", null,
"url", false, playbackCompletionDate, 0, 0)
feed.episodes.add(item)
@@ -547,7 +547,7 @@ class DbWriterTest {
val feed = Feed("url", null, "title")
feed.episodes.clear()
for (i in 0 until numItems) {
- val item = Episode(0, "title $i", "id $i", "link $i", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "title $i", "id $i", "link $i", Date(), PlayState.PLAYED.code, feed)
item.setMedia(EpisodeMedia(item, "", 0, ""))
feed.episodes.add(item)
}
@@ -576,7 +576,7 @@ class DbWriterTest {
fun testAddQueueItemSingleItem() {
val feed = Feed("url", null, "title")
feed.episodes.clear()
- val item = Episode(0, "title", "id", "link", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "title", "id", "link", Date(), PlayState.PLAYED.code, feed)
item.setMedia(EpisodeMedia(item, "", 0, ""))
feed.episodes.add(item)
@@ -587,7 +587,7 @@ class DbWriterTest {
Assert.assertTrue(item.id != 0L)
runBlocking {
- val job = addToQueue(true, item)
+ val job = addToQueue(item)
withTimeout(TIMEOUT*1000) { job.join() }
}
@@ -605,7 +605,7 @@ class DbWriterTest {
fun testAddQueueItemSingleItemAlreadyInQueue() {
val feed = Feed("url", null, "title")
feed.episodes.clear()
- val item = Episode(0, "title", "id", "link", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "title", "id", "link", Date(), PlayState.PLAYED.code, feed)
item.setMedia(EpisodeMedia(item, "", 0, ""))
feed.episodes.add(item)
@@ -616,7 +616,7 @@ class DbWriterTest {
Assert.assertTrue(item.id != 0L)
runBlocking {
- val job = addToQueue(true, item)
+ val job = addToQueue(item)
withTimeout(TIMEOUT*1000) { job.join() }
}
@@ -629,7 +629,7 @@ class DbWriterTest {
// adapter.close()
runBlocking {
- val job = addToQueue(true, item)
+ val job = addToQueue(item)
withTimeout(TIMEOUT*1000) { job.join() }
}
// adapter = getInstance()
@@ -766,7 +766,7 @@ class DbWriterTest {
feed.episodes.clear()
for (i in 0 until numItems) {
val item = Episode(0, "title $i", "id $i", "link $i",
- Date(), Episode.PlayState.PLAYED.code, feed)
+ Date(), PlayState.PLAYED.code, feed)
item.setMedia(EpisodeMedia(item, "", 0, ""))
feed.episodes.add(item)
}
@@ -817,7 +817,7 @@ class DbWriterTest {
val feed = Feed("url", null, "title")
feed.episodes.clear()
for (i in 0 until numItems) {
- val item = Episode(0, "title $i", "id $i", "link $i", Date(), Episode.PlayState.NEW.code, feed)
+ val item = Episode(0, "title $i", "id $i", "link $i", Date(), PlayState.NEW.code, feed)
item.setMedia(EpisodeMedia(item, "", 0, ""))
feed.episodes.add(item)
}
@@ -848,7 +848,7 @@ class DbWriterTest {
val feed = Feed("url", null, "title")
feed.episodes.clear()
for (i in 0 until numItems) {
- val item = Episode(0, "title $i", "id $i", "link $i", Date(), Episode.PlayState.PLAYED.code, feed)
+ val item = Episode(0, "title $i", "id $i", "link $i", Date(), PlayState.PLAYED.code, feed)
item.setMedia(EpisodeMedia(item, "", 0, ""))
feed.episodes.add(item)
}
diff --git a/app/src/test/kotlin/ac/mdiq/podcini/storage/EpisodeDuplicateGuesserTest.kt b/app/src/test/kotlin/ac/mdiq/podcini/storage/EpisodeDuplicateGuesserTest.kt
index 287bc5fd..673717a8 100644
--- a/app/src/test/kotlin/ac/mdiq/podcini/storage/EpisodeDuplicateGuesserTest.kt
+++ b/app/src/test/kotlin/ac/mdiq/podcini/storage/EpisodeDuplicateGuesserTest.kt
@@ -57,7 +57,7 @@ class EpisodeDuplicateGuesserTest {
private fun item(guid: String, title: String, downloadUrl: String,
date: Long, duration: Long, mime: String
): Episode {
- val item = Episode(0, title, guid, "link", Date(date), Episode.PlayState.PLAYED.code, null)
+ val item = Episode(0, title, guid, "link", Date(date), PlayState.PLAYED.code, null)
val media = EpisodeMedia(item, downloadUrl, duration, mime)
item.setMedia(media)
return item
diff --git a/app/src/test/kotlin/ac/mdiq/podcini/storage/ExceptFavoriteCleanupAlgorithmTest.kt b/app/src/test/kotlin/ac/mdiq/podcini/storage/ExceptFavoriteCleanupAlgorithmTest.kt
index d91c9837..3db6cdce 100644
--- a/app/src/test/kotlin/ac/mdiq/podcini/storage/ExceptFavoriteCleanupAlgorithmTest.kt
+++ b/app/src/test/kotlin/ac/mdiq/podcini/storage/ExceptFavoriteCleanupAlgorithmTest.kt
@@ -29,7 +29,7 @@ class ExceptFavoriteCleanupAlgorithmTest : DbCleanupTests() {
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
val files: MutableList = ArrayList()
- populateItems(numberOfItems, feed, items, files, Episode.PlayState.UNPLAYED.code, false, false)
+ populateItems(numberOfItems, feed, items, files, PlayState.UNPLAYED.code, false, false)
performAutoCleanup(context)
for (i in files.indices) {
@@ -48,7 +48,7 @@ class ExceptFavoriteCleanupAlgorithmTest : DbCleanupTests() {
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
val files: MutableList = ArrayList()
- populateItems(numberOfItems, feed, items, files, Episode.PlayState.UNPLAYED.code, true, false)
+ populateItems(numberOfItems, feed, items, files, PlayState.UNPLAYED.code, true, false)
performAutoCleanup(context)
for (i in files.indices) {
@@ -67,7 +67,7 @@ class ExceptFavoriteCleanupAlgorithmTest : DbCleanupTests() {
val items: MutableList = ArrayList()
feed.episodes.addAll(items)
val files: MutableList = ArrayList()
- populateItems(numberOfItems, feed, items, files, Episode.PlayState.UNPLAYED.code, false, true)
+ populateItems(numberOfItems, feed, items, files, PlayState.UNPLAYED.code, false, true)
performAutoCleanup(context)
for (i in files.indices) {
diff --git a/app/src/test/kotlin/ac/mdiq/podcini/storage/ItemEnqueuePositionCalculatorTest.kt b/app/src/test/kotlin/ac/mdiq/podcini/storage/ItemEnqueuePositionCalculatorTest.kt
index 0d23606b..ee0feb53 100644
--- a/app/src/test/kotlin/ac/mdiq/podcini/storage/ItemEnqueuePositionCalculatorTest.kt
+++ b/app/src/test/kotlin/ac/mdiq/podcini/storage/ItemEnqueuePositionCalculatorTest.kt
@@ -57,7 +57,7 @@ object ItemEnqueuePositionCalculatorTest {
fun createFeedItem(id: Long): Episode {
val item = Episode(id, "Item$id", "ItemId$id", "url",
- Date(), Episode.PlayState.PLAYED.code, anyFeed())
+ Date(), PlayState.PLAYED.code, anyFeed())
val media = EpisodeMedia(item, "http://download.url.net/$id", 1234567, "audio/mpeg")
media.id = item.id
item.setMedia(media)
diff --git a/changelog.md b/changelog.md
index fed7f72a..801b16de 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,18 @@
+# 6.12.0
+
+* created a new play state system: Unspecified, Building, New, Unplayed, Later, Soon, InQueue, InProgress, Skipped, Played, Ignored,
+ * among which Unplayed, Later, Soon, Skipped, Played, Ignored are settable by the user
+ * when an episode is started to play, its state is set to InProgress
+ * when episode is added to a queue, its state is set to InQueue, when it's removed from a queue, the state (if lower than Skipped) is set to Skipped
+ * in Episode filter, for now, Unplayed is all lower than Played, while Played includes Played, Ignore
+* fixed issues from last release: action button not update, icon at PlayUI not update
+* re-worked the header layouts of FeedInfo and FeedEpisodes
+* tuned to show PlayerUI in proper conditions
+* enabled open NavDrawer in LogsFragment
+* in list view of Subscriptions, moved the rating icon to the title
+* NavDrawer is fully in Compose
+* cleaned out some unused or redundant stuff
+
# 6.11.7
* added author and title info in SharedLog
diff --git a/fastlane/metadata/android/en-US/changelogs/3020278.txt b/fastlane/metadata/android/en-US/changelogs/3020278.txt
new file mode 100644
index 00000000..06d6ab73
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/3020278.txt
@@ -0,0 +1,14 @@
+ Version 6.12.0
+
+* created a new play state system: Unspecified, Building, New, Unplayed, Later, Soon, InQueue, InProgress, Skipped, Played, Ignored,
+ * among which Unplayed, Later, Soon, Skipped, Played, Ignored are settable by the user
+ * when an episode is started to play, its state is set to InProgress
+ * when episode is added to a queue, its state is set to InQueue, when it's removed from a queue, the state (if lower than Skipped) is set to Skipped
+ * in Episode filter, for now, Unplayed is all lower than Played, while Played includes Played, Ignore
+* fixed issues from last release: action button not update, icon at PlayUI not update
+* re-worked the header layouts of FeedInfo and FeedEpisodes
+* tuned to show PlayerUI in proper conditions
+* enabled open NavDrawer in LogsFragment
+* in list view of Subscriptions, moved the rating icon to the title
+* NavDrawer is fully in Compose
+* cleaned out some unused or redundant stuff