diff --git a/app/build.gradle b/app/build.gradle index 6cce4a9a..61a32456 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -125,8 +125,8 @@ android { buildConfig true } defaultConfig { - versionCode 3020207 - versionName "6.0.7" + versionCode 3020208 + versionName "6.0.8" applicationId "ac.mdiq.podcini.R" def commit = "" diff --git a/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt b/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt index b36b595c..9df8b801 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt @@ -52,7 +52,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() { override fun downloadNow(context: Context, item: Episode, ignoreConstraints: Boolean) { Logd(TAG, "starting downloadNow") - val workRequest: OneTimeWorkRequest.Builder = getRequest(context, item) + val workRequest: OneTimeWorkRequest.Builder = getRequest(item) workRequest.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) if (ignoreConstraints) workRequest.setConstraints(Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) else workRequest.setConstraints(constraints) @@ -63,7 +63,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() { override fun download(context: Context, item: Episode) { Logd(TAG, "starting download") - val workRequest: OneTimeWorkRequest.Builder = getRequest(context, item) + val workRequest: OneTimeWorkRequest.Builder = getRequest(item) workRequest.setConstraints(constraints) if (item.media?.downloadUrl != null) WorkManager.getInstance(context).enqueueUniqueWork(item.media!!.downloadUrl!!, ExistingWorkPolicy.KEEP, workRequest.build()) @@ -108,7 +108,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() { return constraints.build() } - @OptIn(UnstableApi::class) private fun getRequest(context: Context, item: Episode): OneTimeWorkRequest.Builder { + @OptIn(UnstableApi::class) private fun getRequest(item: Episode): OneTimeWorkRequest.Builder { Logd(TAG, "starting getRequest") val workRequest: OneTimeWorkRequest.Builder = OneTimeWorkRequest.Builder(EpisodeDownloadWorker::class.java) .setInitialDelay(0L, TimeUnit.MILLISECONDS) @@ -208,7 +208,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() { if (dest.exists()) { try { - media.fileUrl = request.destination + media.setfileUrlOrNull(request.destination) Episodes.persistEpisodeMedia(media) } catch (e: Exception) { Log.e(TAG, "performDownload Exception in writeFileUrl: " + e.message) @@ -353,8 +353,10 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() { } // media.setDownloaded modifies played state val broadcastUnreadStateUpdate = media.episode != null && media.episode!!.isNew - media.downloaded = true - media.fileUrl = request.destination +// media.downloaded = true + media.setIsDownloaded() + Logd(TAG, "media.episode.isNew: ${media.episode?.isNew} ${media.episode?.playState}") + media.setfileUrlOrNull(request.destination) if (request.destination != null) media.size = File(request.destination).length() media.checkEmbeddedPicture() // enforce check @@ -388,7 +390,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() { // we've received the media, we don't want to autodownload it again if (item != null) { item.disableAutoDownload() - Logd(TAG, "persisting episode downloaded ${item.title} ${item.media?.fileUrl} ${item.media?.downloaded}") + Logd(TAG, "persisting episode downloaded ${item.title} ${item.media?.fileUrl} ${item.media?.downloaded} ${item.isNew}") // setFeedItem() signals that the item has been updated, // so we do it after the enclosing media has been updated above, // to ensure subscribers will get the updated EpisodeMedia as well diff --git a/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt b/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt index a63d6171..c400ce09 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt @@ -550,13 +550,14 @@ class PlaybackService : MediaSessionService() { } override fun onDestroy() { - super.onDestroy() Logd(TAG, "Service is about to be destroyed") isRunning = false currentMediaType = MediaType.UNKNOWN castStateListener.destroy() + currentitem = null + LocalMediaPlayer.cleanup() mediaSession?.run { player.release() @@ -573,6 +574,8 @@ class PlaybackService : MediaSessionService() { unregisterReceiver(bluetoothStateUpdated) unregisterReceiver(audioBecomingNoisy) taskManager.shutdown() + + super.onDestroy() } fun isServiceReady(): Boolean { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/preferences/fragments/SynchronizationPreferencesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/preferences/fragments/SynchronizationPreferencesFragment.kt index 43c9b256..b372e2e4 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/preferences/fragments/SynchronizationPreferencesFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/preferences/fragments/SynchronizationPreferencesFragment.kt @@ -605,8 +605,8 @@ class SynchronizationPreferencesFragment : PreferenceFragmentCompat() { } override fun onDestroy() { - super.onDestroy() cancelFlowEvents() + super.onDestroy() } @OptIn(UnstableApi::class) override fun onResume() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Episodes.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Episodes.kt index 5aed5ac5..7af11979 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Episodes.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/Episodes.kt @@ -108,6 +108,7 @@ object Episodes { Logd(TAG, String.format(Locale.US, "Requested to delete EpisodeMedia [id=%d, title=%s, downloaded=%s", media.id, media.getEpisodeTitle(), media.downloaded)) var localDelete = false val url = media.fileUrl + var episode = episode when { url != null && url.startsWith("content://") -> { // Local feed @@ -116,8 +117,8 @@ object Episodes { EventFlow.postEvent(FlowEvent.MessageEvent(context.getString(R.string.delete_local_failed))) return episode } - upsertBlk(episode) { - it.media?.fileUrl = null + episode = upsertBlk(episode) { + it.media?.setfileUrlOrNull(null) if (media.downloadUrl.isNullOrEmpty()) it.media = null } localDelete = true @@ -131,9 +132,9 @@ object Episodes { EventFlow.postEvent(evt) return episode } - upsertBlk(episode) { + episode = upsertBlk(episode) { it.media?.downloaded = false - it.media?.fileUrl = null + it.media?.setfileUrlOrNull(null) it.media?.hasEmbeddedPicture = false if (media.downloadUrl.isNullOrEmpty()) it.media = null } @@ -209,10 +210,10 @@ object Episodes { fun persistEpisodeMedia(media: EpisodeMedia) : Job { Logd(TAG, "persistEpisodeMedia called") return runOnIOScope { - val episode = media.episode + var episode = media.episode if (episode != null) { episode.media = media - upsert(episode) {} + episode = upsert(episode) {} EventFlow.postEvent(FlowEvent.EpisodeEvent.updated(episode)) } else Log.e(TAG, "persistEpisodeMedia media.episode is null") } diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/RealmDB.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/RealmDB.kt index 22f72894..3e661a2b 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/storage/database/RealmDB.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/database/RealmDB.kt @@ -45,7 +45,7 @@ object RealmDB { if (BuildConfig.DEBUG) { val stackTrace = Thread.currentThread().stackTrace val caller = if (stackTrace.size > 3) stackTrace[3] else null - Logd(TAG, "${caller?.className}.${caller?.methodName} upsert: ${entity.javaClass.simpleName}") + Logd(TAG, "${caller?.className}.${caller?.methodName} unmanaged: ${entity.javaClass.simpleName}") } return if (entity.isManaged()) realm.copyFromRealm(entity) else entity } diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeMedia.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeMedia.kt index 415cb848..83d9e259 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeMedia.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeMedia.kt @@ -19,18 +19,19 @@ class EpisodeMedia: EmbeddedRealmObject, Playable { var id: Long = 0L // same as the episode id var fileUrl: String? = null - set(value) { - field = value - if (value == null) downloaded = false - } +// set(value) { +// field = value +// if (value == null) downloaded = false +// } var downloadUrl: String? = null var downloaded: Boolean = false - set(value) { - field = value - if (value && episode?.isNew == true) episode!!.setPlayed(false) - } +// set(value) { +// Logd(TAG, "setting downloaded: $value ${episode?.isNew}") +// field = value +// if (value && episode?.isNew == true) episode!!.setPlayed(false) +// } @get:JvmName("getDurationProperty") @set:JvmName("setDurationProperty") @@ -88,9 +89,8 @@ class EpisodeMedia: EmbeddedRealmObject, Playable { this.episode = i this.size = size this.mimeType = mime_type - fileUrl = null + setfileUrlOrNull(null) this.downloadUrl = download_url - downloaded = false } constructor(id: Long, item: Episode?, duration: Int, position: Int, @@ -108,20 +108,12 @@ class EpisodeMedia: EmbeddedRealmObject, Playable { this.playbackCompletionDate = playbackCompletionDate?.clone() as? Date this.playbackCompletionTime = playbackCompletionDate?.time ?: 0 this.lastPlayedTime = lastPlayedTime - this.fileUrl = file_url + setfileUrlOrNull(file_url) this.downloadUrl = download_url - this.downloaded = downloaded + if (downloaded) setIsDownloaded() + else this.downloaded = downloaded } -// constructor(id: Long, item: Episode?, duration: Int, position: Int, -// size: Long, mime_type: String?, file_url: String?, download_url: String?, -// downloaded: Boolean, playbackCompletionDate: Date?, played_duration: Int, -// hasEmbeddedPicture: Boolean?, lastPlayedTime: Long) -// : this(id, item, duration, position, size, mime_type, file_url, download_url, downloaded, playbackCompletionDate, played_duration, lastPlayedTime) { -// -// this.hasEmbeddedPicture = hasEmbeddedPicture -// } - fun getHumanReadableIdentifier(): String? { return if (episode?.title != null) episode!!.title else downloadUrl } @@ -158,6 +150,16 @@ class EpisodeMedia: EmbeddedRealmObject, Playable { return FEEDFILETYPE_FEEDMEDIA } + fun setIsDownloaded() { + downloaded = true + if (episode?.isNew == true) episode!!.setPlayed(false) + } + + fun setfileUrlOrNull(url: String?) { + fileUrl = url + if (url == null) downloaded = false + } + override fun getDuration(): Int { return duration } diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Feed.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Feed.kt index 78222f48..6219db3d 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Feed.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/Feed.kt @@ -40,10 +40,10 @@ class Feed : RealmObject { */ @FullText var customTitle: String? = null - set(value) { - field = if (value == null || value == eigenTitle) null - else value - } +// set(value) { +// field = if (value == null || value == eigenTitle) null +// else value +// } var link: String? = null @@ -163,7 +163,7 @@ class Feed : RealmObject { this.fileUrl = fileUrl this.downloadUrl = downloadUrl this.eigenTitle = title - this.customTitle = customTitle + setCustomTitle1(customTitle) this.lastUpdate = lastUpdate this.link = link this.description = description @@ -210,6 +210,10 @@ class Feed : RealmObject { preferences = FeedPreferences(0, false, FeedPreferences.AutoDeleteAction.GLOBAL, VolumeAdaptionSetting.OFF, username, password) } + fun setCustomTitle1(value: String?) { + customTitle = if (value == null || value == eigenTitle) null else value + } + fun getTextIdentifier(): String? { return when { !customTitle.isNullOrEmpty() -> customTitle diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/utils/ChapterUtils.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/utils/ChapterUtils.kt index 3109b59e..e7b0f307 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/storage/utils/ChapterUtils.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/utils/ChapterUtils.kt @@ -246,5 +246,4 @@ object ChapterUtils { } return listOf() } - } diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/EpisodeMultiSelectHandler.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/EpisodeMultiSelectHandler.kt index d30a50b5..4d828786 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/EpisodeMultiSelectHandler.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/EpisodeMultiSelectHandler.kt @@ -36,7 +36,7 @@ class EpisodeMultiSelectHandler(private val activity: MainActivity, private val showMessage(R.plurals.marked_unread_batch_label, items.size) } R.id.download_batch -> downloadChecked(items) - R.id.delete_batch -> LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(activity, items) { deleteChecked(items) } + R.id.delete_batch -> deleteChecked(items) else -> Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=$actionId") } } @@ -57,18 +57,6 @@ class EpisodeMultiSelectHandler(private val activity: MainActivity, private val showMessage(R.plurals.removed_from_queue_batch_label, checkedIds.size) } -// private fun markedCheckedPlayed(items: List) { -//// val checkedIds = getSelectedIds(items) -// DBWriter.markItemsPlayed(FeedItem.PLAYED, *items.toTypedArray()) -// showMessage(R.plurals.marked_read_batch_label, items.size) -// } -// -// private fun markedCheckedUnplayed(items: List) { -//// val checkedIds = getSelectedIds(items) -// DBWriter.markItemsPlayed(FeedItem.UNPLAYED, *items.toTypedArray()) -// showMessage(R.plurals.marked_unread_batch_label, items.size) -// } - private fun markFavorite(items: List, stat: Boolean) { for (item in items) { Episodes.setFavorite(item, true) @@ -85,14 +73,8 @@ class EpisodeMultiSelectHandler(private val activity: MainActivity, private val } private fun deleteChecked(items: List) { - var countHasMedia = 0 - for (feedItem in items) { - if (feedItem.media != null && feedItem.media!!.downloaded) { - countHasMedia++ - deleteMediaOfEpisode(activity, feedItem) - } - } - showMessage(R.plurals.deleted_multi_episode_batch_label, countHasMedia) + LocalDeleteModal.deleteEpisodesWarnLocal(activity, items) + showMessage(R.plurals.deleted_multi_episode_batch_label, items.size) } private fun showMessage(@PluralsRes msgId: Int, numItems: Int) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/actionbutton/DeleteActionButton.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/actionbutton/DeleteActionButton.kt index c6ff3734..54a1a787 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/actionbutton/DeleteActionButton.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/actionbutton/DeleteActionButton.kt @@ -1,11 +1,10 @@ package ac.mdiq.podcini.ui.actions.actionbutton +import ac.mdiq.podcini.R +import ac.mdiq.podcini.storage.model.Episode +import ac.mdiq.podcini.ui.utils.LocalDeleteModal.deleteEpisodesWarnLocal import android.content.Context import android.view.View -import ac.mdiq.podcini.R -import ac.mdiq.podcini.storage.database.Episodes.deleteMediaOfEpisode -import ac.mdiq.podcini.storage.model.Episode -import ac.mdiq.podcini.ui.utils.LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary import androidx.media3.common.util.UnstableApi class DeleteActionButton(item: Episode) : EpisodeActionButton(item) { @@ -16,7 +15,7 @@ class DeleteActionButton(item: Episode) : EpisodeActionButton(item) { return R.drawable.ic_delete } @UnstableApi override fun onClick(context: Context) { - showLocalFeedDeleteWarningIfNecessary(context, listOf(item)) { deleteMediaOfEpisode(context, item) } + deleteEpisodesWarnLocal(context, listOf(item)) } override val visibility: Int diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/actionbutton/TTSActionButton.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/actionbutton/TTSActionButton.kt index 4d6f286b..f4d813f9 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/actionbutton/TTSActionButton.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/actionbutton/TTSActionButton.kt @@ -132,7 +132,8 @@ class TTSActionButton(item: Episode) : EpisodeActionButton(item) { Logd(TAG, "saving TTS to file $mFilename") val media = EpisodeMedia(item, null, 0, "audio/*") media.fileUrl = mFilename - media.downloaded = true +// media.downloaded = true + media.setIsDownloaded() item.media = media // DBWriter.persistFeedMedia(media) item.setTranscriptIfLonger(readerText) diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/menuhandler/EpisodeMenuHandler.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/menuhandler/EpisodeMenuHandler.kt index 0d6fb9d2..69e3b0bd 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/menuhandler/EpisodeMenuHandler.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/menuhandler/EpisodeMenuHandler.kt @@ -137,9 +137,7 @@ object EpisodeMenuHandler { when (menuItemId) { R.id.skip_episode_item -> context.sendBroadcast(MediaButtonReceiver.createIntent(context, KeyEvent.KEYCODE_MEDIA_NEXT)) R.id.remove_item -> { - LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(context, listOf(selectedItem)) { - if (selectedItem.media != null) deleteMediaOfEpisode(context, selectedItem) - } + LocalDeleteModal.deleteEpisodesWarnLocal(context, listOf(selectedItem)) } R.id.mark_read_item -> { selectedItem.setPlayed(true) diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/swipeactions/DeleteSwipeAction.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/swipeactions/DeleteSwipeAction.kt index 933264b7..70a3859d 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/swipeactions/DeleteSwipeAction.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/actions/swipeactions/DeleteSwipeAction.kt @@ -1,13 +1,12 @@ package ac.mdiq.podcini.ui.actions.swipeactions +import ac.mdiq.podcini.R +import ac.mdiq.podcini.storage.model.Episode +import ac.mdiq.podcini.storage.model.EpisodeFilter +import ac.mdiq.podcini.ui.utils.LocalDeleteModal.deleteEpisodesWarnLocal import android.content.Context import androidx.fragment.app.Fragment import androidx.media3.common.util.UnstableApi -import ac.mdiq.podcini.R -import ac.mdiq.podcini.storage.database.Episodes.deleteMediaOfEpisode -import ac.mdiq.podcini.storage.model.Episode -import ac.mdiq.podcini.storage.model.EpisodeFilter -import ac.mdiq.podcini.ui.utils.LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary class DeleteSwipeAction : SwipeAction { override fun getId(): String { @@ -29,9 +28,7 @@ class DeleteSwipeAction : SwipeAction { @UnstableApi override fun performAction(item: Episode, fragment: Fragment, filter: EpisodeFilter) { if (!item.isDownloaded && item.feed?.isLocalFeed != true) return - showLocalFeedDeleteWarningIfNecessary(fragment.requireContext(), listOf(item)) { - deleteMediaOfEpisode(fragment.requireContext(), item) - } + deleteEpisodesWarnLocal(fragment.requireContext(), listOf(item)) } override fun willRemove(filter: EpisodeFilter, item: Episode): Boolean { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/BugReportActivity.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/BugReportActivity.kt index 2e8354a1..f7783b20 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/BugReportActivity.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/BugReportActivity.kt @@ -70,8 +70,8 @@ class BugReportActivity : AppCompatActivity() { } override fun onDestroy() { - super.onDestroy() _binding = null + super.onDestroy() } override fun onCreateOptionsMenu(menu: Menu): Boolean { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/MainActivity.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/MainActivity.kt index 6c1c25c1..8d350182 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/MainActivity.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/MainActivity.kt @@ -364,11 +364,11 @@ class MainActivity : CastEnabledActivity() { override fun onDestroy() { Logd(TAG, "onDestroy") - super.onDestroy() // WorkManager.getInstance(this).pruneWork() _binding = null // realm.close() drawerLayout?.removeDrawerListener(drawerToggle!!) + super.onDestroy() } private fun checkFirstLaunch() { @@ -391,6 +391,7 @@ class MainActivity : CastEnabledActivity() { } fun setPlayerVisible(visible_: Boolean?) { + Logd(TAG, "setPlayerVisible $visible_") val visible = visible_ ?: (bottomSheet.state != BottomSheetBehavior.STATE_COLLAPSED) bottomSheet.setLocked(!visible) diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/OpmlImportActivity.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/OpmlImportActivity.kt index db6e292a..23ccf177 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/OpmlImportActivity.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/OpmlImportActivity.kt @@ -251,8 +251,8 @@ class OpmlImportActivity : AppCompatActivity() { } override fun onDestroy() { - super.onDestroy() _binding = null + super.onDestroy() } companion object { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/PreferenceActivity.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/PreferenceActivity.kt index 5f8671d1..56152d5b 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/PreferenceActivity.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/PreferenceActivity.kt @@ -139,8 +139,8 @@ class PreferenceActivity : AppCompatActivity(), SearchPreferenceResultListener { } override fun onDestroy() { - super.onDestroy() _binding = null + super.onDestroy() } private var eventSink: Job? = null diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt index 66eeb1a1..2bf7cff1 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt @@ -138,8 +138,8 @@ class SelectSubscriptionActivity : AppCompatActivity() { } override fun onDestroy() { - super.onDestroy() _binding = null + super.onDestroy() } companion object { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/VideoplayerActivity.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/VideoplayerActivity.kt index 537d0293..9b8a3298 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/VideoplayerActivity.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/VideoplayerActivity.kt @@ -21,6 +21,8 @@ import ac.mdiq.podcini.ui.dialog.ShareDialog import ac.mdiq.podcini.ui.dialog.SleepTimerDialog import ac.mdiq.podcini.ui.dialog.VariableSpeedDialog import ac.mdiq.podcini.ui.fragment.ChaptersFragment +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.fragment.VideoEpisodeFragment import ac.mdiq.podcini.ui.utils.PictureInPictureUtil import ac.mdiq.podcini.util.IntentUtils.openInBrowser @@ -136,12 +138,12 @@ class VideoplayerActivity : CastEnabledActivity() { } override fun onDestroy() { - super.onDestroy() window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN) window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN) _binding = null + super.onDestroy() } @@ -419,8 +421,9 @@ class VideoplayerActivity : CastEnabledActivity() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } @UnstableApi private fun setupAudioTracks() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/WidgetConfigActivity.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/WidgetConfigActivity.kt index 069e2f33..73ec35a6 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/WidgetConfigActivity.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/activity/WidgetConfigActivity.kt @@ -89,9 +89,9 @@ class WidgetConfigActivity : AppCompatActivity() { } override fun onDestroy() { - super.onDestroy() _binding = null _wpBinding = null + super.onDestroy() } private fun setInitialState() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/adapter/EpisodesAdapter.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/adapter/EpisodesAdapter.kt index ba839e43..016a7161 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/adapter/EpisodesAdapter.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/adapter/EpisodesAdapter.kt @@ -14,7 +14,6 @@ import android.app.Activity import android.os.Bundle import android.view.* import androidx.media3.common.util.UnstableApi - import java.lang.ref.WeakReference /** @@ -51,6 +50,12 @@ open class EpisodesAdapter(mainActivity: MainActivity) setHasStableIds(true) } + fun clearData() { + episodes = listOf() + feed = null + notifyDataSetChanged() + } + fun setDummyViews(dummyViews: Int) { this.dummyViews = dummyViews notifyDataSetChanged() @@ -90,8 +95,7 @@ open class EpisodesAdapter(mainActivity: MainActivity) val item: Episode = unmanaged(episodes[pos]) // val item: Episode = episodes[pos] - if (feed != null) item.feed = feed - else item.feed = episodes[pos].feed + item.feed = feed ?: episodes[pos].feed holder.bind(item) // holder.infoCard.setOnCreateContextMenuListener(this) diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt index f33c0a24..5c53110d 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt @@ -17,7 +17,7 @@ class OnlineFeedsAdapter(private val context: Context, objects: List(context, 0, objects) { // List holding the podcasts found in the search - private val data: List = objects + private val data: MutableList = objects.toMutableList() @UnstableApi override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val podcast: PodcastSearchResult = data[position] @@ -65,6 +65,10 @@ class OnlineFeedsAdapter(private val context: Context, objects: List feed = unmanaged(feed) val newTitle = binding.editText.text.toString() - feed.customTitle = newTitle + feed.setCustomTitle1(newTitle) upsertBlk(feed) {} } .setNeutralButton(R.string.reset, null) diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt index 9b0b1bda..6cfe9a13 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt @@ -4,6 +4,7 @@ import ac.mdiq.podcini.R import ac.mdiq.podcini.databinding.FilterDialogBinding import ac.mdiq.podcini.databinding.FilterDialogRowBinding import ac.mdiq.podcini.storage.model.EpisodeFilter +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion.TAG import ac.mdiq.podcini.util.Logd import android.app.Dialog import android.content.DialogInterface @@ -98,8 +99,9 @@ abstract class EpisodeFilterDialog : BottomSheetDialogFragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } private fun setupFullHeight(bottomSheetDialog: BottomSheetDialog) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeSortDialog.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeSortDialog.kt index d2511bb4..cca097ea 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeSortDialog.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeSortDialog.kt @@ -5,6 +5,8 @@ import ac.mdiq.podcini.databinding.SortDialogBinding import ac.mdiq.podcini.databinding.SortDialogItemActiveBinding import ac.mdiq.podcini.databinding.SortDialogItemBinding import ac.mdiq.podcini.storage.model.EpisodeSortOrder +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion.TAG +import ac.mdiq.podcini.util.Logd import android.app.Dialog import android.content.DialogInterface import android.os.Bundle @@ -98,8 +100,9 @@ open class EpisodeSortDialog : BottomSheetDialogFragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } private fun setupFullHeight(bottomSheetDialog: BottomSheetDialog) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/FeedSortDialogNew.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/FeedSortDialogNew.kt index f138acdc..7b848384 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/FeedSortDialogNew.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/FeedSortDialogNew.kt @@ -9,6 +9,8 @@ import ac.mdiq.podcini.preferences.UserPreferences.feedOrderDir import ac.mdiq.podcini.preferences.UserPreferences.setFeedOrder import ac.mdiq.podcini.storage.model.FeedSortOrder import ac.mdiq.podcini.storage.model.FeedSortOrder.Companion.getSortOrder +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.util.Logd import ac.mdiq.podcini.util.event.EventFlow import ac.mdiq.podcini.util.event.FlowEvent @@ -40,6 +42,7 @@ open class FeedSortDialogNew : BottomSheetDialogFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { _binding = SortDialogBinding.inflate(inflater) + binding.gridLayout.columnCount = 1 populateList() binding.keepSortedCheckbox.setOnCheckedChangeListener { _: CompoundButton?, _: Boolean -> this@FeedSortDialogNew.onSelectionChanged() } return binding.root @@ -117,8 +120,9 @@ open class FeedSortDialogNew : BottomSheetDialogFragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } private fun setupFullHeight(bottomSheetDialog: BottomSheetDialog) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/ShareDialog.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/ShareDialog.kt index 8583a438..5f288b2e 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/ShareDialog.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/ShareDialog.kt @@ -13,6 +13,8 @@ import ac.mdiq.podcini.util.ShareUtils.shareFeedItemLinkWithDownloadLink import ac.mdiq.podcini.util.ShareUtils.shareMediaDownloadLink import ac.mdiq.podcini.databinding.ShareEpisodeDialogBinding import ac.mdiq.podcini.storage.model.Episode +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion.TAG +import ac.mdiq.podcini.util.Logd class ShareDialog : BottomSheetDialogFragment() { private lateinit var ctx: Context @@ -83,8 +85,9 @@ class ShareDialog : BottomSheetDialogFragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } fun setItem(item_: Episode) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/SleepTimerDialog.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/SleepTimerDialog.kt index e7319170..ce9e48fb 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/SleepTimerDialog.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/SleepTimerDialog.kt @@ -18,8 +18,10 @@ import ac.mdiq.podcini.preferences.SleepTimerPreferences.shakeToReset import ac.mdiq.podcini.preferences.SleepTimerPreferences.timerMillis import ac.mdiq.podcini.preferences.SleepTimerPreferences.vibrate import ac.mdiq.podcini.storage.model.Playable +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion.TAG import ac.mdiq.podcini.ui.utils.ThemeUtils.getColorFromAttr import ac.mdiq.podcini.util.Converter.getDurationStringLong +import ac.mdiq.podcini.util.Logd import ac.mdiq.podcini.util.event.EventFlow import ac.mdiq.podcini.util.event.FlowEvent import android.app.Activity @@ -160,8 +162,9 @@ class SleepTimerDialog : DialogFragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } fun extendSleepTimer(extendTime: Long) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt index 4d715fff..811d04e5 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt @@ -11,6 +11,8 @@ import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk import ac.mdiq.podcini.storage.model.Feed import ac.mdiq.podcini.storage.model.FeedPreferences import ac.mdiq.podcini.ui.adapter.SimpleChipAdapter +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.ItemOffsetDecoration import ac.mdiq.podcini.util.Logd import android.app.Dialog @@ -97,8 +99,9 @@ class TagSettingsDialog : DialogFragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } @OptIn(UnstableApi::class) private fun updatePreferencesTags(commonTags: Set) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/VariableSpeedDialog.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/VariableSpeedDialog.kt index 5c50a45a..8346d6c3 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/VariableSpeedDialog.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/VariableSpeedDialog.kt @@ -16,6 +16,8 @@ import ac.mdiq.podcini.storage.database.Feeds.persistFeedPreferences import ac.mdiq.podcini.storage.database.RealmDB.unmanaged import ac.mdiq.podcini.storage.model.EpisodeMedia import ac.mdiq.podcini.storage.model.MediaType +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.ItemOffsetDecoration import ac.mdiq.podcini.ui.view.PlaybackSpeedSeekBar import ac.mdiq.podcini.util.Logd @@ -158,8 +160,9 @@ import java.util.* } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } private fun addCurrentSpeed() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AddFeedFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AddFeedFragment.kt index dadddd4d..bc7afb16 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AddFeedFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AddFeedFragment.kt @@ -10,6 +10,7 @@ import ac.mdiq.podcini.storage.model.Feed import ac.mdiq.podcini.storage.model.EpisodeSortOrder import ac.mdiq.podcini.ui.activity.MainActivity import ac.mdiq.podcini.ui.activity.OpmlImportActivity +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.util.Logd import android.content.* import android.net.Uri @@ -150,8 +151,9 @@ class AddFeedFragment : Fragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } private fun chooseOpmlImportPathResult(uri: Uri?) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AllEpisodesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AllEpisodesFragment.kt index fedc6636..2b6de5a4 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AllEpisodesFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AllEpisodesFragment.kt @@ -12,6 +12,7 @@ import ac.mdiq.podcini.ui.activity.MainActivity import ac.mdiq.podcini.ui.dialog.EpisodeFilterDialog import ac.mdiq.podcini.ui.dialog.EpisodeSortDialog import ac.mdiq.podcini.ui.dialog.SwitchQueueDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.util.Logd import ac.mdiq.podcini.util.event.EventFlow import ac.mdiq.podcini.util.event.FlowEvent @@ -49,6 +50,11 @@ import kotlin.math.min return root } + override fun onDestroyView() { + allEpisodes = listOf() + super.onDestroyView() + } + override fun onStart() { super.onStart() procFlowEvents() @@ -115,6 +121,10 @@ import kotlin.math.min Logd(TAG, "Received event: ${event.TAG}") when (event) { is FlowEvent.AllEpisodesFilterEvent -> onFilterChanged(event) + is FlowEvent.AllEpisodesSortEvent -> { + page = 1 + loadItems() + } else -> {} } } @@ -148,13 +158,14 @@ import kotlin.math.min } override fun onAddItem(title: Int, ascending: EpisodeSortOrder, descending: EpisodeSortOrder, ascendingIsDefault: Boolean) { if (ascending == EpisodeSortOrder.DATE_OLD_NEW || ascending == EpisodeSortOrder.DURATION_SHORT_LONG - || ascending == EpisodeSortOrder.PLAYED_DATE_OLD_NEW || ascending == EpisodeSortOrder.COMPLETED_DATE_OLD_NEW) + || ascending == EpisodeSortOrder.PLAYED_DATE_OLD_NEW || ascending == EpisodeSortOrder.COMPLETED_DATE_OLD_NEW + || ascending == EpisodeSortOrder.EPISODE_TITLE_A_Z) super.onAddItem(title, ascending, descending, ascendingIsDefault) } override fun onSelectionChanged() { super.onSelectionChanged() allEpisodesSortOrder = sortOrder - EventFlow.postEvent(FlowEvent.FeedsSortedEvent()) + EventFlow.postEvent(FlowEvent.AllEpisodesSortEvent()) } } @@ -170,7 +181,6 @@ import kotlin.math.min } } } - companion object { val TAG = AllEpisodesFragment::class.simpleName ?: "Anonymous" const val PREF_NAME: String = "PrefAllEpisodesFragment" diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt index a09452d4..72c65b93 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt @@ -38,6 +38,7 @@ import ac.mdiq.podcini.ui.dialog.MediaPlayerErrorDialog import ac.mdiq.podcini.ui.dialog.SkipPreferenceDialog import ac.mdiq.podcini.ui.dialog.SleepTimerDialog import ac.mdiq.podcini.ui.dialog.VariableSpeedDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.view.ChapterSeekBar import ac.mdiq.podcini.ui.view.PlayButton import ac.mdiq.podcini.util.Converter @@ -145,39 +146,40 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar playerUIView2?.setBackgroundColor(SurfaceColors.getColorForElevation(requireContext(), 8 * resources.displayMetrics.density)) onCollaped() cardViewSeek = binding.cardViewSeek + + initDetailedView() + return binding.root } -// fun initDetailedView() { -// if (playerDetailsFragment == null) { -// val fm = requireActivity().supportFragmentManager -// val transaction = fm.beginTransaction() -// playerDetailsFragment = PlayerDetailsFragment() -// transaction.replace(R.id.itemDescription, playerDetailsFragment!!).commit() -// } -// } - - override fun onDestroyView() { - Logd(TAG, "Fragment destroyed") - super.onDestroyView() - _binding = null - controller?.release() - controller = null - } - - fun onExpanded() { - Logd(TAG, "onExpanded()") + fun initDetailedView() { if (playerDetailsFragment == null) { val fm = requireActivity().supportFragmentManager val transaction = fm.beginTransaction() playerDetailsFragment = PlayerDetailsFragment() transaction.replace(R.id.itemDescription, playerDetailsFragment!!).commit() } - isCollapsed = false - playerUI = playerUI2 - playerUI?.updateUi(currentMedia) - playerUI?.butPlay?.setIsShowPlay(isShowPlay) - playerDetailsFragment?.updateInfo() + } + + override fun onDestroyView() { + Logd(TAG, "Fragment destroyed") + _binding = null + controller?.release() + controller = null + super.onDestroyView() + } + + fun onExpanded() { + Logd(TAG, "onExpanded()") + initDetailedView() +// the function can also be called from MainActivity when a select menu pops up and closes + if (isCollapsed) { + isCollapsed = false + playerUI = playerUI2 + playerUI?.updateUi(currentMedia) + playerUI?.butPlay?.setIsShowPlay(isShowPlay) + playerDetailsFragment?.updateInfo() + } } fun onCollaped() { @@ -340,7 +342,10 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar is FlowEvent.FavoritesEvent -> onFavoriteEvent(event) is FlowEvent.PlayerErrorEvent -> MediaPlayerErrorDialog.show(activity as Activity, event) is FlowEvent.SleepTimerUpdatedEvent -> if (event.isCancelled || event.wasJustEnabled()) loadMediaInfo(false) - is FlowEvent.PlaybackPositionEvent -> playerUI?.onPositionUpdate(event) + is FlowEvent.PlaybackPositionEvent -> { + playerUI?.onPositionUpdate(event) + if (!isCollapsed) playerDetailsFragment?.onPlaybackPositionEvent(event) + } is FlowEvent.SpeedChangedEvent -> playerUI?.updatePlaybackSpeedButton(event) else -> {} } @@ -528,8 +533,9 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar return binding.root } @OptIn(UnstableApi::class) override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } @UnstableApi override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/BaseEpisodesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/BaseEpisodesFragment.kt index 3943c76b..1a6d884f 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/BaseEpisodesFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/BaseEpisodesFragment.kt @@ -20,6 +20,7 @@ import ac.mdiq.podcini.ui.utils.EmptyViewHandler import ac.mdiq.podcini.ui.view.EpisodesRecyclerView import ac.mdiq.podcini.ui.utils.LiftOnScrollListener import ac.mdiq.podcini.storage.utils.EpisodeUtil +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.util.Logd import ac.mdiq.podcini.util.event.EventFlow import ac.mdiq.podcini.util.event.FlowEvent @@ -305,9 +306,12 @@ import kotlinx.coroutines.flow.collectLatest } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + adapter.clearData() adapter.endSelectMode() + episodes.clear() + super.onDestroyView() } override fun onStartSelectMode() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/ChaptersFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/ChaptersFragment.kt index d806bb75..31ea7c35 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/ChaptersFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/ChaptersFragment.kt @@ -15,6 +15,7 @@ import ac.mdiq.podcini.playback.PlaybackController.Companion.curPosition import ac.mdiq.podcini.playback.PlaybackController.Companion.seekTo import ac.mdiq.podcini.storage.model.Chapter import ac.mdiq.podcini.storage.model.EmbeddedChapterImage +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.view.CircularProgressBar import ac.mdiq.podcini.util.Converter.getDurationStringLocalized import ac.mdiq.podcini.util.Converter.getDurationStringLong @@ -133,11 +134,11 @@ class ChaptersFragment : AppCompatDialogFragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null controller?.release() controller = null - + super.onDestroyView() } private var eventSink: Job? = null diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt index 41178c43..ea8234ac 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DiscoveryFragment.kt @@ -64,7 +64,6 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener { private var hidden = false private var needsConfirm = false - /** * Replace adapter data with provided search results from SearchTask. * @@ -131,9 +130,12 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener { } override fun onDestroy() { - super.onDestroy() _binding = null + adapter?.clearData() adapter = null + searchResults = null + topList = null + super.onDestroy() } private fun loadToplist(country: String?) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadLogFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadLogFragment.kt index 3b55a578..e85ae73f 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadLogFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadLogFragment.kt @@ -15,6 +15,7 @@ import ac.mdiq.podcini.storage.model.Feed import ac.mdiq.podcini.ui.actions.actionbutton.DownloadActionButton import ac.mdiq.podcini.ui.activity.MainActivity import ac.mdiq.podcini.ui.dialog.DownloadLogDetailsDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.EmptyViewHandler import ac.mdiq.podcini.ui.utils.ThemeUtils import ac.mdiq.podcini.util.Logd @@ -86,8 +87,10 @@ class DownloadLogFragment : BottomSheetDialogFragment(), OnItemClickListener, To } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + downloadLog = listOf() + super.onDestroyView() } override fun onItemClick(parent: AdapterView<*>?, view: View, position: Int, id: Long) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt index e38b363d..e2a92fc9 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/DownloadsFragment.kt @@ -24,6 +24,7 @@ import ac.mdiq.podcini.ui.adapter.EpisodesAdapter import ac.mdiq.podcini.ui.adapter.SelectableAdapter import ac.mdiq.podcini.ui.dialog.EpisodeSortDialog import ac.mdiq.podcini.ui.dialog.SwitchQueueDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.EmptyViewHandler import ac.mdiq.podcini.ui.utils.LiftOnScrollListener import ac.mdiq.podcini.ui.view.EpisodesRecyclerView @@ -163,10 +164,13 @@ import java.util.* } override fun onDestroyView() { + Logd(TAG, "onDestroyView") _binding = null adapter.endSelectMode() + adapter.clearData() toolbar.setOnMenuItemClickListener(null) toolbar.setOnLongClickListener(null) + episodes = mutableListOf() super.onDestroyView() } @@ -279,7 +283,7 @@ import java.util.* val size: Int = event.episodes.size while (i < size) { val item: Episode = event.episodes[i] - val pos = EpisodeUtil.indexOfItemWithId(episodes.toList(), item.id) + val pos = EpisodeUtil.indexOfItemWithId(episodes, item.id) if (pos >= 0) { episodes.removeAt(pos) val media = item.media diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeHomeFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeHomeFragment.kt index 7bb9f90d..8fc919db 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeHomeFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeHomeFragment.kt @@ -8,6 +8,7 @@ import ac.mdiq.podcini.util.Logd import ac.mdiq.podcini.net.utils.NetworkUtils.fetchHtmlSource import ac.mdiq.podcini.storage.database.Episodes.persistEpisode import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import android.content.Context import android.os.Bundle import android.speech.tts.TextToSpeech @@ -257,7 +258,6 @@ class EpisodeHomeFragment : Fragment() { } @OptIn(UnstableApi::class) override fun onDestroyView() { - super.onDestroyView() Logd(TAG, "onDestroyView") cleatWebview(binding.webView) cleatWebview(binding.readerView) @@ -265,6 +265,7 @@ class EpisodeHomeFragment : Fragment() { tts?.stop() tts?.shutdown() tts = null + super.onDestroyView() } @UnstableApi private fun updateAppearance() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt index 8fb53d7f..7749421b 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/EpisodeInfoFragment.kt @@ -19,6 +19,7 @@ import ac.mdiq.podcini.storage.model.MediaType import ac.mdiq.podcini.ui.actions.actionbutton.* import ac.mdiq.podcini.ui.actions.menuhandler.EpisodeMenuHandler import ac.mdiq.podcini.ui.activity.MainActivity +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.ShownotesCleaner import ac.mdiq.podcini.ui.utils.ThemeUtils import ac.mdiq.podcini.ui.view.ShownotesWebView @@ -230,14 +231,15 @@ import kotlin.math.max } @OptIn(UnstableApi::class) override fun onDestroyView() { - super.onDestroyView() Logd(TAG, "onDestroyView") binding.root.removeView(webvDescription) + episode = null webvDescription.clearHistory() webvDescription.clearCache(true) webvDescription.clearView() webvDescription.destroy() _binding = null + super.onDestroyView() } @UnstableApi private fun onFragmentLoaded() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt index f13426f5..3406e0b0 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt @@ -30,6 +30,7 @@ import ac.mdiq.podcini.ui.activity.MainActivity import ac.mdiq.podcini.ui.adapter.EpisodesAdapter import ac.mdiq.podcini.ui.adapter.SelectableAdapter import ac.mdiq.podcini.ui.dialog.* +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.ToolbarIconTintManager import ac.mdiq.podcini.ui.utils.TransitionEffect import ac.mdiq.podcini.ui.view.viewholder.EpisodeViewHolder @@ -226,18 +227,23 @@ import java.util.concurrent.Semaphore } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null _dialBinding = null - + ioScope.cancel() adapter.endSelectMode() + adapter.clearData() + + feed = null + episodes = mutableListOf() tts?.stop() tts?.shutdown() ttsWorking = false ttsReady = false tts = null + super.onDestroyView() } override fun onSaveInstanceState(outState: Bundle) { @@ -335,8 +341,8 @@ import java.util.concurrent.Semaphore if (item.feedId != feed!!.id) continue val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id) if (pos >= 0) { - episodes.removeAt(pos) - episodes.add(pos, item) + Logd(TAG, "episode event: ${item.title} ${item.playState}") + episodes[pos] = item adapter.notifyItemChangedCompat(pos) } i++ @@ -352,8 +358,7 @@ import java.util.concurrent.Semaphore if (item.feedId != feed!!.id) continue val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id) if (pos >= 0) { - episodes.removeAt(pos) - episodes.add(pos, item) + episodes[pos] = item adapter.notifyItemChangedCompat(pos) // episodes[pos].playState = item.playState // adapter.notifyItemChangedCompat(pos) @@ -375,6 +380,7 @@ import java.util.concurrent.Semaphore val item = event.episode val pos: Int = EpisodeUtil.indexOfItemWithId(episodes, item.id) if (pos >= 0) { + Logd(TAG, "played item: ${item.title} ${item.playState}") episodes[pos] = item adapter.notifyItemChangedCompat(pos) // episodes[pos].playState = item.playState diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt index 2096bb03..1e3ab235 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedInfoFragment.kt @@ -11,6 +11,7 @@ import ac.mdiq.podcini.storage.database.Feeds.updateFeedDownloadURL import ac.mdiq.podcini.storage.model.Feed import ac.mdiq.podcini.storage.model.FeedFunding import ac.mdiq.podcini.ui.activity.MainActivity +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.statistics.FeedStatisticsFragment import ac.mdiq.podcini.ui.statistics.StatisticsFragment import ac.mdiq.podcini.ui.utils.ToolbarIconTintManager @@ -204,9 +205,10 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null -// feed = null + feed = Feed() + super.onDestroyView() } private fun refreshToolbarState() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedSettingsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedSettingsFragment.kt index 7239acca..c75efea2 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedSettingsFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedSettingsFragment.kt @@ -17,6 +17,7 @@ import ac.mdiq.podcini.storage.model.VolumeAdaptionSetting import ac.mdiq.podcini.ui.adapter.SimpleChipAdapter import ac.mdiq.podcini.ui.dialog.AuthenticationDialog import ac.mdiq.podcini.ui.dialog.TagSettingsDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.ItemOffsetDecoration import ac.mdiq.podcini.util.Logd import android.content.Context @@ -65,8 +66,10 @@ class FeedSettingsFragment : Fragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + feed = null + super.onDestroyView() } class FeedSettingsPreferenceFragment : PreferenceFragmentCompat() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/HistoryFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/HistoryFragment.kt index 444809ab..f2092e57 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/HistoryFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/HistoryFragment.kt @@ -12,6 +12,7 @@ import ac.mdiq.podcini.ui.adapter.EpisodesAdapter import ac.mdiq.podcini.ui.dialog.ConfirmationDialog import ac.mdiq.podcini.ui.dialog.DatesFilterDialog import ac.mdiq.podcini.ui.dialog.EpisodeSortDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.view.viewholder.EpisodeViewHolder import ac.mdiq.podcini.util.DateFormatter import ac.mdiq.podcini.util.Logd @@ -86,6 +87,12 @@ import kotlin.math.min cancelFlowEvents() } + override fun onDestroyView() { + allHistory = listOf() + adapter.clearData() + super.onDestroyView() + } + @OptIn(UnstableApi::class) override fun onMenuItemClick(item: MenuItem): Boolean { if (super.onOptionsItemSelected(item)) return true when (item.itemId) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt index f6e9cc83..4c23c28c 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt @@ -19,6 +19,7 @@ import ac.mdiq.podcini.ui.activity.MainActivity import ac.mdiq.podcini.ui.activity.PreferenceActivity import ac.mdiq.podcini.ui.activity.starter.MainActivityStarter import ac.mdiq.podcini.ui.dialog.DrawerPreferencesDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.statistics.StatisticsFragment import ac.mdiq.podcini.ui.utils.ThemeUtils import ac.mdiq.podcini.util.Logd @@ -127,9 +128,10 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null prefs!!.unregisterOnSharedPreferenceChangeListener(this) + super.onDestroyView() } override fun onResume() { @@ -276,7 +278,6 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener { } else return false } @UnstableApi private fun bindNavView(title: String, position: Int, holder: NavHolder) { - Logd(TAG, "bindNavView called") val context = activity ?: return holder.title.text = title // reset for re-use diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineFeedViewFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineFeedViewFragment.kt index 75c7b509..bc8545b9 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineFeedViewFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineFeedViewFragment.kt @@ -164,8 +164,9 @@ import kotlin.concurrent.Volatile } override fun onDestroy() { - super.onDestroy() _binding = null + feeds = null + super.onDestroy() } @OptIn(UnstableApi::class) override fun onSaveInstanceState(outState: Bundle) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt index c056abc3..4617b6e6 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/OnlineSearchFragment.kt @@ -97,10 +97,11 @@ class OnlineSearchFragment : Fragment() { } override fun onDestroy() { - super.onDestroy() _binding = null -// disposable?.dispose() + searchResults = null + adapter?.clearData() adapter = null + super.onDestroy() } private fun setupToolbar(toolbar: MaterialToolbar) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/PlayerDetailsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/PlayerDetailsFragment.kt index 48d4ebc8..ce35ff34 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/PlayerDetailsFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/PlayerDetailsFragment.kt @@ -2,26 +2,22 @@ package ac.mdiq.podcini.ui.fragment import ac.mdiq.podcini.R import ac.mdiq.podcini.databinding.PlayerDetailsFragmentBinding -import ac.mdiq.podcini.storage.utils.ChapterUtils -import ac.mdiq.podcini.storage.utils.ImageResourceUtils import ac.mdiq.podcini.net.utils.NetworkUtils.fetchHtmlSource -import ac.mdiq.podcini.playback.PlaybackController.Companion.curSpeedMultiplier -import ac.mdiq.podcini.playback.base.InTheatre.curMedia import ac.mdiq.podcini.playback.PlaybackController.Companion.curPosition +import ac.mdiq.podcini.playback.PlaybackController.Companion.curSpeedMultiplier import ac.mdiq.podcini.playback.PlaybackController.Companion.seekTo +import ac.mdiq.podcini.playback.base.InTheatre.curMedia import ac.mdiq.podcini.storage.database.Episodes.persistEpisode import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope -import ac.mdiq.podcini.storage.model.Chapter -import ac.mdiq.podcini.storage.model.Episode -import ac.mdiq.podcini.storage.model.EpisodeMedia -import ac.mdiq.podcini.storage.model.Playable -import ac.mdiq.podcini.storage.model.EmbeddedChapterImage +import ac.mdiq.podcini.storage.model.* +import ac.mdiq.podcini.storage.utils.ChapterUtils +import ac.mdiq.podcini.storage.utils.ImageResourceUtils import ac.mdiq.podcini.ui.activity.MainActivity +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.ShownotesCleaner import ac.mdiq.podcini.ui.view.ShownotesWebView import ac.mdiq.podcini.util.DateFormatter import ac.mdiq.podcini.util.Logd -import ac.mdiq.podcini.util.event.EventFlow import ac.mdiq.podcini.util.event.FlowEvent import android.animation.Animator import android.animation.AnimatorListenerAdapter @@ -50,8 +46,9 @@ import coil.request.ErrorResult import coil.request.ImageRequest import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.snackbar.Snackbar -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import net.dankito.readability4j.Readability4J import org.apache.commons.lang3.StringUtils @@ -117,21 +114,24 @@ class PlayerDetailsFragment : Fragment() { override fun onStart() { Logd(TAG, "onStart()") super.onStart() - procFlowEvents() +// procFlowEvents() } override fun onStop() { Logd(TAG, "onStop()") super.onStop() - cancelFlowEvents() +// cancelFlowEvents() } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + prevItem = null + currentItem = null Logd(TAG, "Fragment destroyed") shownoteView.removeAllViews() shownoteView.destroy() + super.onDestroyView() } override fun onContextItemSelected(item: MenuItem): Boolean { @@ -280,6 +280,7 @@ class PlayerDetailsFragment : Fragment() { } private fun refreshChapterData(chapterIndex: Int) { + Logd(TAG, "in refreshChapterData $chapterIndex") if (playable != null && chapterIndex > -1) { if (playable!!.getPosition() > playable!!.getDuration() || chapterIndex >= playable!!.getChapters().size - 1) { displayedChapterIndex = playable!!.getChapters().size - 1 @@ -409,25 +410,25 @@ class PlayerDetailsFragment : Fragment() { savePreference() } - private var eventSink: Job? = null - private fun cancelFlowEvents() { - eventSink?.cancel() - eventSink = null - } - private fun procFlowEvents() { - if (eventSink != null) return - eventSink = lifecycleScope.launch { - EventFlow.events.collectLatest { event -> - Logd(TAG, "Received event: ${event.TAG}") - when (event) { - is FlowEvent.PlaybackPositionEvent -> onEventMainThread(event) - else -> {} - } - } - } - } +// private var eventSink: Job? = null +// private fun cancelFlowEvents() { +// eventSink?.cancel() +// eventSink = null +// } +// private fun procFlowEvents() { +// if (eventSink != null) return +// eventSink = lifecycleScope.launch { +// EventFlow.events.collectLatest { event -> +// Logd(TAG, "Received event: ${event.TAG}") +// when (event) { +// is FlowEvent.PlaybackPositionEvent -> onPlaybackPositionEvent(event) +// else -> {} +// } +// } +// } +// } - private fun onEventMainThread(event: FlowEvent.PlaybackPositionEvent) { + fun onPlaybackPositionEvent(event: FlowEvent.PlaybackPositionEvent) { if (playable?.getIdentifier() != event.media?.getIdentifier()) return val newChapterIndex: Int = ChapterUtils.getCurrentChapterIndex(playable, event.position) if (newChapterIndex >= 0 && newChapterIndex != displayedChapterIndex) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QueueFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QueueFragment.kt index 729e5278..610d2d39 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QueueFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QueueFragment.kt @@ -30,6 +30,7 @@ import ac.mdiq.podcini.ui.adapter.SelectableAdapter import ac.mdiq.podcini.ui.dialog.ConfirmationDialog import ac.mdiq.podcini.ui.dialog.EpisodeSortDialog import ac.mdiq.podcini.ui.dialog.SwitchQueueDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.EmptyViewHandler import ac.mdiq.podcini.ui.utils.LiftOnScrollListener import ac.mdiq.podcini.ui.view.EpisodesRecyclerView @@ -301,8 +302,7 @@ import java.util.* val item: Episode = event.episodes[i] val pos: Int = EpisodeUtil.indexOfItemWithId(queueItems, item.id) if (pos >= 0) { - queueItems.removeAt(pos) - queueItems.add(pos, item) + queueItems[pos] = item adapter?.notifyItemChangedCompat(pos) refreshInfoBar() } @@ -322,7 +322,8 @@ import java.util.* val pos: Int = EpisodeUtil.indexOfItemWithDownloadUrl(queueItems.toList(), downloadUrl) if (pos >= 0) { val item = queueItems[pos] - item.media?.downloaded = true +// item.media?.downloaded = true + item.media?.setIsDownloaded() adapter?.notifyItemChangedCompat(pos) } } @@ -380,12 +381,15 @@ import java.util.* } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + queueItems = mutableListOf() adapter?.endSelectMode() + adapter?.clearData() adapter = null toolbar.setOnMenuItemClickListener(null) toolbar.setOnLongClickListener(null) + super.onDestroyView() } private fun refreshToolbarState() { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QuickDiscoveryFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QuickDiscoveryFragment.kt index 38ab58dc..73f654b2 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QuickDiscoveryFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/QuickDiscoveryFragment.kt @@ -90,8 +90,8 @@ class QuickDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener { } override fun onDestroy() { - super.onDestroy() _binding = null + super.onDestroy() } private var eventSink: Job? = null diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/RemoteEpisodesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/RemoteEpisodesFragment.kt index cd296b58..c07fcd34 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/RemoteEpisodesFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/RemoteEpisodesFragment.kt @@ -2,6 +2,7 @@ package ac.mdiq.podcini.ui.fragment import ac.mdiq.podcini.R import ac.mdiq.podcini.storage.model.Episode +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.util.Logd import ac.mdiq.podcini.util.event.EventFlow import ac.mdiq.podcini.util.event.FlowEvent @@ -46,6 +47,11 @@ import kotlin.math.min cancelFlowEvents() } + override fun onDestroyView() { + episodeList.clear() + super.onDestroyView() + } + fun setEpisodes(episodeList_: MutableList) { episodeList.clear() episodeList.addAll(episodeList_) diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SearchFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SearchFragment.kt index 08158f71..891fc2f0 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SearchFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SearchFragment.kt @@ -19,6 +19,7 @@ import ac.mdiq.podcini.ui.actions.menuhandler.MenuItemUtils import ac.mdiq.podcini.ui.activity.MainActivity import ac.mdiq.podcini.ui.adapter.EpisodesAdapter import ac.mdiq.podcini.ui.adapter.SelectableAdapter +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.EmptyViewHandler import ac.mdiq.podcini.ui.utils.LiftOnScrollListener import ac.mdiq.podcini.ui.view.EpisodesRecyclerView @@ -185,8 +186,11 @@ import java.lang.ref.WeakReference } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + adapter.clearData() + results = mutableListOf() + super.onDestroyView() } private fun setupToolbar(toolbar: MaterialToolbar) { @@ -282,8 +286,7 @@ import java.lang.ref.WeakReference val item: Episode = event.episodes[i] val pos: Int = EpisodeUtil.indexOfItemWithId(results, item.id) if (pos >= 0) { - results.removeAt(pos) - results.add(pos, item) + results[pos] = item adapter.notifyItemChangedCompat(pos) } i++ diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt index a7c7bd39..c2307fa6 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt @@ -210,8 +210,12 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") + feedList = mutableListOf() + feedListFiltered = mutableListOf() + adapter.clearData() _binding = null + super.onDestroyView() } override fun onSaveInstanceState(outState: Bundle) { @@ -309,7 +313,6 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec lifecycleScope.launch { try { withContext(Dispatchers.IO) { - feedList = getFeedList().toMutableList() sortFeeds() resetTags() } @@ -396,7 +399,8 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec comparator(counterMap, dir) } } - synchronized(feedList) { feedList.sortWith(comparator) } + val feedList_ = getFeedList().toMutableList() + synchronized(feedList_) { feedList = feedList_.sortedWith(comparator).toMutableList() } } private fun counterMap(episodes: RealmResults): Map { @@ -552,6 +556,9 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec this.feedList = ArrayList() setHasStableIds(true) } + fun clearData() { + feedList = listOf() + } fun getItem(position: Int): Any { return feedList[position] } diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/VideoEpisodeFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/VideoEpisodeFragment.kt index 3b90f37f..bb386a63 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/VideoEpisodeFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/VideoEpisodeFragment.kt @@ -23,6 +23,7 @@ import ac.mdiq.podcini.ui.activity.VideoplayerActivity import ac.mdiq.podcini.ui.activity.VideoplayerActivity.Companion.videoMode import ac.mdiq.podcini.ui.activity.starter.MainActivityStarter import ac.mdiq.podcini.ui.dialog.SkipPreferenceDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.utils.PictureInPictureUtil import ac.mdiq.podcini.ui.utils.ShownotesCleaner import ac.mdiq.podcini.ui.view.ShownotesWebView @@ -166,12 +167,13 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") root.removeView(webvDescription) webvDescription.destroy() _binding = null controller?.release() controller = null // prevent leak + super.onDestroyView() } private var eventSink: Job? = null diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/FeedStatisticsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/FeedStatisticsFragment.kt index 9eadd900..0562402f 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/FeedStatisticsFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/FeedStatisticsFragment.kt @@ -66,8 +66,8 @@ class FeedStatisticsFragment : Fragment() { } override fun onDestroy() { - super.onDestroy() _binding = null + super.onDestroy() } companion object { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/StatisticsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/StatisticsFragment.kt index 84eaf5cb..725f1d80 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/StatisticsFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/statistics/StatisticsFragment.kt @@ -12,6 +12,8 @@ import ac.mdiq.podcini.ui.activity.MainActivity import ac.mdiq.podcini.ui.activity.starter.MainActivityStarter import ac.mdiq.podcini.ui.dialog.ConfirmationDialog import ac.mdiq.podcini.ui.dialog.DatesFilterDialog +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion import ac.mdiq.podcini.ui.statistics.PieChartView.PieChartData import ac.mdiq.podcini.util.Converter.shortLocalizedDuration import ac.mdiq.podcini.util.Logd @@ -92,8 +94,9 @@ class StatisticsFragment : Fragment() { } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } @Deprecated("Deprecated in Java") @@ -218,8 +221,9 @@ class StatisticsFragment : Fragment() { cancelFlowEvents() } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } private var eventSink: Job? = null private fun cancelFlowEvents() { @@ -370,8 +374,9 @@ class StatisticsFragment : Fragment() { cancelFlowEvents() } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } private var eventSink: Job? = null private fun cancelFlowEvents() { @@ -561,8 +566,9 @@ class StatisticsFragment : Fragment() { return binding.root } override fun onDestroyView() { - super.onDestroyView() + Logd(TAG, "onDestroyView") _binding = null + super.onDestroyView() } @Deprecated("Deprecated in Java") override fun onPrepareOptionsMenu(menu: Menu) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/utils/LocalDeleteModal.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/utils/LocalDeleteModal.kt index cc601793..c936f78c 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/utils/LocalDeleteModal.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/utils/LocalDeleteModal.kt @@ -1,6 +1,7 @@ package ac.mdiq.podcini.ui.utils import ac.mdiq.podcini.R +import ac.mdiq.podcini.storage.database.Episodes.deleteMediaOfEpisode import android.content.Context import android.content.DialogInterface import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -8,25 +9,25 @@ import ac.mdiq.podcini.storage.model.Episode object LocalDeleteModal { - fun showLocalFeedDeleteWarningIfNecessary(context: Context, items: Iterable, deleteCommand: Runnable) { - var anyLocalFeed = false + fun deleteEpisodesWarnLocal(context: Context, items: Iterable) { + val localItems: MutableList = mutableListOf() for (item in items) { if (item.feed?.isLocalFeed == true) { - anyLocalFeed = true - break - } + localItems.add(item) + } else deleteMediaOfEpisode(context, item) } - if (!anyLocalFeed) { - deleteCommand.run() - return + if (localItems.isNotEmpty()) { + MaterialAlertDialogBuilder(context) + .setTitle(R.string.delete_episode_label) + .setMessage(R.string.delete_local_feed_warning_body) + .setPositiveButton(R.string.delete_label) { dialog: DialogInterface?, which: Int -> + for (item in localItems) { + deleteMediaOfEpisode(context, item) + } + } + .setNegativeButton(R.string.cancel_label, null) + .show() } - - MaterialAlertDialogBuilder(context) - .setTitle(R.string.delete_episode_label) - .setMessage(R.string.delete_local_feed_warning_body) - .setPositiveButton(R.string.delete_label) { dialog: DialogInterface?, which: Int -> deleteCommand.run() } - .setNegativeButton(R.string.cancel_label, null) - .show() } } diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/view/viewholder/EpisodeViewHolder.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/view/viewholder/EpisodeViewHolder.kt index 6a24f2ea..ea124b5e 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/view/viewholder/EpisodeViewHolder.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/view/viewholder/EpisodeViewHolder.kt @@ -99,6 +99,7 @@ open class EpisodeViewHolder(private val activity: MainActivity, parent: ViewGro container.alpha = if (item.isPlayed()) 0.7f else 1.0f leftPadding.contentDescription = item.title binding.playedMark.visibility = View.GONE + binding.txtvPubDate.setTextColor(getColorFromAttr(activity, com.google.android.material.R.attr.colorOnSurfaceVariant)) when { item.isPlayed() -> { leftPadding.contentDescription = item.title + ". " + activity.getString(R.string.is_played) diff --git a/app/src/main/kotlin/ac/mdiq/podcini/util/event/FlowEvent.kt b/app/src/main/kotlin/ac/mdiq/podcini/util/event/FlowEvent.kt index 9ef52ed3..5d3b1971 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/util/event/FlowEvent.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/util/event/FlowEvent.kt @@ -155,6 +155,8 @@ sealed class FlowEvent { data class AllEpisodesFilterEvent(val filterValues: Set?) : FlowEvent() + data class AllEpisodesSortEvent(val dummy: Unit = Unit) : FlowEvent() + data class EpisodeEvent(val episodes: List) : FlowEvent() { companion object { fun updated(episodes: List): EpisodeEvent { diff --git a/app/src/main/res/drawable/baseline_home_24.xml b/app/src/main/res/drawable/baseline_home_24.xml index 57d515fa..32f97ef4 100644 --- a/app/src/main/res/drawable/baseline_home_24.xml +++ b/app/src/main/res/drawable/baseline_home_24.xml @@ -1,5 +1,7 @@ - + diff --git a/app/src/main/res/drawable/ic_info_white.xml b/app/src/main/res/drawable/ic_info_white.xml index 3abb510b..726a5966 100644 --- a/app/src/main/res/drawable/ic_info_white.xml +++ b/app/src/main/res/drawable/ic_info_white.xml @@ -1,5 +1,7 @@ - + diff --git a/app/src/main/res/drawable/outline_home_24.xml b/app/src/main/res/drawable/outline_home_24.xml index 94c8f78a..ab486110 100644 --- a/app/src/main/res/drawable/outline_home_24.xml +++ b/app/src/main/res/drawable/outline_home_24.xml @@ -1,5 +1,9 @@ - - + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 18d2e2f0..1d8904e9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -271,7 +271,7 @@ Skip episode Reset playback position No items selected - Deleting removes the episode from Podcini and deletes the media file from your device storage. It cannot be downloaded again through Podcini. + Warning: you are deleting local episodes. It will delete the media files from your device storage. It cannot be downloaded again through Podcini. Continue? successful diff --git a/changelog.md b/changelog.md index 5aecc5a1..0557c1b9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,13 @@ +## 6.0.8 + +* feeds sorting dialog layout is set to single column due to potential long text issue +* fixed issue of not being able to copy text from player detailed view +* fixed issue of some menu icon not correctly shown in dark theme +* fixed issue of results not updated in views when deleting episodes +* fixed issue of downloaded episode still showing as New +* fixed sorting on All Episodes view +* added more garbage collections + ## 6.0.7 * feeds sorting is bi-directional and in the same style as episodes sorting diff --git a/fastlane/metadata/android/en-US/changelogs/3020208.txt b/fastlane/metadata/android/en-US/changelogs/3020208.txt new file mode 100644 index 00000000..e4e3efee --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/3020208.txt @@ -0,0 +1,10 @@ + +Version 6.0.8 brings several changes: + +* feeds sorting dialog layout is set to single column due to potential long text issue +* fixed issue of not being able to copy text from player detailed view +* fixed issue of some menu icon not correctly shown in dark theme +* fixed issue of results not updated in views when deleting episodes +* fixed issue of downloaded episode still showing as New +* fixed sorting on All Episodes view +* added more garbage collections