5.4.0 commit
|
@ -17,7 +17,7 @@ Compared to AntennaPod this project:
|
|||
2. Plays in `AudioOffloadMode`, kind to device battery,
|
||||
3. Is purely `Kotlin` based and mono-modular,
|
||||
4. Targets Android 14 with updated dependencies,
|
||||
5. Outfits with Viewbinding, Coil replacing Glide, coroutines replacing RxJava, and SharedFlow replacing EventBus,
|
||||
5. Outfits with Viewbinding, Coil replacing Glide, coroutines replacing RxJava and threads, and SharedFlow replacing EventBus,
|
||||
6. Boasts new UI's including streamlined drawer, subscriptions view and player controller,
|
||||
7. Accepts podcast as well as plain RSS and YouTube feeds,
|
||||
8. Offers Readability and Text-to-Speech for RSS contents,
|
||||
|
|
|
@ -159,8 +159,8 @@ android {
|
|||
// Version code schema (not used):
|
||||
// "1.2.3-beta4" -> 1020304
|
||||
// "1.2.3" -> 1020395
|
||||
versionCode 3020146
|
||||
versionName "5.3.1"
|
||||
versionCode 3020147
|
||||
versionName "5.4.0"
|
||||
|
||||
def commit = ""
|
||||
try {
|
||||
|
|
|
@ -30,6 +30,7 @@ import ac.mdiq.podcini.preferences.UserPreferences
|
|||
import de.test.podcini.EspressoTestUtils
|
||||
import de.test.podcini.IgnoreOnCi
|
||||
import de.test.podcini.ui.UITestUtils
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.awaitility.Awaitility
|
||||
import org.hamcrest.Matchers
|
||||
import org.junit.*
|
||||
|
@ -166,7 +167,7 @@ class PlaybackTest {
|
|||
fun testStartLocal() {
|
||||
uiTestUtils!!.addLocalFeedData(true)
|
||||
activityTestRule.launchActivity(Intent())
|
||||
clearQueue().get()
|
||||
runBlocking { clearQueue().join() }
|
||||
startLocalPlayback()
|
||||
}
|
||||
|
||||
|
@ -175,7 +176,7 @@ class PlaybackTest {
|
|||
fun testPlayingItemAddsToQueue() {
|
||||
uiTestUtils!!.addLocalFeedData(true)
|
||||
activityTestRule.launchActivity(Intent())
|
||||
clearQueue().get()
|
||||
runBlocking { clearQueue().join() }
|
||||
val queue = getQueue()
|
||||
Assert.assertEquals(0, queue.size.toLong())
|
||||
startLocalPlayback()
|
||||
|
@ -188,7 +189,7 @@ class PlaybackTest {
|
|||
setContinuousPlaybackPreference(false)
|
||||
uiTestUtils!!.addLocalFeedData(true)
|
||||
activityTestRule.launchActivity(Intent())
|
||||
clearQueue().get()
|
||||
runBlocking { clearQueue().join() }
|
||||
startLocalPlayback()
|
||||
}
|
||||
|
||||
|
@ -261,10 +262,9 @@ class PlaybackTest {
|
|||
protected fun replayEpisodeCheck(followQueue: Boolean) {
|
||||
setContinuousPlaybackPreference(followQueue)
|
||||
uiTestUtils!!.addLocalFeedData(true)
|
||||
clearQueue().get()
|
||||
runBlocking { clearQueue().join() }
|
||||
activityTestRule.launchActivity(Intent())
|
||||
val episodes = getEpisodes(0, 10,
|
||||
unfiltered(), SortOrder.DATE_NEW_OLD)
|
||||
val episodes = getEpisodes(0, 10, unfiltered(), SortOrder.DATE_NEW_OLD)
|
||||
|
||||
startLocalPlayback()
|
||||
val media = episodes[0].media
|
||||
|
|
|
@ -147,12 +147,12 @@ class NavigationDrawerTest {
|
|||
val hidden = hiddenDrawerItems
|
||||
Assert.assertEquals(2, hidden!!.size.toLong())
|
||||
Assert.assertTrue(hidden.contains(AllEpisodesFragment.TAG))
|
||||
Assert.assertTrue(hidden.contains(PlaybackHistoryFragment.TAG))
|
||||
Assert.assertTrue(hidden.contains(HistoryFragment.TAG))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDrawerPreferencesUnhideSomeElements() {
|
||||
var hidden = listOf(PlaybackHistoryFragment.TAG, DownloadsFragment.TAG)
|
||||
var hidden = listOf(HistoryFragment.TAG, DownloadsFragment.TAG)
|
||||
hiddenDrawerItems = hidden
|
||||
activityRule.launchActivity(Intent())
|
||||
openNavDrawer()
|
||||
|
@ -166,7 +166,7 @@ class NavigationDrawerTest {
|
|||
hidden = hiddenDrawerItems?.filterNotNull()?: listOf()
|
||||
Assert.assertEquals(2, hidden.size.toLong())
|
||||
Assert.assertTrue(hidden.contains(QueueFragment.TAG))
|
||||
Assert.assertTrue(hidden.contains(PlaybackHistoryFragment.TAG))
|
||||
Assert.assertTrue(hidden.contains(HistoryFragment.TAG))
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ import com.google.android.material.color.DynamicColors
|
|||
import com.joanzapata.iconify.Iconify
|
||||
import com.joanzapata.iconify.fonts.FontAwesomeModule
|
||||
import com.joanzapata.iconify.fonts.MaterialModule
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/** Main application class. */
|
||||
class PodciniApp : Application() {
|
||||
|
@ -42,9 +45,12 @@ class PodciniApp : Application() {
|
|||
|
||||
singleton = this
|
||||
|
||||
ClientConfigurator.initialize(this)
|
||||
PreferenceUpgrader.checkUpgrades(this)
|
||||
|
||||
runBlocking {
|
||||
withContext(Dispatchers.IO) {
|
||||
ClientConfigurator.initialize(this@PodciniApp)
|
||||
PreferenceUpgrader.checkUpgrades(this@PodciniApp)
|
||||
}
|
||||
}
|
||||
Iconify.with(FontAwesomeModule())
|
||||
Iconify.with(MaterialModule())
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.util.Log
|
|||
import ac.mdiq.podcini.net.download.service.PodciniHttpClient.getHttpClient
|
||||
import ac.mdiq.podcini.storage.model.feed.Feed
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.content.SharedPreferences
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
@ -81,6 +82,11 @@ class ItunesTopListLoader(private val context: Context) {
|
|||
const val COUNTRY_CODE_UNSET: String = "99"
|
||||
private const val NUM_LOADED = 25
|
||||
|
||||
var prefs: SharedPreferences? = null
|
||||
fun getSharedPrefs(context: Context) {
|
||||
if (prefs == null) prefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
private fun removeSubscribed(suggestedPodcasts: List<PodcastSearchResult>, subscribedFeeds: List<Feed>, limit: Int): List<PodcastSearchResult> {
|
||||
val subscribedPodcastsSet: MutableSet<String> = HashSet()
|
||||
for (subscribedFeed in subscribedFeeds) {
|
||||
|
|
|
@ -29,6 +29,7 @@ import androidx.work.Worker
|
|||
import androidx.work.WorkerParameters
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.apache.commons.io.FileUtils
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
@ -115,7 +116,7 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker
|
|||
if (dest.exists()) {
|
||||
media.file_url = request.destination
|
||||
try {
|
||||
DBWriter.persistFeedMedia(media).get()
|
||||
runBlocking { DBWriter.persistFeedMedia(media).join() }
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "ExecutionException in writeFileUrl: " + e.message)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.content.Context
|
|||
import android.media.MediaMetadataRetriever
|
||||
import android.util.Log
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
|
@ -60,7 +61,7 @@ class MediaDownloadedHandler(private val context: Context, var updatedStatus: Do
|
|||
val item = media.item
|
||||
|
||||
try {
|
||||
DBWriter.persistFeedMedia(media).get()
|
||||
runBlocking { DBWriter.persistFeedMedia(media).join() }
|
||||
|
||||
// we've received the media, we don't want to autodownload it again
|
||||
if (item != null) {
|
||||
|
@ -68,7 +69,7 @@ class MediaDownloadedHandler(private val context: Context, var updatedStatus: Do
|
|||
// setFeedItem() signals (via EventBus) 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 FeedMedia as well
|
||||
DBWriter.persistFeedItem(item).get()
|
||||
runBlocking { DBWriter.persistFeedItem(item).join() }
|
||||
if (broadcastUnreadStateUpdate) EventFlow.postEvent(FlowEvent.UnreadItemsUpdateEvent())
|
||||
}
|
||||
} catch (e: InterruptedException) {
|
||||
|
|
|
@ -46,6 +46,7 @@ class CompositeX509TrustManager(private val trustManagers: List<X509TrustManager
|
|||
override fun getAcceptedIssuers(): Array<X509Certificate> {
|
||||
val certificates: MutableList<X509Certificate> = ArrayList()
|
||||
for (trustManager in trustManagers) {
|
||||
// TODO: appears time consuming
|
||||
certificates.addAll(listOf(*trustManager.acceptedIssuers))
|
||||
}
|
||||
return certificates.toTypedArray<X509Certificate>()
|
||||
|
|
|
@ -57,6 +57,7 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
|
|||
@UnstableApi override fun doWork(): Result {
|
||||
Logd(TAG, "doWork() called")
|
||||
val activeSyncProvider = getActiveSyncProvider() ?: return Result.failure()
|
||||
Logd(TAG, "doWork() got syn provider")
|
||||
|
||||
SynchronizationSettings.updateLastSynchronizationAttempt()
|
||||
setCurrentlyActive(true)
|
||||
|
@ -165,15 +166,6 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
|
|||
return@launch
|
||||
}
|
||||
scope.cancel()
|
||||
// try {
|
||||
// while (true) {
|
||||
// Thread.sleep(1000)
|
||||
// val event = EventBus.getDefault().getStickyEvent(FlowEvent.FeedUpdateRunningEvent::class.java)
|
||||
// if (event == null || !event.isFeedUpdateRunning) return
|
||||
// }
|
||||
// } catch (e: InterruptedException) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
}
|
||||
|
||||
fun getEpisodeActions(syncServiceImpl: ISyncService) : Pair<Long, Long> {
|
||||
|
@ -315,11 +307,6 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
|
|||
if (selectedService == null) return null
|
||||
|
||||
return when (selectedService) {
|
||||
// SynchronizationProviderViewData.WIFI -> {
|
||||
//// if (hosturl != null) WifiImplSyncService(hosturl!!, hostport)
|
||||
//// else null
|
||||
// null
|
||||
// }
|
||||
SynchronizationProviderViewData.GPODDER_NET -> GpodnetService(getHttpClient(), hosturl, deviceID?:"", username?:"", password?:"")
|
||||
SynchronizationProviderViewData.NEXTCLOUD_GPODDER -> NextcloudSyncService(getHttpClient(), hosturl, username?:"", password?:"")
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import ac.mdiq.podcini.playback.service.PlaybackService
|
|||
import ac.mdiq.podcini.playback.service.PlaybackService.LocalBinder
|
||||
import ac.mdiq.podcini.playback.service.PlaybackServiceConstants
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.loadPlayableFromPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.storage.DBWriter
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
||||
|
@ -24,8 +25,11 @@ import android.view.SurfaceHolder
|
|||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* Communicates with the playback service. GUI classes should use this class to
|
||||
|
@ -73,6 +77,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
|
|||
private fun procFlowEvents() {
|
||||
activity.lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.PlaybackServiceEvent -> if (event.action == FlowEvent.PlaybackServiceEvent.Action.SERVICE_STARTED) init()
|
||||
else -> {}
|
||||
|
@ -305,9 +310,13 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
|
|||
|
||||
fun getMedia(): Playable? {
|
||||
if (media == null && playbackService != null) media = playbackService!!.mPlayerInfo.playable
|
||||
if (media == null) media = PlaybackPreferences.createInstanceFromPreferences(activity)
|
||||
|
||||
return media
|
||||
if (media != null) return media
|
||||
return runBlocking {
|
||||
media = withContext(Dispatchers.IO) {
|
||||
loadPlayableFromPreferences()
|
||||
}
|
||||
media
|
||||
}
|
||||
}
|
||||
|
||||
fun seekTo(time: Int) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import ac.mdiq.podcini.playback.base.MediaPlayerBase
|
|||
import ac.mdiq.podcini.playback.base.PlayerStatus
|
||||
import ac.mdiq.podcini.playback.base.RewindAfterPauseUtils
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.storage.DBWriter.ioScope
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
||||
import ac.mdiq.podcini.storage.model.playback.MediaType
|
||||
import ac.mdiq.podcini.storage.model.playback.Playable
|
||||
|
@ -159,15 +160,15 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
private fun setDataSource(m: MediaMetadata, s: String, user: String?, password: String?) {
|
||||
Logd(TAG, "setDataSource: $s")
|
||||
|
||||
val httpDataSourceFactory = OkHttpDataSource.Factory(PodciniHttpClient.getHttpClient() as okhttp3.Call.Factory)
|
||||
.setUserAgent(ClientConfig.USER_AGENT)
|
||||
if (httpDataSourceFactory == null)
|
||||
httpDataSourceFactory = OkHttpDataSource.Factory(PodciniHttpClient.getHttpClient() as okhttp3.Call.Factory).setUserAgent(ClientConfig.USER_AGENT)
|
||||
|
||||
if (!user.isNullOrEmpty() && !password.isNullOrEmpty()) {
|
||||
val requestProperties = HashMap<String, String>()
|
||||
requestProperties["Authorization"] = HttpCredentialEncoder.encode(user, password, "ISO-8859-1")
|
||||
httpDataSourceFactory.setDefaultRequestProperties(requestProperties)
|
||||
httpDataSourceFactory!!.setDefaultRequestProperties(requestProperties)
|
||||
}
|
||||
val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(context, null, httpDataSourceFactory)
|
||||
val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(context, null, httpDataSourceFactory!!)
|
||||
val extractorsFactory = DefaultExtractorsFactory()
|
||||
extractorsFactory.setConstantBitrateSeekingEnabled(true)
|
||||
extractorsFactory.setMp3ExtractorFlags(Mp3Extractor.FLAG_DISABLE_ID3_METADATA)
|
||||
|
@ -282,6 +283,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
}
|
||||
else -> {
|
||||
val localMediaurl = this.playable!!.getLocalMediaUrl()
|
||||
// TODO: File(localMediaurl).canRead() time consuming
|
||||
if (!localMediaurl.isNullOrEmpty() && File(localMediaurl).canRead()) setDataSource(metadata, localMediaurl, null, null)
|
||||
else throw IOException("Unable to read local file $localMediaurl")
|
||||
}
|
||||
|
@ -603,8 +605,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
* invalid values.
|
||||
*/
|
||||
override fun getVideoSize(): Pair<Int, Int>? {
|
||||
if (status != PlayerStatus.ERROR && mediaType == MediaType.VIDEO)
|
||||
videoSize = Pair(videoWidth, videoHeight)
|
||||
if (status != PlayerStatus.ERROR && mediaType == MediaType.VIDEO) videoSize = Pair(videoWidth, videoHeight)
|
||||
return videoSize
|
||||
}
|
||||
|
||||
|
@ -664,6 +665,12 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
init {
|
||||
mediaType = MediaType.UNKNOWN
|
||||
|
||||
if (httpDataSourceFactory == null) {
|
||||
ioScope.launch {
|
||||
httpDataSourceFactory = OkHttpDataSource.Factory(PodciniHttpClient.getHttpClient() as okhttp3.Call.Factory)
|
||||
.setUserAgent(ClientConfig.USER_AGENT)
|
||||
}
|
||||
}
|
||||
if (exoPlayer == null) {
|
||||
setupPlayerListener()
|
||||
createStaticPlayer(context)
|
||||
|
@ -837,6 +844,8 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
const val BUFFERING_ENDED: Int = -2
|
||||
const val ERROR_CODE_OFFSET: Int = 1000
|
||||
|
||||
private var httpDataSourceFactory: OkHttpDataSource.Factory? = null
|
||||
|
||||
private var trackSelector: DefaultTrackSelector? = null
|
||||
var exoPlayer: ExoPlayer? = null
|
||||
|
||||
|
@ -897,6 +906,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
audioErrorListener = null
|
||||
bufferingUpdateListener = null
|
||||
loudnessEnhancer = null
|
||||
httpDataSourceFactory = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import ac.mdiq.podcini.playback.cast.CastPsmp
|
|||
import ac.mdiq.podcini.playback.cast.CastStateListener
|
||||
import ac.mdiq.podcini.playback.service.PlaybackServiceTaskManager.PSTMCallback
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.clearCurrentlyPlayingTemporaryPlaybackSpeed
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.createInstanceFromPreferences
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.loadPlayableFromPreferences
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.currentEpisodeIsVideo
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.currentlyPlayingFeedMediaId
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.currentlyPlayingTemporaryPlaybackSpeed
|
||||
|
@ -612,7 +612,7 @@ class PlaybackService : MediaSessionService() {
|
|||
scope.launch {
|
||||
try {
|
||||
val playable = withContext(Dispatchers.IO) {
|
||||
createInstanceFromPreferences(applicationContext)
|
||||
loadPlayableFromPreferences()
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
startPlaying(playable, false)
|
||||
|
@ -783,6 +783,7 @@ class PlaybackService : MediaSessionService() {
|
|||
private fun procFlowEvents() {
|
||||
scope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.PlayerErrorEvent -> playerError(event)
|
||||
is FlowEvent.BufferUpdateEvent -> bufferUpdate(event)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ac.mdiq.podcini.preferences
|
||||
|
||||
import ac.mdiq.podcini.playback.base.PlayerStatus
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
||||
|
@ -14,7 +15,6 @@ import android.content.Context
|
|||
import android.content.SharedPreferences
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
|
||||
/**
|
||||
* Provides access to preferences set by the playback service. A private
|
||||
|
@ -88,43 +88,43 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen
|
|||
const val PLAYER_STATUS_OTHER: Int = 3
|
||||
|
||||
private var instance: PlaybackPreferences? = null
|
||||
private lateinit var prefs: SharedPreferences
|
||||
// private lateinit var prefs: SharedPreferences
|
||||
|
||||
@JvmStatic
|
||||
fun init(context: Context) {
|
||||
instance = PlaybackPreferences()
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
prefs.registerOnSharedPreferenceChangeListener(instance)
|
||||
// prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
appPrefs.registerOnSharedPreferenceChangeListener(instance)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val currentlyPlayingMediaType: Long
|
||||
get() = prefs.getLong(PREF_CURRENTLY_PLAYING_MEDIA_TYPE, NO_MEDIA_PLAYING)
|
||||
get() = appPrefs.getLong(PREF_CURRENTLY_PLAYING_MEDIA_TYPE, NO_MEDIA_PLAYING)
|
||||
|
||||
@JvmStatic
|
||||
val currentlyPlayingFeedMediaId: Long
|
||||
get() = prefs.getLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING)
|
||||
get() = appPrefs.getLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING)
|
||||
|
||||
@JvmStatic
|
||||
val currentEpisodeIsVideo: Boolean
|
||||
get() = prefs.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false)
|
||||
get() = appPrefs.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false)
|
||||
|
||||
@JvmStatic
|
||||
val currentPlayerStatus: Int
|
||||
get() = prefs.getInt(PREF_CURRENT_PLAYER_STATUS, PLAYER_STATUS_OTHER)
|
||||
get() = appPrefs.getInt(PREF_CURRENT_PLAYER_STATUS, PLAYER_STATUS_OTHER)
|
||||
|
||||
@JvmStatic
|
||||
var currentlyPlayingTemporaryPlaybackSpeed: Float
|
||||
get() = prefs.getFloat(PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED, FeedPreferences.SPEED_USE_GLOBAL)
|
||||
get() = appPrefs.getFloat(PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED, FeedPreferences.SPEED_USE_GLOBAL)
|
||||
set(speed) {
|
||||
val editor = prefs.edit()
|
||||
val editor = appPrefs.edit()
|
||||
editor.putFloat(PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED, speed)
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun writeNoMediaPlaying() {
|
||||
val editor = prefs.edit()
|
||||
val editor = appPrefs.edit()
|
||||
editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA_TYPE, NO_MEDIA_PLAYING)
|
||||
editor.putLong(PREF_CURRENTLY_PLAYING_FEED_ID, NO_MEDIA_PLAYING)
|
||||
editor.putLong(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING)
|
||||
|
@ -135,7 +135,7 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen
|
|||
@JvmStatic
|
||||
fun writeMediaPlaying(playable: Playable?, playerStatus: PlayerStatus, item: FeedItem? = null) {
|
||||
Logd(TAG, "Writing playback preferences ${playable?.getIdentifier()}")
|
||||
val editor = prefs.edit()
|
||||
val editor = appPrefs.edit()
|
||||
|
||||
if (playable == null) {
|
||||
writeNoMediaPlaying()
|
||||
|
@ -162,14 +162,14 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen
|
|||
fun writePlayerStatus(playerStatus: PlayerStatus) {
|
||||
Logd(TAG, "Writing player status playback preferences")
|
||||
|
||||
val editor = prefs.edit()
|
||||
val editor = appPrefs.edit()
|
||||
editor.putInt(PREF_CURRENT_PLAYER_STATUS, getCurrentPlayerStatusAsInt(playerStatus))
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun clearCurrentlyPlayingTemporaryPlaybackSpeed() {
|
||||
val editor = prefs.edit()
|
||||
val editor = appPrefs.edit()
|
||||
editor.remove(PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED)
|
||||
editor.apply()
|
||||
}
|
||||
|
@ -190,40 +190,23 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen
|
|||
* @return The restored Playable object
|
||||
*/
|
||||
@JvmStatic
|
||||
fun createInstanceFromPreferences(context: Context): Playable? {
|
||||
val currentlyPlayingMedia = currentlyPlayingMediaType
|
||||
Logd(TAG, "currentlyPlayingMedia: $currentlyPlayingMedia")
|
||||
if (currentlyPlayingMedia != NO_MEDIA_PLAYING) {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
|
||||
return createInstanceFromPreferences(currentlyPlayingMedia.toInt(), prefs)
|
||||
fun loadPlayableFromPreferences(): Playable? {
|
||||
val currentlyPlayingType = currentlyPlayingMediaType
|
||||
Logd(TAG, "loadPlayableFromPreferences currentlyPlayingType: $currentlyPlayingType")
|
||||
if (currentlyPlayingType != NO_MEDIA_PLAYING) {
|
||||
val type = currentlyPlayingType.toInt()
|
||||
if (type == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA) {
|
||||
var result: Playable? = null
|
||||
val mediaId = appPrefs.getLong(FeedMedia.PREF_MEDIA_ID, -1)
|
||||
if (mediaId != -1L) result = DBReader.getFeedMedia(mediaId)
|
||||
Logd(TAG, "playable loaded: ${result?.getIdentifier()}")
|
||||
return result
|
||||
} else {
|
||||
Log.e(TAG, "Could not restore Playable object from preferences")
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores a playable object from a sharedPreferences file. This method might load data from the database,
|
||||
* depending on the type of playable that was restored.
|
||||
*
|
||||
* @param type An integer that represents the type of the Playable object
|
||||
* that is restored.
|
||||
* @param pref The SharedPreferences file from which the Playable object
|
||||
* is restored
|
||||
* @return The restored Playable object
|
||||
*/
|
||||
private fun createInstanceFromPreferences(type: Int, pref: SharedPreferences): Playable? {
|
||||
if (type == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA) {
|
||||
return createFeedMediaInstance(pref)
|
||||
} else {
|
||||
Log.e(TAG, "Could not restore Playable object from preferences")
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFeedMediaInstance(pref: SharedPreferences): Playable? {
|
||||
var result: Playable? = null
|
||||
val mediaId = pref.getLong(FeedMedia.PREF_MEDIA_ID, -1)
|
||||
if (mediaId != -1L) result = DBReader.getFeedMedia(mediaId)
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ import ac.mdiq.podcini.preferences.UserPreferences.isStreamOverDownload
|
|||
import ac.mdiq.podcini.preferences.UserPreferences.theme
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeAction
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions.Companion.getSharedPrefs
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions.Companion.prefs
|
||||
import ac.mdiq.podcini.ui.fragment.AllEpisodesFragment
|
||||
import ac.mdiq.podcini.ui.fragment.QueueFragment
|
||||
import ac.mdiq.podcini.util.error.CrashReportWriter.Companion.file
|
||||
|
@ -96,8 +98,9 @@ object PreferenceUpgrader {
|
|||
prefs.edit().putString(UserPreferences.PREF_HARDWARE_PREVIOUS_BUTTON, KeyEvent.KEYCODE_MEDIA_PREVIOUS.toString()).apply()
|
||||
}
|
||||
if (oldVersion < 2040000) {
|
||||
val swipePrefs = context.getSharedPreferences(SwipeActions.PREF_NAME, Context.MODE_PRIVATE)
|
||||
swipePrefs.edit().putString(SwipeActions.KEY_PREFIX_SWIPEACTIONS + QueueFragment.TAG,
|
||||
getSharedPrefs(context)
|
||||
// val swipePrefs = context.getSharedPreferences(SwipeActions.SWIPE_ACTIONS_PREF_NAME, Context.MODE_PRIVATE)
|
||||
SwipeActions.prefs!!.edit().putString(SwipeActions.KEY_PREFIX_SWIPEACTIONS + QueueFragment.TAG,
|
||||
SwipeAction.REMOVE_FROM_QUEUE + "," + SwipeAction.REMOVE_FROM_QUEUE).apply()
|
||||
}
|
||||
if (oldVersion < 2050000) prefs.edit().putBoolean(UserPreferences.PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, true).apply()
|
||||
|
|
|
@ -138,7 +138,7 @@ object UserPreferences {
|
|||
const val DEFAULT_PAGE_REMEMBER: String = "remember"
|
||||
|
||||
private lateinit var context: Context
|
||||
private lateinit var prefs: SharedPreferences
|
||||
lateinit var appPrefs: SharedPreferences
|
||||
|
||||
/**
|
||||
* Sets up the UserPreferences class.
|
||||
|
@ -150,41 +150,41 @@ object UserPreferences {
|
|||
Logd(TAG, "Creating new instance of UserPreferences")
|
||||
|
||||
UserPreferences.context = context.applicationContext
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
appPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
createNoMediaFile()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var theme: ThemePreference
|
||||
get() = when (prefs.getString(PREF_THEME, "system")) {
|
||||
get() = when (appPrefs.getString(PREF_THEME, "system")) {
|
||||
"0" -> ThemePreference.LIGHT
|
||||
"1" -> ThemePreference.DARK
|
||||
else -> ThemePreference.SYSTEM
|
||||
}
|
||||
set(theme) {
|
||||
when (theme) {
|
||||
ThemePreference.LIGHT -> prefs.edit().putString(PREF_THEME, "0").apply()
|
||||
ThemePreference.DARK -> prefs.edit().putString(PREF_THEME, "1").apply()
|
||||
else -> prefs.edit().putString(PREF_THEME, "system").apply()
|
||||
ThemePreference.LIGHT -> appPrefs.edit().putString(PREF_THEME, "0").apply()
|
||||
ThemePreference.DARK -> appPrefs.edit().putString(PREF_THEME, "1").apply()
|
||||
else -> appPrefs.edit().putString(PREF_THEME, "system").apply()
|
||||
}
|
||||
}
|
||||
|
||||
val isBlackTheme: Boolean
|
||||
get() = prefs.getBoolean(PREF_THEME_BLACK, false)
|
||||
get() = appPrefs.getBoolean(PREF_THEME_BLACK, false)
|
||||
|
||||
val isThemeColorTinted: Boolean
|
||||
get() = Build.VERSION.SDK_INT >= 31 && prefs.getBoolean(PREF_TINTED_COLORS, false)
|
||||
get() = Build.VERSION.SDK_INT >= 31 && appPrefs.getBoolean(PREF_TINTED_COLORS, false)
|
||||
|
||||
@JvmStatic
|
||||
var hiddenDrawerItems: List<String>
|
||||
get() {
|
||||
val hiddenItems = prefs.getString(PREF_HIDDEN_DRAWER_ITEMS, "")
|
||||
val hiddenItems = appPrefs.getString(PREF_HIDDEN_DRAWER_ITEMS, "")
|
||||
return ArrayList(listOf(*TextUtils.split(hiddenItems, ",")))
|
||||
}
|
||||
set(items) {
|
||||
val str = TextUtils.join(",", items)
|
||||
prefs.edit()
|
||||
appPrefs.edit()
|
||||
.putString(PREF_HIDDEN_DRAWER_ITEMS, str)
|
||||
.apply()
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ object UserPreferences {
|
|||
@JvmStatic
|
||||
var fullNotificationButtons: List<Int>
|
||||
get() {
|
||||
val buttons = TextUtils.split(prefs.getString(PREF_FULL_NOTIFICATION_BUTTONS, "$NOTIFICATION_BUTTON_SKIP,$NOTIFICATION_BUTTON_PLAYBACK_SPEED"), ",")
|
||||
val buttons = TextUtils.split(appPrefs.getString(PREF_FULL_NOTIFICATION_BUTTONS, "$NOTIFICATION_BUTTON_SKIP,$NOTIFICATION_BUTTON_PLAYBACK_SPEED"), ",")
|
||||
val notificationButtons: MutableList<Int> = ArrayList()
|
||||
for (button in buttons) {
|
||||
notificationButtons.add(button.toInt())
|
||||
|
@ -200,8 +200,8 @@ object UserPreferences {
|
|||
return notificationButtons
|
||||
}
|
||||
set(items) {
|
||||
val str = TextUtils.join(",", items!!)
|
||||
prefs.edit()
|
||||
val str = TextUtils.join(",", items)
|
||||
appPrefs.edit()
|
||||
.putString(PREF_FULL_NOTIFICATION_BUTTONS, str)
|
||||
.apply()
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ object UserPreferences {
|
|||
* @return `true` if button should be shown, `false` otherwise
|
||||
*/
|
||||
private fun showButtonOnFullNotification(buttonId: Int): Boolean {
|
||||
return fullNotificationButtons!!.contains(buttonId)
|
||||
return fullNotificationButtons.contains(buttonId)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -237,13 +237,13 @@ object UserPreferences {
|
|||
@JvmStatic
|
||||
val feedOrder: Int
|
||||
get() {
|
||||
val value = prefs.getString(PREF_DRAWER_FEED_ORDER, "" + FEED_ORDER_COUNTER)
|
||||
val value = appPrefs.getString(PREF_DRAWER_FEED_ORDER, "" + FEED_ORDER_COUNTER)
|
||||
return value!!.toInt()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setFeedOrder(selected: String?) {
|
||||
prefs.edit()
|
||||
appPrefs.edit()
|
||||
.putString(PREF_DRAWER_FEED_ORDER, selected)
|
||||
.apply()
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ object UserPreferences {
|
|||
@JvmStatic
|
||||
val feedCounterSetting: FeedCounter
|
||||
get() {
|
||||
val value = prefs.getString(PREF_DRAWER_FEED_COUNTER, "" + FeedCounter.SHOW_UNPLAYED.id)
|
||||
val value = appPrefs.getString(PREF_DRAWER_FEED_COUNTER, "" + FeedCounter.SHOW_UNPLAYED.id)
|
||||
return FeedCounter.fromOrdinal(value!!.toInt())
|
||||
}
|
||||
|
||||
|
@ -259,14 +259,14 @@ object UserPreferences {
|
|||
/**
|
||||
* @return `true` if episodes should use their own cover, `false` otherwise
|
||||
*/
|
||||
get() = prefs.getBoolean(PREF_USE_EPISODE_COVER, true)
|
||||
get() = appPrefs.getBoolean(PREF_USE_EPISODE_COVER, true)
|
||||
|
||||
/**
|
||||
* @return `true` if we should show remaining time or the duration
|
||||
*/
|
||||
@JvmStatic
|
||||
fun shouldShowRemainingTime(): Boolean {
|
||||
return prefs.getBoolean(PREF_SHOW_TIME_LEFT, false)
|
||||
return appPrefs.getBoolean(PREF_SHOW_TIME_LEFT, false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -277,7 +277,7 @@ object UserPreferences {
|
|||
*/
|
||||
@JvmStatic
|
||||
fun setShowRemainTimeSetting(showRemain: Boolean?) {
|
||||
prefs.edit().putBoolean(PREF_SHOW_TIME_LEFT, showRemain!!).apply()
|
||||
appPrefs.edit().putBoolean(PREF_SHOW_TIME_LEFT, showRemain!!).apply()
|
||||
}
|
||||
|
||||
val notifyPriority: Int
|
||||
|
@ -286,7 +286,7 @@ object UserPreferences {
|
|||
*
|
||||
* @return NotificationCompat.PRIORITY_MAX or NotificationCompat.PRIORITY_DEFAULT
|
||||
*/
|
||||
get() = if (prefs.getBoolean(PREF_EXPANDED_NOTIFICATION, false)) NotificationCompat.PRIORITY_MAX else NotificationCompat.PRIORITY_DEFAULT
|
||||
get() = if (appPrefs.getBoolean(PREF_EXPANDED_NOTIFICATION, false)) NotificationCompat.PRIORITY_MAX else NotificationCompat.PRIORITY_DEFAULT
|
||||
|
||||
@JvmStatic
|
||||
val isPersistNotify: Boolean
|
||||
|
@ -295,23 +295,23 @@ object UserPreferences {
|
|||
*
|
||||
* @return `true` if notifications are persistent, `false` otherwise
|
||||
*/
|
||||
get() = prefs.getBoolean(PREF_PERSISTENT_NOTIFICATION, true)
|
||||
get() = appPrefs.getBoolean(PREF_PERSISTENT_NOTIFICATION, true)
|
||||
|
||||
@JvmStatic
|
||||
val showDownloadReportRaw: Boolean
|
||||
/**
|
||||
* Used for migration of the preference to system notification channels.
|
||||
*/
|
||||
get() = prefs.getBoolean(PREF_SHOW_DOWNLOAD_REPORT, true)
|
||||
get() = appPrefs.getBoolean(PREF_SHOW_DOWNLOAD_REPORT, true)
|
||||
|
||||
fun enqueueDownloadedEpisodes(): Boolean {
|
||||
return prefs.getBoolean(PREF_ENQUEUE_DOWNLOADED, true)
|
||||
return appPrefs.getBoolean(PREF_ENQUEUE_DOWNLOADED, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var enqueueLocation: EnqueueLocation
|
||||
get() {
|
||||
val valStr = prefs.getString(PREF_ENQUEUE_LOCATION, EnqueueLocation.BACK.name)
|
||||
val valStr = appPrefs.getString(PREF_ENQUEUE_LOCATION, EnqueueLocation.BACK.name)
|
||||
try {
|
||||
return EnqueueLocation.valueOf(valStr!!)
|
||||
} catch (t: Throwable) {
|
||||
|
@ -321,64 +321,64 @@ object UserPreferences {
|
|||
}
|
||||
}
|
||||
set(location) {
|
||||
prefs.edit().putString(PREF_ENQUEUE_LOCATION, location.name).apply()
|
||||
appPrefs.edit().putString(PREF_ENQUEUE_LOCATION, location.name).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val isPauseOnHeadsetDisconnect: Boolean
|
||||
get() = prefs.getBoolean(PREF_PAUSE_ON_HEADSET_DISCONNECT, true)
|
||||
get() = appPrefs.getBoolean(PREF_PAUSE_ON_HEADSET_DISCONNECT, true)
|
||||
|
||||
@JvmStatic
|
||||
val isUnpauseOnHeadsetReconnect: Boolean
|
||||
get() = prefs.getBoolean(PREF_UNPAUSE_ON_HEADSET_RECONNECT, true)
|
||||
get() = appPrefs.getBoolean(PREF_UNPAUSE_ON_HEADSET_RECONNECT, true)
|
||||
|
||||
@JvmStatic
|
||||
val isUnpauseOnBluetoothReconnect: Boolean
|
||||
get() = prefs.getBoolean(PREF_UNPAUSE_ON_BLUETOOTH_RECONNECT, false)
|
||||
get() = appPrefs.getBoolean(PREF_UNPAUSE_ON_BLUETOOTH_RECONNECT, false)
|
||||
|
||||
@JvmStatic
|
||||
val hardwareForwardButton: Int
|
||||
get() = prefs.getString(PREF_HARDWARE_FORWARD_BUTTON, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD.toString())!!.toInt()
|
||||
get() = appPrefs.getString(PREF_HARDWARE_FORWARD_BUTTON, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD.toString())!!.toInt()
|
||||
|
||||
@JvmStatic
|
||||
val hardwarePreviousButton: Int
|
||||
get() = prefs.getString(PREF_HARDWARE_PREVIOUS_BUTTON, KeyEvent.KEYCODE_MEDIA_REWIND.toString())!!.toInt()
|
||||
get() = appPrefs.getString(PREF_HARDWARE_PREVIOUS_BUTTON, KeyEvent.KEYCODE_MEDIA_REWIND.toString())!!.toInt()
|
||||
|
||||
@JvmStatic
|
||||
@set:VisibleForTesting
|
||||
var isFollowQueue: Boolean
|
||||
get() = prefs.getBoolean(PREF_FOLLOW_QUEUE, true)
|
||||
get() = appPrefs.getBoolean(PREF_FOLLOW_QUEUE, true)
|
||||
/**
|
||||
* Set to true to enable Continuous Playback
|
||||
*/
|
||||
set(value) {
|
||||
prefs.edit().putBoolean(PREF_FOLLOW_QUEUE, value).apply()
|
||||
appPrefs.edit().putBoolean(PREF_FOLLOW_QUEUE, value).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun shouldSkipKeepEpisode(): Boolean {
|
||||
return prefs.getBoolean(PREF_SKIP_KEEPS_EPISODE, true)
|
||||
return appPrefs.getBoolean(PREF_SKIP_KEEPS_EPISODE, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun shouldFavoriteKeepEpisode(): Boolean {
|
||||
return prefs.getBoolean(PREF_FAVORITE_KEEPS_EPISODE, true)
|
||||
return appPrefs.getBoolean(PREF_FAVORITE_KEEPS_EPISODE, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val isAutoDelete: Boolean
|
||||
get() = prefs.getBoolean(PREF_AUTO_DELETE, false)
|
||||
get() = appPrefs.getBoolean(PREF_AUTO_DELETE, false)
|
||||
|
||||
@JvmStatic
|
||||
val isAutoDeleteLocal: Boolean
|
||||
get() = prefs.getBoolean(PREF_AUTO_DELETE_LOCAL, false)
|
||||
get() = appPrefs.getBoolean(PREF_AUTO_DELETE_LOCAL, false)
|
||||
|
||||
val smartMarkAsPlayedSecs: Int
|
||||
get() = prefs.getString(PREF_SMART_MARK_AS_PLAYED_SECS, "30")!!.toInt()
|
||||
get() = appPrefs.getString(PREF_SMART_MARK_AS_PLAYED_SECS, "30")!!.toInt()
|
||||
|
||||
@JvmStatic
|
||||
fun shouldDeleteRemoveFromQueue(): Boolean {
|
||||
return prefs.getBoolean(PREF_DELETE_REMOVES_FROM_QUEUE, false)
|
||||
return appPrefs.getBoolean(PREF_DELETE_REMOVES_FROM_QUEUE, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -389,7 +389,7 @@ object UserPreferences {
|
|||
private val audioPlaybackSpeed: Float
|
||||
get() {
|
||||
try {
|
||||
return prefs.getString(PREF_PLAYBACK_SPEED, "1.00")!!.toFloat()
|
||||
return appPrefs.getString(PREF_PLAYBACK_SPEED, "1.00")!!.toFloat()
|
||||
} catch (e: NumberFormatException) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
setPlaybackSpeed(1.0f)
|
||||
|
@ -400,7 +400,7 @@ object UserPreferences {
|
|||
val videoPlayMode: Int
|
||||
get() {
|
||||
try {
|
||||
return prefs.getString(PREF_VIDEO_MODE, "1")!!.toInt()
|
||||
return appPrefs.getString(PREF_VIDEO_MODE, "1")!!.toInt()
|
||||
} catch (e: NumberFormatException) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
setVideoMode(1)
|
||||
|
@ -412,7 +412,7 @@ object UserPreferences {
|
|||
var videoPlaybackSpeed: Float
|
||||
get() {
|
||||
try {
|
||||
return prefs.getString(PREF_VIDEO_PLAYBACK_SPEED, "1.00")!!.toFloat()
|
||||
return appPrefs.getString(PREF_VIDEO_PLAYBACK_SPEED, "1.00")!!.toFloat()
|
||||
} catch (e: NumberFormatException) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
videoPlaybackSpeed = 1.0f
|
||||
|
@ -420,21 +420,21 @@ object UserPreferences {
|
|||
}
|
||||
}
|
||||
set(speed) {
|
||||
prefs.edit()
|
||||
appPrefs.edit()
|
||||
.putString(PREF_VIDEO_PLAYBACK_SPEED, speed.toString())
|
||||
.apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var isSkipSilence: Boolean
|
||||
get() = prefs.getBoolean(PREF_PLAYBACK_SKIP_SILENCE, false)
|
||||
get() = appPrefs.getBoolean(PREF_PLAYBACK_SKIP_SILENCE, false)
|
||||
set(skipSilence) {
|
||||
prefs.edit().putBoolean(PREF_PLAYBACK_SKIP_SILENCE, skipSilence).apply()
|
||||
appPrefs.edit().putBoolean(PREF_PLAYBACK_SKIP_SILENCE, skipSilence).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var playbackSpeedArray: List<Float>
|
||||
get() = readPlaybackSpeedArray(prefs.getString(PREF_PLAYBACK_SPEED_ARRAY, null))
|
||||
get() = readPlaybackSpeedArray(appPrefs.getString(PREF_PLAYBACK_SPEED_ARRAY, null))
|
||||
set(speeds) {
|
||||
val format = DecimalFormatSymbols(Locale.US)
|
||||
format.decimalSeparator = '.'
|
||||
|
@ -443,16 +443,16 @@ object UserPreferences {
|
|||
for (speed in speeds) {
|
||||
jsonArray.put(speedFormat.format(speed.toDouble()))
|
||||
}
|
||||
prefs.edit().putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString()).apply()
|
||||
appPrefs.edit().putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString()).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun shouldPauseForFocusLoss(): Boolean {
|
||||
return prefs.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, true)
|
||||
return appPrefs.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, true)
|
||||
}
|
||||
|
||||
val updateInterval: Long
|
||||
get() = prefs.getString(PREF_UPDATE_INTERVAL, "12")!!.toInt().toLong()
|
||||
get() = appPrefs.getString(PREF_UPDATE_INTERVAL, "12")!!.toInt().toLong()
|
||||
|
||||
val isAutoUpdateDisabled: Boolean
|
||||
get() = updateInterval == 0L
|
||||
|
@ -460,7 +460,7 @@ object UserPreferences {
|
|||
private fun isAllowMobileFor(type: String): Boolean {
|
||||
val defaultValue = HashSet<String>()
|
||||
defaultValue.add("images")
|
||||
val allowed = prefs.getStringSet(PREF_MOBILE_UPDATE, defaultValue)
|
||||
val allowed = appPrefs.getStringSet(PREF_MOBILE_UPDATE, defaultValue)
|
||||
return allowed!!.contains(type)
|
||||
}
|
||||
|
||||
|
@ -509,12 +509,12 @@ object UserPreferences {
|
|||
private fun setAllowMobileFor(type: String, allow: Boolean) {
|
||||
val defaultValue = HashSet<String>()
|
||||
defaultValue.add("images")
|
||||
val getValueStringSet = prefs.getStringSet(PREF_MOBILE_UPDATE, defaultValue)
|
||||
val getValueStringSet = appPrefs.getStringSet(PREF_MOBILE_UPDATE, defaultValue)
|
||||
val allowed: MutableSet<String> = HashSet(getValueStringSet!!)
|
||||
if (allow) allowed.add(type)
|
||||
else allowed.remove(type)
|
||||
|
||||
prefs.edit().putStringSet(PREF_MOBILE_UPDATE, allowed).apply()
|
||||
appPrefs.edit().putStringSet(PREF_MOBILE_UPDATE, allowed).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -524,29 +524,29 @@ object UserPreferences {
|
|||
* negative integer EPISODE_CACHE_SIZE_UNLIMITED if the cache size is set to
|
||||
* 'unlimited'.
|
||||
*/
|
||||
get() = prefs.getString(PREF_EPISODE_CACHE_SIZE, "20")!!.toInt()
|
||||
get() = appPrefs.getString(PREF_EPISODE_CACHE_SIZE, "20")!!.toInt()
|
||||
|
||||
@JvmStatic
|
||||
@set:VisibleForTesting
|
||||
var isEnableAutodownload: Boolean
|
||||
get() = prefs.getBoolean(PREF_ENABLE_AUTODL, false)
|
||||
get() = appPrefs.getBoolean(PREF_ENABLE_AUTODL, false)
|
||||
set(enabled) {
|
||||
prefs.edit().putBoolean(PREF_ENABLE_AUTODL, enabled).apply()
|
||||
appPrefs.edit().putBoolean(PREF_ENABLE_AUTODL, enabled).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val isEnableAutodownloadOnBattery: Boolean
|
||||
get() = prefs.getBoolean(PREF_ENABLE_AUTODL_ON_BATTERY, true)
|
||||
get() = appPrefs.getBoolean(PREF_ENABLE_AUTODL_ON_BATTERY, true)
|
||||
|
||||
@JvmStatic
|
||||
val isEnableAutodownloadWifiFilter: Boolean
|
||||
get() = Build.VERSION.SDK_INT < 29 && prefs.getBoolean(PREF_ENABLE_AUTODL_WIFI_FILTER, false)
|
||||
get() = Build.VERSION.SDK_INT < 29 && appPrefs.getBoolean(PREF_ENABLE_AUTODL_WIFI_FILTER, false)
|
||||
|
||||
@JvmStatic
|
||||
var speedforwardSpeed: Float
|
||||
get() {
|
||||
try {
|
||||
return prefs.getString(PREF_SPEEDFORWRD_SPEED, "0.00")!!.toFloat()
|
||||
return appPrefs.getString(PREF_SPEEDFORWRD_SPEED, "0.00")!!.toFloat()
|
||||
} catch (e: NumberFormatException) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
speedforwardSpeed = 0.0f
|
||||
|
@ -554,14 +554,14 @@ object UserPreferences {
|
|||
}
|
||||
}
|
||||
set(speed) {
|
||||
prefs.edit().putString(PREF_SPEEDFORWRD_SPEED, speed.toString()).apply()
|
||||
appPrefs.edit().putString(PREF_SPEEDFORWRD_SPEED, speed.toString()).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var fallbackSpeed: Float
|
||||
get() {
|
||||
try {
|
||||
return prefs.getString(PREF_FALLBACK_SPEED, "0.00")!!.toFloat()
|
||||
return appPrefs.getString(PREF_FALLBACK_SPEED, "0.00")!!.toFloat()
|
||||
} catch (e: NumberFormatException) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
fallbackSpeed = 0.0f
|
||||
|
@ -569,42 +569,42 @@ object UserPreferences {
|
|||
}
|
||||
}
|
||||
set(speed) {
|
||||
prefs.edit().putString(PREF_FALLBACK_SPEED, speed.toString()).apply()
|
||||
appPrefs.edit().putString(PREF_FALLBACK_SPEED, speed.toString()).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var fastForwardSecs: Int
|
||||
get() = prefs.getInt(PREF_FAST_FORWARD_SECS, 30)
|
||||
get() = appPrefs.getInt(PREF_FAST_FORWARD_SECS, 30)
|
||||
set(secs) {
|
||||
prefs.edit().putInt(PREF_FAST_FORWARD_SECS, secs).apply()
|
||||
appPrefs.edit().putInt(PREF_FAST_FORWARD_SECS, secs).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var rewindSecs: Int
|
||||
get() = prefs.getInt(PREF_REWIND_SECS, 10)
|
||||
get() = appPrefs.getInt(PREF_REWIND_SECS, 10)
|
||||
set(secs) {
|
||||
prefs.edit().putInt(PREF_REWIND_SECS, secs).apply()
|
||||
appPrefs.edit().putInt(PREF_REWIND_SECS, secs).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val autodownloadSelectedNetworks: Array<String>
|
||||
get() {
|
||||
val selectedNetWorks = prefs.getString(PREF_AUTODL_SELECTED_NETWORKS, "")
|
||||
val selectedNetWorks = appPrefs.getString(PREF_AUTODL_SELECTED_NETWORKS, "")
|
||||
return TextUtils.split(selectedNetWorks, ",")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var proxyConfig: ProxyConfig
|
||||
get() {
|
||||
val type = Proxy.Type.valueOf(prefs.getString(PREF_PROXY_TYPE, Proxy.Type.DIRECT.name)!!)
|
||||
val host = prefs.getString(PREF_PROXY_HOST, null)
|
||||
val port = prefs.getInt(PREF_PROXY_PORT, 0)
|
||||
val username = prefs.getString(PREF_PROXY_USER, null)
|
||||
val password = prefs.getString(PREF_PROXY_PASSWORD, null)
|
||||
val type = Proxy.Type.valueOf(appPrefs.getString(PREF_PROXY_TYPE, Proxy.Type.DIRECT.name)!!)
|
||||
val host = appPrefs.getString(PREF_PROXY_HOST, null)
|
||||
val port = appPrefs.getInt(PREF_PROXY_PORT, 0)
|
||||
val username = appPrefs.getString(PREF_PROXY_USER, null)
|
||||
val password = appPrefs.getString(PREF_PROXY_PASSWORD, null)
|
||||
return ProxyConfig(type, host, port, username, password)
|
||||
}
|
||||
set(config) {
|
||||
val editor = prefs.edit()
|
||||
val editor = appPrefs.edit()
|
||||
editor.putString(PREF_PROXY_TYPE, config.type.name)
|
||||
if (config.host.isNullOrEmpty()) editor.remove(PREF_PROXY_HOST)
|
||||
else editor.putString(PREF_PROXY_HOST, config.host)
|
||||
|
@ -623,31 +623,31 @@ object UserPreferences {
|
|||
|
||||
@JvmStatic
|
||||
var isQueueLocked: Boolean
|
||||
get() = prefs.getBoolean(PREF_QUEUE_LOCKED, false)
|
||||
get() = appPrefs.getBoolean(PREF_QUEUE_LOCKED, false)
|
||||
set(locked) {
|
||||
prefs.edit().putBoolean(PREF_QUEUE_LOCKED, locked).apply()
|
||||
appPrefs.edit().putBoolean(PREF_QUEUE_LOCKED, locked).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setPlaybackSpeed(speed: Float) {
|
||||
prefs.edit().putString(PREF_PLAYBACK_SPEED, speed.toString()).apply()
|
||||
appPrefs.edit().putString(PREF_PLAYBACK_SPEED, speed.toString()).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setVideoMode(mode: Int) {
|
||||
prefs.edit().putString(PREF_VIDEO_MODE, mode.toString()).apply()
|
||||
appPrefs.edit().putString(PREF_VIDEO_MODE, mode.toString()).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setAutodownloadSelectedNetworks(value: Array<String?>?) {
|
||||
prefs.edit().putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value!!)).apply()
|
||||
appPrefs.edit().putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value!!)).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun gpodnetNotificationsEnabled(): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= 26) return true // System handles notification preferences
|
||||
|
||||
return prefs.getBoolean(PREF_GPODNET_NOTIFICATIONS, true)
|
||||
return appPrefs.getBoolean(PREF_GPODNET_NOTIFICATIONS, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -655,11 +655,11 @@ object UserPreferences {
|
|||
/**
|
||||
* Used for migration of the preference to system notification channels.
|
||||
*/
|
||||
get() = prefs.getBoolean(PREF_GPODNET_NOTIFICATIONS, true)
|
||||
get() = appPrefs.getBoolean(PREF_GPODNET_NOTIFICATIONS, true)
|
||||
|
||||
@JvmStatic
|
||||
fun setGpodnetNotificationsEnabled() {
|
||||
prefs.edit().putBoolean(PREF_GPODNET_NOTIFICATIONS, true).apply()
|
||||
appPrefs.edit().putBoolean(PREF_GPODNET_NOTIFICATIONS, true).apply()
|
||||
}
|
||||
|
||||
private fun readPlaybackSpeedArray(valueFromPrefs: String?): List<Float> {
|
||||
|
@ -682,9 +682,9 @@ object UserPreferences {
|
|||
|
||||
@JvmStatic
|
||||
var episodeCleanupValue: Int
|
||||
get() = prefs.getString(PREF_EPISODE_CLEANUP, "" + EPISODE_CLEANUP_NULL)!!.toInt()
|
||||
get() = appPrefs.getString(PREF_EPISODE_CLEANUP, "" + EPISODE_CLEANUP_NULL)!!.toInt()
|
||||
set(episodeCleanupValue) {
|
||||
prefs.edit().putString(PREF_EPISODE_CLEANUP, episodeCleanupValue.toString()).apply()
|
||||
appPrefs.edit().putString(PREF_EPISODE_CLEANUP, episodeCleanupValue.toString()).apply()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -697,7 +697,7 @@ object UserPreferences {
|
|||
*/
|
||||
@JvmStatic
|
||||
fun getDataFolder(type: String?): File? {
|
||||
var dataFolder = getTypeDir(prefs.getString(PREF_DATA_FOLDER, null), type)
|
||||
var dataFolder = getTypeDir(appPrefs.getString(PREF_DATA_FOLDER, null), type)
|
||||
if (dataFolder == null || !dataFolder.canWrite()) {
|
||||
Logd(TAG, "User data folder not writable or not set. Trying default.")
|
||||
dataFolder = context.getExternalFilesDir(type)
|
||||
|
@ -730,7 +730,7 @@ object UserPreferences {
|
|||
@JvmStatic
|
||||
fun setDataFolder(dir: String) {
|
||||
Logd(TAG, "setDataFolder(dir: $dir)")
|
||||
prefs.edit().putString(PREF_DATA_FOLDER, dir).apply()
|
||||
appPrefs.edit().putString(PREF_DATA_FOLDER, dir).apply()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -751,26 +751,26 @@ object UserPreferences {
|
|||
|
||||
@JvmStatic
|
||||
var defaultPage: String?
|
||||
get() = prefs.getString(PREF_DEFAULT_PAGE, "SubscriptionFragment")
|
||||
get() = appPrefs.getString(PREF_DEFAULT_PAGE, "SubscriptionFragment")
|
||||
set(defaultPage) {
|
||||
prefs.edit().putString(PREF_DEFAULT_PAGE, defaultPage).apply()
|
||||
appPrefs.edit().putString(PREF_DEFAULT_PAGE, defaultPage).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun backButtonOpensDrawer(): Boolean {
|
||||
return prefs.getBoolean(PREF_BACK_OPENS_DRAWER, false)
|
||||
return appPrefs.getBoolean(PREF_BACK_OPENS_DRAWER, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun timeRespectsSpeed(): Boolean {
|
||||
return prefs.getBoolean(PREF_TIME_RESPECTS_SPEED, false)
|
||||
return appPrefs.getBoolean(PREF_TIME_RESPECTS_SPEED, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var isStreamOverDownload: Boolean
|
||||
get() = prefs.getBoolean(PREF_STREAM_OVER_DOWNLOAD, false)
|
||||
get() = appPrefs.getBoolean(PREF_STREAM_OVER_DOWNLOAD, false)
|
||||
set(stream) {
|
||||
prefs.edit().putBoolean(PREF_STREAM_OVER_DOWNLOAD, stream).apply()
|
||||
appPrefs.edit().putBoolean(PREF_STREAM_OVER_DOWNLOAD, stream).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -780,14 +780,14 @@ object UserPreferences {
|
|||
*
|
||||
* @see .getQueueKeepSortedOrder
|
||||
*/
|
||||
get() = prefs.getBoolean(PREF_QUEUE_KEEP_SORTED, false)
|
||||
get() = appPrefs.getBoolean(PREF_QUEUE_KEEP_SORTED, false)
|
||||
/**
|
||||
* Enables/disables the keep sorted mode of the queue.
|
||||
*
|
||||
* @see .setQueueKeepSortedOrder
|
||||
*/
|
||||
set(keepSorted) {
|
||||
prefs.edit().putBoolean(PREF_QUEUE_KEEP_SORTED, keepSorted).apply()
|
||||
appPrefs.edit().putBoolean(PREF_QUEUE_KEEP_SORTED, keepSorted).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -799,7 +799,7 @@ object UserPreferences {
|
|||
* @see .isQueueKeepSorted
|
||||
*/
|
||||
get() {
|
||||
val sortOrderStr = prefs.getString(PREF_QUEUE_KEEP_SORTED_ORDER, "use-default")
|
||||
val sortOrderStr = appPrefs.getString(PREF_QUEUE_KEEP_SORTED_ORDER, "use-default")
|
||||
return SortOrder.parseWithDefault(sortOrderStr, SortOrder.DATE_NEW_OLD)
|
||||
}
|
||||
/**
|
||||
|
@ -809,13 +809,13 @@ object UserPreferences {
|
|||
*/
|
||||
set(sortOrder) {
|
||||
if (sortOrder == null) return
|
||||
prefs.edit().putString(PREF_QUEUE_KEEP_SORTED_ORDER, sortOrder.name).apply()
|
||||
appPrefs.edit().putString(PREF_QUEUE_KEEP_SORTED_ORDER, sortOrder.name).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val newEpisodesAction: NewEpisodesAction
|
||||
get() {
|
||||
val str = prefs.getString(PREF_NEW_EPISODES_ACTION, "" + NewEpisodesAction.GLOBAL.code)
|
||||
val str = appPrefs.getString(PREF_NEW_EPISODES_ACTION, "" + NewEpisodesAction.GLOBAL.code)
|
||||
return NewEpisodesAction.fromCode(str!!.toInt())
|
||||
}
|
||||
|
||||
|
@ -825,14 +825,14 @@ object UserPreferences {
|
|||
* Returns the sort order for the downloads.
|
||||
*/
|
||||
get() {
|
||||
val sortOrderStr = prefs.getString(PREF_DOWNLOADS_SORTED_ORDER, "" + SortOrder.DATE_NEW_OLD.code)
|
||||
val sortOrderStr = appPrefs.getString(PREF_DOWNLOADS_SORTED_ORDER, "" + SortOrder.DATE_NEW_OLD.code)
|
||||
return SortOrder.fromCodeString(sortOrderStr)
|
||||
}
|
||||
/**
|
||||
* Sets the sort order for the downloads.
|
||||
*/
|
||||
set(sortOrder) {
|
||||
prefs.edit().putString(PREF_DOWNLOADS_SORTED_ORDER, "" + sortOrder!!.code).apply()
|
||||
appPrefs.edit().putString(PREF_DOWNLOADS_SORTED_ORDER, "" + sortOrder!!.code).apply()
|
||||
}
|
||||
|
||||
// @JvmStatic
|
||||
|
@ -855,11 +855,11 @@ object UserPreferences {
|
|||
@JvmStatic
|
||||
var subscriptionsFilter: SubscriptionsFilter
|
||||
get() {
|
||||
val value = prefs.getString(PREF_FILTER_FEED, "")
|
||||
val value = appPrefs.getString(PREF_FILTER_FEED, "")
|
||||
return SubscriptionsFilter(value)
|
||||
}
|
||||
set(value) {
|
||||
prefs.edit().putString(PREF_FILTER_FEED, value.serialize()).apply()
|
||||
appPrefs.edit().putString(PREF_FILTER_FEED, value.serialize()).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -870,16 +870,16 @@ object UserPreferences {
|
|||
|
||||
@JvmStatic
|
||||
var allEpisodesSortOrder: SortOrder?
|
||||
get() = SortOrder.fromCodeString(prefs.getString(PREF_SORT_ALL_EPISODES, "" + SortOrder.DATE_NEW_OLD.code))
|
||||
get() = SortOrder.fromCodeString(appPrefs.getString(PREF_SORT_ALL_EPISODES, "" + SortOrder.DATE_NEW_OLD.code))
|
||||
set(s) {
|
||||
prefs.edit().putString(PREF_SORT_ALL_EPISODES, "" + s!!.code).apply()
|
||||
appPrefs.edit().putString(PREF_SORT_ALL_EPISODES, "" + s!!.code).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
var prefFilterAllEpisodes: String
|
||||
get() = prefs.getString(PREF_FILTER_ALL_EPISODES, "")?:""
|
||||
get() = appPrefs.getString(PREF_FILTER_ALL_EPISODES, "")?:""
|
||||
set(filter) {
|
||||
prefs.edit().putString(PREF_FILTER_ALL_EPISODES, filter).apply()
|
||||
appPrefs.edit().putString(PREF_FILTER_ALL_EPISODES, filter).apply()
|
||||
}
|
||||
|
||||
enum class ThemePreference {
|
||||
|
|
|
@ -15,6 +15,7 @@ import ac.mdiq.podcini.net.download.FeedUpdateManager.restartUpdateAlarm
|
|||
import ac.mdiq.podcini.ui.dialog.ChooseDataFolderDialog
|
||||
import ac.mdiq.podcini.ui.dialog.ProxyDialog
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.getDataFolder
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.setDataFolder
|
||||
import kotlin.Any
|
||||
|
@ -32,12 +33,12 @@ class DownloadsPreferencesFragment : PreferenceFragmentCompat(), OnSharedPrefere
|
|||
override fun onStart() {
|
||||
super.onStart()
|
||||
(activity as PreferenceActivity).supportActionBar!!.setTitle(R.string.downloads_pref)
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext()).registerOnSharedPreferenceChangeListener(this)
|
||||
appPrefs.registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext()).unregisterOnSharedPreferenceChangeListener(this)
|
||||
appPrefs.unregisterOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
|
|
@ -21,6 +21,7 @@ class MainPreferencesFragment : PreferenceFragmentCompat() {
|
|||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
Logd("MainPreferencesFragment", "onCreatePreferences")
|
||||
|
||||
// TODO: this can be expensive
|
||||
addPreferencesFromResource(R.xml.preferences)
|
||||
setupMainScreen()
|
||||
setupSearch()
|
||||
|
|
|
@ -37,7 +37,7 @@ class SwipePreferencesFragment : PreferenceFragmentCompat() {
|
|||
true
|
||||
}
|
||||
findPreference<Preference>(PREF_SWIPE_HISTORY)?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
SwipeActionsDialog(requireContext(), PlaybackHistoryFragment.TAG).show (object : SwipeActionsDialog.Callback {
|
||||
SwipeActionsDialog(requireContext(), HistoryFragment.TAG).show (object : SwipeActionsDialog.Callback {
|
||||
override fun onCall() {}
|
||||
})
|
||||
true
|
||||
|
|
|
@ -10,6 +10,9 @@ import ac.mdiq.podcini.net.sync.SynchronizationSettings.isProviderConnected
|
|||
import ac.mdiq.podcini.net.sync.SynchronizationSettings.wifiSyncEnabledKey
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity
|
||||
import ac.mdiq.podcini.ui.dialog.AuthenticationDialog
|
||||
import ac.mdiq.podcini.ui.fragment.AudioPlayerFragment.InternalPlayerFragment
|
||||
import ac.mdiq.podcini.ui.fragment.AudioPlayerFragment.InternalPlayerFragment.Companion
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import android.app.Activity
|
||||
|
@ -56,6 +59,7 @@ class SynchronizationPreferencesFragment : PreferenceFragmentCompat() {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd("SynchronizationPreferencesFragment", "Received event: ${event}")
|
||||
when (event) {
|
||||
is FlowEvent.SyncServiceEvent -> syncStatusChanged(event)
|
||||
else -> {}
|
||||
|
|
|
@ -6,6 +6,8 @@ import ac.mdiq.podcini.net.sync.SynchronizationCredentials
|
|||
import ac.mdiq.podcini.net.sync.SynchronizationSettings.setWifiSyncEnabled
|
||||
import ac.mdiq.podcini.net.sync.wifi.WifiSyncService.Companion.hostPort
|
||||
import ac.mdiq.podcini.net.sync.wifi.WifiSyncService.Companion.startInstantSync
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
|
@ -96,6 +98,7 @@ import java.util.*
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.SyncServiceEvent -> syncStatusChanged(event)
|
||||
else -> {}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ac.mdiq.podcini.receiver
|
||||
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions.Companion.SWIPE_ACTIONS_PREF_NAME
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.ComponentName
|
||||
|
@ -10,6 +11,7 @@ import androidx.work.OneTimeWorkRequest
|
|||
import androidx.work.WorkManager
|
||||
import ac.mdiq.podcini.ui.widget.WidgetUpdaterWorker
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.content.SharedPreferences
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class PlayerWidget : AppWidgetProvider() {
|
||||
|
@ -25,10 +27,9 @@ class PlayerWidget : AppWidgetProvider() {
|
|||
Logd(TAG, "onUpdate() called with: context = [$context], appWidgetManager = [$appWidgetManager], appWidgetIds = [${appWidgetIds.contentToString()}]")
|
||||
WidgetUpdaterWorker.enqueueWork(context)
|
||||
|
||||
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
if (!prefs.getBoolean(KEY_WORKAROUND_ENABLED, false)) {
|
||||
if (!prefs!!.getBoolean(KEY_WORKAROUND_ENABLED, false)) {
|
||||
scheduleWorkaround(context)
|
||||
prefs.edit().putBoolean(KEY_WORKAROUND_ENABLED, true).apply()
|
||||
prefs!!.edit().putBoolean(KEY_WORKAROUND_ENABLED, true).apply()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,26 +41,24 @@ class PlayerWidget : AppWidgetProvider() {
|
|||
|
||||
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
|
||||
Logd(TAG, "OnDeleted")
|
||||
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
for (appWidgetId in appWidgetIds) {
|
||||
prefs.edit().remove(KEY_WIDGET_COLOR + appWidgetId).apply()
|
||||
prefs.edit().remove(KEY_WIDGET_PLAYBACK_SPEED + appWidgetId).apply()
|
||||
prefs.edit().remove(KEY_WIDGET_REWIND + appWidgetId).apply()
|
||||
prefs.edit().remove(KEY_WIDGET_FAST_FORWARD + appWidgetId).apply()
|
||||
prefs.edit().remove(KEY_WIDGET_SKIP + appWidgetId).apply()
|
||||
prefs!!.edit().remove(KEY_WIDGET_COLOR + appWidgetId).apply()
|
||||
prefs!!.edit().remove(KEY_WIDGET_PLAYBACK_SPEED + appWidgetId).apply()
|
||||
prefs!!.edit().remove(KEY_WIDGET_REWIND + appWidgetId).apply()
|
||||
prefs!!.edit().remove(KEY_WIDGET_FAST_FORWARD + appWidgetId).apply()
|
||||
prefs!!.edit().remove(KEY_WIDGET_SKIP + appWidgetId).apply()
|
||||
}
|
||||
val manager = AppWidgetManager.getInstance(context)
|
||||
val widgetIds = manager.getAppWidgetIds(ComponentName(context, PlayerWidget::class.java))
|
||||
if (widgetIds.isEmpty()) {
|
||||
prefs.edit().putBoolean(KEY_WORKAROUND_ENABLED, false).apply()
|
||||
prefs!!.edit().putBoolean(KEY_WORKAROUND_ENABLED, false).apply()
|
||||
WorkManager.getInstance(context).cancelUniqueWork(WORKAROUND_WORK_NAME)
|
||||
}
|
||||
super.onDeleted(context, appWidgetIds)
|
||||
}
|
||||
|
||||
private fun setEnabled(context: Context, enabled: Boolean) {
|
||||
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
prefs.edit().putBoolean(KEY_ENABLED, enabled).apply()
|
||||
prefs!!.edit().putBoolean(KEY_ENABLED, enabled).apply()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -75,6 +74,12 @@ class PlayerWidget : AppWidgetProvider() {
|
|||
const val DEFAULT_COLOR: Int = -0xd9d3cf
|
||||
private const val WORKAROUND_WORK_NAME = "WidgetUpdaterWorkaround"
|
||||
|
||||
var prefs: SharedPreferences? = null
|
||||
|
||||
fun getSharedPrefs(context: Context) {
|
||||
if (prefs == null) prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
private fun scheduleWorkaround(context: Context) {
|
||||
// Enqueueing work enables a BOOT_COMPLETED receiver, which in turn makes Android refresh widgets.
|
||||
// This creates an endless loop with a flickering widget.
|
||||
|
@ -87,8 +92,8 @@ class PlayerWidget : AppWidgetProvider() {
|
|||
|
||||
@JvmStatic
|
||||
fun isEnabled(context: Context): Boolean {
|
||||
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
return prefs.getBoolean(KEY_ENABLED, false)
|
||||
// val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
return prefs!!.getBoolean(KEY_ENABLED, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,17 +9,17 @@ import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
|
|||
import ac.mdiq.podcini.storage.model.feed.SortOrder
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
/**
|
||||
* Implementation of the EpisodeCleanupAlgorithm interface used by Podcini.
|
||||
*/
|
||||
class APCleanupAlgorithm(
|
||||
/** the number of days after playback to wait before an item is eligible to be cleaned up.
|
||||
* Fractional for number of hours, e.g., 0.5 = 12 hours, 0.0416 = 1 hour. */
|
||||
@JvmField @get:VisibleForTesting val numberOfHoursAfterPlayback: Int
|
||||
) : EpisodeCleanupAlgorithm() {
|
||||
/** the number of days after playback to wait before an item is eligible to be cleaned up.
|
||||
* Fractional for number of hours, e.g., 0.5 = 12 hours, 0.0416 = 1 hour. */
|
||||
|
||||
class APCleanupAlgorithm(@JvmField @get:VisibleForTesting val numberOfHoursAfterPlayback: Int) : EpisodeCleanupAlgorithm() {
|
||||
/**
|
||||
* @return the number of episodes that *could* be cleaned up, if needed
|
||||
*/
|
||||
|
@ -44,7 +44,7 @@ class APCleanupAlgorithm(
|
|||
|
||||
for (item in delete) {
|
||||
try {
|
||||
DBWriter.deleteFeedMediaOfItem(context!!, item.media!!.id).get()
|
||||
runBlocking { DBWriter.deleteFeedMediaOfItem(context, item.media!!.id).join() }
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: ExecutionException) {
|
||||
|
@ -53,7 +53,6 @@ class APCleanupAlgorithm(
|
|||
}
|
||||
|
||||
val counter = delete.size
|
||||
|
||||
Log.i(TAG, String.format(Locale.US, "Auto-delete deleted %d episodes (%d requested)", counter, numberOfEpisodesToDelete))
|
||||
|
||||
return counter
|
||||
|
|
|
@ -6,6 +6,9 @@ import ac.mdiq.podcini.storage.DBReader.getEpisodes
|
|||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
|
||||
import ac.mdiq.podcini.storage.model.feed.SortOrder
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
|
@ -21,7 +24,7 @@ class APQueueCleanupAlgorithm : EpisodeCleanupAlgorithm() {
|
|||
return candidates.size
|
||||
}
|
||||
|
||||
public override fun performCleanup(context: Context, numberOfEpisodesToDelete: Int): Int {
|
||||
@OptIn(UnstableApi::class) public override fun performCleanup(context: Context, numberOfEpisodesToDelete: Int): Int {
|
||||
var candidates = candidates
|
||||
|
||||
// in the absence of better data, we'll sort by item publication date
|
||||
|
@ -38,8 +41,9 @@ class APQueueCleanupAlgorithm : EpisodeCleanupAlgorithm() {
|
|||
val delete = if (candidates.size > numberOfEpisodesToDelete) candidates.subList(0, numberOfEpisodesToDelete) else candidates
|
||||
|
||||
for (item in delete) {
|
||||
if (item.media == null) continue
|
||||
try {
|
||||
DBWriter.deleteFeedMediaOfItem(context!!, item.media!!.id).get()
|
||||
runBlocking { DBWriter.deleteFeedMediaOfItem(context, item.media!!.id).join() }
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: ExecutionException) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.text.TextUtils
|
|||
import android.util.Log
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
import java.util.concurrent.*
|
||||
|
||||
|
@ -68,15 +69,13 @@ import java.util.concurrent.*
|
|||
|
||||
if (feedID != 0L) {
|
||||
try {
|
||||
DBWriter.deleteFeed(context, feedID).get()
|
||||
runBlocking { DBWriter.deleteFeed(context, feedID).join() }
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: ExecutionException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "removeFeedWithDownloadUrl: Could not find feed with url: $downloadUrl")
|
||||
}
|
||||
} else Log.w(TAG, "removeFeedWithDownloadUrl: Could not find feed with url: $downloadUrl")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,15 +131,13 @@ import java.util.concurrent.*
|
|||
}
|
||||
|
||||
private fun searchFeedByIdentifyingValueOrID(feed: Feed): Feed? {
|
||||
if (feed.id != 0L) {
|
||||
return getFeed(feed.id)
|
||||
} else {
|
||||
val feeds = getFeedList()
|
||||
for (f in feeds.toList()) {
|
||||
if (f != null && f.identifyingValue == feed.identifyingValue) {
|
||||
f.items = getFeedItemList(f).toMutableList()
|
||||
return f
|
||||
}
|
||||
if (feed.id != 0L) return getFeed(feed.id)
|
||||
|
||||
val feeds = getFeedList()
|
||||
for (f in feeds.toList()) {
|
||||
if (f != null && f.identifyingValue == feed.identifyingValue) {
|
||||
f.items = getFeedItemList(f).toMutableList()
|
||||
return f
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
@ -275,9 +272,8 @@ import java.util.concurrent.*
|
|||
}
|
||||
}
|
||||
|
||||
if (oldItem != null) {
|
||||
oldItem.updateFromOther(item)
|
||||
} else {
|
||||
if (oldItem != null) oldItem.updateFromOther(item)
|
||||
else {
|
||||
Logd(TAG, "Found new item: " + item.title)
|
||||
item.feed = savedFeed
|
||||
|
||||
|
@ -314,13 +310,13 @@ import java.util.concurrent.*
|
|||
|
||||
try {
|
||||
if (savedFeed == null) {
|
||||
DBWriter.addNewFeed(context, newFeed).get()
|
||||
runBlocking { DBWriter.addNewFeed(context, newFeed).join() }
|
||||
// Update with default values that are set in database
|
||||
resultFeed = searchFeedByIdentifyingValueOrID(newFeed)
|
||||
} else DBWriter.persistCompleteFeed(savedFeed).get()
|
||||
} else runBlocking { DBWriter.persistCompleteFeed(savedFeed).join() }
|
||||
|
||||
DBReader.updateFeedList(adapter)
|
||||
if (removeUnlistedItems) DBWriter.deleteFeedItems(context, unlistedItems).get()
|
||||
if (removeUnlistedItems) runBlocking { DBWriter.deleteFeedItems(context, unlistedItems).join() }
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: ExecutionException) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import ac.mdiq.podcini.net.download.serviceinterface.DownloadServiceInterface
|
|||
import ac.mdiq.podcini.net.sync.model.EpisodeAction
|
||||
import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
|
||||
import ac.mdiq.podcini.playback.service.PlaybackServiceConstants
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.createInstanceFromPreferences
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.loadPlayableFromPreferences
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.currentlyPlayingFeedMediaId
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.writeNoMediaPlaying
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.enqueueLocation
|
||||
|
@ -29,7 +29,6 @@ import ac.mdiq.podcini.util.Logd
|
|||
import ac.mdiq.podcini.util.LongList
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import ac.mdiq.podcini.util.showStackTrace
|
||||
import android.app.backup.BackupManager
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
|
@ -37,16 +36,13 @@ import android.util.Log
|
|||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.Future
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.ContinuationInterceptor
|
||||
|
||||
/**
|
||||
* Provides methods for writing data to Podcini's database.
|
||||
|
@ -57,6 +53,8 @@ import java.util.concurrent.TimeUnit
|
|||
@UnstableApi object DBWriter {
|
||||
private const val TAG = "DBWriter"
|
||||
|
||||
val ioScope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
private val dbExec: ExecutorService = Executors.newSingleThreadExecutor { r: Runnable? ->
|
||||
val t = Thread(r)
|
||||
t.name = "DatabaseExecutor"
|
||||
|
@ -77,8 +75,8 @@ import java.util.concurrent.TimeUnit
|
|||
}
|
||||
}
|
||||
|
||||
fun deleteItemsMedia(items: List<FeedItem>) {
|
||||
runOnDbThread {
|
||||
fun deleteItemsMedia(items: List<FeedItem>) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
adapter.removeItemMedia(items)
|
||||
|
@ -93,7 +91,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param mediaId ID of the FeedMedia object whose downloaded file should be deleted.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun deleteFeedMediaOfItem(context: Context, mediaId: Long): Future<*> {
|
||||
fun deleteFeedMediaOfItem(context: Context, mediaId: Long) : Job {
|
||||
Logd(TAG, "deleteFeedMediaOfItem called")
|
||||
return runOnDbThread {
|
||||
val media = getFeedMedia(mediaId)
|
||||
|
@ -179,7 +177,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param feedId ID of the Feed that should be deleted.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun deleteFeed(context: Context, feedId: Long): Future<*> {
|
||||
fun deleteFeed(context: Context, feedId: Long) : Job {
|
||||
return runOnDbThread {
|
||||
val feed = getFeed(feedId) ?: return@runOnDbThread
|
||||
// delete stored media files and mark them as read
|
||||
|
@ -203,7 +201,7 @@ import java.util.concurrent.TimeUnit
|
|||
* Remove the listed items and their FeedMedia entries.
|
||||
* Deleting media also removes the download log entries.
|
||||
*/
|
||||
fun deleteFeedItems(context: Context, items: List<FeedItem>): Future<*> {
|
||||
fun deleteFeedItems(context: Context, items: List<FeedItem>) : Job {
|
||||
Logd(TAG, "deleteFeedItems called")
|
||||
return runOnDbThread { deleteFeedItemsSynchronous(context, items) }
|
||||
}
|
||||
|
@ -252,7 +250,7 @@ import java.util.concurrent.TimeUnit
|
|||
/**
|
||||
* Deletes the entire playback history.
|
||||
*/
|
||||
fun clearPlaybackHistory(): Future<*> {
|
||||
fun clearPlaybackHistory() : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -265,7 +263,7 @@ import java.util.concurrent.TimeUnit
|
|||
/**
|
||||
* Deletes the entire download log.
|
||||
*/
|
||||
fun clearDownloadLog(): Future<*> {
|
||||
fun clearDownloadLog() : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -275,8 +273,8 @@ import java.util.concurrent.TimeUnit
|
|||
}
|
||||
}
|
||||
|
||||
fun deleteFromPlaybackHistory(feedItem: FeedItem): Future<*> {
|
||||
return addItemToPlaybackHistory(feedItem.media, Date(0))
|
||||
fun deleteFromPlaybackHistory(feedItem: FeedItem) {
|
||||
addItemToPlaybackHistory(feedItem.media, Date(0))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -288,7 +286,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param date PlaybackCompletionDate for `media`
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun addItemToPlaybackHistory(media: FeedMedia?, date: Date? = Date()): Future<*> {
|
||||
fun addItemToPlaybackHistory(media: FeedMedia?, date: Date? = Date()) : Job {
|
||||
return runOnDbThread {
|
||||
if (media != null) {
|
||||
Logd(TAG, "Adding item to playback history")
|
||||
|
@ -308,7 +306,7 @@ import java.util.concurrent.TimeUnit
|
|||
*
|
||||
* @param status The DownloadStatus object.
|
||||
*/
|
||||
fun addDownloadStatus(status: DownloadResult?): Future<*> {
|
||||
fun addDownloadStatus(status: DownloadResult?) : Job {
|
||||
Logd(TAG, "addDownloadStatus called")
|
||||
return runOnDbThread {
|
||||
if (status != null) {
|
||||
|
@ -331,7 +329,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param performAutoDownload True if an auto-download process should be started after the operation
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= queue.size()
|
||||
*/
|
||||
@UnstableApi fun addQueueItemAt(context: Context, itemId: Long, index: Int, performAutoDownload: Boolean): Future<*> {
|
||||
@UnstableApi fun addQueueItemAt(context: Context, itemId: Long, index: Int, performAutoDownload: Boolean) : Job {
|
||||
Logd(TAG, "addQueueItemAt called")
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
|
@ -357,11 +355,11 @@ import java.util.concurrent.TimeUnit
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun addQueueItem(context: Context, vararg items: FeedItem): Future<*> {
|
||||
fun addQueueItem(context: Context, vararg items: FeedItem) : Job {
|
||||
return addQueueItem(context, true, *items)
|
||||
}
|
||||
|
||||
fun addQueueItem(context: Context, markAsUnplayed: Boolean, vararg items: FeedItem): Future<*> {
|
||||
fun addQueueItem(context: Context, markAsUnplayed: Boolean, vararg items: FeedItem) : Job {
|
||||
Logd(TAG, "addQueueItem called")
|
||||
val itemIds = LongList(items.size)
|
||||
for (item in items) {
|
||||
|
@ -380,7 +378,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param performAutoDownload true if an auto-download process should be started after the operation.
|
||||
* @param itemIds IDs of the FeedItem objects that should be added to the queue.
|
||||
*/
|
||||
@UnstableApi fun addQueueItem(context: Context, performAutoDownload: Boolean, vararg itemIds: Long): Future<*> {
|
||||
@UnstableApi fun addQueueItem(context: Context, performAutoDownload: Boolean, vararg itemIds: Long) : Job {
|
||||
return addQueueItem(context, performAutoDownload, true, *itemIds)
|
||||
}
|
||||
|
||||
|
@ -393,7 +391,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param markAsUnplayed true if the items should be marked as unplayed when enqueueing
|
||||
* @param itemIds IDs of the FeedItem objects that should be added to the queue.
|
||||
*/
|
||||
@UnstableApi fun addQueueItem(context: Context, performAutoDownload: Boolean, markAsUnplayed: Boolean, vararg itemIds: Long): Future<*> {
|
||||
@UnstableApi fun addQueueItem(context: Context, performAutoDownload: Boolean, markAsUnplayed: Boolean, vararg itemIds: Long) : Job {
|
||||
Logd(TAG, "addQueueItem(context ...) called")
|
||||
return runOnDbThread {
|
||||
if (itemIds.isEmpty()) return@runOnDbThread
|
||||
|
@ -406,9 +404,8 @@ import java.util.concurrent.TimeUnit
|
|||
val markAsUnplayedIds = LongList()
|
||||
val events: MutableList<FlowEvent.QueueEvent> = ArrayList()
|
||||
val updatedItems: MutableList<FeedItem> = ArrayList()
|
||||
val positionCalculator =
|
||||
ItemEnqueuePositionCalculator(enqueueLocation)
|
||||
val currentlyPlaying = createInstanceFromPreferences(context)
|
||||
val positionCalculator = ItemEnqueuePositionCalculator(enqueueLocation)
|
||||
val currentlyPlaying = loadPlayableFromPreferences()
|
||||
var insertPosition = positionCalculator.calcPosition(queue, currentlyPlaying)
|
||||
for (itemId in itemIds) {
|
||||
if (!itemListContains(queue, itemId)) {
|
||||
|
@ -468,7 +465,7 @@ import java.util.concurrent.TimeUnit
|
|||
* Removes all FeedItem objects from the queue.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun clearQueue(): Future<*> {
|
||||
fun clearQueue() : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -486,19 +483,19 @@ import java.util.concurrent.TimeUnit
|
|||
* @param item FeedItem that should be removed.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun removeQueueItem(context: Context, performAutoDownload: Boolean, item: FeedItem): Future<*> {
|
||||
fun removeQueueItem(context: Context, performAutoDownload: Boolean, item: FeedItem) : Job {
|
||||
return runOnDbThread { removeQueueItemSynchronous(context, performAutoDownload, item.id) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun removeQueueItem(context: Context, performAutoDownload: Boolean, vararg itemIds: Long): Future<*> {
|
||||
fun removeQueueItem(context: Context, performAutoDownload: Boolean, vararg itemIds: Long) : Job {
|
||||
return runOnDbThread { removeQueueItemSynchronous(context, performAutoDownload, *itemIds) }
|
||||
}
|
||||
|
||||
@UnstableApi private fun removeQueueItemSynchronous(context: Context, performAutoDownload: Boolean, vararg itemIds: Long) {
|
||||
Logd(TAG, "removeQueueItemSynchronous called $itemIds")
|
||||
if (itemIds.isEmpty()) return
|
||||
showStackTrace()
|
||||
// showStackTrace()
|
||||
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -535,11 +532,12 @@ import java.util.concurrent.TimeUnit
|
|||
if (performAutoDownload) autodownloadUndownloadedItems(context)
|
||||
}
|
||||
|
||||
fun toggleFavoriteItem(item: FeedItem): Future<*> {
|
||||
return if (item.isTagged(FeedItem.TAG_FAVORITE)) removeFavoriteItem(item) else addFavoriteItem(item)
|
||||
|
||||
fun toggleFavoriteItem(item: FeedItem) {
|
||||
if (item.isTagged(FeedItem.TAG_FAVORITE)) removeFavoriteItem(item) else addFavoriteItem(item)
|
||||
}
|
||||
|
||||
fun addFavoriteItem(item: FeedItem): Future<*> {
|
||||
fun addFavoriteItem(item: FeedItem) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance().open()
|
||||
adapter.addFavoriteItem(item)
|
||||
|
@ -550,7 +548,7 @@ import java.util.concurrent.TimeUnit
|
|||
}
|
||||
}
|
||||
|
||||
fun removeFavoriteItem(item: FeedItem): Future<*> {
|
||||
fun removeFavoriteItem(item: FeedItem) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance().open()
|
||||
adapter.removeFavoriteItem(item)
|
||||
|
@ -567,7 +565,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param itemId The item to move to the top of the queue
|
||||
* @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
|
||||
*/
|
||||
fun moveQueueItemToTop(itemId: Long, broadcastUpdate: Boolean): Future<*> {
|
||||
fun moveQueueItemToTop(itemId: Long, broadcastUpdate: Boolean) : Job {
|
||||
return runOnDbThread {
|
||||
val queueIdList = getQueueIDList()
|
||||
val index = queueIdList.indexOf(itemId)
|
||||
|
@ -582,7 +580,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param itemId The item to move to the bottom of the queue
|
||||
* @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
|
||||
*/
|
||||
fun moveQueueItemToBottom(itemId: Long, broadcastUpdate: Boolean): Future<*> {
|
||||
fun moveQueueItemToBottom(itemId: Long, broadcastUpdate: Boolean) : Job {
|
||||
return runOnDbThread {
|
||||
val queueIdList = getQueueIDList()
|
||||
val index = queueIdList.indexOf(itemId)
|
||||
|
@ -601,7 +599,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @throws IndexOutOfBoundsException if (to < 0 || to >= queue.size()) || (from < 0 || from >= queue.size())
|
||||
*/
|
||||
@JvmStatic
|
||||
fun moveQueueItem(from: Int, to: Int, broadcastUpdate: Boolean): Future<*> {
|
||||
fun moveQueueItem(from: Int, to: Int, broadcastUpdate: Boolean) : Job {
|
||||
return runOnDbThread { moveQueueItemHelper(from, to, broadcastUpdate) }
|
||||
}
|
||||
|
||||
|
@ -634,7 +632,7 @@ import java.util.concurrent.TimeUnit
|
|||
adapter.close()
|
||||
}
|
||||
|
||||
fun resetPagedFeedPage(feed: Feed?): Future<*> {
|
||||
fun resetPagedFeedPage(feed: Feed?) : Job {
|
||||
return runOnDbThread {
|
||||
if (feed != null) {
|
||||
val adapter = getInstance()
|
||||
|
@ -652,7 +650,7 @@ import java.util.concurrent.TimeUnit
|
|||
* FeedItem.UNPLAYED
|
||||
* @param itemIds IDs of the FeedItems.
|
||||
*/
|
||||
fun markItemPlayed(played: Int, vararg itemIds: Long): Future<*> {
|
||||
fun markItemPlayed(played: Int, vararg itemIds: Long) : Job {
|
||||
return markItemPlayed(played, true, *itemIds)
|
||||
}
|
||||
|
||||
|
@ -665,7 +663,7 @@ import java.util.concurrent.TimeUnit
|
|||
* This option is usually set to true
|
||||
* @param itemIds IDs of the FeedItems.
|
||||
*/
|
||||
fun markItemPlayed(played: Int, broadcastUpdate: Boolean, vararg itemIds: Long): Future<*> {
|
||||
fun markItemPlayed(played: Int, broadcastUpdate: Boolean, vararg itemIds: Long) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -683,12 +681,12 @@ import java.util.concurrent.TimeUnit
|
|||
* FeedItem.NEW, FeedItem.UNPLAYED
|
||||
* @param resetMediaPosition true if this method should also reset the position of the FeedItem's FeedMedia object.
|
||||
*/
|
||||
fun markItemPlayed(item: FeedItem, played: Int, resetMediaPosition: Boolean): Future<*> {
|
||||
fun markItemPlayed(item: FeedItem, played: Int, resetMediaPosition: Boolean) : Job {
|
||||
val mediaId = if (item.media != null) item.media!!.id else 0
|
||||
return markItemPlayed(item.id, played, mediaId, resetMediaPosition)
|
||||
}
|
||||
|
||||
private fun markItemPlayed(itemId: Long, played: Int, mediaId: Long, resetMediaPosition: Boolean): Future<*> {
|
||||
private fun markItemPlayed(itemId: Long, played: Int, mediaId: Long, resetMediaPosition: Boolean) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -703,7 +701,7 @@ import java.util.concurrent.TimeUnit
|
|||
*
|
||||
* @param feedId ID of the Feed.
|
||||
*/
|
||||
fun removeFeedNewFlag(feedId: Long): Future<*> {
|
||||
fun removeFeedNewFlag(feedId: Long) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -717,7 +715,7 @@ import java.util.concurrent.TimeUnit
|
|||
* Sets the 'read'-attribute of all NEW FeedItems to UNPLAYED.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun removeAllNewFlags(): Future<*> {
|
||||
fun removeAllNewFlags() : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -727,7 +725,7 @@ import java.util.concurrent.TimeUnit
|
|||
}
|
||||
}
|
||||
|
||||
fun addNewFeed(context: Context, vararg feeds: Feed): Future<*> {
|
||||
fun addNewFeed(context: Context, vararg feeds: Feed) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -744,7 +742,7 @@ import java.util.concurrent.TimeUnit
|
|||
}
|
||||
}
|
||||
|
||||
fun persistCompleteFeed(vararg feeds: Feed): Future<*> {
|
||||
fun persistCompleteFeed(vararg feeds: Feed) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -753,7 +751,7 @@ import java.util.concurrent.TimeUnit
|
|||
}
|
||||
}
|
||||
|
||||
fun persistItemList(items: List<FeedItem>): Future<*> {
|
||||
fun persistItemList(items: List<FeedItem>) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -769,7 +767,7 @@ import java.util.concurrent.TimeUnit
|
|||
*
|
||||
* @param media The FeedMedia object.
|
||||
*/
|
||||
fun persistFeedMedia(media: FeedMedia): Future<*> {
|
||||
fun persistFeedMedia(media: FeedMedia) : Job {
|
||||
Logd(TAG, "persistFeedMedia called")
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
|
@ -785,7 +783,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param media The FeedMedia object.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun persistFeedMediaPlaybackInfo(media: FeedMedia?): Future<*> {
|
||||
fun persistFeedMediaPlaybackInfo(media: FeedMedia?) : Job {
|
||||
Logd(TAG, "persistFeedMediaPlaybackInfo called")
|
||||
return runOnDbThread {
|
||||
if (media != null) {
|
||||
|
@ -804,7 +802,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param item The FeedItem object.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun persistFeedItem(item: FeedItem?): Future<*> {
|
||||
fun persistFeedItem(item: FeedItem?) : Job {
|
||||
Logd(TAG, "persistFeedItem called")
|
||||
return runOnDbThread {
|
||||
if (item != null) {
|
||||
|
@ -820,7 +818,7 @@ import java.util.concurrent.TimeUnit
|
|||
/**
|
||||
* Updates download URL of a feed
|
||||
*/
|
||||
fun updateFeedDownloadURL(original: String, updated: String): Future<*> {
|
||||
fun updateFeedDownloadURL(original: String, updated: String) : Job {
|
||||
Logd(TAG, "updateFeedDownloadURL(original: $original, updated: $updated)")
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
|
@ -835,7 +833,7 @@ import java.util.concurrent.TimeUnit
|
|||
*
|
||||
* @param preferences The FeedPreferences object.
|
||||
*/
|
||||
fun persistFeedPreferences(preferences: FeedPreferences): Future<*> {
|
||||
fun persistFeedPreferences(preferences: FeedPreferences) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -863,7 +861,7 @@ import java.util.concurrent.TimeUnit
|
|||
*
|
||||
* @param lastUpdateFailed true if last update failed
|
||||
*/
|
||||
fun persistFeedLastUpdateFailed(feedId: Long, lastUpdateFailed: Boolean): Future<*> {
|
||||
fun persistFeedLastUpdateFailed(feedId: Long, lastUpdateFailed: Boolean) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -873,7 +871,7 @@ import java.util.concurrent.TimeUnit
|
|||
}
|
||||
}
|
||||
|
||||
fun persistFeedCustomTitle(feed: Feed): Future<*> {
|
||||
fun persistFeedCustomTitle(feed: Feed) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -890,10 +888,10 @@ import java.util.concurrent.TimeUnit
|
|||
* QueueUpdateBroadcast. This option should be set to `false`
|
||||
* if the caller wants to avoid unexpected updates of the GUI.
|
||||
*/
|
||||
fun reorderQueue(sortOrder: SortOrder?, broadcastUpdate: Boolean): Future<*> {
|
||||
fun reorderQueue(sortOrder: SortOrder?, broadcastUpdate: Boolean) : Job {
|
||||
if (sortOrder == null) {
|
||||
Log.w(TAG, "reorderQueue() - sortOrder is null. Do nothing.")
|
||||
return runOnDbThread {}
|
||||
return Job()
|
||||
}
|
||||
val permutor = getPermutor(sortOrder)
|
||||
return runOnDbThread {
|
||||
|
@ -914,7 +912,7 @@ import java.util.concurrent.TimeUnit
|
|||
* @param feedId The feed's ID
|
||||
* @param filterValues Values that represent properties to filter by
|
||||
*/
|
||||
fun persistFeedItemsFilter(feedId: Long, filterValues: Set<String>): Future<*> {
|
||||
fun persistFeedItemsFilter(feedId: Long, filterValues: Set<String>) : Job {
|
||||
Logd(TAG, "persistFeedItemsFilter() called with: feedId = [$feedId], filterValues = [$filterValues]")
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
|
@ -929,7 +927,7 @@ import java.util.concurrent.TimeUnit
|
|||
* Set item sort order of the feed
|
||||
*
|
||||
*/
|
||||
fun persistFeedItemSortOrder(feedId: Long, sortOrder: SortOrder?): Future<*> {
|
||||
fun persistFeedItemSortOrder(feedId: Long, sortOrder: SortOrder?) : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
|
@ -942,32 +940,36 @@ import java.util.concurrent.TimeUnit
|
|||
/**
|
||||
* Reset the statistics in DB
|
||||
*/
|
||||
// fun resetStatistics(): Future<*> {
|
||||
// return runOnDbThread {
|
||||
// val adapter = getInstance()
|
||||
// adapter.open()
|
||||
// adapter.resetAllMediaPlayedDuration()
|
||||
// adapter.close()
|
||||
// }
|
||||
// }
|
||||
|
||||
suspend fun resetStatistics(): Unit = withContext(Dispatchers.IO) {
|
||||
val result = async {
|
||||
fun resetStatistics() : Job {
|
||||
return runOnDbThread {
|
||||
val adapter = getInstance()
|
||||
adapter.open()
|
||||
adapter.resetAllMediaPlayedDuration()
|
||||
adapter.close()
|
||||
}
|
||||
result.await()
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit to the DB thread only if caller is not already on the DB thread. Otherwise,
|
||||
* just execute synchronously
|
||||
*/
|
||||
private fun runOnDbThread(runnable: Runnable): Future<*> {
|
||||
if ("DatabaseExecutor" == Thread.currentThread().name) {
|
||||
runnable.run()
|
||||
return Futures.immediateFuture<Any?>(null)
|
||||
} else return dbExec.submit(runnable)
|
||||
// private fun runOnDbThread(runnable: Runnable): Future<*> {
|
||||
// if ("DatabaseExecutor" == Thread.currentThread().name) {
|
||||
// runnable.run()
|
||||
// return Futures.immediateFuture<Any?>(null)
|
||||
// } else return dbExec.submit(runnable)
|
||||
// }
|
||||
|
||||
private fun runOnDbThread(block: suspend () -> Unit) : Job {
|
||||
Logd(TAG, "DBWriter runOnDbThread")
|
||||
return ioScope.launch {
|
||||
if (Dispatchers.IO == coroutineContext[ContinuationInterceptor]) {
|
||||
block()
|
||||
} else {
|
||||
withContext(Dispatchers.IO) {
|
||||
block()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import ac.mdiq.podcini.preferences.UserPreferences
|
|||
import ac.mdiq.podcini.preferences.UserPreferences.episodeCacheSize
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
|
@ -41,8 +42,9 @@ class ExceptFavoriteCleanupAlgorithm : EpisodeCleanupAlgorithm() {
|
|||
val delete = if (candidates.size > numberOfEpisodesToDelete) candidates.subList(0, numberOfEpisodesToDelete) else candidates
|
||||
|
||||
for (item in delete) {
|
||||
if (item.media == null) continue
|
||||
try {
|
||||
DBWriter.deleteFeedMediaOfItem(context!!, item.media!!.id).get()
|
||||
runBlocking { DBWriter.deleteFeedMediaOfItem(context, item.media!!.id).join() }
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: ExecutionException) {
|
||||
|
|
|
@ -105,7 +105,7 @@ class Feed : FeedFile {
|
|||
var sortOrder: SortOrder? = null
|
||||
set(sortOrder) {
|
||||
if (sortOrder == null) {
|
||||
Log.w("Feed sortOrder", "The specified sortOrder $sortOrder is invalid.")
|
||||
// Log.w("Feed sortOrder", "The specified sortOrder $sortOrder is invalid.")
|
||||
return
|
||||
}
|
||||
field = sortOrder
|
||||
|
|
|
@ -9,7 +9,7 @@ import ac.mdiq.podcini.storage.DBWriter
|
|||
import ac.mdiq.podcini.util.LongList
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.net.download.serviceinterface.DownloadServiceInterface
|
||||
import ac.mdiq.podcini.ui.view.LocalDeleteModal
|
||||
import ac.mdiq.podcini.ui.utils.LocalDeleteModal
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
|
||||
@UnstableApi
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.view.View
|
|||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.storage.DBWriter
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.ui.view.LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary
|
||||
import ac.mdiq.podcini.ui.utils.LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
|
||||
class DeleteActionButton(item: FeedItem) : ItemActionButton(item) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package ac.mdiq.podcini.ui.actions.menuhandler
|
||||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.net.sync.SynchronizationSettings
|
||||
import ac.mdiq.podcini.net.sync.SynchronizationSettings.isProviderConnected
|
||||
import ac.mdiq.podcini.net.sync.SynchronizationSettings.wifiSyncEnabledKey
|
||||
import ac.mdiq.podcini.net.sync.model.EpisodeAction
|
||||
|
@ -14,16 +13,19 @@ import ac.mdiq.podcini.storage.model.feed.FeedItem
|
|||
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.dialog.ShareDialog
|
||||
import ac.mdiq.podcini.ui.view.LocalDeleteModal
|
||||
import ac.mdiq.podcini.ui.utils.LocalDeleteModal
|
||||
import ac.mdiq.podcini.util.*
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.math.ceil
|
||||
|
||||
|
||||
|
@ -49,7 +51,6 @@ object FeedItemMenuHandler {
|
|||
val hasMedia = selectedItem.media != null
|
||||
val isPlaying = hasMedia && PlaybackStatus.isPlaying(selectedItem.media)
|
||||
val isInQueue: Boolean = selectedItem.isTagged(FeedItem.TAG_QUEUE)
|
||||
val fileDownloaded = hasMedia && selectedItem.media?.fileExists()?:false
|
||||
val isLocalFile = hasMedia && selectedItem.feed?.isLocalFeed?:false
|
||||
val isFavorite: Boolean = selectedItem.isTagged(FeedItem.TAG_FAVORITE)
|
||||
|
||||
|
@ -73,7 +74,11 @@ object FeedItemMenuHandler {
|
|||
|
||||
setItemVisibility(menu, R.id.add_to_favorites_item, !isFavorite)
|
||||
setItemVisibility(menu, R.id.remove_from_favorites_item, isFavorite)
|
||||
setItemVisibility(menu, R.id.remove_item, fileDownloaded || isLocalFile)
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val fileDownloaded = withContext(Dispatchers.IO) { hasMedia && selectedItem.media?.fileExists() ?: false }
|
||||
setItemVisibility(menu, R.id.remove_item, fileDownloaded || isLocalFile)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import ac.mdiq.podcini.R
|
|||
import ac.mdiq.podcini.storage.DBWriter
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
|
||||
import ac.mdiq.podcini.ui.view.LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary
|
||||
import ac.mdiq.podcini.ui.utils.LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary
|
||||
|
||||
class DeleteSwipeAction : SwipeAction {
|
||||
override fun getId(): String {
|
||||
|
|
|
@ -3,18 +3,21 @@ package ac.mdiq.podcini.ui.actions.swipeactions
|
|||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItemFilter
|
||||
import ac.mdiq.podcini.ui.dialog.SwipeActionsDialog
|
||||
import ac.mdiq.podcini.ui.fragment.*
|
||||
import ac.mdiq.podcini.ui.fragment.AllEpisodesFragment
|
||||
import ac.mdiq.podcini.ui.fragment.DownloadsFragment
|
||||
import ac.mdiq.podcini.ui.fragment.HistoryFragment
|
||||
import ac.mdiq.podcini.ui.fragment.QueueFragment
|
||||
import ac.mdiq.podcini.ui.utils.ThemeUtils.getColorFromAttr
|
||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Canvas
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import androidx.lifecycle.*
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -26,7 +29,7 @@ import kotlin.math.min
|
|||
import kotlin.math.sin
|
||||
|
||||
open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private val tag: String) :
|
||||
ItemTouchHelper.SimpleCallback(dragDirs, ItemTouchHelper.RIGHT or ItemTouchHelper.LEFT), LifecycleObserver {
|
||||
ItemTouchHelper.SimpleCallback(dragDirs, ItemTouchHelper.RIGHT or ItemTouchHelper.LEFT), DefaultLifecycleObserver {
|
||||
|
||||
private var filter: FeedItemFilter? = null
|
||||
|
||||
|
@ -36,17 +39,19 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
private val itemTouchHelper = ItemTouchHelper(this)
|
||||
|
||||
init {
|
||||
reloadPreference()
|
||||
fragment.lifecycle.addObserver(this)
|
||||
actions = getPrefs(fragment.requireContext(), tag)
|
||||
}
|
||||
|
||||
constructor(fragment: Fragment, tag: String) : this(0, fragment, tag)
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_START)
|
||||
fun reloadPreference() {
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
actions = getPrefs(fragment.requireContext(), tag)
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
actions = null
|
||||
}
|
||||
|
||||
fun setFilter(filter: FeedItemFilter?) {
|
||||
this.filter = filter
|
||||
}
|
||||
|
@ -69,19 +74,10 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
|
||||
@UnstableApi override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {
|
||||
if (actions != null && !actions!!.hasActions()) {
|
||||
//open settings dialog if no prefs are set
|
||||
showDialog()
|
||||
// SwipeActionsDialog(fragment.requireContext(), tag).show(object : SwipeActionsDialog.Callback {
|
||||
// override fun onCall() {
|
||||
// this@SwipeActions.reloadPreference()
|
||||
// EventBus.getDefault().post(SwipeActionsChangedEvent())
|
||||
// }
|
||||
// })
|
||||
return
|
||||
}
|
||||
|
||||
val item = (viewHolder as EpisodeItemViewHolder).feedItem
|
||||
|
||||
if (actions != null && item != null && filter != null)
|
||||
(if (swipeDir == ItemTouchHelper.RIGHT) actions!!.right else actions!!.left)?.performAction(item, fragment, filter!!)
|
||||
}
|
||||
|
@ -89,7 +85,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
fun showDialog() {
|
||||
SwipeActionsDialog(fragment.requireContext(), tag).show(object : SwipeActionsDialog.Callback {
|
||||
override fun onCall() {
|
||||
this@SwipeActions.reloadPreference()
|
||||
actions = getPrefs(fragment.requireContext(), tag)
|
||||
EventFlow.postEvent(FlowEvent.SwipeActionsChangedEvent())
|
||||
}
|
||||
})
|
||||
|
@ -124,12 +120,10 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE && wontLeave) {
|
||||
swipeOutEnabled = false
|
||||
|
||||
val swipeThresholdReached = displacementPercentage == 1f
|
||||
|
||||
// Move slower when getting near the maxMovement
|
||||
dx = sign * maxMovement * sin((Math.PI / 2) * displacementPercentage)
|
||||
.toFloat()
|
||||
dx = sign * maxMovement * sin((Math.PI / 2) * displacementPercentage).toFloat()
|
||||
|
||||
if (isCurrentlyActive) {
|
||||
val dir = if (dx > 0) ItemTouchHelper.RIGHT else ItemTouchHelper.LEFT
|
||||
|
@ -202,10 +196,16 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val PREF_NAME: String = "SwipeActionsPrefs"
|
||||
const val SWIPE_ACTIONS_PREF_NAME: String = "SwipeActionsPrefs"
|
||||
const val KEY_PREFIX_SWIPEACTIONS: String = "PrefSwipeActions"
|
||||
const val KEY_PREFIX_NO_ACTION: String = "PrefNoSwipeAction"
|
||||
|
||||
var prefs: SharedPreferences? = null
|
||||
|
||||
fun getSharedPrefs(context: Context) {
|
||||
if (prefs == null) prefs = context.getSharedPreferences(SWIPE_ACTIONS_PREF_NAME, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val swipeActions: List<SwipeAction> = Collections.unmodifiableList(
|
||||
listOf(NoActionSwipeAction(), AddToQueueSwipeAction(), StartDownloadSwipeAction(), MarkFavoriteSwipeAction(),
|
||||
|
@ -214,9 +214,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
)
|
||||
|
||||
private fun getPrefs(context: Context, tag: String, defaultActions: String): Actions {
|
||||
val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
val prefsString = prefs.getString(KEY_PREFIX_SWIPEACTIONS + tag, defaultActions)
|
||||
|
||||
val prefsString = prefs!!.getString(KEY_PREFIX_SWIPEACTIONS + tag, defaultActions)
|
||||
return Actions(prefsString)
|
||||
}
|
||||
|
||||
|
@ -224,12 +222,12 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
return getPrefs(context, tag, "")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@OptIn(UnstableApi::class) @JvmStatic
|
||||
fun getPrefsWithDefaults(context: Context, tag: String): Actions {
|
||||
val defaultActions = when (tag) {
|
||||
QueueFragment.TAG -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
|
||||
DownloadsFragment.TAG -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
|
||||
PlaybackHistoryFragment.TAG -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
|
||||
HistoryFragment.TAG -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
|
||||
AllEpisodesFragment.TAG -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
|
||||
else -> SwipeAction.NO_ACTION + "," + SwipeAction.NO_ACTION
|
||||
}
|
||||
|
@ -238,8 +236,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
|
||||
@JvmStatic
|
||||
fun isSwipeActionEnabled(context: Context, tag: String): Boolean {
|
||||
val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
return prefs.getBoolean(KEY_PREFIX_NO_ACTION + tag, true)
|
||||
return prefs!!.getBoolean(KEY_PREFIX_NO_ACTION + tag, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package ac.mdiq.podcini.ui.activity
|
|||
import ac.mdiq.podcini.BuildConfig
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.databinding.MainActivityBinding
|
||||
import ac.mdiq.podcini.net.discovery.ItunesTopListLoader
|
||||
import ac.mdiq.podcini.net.download.FeedUpdateManager
|
||||
import ac.mdiq.podcini.net.download.FeedUpdateManager.restartUpdateAlarm
|
||||
import ac.mdiq.podcini.net.download.FeedUpdateManager.runOnceOrAsk
|
||||
|
@ -16,14 +17,19 @@ import ac.mdiq.podcini.preferences.UserPreferences.backButtonOpensDrawer
|
|||
import ac.mdiq.podcini.preferences.UserPreferences.defaultPage
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.hiddenDrawerItems
|
||||
import ac.mdiq.podcini.receiver.MediaButtonReceiver.Companion.createIntent
|
||||
import ac.mdiq.podcini.receiver.PlayerWidget
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
import ac.mdiq.podcini.storage.DBWriter.ioScope
|
||||
import ac.mdiq.podcini.storage.model.download.DownloadStatus
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions
|
||||
import ac.mdiq.podcini.ui.activity.appstartintent.MainActivityStarter
|
||||
import ac.mdiq.podcini.ui.dialog.RatingDialog
|
||||
import ac.mdiq.podcini.ui.fragment.*
|
||||
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
|
||||
import ac.mdiq.podcini.ui.utils.ThemeUtils.getDrawableFromAttr
|
||||
import ac.mdiq.podcini.ui.view.LockableBottomSheetBehavior
|
||||
import ac.mdiq.podcini.ui.utils.TransitionEffect
|
||||
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
|
||||
import ac.mdiq.podcini.ui.utils.LockableBottomSheetBehavior
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
|
@ -110,7 +116,18 @@ class MainActivity : CastEnabledActivity() {
|
|||
StrictMode.setThreadPolicy(builder.build())
|
||||
}
|
||||
|
||||
DBReader.updateFeedList()
|
||||
ioScope.launch {
|
||||
NavDrawerFragment.getSharedPrefs(this@MainActivity)
|
||||
SwipeActions.getSharedPrefs(this@MainActivity)
|
||||
QueueFragment.getSharedPrefs(this@MainActivity)
|
||||
DBReader.updateFeedList()
|
||||
EpisodeItemListRecyclerView.getSharedPrefs(this@MainActivity)
|
||||
PlayerDetailsFragment.getSharedPrefs(this@MainActivity)
|
||||
PlayerWidget.getSharedPrefs(this@MainActivity)
|
||||
StatisticsFragment.getSharedPrefs(this@MainActivity)
|
||||
OnlineFeedViewFragment.getSharedPrefs(this@MainActivity)
|
||||
ItunesTopListLoader.getSharedPrefs(this@MainActivity)
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) ensureGeneratedViewIdGreaterThan(savedInstanceState.getInt(KEY_GENERATED_VIEW_ID, 0))
|
||||
|
||||
|
@ -145,9 +162,8 @@ class MainActivity : CastEnabledActivity() {
|
|||
|
||||
val fm = supportFragmentManager
|
||||
if (fm.findFragmentByTag(MAIN_FRAGMENT_TAG) == null) {
|
||||
if (UserPreferences.DEFAULT_PAGE_REMEMBER != defaultPage) {
|
||||
loadFragment(defaultPage, null)
|
||||
} else {
|
||||
if (UserPreferences.DEFAULT_PAGE_REMEMBER != defaultPage) loadFragment(defaultPage, null)
|
||||
else {
|
||||
val lastFragment = NavDrawerFragment.getLastNavFragment(this)
|
||||
if (ArrayUtils.contains(NavDrawerFragment.NAV_DRAWER_TAGS, lastFragment)) {
|
||||
loadFragment(lastFragment, null)
|
||||
|
@ -173,14 +189,15 @@ class MainActivity : CastEnabledActivity() {
|
|||
navDrawer = findViewById(R.id.navDrawerFragment)
|
||||
audioPlayerFragmentView = findViewById(R.id.audioplayerFragment)
|
||||
|
||||
checkFirstLaunch()
|
||||
ioScope.launch { checkFirstLaunch() }
|
||||
|
||||
this.bottomSheet = BottomSheetBehavior.from(audioPlayerFragmentView) as LockableBottomSheetBehavior<*>
|
||||
this.bottomSheet.isHideable = false
|
||||
this.bottomSheet.isDraggable = false
|
||||
this.bottomSheet.setBottomSheetCallback(bottomSheetCallback)
|
||||
|
||||
restartUpdateAlarm(this, false)
|
||||
SynchronizationQueueSink.syncNowIfNotSyncedRecently()
|
||||
ioScope.launch { SynchronizationQueueSink.syncNowIfNotSyncedRecently() }
|
||||
|
||||
WorkManager.getInstance(this)
|
||||
.getWorkInfosByTagLiveData(FeedUpdateManager.WORK_TAG_FEED_UPDATE)
|
||||
|
@ -376,7 +393,7 @@ class MainActivity : CastEnabledActivity() {
|
|||
QueueFragment.TAG -> fragment = QueueFragment()
|
||||
AllEpisodesFragment.TAG -> fragment = AllEpisodesFragment()
|
||||
DownloadsFragment.TAG -> fragment = DownloadsFragment()
|
||||
PlaybackHistoryFragment.TAG -> fragment = PlaybackHistoryFragment()
|
||||
HistoryFragment.TAG -> fragment = HistoryFragment()
|
||||
AddFeedFragment.TAG -> fragment = AddFeedFragment()
|
||||
SubscriptionFragment.TAG -> fragment = SubscriptionFragment()
|
||||
StatisticsFragment.TAG -> fragment = StatisticsFragment()
|
||||
|
@ -389,7 +406,7 @@ class MainActivity : CastEnabledActivity() {
|
|||
}
|
||||
if (args != null) fragment.arguments = args
|
||||
|
||||
NavDrawerFragment.saveLastNavFragment(this, tag)
|
||||
ioScope.launch { NavDrawerFragment.saveLastNavFragment(this@MainActivity, tag) }
|
||||
loadFragment(fragment)
|
||||
}
|
||||
|
||||
|
@ -560,6 +577,7 @@ class MainActivity : CastEnabledActivity() {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.MessageEvent -> onEventMainThread(event)
|
||||
else -> {}
|
||||
|
@ -660,7 +678,7 @@ class MainActivity : CastEnabledActivity() {
|
|||
val feature = uri.getQueryParameter("page") ?: return
|
||||
when (feature) {
|
||||
"DOWNLOADS" -> loadFragment(DownloadsFragment.TAG, null)
|
||||
"HISTORY" -> loadFragment(PlaybackHistoryFragment.TAG, null)
|
||||
"HISTORY" -> loadFragment(HistoryFragment.TAG, null)
|
||||
"EPISODES" -> loadFragment(AllEpisodesFragment.TAG, null)
|
||||
"QUEUE" -> loadFragment(QueueFragment.TAG, null)
|
||||
"SUBSCRIPTIONS" -> loadFragment(SubscriptionFragment.TAG, null)
|
||||
|
|
|
@ -161,6 +161,7 @@ class PreferenceActivity : AppCompatActivity(), SearchPreferenceResultListener {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd("PreferenceActivity", "Received event: ${event}")
|
||||
when (event) {
|
||||
is FlowEvent.MessageEvent -> onEventMainThread(event)
|
||||
else -> {}
|
||||
|
|
|
@ -13,6 +13,8 @@ import ac.mdiq.podcini.storage.model.feed.FeedItem
|
|||
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
||||
import ac.mdiq.podcini.storage.model.playback.Playable
|
||||
import ac.mdiq.podcini.ui.dialog.*
|
||||
import ac.mdiq.podcini.ui.fragment.AudioPlayerFragment.InternalPlayerFragment
|
||||
import ac.mdiq.podcini.ui.fragment.AudioPlayerFragment.InternalPlayerFragment.Companion
|
||||
import ac.mdiq.podcini.ui.fragment.ChaptersFragment
|
||||
import ac.mdiq.podcini.ui.fragment.VideoEpisodeFragment
|
||||
import ac.mdiq.podcini.ui.utils.PictureInPictureUtil
|
||||
|
@ -169,6 +171,7 @@ class VideoplayerActivity : CastEnabledActivity() {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.SleepTimerUpdatedEvent -> if (event.isCancelled || event.wasJustEnabled()) supportInvalidateOptionsMenu()
|
||||
is FlowEvent.PlaybackServiceEvent -> if (event.action == FlowEvent.PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN) finish()
|
||||
|
|
|
@ -16,6 +16,7 @@ import ac.mdiq.podcini.databinding.ActivityWidgetConfigBinding
|
|||
import ac.mdiq.podcini.databinding.PlayerWidgetBinding
|
||||
import ac.mdiq.podcini.preferences.ThemeSwitcher.getTheme
|
||||
import ac.mdiq.podcini.receiver.PlayerWidget
|
||||
import ac.mdiq.podcini.receiver.PlayerWidget.Companion.prefs
|
||||
import ac.mdiq.podcini.ui.widget.WidgetUpdaterWorker
|
||||
|
||||
class WidgetConfigActivity : AppCompatActivity() {
|
||||
|
@ -95,13 +96,13 @@ class WidgetConfigActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun setInitialState() {
|
||||
val prefs = getSharedPreferences(PlayerWidget.PREFS_NAME, MODE_PRIVATE)
|
||||
ckPlaybackSpeed.isChecked = prefs.getBoolean(PlayerWidget.KEY_WIDGET_PLAYBACK_SPEED + appWidgetId, true)
|
||||
ckRewind.isChecked = prefs.getBoolean(PlayerWidget.KEY_WIDGET_REWIND + appWidgetId, true)
|
||||
ckFastForward.isChecked = prefs.getBoolean(PlayerWidget.KEY_WIDGET_FAST_FORWARD + appWidgetId, true)
|
||||
ckSkip.isChecked = prefs.getBoolean(PlayerWidget.KEY_WIDGET_SKIP + appWidgetId, true)
|
||||
// val prefs = getSharedPreferences(PlayerWidget.PREFS_NAME, MODE_PRIVATE)
|
||||
ckPlaybackSpeed.isChecked = prefs!!.getBoolean(PlayerWidget.KEY_WIDGET_PLAYBACK_SPEED + appWidgetId, true)
|
||||
ckRewind.isChecked = prefs!!.getBoolean(PlayerWidget.KEY_WIDGET_REWIND + appWidgetId, true)
|
||||
ckFastForward.isChecked = prefs!!.getBoolean(PlayerWidget.KEY_WIDGET_FAST_FORWARD + appWidgetId, true)
|
||||
ckSkip.isChecked = prefs!!.getBoolean(PlayerWidget.KEY_WIDGET_SKIP + appWidgetId, true)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val color = prefs.getInt(PlayerWidget.KEY_WIDGET_COLOR + appWidgetId, PlayerWidget.DEFAULT_COLOR)
|
||||
val color = prefs!!.getInt(PlayerWidget.KEY_WIDGET_COLOR + appWidgetId, PlayerWidget.DEFAULT_COLOR)
|
||||
val opacity = Color.alpha(color) * 100 / 0xFF
|
||||
|
||||
opacitySeekBar.setProgress(opacity, false)
|
||||
|
@ -122,8 +123,8 @@ class WidgetConfigActivity : AppCompatActivity() {
|
|||
private fun confirmCreateWidget() {
|
||||
val backgroundColor = getColorWithAlpha(PlayerWidget.DEFAULT_COLOR, opacitySeekBar.progress)
|
||||
|
||||
val prefs = getSharedPreferences(PlayerWidget.PREFS_NAME, MODE_PRIVATE)
|
||||
val editor = prefs.edit()
|
||||
// val prefs = getSharedPreferences(PlayerWidget.PREFS_NAME, MODE_PRIVATE)
|
||||
val editor = prefs!!.edit()
|
||||
editor.putInt(PlayerWidget.KEY_WIDGET_COLOR + appWidgetId, backgroundColor)
|
||||
editor.putBoolean(PlayerWidget.KEY_WIDGET_PLAYBACK_SPEED + appWidgetId, ckPlaybackSpeed.isChecked)
|
||||
editor.putBoolean(PlayerWidget.KEY_WIDGET_SKIP + appWidgetId, ckSkip.isChecked)
|
||||
|
|
|
@ -7,6 +7,7 @@ import ac.mdiq.podcini.ui.activity.MainActivity
|
|||
import ac.mdiq.podcini.ui.fragment.EpisodeInfoFragment
|
||||
import ac.mdiq.podcini.ui.utils.ThemeUtils
|
||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.R.color
|
||||
import android.app.Activity
|
||||
import android.util.Log
|
||||
|
@ -18,9 +19,10 @@ import java.lang.ref.WeakReference
|
|||
/**
|
||||
* List adapter for the list of new episodes.
|
||||
*/
|
||||
open class EpisodeItemListAdapter(mainActivity: MainActivity) :
|
||||
SelectableAdapter<EpisodeItemViewHolder?>(mainActivity), View.OnCreateContextMenuListener {
|
||||
open class EpisodeItemListAdapter(mainActivity: MainActivity)
|
||||
: SelectableAdapter<EpisodeItemViewHolder?>(mainActivity), View.OnCreateContextMenuListener {
|
||||
|
||||
val TAG = "EpisodeItemListAdapter"
|
||||
val mainActivityRef: WeakReference<MainActivity> = WeakReference<MainActivity>(mainActivity)
|
||||
|
||||
private var episodes: List<FeedItem> = ArrayList()
|
||||
|
@ -49,6 +51,8 @@ open class EpisodeItemListAdapter(mainActivity: MainActivity) :
|
|||
}
|
||||
|
||||
@UnstableApi override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EpisodeItemViewHolder {
|
||||
// TODO: the Invalid resource ID 0x00000000 on Android 14 occurs after this and before onBindViewHolder,
|
||||
// somehow, only on the first time EpisodeItemListAdapter is called
|
||||
return EpisodeItemViewHolder(mainActivityRef.get()!!, parent)
|
||||
}
|
||||
|
||||
|
@ -79,24 +83,13 @@ open class EpisodeItemListAdapter(mainActivity: MainActivity) :
|
|||
}
|
||||
holder.infoCard.setOnClickListener {
|
||||
val activity: MainActivity? = mainActivityRef.get()
|
||||
if (!inActionMode()) {
|
||||
// val ids: LongArray = FeedItemUtil.getIds(episodes)
|
||||
// val position = ArrayUtils.indexOf(ids, item.id)
|
||||
activity?.loadChildFragment(EpisodeInfoFragment.newInstance(episodes[pos]))
|
||||
} else {
|
||||
toggleSelection(holder.bindingAdapterPosition)
|
||||
}
|
||||
if (!inActionMode()) activity?.loadChildFragment(EpisodeInfoFragment.newInstance(episodes[pos]))
|
||||
else toggleSelection(holder.bindingAdapterPosition)
|
||||
}
|
||||
|
||||
holder.coverHolder.setOnClickListener {
|
||||
val activity: MainActivity? = mainActivityRef.get()
|
||||
if (!inActionMode()) {
|
||||
// val ids: LongArray = FeedItemUtil.getIds(episodes)
|
||||
// val position = ArrayUtils.indexOf(ids, item.id)
|
||||
activity?.loadChildFragment(EpisodeInfoFragment.newInstance(episodes[pos]))
|
||||
} else {
|
||||
toggleSelection(holder.bindingAdapterPosition)
|
||||
}
|
||||
if (!inActionMode()) activity?.loadChildFragment(EpisodeInfoFragment.newInstance(episodes[pos]))
|
||||
else toggleSelection(holder.bindingAdapterPosition)
|
||||
}
|
||||
holder.itemView.setOnTouchListener(View.OnTouchListener { _: View?, e: MotionEvent ->
|
||||
if (e.isFromSource(InputDevice.SOURCE_MOUSE) && e.buttonState == MotionEvent.BUTTON_SECONDARY) {
|
||||
|
@ -106,12 +99,11 @@ open class EpisodeItemListAdapter(mainActivity: MainActivity) :
|
|||
}
|
||||
false
|
||||
})
|
||||
|
||||
if (inActionMode()) {
|
||||
holder.secondaryActionButton.setOnClickListener(null)
|
||||
if (isSelected(pos)) {
|
||||
if (isSelected(pos))
|
||||
holder.itemView.setBackgroundColor(-0x78000000 + (0xffffff and ThemeUtils.getColorFromAttr(mainActivityRef.get()!!, R.attr.colorAccent)))
|
||||
} else holder.itemView.setBackgroundResource(color.transparent)
|
||||
else holder.itemView.setBackgroundResource(color.transparent)
|
||||
}
|
||||
|
||||
afterBindViewHolder(holder, pos)
|
||||
|
|
|
@ -4,13 +4,14 @@ import ac.mdiq.podcini.R
|
|||
import ac.mdiq.podcini.databinding.NavListitemBinding
|
||||
import ac.mdiq.podcini.databinding.NavSectionItemBinding
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.episodeCacheSize
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.hiddenDrawerItems
|
||||
import ac.mdiq.podcini.storage.DBWriter.ioScope
|
||||
import ac.mdiq.podcini.storage.NavDrawerData.FeedDrawerItem
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity
|
||||
import ac.mdiq.podcini.ui.fragment.*
|
||||
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
|
@ -28,6 +29,9 @@ import androidx.media3.common.util.UnstableApi
|
|||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.apache.commons.lang3.ArrayUtils
|
||||
import java.lang.ref.WeakReference
|
||||
import java.text.NumberFormat
|
||||
|
@ -49,9 +53,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
|
|||
|
||||
init {
|
||||
loadItems()
|
||||
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
prefs.registerOnSharedPreferenceChangeListener(this)
|
||||
appPrefs.registerOnSharedPreferenceChangeListener(this@NavListAdapter)
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
|
||||
|
@ -78,7 +80,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
|
|||
QueueFragment.TAG -> R.drawable.ic_playlist_play
|
||||
AllEpisodesFragment.TAG -> R.drawable.ic_feed
|
||||
DownloadsFragment.TAG -> R.drawable.ic_download
|
||||
PlaybackHistoryFragment.TAG -> R.drawable.ic_history
|
||||
HistoryFragment.TAG -> R.drawable.ic_history
|
||||
SubscriptionFragment.TAG -> R.drawable.ic_subscriptions
|
||||
StatisticsFragment.TAG -> R.drawable.ic_chart_box
|
||||
AddFeedFragment.TAG -> R.drawable.ic_add
|
||||
|
@ -200,7 +202,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) :
|
|||
}
|
||||
}
|
||||
|
||||
Logd("NavListAdapter", "bindNavView getting drawable for: ${fragmentTags[position]}")
|
||||
// Logd("NavListAdapter", "bindNavView getting drawable for: ${fragmentTags[position]}")
|
||||
holder.image.setImageResource(getDrawable(fragmentTags[position]))
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,7 @@ import android.util.Log
|
|||
/**
|
||||
* Used by Recyclerviews that need to provide ability to select items.
|
||||
*/
|
||||
abstract class SelectableAdapter<T : RecyclerView.ViewHolder?>(private val activity: Activity) :
|
||||
RecyclerView.Adapter<T>() {
|
||||
abstract class SelectableAdapter<T : RecyclerView.ViewHolder?>(private val activity: Activity) : RecyclerView.Adapter<T>() {
|
||||
|
||||
private var actionMode: ActionMode? = null
|
||||
private val selectedIds = HashSet<Long>()
|
||||
|
|
|
@ -6,10 +6,10 @@ import ac.mdiq.podcini.storage.NavDrawerData
|
|||
import ac.mdiq.podcini.storage.model.feed.Feed
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.fragment.FeedItemlistFragment
|
||||
import ac.mdiq.podcini.ui.utils.CoverLoader
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.view.*
|
||||
import android.widget.*
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
|
@ -153,6 +153,7 @@ open class SubscriptionsAdapter(mainActivity: MainActivity)
|
|||
}
|
||||
|
||||
inner class SubscriptionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
val binding = SubscriptionItemBinding.bind(itemView)
|
||||
private val title = binding.titleLabel
|
||||
private val producer = binding.producerLabel
|
||||
|
|
|
@ -12,6 +12,7 @@ import ac.mdiq.podcini.net.download.FeedUpdateManager.runOnce
|
|||
import ac.mdiq.podcini.databinding.EditTextDialogBinding
|
||||
import ac.mdiq.podcini.storage.model.feed.Feed
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
@ -37,7 +38,7 @@ import java.util.concurrent.ExecutionException
|
|||
|
||||
@UnstableApi private fun onConfirmed(original: String, updated: String) {
|
||||
try {
|
||||
DBWriter.updateFeedDownloadURL(original, updated).get()
|
||||
runBlocking { DBWriter.updateFeedDownloadURL(original, updated).join() }
|
||||
feed.download_url = updated
|
||||
runOnce(activityRef.get()!!, feed)
|
||||
} catch (e: ExecutionException) {
|
||||
|
|
|
@ -4,7 +4,7 @@ import ac.mdiq.podcini.R
|
|||
import ac.mdiq.podcini.databinding.EpisodeFilterDialogBinding
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedFilter
|
||||
import ac.mdiq.podcini.ui.adapter.SimpleChipAdapter
|
||||
import ac.mdiq.podcini.ui.view.ItemOffsetDecoration
|
||||
import ac.mdiq.podcini.ui.utils.ItemOffsetDecoration
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.view.LayoutInflater
|
||||
|
|
|
@ -10,10 +10,8 @@ import android.content.DialogInterface
|
|||
import android.util.Log
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
import java.lang.Runnable
|
||||
|
||||
object RemoveFeedDialog {
|
||||
private const val TAG = "RemoveFeedDialog"
|
||||
|
@ -63,7 +61,7 @@ object RemoveFeedDialog {
|
|||
try {
|
||||
withContext(Dispatchers.IO) {
|
||||
for (feed in feeds) {
|
||||
DBWriter.deleteFeed(context, feed.id).get()
|
||||
runBlocking { DBWriter.deleteFeed(context, feed.id).join() }
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
|
|
|
@ -17,10 +17,13 @@ import ac.mdiq.podcini.ui.fragment.*
|
|||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeAction
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions.Companion.getPrefsWithDefaults
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions.Companion.getSharedPrefs
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions.Companion.isSwipeActionEnabled
|
||||
import ac.mdiq.podcini.ui.utils.ThemeUtils.getColorFromAttr
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
|
||||
class SwipeActionsDialog(private val context: Context, private val tag: String) {
|
||||
@OptIn(UnstableApi::class) class SwipeActionsDialog(private val context: Context, private val tag: String) {
|
||||
private lateinit var keys: List<SwipeAction>
|
||||
|
||||
private var rightAction: SwipeAction? = null
|
||||
|
@ -55,15 +58,13 @@ class SwipeActionsDialog(private val context: Context, private val tag: String)
|
|||
keys = Stream.of(keys).filter { a: SwipeAction ->
|
||||
(!a.getId().equals(SwipeAction.ADD_TO_QUEUE) && !a.getId().equals(SwipeAction.REMOVE_FROM_HISTORY)) }.toList()
|
||||
}
|
||||
PlaybackHistoryFragment.TAG -> {
|
||||
HistoryFragment.TAG -> {
|
||||
forFragment = context.getString(R.string.playback_history_label)
|
||||
keys = Stream.of(keys).toList()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
if (tag != QueueFragment.TAG) {
|
||||
keys = Stream.of(keys).filter { a: SwipeAction -> !a.getId().equals(SwipeAction.REMOVE_FROM_QUEUE) }.toList()
|
||||
}
|
||||
if (tag != QueueFragment.TAG) keys = Stream.of(keys).filter { a: SwipeAction -> !a.getId().equals(SwipeAction.REMOVE_FROM_QUEUE) }.toList()
|
||||
|
||||
builder.setTitle(context.getString(R.string.swipeactions_label) + " - " + forFragment)
|
||||
val binding = SwipeactionsDialogBinding.inflate(LayoutInflater.from(context))
|
||||
|
@ -127,11 +128,9 @@ class SwipeActionsDialog(private val context: Context, private val tag: String)
|
|||
if ((direction == LEFT && leftAction === action) || (direction == RIGHT && rightAction === action)) {
|
||||
icon.setTint(getColorFromAttr(context, action.getActionColor()))
|
||||
item.swipeActionLabel.setTextColor(getColorFromAttr(context, action.getActionColor()))
|
||||
} else {
|
||||
icon.setTint(getColorFromAttr(context, R.attr.action_icon_color))
|
||||
}
|
||||
item.swipeIcon.setImageDrawable(icon)
|
||||
} else icon.setTint(getColorFromAttr(context, R.attr.action_icon_color))
|
||||
|
||||
item.swipeIcon.setImageDrawable(icon)
|
||||
item.root.setOnClickListener {
|
||||
if (direction == LEFT) leftAction = keys[i]
|
||||
else rightAction = keys[i]
|
||||
|
@ -158,13 +157,13 @@ class SwipeActionsDialog(private val context: Context, private val tag: String)
|
|||
}
|
||||
|
||||
private fun savePrefs(tag: String, right: String?, left: String?) {
|
||||
val prefs = context.getSharedPreferences(SwipeActions.PREF_NAME, Context.MODE_PRIVATE)
|
||||
prefs.edit().putString(SwipeActions.KEY_PREFIX_SWIPEACTIONS + tag, "$right,$left").apply()
|
||||
getSharedPrefs(context)
|
||||
SwipeActions.prefs!!.edit().putString(SwipeActions.KEY_PREFIX_SWIPEACTIONS + tag, "$right,$left").apply()
|
||||
}
|
||||
|
||||
private fun saveActionsEnabledPrefs(enabled: Boolean) {
|
||||
val prefs = context.getSharedPreferences(SwipeActions.PREF_NAME, Context.MODE_PRIVATE)
|
||||
prefs.edit().putBoolean(SwipeActions.KEY_PREFIX_NO_ACTION + tag, enabled).apply()
|
||||
getSharedPrefs(context)
|
||||
SwipeActions.prefs!!.edit().putBoolean(SwipeActions.KEY_PREFIX_NO_ACTION + tag, enabled).apply()
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
|
|
|
@ -6,7 +6,7 @@ import ac.mdiq.podcini.storage.DBReader
|
|||
import ac.mdiq.podcini.storage.DBWriter
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedPreferences
|
||||
import ac.mdiq.podcini.ui.adapter.SimpleChipAdapter
|
||||
import ac.mdiq.podcini.ui.view.ItemOffsetDecoration
|
||||
import ac.mdiq.podcini.ui.utils.ItemOffsetDecoration
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import android.app.Dialog
|
||||
|
|
|
@ -8,7 +8,7 @@ import ac.mdiq.podcini.playback.PlaybackController.Companion.setPlaybackSpeed
|
|||
import ac.mdiq.podcini.playback.PlaybackController.Companion.setSkipSilence
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.isSkipSilence
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.playbackSpeedArray
|
||||
import ac.mdiq.podcini.ui.view.ItemOffsetDecoration
|
||||
import ac.mdiq.podcini.ui.utils.ItemOffsetDecoration
|
||||
import ac.mdiq.podcini.ui.view.PlaybackSpeedSeekBar
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package ac.mdiq.podcini.ui.fragment
|
||||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.allEpisodesSortOrder
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.prefFilterAllEpisodes
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
|
@ -99,6 +101,7 @@ import org.apache.commons.lang3.StringUtils
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.AllEpisodesFilterChangedEvent -> onFilterChanged(event)
|
||||
else -> {}
|
||||
|
|
|
@ -14,6 +14,7 @@ import ac.mdiq.podcini.playback.base.MediaPlayerBase
|
|||
import ac.mdiq.podcini.playback.base.PlayerStatus
|
||||
import ac.mdiq.podcini.playback.cast.CastEnabledActivity
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.videoPlayMode
|
||||
import ac.mdiq.podcini.receiver.MediaButtonReceiver
|
||||
|
@ -309,9 +310,8 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
|
|||
|
||||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
Logd(TAG, "subscribing PositionFlowEvent")
|
||||
EventFlow.events.collectLatest { event ->
|
||||
// Logd(TAG, "PositionFlowEvent: ${event}")
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.PlaybackServiceEvent ->
|
||||
if (event.action == FlowEvent.PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN)
|
||||
|
@ -546,7 +546,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
// Logd(TAG, "PositionFlowEvent: ${event}")
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.PlaybackPositionEvent -> onPositionObserverUpdate(event)
|
||||
is FlowEvent.SpeedChangedEvent -> updatePlaybackSpeedButton(event)
|
||||
|
|
|
@ -14,9 +14,9 @@ import ac.mdiq.podcini.ui.activity.MainActivity
|
|||
import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter
|
||||
import ac.mdiq.podcini.ui.adapter.SelectableAdapter
|
||||
import ac.mdiq.podcini.ui.dialog.ConfirmationDialog
|
||||
import ac.mdiq.podcini.ui.view.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.utils.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
|
||||
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.ui.utils.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||
import ac.mdiq.podcini.util.FeedItemUtil
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
|
@ -104,6 +104,7 @@ import kotlinx.coroutines.withContext
|
|||
recyclerView.addOnScrollListener(LiftOnScrollListener(binding.appbar))
|
||||
|
||||
swipeActions = SwipeActions(this, getFragmentTag()).attachTo(recyclerView)
|
||||
lifecycle.addObserver(swipeActions)
|
||||
swipeActions.setFilter(getFilter())
|
||||
refreshSwipeTelltale()
|
||||
binding.leftActionIcon.setOnClickListener {
|
||||
|
@ -423,6 +424,7 @@ import kotlinx.coroutines.withContext
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.SwipeActionsChangedEvent -> refreshSwipeTelltale()
|
||||
is FlowEvent.FeedListUpdateEvent, is FlowEvent.UnreadItemsUpdateEvent, is FlowEvent.PlayerStatusEvent -> loadItems()
|
||||
|
|
|
@ -5,6 +5,8 @@ import ac.mdiq.podcini.databinding.SimpleListFragmentBinding
|
|||
import ac.mdiq.podcini.playback.PlaybackController
|
||||
import ac.mdiq.podcini.playback.base.MediaPlayerBase
|
||||
import ac.mdiq.podcini.playback.base.PlayerStatus
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
||||
import ac.mdiq.podcini.storage.model.playback.Playable
|
||||
import ac.mdiq.podcini.ui.adapter.ChaptersListAdapter
|
||||
|
@ -124,6 +126,7 @@ class ChaptersFragment : AppCompatDialogFragment() {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.PlaybackPositionEvent -> onEventMainThread(event)
|
||||
else -> {}
|
||||
|
|
|
@ -5,6 +5,7 @@ import ac.mdiq.podcini.R
|
|||
import ac.mdiq.podcini.databinding.FragmentItunesSearchBinding
|
||||
import ac.mdiq.podcini.databinding.SelectCountryDialogBinding
|
||||
import ac.mdiq.podcini.net.discovery.ItunesTopListLoader
|
||||
import ac.mdiq.podcini.net.discovery.ItunesTopListLoader.Companion.prefs
|
||||
import ac.mdiq.podcini.net.discovery.PodcastSearchResult
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
|
@ -42,7 +43,7 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
private var _binding: FragmentItunesSearchBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private lateinit var prefs: SharedPreferences
|
||||
// private lateinit var prefs: SharedPreferences
|
||||
private lateinit var gridView: GridView
|
||||
private lateinit var progressBar: ProgressBar
|
||||
private lateinit var txtvError: TextView
|
||||
|
@ -91,10 +92,10 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
prefs = requireActivity().getSharedPreferences(ItunesTopListLoader.PREFS, Context.MODE_PRIVATE)
|
||||
countryCode = prefs.getString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, Locale.getDefault().country)
|
||||
hidden = prefs.getBoolean(ItunesTopListLoader.PREF_KEY_HIDDEN_DISCOVERY_COUNTRY, false)
|
||||
needsConfirm = prefs.getBoolean(ItunesTopListLoader.PREF_KEY_NEEDS_CONFIRM, true)
|
||||
// prefs = requireActivity().getSharedPreferences(ItunesTopListLoader.PREFS, Context.MODE_PRIVATE)
|
||||
countryCode = prefs!!.getString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, Locale.getDefault().country)
|
||||
hidden = prefs!!.getBoolean(ItunesTopListLoader.PREF_KEY_HIDDEN_DISCOVERY_COUNTRY, false)
|
||||
needsConfirm = prefs!!.getBoolean(ItunesTopListLoader.PREF_KEY_NEEDS_CONFIRM, true)
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
|
@ -167,7 +168,7 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
butRetry.visibility = View.VISIBLE
|
||||
butRetry.setText(R.string.discover_confirm)
|
||||
butRetry.setOnClickListener {
|
||||
prefs.edit().putBoolean(ItunesTopListLoader.PREF_KEY_NEEDS_CONFIRM, false).apply()
|
||||
prefs!!.edit().putBoolean(ItunesTopListLoader.PREF_KEY_NEEDS_CONFIRM, false).apply()
|
||||
needsConfirm = false
|
||||
loadToplist(country)
|
||||
}
|
||||
|
@ -225,7 +226,7 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
R.id.discover_hide_item -> {
|
||||
item.setChecked(!item.isChecked)
|
||||
hidden = item.isChecked
|
||||
prefs.edit().putBoolean(ItunesTopListLoader.PREF_KEY_HIDDEN_DISCOVERY_COUNTRY, hidden).apply()
|
||||
prefs!!.edit().putBoolean(ItunesTopListLoader.PREF_KEY_HIDDEN_DISCOVERY_COUNTRY, hidden).apply()
|
||||
|
||||
EventFlow.postEvent(FlowEvent.DiscoveryDefaultUpdateEvent())
|
||||
loadToplist(countryCode)
|
||||
|
@ -278,8 +279,8 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
hidden = false
|
||||
}
|
||||
|
||||
prefs.edit().putBoolean(ItunesTopListLoader.PREF_KEY_HIDDEN_DISCOVERY_COUNTRY, hidden).apply()
|
||||
prefs.edit().putString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, countryCode).apply()
|
||||
prefs!!.edit().putBoolean(ItunesTopListLoader.PREF_KEY_HIDDEN_DISCOVERY_COUNTRY, hidden).apply()
|
||||
prefs!!.edit().putString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, countryCode).apply()
|
||||
|
||||
EventFlow.postEvent(FlowEvent.DiscoveryDefaultUpdateEvent())
|
||||
loadToplist(countryCode)
|
||||
|
|
|
@ -7,7 +7,7 @@ import ac.mdiq.podcini.storage.DBWriter
|
|||
import ac.mdiq.podcini.storage.model.download.DownloadResult
|
||||
import ac.mdiq.podcini.ui.adapter.DownloadLogAdapter
|
||||
import ac.mdiq.podcini.ui.dialog.DownloadLogDetailsDialog
|
||||
import ac.mdiq.podcini.ui.view.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.utils.EmptyViewHandler
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
|
@ -83,6 +83,7 @@ class DownloadLogFragment : BottomSheetDialogFragment(), OnItemClickListener, To
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.DownloadLogEvent -> loadDownloadLog()
|
||||
else -> {}
|
||||
|
|
|
@ -19,9 +19,9 @@ import ac.mdiq.podcini.ui.activity.MainActivity
|
|||
import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter
|
||||
import ac.mdiq.podcini.ui.adapter.SelectableAdapter
|
||||
import ac.mdiq.podcini.ui.dialog.ItemSortDialog
|
||||
import ac.mdiq.podcini.ui.view.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.utils.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
|
||||
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.ui.utils.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||
import ac.mdiq.podcini.util.FeedItemUtil
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
|
@ -97,6 +97,7 @@ import java.util.*
|
|||
recyclerView.addOnScrollListener(LiftOnScrollListener(binding.appbar))
|
||||
|
||||
swipeActions = SwipeActions(this, TAG).attachTo(recyclerView)
|
||||
lifecycle.addObserver(swipeActions)
|
||||
swipeActions.setFilter(FeedItemFilter(FeedItemFilter.DOWNLOADED))
|
||||
refreshSwipeTelltale()
|
||||
binding.leftActionIcon.setOnClickListener {
|
||||
|
@ -213,6 +214,7 @@ import java.util.*
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.FeedItemEvent -> onEventMainThread(event)
|
||||
is FlowEvent.PlaybackPositionEvent -> onEventMainThread(event)
|
||||
|
|
|
@ -66,7 +66,7 @@ import kotlin.math.max
|
|||
|
||||
private var homeFragment: EpisodeHomeFragment? = null
|
||||
|
||||
private var itemsLoaded = false
|
||||
private var itemLoaded = false
|
||||
private var item: FeedItem? = null
|
||||
private var webviewData: String? = null
|
||||
|
||||
|
@ -89,16 +89,8 @@ import kotlin.math.max
|
|||
private var actionButton1: ItemActionButton? = null
|
||||
private var actionButton2: ItemActionButton? = null
|
||||
|
||||
// private var disposable: Disposable? = null
|
||||
private var controller: PlaybackController? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// item = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) requireArguments().getSerializable(ARG_FEEDITEM, FeedItem::class.java)
|
||||
// else requireArguments().getSerializable(ARG_FEEDITEM) as? FeedItem
|
||||
}
|
||||
|
||||
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
|
@ -140,9 +132,7 @@ import kotlin.math.max
|
|||
if (!item?.link.isNullOrEmpty()) {
|
||||
homeFragment = EpisodeHomeFragment.newInstance(item!!)
|
||||
(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 ${item?.link}", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
butAction1.setOnClickListener(View.OnClickListener {
|
||||
|
@ -169,9 +159,7 @@ import kotlin.math.max
|
|||
})
|
||||
|
||||
controller = object : PlaybackController(requireActivity()) {
|
||||
override fun loadMediaInfo() {
|
||||
// Do nothing
|
||||
}
|
||||
override fun loadMediaInfo() {}
|
||||
}
|
||||
controller?.init()
|
||||
load()
|
||||
|
@ -246,7 +234,7 @@ import kotlin.math.max
|
|||
|
||||
@UnstableApi override fun onResume() {
|
||||
super.onResume()
|
||||
if (itemsLoaded) {
|
||||
if (itemLoaded) {
|
||||
progbarLoading.visibility = View.GONE
|
||||
updateAppearance()
|
||||
}
|
||||
|
@ -258,7 +246,6 @@ import kotlin.math.max
|
|||
_binding = null
|
||||
|
||||
controller?.release()
|
||||
// disposable?.dispose()
|
||||
root.removeView(webvDescription)
|
||||
webvDescription.clearHistory()
|
||||
webvDescription.clearCache(true)
|
||||
|
@ -267,9 +254,9 @@ import kotlin.math.max
|
|||
}
|
||||
|
||||
@UnstableApi private fun onFragmentLoaded() {
|
||||
if (webviewData != null && !itemsLoaded) {
|
||||
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()
|
||||
}
|
||||
|
@ -279,14 +266,13 @@ import kotlin.math.max
|
|||
Logd(TAG, "updateAppearance item is null")
|
||||
return
|
||||
}
|
||||
if (item!!.hasMedia()) {
|
||||
FeedItemMenuHandler.onPrepareMenu(toolbar.menu, item, R.id.open_podcast)
|
||||
} else {
|
||||
// these are already available via button1 and button2
|
||||
FeedItemMenuHandler.onPrepareMenu(toolbar.menu, item, R.id.open_podcast, R.id.mark_read_item, R.id.visit_website_item)
|
||||
}
|
||||
if (item!!.hasMedia()) FeedItemMenuHandler.onPrepareMenu(toolbar.menu, item, R.id.open_podcast)
|
||||
// these are already available via button1 and button2
|
||||
else FeedItemMenuHandler.onPrepareMenu(toolbar.menu, item, R.id.open_podcast, R.id.mark_read_item, R.id.visit_website_item)
|
||||
|
||||
if (item!!.feed != null) txtvPodcast.text = item!!.feed!!.title
|
||||
txtvTitle.text = item!!.title
|
||||
binding.itemLink.text = item!!.link
|
||||
|
||||
if (item?.pubDate != null) {
|
||||
val pubDateStr = DateFormatter.formatAbbrev(context, item!!.pubDate)
|
||||
|
@ -385,6 +371,7 @@ import kotlin.math.max
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.FeedItemEvent -> onEventMainThread(event)
|
||||
is FlowEvent.PlayerStatusEvent -> updateButtons()
|
||||
|
@ -404,7 +391,7 @@ import kotlin.math.max
|
|||
}
|
||||
|
||||
fun onEventMainThread(event: FlowEvent.FeedItemEvent) {
|
||||
Logd(TAG, "onEventMainThread() called with: event = [$event]")
|
||||
Logd(TAG, "onEventMainThread() called with: FeedItemEvent")
|
||||
if (this.item == null) return
|
||||
for (item in event.items) {
|
||||
if (this.item!!.id == item.id) {
|
||||
|
@ -417,33 +404,13 @@ import kotlin.math.max
|
|||
fun onEventMainThread(event: FlowEvent.EpisodeDownloadEvent) {
|
||||
if (item == null || item!!.media == null) return
|
||||
if (!event.urls.contains(item!!.media!!.download_url)) return
|
||||
if (itemsLoaded && activity != null) updateButtons()
|
||||
if (itemLoaded && activity != null) updateButtons()
|
||||
}
|
||||
|
||||
// @UnstableApi private fun load0() {
|
||||
// disposable?.dispose()
|
||||
// if (!itemsLoaded) progbarLoading.visibility = View.VISIBLE
|
||||
//
|
||||
// Logd(TAG, "load() called")
|
||||
// disposable = Observable.fromCallable<FeedItem?> { this.loadInBackground() }
|
||||
// .subscribeOn(Schedulers.io())
|
||||
// .observeOn(AndroidSchedulers.mainThread())
|
||||
// .subscribe({ result: FeedItem? ->
|
||||
// progbarLoading.visibility = View.GONE
|
||||
// item = result
|
||||
// onFragmentLoaded()
|
||||
// itemsLoaded = true
|
||||
// },
|
||||
// { error: Throwable? ->
|
||||
// Log.e(TAG, Log.getStackTraceString(error))
|
||||
// })
|
||||
// }
|
||||
|
||||
@UnstableApi private fun load() {
|
||||
if (!itemsLoaded) progbarLoading.visibility = View.VISIBLE
|
||||
if (!itemLoaded) progbarLoading.visibility = View.VISIBLE
|
||||
|
||||
Logd(TAG, "load() called")
|
||||
// val scope = CoroutineScope(Dispatchers.Main)
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
|
@ -459,7 +426,7 @@ import kotlin.math.max
|
|||
progbarLoading.visibility = View.GONE
|
||||
item = result
|
||||
onFragmentLoaded()
|
||||
itemsLoaded = true
|
||||
itemLoaded = true
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
|
|
|
@ -105,6 +105,7 @@ import kotlin.math.min
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.AllEpisodesFilterChangedEvent -> page = 1
|
||||
else -> {}
|
||||
|
|
|
@ -10,7 +10,8 @@ import ac.mdiq.podcini.ui.activity.MainActivity
|
|||
import ac.mdiq.podcini.ui.dialog.EditUrlSettingsDialog
|
||||
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
|
||||
import ac.mdiq.podcini.ui.statistics.feed.FeedStatisticsFragment
|
||||
import ac.mdiq.podcini.ui.view.ToolbarIconTintManager
|
||||
import ac.mdiq.podcini.ui.utils.TransitionEffect
|
||||
import ac.mdiq.podcini.ui.utils.ToolbarIconTintManager
|
||||
import ac.mdiq.podcini.util.IntentUtils
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.ShareUtils
|
||||
|
@ -45,7 +46,6 @@ import com.google.android.material.appbar.CollapsingToolbarLayout
|
|||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
|
@ -21,7 +21,8 @@ import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter
|
|||
import ac.mdiq.podcini.ui.adapter.SelectableAdapter
|
||||
import ac.mdiq.podcini.ui.dialog.*
|
||||
import ac.mdiq.podcini.ui.utils.MoreContentListFooterUtil
|
||||
import ac.mdiq.podcini.ui.view.ToolbarIconTintManager
|
||||
import ac.mdiq.podcini.ui.utils.TransitionEffect
|
||||
import ac.mdiq.podcini.ui.utils.ToolbarIconTintManager
|
||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||
import ac.mdiq.podcini.util.*
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
|
@ -112,6 +113,7 @@ import java.util.concurrent.Semaphore
|
|||
binding.recyclerView.adapter = adapter
|
||||
|
||||
swipeActions = SwipeActions(this, TAG).attachTo(binding.recyclerView)
|
||||
lifecycle.addObserver(swipeActions)
|
||||
refreshSwipeTelltale()
|
||||
binding.header.leftActionIcon.setOnClickListener {
|
||||
swipeActions.showDialog()
|
||||
|
@ -257,7 +259,7 @@ import java.util.concurrent.Semaphore
|
|||
feed!!.nextPageLink = feed!!.download_url
|
||||
feed!!.pageNr = 0
|
||||
try {
|
||||
DBWriter.resetPagedFeedPage(feed).get()
|
||||
runBlocking { DBWriter.resetPagedFeedPage(feed).join() }
|
||||
FeedUpdateManager.runOnce(requireContext(), feed)
|
||||
} catch (e: ExecutionException) {
|
||||
throw RuntimeException(e)
|
||||
|
@ -352,6 +354,7 @@ import java.util.concurrent.Semaphore
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.QueueEvent -> loadItems()
|
||||
is FlowEvent.FavoritesEvent -> loadItems()
|
||||
|
|
|
@ -286,7 +286,7 @@ class FeedSettingsFragment : Fragment() {
|
|||
val setPreferencesFuture = DBWriter.persistFeedPreferences(feedPreferences!!)
|
||||
Thread({
|
||||
try {
|
||||
setPreferencesFuture.get()
|
||||
runBlocking { setPreferencesFuture.join() }
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: ExecutionException) {
|
||||
|
|
|
@ -11,7 +11,6 @@ import ac.mdiq.podcini.ui.activity.MainActivity
|
|||
import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter
|
||||
import ac.mdiq.podcini.ui.dialog.ConfirmationDialog
|
||||
import ac.mdiq.podcini.ui.dialog.ItemSortDialog
|
||||
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
|
||||
import ac.mdiq.podcini.ui.statistics.subscriptions.DatesFilterDialog
|
||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||
import ac.mdiq.podcini.util.DateFormatter
|
||||
|
@ -28,18 +27,18 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
|
||||
@UnstableApi class PlaybackHistoryFragment : BaseEpisodesListFragment() {
|
||||
@UnstableApi class HistoryFragment : BaseEpisodesListFragment() {
|
||||
|
||||
private var sortOrder : SortOrder = SortOrder.PLAYED_DATE_NEW_OLD
|
||||
private var startDate : Long = 0L
|
||||
private var endDate : Long = Date().time
|
||||
|
||||
override fun getFragmentTag(): String {
|
||||
return "PlaybackHistoryFragment"
|
||||
return TAG
|
||||
}
|
||||
|
||||
override fun getPrefName(): String {
|
||||
return "PlaybackHistoryFragment"
|
||||
return TAG
|
||||
}
|
||||
|
||||
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
|
@ -69,7 +68,7 @@ import java.util.*
|
|||
}
|
||||
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo)
|
||||
MenuItemUtils.setOnClickListeners(menu) { item: MenuItem -> this@PlaybackHistoryFragment.onContextItemSelected(item) }
|
||||
MenuItemUtils.setOnClickListeners(menu) { item: MenuItem -> this@HistoryFragment.onContextItemSelected(item) }
|
||||
}
|
||||
}
|
||||
listAdapter.setOnSelectModeListener(this)
|
||||
|
@ -131,6 +130,7 @@ import java.util.*
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.HistoryEvent -> {
|
||||
sortOrder = event.sortOrder
|
||||
|
@ -177,6 +177,6 @@ import java.util.*
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val TAG: String = "PlaybackHistoryFragment"
|
||||
const val TAG: String = "HistoryFragment"
|
||||
}
|
||||
}
|
|
@ -82,9 +82,9 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
|
|||
insets
|
||||
}
|
||||
|
||||
val preferences: SharedPreferences = requireContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
// val preferences: SharedPreferences = requireContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
// TODO: what is this?
|
||||
openFolders = HashSet(preferences.getStringSet(PREF_OPEN_FOLDERS, HashSet<String>())!!) // Must not modify
|
||||
openFolders = HashSet(prefs!!.getStringSet(PREF_OPEN_FOLDERS, HashSet<String>())!!) // Must not modify
|
||||
|
||||
val navList = binding.navRecycler
|
||||
navAdapter = NavListAdapter(itemAccess, requireActivity())
|
||||
|
@ -96,7 +96,7 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
|
|||
startActivity(Intent(activity, PreferenceActivity::class.java))
|
||||
}
|
||||
|
||||
preferences.registerOnSharedPreferenceChangeListener(this)
|
||||
prefs!!.registerOnSharedPreferenceChangeListener(this)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
@ -125,12 +125,13 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
|
|||
_binding = null
|
||||
|
||||
// scope.cancel()
|
||||
requireContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).unregisterOnSharedPreferenceChangeListener(this)
|
||||
prefs!!.unregisterOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.UnreadItemsUpdateEvent, is FlowEvent.FeedListUpdateEvent -> loadData()
|
||||
is FlowEvent.QueueEvent -> onQueueChanged(event)
|
||||
|
@ -292,6 +293,10 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
|
|||
@VisibleForTesting
|
||||
const val PREF_NAME: String = "NavDrawerPrefs"
|
||||
const val TAG: String = "NavDrawerFragment"
|
||||
var prefs: SharedPreferences? = null
|
||||
fun getSharedPrefs(context: Context) {
|
||||
if (prefs == null) prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
// caution: an array in re/values/arrays.xml relates to this
|
||||
@JvmField
|
||||
|
@ -301,15 +306,15 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
|
|||
QueueFragment.TAG,
|
||||
AllEpisodesFragment.TAG,
|
||||
DownloadsFragment.TAG,
|
||||
PlaybackHistoryFragment.TAG,
|
||||
HistoryFragment.TAG,
|
||||
StatisticsFragment.TAG,
|
||||
AddFeedFragment.TAG,
|
||||
)
|
||||
|
||||
fun saveLastNavFragment(context: Context, tag: String?) {
|
||||
Logd(TAG, "saveLastNavFragment(tag: $tag)")
|
||||
val prefs: SharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
val edit: SharedPreferences.Editor = prefs.edit()
|
||||
// val prefs: SharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
val edit: SharedPreferences.Editor = prefs!!.edit()
|
||||
if (tag != null) edit.putString(PREF_LAST_FRAGMENT_TAG, tag)
|
||||
else edit.remove(PREF_LAST_FRAGMENT_TAG)
|
||||
|
||||
|
@ -317,9 +322,9 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
|
|||
}
|
||||
|
||||
fun getLastNavFragment(context: Context): String {
|
||||
val prefs: SharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
val lastFragment: String = prefs.getString(PREF_LAST_FRAGMENT_TAG, SubscriptionFragment.TAG)?:""
|
||||
Logd(TAG, "getLastNavFragment() -> $lastFragment")
|
||||
// val prefs: SharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
val lastFragment: String = prefs!!.getString(PREF_LAST_FRAGMENT_TAG, SubscriptionFragment.TAG)?:""
|
||||
// Logd(TAG, "getLastNavFragment() -> $lastFragment")
|
||||
return lastFragment
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,10 @@ import ac.mdiq.podcini.net.download.service.DownloadRequestCreator.create
|
|||
import ac.mdiq.podcini.net.download.service.Downloader
|
||||
import ac.mdiq.podcini.net.download.service.HttpDownloader
|
||||
import ac.mdiq.podcini.net.download.serviceinterface.DownloadServiceInterface
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownload
|
||||
import ac.mdiq.podcini.receiver.PlayerWidget.Companion.PREFS_NAME
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
import ac.mdiq.podcini.storage.DBTasks
|
||||
import ac.mdiq.podcini.storage.DBWriter
|
||||
|
@ -35,6 +38,7 @@ import android.app.Dialog
|
|||
import android.content.Context
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import android.content.DialogInterface
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.LightingColorFilter
|
||||
import android.os.Bundle
|
||||
import android.text.Spannable
|
||||
|
@ -330,6 +334,7 @@ import kotlin.concurrent.Volatile
|
|||
@OptIn(UnstableApi::class) private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.FeedListUpdateEvent -> onFeedListChanged(event)
|
||||
else -> {}
|
||||
|
@ -507,8 +512,8 @@ import kotlin.concurrent.Volatile
|
|||
}
|
||||
|
||||
if (isEnableAutodownload) {
|
||||
val preferences = requireContext().getSharedPreferences(PREFS, MODE_PRIVATE)
|
||||
binding.autoDownloadCheckBox.isChecked = preferences.getBoolean(PREF_LAST_AUTO_DOWNLOAD, true)
|
||||
// val preferences = requireContext().getSharedPreferences(PREFS, MODE_PRIVATE)
|
||||
binding.autoDownloadCheckBox.isChecked = prefs!!.getBoolean(PREF_LAST_AUTO_DOWNLOAD, true)
|
||||
}
|
||||
|
||||
if (alternateFeedUrls.isEmpty()) {
|
||||
|
@ -587,8 +592,8 @@ import kotlin.concurrent.Volatile
|
|||
val autoDownload = binding.autoDownloadCheckBox.isChecked
|
||||
feedPreferences.autoDownload = autoDownload
|
||||
|
||||
val preferences = requireContext().getSharedPreferences(PREFS, MODE_PRIVATE)
|
||||
val editor = preferences.edit()
|
||||
// val preferences = requireContext().getSharedPreferences(PREFS, MODE_PRIVATE)
|
||||
val editor = prefs!!.edit()
|
||||
editor.putBoolean(PREF_LAST_AUTO_DOWNLOAD, autoDownload)
|
||||
editor.apply()
|
||||
}
|
||||
|
@ -738,6 +743,12 @@ import kotlin.concurrent.Volatile
|
|||
private const val PREF_LAST_AUTO_DOWNLOAD = "lastAutoDownload"
|
||||
private const val KEY_UP_ARROW = "up_arrow"
|
||||
|
||||
var prefs: SharedPreferences? = null
|
||||
|
||||
fun getSharedPrefs(context: Context) {
|
||||
if (prefs == null) prefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(feedUrl: String): OnlineFeedViewFragment {
|
||||
val fragment = OnlineFeedViewFragment()
|
||||
|
|
|
@ -4,6 +4,8 @@ import ac.mdiq.podcini.R
|
|||
import ac.mdiq.podcini.databinding.PlayerDetailsFragmentBinding
|
||||
import ac.mdiq.podcini.feed.util.ImageResourceUtils
|
||||
import ac.mdiq.podcini.playback.PlaybackController
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
import ac.mdiq.podcini.storage.DBWriter.persistFeedItem
|
||||
import ac.mdiq.podcini.storage.model.feed.Chapter
|
||||
|
@ -11,6 +13,8 @@ import ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage
|
|||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
||||
import ac.mdiq.podcini.storage.model.playback.Playable
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions
|
||||
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions.Companion.SWIPE_ACTIONS_PREF_NAME
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.utils.ShownotesCleaner
|
||||
import ac.mdiq.podcini.ui.view.ShownotesWebView
|
||||
|
@ -25,9 +29,7 @@ import android.animation.AnimatorListenerAdapter
|
|||
import android.animation.AnimatorSet
|
||||
import android.animation.ObjectAnimator
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Intent
|
||||
import android.content.*
|
||||
import android.graphics.ColorFilter
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
|
@ -409,8 +411,8 @@ class PlayerDetailsFragment : Fragment() {
|
|||
|
||||
@UnstableApi private fun savePreference() {
|
||||
Logd(TAG, "Saving preferences")
|
||||
val prefs = requireActivity().getSharedPreferences(PREF, Activity.MODE_PRIVATE)
|
||||
val editor = prefs.edit()
|
||||
// val prefs = requireActivity().getSharedPreferences(PREF, Activity.MODE_PRIVATE)
|
||||
val editor = prefs!!.edit()
|
||||
if (controller?.getMedia() != null) {
|
||||
Logd(TAG, "Saving scroll position: " + binding.itemDescriptionFragment.scrollY)
|
||||
editor.putInt(PREF_SCROLL_Y, binding.itemDescriptionFragment.scrollY)
|
||||
|
@ -429,9 +431,9 @@ class PlayerDetailsFragment : Fragment() {
|
|||
Logd(TAG, "Restoring from preferences")
|
||||
val activity: Activity? = activity
|
||||
if (activity != null) {
|
||||
val prefs = activity.getSharedPreferences(PREF, Activity.MODE_PRIVATE)
|
||||
val id = prefs.getString(PREF_PLAYABLE_ID, "")
|
||||
val scrollY = prefs.getInt(PREF_SCROLL_Y, -1)
|
||||
// val prefs = activity.getSharedPreferences(PREF, Activity.MODE_PRIVATE)
|
||||
val id = prefs!!.getString(PREF_PLAYABLE_ID, "")
|
||||
val scrollY = prefs!!.getInt(PREF_SCROLL_Y, -1)
|
||||
if (scrollY != -1) {
|
||||
if (id == controller?.getMedia()?.getIdentifier()?.toString()) {
|
||||
Logd(TAG, "Restored scroll Position: $scrollY")
|
||||
|
@ -455,6 +457,7 @@ class PlayerDetailsFragment : Fragment() {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.PlaybackPositionEvent -> onEventMainThread(event)
|
||||
else -> {}
|
||||
|
@ -525,5 +528,10 @@ class PlayerDetailsFragment : Fragment() {
|
|||
private const val PREF = "ItemDescriptionFragmentPrefs"
|
||||
private const val PREF_SCROLL_Y = "prefScrollY"
|
||||
private const val PREF_PLAYABLE_ID = "prefPlayableId"
|
||||
|
||||
var prefs: SharedPreferences? = null
|
||||
fun getSharedPrefs(context: Context) {
|
||||
if (prefs == null) prefs = context.getSharedPreferences(PREF, Context.MODE_PRIVATE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ import ac.mdiq.podcini.ui.adapter.QueueRecyclerAdapter
|
|||
import ac.mdiq.podcini.ui.adapter.SelectableAdapter
|
||||
import ac.mdiq.podcini.ui.dialog.ConfirmationDialog
|
||||
import ac.mdiq.podcini.ui.dialog.ItemSortDialog
|
||||
import ac.mdiq.podcini.ui.view.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.utils.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
|
||||
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.ui.utils.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||
import ac.mdiq.podcini.util.Converter
|
||||
import ac.mdiq.podcini.util.FeedItemUtil
|
||||
|
@ -72,7 +72,6 @@ import java.util.*
|
|||
private lateinit var toolbar: MaterialToolbar
|
||||
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
|
||||
private lateinit var swipeActions: SwipeActions
|
||||
private lateinit var prefs: SharedPreferences
|
||||
private lateinit var speedDialView: SpeedDialView
|
||||
private lateinit var progressBar: ProgressBar
|
||||
|
||||
|
@ -88,7 +87,7 @@ import java.util.*
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
retainInstance = true
|
||||
prefs = requireActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
// ioScope.launch { prefs = requireActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE) }
|
||||
}
|
||||
|
||||
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
|
@ -122,15 +121,12 @@ import java.util.*
|
|||
recyclerView.addOnScrollListener(LiftOnScrollListener(binding.appbar))
|
||||
|
||||
swipeActions = QueueSwipeActions()
|
||||
lifecycle.addObserver(swipeActions)
|
||||
swipeActions.setFilter(FeedItemFilter(FeedItemFilter.QUEUED))
|
||||
swipeActions.attachTo(recyclerView)
|
||||
refreshSwipeTelltale()
|
||||
binding.leftActionIcon.setOnClickListener {
|
||||
swipeActions.showDialog()
|
||||
}
|
||||
binding.rightActionIcon.setOnClickListener {
|
||||
swipeActions.showDialog()
|
||||
}
|
||||
binding.leftActionIcon.setOnClickListener { swipeActions.showDialog() }
|
||||
binding.rightActionIcon.setOnClickListener { swipeActions.showDialog() }
|
||||
|
||||
recyclerAdapter = object : QueueRecyclerAdapter(activity as MainActivity, swipeActions) {
|
||||
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
|
||||
|
@ -143,9 +139,7 @@ import java.util.*
|
|||
|
||||
swipeRefreshLayout = binding.swipeRefresh
|
||||
swipeRefreshLayout.setDistanceToTriggerSync(resources.getInteger(R.integer.swipe_refresh_distance))
|
||||
swipeRefreshLayout.setOnRefreshListener {
|
||||
FeedUpdateManager.runOnceOrAsk(requireContext())
|
||||
}
|
||||
swipeRefreshLayout.setOnRefreshListener { FeedUpdateManager.runOnceOrAsk(requireContext()) }
|
||||
|
||||
emptyView = EmptyViewHandler(requireContext())
|
||||
emptyView.attachToRecyclerView(recyclerView)
|
||||
|
@ -200,6 +194,7 @@ import java.util.*
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.QueueEvent -> onEventMainThread(event)
|
||||
is FlowEvent.FeedItemEvent -> onEventMainThread(event)
|
||||
|
@ -406,7 +401,7 @@ import java.util.*
|
|||
val isLocked: Boolean = UserPreferences.isQueueLocked
|
||||
if (isLocked) setQueueLocked(false)
|
||||
else {
|
||||
val shouldShowLockWarning: Boolean = prefs.getBoolean(PREF_SHOW_LOCK_WARNING, true)
|
||||
val shouldShowLockWarning: Boolean = prefs!!.getBoolean(PREF_SHOW_LOCK_WARNING, true)
|
||||
if (!shouldShowLockWarning) setQueueLocked(true)
|
||||
else {
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
|
@ -419,7 +414,7 @@ import java.util.*
|
|||
builder.setView(view)
|
||||
|
||||
builder.setPositiveButton(R.string.lock_queue) { _: DialogInterface?, _: Int ->
|
||||
prefs.edit().putBoolean(PREF_SHOW_LOCK_WARNING, !checkDoNotShowAgain.isChecked).apply()
|
||||
prefs!!.edit().putBoolean(PREF_SHOW_LOCK_WARNING, !checkDoNotShowAgain.isChecked).apply()
|
||||
setQueueLocked(true)
|
||||
}
|
||||
builder.setNegativeButton(R.string.cancel_label, null)
|
||||
|
@ -586,7 +581,6 @@ import java.util.*
|
|||
|
||||
// Update tracked position
|
||||
if (dragFrom == -1) dragFrom = fromPosition
|
||||
|
||||
dragTo = toPosition
|
||||
|
||||
val from = viewHolder.bindingAdapterPosition
|
||||
|
@ -632,5 +626,11 @@ import java.util.*
|
|||
|
||||
private const val PREFS = "QueueFragment"
|
||||
private const val PREF_SHOW_LOCK_WARNING = "show_lock_warning"
|
||||
|
||||
private var prefs: SharedPreferences? = null
|
||||
fun getSharedPrefs(context: Context) {
|
||||
if (prefs == null) prefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import ac.mdiq.podcini.BuildConfig
|
|||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.databinding.QuickFeedDiscoveryBinding
|
||||
import ac.mdiq.podcini.net.discovery.ItunesTopListLoader
|
||||
import ac.mdiq.podcini.net.discovery.ItunesTopListLoader.Companion.prefs
|
||||
import ac.mdiq.podcini.net.discovery.PodcastSearchResult
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
|
@ -11,8 +12,6 @@ import ac.mdiq.podcini.ui.adapter.FeedDiscoverAdapter
|
|||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
|
@ -96,6 +95,7 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.DiscoveryDefaultUpdateEvent -> loadToplist()
|
||||
else -> {}
|
||||
|
@ -111,9 +111,9 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
|
|||
poweredByTextView.visibility = View.VISIBLE
|
||||
|
||||
val loader = ItunesTopListLoader(requireContext())
|
||||
val prefs: SharedPreferences = requireActivity().getSharedPreferences(ItunesTopListLoader.PREFS, Context.MODE_PRIVATE)
|
||||
val countryCode: String = prefs.getString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, Locale.getDefault().country)!!
|
||||
if (prefs.getBoolean(ItunesTopListLoader.PREF_KEY_HIDDEN_DISCOVERY_COUNTRY, false)) {
|
||||
// val prefs: SharedPreferences = requireActivity().getSharedPreferences(ItunesTopListLoader.PREFS, Context.MODE_PRIVATE)
|
||||
val countryCode: String = prefs!!.getString(ItunesTopListLoader.PREF_KEY_COUNTRY_CODE, Locale.getDefault().country)!!
|
||||
if (prefs!!.getBoolean(ItunesTopListLoader.PREF_KEY_HIDDEN_DISCOVERY_COUNTRY, false)) {
|
||||
errorTextView.setText(R.string.discover_is_hidden)
|
||||
errorView.visibility = View.VISIBLE
|
||||
discoverGridLayout.visibility = View.GONE
|
||||
|
@ -121,7 +121,7 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
|
|||
poweredByTextView.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
if (BuildConfig.FLAVOR == "free" && prefs.getBoolean(ItunesTopListLoader.PREF_KEY_NEEDS_CONFIRM, true)) {
|
||||
if (BuildConfig.FLAVOR == "free" && prefs!!.getBoolean(ItunesTopListLoader.PREF_KEY_NEEDS_CONFIRM, true)) {
|
||||
errorTextView.text = ""
|
||||
errorView.visibility = View.VISIBLE
|
||||
discoverGridLayout.visibility = View.VISIBLE
|
||||
|
@ -129,7 +129,7 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
|
|||
errorRetry.setText(R.string.discover_confirm)
|
||||
poweredByTextView.visibility = View.VISIBLE
|
||||
errorRetry.setOnClickListener {
|
||||
prefs.edit().putBoolean(ItunesTopListLoader.PREF_KEY_NEEDS_CONFIRM, false).apply()
|
||||
prefs!!.edit().putBoolean(ItunesTopListLoader.PREF_KEY_NEEDS_CONFIRM, false).apply()
|
||||
loadToplist()
|
||||
}
|
||||
return
|
||||
|
@ -185,7 +185,6 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
|
|||
errorRetry.setOnClickListener { loadToplist() }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class) override fun onItemClick(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
|
||||
|
|
|
@ -16,9 +16,9 @@ import ac.mdiq.podcini.ui.activity.MainActivity
|
|||
import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter
|
||||
import ac.mdiq.podcini.ui.adapter.HorizontalFeedListAdapter
|
||||
import ac.mdiq.podcini.ui.adapter.SelectableAdapter
|
||||
import ac.mdiq.podcini.ui.view.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.utils.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
|
||||
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.ui.utils.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||
import ac.mdiq.podcini.util.FeedItemUtil
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
|
@ -239,6 +239,7 @@ import kotlinx.coroutines.withContext
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.FeedListUpdateEvent, is FlowEvent.UnreadItemsUpdateEvent, is FlowEvent.PlayerStatusEvent -> search()
|
||||
is FlowEvent.FeedItemEvent -> onEventMainThread(event)
|
||||
|
|
|
@ -16,13 +16,11 @@ import ac.mdiq.podcini.ui.adapter.SelectableAdapter
|
|||
import ac.mdiq.podcini.ui.adapter.SubscriptionsAdapter
|
||||
import ac.mdiq.podcini.ui.dialog.FeedSortDialog
|
||||
import ac.mdiq.podcini.ui.dialog.SubscriptionsFilterDialog
|
||||
import ac.mdiq.podcini.ui.view.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.ui.utils.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.utils.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
|
@ -62,7 +60,7 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select
|
|||
private lateinit var toolbar: MaterialToolbar
|
||||
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
|
||||
private lateinit var progressBar: ProgressBar
|
||||
private lateinit var prefs: SharedPreferences
|
||||
// private lateinit var prefs: SharedPreferences
|
||||
private lateinit var speedDialView: SpeedDialView
|
||||
|
||||
private var tagFilterIndex = 1
|
||||
|
@ -78,7 +76,7 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select
|
|||
super.onCreate(savedInstanceState)
|
||||
retainInstance = true
|
||||
|
||||
prefs = requireActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
// prefs = requireActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
|
@ -236,6 +234,7 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.FeedListUpdateEvent -> onFeedListChanged(event)
|
||||
is FlowEvent.UnreadItemsUpdateEvent -> loadSubscriptions()
|
||||
|
|
|
@ -8,6 +8,8 @@ import ac.mdiq.podcini.playback.PlaybackController.Companion.setVideoSurface
|
|||
import ac.mdiq.podcini.playback.PlaybackController.Companion.videoSize
|
||||
import ac.mdiq.podcini.playback.base.MediaPlayerBase
|
||||
import ac.mdiq.podcini.playback.base.PlayerStatus
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.fastForwardSecs
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.rewindSecs
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.setShowRemainTimeSetting
|
||||
|
@ -155,6 +157,7 @@ class VideoEpisodeFragment : Fragment(), OnSeekBarChangeListener {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.BufferUpdateEvent -> bufferUpdate(event)
|
||||
is FlowEvent.PlaybackPositionEvent -> onPositionObserverUpdate()
|
||||
|
|
|
@ -3,6 +3,7 @@ package ac.mdiq.podcini.ui.statistics
|
|||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.databinding.PagerFragmentBinding
|
||||
import ac.mdiq.podcini.receiver.PlayerWidget.Companion.PREFS_NAME
|
||||
import ac.mdiq.podcini.storage.DBWriter
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.dialog.ConfirmationDialog
|
||||
|
@ -14,6 +15,7 @@ import ac.mdiq.podcini.util.event.EventFlow
|
|||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
|
@ -98,7 +100,7 @@ class StatisticsFragment : PagedToolbarFragment() {
|
|||
}
|
||||
|
||||
@UnstableApi private fun doResetStatistics() {
|
||||
requireContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).edit()
|
||||
prefs!!.edit()
|
||||
.putBoolean(PREF_INCLUDE_MARKED_PLAYED, false)
|
||||
.putLong(PREF_FILTER_FROM, 0)
|
||||
.putLong(PREF_FILTER_TO, Long.MAX_VALUE)
|
||||
|
@ -146,10 +148,16 @@ class StatisticsFragment : PagedToolbarFragment() {
|
|||
const val PREF_FILTER_FROM: String = "filterFrom"
|
||||
const val PREF_FILTER_TO: String = "filterTo"
|
||||
|
||||
|
||||
private const val POS_SUBSCRIPTIONS = 0
|
||||
private const val POS_YEARS = 1
|
||||
private const val POS_SPACE_TAKEN = 2
|
||||
private const val TOTAL_COUNT = 3
|
||||
|
||||
var prefs: SharedPreferences? = null
|
||||
|
||||
fun getSharedPrefs(context: Context) {
|
||||
if (prefs == null) prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ abstract class DatesFilterDialog(private val context: Context, oldestDate: Long)
|
|||
protected val filterDatesFrom: Pair<Array<String>, Array<Long>>
|
||||
protected val filterDatesTo: Pair<Array<String>, Array<Long>>
|
||||
|
||||
|
||||
init {
|
||||
initParams()
|
||||
filterDatesFrom = makeMonthlyList(oldestDate, false)
|
||||
|
|
|
@ -4,15 +4,13 @@ package ac.mdiq.podcini.ui.statistics.subscriptions
|
|||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.databinding.StatisticsFragmentBinding
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
import ac.mdiq.podcini.storage.DBReader.MonthlyStatisticsItem
|
||||
import ac.mdiq.podcini.storage.DBReader.StatisticsResult
|
||||
import ac.mdiq.podcini.storage.StatisticsItem
|
||||
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
|
||||
import ac.mdiq.podcini.ui.statistics.years.YearsStatisticsFragment
|
||||
import ac.mdiq.podcini.ui.statistics.years.YearsStatisticsFragment.Companion
|
||||
import ac.mdiq.podcini.ui.statistics.StatisticsFragment.Companion.prefs
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
|
@ -21,10 +19,6 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -77,6 +71,7 @@ class SubscriptionStatisticsFragment : Fragment() {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.StatisticsEvent -> refreshStatistics()
|
||||
else -> {}
|
||||
|
@ -96,7 +91,7 @@ class SubscriptionStatisticsFragment : Fragment() {
|
|||
if (statisticsResult != null) {
|
||||
val dialog = object: DatesFilterDialog(requireContext(), statisticsResult!!.oldestDate) {
|
||||
override fun initParams() {
|
||||
prefs = requireContext().getSharedPreferences(StatisticsFragment.PREF_NAME, Context.MODE_PRIVATE)
|
||||
prefs = StatisticsFragment.prefs
|
||||
includeMarkedAsPlayed = prefs!!.getBoolean(StatisticsFragment.PREF_INCLUDE_MARKED_PLAYED, false)
|
||||
timeFilterFrom = prefs!!.getLong(StatisticsFragment.PREF_FILTER_FROM, 0)
|
||||
timeFilterTo = prefs!!.getLong(StatisticsFragment.PREF_FILTER_TO, Long.MAX_VALUE)
|
||||
|
@ -126,10 +121,10 @@ class SubscriptionStatisticsFragment : Fragment() {
|
|||
private fun loadStatistics() {
|
||||
// disposable?.dispose()
|
||||
|
||||
val prefs = requireContext().getSharedPreferences(StatisticsFragment.PREF_NAME, Context.MODE_PRIVATE)
|
||||
val includeMarkedAsPlayed = prefs.getBoolean(StatisticsFragment.PREF_INCLUDE_MARKED_PLAYED, false)
|
||||
val timeFilterFrom = prefs.getLong(StatisticsFragment.PREF_FILTER_FROM, 0)
|
||||
val timeFilterTo = prefs.getLong(StatisticsFragment.PREF_FILTER_TO, Long.MAX_VALUE)
|
||||
// val prefs = requireContext().getSharedPreferences(StatisticsFragment.PREF_NAME, Context.MODE_PRIVATE)
|
||||
val includeMarkedAsPlayed = prefs!!.getBoolean(StatisticsFragment.PREF_INCLUDE_MARKED_PLAYED, false)
|
||||
val timeFilterFrom = prefs!!.getLong(StatisticsFragment.PREF_FILTER_FROM, 0)
|
||||
val timeFilterTo = prefs!!.getLong(StatisticsFragment.PREF_FILTER_TO, Long.MAX_VALUE)
|
||||
|
||||
// disposable = Observable.fromCallable {
|
||||
// val statisticsData = DBReader.getStatistics(
|
||||
|
|
|
@ -3,8 +3,11 @@ package ac.mdiq.podcini.ui.statistics.years
|
|||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.databinding.StatisticsFragmentBinding
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
import ac.mdiq.podcini.storage.DBReader.MonthlyStatisticsItem
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import android.os.Bundle
|
||||
|
@ -65,6 +68,7 @@ class YearsStatisticsFragment : Fragment() {
|
|||
private fun procFlowEvents() {
|
||||
lifecycleScope.launch {
|
||||
EventFlow.events.collectLatest { event ->
|
||||
Logd(TAG, "Received event: $event")
|
||||
when (event) {
|
||||
is FlowEvent.StatisticsEvent -> refreshStatistics()
|
||||
else -> {}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package ac.mdiq.podcini.ui.adapter
|
||||
package ac.mdiq.podcini.ui.utils
|
||||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
|
@ -75,6 +76,7 @@ class CoverLoader(private val activity: MainActivity) {
|
|||
.setHeader("User-Agent", "Mozilla/5.0")
|
||||
.listener(object : ImageRequest.Listener {
|
||||
override fun onError(request: ImageRequest, throwable: ErrorResult) {
|
||||
Logd("CoverLoader", "Trying to get fallback image")
|
||||
val fallbackImageRequest = ImageRequest.Builder(activity)
|
||||
.data(fallbackUri)
|
||||
.setHeader("User-Agent", "Mozilla/5.0")
|
||||
|
@ -86,9 +88,7 @@ class CoverLoader(private val activity: MainActivity) {
|
|||
})
|
||||
.target(coverTargetCoil)
|
||||
.build()
|
||||
activity.imageLoader
|
||||
.enqueue(request)
|
||||
|
||||
activity.imageLoader.enqueue(request)
|
||||
}
|
||||
|
||||
internal class CoilCoverTarget(fallbackTitle: TextView?, coverImage: ImageView, private val textAndImageCombined: Boolean) : Target {
|
|
@ -1,4 +1,4 @@
|
|||
package ac.mdiq.podcini.ui.view
|
||||
package ac.mdiq.podcini.ui.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.database.DataSetObserver
|
|
@ -1,4 +1,4 @@
|
|||
package ac.mdiq.podcini.ui.view
|
||||
package ac.mdiq.podcini.ui.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
|
@ -1,4 +1,4 @@
|
|||
package ac.mdiq.podcini.ui.view
|
||||
package ac.mdiq.podcini.ui.utils
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.view.View
|
|
@ -1,4 +1,4 @@
|
|||
package ac.mdiq.podcini.ui.view
|
||||
package ac.mdiq.podcini.ui.utils
|
||||
|
||||
import ac.mdiq.podcini.R
|
||||
import android.content.Context
|
|
@ -1,4 +1,4 @@
|
|||
package ac.mdiq.podcini.ui.view
|
||||
package ac.mdiq.podcini.ui.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
|
@ -1,4 +1,4 @@
|
|||
package ac.mdiq.podcini.ui.view
|
||||
package ac.mdiq.podcini.ui.utils
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package ac.mdiq.podcini.ui.view
|
||||
package ac.mdiq.podcini.ui.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PorterDuff
|
|
@ -1,4 +1,4 @@
|
|||
package ac.mdiq.podcini.ui.fragment
|
||||
package ac.mdiq.podcini.ui.utils
|
||||
|
||||
enum class TransitionEffect {
|
||||
NONE, FADE, SLIDE
|
|
@ -8,6 +8,8 @@ import androidx.recyclerview.widget.DividerItemDecoration
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.receiver.PlayerWidget.Companion.PREFS_NAME
|
||||
import android.content.SharedPreferences
|
||||
|
||||
class EpisodeItemListRecyclerView : RecyclerView {
|
||||
private lateinit var layoutManager: LinearLayoutManager
|
||||
|
@ -46,16 +48,16 @@ class EpisodeItemListRecyclerView : RecyclerView {
|
|||
val firstItemView = layoutManager.findViewByPosition(firstItem)
|
||||
val topOffset = firstItemView?.top?.toFloat() ?: 0f
|
||||
|
||||
context.getSharedPreferences(TAG, Context.MODE_PRIVATE).edit()
|
||||
prefs!!.edit()
|
||||
.putInt(PREF_PREFIX_SCROLL_POSITION + tag, firstItem)
|
||||
.putInt(PREF_PREFIX_SCROLL_OFFSET + tag, topOffset.toInt())
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun restoreScrollPosition(tag: String) {
|
||||
val prefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE)
|
||||
val position = prefs.getInt(PREF_PREFIX_SCROLL_POSITION + tag, 0)
|
||||
val offset = prefs.getInt(PREF_PREFIX_SCROLL_OFFSET + tag, 0)
|
||||
// val prefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE)
|
||||
val position = prefs!!.getInt(PREF_PREFIX_SCROLL_POSITION + tag, 0)
|
||||
val offset = prefs!!.getInt(PREF_PREFIX_SCROLL_OFFSET + tag, 0)
|
||||
if (position > 0 || offset > 0) layoutManager.scrollToPositionWithOffset(position, offset)
|
||||
}
|
||||
|
||||
|
@ -71,5 +73,11 @@ class EpisodeItemListRecyclerView : RecyclerView {
|
|||
private const val TAG = "EpisodeItemListRecyclerView"
|
||||
private const val PREF_PREFIX_SCROLL_POSITION = "scroll_position_"
|
||||
private const val PREF_PREFIX_SCROLL_OFFSET = "scroll_offset_"
|
||||
|
||||
var prefs: SharedPreferences? = null
|
||||
|
||||
fun getSharedPrefs(context: Context) {
|
||||
if (prefs == null) prefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package ac.mdiq.podcini.ui.view.viewholder
|
||||
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import android.os.Build
|
||||
import android.text.Layout
|
||||
import android.text.format.Formatter
|
||||
import android.util.Log
|
||||
|
@ -18,7 +17,7 @@ import com.google.android.material.elevation.SurfaceColors
|
|||
import com.joanzapata.iconify.Iconify
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.databinding.FeeditemlistItemBinding
|
||||
import ac.mdiq.podcini.ui.adapter.CoverLoader
|
||||
import ac.mdiq.podcini.ui.utils.CoverLoader
|
||||
import ac.mdiq.podcini.feed.util.ImageResourceUtils
|
||||
import ac.mdiq.podcini.net.download.MediaSizeLoader
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
|
@ -37,7 +36,6 @@ import ac.mdiq.podcini.util.*
|
|||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.content.ContextCompat.getDrawable
|
||||
import io.reactivex.functions.Consumer
|
||||
import kotlin.math.max
|
||||
|
||||
|
@ -45,8 +43,8 @@ import kotlin.math.max
|
|||
* Holds the view which shows FeedItems.
|
||||
*/
|
||||
@UnstableApi
|
||||
open class EpisodeItemViewHolder(private val activity: MainActivity, parent: ViewGroup?) :
|
||||
RecyclerView.ViewHolder(LayoutInflater.from(activity).inflate(R.layout.feeditemlist_item, parent, false)) {
|
||||
open class EpisodeItemViewHolder(private val activity: MainActivity, parent: ViewGroup)
|
||||
: RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.feeditemlist_item, parent, false)) {
|
||||
|
||||
val binding: FeeditemlistItemBinding = FeeditemlistItemBinding.bind(itemView)
|
||||
|
||||
|
@ -108,7 +106,7 @@ open class EpisodeItemViewHolder(private val activity: MainActivity, parent: Vie
|
|||
container.alpha = if (item.isPlayed()) 0.75f else 1.0f
|
||||
|
||||
val newButton = ItemActionButton.forItem(item)
|
||||
Logd(TAG, "bind ${actionButton?.TAG} ${newButton.TAG} ${item.title}")
|
||||
Logd(TAG, "Trying to bind button ${actionButton?.TAG} ${newButton.TAG} ${item.title}")
|
||||
// not using a new button to ensure valid progress values, for TTS audio generation
|
||||
if (!(actionButton?.TAG == TTSActionButton::class.simpleName && newButton.TAG == TTSActionButton::class.simpleName)) {
|
||||
actionButton = newButton
|
||||
|
@ -118,11 +116,9 @@ open class EpisodeItemViewHolder(private val activity: MainActivity, parent: Vie
|
|||
|
||||
// Log.d(TAG, "bind called ${item.media}")
|
||||
when {
|
||||
item.media != null -> {
|
||||
bind(item.media!!)
|
||||
}
|
||||
item.media != null -> bind(item.media!!)
|
||||
// for generating TTS files for episode without media
|
||||
item.playState == BUILDING -> {
|
||||
// for generating TTS files for episode without media
|
||||
secondaryActionProgress.setPercentage(actionButton!!.processing, item)
|
||||
secondaryActionProgress.setIndeterminate(false)
|
||||
}
|
||||
|
@ -139,15 +135,16 @@ open class EpisodeItemViewHolder(private val activity: MainActivity, parent: Vie
|
|||
|
||||
if (coverHolder.visibility == View.VISIBLE) {
|
||||
val imgLoc = ImageResourceUtils.getEpisodeListImageLocation(item)
|
||||
// Logd(TAG, "imgLoc $imgLoc ${item.feed?.imageUrl} ${item.title}")
|
||||
if (!imgLoc.isNullOrBlank() && !imgLoc.contains(PREFIX_GENERATIVE_COVER)) CoverLoader(activity)
|
||||
.withUri(imgLoc)
|
||||
.withFallbackUri(item.feed?.imageUrl)
|
||||
.withPlaceholderView(placeholder)
|
||||
.withCoverView(cover)
|
||||
.load()
|
||||
Logd(TAG, "imgLoc $imgLoc ${item.feed?.imageUrl} ${item.title}")
|
||||
if (!imgLoc.isNullOrBlank() && !imgLoc.contains(PREFIX_GENERATIVE_COVER))
|
||||
CoverLoader(activity)
|
||||
.withUri(imgLoc)
|
||||
.withFallbackUri(item.feed?.imageUrl)
|
||||
.withPlaceholderView(placeholder)
|
||||
.withCoverView(cover)
|
||||
.load()
|
||||
else {
|
||||
Logd(TAG, "setting to ic_launcher")
|
||||
Logd(TAG, "setting cover to ic_launcher")
|
||||
cover.setImageDrawable(AppCompatResources.getDrawable(activity, R.drawable.ic_launcher_foreground))
|
||||
}
|
||||
}
|
||||
|
@ -211,12 +208,11 @@ open class EpisodeItemViewHolder(private val activity: MainActivity, parent: Vie
|
|||
NetworkUtils.isEpisodeHeadDownloadAllowed && !media.checkedOnSizeButUnknown() -> {
|
||||
size.text = "{fa-spinner}"
|
||||
Iconify.addIcons(size)
|
||||
MediaSizeLoader.getFeedMediaSizeObservable(media).subscribe(
|
||||
Consumer<Long?> { sizeValue: Long? ->
|
||||
if (sizeValue == null) return@Consumer
|
||||
if (sizeValue > 0) size.text = Formatter.formatShortFileSize(activity, sizeValue)
|
||||
else size.text = ""
|
||||
}) { error: Throwable? ->
|
||||
MediaSizeLoader.getFeedMediaSizeObservable(media).subscribe(Consumer<Long?> { sizeValue: Long? ->
|
||||
if (sizeValue == null) return@Consumer
|
||||
if (sizeValue > 0) size.text = Formatter.formatShortFileSize(activity, sizeValue)
|
||||
else size.text = ""
|
||||
}) { error: Throwable? ->
|
||||
size.text = ""
|
||||
Log.e(TAG, Log.getStackTraceString(error))
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import ac.mdiq.podcini.preferences.UserPreferences.shouldShowRemainingTime
|
|||
import ac.mdiq.podcini.receiver.MediaButtonReceiver.Companion.createPendingIntent
|
||||
import ac.mdiq.podcini.receiver.PlayerWidget
|
||||
import ac.mdiq.podcini.receiver.PlayerWidget.Companion.isEnabled
|
||||
import ac.mdiq.podcini.receiver.PlayerWidget.Companion.prefs
|
||||
import ac.mdiq.podcini.storage.model.playback.MediaType
|
||||
import ac.mdiq.podcini.storage.model.playback.Playable
|
||||
import ac.mdiq.podcini.ui.activity.appstartintent.MainActivityStarter
|
||||
|
@ -14,13 +15,10 @@ import ac.mdiq.podcini.ui.activity.appstartintent.PlaybackSpeedActivityStarter
|
|||
import ac.mdiq.podcini.ui.activity.appstartintent.VideoPlayerActivityStarter
|
||||
import ac.mdiq.podcini.util.Converter.getDurationStringLong
|
||||
import ac.mdiq.podcini.util.TimeSpeedConverter
|
||||
import android.R.attr.bitmap
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
|
@ -165,16 +163,16 @@ object WidgetUpdater {
|
|||
|
||||
for (id in widgetIds) {
|
||||
val options = manager.getAppWidgetOptions(id)
|
||||
val prefs = context.getSharedPreferences(PlayerWidget.PREFS_NAME, Context.MODE_PRIVATE)
|
||||
// val prefs = context.getSharedPreferences(PlayerWidget.PREFS_NAME, Context.MODE_PRIVATE)
|
||||
val minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
|
||||
val columns = getCellsForSize(minWidth)
|
||||
if (columns < 3) views.setViewVisibility(R.id.layout_center, View.INVISIBLE)
|
||||
else views.setViewVisibility(R.id.layout_center, View.VISIBLE)
|
||||
|
||||
val showPlaybackSpeed = prefs.getBoolean(PlayerWidget.KEY_WIDGET_PLAYBACK_SPEED + id, true)
|
||||
val showRewind = prefs.getBoolean(PlayerWidget.KEY_WIDGET_REWIND + id, true)
|
||||
val showFastForward = prefs.getBoolean(PlayerWidget.KEY_WIDGET_FAST_FORWARD + id, true)
|
||||
val showSkip = prefs.getBoolean(PlayerWidget.KEY_WIDGET_SKIP + id, true)
|
||||
val showPlaybackSpeed = prefs!!.getBoolean(PlayerWidget.KEY_WIDGET_PLAYBACK_SPEED + id, true)
|
||||
val showRewind = prefs!!.getBoolean(PlayerWidget.KEY_WIDGET_REWIND + id, true)
|
||||
val showFastForward = prefs!!.getBoolean(PlayerWidget.KEY_WIDGET_FAST_FORWARD + id, true)
|
||||
val showSkip = prefs!!.getBoolean(PlayerWidget.KEY_WIDGET_SKIP + id, true)
|
||||
|
||||
if (showPlaybackSpeed || showRewind || showSkip || showFastForward) {
|
||||
views.setInt(R.id.extendedButtonsContainer, "setVisibility", View.VISIBLE)
|
||||
|
@ -188,7 +186,7 @@ object WidgetUpdater {
|
|||
views.setInt(R.id.butPlay, "setVisibility", View.VISIBLE)
|
||||
}
|
||||
|
||||
val backgroundColor = prefs.getInt(PlayerWidget.KEY_WIDGET_COLOR + id, PlayerWidget.DEFAULT_COLOR)
|
||||
val backgroundColor = prefs!!.getInt(PlayerWidget.KEY_WIDGET_COLOR + id, PlayerWidget.DEFAULT_COLOR)
|
||||
views.setInt(R.id.widgetLayout, "setBackgroundColor", backgroundColor)
|
||||
|
||||
manager.updateAppWidget(id, views)
|
||||
|
|
|
@ -2,7 +2,7 @@ package ac.mdiq.podcini.ui.widget
|
|||
|
||||
import ac.mdiq.podcini.feed.util.PlaybackSpeedUtils.getCurrentPlaybackSpeed
|
||||
import ac.mdiq.podcini.playback.base.PlayerStatus
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.createInstanceFromPreferences
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences.Companion.loadPlayableFromPreferences
|
||||
import ac.mdiq.podcini.ui.widget.WidgetUpdater.WidgetState
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.content.Context
|
||||
|
@ -24,7 +24,7 @@ class WidgetUpdaterWorker(context: Context, workerParams: WorkerParameters) : Wo
|
|||
* Loads the current media from the database and updates the widget in a background job.
|
||||
*/
|
||||
private fun updateWidget() {
|
||||
val media = createInstanceFromPreferences(applicationContext)
|
||||
val media = loadPlayableFromPreferences()
|
||||
if (media != null) WidgetUpdater.updateWidget(applicationContext, WidgetState(media, PlayerStatus.STOPPED, media.getPosition(), media.getDuration(), getCurrentPlaybackSpeed(media)))
|
||||
else WidgetUpdater.updateWidget(applicationContext, WidgetState(PlayerStatus.STOPPED))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ac.mdiq.podcini.util
|
||||
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.receiver.SPAReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
@ -31,12 +32,12 @@ object SPAUtil {
|
|||
Log.wtf(TAG, "Unable to get application context")
|
||||
return false
|
||||
}
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(appContext)
|
||||
if (!prefs.getBoolean(PREF_HAS_QUERIED_SP_APPS, false)) {
|
||||
// val prefs = PreferenceManager.getDefaultSharedPreferences(appContext)
|
||||
if (!appPrefs.getBoolean(PREF_HAS_QUERIED_SP_APPS, false)) {
|
||||
appContext.sendBroadcast(Intent(SPAReceiver.ACTION_SP_APPS_QUERY_FEEDS))
|
||||
Logd(TAG, "Sending SP_APPS_QUERY_FEEDS intent")
|
||||
|
||||
val editor = prefs.edit()
|
||||
val editor = appPrefs.edit()
|
||||
editor.putBoolean(PREF_HAS_QUERIED_SP_APPS, true)
|
||||
editor.apply()
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ import ac.mdiq.podcini.storage.database.PodDBAdapter
|
|||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.proxyConfig
|
||||
import ac.mdiq.podcini.net.download.service.DownloadServiceInterfaceImpl
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
@UnstableApi
|
||||
|
|
Before Width: | Height: | Size: 590 KiB |
Before Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 953 KiB |
Before Width: | Height: | Size: 910 KiB |
Before Width: | Height: | Size: 619 KiB |
Before Width: | Height: | Size: 813 KiB |
Before Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 198 KiB |
Before Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 225 KiB |
Before Width: | Height: | Size: 219 KiB |
Before Width: | Height: | Size: 375 KiB |