6.3.5 commit
This commit is contained in:
parent
87af1a18f6
commit
50e9dffdb8
|
@ -31,8 +31,8 @@ android {
|
|||
testApplicationId "ac.mdiq.podcini.tests"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
versionCode 3020228
|
||||
versionName "6.3.4"
|
||||
versionCode 3020229
|
||||
versionName "6.3.5"
|
||||
|
||||
applicationId "ac.mdiq.podcini.R"
|
||||
def commit = ""
|
||||
|
|
|
@ -85,7 +85,6 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() {
|
|||
try {
|
||||
val workInfoList = future.get() // Wait for the completion of the future operation and retrieve the result
|
||||
workInfoList.forEach { workInfo ->
|
||||
// TODO: why cancel so many times??
|
||||
if (workInfo.tags.contains(WORK_DATA_WAS_QUEUED)) {
|
||||
val item_ = media.episodeOrFetch()
|
||||
if (item_ != null) Queues.removeFromQueue(item_)
|
||||
|
|
|
@ -271,7 +271,7 @@ class PlaybackService : MediaSessionService() {
|
|||
}
|
||||
|
||||
override fun onMediaChanged(reloadUI: Boolean) {
|
||||
Logd(TAG, "reloadUI callback reached")
|
||||
Logd(TAG, "onMediaChanged reloadUI callback reached")
|
||||
if (reloadUI) sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0)
|
||||
}
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ class MainPreferencesFragment : PreferenceFragmentCompat() {
|
|||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_autodownload))
|
||||
config.index(R.xml.preferences_synchronization).addBreadcrumb(getTitleOfPage(R.xml.preferences_synchronization))
|
||||
config.index(R.xml.preferences_notifications).addBreadcrumb(getTitleOfPage(R.xml.preferences_notifications))
|
||||
config.index(R.xml.feed_settings).addBreadcrumb(getTitleOfPage(R.xml.feed_settings))
|
||||
// config.index(R.xml.feed_settings).addBreadcrumb(getTitleOfPage(R.xml.feed_settings))
|
||||
config.index(R.xml.preferences_swipe)
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_user_interface))
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_swipe))
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package ac.mdiq.podcini.receiver
|
||||
|
||||
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.config.ClientConfigurator
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
|
@ -12,7 +10,6 @@ import android.util.Log
|
|||
import android.view.KeyEvent
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import ac.mdiq.podcini.util.config.ClientConfigurator
|
||||
|
||||
/**
|
||||
* Receives media button events.
|
||||
|
@ -20,17 +17,29 @@ import ac.mdiq.podcini.util.config.ClientConfigurator
|
|||
class MediaButtonReceiver : BroadcastReceiver() {
|
||||
@UnstableApi
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Log.d(TAG, "onReceive called with action: ${intent.action}")
|
||||
if (intent.extras == null) return
|
||||
Log.d(TAG, "onReceive Received intent: $intent")
|
||||
Log.d(TAG, "onReceive Action: ${intent.action}")
|
||||
val extras = intent.extras
|
||||
Log.d(TAG, "onReceive Extras: $extras")
|
||||
if (extras == null) return
|
||||
|
||||
val event = intent.extras!![Intent.EXTRA_KEY_EVENT] as? KeyEvent
|
||||
if (event != null && event.action == KeyEvent.ACTION_DOWN && event.repeatCount == 0) {
|
||||
Log.d(TAG, "onReceive Extras: ${extras.keySet()}")
|
||||
for (key in extras.keySet()) {
|
||||
Log.d(TAG, "onReceive Extra[$key] = ${extras[key]}")
|
||||
}
|
||||
|
||||
// val event = extras.getParcelable(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java)
|
||||
val keyEvent: KeyEvent? = if (Build.VERSION.SDK_INT >= 33) extras.getParcelable(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java)
|
||||
else extras.getParcelable(Intent.EXTRA_KEY_EVENT) as KeyEvent?
|
||||
Log.d(TAG, "onReceive keyEvent = $keyEvent" )
|
||||
|
||||
if (keyEvent != null && keyEvent.action == KeyEvent.ACTION_DOWN && keyEvent.repeatCount == 0) {
|
||||
ClientConfigurator.initialize(context)
|
||||
val serviceIntent = Intent(PLAYBACK_SERVICE_INTENT)
|
||||
serviceIntent.setPackage(context.packageName)
|
||||
serviceIntent.putExtra(EXTRA_KEYCODE, event.keyCode)
|
||||
serviceIntent.putExtra(EXTRA_SOURCE, event.source)
|
||||
serviceIntent.putExtra(EXTRA_HARDWAREBUTTON, event.eventTime > 0 || event.downTime > 0)
|
||||
serviceIntent.putExtra(EXTRA_KEYCODE, keyEvent.keyCode)
|
||||
serviceIntent.putExtra(EXTRA_SOURCE, keyEvent.source)
|
||||
serviceIntent.putExtra(EXTRA_HARDWAREBUTTON, keyEvent.eventTime > 0 || keyEvent.downTime > 0)
|
||||
try {
|
||||
ContextCompat.startForegroundService(context, serviceIntent)
|
||||
} catch (e: Exception) {
|
||||
|
|
|
@ -71,48 +71,7 @@ object AutoDownloads {
|
|||
// likely not needed
|
||||
@UnstableApi
|
||||
open fun autoDownloadEpisodeMedia(context: Context, feeds: List<Feed>? = null): Runnable? {
|
||||
return Runnable {
|
||||
// // true if we should auto download based on network status
|
||||
//// val networkShouldAutoDl = (isAutoDownloadAllowed)
|
||||
// val networkShouldAutoDl = (isAutoDownloadAllowed && isEnableAutodownload)
|
||||
// // true if we should auto download based on power status
|
||||
// val powerShouldAutoDl = (deviceCharging(context) || isEnableAutodownloadOnBattery)
|
||||
// Logd(TAG, "prepare autoDownloadUndownloadedItems $networkShouldAutoDl $powerShouldAutoDl")
|
||||
// // we should only auto download if both network AND power are happy
|
||||
// if (networkShouldAutoDl && powerShouldAutoDl) {
|
||||
// Logd(TAG, "Performing auto-dl of undownloaded episodes")
|
||||
// val queueItems = curQueue.episodes
|
||||
// val newItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.new.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
// Logd(TAG, "newItems: ${newItems.size}")
|
||||
// val candidates: MutableList<Episode> = ArrayList(queueItems.size + newItems.size)
|
||||
// candidates.addAll(queueItems)
|
||||
// for (newItem in newItems) {
|
||||
// val feedPrefs = newItem.feed!!.preferences
|
||||
// if (feedPrefs!!.autoDownload && !candidates.contains(newItem) && feedPrefs.autoDownloadFilter!!.shouldAutoDownload(newItem)) candidates.add(newItem)
|
||||
// }
|
||||
// // filter items that are not auto downloadable
|
||||
// val it = candidates.iterator()
|
||||
// while (it.hasNext()) {
|
||||
// val item = it.next()
|
||||
// if (!item.isAutoDownloadEnabled || item.isDownloaded || item.media == null || isCurMedia(item.media) || item.feed?.isLocalFeed == true)
|
||||
// it.remove()
|
||||
// }
|
||||
// val autoDownloadableEpisodes = candidates.size
|
||||
// val downloadedEpisodes = getEpisodesCount(EpisodeFilter(EpisodeFilter.States.downloaded.name))
|
||||
// val deletedEpisodes = AutoCleanups.build().makeRoomForEpisodes(context, autoDownloadableEpisodes)
|
||||
// val cacheIsUnlimited = episodeCacheSize == UserPreferences.EPISODE_CACHE_SIZE_UNLIMITED
|
||||
// val episodeCacheSize = episodeCacheSize
|
||||
// val episodeSpaceLeft =
|
||||
// if (cacheIsUnlimited || episodeCacheSize >= downloadedEpisodes + autoDownloadableEpisodes) autoDownloadableEpisodes
|
||||
// else episodeCacheSize - (downloadedEpisodes - deletedEpisodes)
|
||||
// val itemsToDownload: List<Episode> = candidates.subList(0, episodeSpaceLeft)
|
||||
// if (itemsToDownload.isNotEmpty()) {
|
||||
// Logd(TAG, "Enqueueing " + itemsToDownload.size + " items for download")
|
||||
// for (episode in itemsToDownload) DownloadServiceInterface.get()?.download(context, episode)
|
||||
// }
|
||||
// }
|
||||
// else Logd(TAG, "not auto downloaded networkShouldAutoDl: $networkShouldAutoDl powerShouldAutoDl $powerShouldAutoDl")
|
||||
}
|
||||
return Runnable {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@ import ac.mdiq.podcini.preferences.UserPreferences.isAutoDelete
|
|||
import ac.mdiq.podcini.preferences.UserPreferences.isAutoDeleteLocal
|
||||
import ac.mdiq.podcini.storage.database.Episodes.deleteEpisodes
|
||||
import ac.mdiq.podcini.storage.database.LogsAndStats.addDownloadStatus
|
||||
import ac.mdiq.podcini.storage.database.Queues.addToQueueSync
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromAllQueuesQuiet
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
|
||||
|
@ -284,6 +285,10 @@ object Feeds {
|
|||
if (pubDate == null || priorMostRecentDate == null || priorMostRecentDate.before(pubDate) || priorMostRecentDate == pubDate) {
|
||||
Logd(TAG, "Marking episode published on $pubDate new, prior most recent date = $priorMostRecentDate")
|
||||
episode.setNew()
|
||||
if (savedFeed.preferences?.autoAddNewToQueue == true) {
|
||||
val q = savedFeed.preferences?.queue
|
||||
if (q != null) runOnIOScope { addToQueueSync(false, episode, q) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,18 +133,13 @@ object Queues {
|
|||
if (queueModified) {
|
||||
// TODO: handle sorting
|
||||
applySortOrder(qItems, events)
|
||||
// curQueue.episodes.clear()
|
||||
// curQueue.episodes.addAll(qItems)
|
||||
curQueue = upsert(curQueue) {
|
||||
it.episodeIds.clear()
|
||||
it.episodeIds.addAll(qItemIds)
|
||||
it.update()
|
||||
}
|
||||
// curQueue.episodes.addAll(qItems)
|
||||
|
||||
for (event in events) EventFlow.postEvent(event)
|
||||
|
||||
// EventFlow.postEvent(FlowEvent.EpisodeEvent.updated(updatedItems))
|
||||
if (markAsUnplayed && markAsUnplayeds.size > 0) setPlayState(Episode.PlayState.UNPLAYED.code, false, *markAsUnplayeds.toTypedArray())
|
||||
// if (performAutoDownload) autodownloadEpisodeMedia(context)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import kotlin.coroutines.ContinuationInterceptor
|
|||
object RealmDB {
|
||||
private val TAG: String = RealmDB::class.simpleName ?: "Anonymous"
|
||||
|
||||
private const val SCHEMA_VERSION_NUMBER = 18L
|
||||
private const val SCHEMA_VERSION_NUMBER = 19L
|
||||
|
||||
private val ioScope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ac.mdiq.podcini.storage.model
|
||||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.model.VolumeAdaptionSetting.Companion.fromInteger
|
||||
|
@ -93,6 +94,8 @@ class FeedPreferences : EmbeddedRealmObject {
|
|||
}
|
||||
var queueId: Long = 0L
|
||||
|
||||
var autoAddNewToQueue: Boolean = false
|
||||
|
||||
@Ignore
|
||||
var autoDownloadFilter: FeedAutoDownloadFilter? = null
|
||||
get() = field ?: FeedAutoDownloadFilter(autoDLInclude, autoDLExclude, autoDLMinDuration, markExcludedPlayed)
|
||||
|
@ -121,10 +124,10 @@ class FeedPreferences : EmbeddedRealmObject {
|
|||
}
|
||||
var autoDLPolicyCode: Int = 0
|
||||
|
||||
enum class AutoDLPolicy(val code: Int) {
|
||||
ONLY_NEW(0),
|
||||
NEWER(1),
|
||||
OLDER(2);
|
||||
enum class AutoDLPolicy(val code: Int, val resId: Int) {
|
||||
ONLY_NEW(0, R.string.feed_auto_download_new),
|
||||
NEWER(1, R.string.feed_auto_download_newer),
|
||||
OLDER(2, R.string.feed_auto_download_older);
|
||||
|
||||
companion object {
|
||||
fun fromCode(code: Int): AutoDLPolicy {
|
||||
|
@ -190,5 +193,6 @@ class FeedPreferences : EmbeddedRealmObject {
|
|||
const val TAG_SEPARATOR: String = "\u001e"
|
||||
|
||||
val FeedAutoDeleteOptions = AutoDeleteAction.values().map { it.tag }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package ac.mdiq.podcini.storage.model
|
||||
|
||||
enum class VolumeAdaptionSetting(private val value: Int, @JvmField val adaptionFactor: Float) {
|
||||
OFF(0, 1.0f),
|
||||
LIGHT_REDUCTION(1, 0.5f),
|
||||
HEAVY_REDUCTION(2, 0.2f),
|
||||
LIGHT_BOOST(3, 1.5f),
|
||||
MEDIUM_BOOST(4, 2f),
|
||||
HEAVY_BOOST(5, 2.5f);
|
||||
import ac.mdiq.podcini.R
|
||||
|
||||
enum class VolumeAdaptionSetting(private val value: Int, @JvmField val adaptionFactor: Float, val resId: Int) {
|
||||
OFF(0, 1.0f, R.string.feed_volume_reduction_off),
|
||||
LIGHT_REDUCTION(1, 0.5f, R.string.feed_volume_reduction_light),
|
||||
HEAVY_REDUCTION(2, 0.2f, R.string.feed_volume_reduction_heavy),
|
||||
LIGHT_BOOST(3, 1.5f, R.string.feed_volume_boost_light),
|
||||
MEDIUM_BOOST(4, 2f, R.string.feed_volume_boost_medium),
|
||||
HEAVY_BOOST(5, 2.5f, R.string.feed_volume_boost_heavy);
|
||||
|
||||
fun toInteger(): Int {
|
||||
return value
|
||||
|
|
|
@ -215,11 +215,11 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
}
|
||||
|
||||
@JvmField
|
||||
val swipeActions: List<SwipeAction> = Collections.unmodifiableList(
|
||||
listOf(NoActionSwipeAction(), AddToQueueSwipeAction(), StartDownloadSwipeAction(), MarkFavoriteSwipeAction(),
|
||||
TogglePlaybackStateSwipeAction(), RemoveFromQueueSwipeAction(),
|
||||
DeleteSwipeAction(), RemoveFromHistorySwipeAction())
|
||||
)
|
||||
val swipeActions: List<SwipeAction> = listOf(
|
||||
NoActionSwipeAction(), AddToQueueSwipeAction(),
|
||||
StartDownloadSwipeAction(), MarkFavoriteSwipeAction(),
|
||||
TogglePlaybackStateSwipeAction(), RemoveFromQueueSwipeAction(),
|
||||
DeleteSwipeAction(), RemoveFromHistorySwipeAction())
|
||||
|
||||
private fun getPrefs(tag: String, defaultActions: String): Actions {
|
||||
val prefsString = prefs!!.getString(KEY_PREFIX_SWIPEACTIONS + tag, defaultActions)
|
||||
|
|
|
@ -113,13 +113,13 @@ class PreferenceActivity : AppCompatActivity(), SearchPreferenceResultListener {
|
|||
|
||||
override fun onSearchResultClicked(result: SearchPreferenceResult) {
|
||||
when (val screen = result.resourceFile) {
|
||||
R.xml.feed_settings -> {
|
||||
val builder = MaterialAlertDialogBuilder(this)
|
||||
builder.setTitle(R.string.feed_settings_label)
|
||||
builder.setMessage(R.string.pref_feed_settings_dialog_msg)
|
||||
builder.setPositiveButton(android.R.string.ok, null)
|
||||
builder.show()
|
||||
}
|
||||
// R.xml.feed_settings -> {
|
||||
// val builder = MaterialAlertDialogBuilder(this)
|
||||
// builder.setTitle(R.string.feed_settings_label)
|
||||
// builder.setMessage(R.string.pref_feed_settings_dialog_msg)
|
||||
// builder.setPositiveButton(android.R.string.ok, null)
|
||||
// builder.show()
|
||||
// }
|
||||
R.xml.preferences_notifications -> openScreen(screen)
|
||||
else -> {
|
||||
val fragment = openScreen(result.resourceFile)
|
||||
|
@ -197,9 +197,9 @@ class PreferenceActivity : AppCompatActivity(), SearchPreferenceResultListener {
|
|||
R.xml.preferences_notifications -> {
|
||||
return R.string.notification_pref_fragment
|
||||
}
|
||||
R.xml.feed_settings -> {
|
||||
return R.string.feed_settings_label
|
||||
}
|
||||
// R.xml.feed_settings -> {
|
||||
// return R.string.feed_settings_label
|
||||
// }
|
||||
R.xml.preferences_swipe -> {
|
||||
return R.string.swipeactions_label
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ object SkipPreferenceDialog {
|
|||
val choices = arrayOfNulls<String>(values.size)
|
||||
for (i in values.indices) {
|
||||
if (skipSecs == values[i]) checked = i
|
||||
|
||||
choices[i] = String.format(Locale.getDefault(), "%d %s", values[i], context.getString(R.string.time_seconds))
|
||||
}
|
||||
|
||||
|
@ -31,15 +30,12 @@ object SkipPreferenceDialog {
|
|||
builder.setTitle(if (direction == SkipDirection.SKIP_FORWARD) R.string.pref_fast_forward else R.string.pref_rewind)
|
||||
builder.setSingleChoiceItems(choices, checked) { dialog: DialogInterface, _: Int ->
|
||||
val choice = (dialog as AlertDialog).listView.checkedItemPosition
|
||||
if (choice < 0 || choice >= values.size) {
|
||||
System.err.printf("Choice in showSkipPreference is out of bounds %d", choice)
|
||||
} else {
|
||||
if (choice < 0 || choice >= values.size) System.err.printf("Choice in showSkipPreference is out of bounds %d", choice)
|
||||
else {
|
||||
val seconds = values[choice]
|
||||
if (direction == SkipDirection.SKIP_FORWARD) fastForwardSecs = seconds
|
||||
else rewindSecs = seconds
|
||||
|
||||
if (textView != null) textView.text = NumberFormat.getInstance().format(seconds.toLong())
|
||||
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class TagSettingsDialog : DialogFragment() {
|
|||
private var _binding: EditTagsDialogBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var feedList: List<Feed> = mutableListOf()
|
||||
private var feedList: MutableList<Feed> = mutableListOf()
|
||||
|
||||
private lateinit var displayedTags: MutableList<String>
|
||||
private lateinit var adapter: SimpleChipAdapter
|
||||
|
@ -100,9 +100,10 @@ class TagSettingsDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
@OptIn(UnstableApi::class) private fun updatePreferencesTags(commonTags: Set<String>) {
|
||||
for (f in feedList) {
|
||||
for (i in 0..feedList.size-1) {
|
||||
val f = feedList[i]
|
||||
Logd(TAG, "${f.title} $displayedTags")
|
||||
upsertBlk(f) {
|
||||
feedList[i] = upsertBlk(f) {
|
||||
if (it.preferences != null) {
|
||||
it.preferences!!.tags.removeAll(commonTags)
|
||||
it.preferences!!.tags.addAll(displayedTags)
|
||||
|
@ -112,7 +113,7 @@ class TagSettingsDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
private fun setFeedList(feedLst_: List<Feed>) {
|
||||
feedList = feedLst_
|
||||
feedList = feedLst_.toMutableList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -70,8 +70,6 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
|
|||
private var datasetStats: DatasetStats? = null
|
||||
private lateinit var navAdapter: NavListAdapter
|
||||
|
||||
// private var openFolders: MutableSet<String> = HashSet()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
_binding = NavListBinding.inflate(inflater)
|
||||
|
@ -92,11 +90,6 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
|
|||
insets
|
||||
}
|
||||
|
||||
// val preferences: SharedPreferences = requireContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
// TODO: what is this?
|
||||
// openFolders = HashSet(prefs!!.getStringSet(PREF_OPEN_FOLDERS, HashSet())!!) // Must not modify
|
||||
|
||||
// loadData()
|
||||
val navList = binding.navRecycler
|
||||
navAdapter = NavListAdapter()
|
||||
navAdapter.setHasStableIds(true)
|
||||
|
@ -197,7 +190,7 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
|
|||
}
|
||||
}
|
||||
fun getFragmentTags(): List<String?> {
|
||||
return Collections.unmodifiableList(fragmentTags)
|
||||
return fragmentTags
|
||||
}
|
||||
override fun getItemCount(): Int {
|
||||
return subscriptionOffset
|
||||
|
@ -359,7 +352,6 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
|
|||
|
||||
@VisibleForTesting
|
||||
const val PREF_LAST_FRAGMENT_TAG: String = "prefLastFragmentTag"
|
||||
// private const val PREF_OPEN_FOLDERS = "prefOpenFolders"
|
||||
const val VIEW_TYPE_NAV: Int = 0
|
||||
const val VIEW_TYPE_SECTION_DIVIDER: Int = 1
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ import java.util.*
|
|||
val pos = queueItems.size
|
||||
queueItems.addAll(event.episodes)
|
||||
adapter?.notifyItemRangeInserted(pos, queueItems.size)
|
||||
adapter?.notifyItemRangeChanged(pos, event.episodes.size);
|
||||
adapter?.notifyItemRangeChanged(pos, event.episodes.size)
|
||||
}
|
||||
}
|
||||
FlowEvent.QueueEvent.Action.SET_QUEUE, FlowEvent.QueueEvent.Action.SORTED -> {
|
||||
|
@ -312,7 +312,7 @@ import java.util.*
|
|||
holder?.unbind()
|
||||
queueItems.removeAt(pos)
|
||||
adapter?.notifyItemRemoved(pos)
|
||||
adapter?.notifyItemRangeChanged(pos, adapter!!.getItemCount()-pos);
|
||||
adapter?.notifyItemRangeChanged(pos, adapter!!.itemCount -pos)
|
||||
} else {
|
||||
Log.e(TAG, "Trying to remove item non-existent from queue ${e.id} ${e.title}")
|
||||
continue
|
||||
|
@ -494,19 +494,16 @@ import java.util.*
|
|||
fun RenameQueueDialog(showDialog: Boolean, onDismiss: () -> Unit) {
|
||||
if (showDialog) {
|
||||
Dialog(onDismissRequest = onDismiss) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
Card(modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
Column(modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
var newName by remember { mutableStateOf(curQueue.name) }
|
||||
TextField(
|
||||
value = newName,
|
||||
TextField(value = newName,
|
||||
onValueChange = { newName = it },
|
||||
label = { Text("Rename (Unique name only)") }
|
||||
)
|
||||
|
@ -537,19 +534,16 @@ import java.util.*
|
|||
fun AddQueueDialog(showDialog: Boolean, onDismiss: () -> Unit) {
|
||||
if (showDialog) {
|
||||
Dialog(onDismissRequest = onDismiss) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
Card(modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
Column(modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
var newName by remember { mutableStateOf("") }
|
||||
TextField(
|
||||
value = newName,
|
||||
TextField(value = newName,
|
||||
onValueChange = { newName = it },
|
||||
label = { Text("Add queue (Unique name only)") }
|
||||
)
|
||||
|
|
|
@ -27,6 +27,7 @@ import ac.mdiq.podcini.ui.fragment.FeedSettingsFragment.Companion.queueSettingOp
|
|||
import ac.mdiq.podcini.ui.utils.CoverLoader
|
||||
import ac.mdiq.podcini.ui.utils.EmptyViewHandler
|
||||
import ac.mdiq.podcini.ui.utils.LiftOnScrollListener
|
||||
import ac.mdiq.podcini.util.DateFormatter.formatAbbrev
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.event.EventFlow
|
||||
import ac.mdiq.podcini.util.event.FlowEvent
|
||||
|
@ -425,8 +426,8 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
for (f in feedList_) {
|
||||
val d = realm.query(Episode::class).query(queryString, f.id).first().find()?.pubDate ?: 0L
|
||||
counterMap[f.id] = d
|
||||
val dateFormat = SimpleDateFormat("yy-MM-dd HH:mm", Locale.getDefault())
|
||||
f.sortInfo = "Updated: " + dateFormat.format(Date(d))
|
||||
// val dateFormat = SimpleDateFormat("yy-MM-dd HH:mm", Locale.getDefault())
|
||||
f.sortInfo = "Updated: " + formatAbbrev(requireContext(), Date(d))
|
||||
}
|
||||
comparator(counterMap, dir)
|
||||
}
|
||||
|
@ -434,11 +435,10 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
val queryString = "feedId == $0 SORT(media.downloadTime DESC)"
|
||||
val counterMap: MutableMap<Long, Long> = mutableMapOf()
|
||||
for (f in feedList_) {
|
||||
val d =
|
||||
realm.query(Episode::class).query(queryString, f.id).first().find()?.media?.downloadTime ?: 0L
|
||||
val d = realm.query(Episode::class).query(queryString, f.id).first().find()?.media?.downloadTime ?: 0L
|
||||
counterMap[f.id] = d
|
||||
val dateFormat = SimpleDateFormat("yy-MM-dd HH:mm", Locale.getDefault())
|
||||
f.sortInfo = "Downloaded: " + dateFormat.format(Date(d))
|
||||
// val dateFormat = SimpleDateFormat("yy-MM-dd HH:mm", Locale.getDefault())
|
||||
f.sortInfo = "Downloaded: " + formatAbbrev(requireContext(), Date(d))
|
||||
}
|
||||
comparator(counterMap, dir)
|
||||
}
|
||||
|
@ -449,8 +449,8 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
for (f in feedList_) {
|
||||
val d = realm.query(Episode::class).query(queryString, f.id).first().find()?.pubDate ?: 0L
|
||||
counterMap[f.id] = d
|
||||
val dateFormat = SimpleDateFormat("yy-MM-dd HH:mm", Locale.getDefault())
|
||||
f.sortInfo = "Unplayed: " + dateFormat.format(Date(d))
|
||||
// val dateFormat = SimpleDateFormat("yy-MM-dd HH:mm", Locale.getDefault())
|
||||
f.sortInfo = "Unplayed: " + formatAbbrev(requireContext(), Date(d))
|
||||
}
|
||||
comparator(counterMap, dir)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ object DateFormatter {
|
|||
@JvmStatic
|
||||
fun formatRfc822Date(date: Date?): String {
|
||||
val format = SimpleDateFormat("dd MMM yy HH:mm:ss Z", Locale.US)
|
||||
return format.format(date)
|
||||
return format.format(date?: Date(0))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -25,16 +25,40 @@ object DateFormatter {
|
|||
cal.time = date
|
||||
val withinLastYear = now[Calendar.YEAR] == cal[Calendar.YEAR]
|
||||
var format = DateUtils.FORMAT_ABBREV_ALL
|
||||
if (withinLastYear) {
|
||||
format = format or DateUtils.FORMAT_NO_YEAR
|
||||
}
|
||||
if (withinLastYear) format = format or DateUtils.FORMAT_NO_YEAR
|
||||
|
||||
return DateUtils.formatDateTime(context, date.time, format)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun formatForAccessibility(date: Date?): String {
|
||||
if (date == null) return ""
|
||||
|
||||
return DateFormat.getDateInstance(DateFormat.LONG).format(date)
|
||||
}
|
||||
|
||||
fun formatDateTimeFlex(date: Date): String {
|
||||
val now = Date()
|
||||
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault())
|
||||
return when {
|
||||
isSameDay(date, now) -> SimpleDateFormat("HH:mm", Locale.getDefault()).format(date)
|
||||
isSameYear(date, now) -> SimpleDateFormat("MM-dd HH:mm", Locale.getDefault()).format(date)
|
||||
else -> formatter.format(date)
|
||||
}
|
||||
}
|
||||
|
||||
fun isSameDay(date1: Date, date2: Date): Boolean {
|
||||
val cal1 = Calendar.getInstance()
|
||||
cal1.time = date1
|
||||
val cal2 = Calendar.getInstance()
|
||||
cal2.time = date2
|
||||
return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)
|
||||
}
|
||||
|
||||
fun isSameYear(date1: Date, date2: Date): Boolean {
|
||||
val cal1 = Calendar.getInstance()
|
||||
cal1.time = date1
|
||||
val cal2 = Calendar.getInstance()
|
||||
cal2.time = date2
|
||||
return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,22 +23,9 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/compose_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/compose_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/settings_fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
android:layout_height="wrap_content" />
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,47 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string-array name="spnAutoDLPolicyItems">
|
||||
<item>@string/feed_auto_download_new</item>
|
||||
<item>@string/feed_auto_download_newer</item>
|
||||
<item>@string/feed_auto_download_older</item>
|
||||
</string-array>
|
||||
<string-array name="spnAutoDLPolicyValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="spnAutoDeleteItems">
|
||||
<item>@string/global_default</item>
|
||||
<item>@string/feed_auto_download_always</item>
|
||||
<item>@string/feed_auto_download_never</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="spnAutoDeleteValues">
|
||||
<item>global</item>
|
||||
<item>always</item>
|
||||
<item>never</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="spnVolumeAdaptationItems">
|
||||
<item>@string/feed_volume_reduction_heavy</item>
|
||||
<item>@string/feed_volume_reduction_light</item>
|
||||
<item>@string/feed_volume_reduction_off</item>
|
||||
<item>@string/feed_volume_boost_light</item>
|
||||
<item>@string/feed_volume_boost_medium</item>
|
||||
<item>@string/feed_volume_boost_heavy</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="spnVolumeAdaptationValues">
|
||||
<item>heavy</item>
|
||||
<item>light</item>
|
||||
<item>off</item>
|
||||
<item>light_boost</item>
|
||||
<item>medium_boost</item>
|
||||
<item>heavy_boost</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="feed_refresh_interval_entries">
|
||||
<item>@string/feed_refresh_never</item>
|
||||
<item>@string/feed_every_hour</item>
|
||||
|
@ -92,7 +50,6 @@
|
|||
<item>500</item>
|
||||
<item>@string/pref_episode_cache_unlimited</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="episode_cache_size_values">
|
||||
<item>5</item>
|
||||
<item>10</item>
|
||||
|
@ -103,27 +60,6 @@
|
|||
<item>-1</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="feed_episode_cache_size_entries">
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>10</item>
|
||||
<item>15</item>
|
||||
<item>20</item>
|
||||
<item>@string/pref_episode_cache_unlimited</item>
|
||||
</string-array>
|
||||
<string-array name="feed_episode_cache_size_values">
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>10</item>
|
||||
<item>15</item>
|
||||
<item>20</item>
|
||||
<item>-1</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="mobile_update_entries">
|
||||
<item>@string/pref_mobileUpdate_refresh</item>
|
||||
<item>@string/pref_mobileUpdate_episode_download</item>
|
||||
|
|
|
@ -810,6 +810,8 @@
|
|||
<string name="mark_excluded_episodes_played">Mark excluded episodes played</string>
|
||||
<string name="keep_updated">Keep updated</string>
|
||||
<string name="keep_updated_summary">Include this podcast when (auto-)refreshing all podcasts</string>
|
||||
<string name="audo_add_new_queue">Auto add new to queue</string>
|
||||
<string name="audo_add_new_queue_summary">Automatically add new episodes in this podcast to the designated queue when (auto-)refreshing</string>
|
||||
<string name="auto_download_disabled_globally">Auto download is disabled in the main Podcini settings</string>
|
||||
<string name="statistics_time_played">Time played:</string>
|
||||
<string name="statistics_total_duration">Total duration (estimate):</string>
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:key="feedSettingsScreen">
|
||||
|
||||
<!-- <SwitchPreferenceCompat-->
|
||||
<!-- android:icon="@drawable/ic_refresh"-->
|
||||
<!-- android:key="keepUpdated"-->
|
||||
<!-- android:summary="@string/keep_updated_summary"-->
|
||||
<!-- android:title="@string/keep_updated" />-->
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_key"
|
||||
android:key="authentication"
|
||||
android:summary="@string/authentication_descr"
|
||||
android:title="@string/authentication_label" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_tag"
|
||||
android:key="tags"
|
||||
android:summary="@string/feed_tags_summary"
|
||||
android:title="@string/feed_tags_label" />
|
||||
|
||||
<!-- <Preference-->
|
||||
<!-- android:icon="@drawable/ic_playlist_play"-->
|
||||
<!-- android:key="associatedQueue"-->
|
||||
<!-- android:summary="@string/pref_feed_associated_queue_sum"-->
|
||||
<!-- android:title="@string/pref_feed_associated_queue" />-->
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_playback_speed"
|
||||
android:key="feedPlaybackSpeed"
|
||||
android:summary="@string/pref_feed_playback_speed_sum"
|
||||
android:title="@string/playback_speed" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_skip_24dp"
|
||||
android:key="feedAutoSkip"
|
||||
android:summary="@string/pref_feed_skip_sum"
|
||||
android:title="@string/pref_feed_skip" />
|
||||
|
||||
<!-- <ac.mdiq.podcini.preferences.MaterialListPreference-->
|
||||
<!-- android:entries="@array/spnAutoDeleteItems"-->
|
||||
<!-- android:entryValues="@array/spnAutoDeleteValues"-->
|
||||
<!-- android:icon="@drawable/ic_delete"-->
|
||||
<!-- android:key="autoDelete"-->
|
||||
<!-- android:summary="@string/global_default"-->
|
||||
<!-- android:title="@string/auto_delete_label" />-->
|
||||
|
||||
<ac.mdiq.podcini.preferences.MaterialListPreference
|
||||
android:defaultValue="off"
|
||||
android:entries="@array/spnVolumeAdaptationItems"
|
||||
android:entryValues="@array/spnVolumeAdaptationValues"
|
||||
android:icon="@drawable/ic_volume_adaption"
|
||||
android:key="volumeReduction"
|
||||
android:summary="@string/feed_volume_adaptation_summary"
|
||||
android:title="@string/feed_volume_adapdation" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="autoDownloadCategory"
|
||||
android:title="@string/auto_download_settings_label">
|
||||
<SwitchPreferenceCompat
|
||||
android:key="autoDownload"
|
||||
android:title="@string/auto_download_label" />
|
||||
<ac.mdiq.podcini.preferences.MaterialListPreference
|
||||
android:entries="@array/spnAutoDLPolicyItems"
|
||||
android:entryValues="@array/spnAutoDLPolicyValues"
|
||||
android:key="feedAutoDownloadPolicy"
|
||||
android:title="@string/feed_auto_download_policy" />
|
||||
<ac.mdiq.podcini.preferences.MaterialListPreference
|
||||
android:defaultValue="3"
|
||||
android:entries="@array/feed_episode_cache_size_entries"
|
||||
android:key="feedEpisodeCacheSize"
|
||||
android:title="@string/pref_episode_cache_title"
|
||||
android:summary="@string/pref_episode_cache_summary"
|
||||
android:entryValues="@array/feed_episode_cache_size_values"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:key="countingPlayed"
|
||||
android:summary="@string/pref_auto_download_counting_played_summary"
|
||||
android:title="@string/pref_auto_download_counting_played_title" />
|
||||
<Preference
|
||||
android:key="episodeInclusiveFilter"
|
||||
android:summary="@string/episode_filters_description"
|
||||
android:title="@string/episode_inclusive_filters_label" />
|
||||
<Preference
|
||||
android:key="episodeExclusiveFilter"
|
||||
android:summary="@string/episode_filters_description"
|
||||
android:title="@string/episode_exclusive_filters_label" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
|
@ -1,3 +1,11 @@
|
|||
# 6.3.5
|
||||
|
||||
* added more Log.d statements in hope for tracking down the mysterious random playing
|
||||
* FeedSettings view is all in Jetpack Compose, FeedSettingsPreferenceFragment removed
|
||||
* in FeedSettings, added "Audo add new to queue" (accissible when associated queue not set to "None")
|
||||
* when set, new episodes during refresh will be added to the associated queue, regardless of being downloaded
|
||||
* use adaptive date formats (stripped time) in Subscriptions view
|
||||
|
||||
# 6.3.4
|
||||
|
||||
* fixed mis-behavior of setting associated queue to Active in FeedSettings
|
||||
|
|
Loading…
Reference in New Issue