6.12.0 commit
This commit is contained in:
parent
a9f59905bd
commit
0c801717ac
|
@ -12,7 +12,7 @@ An open source podcast instrument, attuned to Puccini ![Puccini](./images/Puccin
|
|||
[<img src="./images/external/amazon.png" alt="Amazon" height="40">](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.
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<Episode> = 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) {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ object LogsAndStats {
|
|||
feedTotalTime += m.duration
|
||||
if (m.lastPlayedTime in timeFilterFrom..<timeFilterTo) {
|
||||
if (includeMarkedAsPlayed) {
|
||||
if ((m.playbackCompletionTime > 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
|
||||
}
|
||||
|
|
|
@ -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<Long> {
|
||||
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<Episode>()
|
||||
val setInQueue = mutableListOf<Episode>()
|
||||
val events: MutableList<FlowEvent.QueueEvent> = ArrayList()
|
||||
val updatedItems: MutableList<Episode> = 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<FlowEvent.QueueEvent> = ArrayList()
|
||||
val events: MutableList<FlowEvent.QueueEvent> = mutableListOf()
|
||||
val indicesToRemove: MutableList<Int> = 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)
|
||||
|
|
|
@ -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<Long>(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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<String> = 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("")
|
||||
|
|
|
@ -283,7 +283,7 @@ class Feed : RealmObject {
|
|||
}
|
||||
|
||||
fun getVirtualQueueItems(): List<Episode> {
|
||||
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()
|
||||
|
|
|
@ -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<PlayState>().firstOrNull { it.code == code } ?: UNSPECIFIED
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ interface SwipeAction {
|
|||
START_DOWNLOAD,
|
||||
MARK_FAV,
|
||||
TOGGLE_PLAYED,
|
||||
SET_PLAY_STATE,
|
||||
REMOVE_FROM_QUEUE,
|
||||
DELETE,
|
||||
REMOVE_FROM_HISTORY
|
||||
|
|
|
@ -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<SwipeAction> = listOf(
|
||||
NoActionSwipeAction(), ComboSwipeAction(), AddToQueueSwipeAction(),
|
||||
StartDownloadSwipeAction(), SetRatingSwipeAction(),
|
||||
TogglePlaybackStateSwipeAction(), RemoveFromQueueSwipeAction(),
|
||||
SetPlaybackStateSwipeAction(), RemoveFromQueueSwipeAction(),
|
||||
DeleteSwipeAction(), RemoveFromHistorySwipeAction())
|
||||
|
||||
private fun getPrefs(tag: String, defaultActions: String): Actions {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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<Episode>, onDismissRequest: () -> Unit) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PlayStateDialog(selected: List<Episode>, 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<Episode>, onDismissRequest: () -> Unit) {
|
||||
val queues = realm.query(PlayQueue::class).find()
|
||||
|
@ -271,7 +336,7 @@ fun PutToQueueDialog(selected: List<Episode>, 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<EpisodeVM>, 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<EpisodeVM>, 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<EpisodeVM>, 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<EpisodeVM>, 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<EpisodeVM>, 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<EpisodeVM>, 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<EpisodeVM>, 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<EpisodeVM>, 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 },
|
||||
|
|
|
@ -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 ->
|
||||
|
|
|
@ -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()})
|
||||
|
|
|
@ -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<String> = 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()})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Feed?>(null)
|
||||
var rating by mutableStateOf(Rating.UNRATED.code)
|
||||
|
||||
private val episodes = mutableStateListOf<Episode>()
|
||||
private val vms = mutableStateListOf<EpisodeVM>()
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ShareLog>()
|
||||
private val subscriptionLogs = mutableStateListOf<SubscriptionLog>()
|
||||
private val downloadLogs = mutableStateListOf<DownloadResult>()
|
||||
|
||||
// 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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Feed>()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -381,7 +381,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
val dir = 1 - 2*feedOrderDir // get from 0, 1 to 1, -1
|
||||
val comparator: Comparator<Feed> = 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<Long, Long> = 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<Long, Long> = 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<Long, Long> = 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<Long, Long> = 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<Long, Long> = 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()) + " : " +
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M20.13,5.41l-1.41,-1.41l-9.19,9.19l-4.25,-4.24l-1.41,1.41l5.66,5.66z"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M5,18h14v2h-14z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M20,4H4C2.89,4 2.01,4.89 2.01,6L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V6C22,4.89 21.11,4 20,4zM8.5,15H7.3l-2.55,-3.5V15H3.5V9h1.25l2.5,3.5V9H8.5V15zM13.5,10.26H11v1.12h2.5v1.26H11v1.11h2.5V15h-4V9h4V10.26zM20.5,14c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1V9h1.25v4.51h1.13V9.99h1.25v3.51h1.12V9h1.25V14z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M20,12c0,-1.1 0.9,-2 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -1.99,0.9 -1.99,2v4c1.1,0 1.99,0.9 1.99,2s-0.89,2 -2,2v4c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-4c-1.1,0 -2,-0.9 -2,-2zM15.58,16.8L12,14.5l-3.58,2.3 1.08,-4.12 -3.29,-2.69 4.24,-0.25L12,5.8l1.54,3.95 4.24,0.25 -3.29,2.69 1.09,4.11z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M21,12l-4.37,6.16C16.26,18.68 15.65,19 15,19h-3l0,-6H9v-3H3V7c0,-1.1 0.9,-2 2,-2h10c0.65,0 1.26,0.31 1.63,0.84L21,12zM10,15H7v-3H5v3H2v2h3v3h2v-3h3V15z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M10,16.5l6,-4.5 -6,-4.5v9zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M8,5.19L8,5l11,7 -2.55,1.63L8,5.19zM20,19.73l-5.11,-5.11L8,7.73 4.27,4 3,5.27l5,5L8,19l5.33,-3.4 5.4,5.4L20,19.73z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10s10,-4.5 10,-10S17.5,2 12,2zM16.2,16.2L11,13V7h1.5v5.2l4.5,2.7L16.2,16.2z"/>
|
||||
|
||||
</vector>
|
|
@ -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">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:elevation="0dp">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
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" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
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" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/episodes_list_fragment">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/actionBarSize"
|
||||
app:navigationContentDescription="@string/toolbar_back_button_content_description"
|
||||
app:navigationIcon="?homeAsUpIndicator" />
|
||||
|
||||
<!-- <androidx.compose.ui.platform.ComposeView-->
|
||||
<!-- android:id="@+id/infobar"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="wrap_content"/>-->
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/lazyColumn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,26 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/episode_info_fragment"
|
||||
android:orientation="vertical"
|
||||
android:fitsSystemWindows="true"
|
||||
android:orientation="vertical">
|
||||
android:id="@+id/compose_fragment">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
android:layout_height="?android:attr/actionBarSize"
|
||||
app:navigationContentDescription="@string/toolbar_back_button_content_description"
|
||||
app:navigationIcon="?homeAsUpIndicator" />
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/composeView"
|
||||
android:id="@+id/mainView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/actionBarSize"
|
||||
app:navigationContentDescription="@string/toolbar_back_button_content_description"
|
||||
app:navigationIcon="?homeAsUpIndicator" />
|
||||
|
||||
<!-- <androidx.compose.ui.platform.ComposeView-->
|
||||
<!-- android:id="@+id/infobar"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="wrap_content"/>-->
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/lazyColumn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/actionBarSize"
|
||||
app:navigationIcon="?homeAsUpIndicator"
|
||||
app:navigationContentDescription="@string/toolbar_back_button_content_description"/>
|
||||
|
||||
<!-- <androidx.compose.ui.platform.ComposeView-->
|
||||
<!-- android:id="@+id/header"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="wrap_content"/>-->
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/mainView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/feedinfo_fragment"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:minHeight="?android:attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:layout_collapseMode="pin"
|
||||
app:navigationContentDescription="@string/toolbar_back_button_content_description"
|
||||
app:navigationIcon="?homeAsUpIndicator" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/mainUI"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/fragment_search_results">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:elevation="0dp">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:title="@string/discover"
|
||||
app:navigationContentDescription="@string/toolbar_back_button_content_description"
|
||||
app:navigationIcon="?homeAsUpIndicator" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/mainView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:title="@string/logs_label" />
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/lazyColumn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/nav_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/mainView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,33 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:elevation="0dp">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:title="@string/online_feed"
|
||||
app:navigationContentDescription="@string/toolbar_back_button_content_description"
|
||||
app:navigationIcon="?homeAsUpIndicator" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/mainView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,36 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/queue_fragment">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/actionBarSize"
|
||||
app:navigationContentDescription="@string/toolbar_back_button_content_description"
|
||||
app:navigationIcon="?homeAsUpIndicator"/>
|
||||
|
||||
<!-- <androidx.compose.ui.platform.ComposeView-->
|
||||
<!-- android:id="@+id/infobar"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="wrap_content"/>-->
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/mainView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -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">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:elevation="0dp">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
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" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
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" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/feed_title_chip"
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- the order is opposite of the typical menu:
|
||||
catered to FAB speed dial, which somehow shows the item in reverse.
|
||||
E.g., item @id/delete_batch is the first in the xml,
|
||||
visually it will be shown at the bottom of the list of actions.
|
||||
-->
|
||||
<item
|
||||
android:id="@+id/delete_batch"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:title="@string/delete_episode_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/download_batch"
|
||||
android:icon="@drawable/ic_download"
|
||||
android:title="@string/download_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/toggle_played_batch"
|
||||
android:icon="@drawable/ic_mark_played"
|
||||
android:title="@string/toggle_played_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/remove_from_queue_batch"
|
||||
android:icon="@drawable/ic_playlist_remove"
|
||||
android:title="@string/remove_from_queue_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/add_to_queue_batch"
|
||||
android:icon="@drawable/ic_playlist_play"
|
||||
android:title="@string/add_to_queue_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/put_in_queue_batch"
|
||||
android:icon="@drawable/ic_playlist_play"
|
||||
android:title="@string/put_in_queue_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/toggle_favorite_batch"
|
||||
android:icon="@drawable/ic_star"
|
||||
android:title="@string/toggle_favorite_label" />
|
||||
|
||||
</menu>
|
|
@ -8,12 +8,12 @@
|
|||
android:icon="@drawable/playlist_play"
|
||||
custom:showAsAction="always"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/sort_items"
|
||||
android:icon="@drawable/arrows_sort"
|
||||
android:title="@string/sort"
|
||||
custom:showAsAction="always">
|
||||
</item>
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/sort_items"-->
|
||||
<!-- android:icon="@drawable/arrows_sort"-->
|
||||
<!-- android:title="@string/sort"-->
|
||||
<!-- custom:showAsAction="always">-->
|
||||
<!-- </item>-->
|
||||
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/filter_items"-->
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@id/skip_episode_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/skip_episode_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/mark_read_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/mark_read_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/mark_unread_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/mark_unread_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/add_to_queue_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/add_to_queue_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/remove_from_queue_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/remove_from_queue_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/remove_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/delete_label" />
|
||||
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/add_to_favorites_item"-->
|
||||
<!-- android:menuCategory="container"-->
|
||||
<!-- android:title="@string/add_to_favorite_label" />-->
|
||||
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/remove_from_favorites_item"-->
|
||||
<!-- android:menuCategory="container"-->
|
||||
<!-- android:title="@string/remove_from_favorite_label" />-->
|
||||
|
||||
<item
|
||||
android:id="@+id/reset_position"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/reset_position" />
|
||||
|
||||
<item
|
||||
android:id="@+id/share_item"
|
||||
android:icon="@drawable/ic_share"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/share_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/multi_select"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/multi_select"
|
||||
android:visible="false" />
|
||||
</menu>
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/select_all_above"
|
||||
android:title="@string/select_all_above">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/select_all_below"
|
||||
android:title="@string/select_all_below">
|
||||
</item>
|
||||
</menu>
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/select_all_above"
|
||||
android:title="@string/select_all_above"
|
||||
android:icon="@drawable/baseline_arrow_upward_24"
|
||||
app:showAsAction="always"/>
|
||||
<item
|
||||
android:id="@+id/select_all_below"
|
||||
android:title="@string/select_all_below"
|
||||
android:icon="@drawable/baseline_arrow_downward_24"
|
||||
app:showAsAction="always"/>
|
||||
<item
|
||||
android:id="@+id/select_toggle"
|
||||
android:title="@string/select_all_label"
|
||||
app:showAsAction="always"/>
|
||||
</menu>
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/move_to_top_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/move_to_top_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/move_to_bottom_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/move_to_bottom_label" />
|
||||
<!-- rest of the menu items can be found in the generic feeditemlist_context.xml -->
|
||||
|
||||
</menu>
|
|
@ -228,31 +228,14 @@
|
|||
<item quantity="other">تم مسح %d حلقات منزلة.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">تم الإزالة من صندوق الوارد</string>
|
||||
<string name="mark_read_label">علمها كمشغلة</string>
|
||||
<string name="toggle_played_label">فعل حالة التشغيل</string>
|
||||
<string name="marked_as_played_label">تم الاستماع</string>
|
||||
<string name="marked_as_unplayed_label">لم يتم الاستماع بعد</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">علمها كمقروءة</string>
|
||||
<string name="play_this_to_seek_position">للإنتقال للتوقيتات, يجب أن تشغل الحلقة</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="zero">%d حلقة علمت كـ مقروءة.</item>
|
||||
<item quantity="one">%d حلقة علمت كـ مقروءة.</item>
|
||||
<item quantity="two">%d حلقتان علمتا كـ مقروءة.</item>
|
||||
<item quantity="few">%d حلقات علمت كـ مقروءة.</item>
|
||||
<item quantity="many">%d حلقات علمت كـ مقروءة. </item>
|
||||
<item quantity="other">%d حلقات علمت كمقروءة.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">علمها كغير مشغلة</string>
|
||||
<string name="mark_unread_label_no_media">علمها كغير مقروءة</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="zero">%d حلقة علمت بأنه لم يتم تشغيلها.</item>
|
||||
<item quantity="one">%d حلقة علمت بأنه لم يتم تشغيلها.</item>
|
||||
<item quantity="two"> %d حلقتان علمتا بأنه لم يتم تشغيلها.</item>
|
||||
<item quantity="few">%d حلقات علمت بأنه لم يتم تشغيلها.</item>
|
||||
<item quantity="many">%d حلقة علمت بأنه لم يتم تشغيلها.</item>
|
||||
<item quantity="other">%d حلقات علمت بأنه لم يتم تشغيلها.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">اضف للائحة الاستماع</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="zero">%d حلقة أضيفت إلى لائحة الاستماع.</item>
|
||||
|
|
|
@ -104,9 +104,9 @@
|
|||
<string name="stream_label">Sentir</string>
|
||||
<string name="delete_label">Desaniciar</string>
|
||||
<string name="delete_failed">Nun ye posible desaniciar el ficheru. Reaniciar el preséu podría ayudar.</string>
|
||||
<string name="mark_read_label">Marcar como «Reprodúxose»</string>
|
||||
<string name="mark_unread_label">Marcar como «Ensin reproducir»</string>
|
||||
<string name="mark_unread_label_no_media">Marcar como «Ensin lleer»</string>
|
||||
|
||||
|
||||
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">Amestóse %d episodiu a la cola.</item>
|
||||
<item quantity="other">Amestáronse %d episodios a la cola.</item>
|
||||
|
|
|
@ -193,29 +193,15 @@
|
|||
<item quantity="other">Dilamet ez eus bet %d rann pellgarget.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Tennet eo bet eus ar voest degemer</string>
|
||||
<string name="mark_read_label">Merkañ evel lennet</string>
|
||||
<string name="toggle_played_label">Lakaat da gemm stad al lenn</string>
|
||||
<string name="marked_as_played_label">Lakaet war-well evel lennet</string>
|
||||
<string name="marked_as_unplayed_label">Lakaet war-well evel lakaet da baouez</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Merkañ evel lennet</string>
|
||||
<string name="play_this_to_seek_position">Evit kemmañ al lec\'hiadur e rankit lenn ar rann</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d rann merket evel lennet</item>
|
||||
<item quantity="two">%d rann merket evel lennet</item>
|
||||
<item quantity="few">%d rann merket evel lennet</item>
|
||||
<item quantity="many">%d rann merket evel lennet</item>
|
||||
<item quantity="other">%d rann merket evel lennet</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Merkañ evel anlennet</string>
|
||||
<string name="mark_unread_label_no_media">Merkañ evel anlennet</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d rann merket evel anlennet. </item>
|
||||
<item quantity="two">%d rann merket evel anlennet. </item>
|
||||
<item quantity="few">%d rann merket evel anlennet. </item>
|
||||
<item quantity="many">%d rann merket evel anlennet.</item>
|
||||
<item quantity="other">%d rann merket evel anlennet. </item>
|
||||
</plurals>
|
||||
|
||||
|
||||
<string name="add_to_queue_label">Ouzhpennañ el lost</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d rann ouzhpennet el lost</item>
|
||||
|
|
|
@ -188,23 +188,14 @@
|
|||
<item quantity="other">%d episodis baixats, suprimits.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Eliminat de la Safata d\'entrada</string>
|
||||
<string name="mark_read_label">Marca com a reproduït</string>
|
||||
<string name="toggle_played_label">Commuta l\'estat de reproducció</string>
|
||||
<string name="marked_as_played_label">Marca com a reproduït</string>
|
||||
<string name="marked_as_unplayed_label">Marca com a no reproduït</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Marcar com a llegit</string>
|
||||
<string name="play_this_to_seek_position">Per a botar a posicions deus reproduir l\'episodi.</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d episodi marcat com a reproduït.</item>
|
||||
<item quantity="other">%d episodis marcats com a reproduïts. </item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Marca com a pendent</string>
|
||||
<string name="mark_unread_label_no_media">Marcar com a no llegit</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d episodi marcat com a no llegit.</item>
|
||||
<item quantity="other">%d episodis marcats com a no llegits.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Afegeix a la cua</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d episodi afegit a la cua.</item>
|
||||
|
|
|
@ -217,27 +217,15 @@
|
|||
<item quantity="other">%d stažených epizod smazáno.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Odebráno z nových</string>
|
||||
<string name="mark_read_label">Označit jako poslechnuté</string>
|
||||
<string name="toggle_played_label">Přepnutí stavu přehrávání</string>
|
||||
<string name="marked_as_played_label">Označeno jako poslechnuté</string>
|
||||
<string name="marked_as_unplayed_label">Označeno jako neposlechnuté</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Označit jako poslechnuté</string>
|
||||
<string name="play_this_to_seek_position">Pro přeskočení na pozice musíte epizodu přehrát</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d epizoda označena jako přehraná</item>
|
||||
<item quantity="few">%d epizody označeny jako přehrané</item>
|
||||
<item quantity="many">%d epizod označeno jako přehrané</item>
|
||||
<item quantity="other">%d epizod označeno jako přehrané</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Označit jako neposlechnuté</string>
|
||||
<string name="mark_unread_label_no_media">Označit jako nepřečtené</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d epizoda označena jako neposlechnutá</item>
|
||||
<item quantity="few">%d epizody označeny jako neposlechnuté</item>
|
||||
<item quantity="many">%d epizod označeno jako neposlechnuté</item>
|
||||
<item quantity="other">%d epizod označeno jako neposlechnuté</item>
|
||||
</plurals>
|
||||
|
||||
|
||||
<string name="add_to_queue_label">Přidat do fronty</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d epizoda přidána do fronty</item>
|
||||
|
|
|
@ -199,23 +199,14 @@
|
|||
<item quantity="other">%d overførte afsnit slettet.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Fjernet fra indbakken</string>
|
||||
<string name="mark_read_label">Markér som afspillet</string>
|
||||
<string name="toggle_played_label">Skift afspilningstilstand</string>
|
||||
<string name="marked_as_played_label">Markér som afspillet</string>
|
||||
<string name="marked_as_unplayed_label">Markér som uafspillet</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Marker som læst</string>
|
||||
<string name="play_this_to_seek_position">For at springe til positioner, er du nødt til at afspille afsnittet</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d afsnit markeret som afspillet.</item>
|
||||
<item quantity="other">%d afsnit markeret som afspillet.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Markér som uafspillet</string>
|
||||
<string name="mark_unread_label_no_media">Marker som ulæst</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d afsnit markeret som uafspillet.</item>
|
||||
<item quantity="other">%d afsnit markeret som uafspillede.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Føj til kø</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d afsnit føjet til køen.</item>
|
||||
|
|
|
@ -203,23 +203,14 @@
|
|||
<item quantity="other">%d heruntergeladene Episoden gelöscht.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Aus dem Posteingang entfernt</string>
|
||||
<string name="mark_read_label">Als gespielt markieren</string>
|
||||
<string name="toggle_played_label">Abgespielt-Zustand umschalten</string>
|
||||
<string name="marked_as_played_label">Als gespielt markieren</string>
|
||||
<string name="marked_as_unplayed_label">Als ungespielt markieren</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Als gelesen markieren</string>
|
||||
<string name="play_this_to_seek_position">Um auf eine Position zu springen, musst du die Episode abspielen</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d Episode als gespielt markiert.</item>
|
||||
<item quantity="other">%d Episoden als gespielt markiert.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Als ungespielt markieren</string>
|
||||
<string name="mark_unread_label_no_media">Als ungelesen markieren</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d Episode als ungespielt markiert.</item>
|
||||
<item quantity="other">%d Episoden als ungespielt markiert.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Zur Warteschlange hinzufügen</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d Episode zur Warteschlange hinzugefügt.</item>
|
||||
|
|
|
@ -211,25 +211,14 @@
|
|||
<item quantity="other">Eliminados %d episodios descargados.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Borrado de la bandeja de entrada</string>
|
||||
<string name="mark_read_label">Marcar como reproducido</string>
|
||||
<string name="toggle_played_label">Cambiar estado de reproducción</string>
|
||||
<string name="marked_as_played_label">Marcar como reproducido</string>
|
||||
<string name="marked_as_unplayed_label">Marcar como no reproducido</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Marcar como leído</string>
|
||||
<string name="play_this_to_seek_position">Para saltar a posiciones, necesitas reproducir el episodio</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%depisodio marcado como reproducido.</item>
|
||||
<item quantity="many">%depisodios marcados como reproducidos.</item>
|
||||
<item quantity="other">%depisodios marcados como reproducidos.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Marcar como no reproducido</string>
|
||||
<string name="mark_unread_label_no_media">Marcar como no leído</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d episodio marcado como no reproducido.</item>
|
||||
<item quantity="many">%d episodios marcados como no reproducidos.</item>
|
||||
<item quantity="other">%d episodios marcados como no reproducidos.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Añadir a la cola</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d episodio añadido a la cola.</item>
|
||||
|
|
|
@ -160,21 +160,11 @@
|
|||
<item quantity="one">1 allalaaditud saade kustutatud.</item>
|
||||
<item quantity="other">%d allalaaditud saadet kustutatud.</item>
|
||||
</plurals>
|
||||
<string name="mark_read_label">Märgi kuulatuks</string>
|
||||
<string name="marked_as_played_label">Märgitud kuulatuks</string>
|
||||
<string name="marked_as_unplayed_label">Märgitud kui kuulamata</string>
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Märgi loetuks</string>
|
||||
<string name="play_this_to_seek_position">Asukohale hüppamiseks pead saadet esitama</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d saade märgiti kuulatuks.</item>
|
||||
<item quantity="other">%d saadet märgiti kuulatuks.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Märgitud kui kuulamata</string>
|
||||
<string name="mark_unread_label_no_media">Märgi mitteloetuks</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d saade märgiti kui kuulamata.</item>
|
||||
<item quantity="other">%d saadet märgiti kui kuulamata.</item>
|
||||
</plurals>
|
||||
<string name="add_to_queue_label">Lisa järjekorda</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d saade lisati järjekorda.</item>
|
||||
|
|
|
@ -187,23 +187,14 @@
|
|||
<item quantity="other">%d deskargatutako kapituluak ezabatu egin dira</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Sarrerako ontzitik kenduta</string>
|
||||
<string name="mark_read_label">Markatu entzundakotzat</string>
|
||||
<string name="toggle_played_label">Erreprodukzio-egoera txandakatu</string>
|
||||
<string name="marked_as_played_label">Entzundakotzat markatua</string>
|
||||
<string name="marked_as_unplayed_label">Ez entzundakotzat markatua</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Markatu iraurrita gisa</string>
|
||||
<string name="play_this_to_seek_position">Posizioetara jauzi egiteko, pasartea erreproduzitu behar duzu</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d saio markatuta ikusita bezala.</item>
|
||||
<item quantity="other">%d saio markatuta ikusita bezala.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Markatu ez entzundakotzat bezala</string>
|
||||
<string name="mark_unread_label_no_media">Markatu ez irakurrita bezala</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d saio markatuta ikusita bezala.</item>
|
||||
<item quantity="other">%d saio markatuta ez ikusita bezala.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Gehitu ilaran</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d saio ilaran gehitua.</item>
|
||||
|
|
|
@ -194,23 +194,14 @@
|
|||
<item quantity="other">%dقسمت بار گرفته حذف شد.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">حذف شده از صندوق ورودی</string>
|
||||
<string name="mark_read_label">علامتگذاری بهعنوان پخششده</string>
|
||||
<string name="toggle_played_label">وضعیت پخش را تغییر دهید</string>
|
||||
<string name="marked_as_played_label">علامتگذاری شد بهعنوان پخششده</string>
|
||||
<string name="marked_as_unplayed_label">علامتگذاری شد بهعنوان پخشنشده</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">علامت زدن به عنوان خوانده شده</string>
|
||||
<string name="play_this_to_seek_position">برای پرش به موقعیتها، میتوانید قسمت را پخش کنید</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d قسمت بهعنوان پخششده علامتگذاری شد.</item>
|
||||
<item quantity="other">%d قسمت بهعنوان پخششده علامتگذاری شد.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">علامتگذاری بهعنوان پخشنشده</string>
|
||||
<string name="mark_unread_label_no_media">علامتگذاری بهعنوان نخواندهشده</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d قسمت بهعنوان پخشنشده علامتگذاری شد.</item>
|
||||
<item quantity="other">%d قسمت بهعنوان پخشنشده علامتگذاری شد.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">افزودن به صف</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d قسمت به صف اضافه شد.</item>
|
||||
|
|
|
@ -187,23 +187,14 @@
|
|||
<item quantity="other">%d ladattua jaksoa poistettu.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Poistettu saapuneista</string>
|
||||
<string name="mark_read_label">Merkitse toistetuksi</string>
|
||||
<string name="toggle_played_label">Vaihda toistettu-tila</string>
|
||||
<string name="marked_as_played_label">Merkattu toistetuksi</string>
|
||||
<string name="marked_as_unplayed_label">Merkattu toistamattomaksi</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Merkitse luetuksi</string>
|
||||
<string name="play_this_to_seek_position">Jaksoa pitää toistaa siirtyäksesi kohtiin</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d jakso merkitty soitetuksi.</item>
|
||||
<item quantity="other">%d jaksoa merkitty toistetuksi</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Merkitse toistamattomaksi</string>
|
||||
<string name="mark_unread_label_no_media">Merkitse lukemattomaksi</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d jakso merkitty soittamattomaksi.</item>
|
||||
<item quantity="other">%d jaksoa merkitty toistamattomaksi.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Lisää jonoon</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d jakso lisätty jonoon.</item>
|
||||
|
|
|
@ -212,25 +212,14 @@
|
|||
<item quantity="other">%d épisodes téléchargés supprimés.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Supprimé de la boîte de réception</string>
|
||||
<string name="mark_read_label">Marquer comme lu</string>
|
||||
<string name="toggle_played_label">Modifier l\'état de lecture</string>
|
||||
<string name="marked_as_played_label">Marqué comme lu</string>
|
||||
<string name="marked_as_unplayed_label">Marqué comme non lu</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Marquer comme lu</string>
|
||||
<string name="play_this_to_seek_position">Pour changer la position l\'épisode doit être en cours de lecture</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d épisode marqué comme lu.</item>
|
||||
<item quantity="many">%d épisodes marqués comme lus.</item>
|
||||
<item quantity="other">%d épisodes marqués comme lus.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Marquer comme non lu</string>
|
||||
<string name="mark_unread_label_no_media">Marquer comme non lu</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d épisode marqué comme non lu.</item>
|
||||
<item quantity="many">%d épisodes marqués comme non lus.</item>
|
||||
<item quantity="other">%d épisodes marqués comme non lus.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Ajouter à la liste de lecture</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d épisode ajouté à la liste de lecture.</item>
|
||||
|
|
|
@ -199,23 +199,13 @@
|
|||
<item quantity="other">Eliminados %d episodios descargados.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Retirado da lista de novidades</string>
|
||||
<string name="mark_read_label">Marcar como reproducido</string>
|
||||
<string name="toggle_played_label">Cambiar estado de reprodución</string>
|
||||
<string name="marked_as_played_label">Marcado como reproducido</string>
|
||||
<string name="marked_as_unplayed_label">Marcado como non reproducido</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Marcar como lido</string>
|
||||
<string name="play_this_to_seek_position">Para ir á posición, debes reproducir o episodio</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d episodio marcado como reproducido.</item>
|
||||
<item quantity="other">%d episodios marcados como reproducidos.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Marcar como non reproducido</string>
|
||||
<string name="mark_unread_label_no_media">Marcar como non lido</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d episodio marcado como non reproducido.</item>
|
||||
<item quantity="other">%d episodios marcados como non reproducidos.</item>
|
||||
</plurals>
|
||||
<string name="add_to_queue_label">Engadir á cola</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d episodio engadido a cola.</item>
|
||||
|
|
|
@ -175,23 +175,14 @@
|
|||
<item quantity="other">%d letöltött epizód törölve.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Eltávolítva a beérkezők közül</string>
|
||||
<string name="mark_read_label">Megjelölés lejátszottként</string>
|
||||
<string name="toggle_played_label">Lejátszott állapot be/ki</string>
|
||||
<string name="marked_as_played_label">Megjelölve lejátszottként</string>
|
||||
<string name="marked_as_unplayed_label">Megjelölve nem lejátszottként</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Megjelölés olvasottként</string>
|
||||
<string name="play_this_to_seek_position">A pozíciókra ugráshoz le kell játszania az epizódot</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d epizód megjelölve lejátszottként.</item>
|
||||
<item quantity="other">%d epizód megjelölve lejátszottként.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Megjelölés nem lejátszottként</string>
|
||||
<string name="mark_unread_label_no_media">Megjelölés olvasatlanként</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d epizód megjelölve nem lejátszottként.</item>
|
||||
<item quantity="other">%d epizód megjelölve nem lejátszottként.</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d epizód sorbaállítva.</item>
|
||||
<item quantity="other">%d epizód sorbaállítva.</item>
|
||||
|
|
|
@ -155,21 +155,14 @@
|
|||
<item quantity="other">%depisode terunduh dihapus.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Dihapus dari kotak masuk</string>
|
||||
<string name="mark_read_label">Tandai diputar</string>
|
||||
<string name="toggle_played_label">Aktifkan status diputar</string>
|
||||
<string name="marked_as_played_label">Ditandai sebagai \'diputar\'</string>
|
||||
<string name="marked_as_unplayed_label">Ditandai sebagai \'belum diputar\'</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Tandai dibaca</string>
|
||||
<string name="play_this_to_seek_position">Untuk melompat posisi waktu, Anda perlu memutar episode terlebih dahulu</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="other">%d episode ditandai sebagai telah diputar.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Tandai belum diputar</string>
|
||||
<string name="mark_unread_label_no_media">Tandai belum dibaca</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="other">%d episode ditandai sebagai belum diputar</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="other">%d episode ditambahkan ke antrian.</item>
|
||||
</plurals>
|
||||
|
|
|
@ -212,25 +212,14 @@
|
|||
<item quantity="other">%d episodi scaricati eliminati.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Rimosso dall\'inbox</string>
|
||||
<string name="mark_read_label">Segna come riprodotto</string>
|
||||
<string name="toggle_played_label">Cambia stato di riproduzione</string>
|
||||
<string name="marked_as_played_label">Segnato come riprodotto</string>
|
||||
<string name="marked_as_unplayed_label">Segnato come non riprodotto</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Segna come letto</string>
|
||||
<string name="play_this_to_seek_position">Per saltare alla posizione devi riprodurre l\'episodio</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d episodio segnato come riprodotto.</item>
|
||||
<item quantity="many">%d di episodi segnati come riprodotti.</item>
|
||||
<item quantity="other">%d episodi segnati come riprodotti.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Segna come non riprodotto</string>
|
||||
<string name="mark_unread_label_no_media">Segna come non letto</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d episodio segnato come non riprodotto.</item>
|
||||
<item quantity="many">%d di episodi segnati come non riprodotti.</item>
|
||||
<item quantity="other">%d episodi segnati come non riprodotti.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Aggiungi alla coda</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d episodio aggiunto alla coda.</item>
|
||||
|
|
|
@ -217,27 +217,14 @@
|
|||
<item quantity="other">%d פרקים שהורדו נמחקו.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">הוסר מהדואר הנכנס</string>
|
||||
<string name="mark_read_label">סימון כנצפה</string>
|
||||
<string name="toggle_played_label">החלפת מצב נגינה</string>
|
||||
<string name="marked_as_played_label">סומן כהתנגן</string>
|
||||
<string name="marked_as_unplayed_label">סומן שלא התנגן</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">סימון כנקרא</string>
|
||||
<string name="play_this_to_seek_position">כדי לקפוץ למיקומים, עליך לנגן את הפרק</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">פרק אחד סומן שנוגן.</item>
|
||||
<item quantity="two">%d פרקים סומנו שנוגנו.</item>
|
||||
<item quantity="many">%d פרקים סומנו שנוגנו.</item>
|
||||
<item quantity="other">%d פרקים סומנו שנוגנו.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">סימון כלא נוגן</string>
|
||||
<string name="mark_unread_label_no_media">סימון כלא נקרא</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">פרק אחד סומן שטרם נוגן.</item>
|
||||
<item quantity="two">%d פרקים סומנו שטרם נוגנו.</item>
|
||||
<item quantity="many">%d פרקים סומנו שטרם נוגנו.</item>
|
||||
<item quantity="other">%d פרקים סומנו שטרם נוגנו.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">הוספה לתור</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">פרק אחד נוסף לתור.</item>
|
||||
|
|
|
@ -147,21 +147,13 @@
|
|||
<item quantity="other">ダウンロードした %d 項目のエピソードが削除されました。</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">受信トレイから取り除きました</string>
|
||||
<string name="mark_read_label">再生済としてマーク</string>
|
||||
<string name="toggle_played_label">再生状態の切り替え</string>
|
||||
<string name="marked_as_played_label">再生済みとマーク済み</string>
|
||||
<string name="marked_as_unplayed_label">未再生としてマーク</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">既読としてマーク</string>
|
||||
<string name="play_this_to_seek_position">位置にジャンプするには、エピソードを再生する必要があります</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="other">%d エピソードを再生済にしました。</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">未再生としてマーク</string>
|
||||
<string name="mark_unread_label_no_media">未読としてマーク</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="other">%d エピソードを未再生にしました。</item>
|
||||
</plurals>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="other">%d エピソードをキューに追加しました。</item>
|
||||
</plurals>
|
||||
|
|
|
@ -178,21 +178,14 @@
|
|||
<item quantity="other">다운로드한 %d개 에피소드 삭제함.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">새로 받음 목록에서 제거함</string>
|
||||
<string name="mark_read_label">재생했다고 표시</string>
|
||||
<string name="toggle_played_label">재생함 상태 토글</string>
|
||||
<string name="marked_as_played_label">재생했다고 표시</string>
|
||||
<string name="marked_as_unplayed_label">재생하지 않음으로 표시</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">읽었다고 표시</string>
|
||||
<string name="play_this_to_seek_position">특정 재생 위치로 이동하려면, 에피소드를 재생해야 합니다</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="other">%d개 에피소드를 재생한 것으로 표시했습니다.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">재생하지 않음으로 표시</string>
|
||||
<string name="mark_unread_label_no_media">읽지 않음으로 표시</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="other">%d개 에피소드를 재생하지 않은 것으로 표시했습니다.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">대기열에 추가</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="other">%d개 에피소드를 대기열에 추가했습니다.</item>
|
||||
|
|
|
@ -151,25 +151,12 @@
|
|||
<item quantity="many">%d atsiųsti epizodai ištrinti.</item>
|
||||
<item quantity="other">%d atsiųsti epizodai ištrinti.</item>
|
||||
</plurals>
|
||||
<string name="mark_read_label">Pažymėti kaip perklausytą</string>
|
||||
<string name="marked_as_played_label">Pažymėtas kaip perklausytas</string>
|
||||
<string name="marked_as_unplayed_label">Pažymėtas kaip neperklausytas</string>
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Pažymėti kaip perskaitytą</string>
|
||||
<string name="play_this_to_seek_position">Norint peršokti į poziciją reikia pradėti epizodo atkūrimą</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d epizodas pažymėtas kaip perklausytas.</item>
|
||||
<item quantity="few">%d epizodai pažymėti kaip perklausyti.</item>
|
||||
<item quantity="many">%d epizodai pažymėti kaip perklausyti.</item>
|
||||
<item quantity="other">%d epizodai pažymėti kaip perklausyti.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Pažymėti kaip neperklausytą</string>
|
||||
<string name="mark_unread_label_no_media">Pažymėti kaip neperskaitytą</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d epizodas pažymėtas kaip neperklausytas.</item>
|
||||
<item quantity="few">%d epizodai pažymėti kaip neperklausyti.</item>
|
||||
<item quantity="many">%d epizodai pažymėti kaip neperklausyti.</item>
|
||||
<item quantity="other">%d epizodai pažymėti kaip neperklausyti.</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d epizodas pridėtas į eilę.</item>
|
||||
<item quantity="few">%d epizodai pridėti į eilę.</item>
|
||||
|
|
|
@ -183,23 +183,14 @@
|
|||
<item quantity="other">%d nedlasted episoder slettet.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Fjernet fra innboksen</string>
|
||||
<string name="mark_read_label">Marker som avspilt</string>
|
||||
<string name="toggle_played_label">Bytte avspilt status</string>
|
||||
<string name="marked_as_played_label">Marker som avspilt</string>
|
||||
<string name="marked_as_unplayed_label">Marker som ikke avspilt</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Merk som lest</string>
|
||||
<string name="play_this_to_seek_position">For å hoppe til posisjoner, må du spille episoden</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d episode merket som avspilt.</item>
|
||||
<item quantity="other">%d episoder merket som avspilt.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Marker som ikke avspilt</string>
|
||||
<string name="mark_unread_label_no_media">Merk som ulest</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d episode merket som ikke avspilt.</item>
|
||||
<item quantity="other">%d episoder merket som ikke avspilt.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Legg til i kø</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d episode lagt til i køen.</item>
|
||||
|
|
|
@ -193,23 +193,14 @@
|
|||
<item quantity="other">%d gedownloade afleveringen verwijderd.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Verwijderd uit Postvak IN</string>
|
||||
<string name="mark_read_label">Als afgespeeld markeren</string>
|
||||
<string name="toggle_played_label">Afspeelstatus wijzigen</string>
|
||||
<string name="marked_as_played_label">Gemarkeerd als afgespeeld</string>
|
||||
<string name="marked_as_unplayed_label">Gemarkeerd als niet-afgespeeld</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Markeren als gelezen</string>
|
||||
<string name="play_this_to_seek_position">Speel de aflevering af om naar posities te springen</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d aflevering gemarkeerd als afgespeeld.</item>
|
||||
<item quantity="other">%d afleveringen gemarkeerd als afgespeeld.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Als niet-afgespeeld markeren</string>
|
||||
<string name="mark_unread_label_no_media">Markeren als ongelezen</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d aflevering gemarkeerd als niet-afgespeeld.</item>
|
||||
<item quantity="other">%d afleveringen gemarkeerd als niet-afgespeeld.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Toevoegen aan wachtrij</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d aflevering toegevoegd aan de wachtrij.</item>
|
||||
|
|
|
@ -204,27 +204,14 @@
|
|||
<item quantity="other">Usunięto %d pobranych odcinków.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Usunięto ze skrzynki odbiorczej</string>
|
||||
<string name="mark_read_label">Oznacz jako odtworzone</string>
|
||||
<string name="toggle_played_label">Pokaż status odtworzenia</string>
|
||||
<string name="marked_as_played_label">Oznaczone jako odtworzone</string>
|
||||
<string name="marked_as_unplayed_label">Oznaczone jako nieodtworzone</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Oznacz jako przeczytane</string>
|
||||
<string name="play_this_to_seek_position">Aby skoczyć do konkretnej pozycji, musisz odtworzyć odcinek</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">Oznaczono %d odcinek jako odtworzony.</item>
|
||||
<item quantity="few">Oznaczono %d odcinki(ów) jako odtworzone.</item>
|
||||
<item quantity="many">Oznaczono %d odcinki(ów) jako odtworzone.</item>
|
||||
<item quantity="other">Oznaczono %d odcinki(ów) jako odtworzone.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Oznacz jako nieodtworzone</string>
|
||||
<string name="mark_unread_label_no_media">Oznacz jako nieprzeczytane</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">Oznaczono %d odcinek jako nieodtworzony.</item>
|
||||
<item quantity="few">Oznaczono %d odcinki(ów) jako nieodtworzone.</item>
|
||||
<item quantity="many">Oznaczono %d odcinki(ów) jako nieodtworzone.</item>
|
||||
<item quantity="other">Oznaczono %d odcinki(ów) jako nieodtworzone.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Dodaj do kolejki</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d odcinek dodano do kolejki.</item>
|
||||
|
|
|
@ -199,25 +199,14 @@
|
|||
<item quantity="other">%d episódios baixados deletados.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Removido da caixa de entrada</string>
|
||||
<string name="mark_read_label">Marcar como reproduzido</string>
|
||||
<string name="toggle_played_label">Alterar estado de reprodução</string>
|
||||
<string name="marked_as_played_label">Marcado como reproduzido</string>
|
||||
<string name="marked_as_unplayed_label">Marcado como não reproduzido</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Marcar como lido</string>
|
||||
<string name="play_this_to_seek_position">Para pular para as posições, você precisa reproduzir o episódio</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d episódio marcado como reproduzido.</item>
|
||||
<item quantity="many">%d episódios marcados como reproduzidos.</item>
|
||||
<item quantity="other">%d episódios marcados como reproduzidos.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Marcar como não reproduzido</string>
|
||||
<string name="mark_unread_label_no_media">Marcar como não reproduzido</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d episódio marcado como não reproduzido.</item>
|
||||
<item quantity="many">%d episódios marcados como não reproduzidos.</item>
|
||||
<item quantity="other">%d episódios marcados como não reproduzidos.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Adicionar à fila</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d episódio adicionado à fila.</item>
|
||||
|
|
|
@ -211,25 +211,14 @@
|
|||
<item quantity="other">%d episódios eliminados</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Removido da caixa de entrada</string>
|
||||
<string name="mark_read_label">Marcar como reproduzido</string>
|
||||
<string name="toggle_played_label">Alternar estado de reprodução</string>
|
||||
<string name="marked_as_played_label">Marcado como reproduzido</string>
|
||||
<string name="marked_as_unplayed_label">Marcado como não reproduzido</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Marcar como lido</string>
|
||||
<string name="play_this_to_seek_position">Se quiser ir para uma posição, tem que reproduzir o episódio</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d episódio marcado como reproduzido</item>
|
||||
<item quantity="many">%d episódios marcados como reproduzidos</item>
|
||||
<item quantity="other">%d episódios marcados como reproduzidos</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Marcar como não reproduzido</string>
|
||||
<string name="mark_unread_label_no_media">Marcar como não lido</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d episódio marcado como não reproduzido</item>
|
||||
<item quantity="many">%d episódios marcados como não reproduzidos</item>
|
||||
<item quantity="other">%d episódios marcados como não reproduzidos</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Adicionar à fila</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d episódio adicionado à fila</item>
|
||||
|
|
|
@ -208,25 +208,14 @@
|
|||
<item quantity="other">%d de episoade descărcare au fost șterse.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Eliminat din inbox</string>
|
||||
<string name="mark_read_label">Marchează ca redat</string>
|
||||
<string name="toggle_played_label">Comută starea de redare</string>
|
||||
<string name="marked_as_played_label">Marcat ca redat</string>
|
||||
<string name="marked_as_unplayed_label">Marcat ca neredat</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Marcați ca citit</string>
|
||||
<string name="play_this_to_seek_position">Pentru a sări către o poziție, trebuie sa începeți redarea episodului</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">Un episod marcat ca redat.</item>
|
||||
<item quantity="few">%d episoade marcate ca redate.</item>
|
||||
<item quantity="other">%d de episoade marcate ca redate.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Marchează ca neredat</string>
|
||||
<string name="mark_unread_label_no_media">Marchează ca necitit.</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">Un episod marcat ca neredat.</item>
|
||||
<item quantity="few">%d episoade marcate ca neredate.</item>
|
||||
<item quantity="other">%d de episoade marcate ca neredate.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Adaugă la coadă</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">Un episod adăugat la coadă.</item>
|
||||
|
|
|
@ -205,27 +205,14 @@
|
|||
<item quantity="other">%d загруженных выпусков удалёно.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Убрано из входящих</string>
|
||||
<string name="mark_read_label">Отметить как прослушанное</string>
|
||||
<string name="toggle_played_label">Переключить состояние \"прослушано\"</string>
|
||||
<string name="marked_as_played_label">Отмечено как прослушанное</string>
|
||||
<string name="marked_as_unplayed_label">Отметить как непрослушанное</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Отметить как прочитанное</string>
|
||||
<string name="play_this_to_seek_position">Для переходов в выпуске нужно слушать выпуск</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d выпуск отмечен как прослушанный.</item>
|
||||
<item quantity="few">%d выпуска отмечены как прослушанные.</item>
|
||||
<item quantity="many">%d выпусков отмечены как прослушанные.</item>
|
||||
<item quantity="other">%d выпусков отмечено как прослушанные.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Отметить как непрослушанное</string>
|
||||
<string name="mark_unread_label_no_media">Отметить как непрочитанное</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d выпуск отмечен непрослушанный.</item>
|
||||
<item quantity="few">%d выпуска отмечены непрослушанные.</item>
|
||||
<item quantity="many">%d выпусков отмечены непрослушанные.</item>
|
||||
<item quantity="other">%d выпусков отмечено непрослушанные.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Добавить в очередь</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d выпуск добавлен в очередь.</item>
|
||||
|
|
|
@ -217,27 +217,14 @@
|
|||
<item quantity="other">%dstiahnutých epizód zmazaných.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Odstránené zo schránky</string>
|
||||
<string name="mark_read_label">Označiť ako prehrané</string>
|
||||
<string name="toggle_played_label">Prepnúť stav prehratia</string>
|
||||
<string name="marked_as_played_label">Označené ako prehrané</string>
|
||||
<string name="marked_as_unplayed_label">Označené ako neprehrané</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Označiť ako prečítané</string>
|
||||
<string name="play_this_to_seek_position">Preskočenie na určitú pozíciu funguje len pri prehrávaní epizódy.</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d epizóda bola označená ako prehraná.</item>
|
||||
<item quantity="few">%d epizódy boli označené ako prehrané.</item>
|
||||
<item quantity="many">%d epizód bolo označených ako prehrané.</item>
|
||||
<item quantity="other">%d epizód bolo označených ako prehrané.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Označiť ako neprehrané</string>
|
||||
<string name="mark_unread_label_no_media">Označiť ako prehrané</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d epizóda bola označená ako neprehraná.</item>
|
||||
<item quantity="few">%d epizódy bolo označené ako neprehrané.</item>
|
||||
<item quantity="many">%d epizód bolo označených ako neprehrané.</item>
|
||||
<item quantity="other">%d epizód bolo označených ako neprehrané.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Pridať do poradia</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d epizóda bola pridaná do poradia</item>
|
||||
|
|
|
@ -142,25 +142,12 @@
|
|||
<string name="stream_label">Tok</string>
|
||||
<string name="delete_label">Briši</string>
|
||||
<string name="delete_failed">Ni bilo mogoče brisati datoteke. Ponovni zagon naprave bi lahko pomagal.</string>
|
||||
<string name="mark_read_label">Označi kot predvajan</string>
|
||||
<string name="marked_as_played_label">Označi kot predvajano.</string>
|
||||
<string name="marked_as_unplayed_label">Označi kot ne predvajano.</string>
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Označi kot prebrano</string>
|
||||
<string name="play_this_to_seek_position">Če želite skočiti na to mesto, morate predvajati epizodo </string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d označi kot predvajano.</item>
|
||||
<item quantity="two">%d označi kot predvajani.</item>
|
||||
<item quantity="few"> %d označi kot predvajano.</item>
|
||||
<item quantity="other">%d označi kot predvajano.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Označi kot ne predvajano.</string>
|
||||
<string name="mark_unread_label_no_media">Pusti ne prebrano.</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d epizodo označi kot ne predvajano.</item>
|
||||
<item quantity="two">%depizodi označi kot ne predvajani.</item>
|
||||
<item quantity="few">%d epizode označi kot ne predvajane.</item>
|
||||
<item quantity="other">%d epizode označi kot ne predvajane.</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d epizoda je dodana v čakalno vrsto.</item>
|
||||
<item quantity="two">%d epizodi sta dodani v čakalno vrsto.</item>
|
||||
|
|
|
@ -199,23 +199,14 @@
|
|||
<item quantity="other">%d nedladdade episoder borttagna.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Tog bort från inkorg</string>
|
||||
<string name="mark_read_label">Markera som spelad</string>
|
||||
<string name="toggle_played_label">Växla spelläge</string>
|
||||
<string name="marked_as_played_label">Markera som spelad</string>
|
||||
<string name="marked_as_unplayed_label">Markera som ospelad</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Markera som läst</string>
|
||||
<string name="play_this_to_seek_position">Spela episoden för att kunna hoppa till olika positioner</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">1%d episod markerad som spelad.</item>
|
||||
<item quantity="other">%d episoder markerade som spelade.</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Markera som ospelad</string>
|
||||
<string name="mark_unread_label_no_media">Markera som ospelad</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">1%d episod markerad som ospelad.</item>
|
||||
<item quantity="other">%d episoder markerade som ospelade.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Lägg till i kön</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">1%d episod tillagd i kön.</item>
|
||||
|
|
|
@ -192,23 +192,14 @@
|
|||
<item quantity="other">%d indirilmiş bölüm silindi.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Gelen kutusundan silindi</string>
|
||||
<string name="mark_read_label">Oynatıldı olarak işaretle</string>
|
||||
<string name="toggle_played_label">Oynatma durumunu değiştir</string>
|
||||
<string name="marked_as_played_label">Çalındı olarak işaretlendi</string>
|
||||
<string name="marked_as_unplayed_label">Çalınmadı olarak işaretlendi</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Okundu olarak işaretle</string>
|
||||
<string name="play_this_to_seek_position">Başka bir konuma atlamak için bölümü oynatmanız gerekir.</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d bölüm oynatıldı olarak işaretlendi.</item>
|
||||
<item quantity="other">%d bölüm oynatıldı olarak işaretlendi. </item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Oynatılmadı olarak işaretle</string>
|
||||
<string name="mark_unread_label_no_media">Okunmadı olarak işaretle</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d bölüm oynanmamış olarak işaretlendi.</item>
|
||||
<item quantity="other">%d bölüm oynanmamış olarak işaretlendi.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Sıraya ekle</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d bölüm kuyruğa eklendi.</item>
|
||||
|
|
|
@ -217,27 +217,14 @@
|
|||
<item quantity="other">%d завантажених епізодів видалено.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">Вилучено з вхідних</string>
|
||||
<string name="mark_read_label">Позначити як відтворений</string>
|
||||
<string name="toggle_played_label">Перемикнути стан прослуханості</string>
|
||||
<string name="marked_as_played_label">Позначено як відтворений</string>
|
||||
<string name="marked_as_unplayed_label">Позначено як невідтворений</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">Позначити як прочитане</string>
|
||||
<string name="play_this_to_seek_position">Щоб перейти до позиції, потрібно відтворити епізод</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="one">%d епізод помічено як відтворений</item>
|
||||
<item quantity="few">%d епізоди помічено як відтворені</item>
|
||||
<item quantity="many">%d епізодів помічено як відтворені</item>
|
||||
<item quantity="other">%d епізодів помічено як відтворені</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">Позначити як невідтворений</string>
|
||||
<string name="mark_unread_label_no_media">Позначити як непрочитане</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="one">%d епізод помічено як невідтворений.</item>
|
||||
<item quantity="few">%d епізоди помічено як невідтворені.</item>
|
||||
<item quantity="many">%d епізодів помічено як невідтворені.</item>
|
||||
<item quantity="other">%d епізодів помічено як невідтворені.</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">Додати до черги</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="one">%d епізод додано до черги.</item>
|
||||
|
|
|
@ -194,21 +194,14 @@
|
|||
<item quantity="other">删除了 %d 个已下载的节目。</item>
|
||||
</plurals>
|
||||
|
||||
<string name="removed_inbox_label">已从收件箱删除</string>
|
||||
<string name="mark_read_label">标记已播放</string>
|
||||
<string name="toggle_played_label">切换播放状态</string>
|
||||
<string name="marked_as_played_label">标记为已播放</string>
|
||||
<string name="marked_as_unplayed_label">标记为未播放</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="mark_read_no_media_label">标记为已读</string>
|
||||
<string name="play_this_to_seek_position">要跳转到某处,你需要播放这一集</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="other">已将%d个节目标记为已播放</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">标记未播放</string>
|
||||
<string name="mark_unread_label_no_media">标为未读</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="other">已将%d个节目标记为未播放</item>
|
||||
</plurals>
|
||||
|
||||
<string name="add_to_queue_label">加至队列</string>
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="other">已将%d个节目添加到序列中</item>
|
||||
|
|
|
@ -105,17 +105,10 @@
|
|||
<string name="stream_label">串流播放</string>
|
||||
<string name="delete_label">刪除</string>
|
||||
<string name="delete_failed">刪除文件失敗。重啟設備試試看。</string>
|
||||
<string name="mark_read_label">標記為已播放</string>
|
||||
|
||||
<string name="mark_read_no_media_label">標示為已讀</string>
|
||||
<string name="play_this_to_seek_position">若想指定播放位置,請先播放該單集</string>
|
||||
<plurals name="marked_read_batch_label">
|
||||
<item quantity="other">共有 %d 集標示為已播放。</item>
|
||||
</plurals>
|
||||
<string name="mark_unread_label">標記為未播放</string>
|
||||
<string name="mark_unread_label_no_media">標示為未讀</string>
|
||||
<plurals name="marked_unread_batch_label">
|
||||
<item quantity="other">共有 %d 集標示為未播放。</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="added_to_queue_batch_label">
|
||||
<item quantity="other">已將 %d 集加入待播清單。</item>
|
||||
</plurals>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue