6.0.4 commit
This commit is contained in:
parent
8d8db46adc
commit
a21e99fa08
|
@ -125,8 +125,8 @@ android {
|
|||
buildConfig true
|
||||
}
|
||||
defaultConfig {
|
||||
versionCode 3020203
|
||||
versionName "6.0.3"
|
||||
versionCode 3020204
|
||||
versionName "6.0.4"
|
||||
|
||||
applicationId "ac.mdiq.podcini.R"
|
||||
def commit = ""
|
||||
|
|
|
@ -720,7 +720,6 @@ object UserPreferences {
|
|||
/**
|
||||
* Returns the sort order for the queue keep sorted mode.
|
||||
* Note: This value is stored independently from the keep sorted state.
|
||||
*
|
||||
* @see .isQueueKeepSorted
|
||||
*/
|
||||
get() {
|
||||
|
@ -729,7 +728,6 @@ object UserPreferences {
|
|||
}
|
||||
/**
|
||||
* Sets the sort order for the queue keep sorted mode.
|
||||
*
|
||||
* @see .setQueueKeepSorted
|
||||
*/
|
||||
set(sortOrder) {
|
||||
|
|
|
@ -45,7 +45,7 @@ class UserInterfacePreferencesFragment : PreferenceFragmentCompat() {
|
|||
findPreference<Preference>(UserPreferences.PREF_SHOW_TIME_LEFT)?.setOnPreferenceChangeListener { _: Preference?, newValue: Any? ->
|
||||
setShowRemainTimeSetting(newValue as Boolean?)
|
||||
// TODO: need another event type?
|
||||
EventFlow.postEvent(FlowEvent.EpisodePlayedEvent())
|
||||
// EventFlow.postEvent(FlowEvent.EpisodePlayedEvent())
|
||||
EventFlow.postEvent(FlowEvent.PlayerSettingsEvent())
|
||||
true
|
||||
}
|
||||
|
|
|
@ -249,19 +249,21 @@ object Episodes {
|
|||
fun addToHistory(episode: Episode, date: Date? = Date()) : Job {
|
||||
Logd(TAG, "addToHistory called")
|
||||
return runOnIOScope {
|
||||
episode.media?.playbackCompletionDate = date
|
||||
upsert(episode) {}
|
||||
upsert(episode) {
|
||||
it.media?.playbackCompletionDate = date
|
||||
}
|
||||
EventFlow.postEvent(FlowEvent.HistoryEvent())
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setFavorite(episode: Episode, stat: Boolean) : Job {
|
||||
Logd(TAG, "setFavorite called")
|
||||
Logd(TAG, "setFavorite called $stat")
|
||||
return runOnIOScope {
|
||||
episode.isFavorite = stat
|
||||
upsert(episode) {}
|
||||
EventFlow.postEvent(FlowEvent.FavoritesEvent(episode))
|
||||
val result = upsert(episode) {
|
||||
it.isFavorite = stat
|
||||
}
|
||||
EventFlow.postEvent(FlowEvent.FavoritesEvent(result))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,11 +278,12 @@ object Episodes {
|
|||
Logd(TAG, "markPlayed called")
|
||||
return runOnIOScope {
|
||||
for (episode in episodes) {
|
||||
episode.playState = played
|
||||
if (resetMediaPosition) episode.media?.setPosition(0)
|
||||
upsert(episode) {}
|
||||
val result = upsert(episode) {
|
||||
it.playState = played
|
||||
if (resetMediaPosition) it.media?.setPosition(0)
|
||||
}
|
||||
if (played == Episode.PLAYED) removeFromAllQueues(episode)
|
||||
EventFlow.postEvent(FlowEvent.EpisodePlayedEvent(episode))
|
||||
EventFlow.postEvent(FlowEvent.EpisodePlayedEvent(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ object Feeds {
|
|||
private val feedMap: MutableMap<Long, Feed> = mutableMapOf()
|
||||
private val tags: MutableList<String> = mutableListOf()
|
||||
|
||||
@Synchronized
|
||||
fun getFeedList(): List<Feed> {
|
||||
return feedMap.values.toList()
|
||||
}
|
||||
|
@ -44,6 +45,7 @@ object Feeds {
|
|||
return tags
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun updateFeedMap(feeds: List<Feed> = listOf(), wipe: Boolean = false) {
|
||||
Logd(TAG, "updateFeedMap called feeds: ${feeds.size} wipe: $wipe")
|
||||
when {
|
||||
|
@ -65,13 +67,17 @@ object Feeds {
|
|||
|
||||
fun buildTags() {
|
||||
val tagsSet = mutableSetOf<String>()
|
||||
val feedsCopy = feedMap.values
|
||||
val feedsCopy = synchronized(feedMap) { feedMap.values.toList() }
|
||||
for (feed in feedsCopy) {
|
||||
if (feed.preferences != null) tagsSet.addAll(feed.preferences!!.tags.filter { it != TAG_ROOT })
|
||||
}
|
||||
tags.clear()
|
||||
tags.addAll(tagsSet)
|
||||
tags.sort()
|
||||
val newTags = tagsSet.intersect(tags.toSet())
|
||||
if (newTags.isNotEmpty()) {
|
||||
tags.clear()
|
||||
tags.addAll(tagsSet)
|
||||
tags.sort()
|
||||
EventFlow.postEvent(FlowEvent.FeedTagsChangedEvent())
|
||||
}
|
||||
}
|
||||
|
||||
fun monitorFeeds() {
|
||||
|
@ -90,8 +96,8 @@ object Feeds {
|
|||
Logd(TAG, "monitorFeeds inserted feed: ${changes.list[i].title}")
|
||||
updateFeedMap(listOf(changes.list[i]))
|
||||
monitorFeed(changes.list[i])
|
||||
EventFlow.postEvent(FlowEvent.FeedListEvent(FlowEvent.FeedListEvent.Action.ADDED, changes.list[i].id))
|
||||
}
|
||||
EventFlow.postEvent(FlowEvent.FeedListEvent(FlowEvent.FeedListEvent.Action.ADDED))
|
||||
}
|
||||
// changes.changes.isNotEmpty() -> {
|
||||
// for (i in changes.changes) {
|
||||
|
@ -456,12 +462,20 @@ object Feeds {
|
|||
// remove from queues
|
||||
removeFromAllQueuesQuiet(eids)
|
||||
// remove media files
|
||||
deleteMediaFilesQuiet(context, feed.episodes)
|
||||
// deleteMediaFilesQuiet(context, feed.episodes)
|
||||
realm.write {
|
||||
val feed_ = query(Feed::class).query("id == $0", feedId).first().find()
|
||||
if (feed_ != null) {
|
||||
val episodes = feed_.episodes.toList()
|
||||
if (episodes.isNotEmpty()) episodes.forEach { e -> delete(e) }
|
||||
if (episodes.isNotEmpty()) episodes.forEach { episode ->
|
||||
val url = episode.media?.fileUrl
|
||||
when {
|
||||
// Local feed
|
||||
url != null && url.startsWith("content://") -> DocumentFile.fromSingleUri(context, Uri.parse(url))?.delete()
|
||||
url != null -> File(url).delete()
|
||||
}
|
||||
delete(episode)
|
||||
}
|
||||
val feedToDelete = findLatest(feed_)
|
||||
if (feedToDelete != null) {
|
||||
delete(feedToDelete)
|
||||
|
@ -475,28 +489,29 @@ object Feeds {
|
|||
}
|
||||
}
|
||||
|
||||
private fun deleteMediaFilesQuiet(context: Context, episodes: List<Episode>) {
|
||||
for (episode in episodes) {
|
||||
val media = episode.media ?: continue
|
||||
val url = media.fileUrl
|
||||
when {
|
||||
url != null && url.startsWith("content://") -> {
|
||||
// Local feed
|
||||
val documentFile = DocumentFile.fromSingleUri(context, Uri.parse(media.fileUrl))
|
||||
documentFile?.delete()
|
||||
episode.media?.fileUrl = null
|
||||
}
|
||||
url != null -> {
|
||||
// delete downloaded media file
|
||||
val mediaFile = File(url)
|
||||
mediaFile.delete()
|
||||
episode.media?.downloaded = false
|
||||
episode.media?.fileUrl = null
|
||||
episode.media?.hasEmbeddedPicture = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// private fun deleteMediaFilesQuiet(context: Context, episodes: List<Episode>) {
|
||||
// for (episode in episodes) {
|
||||
// val media = episode.media ?: continue
|
||||
// val url = media.fileUrl
|
||||
// when {
|
||||
// url != null && url.startsWith("content://") -> {
|
||||
// // Local feed
|
||||
// val documentFile = DocumentFile.fromSingleUri(context, Uri.parse(media.fileUrl))
|
||||
// documentFile?.delete()
|
||||
//// episode.media?.fileUrl = null
|
||||
// }
|
||||
// url != null -> {
|
||||
// // delete downloaded media file
|
||||
// val mediaFile = File(url)
|
||||
// mediaFile.delete()
|
||||
//// since deleting entire feed, these are not necessary
|
||||
//// episode.media?.downloaded = false
|
||||
//// episode.media?.fileUrl = null
|
||||
//// episode.media?.hasEmbeddedPicture = false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@JvmStatic
|
||||
fun shouldAutoDeleteItemsOnFeed(feed: Feed): Boolean {
|
||||
|
|
|
@ -18,7 +18,7 @@ import kotlin.coroutines.ContinuationInterceptor
|
|||
object RealmDB {
|
||||
private val TAG: String = RealmDB::class.simpleName ?: "Anonymous"
|
||||
|
||||
private const val SCHEMA_VERSION_NUMBER = 4L
|
||||
private const val SCHEMA_VERSION_NUMBER = 6L
|
||||
|
||||
private val ioScope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
|
@ -93,21 +93,24 @@ object RealmDB {
|
|||
Logd(TAG, "${caller?.className}.${caller?.methodName} upsert: ${entity.javaClass.simpleName}")
|
||||
}
|
||||
return realm.write {
|
||||
var result: T = entity
|
||||
if (entity.isManaged()) {
|
||||
findLatest(entity)?.let {
|
||||
result = findLatest(entity)?.let {
|
||||
block(it)
|
||||
}
|
||||
it
|
||||
} ?: entity
|
||||
} else {
|
||||
try {
|
||||
copyToRealm(entity, UpdatePolicy.ALL).let {
|
||||
result = copyToRealm(entity, UpdatePolicy.ALL).let {
|
||||
block(it)
|
||||
it
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "copyToRealm error: ${e.message}")
|
||||
showStackTrace()
|
||||
}
|
||||
}
|
||||
entity
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import ac.mdiq.podcini.storage.utils.FeedFunding.Companion.extractPaymentLinks
|
|||
import ac.mdiq.podcini.storage.utils.EpisodeFilter
|
||||
import ac.mdiq.podcini.storage.utils.FeedFunding
|
||||
import ac.mdiq.podcini.storage.utils.SortOrder
|
||||
import ac.mdiq.podcini.storage.utils.SortOrder.Companion.fromCode
|
||||
import ac.mdiq.podcini.storage.utils.VolumeAdaptionSetting
|
||||
import io.realm.kotlin.ext.realmListOf
|
||||
import io.realm.kotlin.types.RealmList
|
||||
|
@ -126,6 +127,7 @@ class Feed : RealmObject {
|
|||
|
||||
@Ignore
|
||||
var sortOrder: SortOrder? = null
|
||||
get() = fromCode(preferences?.sortOrderCode ?: 0)
|
||||
set(value) {
|
||||
if (value == null) return
|
||||
field = value
|
||||
|
|
|
@ -23,7 +23,8 @@ class EpisodeMultiSelectHandler(private val activity: MainActivity, private val
|
|||
|
||||
fun handleAction(items: List<Episode>) {
|
||||
when (actionId) {
|
||||
R.id.add_to_favorite_batch -> markFavorite(items)
|
||||
R.id.add_to_favorite_batch -> markFavorite(items, true)
|
||||
R.id.remove_favorite_batch -> markFavorite(items, false)
|
||||
R.id.add_to_queue_batch -> queueChecked(items)
|
||||
R.id.remove_from_queue_batch -> removeFromQueueChecked(items)
|
||||
R.id.mark_read_batch -> {
|
||||
|
@ -68,7 +69,7 @@ class EpisodeMultiSelectHandler(private val activity: MainActivity, private val
|
|||
// showMessage(R.plurals.marked_unread_batch_label, items.size)
|
||||
// }
|
||||
|
||||
private fun markFavorite(items: List<Episode>) {
|
||||
private fun markFavorite(items: List<Episode>, stat: Boolean) {
|
||||
for (item in items) {
|
||||
Episodes.setFavorite(item, true)
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ object EpisodeMenuHandler {
|
|||
/**
|
||||
* This method should be called in the prepare-methods of menus. It changes
|
||||
* the visibility of the menu items depending on a FeedItem's attributes.
|
||||
*
|
||||
* @param menu An instance of Menu
|
||||
* @param selectedItem The FeedItem for which the menu is supposed to be prepared
|
||||
* @return Returns true if selectedItem is not null.
|
||||
|
@ -101,7 +100,6 @@ object EpisodeMenuHandler {
|
|||
*/
|
||||
private fun setItemVisibility(menu: Menu?, menuId: Int, visibility: Boolean) {
|
||||
if (menu == null) return
|
||||
|
||||
val item = menu.findItem(menuId)
|
||||
item?.setVisible(visibility)
|
||||
}
|
||||
|
@ -120,26 +118,21 @@ object EpisodeMenuHandler {
|
|||
/**
|
||||
* The same method as [.onPrepareMenu], but lets the
|
||||
* caller also specify a list of menu items that should not be shown.
|
||||
*
|
||||
* @param excludeIds Menu item that should be excluded
|
||||
* @return true if selectedItem is not null.
|
||||
*/
|
||||
@UnstableApi
|
||||
fun onPrepareMenu(menu: Menu?, selectedItem: Episode?, vararg excludeIds: Int): Boolean {
|
||||
if (menu == null || selectedItem == null) return false
|
||||
|
||||
val rc = onPrepareMenu(menu, selectedItem)
|
||||
if (rc && excludeIds.isNotEmpty()) {
|
||||
for (id in excludeIds) {
|
||||
setItemVisibility(menu, id, false)
|
||||
}
|
||||
for (id in excludeIds) setItemVisibility(menu, id, false)
|
||||
}
|
||||
return rc
|
||||
}
|
||||
|
||||
/**
|
||||
* Default menu handling for the given FeedItem.
|
||||
*
|
||||
* A Fragment instance, (rather than the more generic Context), is needed as a parameter
|
||||
* to support some UI operations, e.g., creating a Snackbar.
|
||||
*/
|
||||
|
@ -204,14 +197,12 @@ object EpisodeMenuHandler {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh menu state
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove new flag with additional UI logic to allow undo with Snackbar.
|
||||
*
|
||||
* Undo is useful for Remove new flag, given there is no UI to undo it otherwise
|
||||
* ,i.e., there is (context) menu item for add new flag
|
||||
*/
|
||||
|
@ -219,7 +210,7 @@ object EpisodeMenuHandler {
|
|||
fun markReadWithUndo(fragment: Fragment, item: Episode?, playState: Int, showSnackbar: Boolean) {
|
||||
if (item == null) return
|
||||
|
||||
Logd(TAG, "markReadWithUndo(" + item.id + ")")
|
||||
Logd(TAG, "markReadWithUndo( ${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
|
||||
markPlayed(playState, false, item)
|
||||
|
@ -228,8 +219,7 @@ object EpisodeMenuHandler {
|
|||
val r = Runnable {
|
||||
val media: EpisodeMedia? = item.media
|
||||
val shouldAutoDelete: Boolean = if (item.feed == null) false else shouldAutoDeleteItemsOnFeed(item.feed!!)
|
||||
if (media != null && EpisodeUtil.hasAlmostEnded(media) && shouldAutoDelete)
|
||||
deleteMediaOfEpisode(fragment.requireContext(), item)
|
||||
if (media != null && EpisodeUtil.hasAlmostEnded(media) && shouldAutoDelete) deleteMediaOfEpisode(fragment.requireContext(), item)
|
||||
}
|
||||
val playStateStringRes: Int = when (playState) {
|
||||
Episode.UNPLAYED -> if (item.playState == Episode.NEW) R.string.removed_inbox_label //was new
|
||||
|
@ -252,8 +242,4 @@ object EpisodeMenuHandler {
|
|||
|
||||
h.postDelayed(r, ceil((duration * 1.05f).toDouble()).toInt().toLong())
|
||||
}
|
||||
|
||||
fun removeNewFlagWithUndo(fragment: Fragment, item: Episode?) {
|
||||
markReadWithUndo(fragment, item, Episode.UNPLAYED, false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,7 +152,6 @@ open class EpisodesAdapter(mainActivity: MainActivity)
|
|||
* Instead, we tell the adapter to use partial binding by calling [.notifyItemChanged].
|
||||
* We actually ignore the payload and always do a full bind but calling the partial bind method ensures
|
||||
* that ViewHolders are always re-used.
|
||||
*
|
||||
* @param position Position of the item that has changed
|
||||
*/
|
||||
fun notifyItemChangedCompat(position: Int) {
|
||||
|
|
|
@ -25,7 +25,6 @@ class ShareDialog : BottomSheetDialogFragment() {
|
|||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
|
||||
ctx = requireContext()
|
||||
item = requireArguments().getSerializable(ARGUMENT_FEED_ITEM) as Episode?
|
||||
prefs = requireActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
|
||||
_binding = ShareEpisodeDialogBinding.inflate(inflater)
|
||||
|
@ -93,7 +92,7 @@ class ShareDialog : BottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
companion object {
|
||||
private const val ARGUMENT_FEED_ITEM = "feedItem"
|
||||
// private const val ARGUMENT_FEED_ITEM = "feedItem"
|
||||
private const val PREF_NAME = "ShareDialog"
|
||||
private const val PREF_SHARE_EPISODE_START_AT = "prefShareEpisodeStartAt"
|
||||
private const val PREF_SHARE_EPISODE_TYPE = "prefShareEpisodeType"
|
||||
|
|
|
@ -78,7 +78,7 @@ class TagSettingsDialog : DialogFragment() {
|
|||
addTag(binding.newTagEditText.text.toString().trim { it <= ' ' })
|
||||
updatePreferencesTags(commonTags)
|
||||
buildTags()
|
||||
EventFlow.postEvent(FlowEvent.FeedTagsChangedEvent())
|
||||
// EventFlow.postEvent(FlowEvent.FeedTagsChangedEvent())
|
||||
}
|
||||
dialog.setNegativeButton(R.string.cancel_label, null)
|
||||
return dialog.create()
|
||||
|
@ -113,7 +113,7 @@ class TagSettingsDialog : DialogFragment() {
|
|||
feed.preferences!!.tags.removeAll(commonTags)
|
||||
feed.preferences!!.tags.addAll(displayedTags)
|
||||
persistFeedPreferences(feed)
|
||||
// EventFlow.postEvent(FlowEvent.FeedListUpdateEvent(feed.id))
|
||||
// EventFlow.postEvent(FlowEvent.FeedPrefsChangeEvent(feed))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ import kotlin.math.min
|
|||
|
||||
override fun loadData(): List<Episode> {
|
||||
allEpisodes = getEpisodes(0, Int.MAX_VALUE, getFilter(), allEpisodesSortOrder, false)
|
||||
if (allEpisodes.isEmpty()) return listOf()
|
||||
return allEpisodes.subList(0, min(allEpisodes.size-1, page * EPISODES_PER_PAGE))
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import ac.mdiq.podcini.playback.PlaybackController.Companion.isPlayingVideoLocal
|
|||
import ac.mdiq.podcini.playback.PlaybackController.Companion.playbackService
|
||||
import ac.mdiq.podcini.playback.PlaybackController.Companion.seekTo
|
||||
import ac.mdiq.podcini.playback.PlaybackController.Companion.sleepTimerActive
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curEpisode
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curMedia
|
||||
import ac.mdiq.podcini.playback.base.MediaPlayerBase
|
||||
import ac.mdiq.podcini.playback.base.MediaPlayerBase.Companion.getCurrentPlaybackSpeed
|
||||
|
@ -22,6 +23,7 @@ import ac.mdiq.podcini.preferences.UserPreferences
|
|||
import ac.mdiq.podcini.preferences.UserPreferences.isSkipSilence
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.videoPlayMode
|
||||
import ac.mdiq.podcini.receiver.MediaButtonReceiver
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.unmanagedCopy
|
||||
import ac.mdiq.podcini.storage.model.Chapter
|
||||
import ac.mdiq.podcini.storage.model.EpisodeMedia
|
||||
import ac.mdiq.podcini.storage.model.Playable
|
||||
|
@ -187,11 +189,11 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
|
|||
playerUI?.butPlay?.setIsShowPlay(isShowPlay)
|
||||
}
|
||||
|
||||
private fun setChapterDividers(media: Playable?) {
|
||||
if (media == null) return
|
||||
private fun setChapterDividers() {
|
||||
if (currentMedia == null) return
|
||||
|
||||
if (media.getChapters().isNotEmpty()) {
|
||||
val chapters: List<Chapter> = media.getChapters()
|
||||
if (currentMedia!!.getChapters().isNotEmpty()) {
|
||||
val chapters: List<Chapter> = currentMedia!!.getChapters()
|
||||
val dividerPos = FloatArray(chapters.size)
|
||||
|
||||
for (i in chapters.indices) {
|
||||
|
@ -213,22 +215,19 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
|
|||
return
|
||||
}
|
||||
if (!actMain.isPlayerVisible()) actMain.setPlayerVisible(true)
|
||||
|
||||
if (!isCollapsed && (currentMedia == null || curMedia?.getIdentifier() != currentMedia?.getIdentifier())) playerDetailsFragment?.updateInfo()
|
||||
|
||||
if (currentMedia == null || curMedia?.getIdentifier() != currentMedia?.getIdentifier() || (includingChapters && !curMedia!!.chaptersLoaded())) {
|
||||
Logd(TAG, "loadMediaInfo loading details ${curMedia?.getIdentifier()} chapter: $includingChapters")
|
||||
lifecycleScope.launch {
|
||||
val media: Playable = withContext(Dispatchers.IO) {
|
||||
withContext(Dispatchers.IO) {
|
||||
curMedia!!.apply {
|
||||
if (includingChapters) ChapterUtils.loadChapters(this, requireContext(), false)
|
||||
}
|
||||
}
|
||||
currentMedia = media
|
||||
if (currentMedia is EpisodeMedia) {
|
||||
val item = (currentMedia as EpisodeMedia).episode
|
||||
if (item != null) playerDetailsFragment?.setItem(item)
|
||||
}
|
||||
currentMedia = curMedia
|
||||
val item = (currentMedia as? EpisodeMedia)?.episode
|
||||
if (item != null) playerDetailsFragment?.setItem(item)
|
||||
updateUi()
|
||||
playerUI?.updateUi(currentMedia)
|
||||
// TODO: disable for now
|
||||
|
@ -263,8 +262,8 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
|
|||
|
||||
private fun updateUi() {
|
||||
Logd(TAG, "updateUi called")
|
||||
setChapterDividers(currentMedia)
|
||||
setupOptionsMenu(currentMedia)
|
||||
setChapterDividers()
|
||||
setupOptionsMenu()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -339,10 +338,10 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
|
|||
playerUI?.onPlaybackServiceChanged(event)
|
||||
}
|
||||
is FlowEvent.PlayEvent -> onEvenStartPlay(event)
|
||||
is FlowEvent.FavoritesEvent -> onFavoriteEvent(event)
|
||||
is FlowEvent.PlayerErrorEvent -> MediaPlayerErrorDialog.show(activity as Activity, event)
|
||||
is FlowEvent.FavoritesEvent -> loadMediaInfo(false)
|
||||
is FlowEvent.SleepTimerUpdatedEvent -> if (event.isCancelled || event.wasJustEnabled()) loadMediaInfo(false)
|
||||
is FlowEvent.PlaybackPositionEvent -> onPositionUpdate(event)
|
||||
is FlowEvent.PlaybackPositionEvent -> playerUI?.onPositionUpdate(event)
|
||||
is FlowEvent.SpeedChangedEvent -> playerUI?.updatePlaybackSpeedButton(event)
|
||||
else -> {}
|
||||
}
|
||||
|
@ -350,9 +349,8 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
|
|||
}
|
||||
}
|
||||
|
||||
private fun onPositionUpdate(event: FlowEvent.PlaybackPositionEvent) {
|
||||
// if (!isCollapsed) loadMediaInfo(false)
|
||||
playerUI?.onPositionUpdate(event)
|
||||
private fun onFavoriteEvent(event: FlowEvent.FavoritesEvent) {
|
||||
if (curEpisode?.id == event.episode.id) EpisodeMenuHandler.onPrepareMenu(toolbar.menu, event.episode)
|
||||
}
|
||||
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
|
@ -409,12 +407,12 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
|
|||
?.start()
|
||||
}
|
||||
|
||||
private fun setupOptionsMenu(media: Playable?) {
|
||||
private fun setupOptionsMenu() {
|
||||
if (toolbar.menu.size() == 0) toolbar.inflateMenu(R.menu.mediaplayer)
|
||||
|
||||
val isEpisodeMedia = media is EpisodeMedia
|
||||
val isEpisodeMedia = currentMedia is EpisodeMedia
|
||||
toolbar.menu?.findItem(R.id.open_feed_item)?.setVisible(isEpisodeMedia)
|
||||
val item = if (isEpisodeMedia) (media as EpisodeMedia).episode else null
|
||||
val item = if (isEpisodeMedia) (currentMedia as EpisodeMedia).episode else null
|
||||
EpisodeMenuHandler.onPrepareMenu(toolbar.menu, item)
|
||||
|
||||
val mediaType = curMedia?.getMediaType()
|
||||
|
|
|
@ -130,7 +130,6 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
override fun onMainActionSelected(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onToggleChanged(open: Boolean) {
|
||||
if (open && listAdapter.selectedCount == 0) {
|
||||
(activity as MainActivity).showSnackbarAbovePlayer(R.string.no_items_selected, Snackbar.LENGTH_SHORT)
|
||||
|
@ -147,9 +146,8 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
R.id.mark_unread_batch -> confirmationString = R.string.multi_select_mark_unplayed_confirmation
|
||||
}
|
||||
}
|
||||
if (confirmationString == 0) {
|
||||
performMultiSelectAction(actionItem.id)
|
||||
} else {
|
||||
if (confirmationString == 0) performMultiSelectAction(actionItem.id)
|
||||
else {
|
||||
object : ConfirmationDialog(activity as MainActivity, R.string.multi_select, confirmationString) {
|
||||
override fun onConfirmButtonPressed(dialog: DialogInterface) {
|
||||
performMultiSelectAction(actionItem.id)
|
||||
|
@ -158,7 +156,6 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
}
|
||||
true
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
@ -384,7 +381,7 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
Logd(TAG, "Received event: ${event.TAG}")
|
||||
when (event) {
|
||||
is FlowEvent.SwipeActionsChangedEvent -> refreshSwipeTelltale()
|
||||
is FlowEvent.FeedListEvent, is FlowEvent.EpisodePlayedEvent, is FlowEvent.PlayerSettingsEvent -> loadItems()
|
||||
is FlowEvent.FeedListEvent, is FlowEvent.EpisodePlayedEvent, is FlowEvent.PlayerSettingsEvent, is FlowEvent.FavoritesEvent -> loadItems()
|
||||
is FlowEvent.PlaybackPositionEvent -> onPlaybackPositionEvent(event)
|
||||
is FlowEvent.EpisodeEvent -> onEpisodeEvent(event)
|
||||
else -> {}
|
||||
|
|
|
@ -59,7 +59,7 @@ import java.util.*
|
|||
private val binding get() = _binding!!
|
||||
|
||||
private var runningDownloads: Set<String> = HashSet()
|
||||
private var items: MutableList<Episode> = mutableListOf()
|
||||
private var episodes: MutableList<Episode> = mutableListOf()
|
||||
|
||||
private lateinit var adapter: DownloadsListAdapter
|
||||
private lateinit var toolbar: MaterialToolbar
|
||||
|
@ -124,7 +124,6 @@ import java.util.*
|
|||
override fun onMainActionSelected(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onToggleChanged(open: Boolean) {
|
||||
if (open && adapter.selectedCount == 0) {
|
||||
(activity as MainActivity).showSnackbarAbovePlayer(R.string.no_items_selected, Snackbar.LENGTH_SHORT)
|
||||
|
@ -143,7 +142,6 @@ import java.util.*
|
|||
DownloadLogFragment().show(childFragmentManager, null)
|
||||
|
||||
addEmptyView()
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
@ -195,7 +193,7 @@ import java.util.*
|
|||
return // Refreshed anyway
|
||||
}
|
||||
for (downloadUrl in event.urls) {
|
||||
val pos = EpisodeUtil.indexOfItemWithDownloadUrl(items.toList(), downloadUrl)
|
||||
val pos = EpisodeUtil.indexOfItemWithDownloadUrl(episodes.toList(), downloadUrl)
|
||||
if (pos >= 0) adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +213,11 @@ import java.util.*
|
|||
when (event) {
|
||||
is FlowEvent.EpisodeEvent -> onEpisodeEvent(event)
|
||||
is FlowEvent.PlaybackPositionEvent -> onPlaybackPositionEvent(event)
|
||||
is FlowEvent.PlayerSettingsEvent, is FlowEvent.DownloadLogEvent, is FlowEvent.EpisodePlayedEvent -> loadItems()
|
||||
is FlowEvent.FavoritesEvent -> onFavoriteEvent(event)
|
||||
is FlowEvent.PlayerSettingsEvent -> loadItems()
|
||||
is FlowEvent.DownloadLogEvent -> loadItems()
|
||||
is FlowEvent.EpisodePlayedEvent -> onEpisodePlayedEvent(event)
|
||||
is FlowEvent.QueueEvent -> loadItems()
|
||||
is FlowEvent.SwipeActionsChangedEvent -> refreshSwipeTelltale()
|
||||
is FlowEvent.EpisodeDownloadEvent -> onEpisodeDownloadEvent(event)
|
||||
else -> {}
|
||||
|
@ -233,6 +235,27 @@ import java.util.*
|
|||
// }
|
||||
}
|
||||
|
||||
private fun onFavoriteEvent(event: FlowEvent.FavoritesEvent) {
|
||||
val item = event.episode
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
episodes.removeAt(pos)
|
||||
episodes.add(pos, item)
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onEpisodePlayedEvent(event: FlowEvent.EpisodePlayedEvent) {
|
||||
if (event.episode == null) return
|
||||
val item = event.episode
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
episodes.removeAt(pos)
|
||||
episodes.add(pos, item)
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onContextItemSelected(item: MenuItem): Boolean {
|
||||
val selectedItem: Episode? = adapter.longPressedItem
|
||||
if (selectedItem == null) {
|
||||
|
@ -257,12 +280,12 @@ import java.util.*
|
|||
val size: Int = event.episodes.size
|
||||
while (i < size) {
|
||||
val item: Episode = event.episodes[i]
|
||||
val pos = EpisodeUtil.indexOfItemWithId(items.toList(), item.id)
|
||||
val pos = EpisodeUtil.indexOfItemWithId(episodes.toList(), item.id)
|
||||
if (pos >= 0) {
|
||||
items.removeAt(pos)
|
||||
episodes.removeAt(pos)
|
||||
val media = item.media
|
||||
if (media != null && media.downloaded) {
|
||||
items.add(pos, item)
|
||||
episodes.add(pos, item)
|
||||
// adapter.notifyItemChangedCompat(pos)
|
||||
} else {
|
||||
// adapter.notifyItemRemoved(pos)
|
||||
|
@ -273,7 +296,7 @@ import java.util.*
|
|||
// have to do this as adapter.notifyItemRemoved(pos) when pos == 0 causes crash
|
||||
if (size > 0) {
|
||||
// adapter.setDummyViews(0)
|
||||
adapter.updateItems(items)
|
||||
adapter.updateItems(episodes)
|
||||
}
|
||||
refreshInfoBar()
|
||||
}
|
||||
|
@ -304,16 +327,11 @@ import java.util.*
|
|||
emptyView.hide()
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
Logd(TAG, "loading")
|
||||
withContext(Dispatchers.IO) {
|
||||
val sortOrder: SortOrder? = UserPreferences.downloadsSortedOrder
|
||||
// val downloadedItems = realm.query(Episode::class).query("media.downloaded == true").find().toMutableList()
|
||||
// if (sortOrder != null) getPermutor(sortOrder).reorder(downloadedItems)
|
||||
val downloadedItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.DOWNLOADED), sortOrder)
|
||||
Logd(TAG, "downloadedItems: ${downloadedItems.size}")
|
||||
if (runningDownloads.isEmpty()) downloadedItems
|
||||
if (runningDownloads.isEmpty()) episodes = downloadedItems.toMutableList()
|
||||
else {
|
||||
Logd(TAG, "runningDownloads: ${runningDownloads.size}")
|
||||
val mediaUrls: MutableList<String> = ArrayList()
|
||||
for (url in runningDownloads) {
|
||||
if (EpisodeUtil.indexOfItemWithDownloadUrl(downloadedItems, url) != -1) continue
|
||||
|
@ -321,14 +339,13 @@ import java.util.*
|
|||
}
|
||||
val currentDownloads = getEpisdesWithUrl(mediaUrls).toMutableList()
|
||||
currentDownloads.addAll(downloadedItems)
|
||||
currentDownloads
|
||||
episodes = currentDownloads
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
items = result.toMutableList()
|
||||
// adapter.setDummyViews(0)
|
||||
binding.progLoading.visibility = View.GONE
|
||||
adapter.updateItems(result)
|
||||
adapter.updateItems(episodes)
|
||||
refreshInfoBar()
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
|
@ -352,10 +369,10 @@ import java.util.*
|
|||
}
|
||||
|
||||
private fun refreshInfoBar() {
|
||||
var info = String.format(Locale.getDefault(), "%d%s", items.size, getString(R.string.episodes_suffix))
|
||||
if (items.isNotEmpty()) {
|
||||
var info = String.format(Locale.getDefault(), "%d%s", episodes.size, getString(R.string.episodes_suffix))
|
||||
if (episodes.isNotEmpty()) {
|
||||
var sizeMB: Long = 0
|
||||
for (item in items) sizeMB += item.media?.size ?: 0
|
||||
for (item in episodes) sizeMB += item.media?.size ?: 0
|
||||
info += " • " + (sizeMB / 1000000) + " MB"
|
||||
}
|
||||
binding.infoBar.text = info
|
||||
|
|
|
@ -21,7 +21,6 @@ import ac.mdiq.podcini.ui.actions.menuhandler.EpisodeMenuHandler
|
|||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.utils.ShownotesCleaner
|
||||
import ac.mdiq.podcini.ui.utils.ThemeUtils
|
||||
import ac.mdiq.podcini.ui.view.CircularProgressBar
|
||||
import ac.mdiq.podcini.ui.view.ShownotesWebView
|
||||
import ac.mdiq.podcini.util.Converter
|
||||
import ac.mdiq.podcini.util.DateFormatter
|
||||
|
@ -75,7 +74,7 @@ import kotlin.math.max
|
|||
private var homeFragment: EpisodeHomeFragment? = null
|
||||
|
||||
private var itemLoaded = false
|
||||
private var item: Episode? = null
|
||||
private var episode: Episode? = null
|
||||
private var webviewData: String? = null
|
||||
|
||||
private lateinit var shownotesCleaner: ShownotesCleaner
|
||||
|
@ -93,7 +92,6 @@ import kotlin.math.max
|
|||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
_binding = EpisodeInfoFragmentBinding.inflate(inflater, container, false)
|
||||
// root = binding.root
|
||||
Logd(TAG, "fragment onCreateView")
|
||||
|
||||
toolbar = binding.toolbar
|
||||
|
@ -108,7 +106,7 @@ import kotlin.math.max
|
|||
webvDescription = binding.webvDescription
|
||||
webvDescription.setTimecodeSelectedListener { time: Int? ->
|
||||
val cMedia = curMedia
|
||||
if (item?.media?.getIdentifier() == cMedia?.getIdentifier()) seekTo(time ?: 0)
|
||||
if (episode?.media?.getIdentifier() == cMedia?.getIdentifier()) seekTo(time ?: 0)
|
||||
else (activity as MainActivity).showSnackbarAbovePlayer(R.string.play_this_to_seek_position, Snackbar.LENGTH_LONG)
|
||||
}
|
||||
registerForContextMenu(webvDescription)
|
||||
|
@ -119,10 +117,10 @@ import kotlin.math.max
|
|||
butAction2 = binding.butAction2
|
||||
|
||||
binding.homeButton.setOnClickListener {
|
||||
if (!item?.link.isNullOrEmpty()) {
|
||||
homeFragment = EpisodeHomeFragment.newInstance(item!!)
|
||||
if (!episode?.link.isNullOrEmpty()) {
|
||||
homeFragment = EpisodeHomeFragment.newInstance(episode!!)
|
||||
(activity as MainActivity).loadChildFragment(homeFragment!!)
|
||||
} else Toast.makeText(context, "Episode link is not valid ${item?.link}", Toast.LENGTH_LONG).show()
|
||||
} else Toast.makeText(context, "Episode link is not valid ${episode?.link}", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
butAction1.setOnClickListener(View.OnClickListener {
|
||||
|
@ -201,8 +199,8 @@ import kotlin.math.max
|
|||
@UnstableApi override fun onMenuItemClick(menuItem: MenuItem): Boolean {
|
||||
when (menuItem.itemId) {
|
||||
R.id.share_notes -> {
|
||||
if (item == null) return false
|
||||
val notes = item!!.description
|
||||
if (episode == null) return false
|
||||
val notes = episode!!.description
|
||||
if (!notes.isNullOrEmpty()) {
|
||||
val shareText = if (Build.VERSION.SDK_INT >= 24) HtmlCompat.fromHtml(notes, HtmlCompat.FROM_HTML_MODE_COMPACT).toString()
|
||||
else HtmlCompat.fromHtml(notes, HtmlCompat.FROM_HTML_MODE_COMPACT).toString()
|
||||
|
@ -217,8 +215,8 @@ import kotlin.math.max
|
|||
return true
|
||||
}
|
||||
else -> {
|
||||
if (item == null) return false
|
||||
return EpisodeMenuHandler.onMenuItemClicked(this, menuItem.itemId, item!!)
|
||||
if (episode == null) return false
|
||||
return EpisodeMenuHandler.onMenuItemClicked(this, menuItem.itemId, episode!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -234,44 +232,45 @@ import kotlin.math.max
|
|||
@OptIn(UnstableApi::class) override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
Logd(TAG, "onDestroyView")
|
||||
|
||||
binding.root.removeView(webvDescription)
|
||||
webvDescription.clearHistory()
|
||||
webvDescription.clearCache(true)
|
||||
webvDescription.clearView()
|
||||
webvDescription.destroy()
|
||||
|
||||
_binding = null
|
||||
}
|
||||
|
||||
@UnstableApi private fun onFragmentLoaded() {
|
||||
if (webviewData != null && !itemLoaded)
|
||||
webvDescription.loadDataWithBaseURL("https://127.0.0.1", webviewData!!, "text/html", "utf-8", "about:blank")
|
||||
|
||||
// if (item?.link != null) binding.webView.loadUrl(item!!.link!!)
|
||||
updateAppearance()
|
||||
}
|
||||
|
||||
private fun prepareMenu() {
|
||||
if (episode!!.media != null) EpisodeMenuHandler.onPrepareMenu(toolbar.menu, episode, R.id.open_podcast)
|
||||
// these are already available via button1 and button2
|
||||
else EpisodeMenuHandler.onPrepareMenu(toolbar.menu, episode, R.id.open_podcast, R.id.mark_read_item, R.id.visit_website_item)
|
||||
}
|
||||
|
||||
@UnstableApi private fun updateAppearance() {
|
||||
if (item == null) {
|
||||
if (episode == null) {
|
||||
Logd(TAG, "updateAppearance item is null")
|
||||
return
|
||||
}
|
||||
if (item!!.media != null) EpisodeMenuHandler.onPrepareMenu(toolbar.menu, item, R.id.open_podcast)
|
||||
// these are already available via button1 and button2
|
||||
else EpisodeMenuHandler.onPrepareMenu(toolbar.menu, item, R.id.open_podcast, R.id.mark_read_item, R.id.visit_website_item)
|
||||
prepareMenu()
|
||||
|
||||
if (item!!.feed != null) binding.txtvPodcast.text = item!!.feed!!.title
|
||||
binding.txtvTitle.text = item!!.title
|
||||
binding.itemLink.text = item!!.link
|
||||
if (episode!!.feed != null) binding.txtvPodcast.text = episode!!.feed!!.title
|
||||
binding.txtvTitle.text = episode!!.title
|
||||
binding.itemLink.text = episode!!.link
|
||||
|
||||
if (item?.pubDate != null) {
|
||||
val pubDateStr = DateFormatter.formatAbbrev(context, Date(item!!.pubDate))
|
||||
if (episode?.pubDate != null) {
|
||||
val pubDateStr = DateFormatter.formatAbbrev(context, Date(episode!!.pubDate))
|
||||
binding.txtvPublished.text = pubDateStr
|
||||
binding.txtvPublished.setContentDescription(DateFormatter.formatForAccessibility(Date(item!!.pubDate)))
|
||||
binding.txtvPublished.setContentDescription(DateFormatter.formatForAccessibility(Date(episode!!.pubDate)))
|
||||
}
|
||||
|
||||
val media = item?.media
|
||||
val media = episode?.media
|
||||
when {
|
||||
media == null -> binding.txtvSize.text = ""
|
||||
media.size > 0 -> binding.txtvSize.text = Formatter.formatShortFileSize(activity, media.size)
|
||||
|
@ -279,7 +278,7 @@ import kotlin.math.max
|
|||
binding.txtvSize.text = "{faw_spinner}"
|
||||
// Iconify.addIcons(size)
|
||||
lifecycleScope.launch {
|
||||
val sizeValue = getMediaSize(item)
|
||||
val sizeValue = getMediaSize(episode)
|
||||
if (sizeValue <= 0) binding.txtvSize.text = ""
|
||||
else binding.txtvSize.text = Formatter.formatShortFileSize(activity, sizeValue)
|
||||
}
|
||||
|
@ -287,10 +286,10 @@ import kotlin.math.max
|
|||
else -> binding.txtvSize.text = ""
|
||||
}
|
||||
|
||||
val imgLocFB = ImageResourceUtils.getFallbackImageLocation(item!!)
|
||||
val imgLocFB = ImageResourceUtils.getFallbackImageLocation(episode!!)
|
||||
val imageLoader = imgvCover.context.imageLoader
|
||||
val imageRequest = ImageRequest.Builder(requireContext())
|
||||
.data(item!!.imageLocation)
|
||||
.data(episode!!.imageLocation)
|
||||
.placeholder(R.color.light_gray)
|
||||
.listener(object : ImageRequest.Listener {
|
||||
override fun onError(request: ImageRequest, result: ErrorResult) {
|
||||
|
@ -313,21 +312,21 @@ import kotlin.math.max
|
|||
@UnstableApi private fun updateButtons() {
|
||||
binding.circularProgressBar.visibility = View.GONE
|
||||
val dls = DownloadServiceInterface.get()
|
||||
if (item != null && item!!.media != null && item!!.media!!.downloadUrl != null) {
|
||||
val url = item!!.media!!.downloadUrl!!
|
||||
if (episode != null && episode!!.media != null && episode!!.media!!.downloadUrl != null) {
|
||||
val url = episode!!.media!!.downloadUrl!!
|
||||
if (dls != null && dls.isDownloadingEpisode(url)) {
|
||||
binding.circularProgressBar.visibility = View.VISIBLE
|
||||
binding.circularProgressBar.setPercentage(0.01f * max(1.0, dls.getProgress(url).toDouble()).toFloat(), item)
|
||||
binding.circularProgressBar.setPercentage(0.01f * max(1.0, dls.getProgress(url).toDouble()).toFloat(), episode)
|
||||
binding.circularProgressBar.setIndeterminate(dls.isEpisodeQueued(url))
|
||||
}
|
||||
}
|
||||
|
||||
val media: EpisodeMedia? = item?.media
|
||||
val media: EpisodeMedia? = episode?.media
|
||||
if (media == null) {
|
||||
if (item != null) {
|
||||
if (episode != null) {
|
||||
// actionButton1 = VisitWebsiteActionButton(item!!)
|
||||
butAction1.visibility = View.INVISIBLE
|
||||
actionButton2 = VisitWebsiteActionButton(item!!)
|
||||
actionButton2 = VisitWebsiteActionButton(episode!!)
|
||||
}
|
||||
binding.noMediaLabel.visibility = View.VISIBLE
|
||||
} else {
|
||||
|
@ -336,19 +335,19 @@ import kotlin.math.max
|
|||
binding.txtvDuration.text = Converter.getDurationStringLong(media.getDuration())
|
||||
binding.txtvDuration.setContentDescription(Converter.getDurationStringLocalized(requireContext(), media.getDuration().toLong()))
|
||||
}
|
||||
if (item != null) {
|
||||
if (episode != null) {
|
||||
actionButton1 = when {
|
||||
media.getMediaType() == MediaType.FLASH -> VisitWebsiteActionButton(item!!)
|
||||
InTheatre.isCurrentlyPlaying(media) -> PauseActionButton(item!!)
|
||||
item!!.feed != null && item!!.feed!!.isLocalFeed -> PlayLocalActionButton(item!!)
|
||||
media.downloaded -> PlayActionButton(item!!)
|
||||
else -> StreamActionButton(item!!)
|
||||
media.getMediaType() == MediaType.FLASH -> VisitWebsiteActionButton(episode!!)
|
||||
InTheatre.isCurrentlyPlaying(media) -> PauseActionButton(episode!!)
|
||||
episode!!.feed != null && episode!!.feed!!.isLocalFeed -> PlayLocalActionButton(episode!!)
|
||||
media.downloaded -> PlayActionButton(episode!!)
|
||||
else -> StreamActionButton(episode!!)
|
||||
}
|
||||
actionButton2 = when {
|
||||
media.getMediaType() == MediaType.FLASH -> VisitWebsiteActionButton(item!!)
|
||||
dls != null && media.downloadUrl != null && dls.isDownloadingEpisode(media.downloadUrl!!) -> CancelDownloadActionButton(item!!)
|
||||
!media.downloaded -> DownloadActionButton(item!!)
|
||||
else -> DeleteActionButton(item!!)
|
||||
media.getMediaType() == MediaType.FLASH -> VisitWebsiteActionButton(episode!!)
|
||||
dls != null && media.downloadUrl != null && dls.isDownloadingEpisode(media.downloadUrl!!) -> CancelDownloadActionButton(episode!!)
|
||||
!media.downloaded -> DownloadActionButton(episode!!)
|
||||
else -> DeleteActionButton(episode!!)
|
||||
}
|
||||
// if (actionButton2 != null && media.getMediaType() == MediaType.FLASH) actionButton2!!.visibility = View.GONE
|
||||
}
|
||||
|
@ -369,9 +368,9 @@ import kotlin.math.max
|
|||
}
|
||||
|
||||
@OptIn(UnstableApi::class) private fun openPodcast() {
|
||||
if (item?.feedId == null) return
|
||||
if (episode?.feedId == null) return
|
||||
|
||||
val fragment: Fragment = FeedEpisodesFragment.newInstance(item!!.feedId!!)
|
||||
val fragment: Fragment = FeedEpisodesFragment.newInstance(episode!!.feedId!!)
|
||||
(activity as MainActivity).loadChildFragment(fragment)
|
||||
}
|
||||
|
||||
|
@ -388,6 +387,8 @@ import kotlin.math.max
|
|||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: ${event.TAG}")
|
||||
when (event) {
|
||||
is FlowEvent.QueueEvent -> onQueueEvent(event)
|
||||
is FlowEvent.FavoritesEvent -> onFavoriteEvent(event)
|
||||
is FlowEvent.EpisodeEvent -> onEpisodeEvent(event)
|
||||
is FlowEvent.PlayerSettingsEvent -> updateButtons()
|
||||
is FlowEvent.EpisodePlayedEvent -> load()
|
||||
|
@ -406,11 +407,32 @@ import kotlin.math.max
|
|||
}
|
||||
}
|
||||
|
||||
private fun onFavoriteEvent(event: FlowEvent.FavoritesEvent) {
|
||||
if (episode?.id == event.episode.id) {
|
||||
episode = unmanagedCopy(event.episode)
|
||||
prepareMenu()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onQueueEvent(event: FlowEvent.QueueEvent) {
|
||||
var i = 0
|
||||
val size: Int = event.episodes.size
|
||||
while (i < size) {
|
||||
val item_ = event.episodes[i]
|
||||
if (item_.id == episode?.id) {
|
||||
episode = unmanagedCopy(item_)
|
||||
prepareMenu()
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
private fun onEpisodeEvent(event: FlowEvent.EpisodeEvent) {
|
||||
// Logd(TAG, "onEventMainThread() called with ${event.TAG}")
|
||||
if (this.item == null) return
|
||||
if (this.episode == null) return
|
||||
for (item in event.episodes) {
|
||||
if (this.item!!.id == item.id) {
|
||||
if (this.episode!!.id == item.id) {
|
||||
load()
|
||||
return
|
||||
}
|
||||
|
@ -418,8 +440,8 @@ import kotlin.math.max
|
|||
}
|
||||
|
||||
private fun onEpisodeDownloadEvent(event: FlowEvent.EpisodeDownloadEvent) {
|
||||
if (item == null || item!!.media == null) return
|
||||
if (!event.urls.contains(item!!.media!!.downloadUrl)) return
|
||||
if (episode == null || episode!!.media == null) return
|
||||
if (!event.urls.contains(episode!!.media!!.downloadUrl)) return
|
||||
if (itemLoaded && activity != null) updateButtons()
|
||||
}
|
||||
|
||||
|
@ -429,17 +451,14 @@ import kotlin.math.max
|
|||
Logd(TAG, "load() called")
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
val feedItem = item
|
||||
if (feedItem != null) {
|
||||
val duration = feedItem.media?.getDuration()?: Int.MAX_VALUE
|
||||
webviewData = shownotesCleaner.processShownotes(feedItem.description?:"", duration)
|
||||
withContext(Dispatchers.IO) {
|
||||
if (episode != null) {
|
||||
val duration = episode!!.media?.getDuration()?: Int.MAX_VALUE
|
||||
webviewData = shownotesCleaner.processShownotes(episode!!.description?:"", duration)
|
||||
}
|
||||
feedItem
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.progbarLoading.visibility = View.GONE
|
||||
item = result
|
||||
onFragmentLoaded()
|
||||
itemLoaded = true
|
||||
}
|
||||
|
@ -450,7 +469,7 @@ import kotlin.math.max
|
|||
}
|
||||
|
||||
fun setItem(item_: Episode) {
|
||||
item = unmanagedCopy(item_)
|
||||
episode = unmanagedCopy(item_)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -498,7 +517,6 @@ import kotlin.math.max
|
|||
if (size <= 0) media.setCheckedOnSizeButUnknown()
|
||||
else media.size = size
|
||||
upsert(episode) {}
|
||||
|
||||
size
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,8 +183,7 @@ import java.util.concurrent.Semaphore
|
|||
}
|
||||
})
|
||||
dialBinding.fabSD.setOnActionSelectedListener { actionItem: SpeedDialActionItem ->
|
||||
EpisodeMultiSelectHandler((activity as MainActivity), actionItem.id)
|
||||
.handleAction(adapter.selectedItems.filterIsInstance<Episode>())
|
||||
EpisodeMultiSelectHandler((activity as MainActivity), actionItem.id).handleAction(adapter.selectedItems.filterIsInstance<Episode>())
|
||||
adapter.endSelectMode()
|
||||
true
|
||||
}
|
||||
|
@ -331,7 +330,6 @@ import java.util.concurrent.Semaphore
|
|||
|
||||
var i = 0
|
||||
val size: Int = event.episodes.size
|
||||
// feed = getFeed(feed!!.id) ?: error("Can't find latest for feed ${feed?.title}")
|
||||
while (i < size) {
|
||||
val item = event.episodes[i]
|
||||
if (item.feedId != feed!!.id) continue
|
||||
|
@ -354,8 +352,11 @@ import java.util.concurrent.Semaphore
|
|||
if (item.feedId != feed!!.id) continue
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
episodes[pos].playState = item.playState
|
||||
episodes.removeAt(pos)
|
||||
episodes.add(pos, item)
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
// episodes[pos].playState = item.playState
|
||||
// adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
@ -374,8 +375,11 @@ import java.util.concurrent.Semaphore
|
|||
val item = event.episode
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
episodes[pos].playState = item.playState
|
||||
episodes.removeAt(pos)
|
||||
episodes.add(pos, item)
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
// episodes[pos].playState = item.playState
|
||||
// adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,8 +387,11 @@ import java.util.concurrent.Semaphore
|
|||
val item = event.episode
|
||||
val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id)
|
||||
if (pos >= 0) {
|
||||
episodes[pos].isFavorite = item.isFavorite
|
||||
episodes.removeAt(pos)
|
||||
episodes.add(pos, item)
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
// episodes[pos].isFavorite = item.isFavorite
|
||||
// adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,9 +403,6 @@ import java.util.concurrent.Semaphore
|
|||
val pos: Int = EpisodeUtil.indexOfItemWithDownloadUrl(episodes, downloadUrl)
|
||||
if (pos >= 0) {
|
||||
// TODO: need a better way
|
||||
val item = episodes[pos]
|
||||
// item.media?.downloaded = true
|
||||
Logd(TAG, "onEpisodeDownloadEvent ${item.title}")
|
||||
adapter.notifyItemChangedCompat(pos)
|
||||
}
|
||||
}
|
||||
|
@ -704,8 +708,7 @@ import java.util.concurrent.Semaphore
|
|||
class SingleFeedSortDialog(val feed: Feed?) : EpisodeSortDialog() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
sortOrder = if (feed?.sortOrder == null) SortOrder.DATE_NEW_OLD
|
||||
else feed.sortOrder
|
||||
sortOrder = feed?.sortOrder ?: SortOrder.DATE_NEW_OLD
|
||||
}
|
||||
override fun onAddItem(title: Int, ascending: SortOrder, descending: SortOrder, ascendingIsDefault: Boolean) {
|
||||
if (ascending == SortOrder.DATE_OLD_NEW || ascending == SortOrder.PLAYED_DATE_OLD_NEW || ascending == SortOrder.COMPLETED_DATE_OLD_NEW
|
||||
|
|
|
@ -152,6 +152,7 @@ import kotlin.math.min
|
|||
|
||||
override fun loadData(): List<Episode> {
|
||||
allHistory = getHistory(0, Int.MAX_VALUE, startDate, endDate, sortOrder).toMutableList()
|
||||
if (allHistory.isEmpty()) return listOf()
|
||||
return allHistory.subList(0, min(allHistory.size-1, page * EPISODES_PER_PAGE))
|
||||
}
|
||||
|
||||
|
|
|
@ -408,10 +408,6 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
|
|||
val numFeeds = getFeedList().size
|
||||
while (curQueue.name.isEmpty()) runBlocking { delay(100) }
|
||||
val queueSize = curQueue.episodeIds.size
|
||||
// if (queueSize == 0) {
|
||||
// val queue = realm.query(PlayQueue::class).sort("updated", Sort.DESCENDING).first().find()
|
||||
// queueSize = queue?.episodeIds?.size ?: 0
|
||||
// }
|
||||
Logd(TAG, "getDatasetStats: queueSize: $queueSize")
|
||||
return DatasetStats(queueSize, numDownloadedItems, AutoCleanups.build().getReclaimableItems(), numItems, numFeeds)
|
||||
}
|
||||
|
|
|
@ -75,12 +75,16 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
private lateinit var toolbar: MaterialToolbar
|
||||
private lateinit var speedDialView: SpeedDialView
|
||||
|
||||
private lateinit var catAdapter: ArrayAdapter<String>
|
||||
|
||||
private var tagFilterIndex = 1
|
||||
// TODO: currently not used
|
||||
private var displayedFolder: String = ""
|
||||
private var displayUpArrow = false
|
||||
|
||||
private var feedList: MutableList<Feed> = mutableListOf()
|
||||
private var feedListFiltered: List<Feed> = mutableListOf()
|
||||
private val tags: MutableList<String> = mutableListOf()
|
||||
|
||||
private var useGrid: Boolean? = null
|
||||
|
||||
|
@ -121,12 +125,11 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
|
||||
resetTags()
|
||||
|
||||
val catAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, tags)
|
||||
catAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, tags)
|
||||
catAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
val catSpinner = binding.categorySpinner
|
||||
catSpinner.setAdapter(catAdapter)
|
||||
catSpinner.setSelection(catAdapter.getPosition("All"))
|
||||
catSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
binding.categorySpinner.setAdapter(catAdapter)
|
||||
binding.categorySpinner.setSelection(catAdapter.getPosition("All"))
|
||||
binding.categorySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
tagFilterIndex = position
|
||||
filterOnTag()
|
||||
|
@ -192,6 +195,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
}
|
||||
|
||||
override fun onStart() {
|
||||
Logd(TAG, "onStart()")
|
||||
super.onStart()
|
||||
initAdapter()
|
||||
procFlowEvents()
|
||||
|
@ -231,6 +235,13 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
listAdapter.setItems(feedListFiltered)
|
||||
}
|
||||
|
||||
private fun resetTags() {
|
||||
tags.clear()
|
||||
tags.add("Untagged")
|
||||
tags.add("All")
|
||||
tags.addAll(getTags())
|
||||
}
|
||||
|
||||
private var eventSink: Job? = null
|
||||
private var eventStickySink: Job? = null
|
||||
private fun cancelFlowEvents() {
|
||||
|
@ -244,9 +255,9 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: ${event.TAG}")
|
||||
when (event) {
|
||||
is FlowEvent.FeedListEvent -> onFeedListChanged(event)
|
||||
is FlowEvent.FeedListEvent -> loadSubscriptions()
|
||||
is FlowEvent.EpisodePlayedEvent, is FlowEvent.FeedsSortedEvent -> loadSubscriptions()
|
||||
is FlowEvent.FeedTagsChangedEvent -> resetTags()
|
||||
is FlowEvent.FeedTagsChangedEvent -> loadSubscriptions()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +278,6 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
when (itemId) {
|
||||
R.id.action_search -> (activity as MainActivity).loadChildFragment(SearchFragment.newInstance())
|
||||
R.id.subscriptions_sort -> FeedSortDialog.showDialog(requireContext())
|
||||
// R.id.subscriptions_filter -> SubscriptionsFilterDialog().show(childFragmentManager, "filter")
|
||||
R.id.refresh_item -> FeedUpdateManager.runOnceOrAsk(requireContext())
|
||||
else -> return false
|
||||
}
|
||||
|
@ -286,15 +296,14 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
emptyView.hide()
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
withContext(Dispatchers.IO) {
|
||||
feedList = getFeedList().toMutableList()
|
||||
sortFeeds()
|
||||
val fList: List<Feed> = getFeedList()
|
||||
fList
|
||||
resetTags()
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
// We have fewer items. This can result in items being selected that are no longer visible.
|
||||
if ( feedListFiltered.size > result.size) listAdapter.endSelectMode()
|
||||
feedList = result.toMutableList()
|
||||
if ( feedListFiltered.size > feedList.size) listAdapter.endSelectMode()
|
||||
filterOnTag()
|
||||
binding.progressBar.visibility = View.GONE
|
||||
listAdapter.setItems(feedListFiltered)
|
||||
|
@ -374,7 +383,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
comparator(counterMap)
|
||||
}
|
||||
}
|
||||
feedList.sortWith(comparator)
|
||||
synchronized(feedList) { feedList.sortWith(comparator) }
|
||||
}
|
||||
|
||||
private fun counterMap(episodes: RealmResults<Episode>): Map<Long, Long> {
|
||||
|
@ -411,12 +420,6 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
return FeedMenuHandler.onMenuItemClicked(this, item.itemId, feed) { this.loadSubscriptions() }
|
||||
}
|
||||
|
||||
private fun onFeedListChanged(event: FlowEvent.FeedListEvent) {
|
||||
// val feeds_ = realm.query(Feed::class,"id IN $0", event.feedIds).find()
|
||||
// updateFeedMap(feeds_)
|
||||
loadSubscriptions()
|
||||
}
|
||||
|
||||
override fun onEndSelectMode() {
|
||||
speedDialView.close()
|
||||
speedDialView.visibility = View.GONE
|
||||
|
@ -425,10 +428,8 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
|
||||
override fun onStartSelectMode() {
|
||||
speedDialView.visibility = View.VISIBLE
|
||||
val feedsOnly: MutableList<Feed> = ArrayList<Feed>()
|
||||
for (item in feedListFiltered) {
|
||||
feedsOnly.add(item)
|
||||
}
|
||||
val feedsOnly: MutableList<Feed> = ArrayList<Feed>(feedListFiltered)
|
||||
// feedsOnly.addAll(feedListFiltered)
|
||||
listAdapter.setItems(feedsOnly)
|
||||
}
|
||||
|
||||
|
@ -437,9 +438,6 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
fun handleAction(id: Int) {
|
||||
when (id) {
|
||||
R.id.remove_feed -> RemoveFeedDialog.show(activity, selectedItems)
|
||||
// R.id.notify_new_episodes -> {
|
||||
// notifyNewEpisodesPrefHandler()
|
||||
// }
|
||||
R.id.keep_updated -> keepUpdatedPrefHandler()
|
||||
R.id.autodownload -> autoDownloadPrefHandler()
|
||||
R.id.autoDeleteDownload -> autoDeleteEpisodesPrefHandler()
|
||||
|
@ -458,22 +456,22 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
preferenceSwitchDialog.openDialog()
|
||||
}
|
||||
@UnstableApi private fun playbackSpeedPrefHandler() {
|
||||
val viewBinding = PlaybackSpeedFeedSettingDialogBinding.inflate(activity.layoutInflater)
|
||||
viewBinding.seekBar.setProgressChangedListener { speed: Float? ->
|
||||
viewBinding.currentSpeedLabel.text = String.format(Locale.getDefault(), "%.2fx", speed)
|
||||
val vBinding = PlaybackSpeedFeedSettingDialogBinding.inflate(activity.layoutInflater)
|
||||
vBinding.seekBar.setProgressChangedListener { speed: Float? ->
|
||||
vBinding.currentSpeedLabel.text = String.format(Locale.getDefault(), "%.2fx", speed)
|
||||
}
|
||||
viewBinding.useGlobalCheckbox.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||
viewBinding.seekBar.isEnabled = !isChecked
|
||||
viewBinding.seekBar.alpha = if (isChecked) 0.4f else 1f
|
||||
viewBinding.currentSpeedLabel.alpha = if (isChecked) 0.4f else 1f
|
||||
vBinding.useGlobalCheckbox.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||
vBinding.seekBar.isEnabled = !isChecked
|
||||
vBinding.seekBar.alpha = if (isChecked) 0.4f else 1f
|
||||
vBinding.currentSpeedLabel.alpha = if (isChecked) 0.4f else 1f
|
||||
}
|
||||
viewBinding.seekBar.updateSpeed(1.0f)
|
||||
vBinding.seekBar.updateSpeed(1.0f)
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.playback_speed)
|
||||
.setView(viewBinding.root)
|
||||
.setView(vBinding.root)
|
||||
.setPositiveButton("OK") { _: DialogInterface?, _: Int ->
|
||||
val newSpeed = if (viewBinding.useGlobalCheckbox.isChecked) FeedPreferences.SPEED_USE_GLOBAL
|
||||
else viewBinding.seekBar.currentSpeed
|
||||
val newSpeed = if (vBinding.useGlobalCheckbox.isChecked) FeedPreferences.SPEED_USE_GLOBAL
|
||||
else vBinding.seekBar.currentSpeed
|
||||
saveFeedPreferences { feedPreferences: FeedPreferences ->
|
||||
feedPreferences.playSpeed = newSpeed
|
||||
}
|
||||
|
@ -522,7 +520,6 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
|
||||
@OptIn(UnstableApi::class)
|
||||
private abstract inner class SubscriptionsAdapter<T : RecyclerView.ViewHolder?> : SelectableAdapter<T>(activity as MainActivity), View.OnCreateContextMenuListener {
|
||||
|
||||
protected var feedList: List<Feed>
|
||||
var selectedItem: Feed? = null
|
||||
protected var longPressedPosition: Int = 0 // used to init actionMode
|
||||
|
@ -701,29 +698,25 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
private inner class ViewHolderExpanded(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val binding = SubscriptionItemBinding.bind(itemView)
|
||||
val count: TextView = binding.countLabel
|
||||
|
||||
val coverImage: ImageView = binding.coverImage
|
||||
val infoCard: LinearLayout = binding.infoCard
|
||||
val selectView: FrameLayout = binding.selectContainer
|
||||
val selectCheckbox: CheckBox = binding.selectCheckBox
|
||||
|
||||
private val errorIcon: View = binding.errorIcon
|
||||
|
||||
fun bind(drawerItem: Feed) {
|
||||
fun bind(feed: Feed) {
|
||||
val drawable: Drawable? = AppCompatResources.getDrawable(selectView.context, R.drawable.ic_checkbox_background)
|
||||
selectView.background = drawable // Setting this in XML crashes API <= 21
|
||||
binding.titleLabel.text = drawerItem.title
|
||||
binding.producerLabel.text = drawerItem.author
|
||||
coverImage.contentDescription = drawerItem.title
|
||||
binding.titleLabel.text = feed.title
|
||||
binding.producerLabel.text = feed.author
|
||||
coverImage.contentDescription = feed.title
|
||||
coverImage.setImageDrawable(null)
|
||||
|
||||
val counter = drawerItem.episodes.size
|
||||
count.text = NumberFormat.getInstance().format(counter.toLong()) + " episodes"
|
||||
count.text = NumberFormat.getInstance().format(feed.episodes.size.toLong()) + " episodes"
|
||||
count.visibility = View.VISIBLE
|
||||
|
||||
val mainActRef = (activity as MainActivity)
|
||||
val coverLoader = CoverLoader(mainActRef)
|
||||
val feed: Feed = drawerItem
|
||||
coverLoader.withUri(feed.imageUrl)
|
||||
errorIcon.visibility = if (feed.lastUpdateFailed) View.VISIBLE else View.GONE
|
||||
|
||||
|
@ -755,20 +748,18 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
|
||||
private val errorIcon: View = binding.errorIcon
|
||||
|
||||
fun bind(drawerItem: Feed) {
|
||||
fun bind(feed: Feed) {
|
||||
val drawable: Drawable? = AppCompatResources.getDrawable(selectView.context, R.drawable.ic_checkbox_background)
|
||||
selectView.background = drawable // Setting this in XML crashes API <= 21
|
||||
title.text = drawerItem.title
|
||||
coverImage.contentDescription = drawerItem.title
|
||||
title.text = feed.title
|
||||
coverImage.contentDescription = feed.title
|
||||
coverImage.setImageDrawable(null)
|
||||
|
||||
val counter = drawerItem.episodes.size
|
||||
count.text = NumberFormat.getInstance().format(counter.toLong())
|
||||
count.text = NumberFormat.getInstance().format(feed.episodes.size.toLong())
|
||||
count.visibility = View.VISIBLE
|
||||
|
||||
val mainActRef = (activity as MainActivity)
|
||||
val coverLoader = CoverLoader(mainActRef)
|
||||
val feed: Feed = drawerItem
|
||||
coverLoader.withUri(feed.imageUrl)
|
||||
errorIcon.visibility = if (feed.lastUpdateFailed) View.VISIBLE else View.GONE
|
||||
|
||||
|
@ -800,30 +791,6 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = SubscriptionsFragment::class.simpleName ?: "Anonymous"
|
||||
|
||||
private const val KEY_UP_ARROW = "up_arrow"
|
||||
private const val ARGUMENT_FOLDER = "folder"
|
||||
|
||||
private val tags: MutableList<String> = mutableListOf()
|
||||
|
||||
fun newInstance(folderTitle: String?): SubscriptionsFragment {
|
||||
val fragment = SubscriptionsFragment()
|
||||
val args = Bundle()
|
||||
args.putString(ARGUMENT_FOLDER, folderTitle)
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
|
||||
fun resetTags() {
|
||||
tags.clear()
|
||||
tags.add("Untagged")
|
||||
tags.add("All")
|
||||
tags.addAll(getTags())
|
||||
}
|
||||
}
|
||||
|
||||
class PreferenceListDialog(private var context: Context, private val title: String) {
|
||||
private var onPreferenceChangedListener: OnPreferenceChangedListener? = null
|
||||
private var selectedPos = 0
|
||||
|
@ -882,4 +849,19 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
this.onPreferenceChangedListener = onPreferenceChangedListener
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = SubscriptionsFragment::class.simpleName ?: "Anonymous"
|
||||
|
||||
private const val KEY_UP_ARROW = "up_arrow"
|
||||
private const val ARGUMENT_FOLDER = "folder"
|
||||
|
||||
fun newInstance(folderTitle: String?): SubscriptionsFragment {
|
||||
val fragment = SubscriptionsFragment()
|
||||
val args = Bundle()
|
||||
args.putString(ARGUMENT_FOLDER, folderTitle)
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ open class EpisodeViewHolder(private val activity: MainActivity, parent: ViewGro
|
|||
}
|
||||
|
||||
fun bind(item: Episode) {
|
||||
// Logd(TAG, "in bind: ${item.title} ${item.isFavorite} ${item.isPlayed()}")
|
||||
this.episode = item
|
||||
placeholder.text = item.feed?.title
|
||||
title.text = item.title
|
||||
|
|
|
@ -42,4 +42,9 @@
|
|||
android:icon="@drawable/ic_star"
|
||||
android:title="@string/add_to_favorite_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/remove_favorite_batch"
|
||||
android:icon="@drawable/ic_star_border"
|
||||
android:title="@string/remove_from_favorite_label" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<item
|
||||
android:id="@+id/show_video"
|
||||
android:icon="@drawable/baseline_fullscreen_24"
|
||||
android:title="@string/add_to_favorite_label"
|
||||
android:title="@string/show_video_label"
|
||||
android:visible="false"
|
||||
custom:showAsAction="always">
|
||||
</item>
|
||||
|
|
|
@ -22,9 +22,4 @@
|
|||
android:title="@string/refresh_label"
|
||||
android:menuCategory="container"
|
||||
custom:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/subscriptions_filter"
|
||||
android:title="@string/filter"
|
||||
android:visible="false"
|
||||
custom:showAsAction="never"/>
|
||||
</menu>
|
||||
|
|
13
changelog.md
13
changelog.md
|
@ -1,3 +1,16 @@
|
|||
## 6.0.4
|
||||
|
||||
* bug fix on ShareDialog having no argument
|
||||
* tuned and fixed menu issues in EpisodeIndo and PlayerDetailed views
|
||||
* corrected current order in FeedEpisode sort dialog
|
||||
* fixed sorting in Subscriptions view
|
||||
* fixed tags spinner update issue in Subscriptions view
|
||||
* made various episodes list views to reflect change on status changes of episodes
|
||||
* fixed DB write error when deleting a feed
|
||||
* fixed illegal index error in AllEpisodes and History views when the list is empty
|
||||
* synchronized feeds list update when adding or deleting multiple feeds
|
||||
* added "Remove from favorites" in speed-dial menu
|
||||
|
||||
## 6.0.3
|
||||
|
||||
* minor class restructuring
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
Version 6.0.4 brings several changes:
|
||||
|
||||
* bug fix on ShareDialog having no argument
|
||||
* tuned and fixed menu issues in EpisodeIndo and PlayerDetailed views
|
||||
* corrected current order in FeedEpisode sort dialog
|
||||
* fixed sorting in Subscriptions view
|
||||
* fixed tags spinner update issue in Subscriptions view
|
||||
* made various episodes list views to reflect change on status changes of episodes
|
||||
* fixed DB write error when deleting a feed
|
||||
* fixed illegal index error in AllEpisodes and History views when the list is empty
|
||||
* synchronized feeds list update when adding or deleting multiple feeds
|
||||
* added "Remove from favorites" in speed-dial menu
|
Loading…
Reference in New Issue