4.3.4 commit
This commit is contained in:
parent
c5bf432283
commit
cc4cdb281a
|
@ -149,8 +149,8 @@ android {
|
||||||
// Version code schema (not used):
|
// Version code schema (not used):
|
||||||
// "1.2.3-beta4" -> 1020304
|
// "1.2.3-beta4" -> 1020304
|
||||||
// "1.2.3" -> 1020395
|
// "1.2.3" -> 1020395
|
||||||
versionCode 3020114
|
versionCode 3020115
|
||||||
versionName "4.3.3"
|
versionName "4.3.4"
|
||||||
|
|
||||||
def commit = ""
|
def commit = ""
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -62,12 +62,12 @@ class HttpDownloaderTest {
|
||||||
|
|
||||||
private fun download(url: String?, title: String, expectedResult: Boolean, deleteExisting: Boolean = true,
|
private fun download(url: String?, title: String, expectedResult: Boolean, deleteExisting: Boolean = true,
|
||||||
username: String? = null, password: String? = null
|
username: String? = null, password: String? = null
|
||||||
): ac.mdiq.podcini.service.download.Downloader {
|
): Downloader {
|
||||||
val feedFile: FeedFile = setupFeedFile(url, title, deleteExisting)
|
val feedFile: FeedFile = setupFeedFile(url, title, deleteExisting)
|
||||||
val request = DownloadRequest(
|
val request = DownloadRequest(
|
||||||
feedFile.getFile_url()!!, url!!, title, 0, feedFile.getTypeAsInt(),
|
feedFile.getFile_url()!!, url!!, title, 0, feedFile.getTypeAsInt(),
|
||||||
username, password, null, false)
|
username, password, null, false)
|
||||||
val downloader: ac.mdiq.podcini.service.download.Downloader = HttpDownloader(request)
|
val downloader: Downloader = HttpDownloader(request)
|
||||||
downloader.call()
|
downloader.call()
|
||||||
val status = downloader.result
|
val status = downloader.result
|
||||||
Assert.assertNotNull(status)
|
Assert.assertNotNull(status)
|
||||||
|
@ -101,7 +101,7 @@ class HttpDownloaderTest {
|
||||||
fun testCancel() {
|
fun testCancel() {
|
||||||
val url = httpServer!!.baseUrl + "/delay/3"
|
val url = httpServer!!.baseUrl + "/delay/3"
|
||||||
val feedFile = setupFeedFile(url, "delay", true)
|
val feedFile = setupFeedFile(url, "delay", true)
|
||||||
val downloader: ac.mdiq.podcini.service.download.Downloader = HttpDownloader(DownloadRequest(
|
val downloader: Downloader = HttpDownloader(DownloadRequest(
|
||||||
feedFile.getFile_url()!!, url, "delay", 0,
|
feedFile.getFile_url()!!, url, "delay", 0,
|
||||||
feedFile.getTypeAsInt(), null, null, null, false))
|
feedFile.getTypeAsInt(), null, null, null, false))
|
||||||
val t: Thread = object : Thread() {
|
val t: Thread = object : Thread() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ac.mdiq.podcini.feed.parser.namespace
|
package ac.mdiq.podcini.feed.parser.namespace
|
||||||
|
|
||||||
|
import ac.mdiq.podcini.feed.parser.HandlerState
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import ac.mdiq.podcini.storage.model.feed.FeedFunding
|
import ac.mdiq.podcini.storage.model.feed.FeedFunding
|
||||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||||
|
@ -13,7 +14,7 @@ import ac.mdiq.podcini.feed.parser.util.SyndStringUtils.trimAllWhitespace
|
||||||
import org.xml.sax.Attributes
|
import org.xml.sax.Attributes
|
||||||
|
|
||||||
class Atom : Namespace() {
|
class Atom : Namespace() {
|
||||||
override fun handleElementStart(localName: String, state: ac.mdiq.podcini.feed.parser.HandlerState, attributes: Attributes): SyndElement {
|
override fun handleElementStart(localName: String, state: HandlerState, attributes: Attributes): SyndElement {
|
||||||
if (ENTRY == localName) {
|
if (ENTRY == localName) {
|
||||||
state.currentItem = FeedItem()
|
state.currentItem = FeedItem()
|
||||||
state.items.add(state.currentItem!!)
|
state.items.add(state.currentItem!!)
|
||||||
|
@ -88,7 +89,7 @@ class Atom : Namespace() {
|
||||||
return SyndElement(localName, this)
|
return SyndElement(localName, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleElementEnd(localName: String, state: ac.mdiq.podcini.feed.parser.HandlerState) {
|
override fun handleElementEnd(localName: String, state: HandlerState) {
|
||||||
if (ENTRY == localName) {
|
if (ENTRY == localName) {
|
||||||
if (state.currentItem != null &&
|
if (state.currentItem != null &&
|
||||||
state.tempObjects.containsKey(Itunes.DURATION)) {
|
state.tempObjects.containsKey(Itunes.DURATION)) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ac.mdiq.podcini.feed.parser.namespace
|
package ac.mdiq.podcini.feed.parser.namespace
|
||||||
|
|
||||||
|
import ac.mdiq.podcini.feed.parser.HandlerState
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import ac.mdiq.podcini.feed.parser.element.SyndElement
|
import ac.mdiq.podcini.feed.parser.element.SyndElement
|
||||||
|
@ -7,7 +8,7 @@ import ac.mdiq.podcini.feed.parser.util.DurationParser.inMillis
|
||||||
import org.xml.sax.Attributes
|
import org.xml.sax.Attributes
|
||||||
|
|
||||||
class Itunes : Namespace() {
|
class Itunes : Namespace() {
|
||||||
override fun handleElementStart(localName: String, state: ac.mdiq.podcini.feed.parser.HandlerState,
|
override fun handleElementStart(localName: String, state: HandlerState,
|
||||||
attributes: Attributes): SyndElement {
|
attributes: Attributes): SyndElement {
|
||||||
if (IMAGE == localName) {
|
if (IMAGE == localName) {
|
||||||
val url: String? = attributes.getValue(IMAGE_HREF)
|
val url: String? = attributes.getValue(IMAGE_HREF)
|
||||||
|
@ -25,7 +26,7 @@ class Itunes : Namespace() {
|
||||||
return SyndElement(localName, this)
|
return SyndElement(localName, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleElementEnd(localName: String, state: ac.mdiq.podcini.feed.parser.HandlerState) {
|
override fun handleElementEnd(localName: String, state: HandlerState) {
|
||||||
if (state.contentBuf == null) {
|
if (state.contentBuf == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ac.mdiq.podcini.feed.parser.namespace
|
package ac.mdiq.podcini.feed.parser.namespace
|
||||||
|
|
||||||
|
import ac.mdiq.podcini.feed.parser.HandlerState
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import ac.mdiq.podcini.storage.model.feed.Chapter
|
import ac.mdiq.podcini.storage.model.feed.Chapter
|
||||||
import ac.mdiq.podcini.feed.parser.element.SyndElement
|
import ac.mdiq.podcini.feed.parser.element.SyndElement
|
||||||
|
@ -7,7 +8,7 @@ import ac.mdiq.podcini.feed.parser.util.DateUtils.parseTimeString
|
||||||
import org.xml.sax.Attributes
|
import org.xml.sax.Attributes
|
||||||
|
|
||||||
class SimpleChapters : Namespace() {
|
class SimpleChapters : Namespace() {
|
||||||
override fun handleElementStart(localName: String, state: ac.mdiq.podcini.feed.parser.HandlerState, attributes: Attributes): SyndElement {
|
override fun handleElementStart(localName: String, state: HandlerState, attributes: Attributes): SyndElement {
|
||||||
val currentItem = state.currentItem
|
val currentItem = state.currentItem
|
||||||
if (currentItem != null) {
|
if (currentItem != null) {
|
||||||
if (localName == CHAPTERS) {
|
if (localName == CHAPTERS) {
|
||||||
|
@ -29,7 +30,7 @@ class SimpleChapters : Namespace() {
|
||||||
return SyndElement(localName, this)
|
return SyndElement(localName, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleElementEnd(localName: String, state: ac.mdiq.podcini.feed.parser.HandlerState) {
|
override fun handleElementEnd(localName: String, state: HandlerState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -267,17 +267,20 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
|
||||||
fun playPause() {
|
fun playPause() {
|
||||||
if (media == null) return
|
if (media == null) return
|
||||||
if (playbackService == null) {
|
if (playbackService == null) {
|
||||||
PlaybackServiceStarter(activity, media!!).start()
|
// PlaybackServiceStarter(activity, media!!).start()
|
||||||
|
PlaybackServiceStarter(activity, media!!)
|
||||||
|
.callEvenIfRunning(true)
|
||||||
|
.start()
|
||||||
Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!")
|
Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!")
|
||||||
return
|
// return
|
||||||
}
|
}
|
||||||
when (status) {
|
when (status) {
|
||||||
PlayerStatus.PLAYING -> playbackService!!.pause(true, false)
|
PlayerStatus.PLAYING -> playbackService?.pause(true, false)
|
||||||
PlayerStatus.PAUSED, PlayerStatus.PREPARED -> playbackService!!.resume()
|
PlayerStatus.PAUSED, PlayerStatus.PREPARED -> playbackService?.resume()
|
||||||
PlayerStatus.PREPARING -> playbackService!!.isStartWhenPrepared = !playbackService!!.isStartWhenPrepared
|
PlayerStatus.PREPARING -> playbackService!!.isStartWhenPrepared = !playbackService!!.isStartWhenPrepared
|
||||||
PlayerStatus.INITIALIZED -> {
|
PlayerStatus.INITIALIZED -> {
|
||||||
playbackService!!.isStartWhenPrepared = true
|
if (playbackService != null) playbackService!!.isStartWhenPrepared = true
|
||||||
playbackService!!.prepare()
|
playbackService?.prepare()
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
PlaybackServiceStarter(activity, media!!)
|
PlaybackServiceStarter(activity, media!!)
|
||||||
|
|
|
@ -1,29 +1,28 @@
|
||||||
package ac.mdiq.podcini.preferences
|
package ac.mdiq.podcini.preferences
|
||||||
|
|
||||||
|
import ac.mdiq.podcini.R
|
||||||
|
import ac.mdiq.podcini.databinding.ThemePreferenceBinding
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceViewHolder
|
import androidx.preference.PreferenceViewHolder
|
||||||
import com.google.android.material.elevation.SurfaceColors
|
import com.google.android.material.elevation.SurfaceColors
|
||||||
import ac.mdiq.podcini.R
|
|
||||||
import ac.mdiq.podcini.databinding.ThemePreferenceBinding
|
|
||||||
|
|
||||||
class ThemePreference : Preference {
|
class ThemePreference : Preference {
|
||||||
var viewBinding: ThemePreferenceBinding? = null
|
var binding: ThemePreferenceBinding? = null
|
||||||
|
|
||||||
constructor(context: Context) : super(context!!) {
|
constructor(context: Context) : super(context) {
|
||||||
layoutResource = R.layout.theme_preference
|
layoutResource = R.layout.theme_preference
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet?) : super(context!!, attrs) {
|
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
|
||||||
layoutResource = R.layout.theme_preference
|
layoutResource = R.layout.theme_preference
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||||
super.onBindViewHolder(holder)
|
super.onBindViewHolder(holder)
|
||||||
viewBinding = ThemePreferenceBinding.bind(holder.itemView)
|
binding = ThemePreferenceBinding.bind(holder.itemView)
|
||||||
updateUi()
|
updateUi()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +32,7 @@ class ThemePreference : Preference {
|
||||||
val surfaceColorActive = SurfaceColors.getColorForElevation(context, 32 * density)
|
val surfaceColorActive = SurfaceColors.getColorForElevation(context, 32 * density)
|
||||||
val activeTheme = UserPreferences.theme
|
val activeTheme = UserPreferences.theme
|
||||||
card.setCardBackgroundColor(if (theme == activeTheme) surfaceColorActive else surfaceColor)
|
card.setCardBackgroundColor(if (theme == activeTheme) surfaceColorActive else surfaceColor)
|
||||||
card.setOnClickListener { v: View? ->
|
card.setOnClickListener {
|
||||||
UserPreferences.theme = theme
|
UserPreferences.theme = theme
|
||||||
if (onPreferenceChangeListener != null) {
|
if (onPreferenceChangeListener != null) {
|
||||||
onPreferenceChangeListener!!.onPreferenceChange(this, UserPreferences.theme)
|
onPreferenceChangeListener!!.onPreferenceChange(this, UserPreferences.theme)
|
||||||
|
@ -43,8 +42,8 @@ class ThemePreference : Preference {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateUi() {
|
fun updateUi() {
|
||||||
updateThemeCard(viewBinding!!.themeSystemCard, UserPreferences.ThemePreference.SYSTEM)
|
updateThemeCard(binding!!.themeSystemCard, UserPreferences.ThemePreference.SYSTEM)
|
||||||
updateThemeCard(viewBinding!!.themeLightCard, UserPreferences.ThemePreference.LIGHT)
|
updateThemeCard(binding!!.themeLightCard, UserPreferences.ThemePreference.LIGHT)
|
||||||
updateThemeCard(viewBinding!!.themeDarkCard, UserPreferences.ThemePreference.DARK)
|
updateThemeCard(binding!!.themeDarkCard, UserPreferences.ThemePreference.DARK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ac.mdiq.podcini.service.download.handler
|
package ac.mdiq.podcini.service.download.handler
|
||||||
|
|
||||||
|
import ac.mdiq.podcini.feed.parser.FeedHandlerResult
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import ac.mdiq.podcini.util.InvalidFeedException
|
import ac.mdiq.podcini.util.InvalidFeedException
|
||||||
import ac.mdiq.podcini.storage.model.download.DownloadError
|
import ac.mdiq.podcini.storage.model.download.DownloadError
|
||||||
|
@ -16,7 +17,7 @@ import java.util.*
|
||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.Callable
|
||||||
import javax.xml.parsers.ParserConfigurationException
|
import javax.xml.parsers.ParserConfigurationException
|
||||||
|
|
||||||
class FeedParserTask(private val request: DownloadRequest) : Callable<ac.mdiq.podcini.feed.parser.FeedHandlerResult?> {
|
class FeedParserTask(private val request: DownloadRequest) : Callable<FeedHandlerResult?> {
|
||||||
var downloadStatus: DownloadResult
|
var downloadStatus: DownloadResult
|
||||||
private set
|
private set
|
||||||
var isSuccessful: Boolean = true
|
var isSuccessful: Boolean = true
|
||||||
|
@ -29,7 +30,7 @@ class FeedParserTask(private val request: DownloadRequest) : Callable<ac.mdiq.po
|
||||||
"Unknown error: Status not set")
|
"Unknown error: Status not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun call(): ac.mdiq.podcini.feed.parser.FeedHandlerResult? {
|
override fun call(): FeedHandlerResult? {
|
||||||
val feed = Feed(request.source, request.lastModified)
|
val feed = Feed(request.source, request.lastModified)
|
||||||
feed.file_url = request.destination
|
feed.file_url = request.destination
|
||||||
feed.id = request.feedfileId
|
feed.id = request.feedfileId
|
||||||
|
@ -42,7 +43,7 @@ class FeedParserTask(private val request: DownloadRequest) : Callable<ac.mdiq.po
|
||||||
var reasonDetailed: String? = null
|
var reasonDetailed: String? = null
|
||||||
val feedHandler = ac.mdiq.podcini.feed.parser.FeedHandler()
|
val feedHandler = ac.mdiq.podcini.feed.parser.FeedHandler()
|
||||||
|
|
||||||
var result: ac.mdiq.podcini.feed.parser.FeedHandlerResult? = null
|
var result: FeedHandlerResult? = null
|
||||||
try {
|
try {
|
||||||
result = feedHandler.parseFeed(feed)
|
result = feedHandler.parseFeed(feed)
|
||||||
Log.d(TAG, feed.title + " parsed")
|
Log.d(TAG, feed.title + " parsed")
|
||||||
|
|
|
@ -25,6 +25,7 @@ import ac.mdiq.podcini.playback.base.PlaybackServiceMediaPlayer
|
||||||
import ac.mdiq.podcini.playback.base.PlayerStatus
|
import ac.mdiq.podcini.playback.base.PlayerStatus
|
||||||
import ac.mdiq.podcini.playback.base.RewindAfterPauseUtils
|
import ac.mdiq.podcini.playback.base.RewindAfterPauseUtils
|
||||||
import ac.mdiq.podcini.preferences.UserPreferences
|
import ac.mdiq.podcini.preferences.UserPreferences
|
||||||
|
import ac.mdiq.podcini.util.event.PlayerErrorEvent
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
@ -197,11 +198,11 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
setPlayerStatus(PlayerStatus.ERROR, null)
|
setPlayerStatus(PlayerStatus.ERROR, null)
|
||||||
EventBus.getDefault().postSticky(ac.mdiq.podcini.util.event.PlayerErrorEvent(e.localizedMessage ?: ""))
|
EventBus.getDefault().postSticky(PlayerErrorEvent(e.localizedMessage ?: ""))
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
setPlayerStatus(PlayerStatus.ERROR, null)
|
setPlayerStatus(PlayerStatus.ERROR, null)
|
||||||
EventBus.getDefault().postSticky(ac.mdiq.podcini.util.event.PlayerErrorEvent(e.localizedMessage ?: ""))
|
EventBus.getDefault().postSticky(PlayerErrorEvent(e.localizedMessage ?: ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -727,7 +728,7 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
mp.setOnErrorListener(Consumer { message: String ->
|
mp.setOnErrorListener(Consumer { message: String ->
|
||||||
EventBus.getDefault().postSticky(ac.mdiq.podcini.util.event.PlayerErrorEvent(message))
|
EventBus.getDefault().postSticky(PlayerErrorEvent(message))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,8 @@ import ac.mdiq.podcini.util.FeedUtil.shouldAutoDeleteItemsOnThatFeed
|
||||||
import ac.mdiq.podcini.util.IntentUtils.sendLocalBroadcast
|
import ac.mdiq.podcini.util.IntentUtils.sendLocalBroadcast
|
||||||
import ac.mdiq.podcini.util.NetworkUtils.isStreamingAllowed
|
import ac.mdiq.podcini.util.NetworkUtils.isStreamingAllowed
|
||||||
import ac.mdiq.podcini.util.event.MessageEvent
|
import ac.mdiq.podcini.util.event.MessageEvent
|
||||||
|
import ac.mdiq.podcini.util.event.PlayerErrorEvent
|
||||||
|
import ac.mdiq.podcini.util.event.settings.SkipIntroEndingChangedEvent
|
||||||
import ac.mdiq.podcini.util.event.settings.SpeedPresetChangedEvent
|
import ac.mdiq.podcini.util.event.settings.SpeedPresetChangedEvent
|
||||||
import ac.mdiq.podcini.util.event.settings.VolumeAdaptionChangedEvent
|
import ac.mdiq.podcini.util.event.settings.VolumeAdaptionChangedEvent
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
@ -924,7 +926,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun playerError(event: ac.mdiq.podcini.util.event.PlayerErrorEvent?) {
|
fun playerError(event: PlayerErrorEvent?) {
|
||||||
if (mediaPlayer?.playerStatus == PlayerStatus.PLAYING) {
|
if (mediaPlayer?.playerStatus == PlayerStatus.PLAYING) {
|
||||||
mediaPlayer!!.pause(true, false)
|
mediaPlayer!!.pause(true, false)
|
||||||
}
|
}
|
||||||
|
@ -1548,7 +1550,7 @@ class PlaybackService : MediaBrowserServiceCompat() {
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun skipIntroEndingPresetChanged(event: ac.mdiq.podcini.util.event.settings.SkipIntroEndingChangedEvent) {
|
fun skipIntroEndingPresetChanged(event: SkipIntroEndingChangedEvent) {
|
||||||
if (playable is FeedMedia) {
|
if (playable is FeedMedia) {
|
||||||
if ((playable as FeedMedia).item?.feed?.id == event.feedId) {
|
if ((playable as FeedMedia).item?.feed?.id == event.feedId) {
|
||||||
if (event.skipEnding != 0) {
|
if (event.skipEnding != 0) {
|
||||||
|
|
|
@ -310,7 +310,7 @@ object DBReader {
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getEpisodes(offset: Int, limit: Int, filter: FeedItemFilter?, sortOrder: SortOrder?): List<FeedItem> {
|
fun getEpisodes(offset: Int, limit: Int, filter: FeedItemFilter?, sortOrder: SortOrder?): List<FeedItem> {
|
||||||
Log.d(TAG, "getRecentlyPublishedEpisodes() called with: offset=$offset, limit=$limit")
|
Log.d(TAG, "getEpisodes called with: offset=$offset, limit=$limit")
|
||||||
val adapter = getInstance()
|
val adapter = getInstance()
|
||||||
adapter.open()
|
adapter.open()
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -8,6 +8,8 @@ object FeedItemSortQuery {
|
||||||
fun generateFrom(sortOrder: SortOrder?): String {
|
fun generateFrom(sortOrder: SortOrder?): String {
|
||||||
var sortQuery = ""
|
var sortQuery = ""
|
||||||
sortQuery = when (sortOrder) {
|
sortQuery = when (sortOrder) {
|
||||||
|
SortOrder.FEED_TITLE_A_Z -> PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_FEED + " " + "ASC"
|
||||||
|
SortOrder.FEED_TITLE_Z_A -> PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_FEED + " " + "DESC"
|
||||||
SortOrder.EPISODE_TITLE_A_Z -> PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_TITLE + " " + "ASC"
|
SortOrder.EPISODE_TITLE_A_Z -> PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_TITLE + " " + "ASC"
|
||||||
SortOrder.EPISODE_TITLE_Z_A -> PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_TITLE + " " + "DESC"
|
SortOrder.EPISODE_TITLE_Z_A -> PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_TITLE + " " + "DESC"
|
||||||
SortOrder.DATE_OLD_NEW -> PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_PUBDATE + " " + "ASC"
|
SortOrder.DATE_OLD_NEW -> PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_PUBDATE + " " + "ASC"
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ac.mdiq.podcini.storage.model.feed
|
||||||
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import ac.mdiq.podcini.storage.model.feed.FeedFunding.Companion.extractPaymentLinks
|
import ac.mdiq.podcini.storage.model.feed.FeedFunding.Companion.extractPaymentLinks
|
||||||
|
import android.util.Log
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
@ -107,10 +108,15 @@ class Feed : FeedFile {
|
||||||
*/
|
*/
|
||||||
var sortOrder: SortOrder? = null
|
var sortOrder: SortOrder? = null
|
||||||
set(sortOrder) {
|
set(sortOrder) {
|
||||||
require(!(sortOrder != null && sortOrder.scope != SortOrder.Scope.INTRA_FEED)) {
|
if (!(sortOrder != null && sortOrder.scope != SortOrder.Scope.INTRA_FEED)) {
|
||||||
("The specified sortOrder " + sortOrder
|
Log.w("Feed sortOrder", "The specified sortOrder " + sortOrder
|
||||||
+ " is invalid. Only those with INTRA_FEED scope are allowed.")
|
+ " is invalid. Only those with INTRA_FEED scope are allowed.")
|
||||||
}
|
}
|
||||||
|
// This looks suicidal:
|
||||||
|
// require(!(sortOrder != null && sortOrder.scope != SortOrder.Scope.INTRA_FEED)) {
|
||||||
|
// ("The specified sortOrder " + sortOrder
|
||||||
|
// + " is invalid. Only those with INTRA_FEED scope are allowed.")
|
||||||
|
// }
|
||||||
field = sortOrder
|
field = sortOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -286,10 +286,6 @@ class MainActivity : CastEnabledActivity() {
|
||||||
}
|
}
|
||||||
override fun onSlide(view: View, slideOffset: Float) {
|
override fun onSlide(view: View, slideOffset: Float) {
|
||||||
val audioPlayer = supportFragmentManager.findFragmentByTag(AudioPlayerFragment.TAG) as? AudioPlayerFragment ?: return
|
val audioPlayer = supportFragmentManager.findFragmentByTag(AudioPlayerFragment.TAG) as? AudioPlayerFragment ?: return
|
||||||
|
|
||||||
// if (slideOffset == 0.0f) { //STATE_COLLAPSED
|
|
||||||
// audioPlayer.scrollToPage(AudioPlayerFragment.FIRST_PAGE)
|
|
||||||
// }
|
|
||||||
audioPlayer.fadePlayerToToolbar(slideOffset)
|
audioPlayer.fadePlayerToToolbar(slideOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import ac.mdiq.podcini.preferences.UserPreferences.setShowRemainTimeSetting
|
||||||
import ac.mdiq.podcini.preferences.UserPreferences.shouldShowRemainingTime
|
import ac.mdiq.podcini.preferences.UserPreferences.shouldShowRemainingTime
|
||||||
import ac.mdiq.podcini.ui.appstartintent.MainActivityStarter
|
import ac.mdiq.podcini.ui.appstartintent.MainActivityStarter
|
||||||
import ac.mdiq.podcini.util.event.MessageEvent
|
import ac.mdiq.podcini.util.event.MessageEvent
|
||||||
|
import ac.mdiq.podcini.util.event.PlayerErrorEvent
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.PixelFormat
|
import android.graphics.PixelFormat
|
||||||
|
@ -489,7 +490,7 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onMediaPlayerError(event: ac.mdiq.podcini.util.event.PlayerErrorEvent) {
|
fun onMediaPlayerError(event: PlayerErrorEvent) {
|
||||||
MediaPlayerErrorDialog.show(this, event)
|
MediaPlayerErrorDialog.show(this, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import ac.mdiq.podcini.util.Converter.getDurationStringLocalized
|
||||||
import ac.mdiq.podcini.util.Converter.getDurationStringLong
|
import ac.mdiq.podcini.util.Converter.getDurationStringLong
|
||||||
import ac.mdiq.podcini.util.IntentUtils.openInBrowser
|
import ac.mdiq.podcini.util.IntentUtils.openInBrowser
|
||||||
import ac.mdiq.podcini.storage.model.feed.Chapter
|
import ac.mdiq.podcini.storage.model.feed.Chapter
|
||||||
|
import ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage
|
||||||
import ac.mdiq.podcini.storage.model.playback.Playable
|
import ac.mdiq.podcini.storage.model.playback.Playable
|
||||||
import ac.mdiq.podcini.ui.common.CircularProgressBar
|
import ac.mdiq.podcini.ui.common.CircularProgressBar
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
@ -89,7 +90,7 @@ class ChaptersListAdapter(private val context: Context, private val callback: Ca
|
||||||
Glide.with(context).clear(holder.image)
|
Glide.with(context).clear(holder.image)
|
||||||
} else {
|
} else {
|
||||||
if (media != null) Glide.with(context)
|
if (media != null) Glide.with(context)
|
||||||
.load(ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage.getModelFor(media!!, position))
|
.load(EmbeddedChapterImage.getModelFor(media!!, position))
|
||||||
.apply(RequestOptions()
|
.apply(RequestOptions()
|
||||||
.dontAnimate()
|
.dontAnimate()
|
||||||
.transform(FitCenter(), RoundedCorners((4 * context.resources.displayMetrics.density).toInt())))
|
.transform(FitCenter(), RoundedCorners((4 * context.resources.displayMetrics.density).toInt())))
|
||||||
|
|
|
@ -15,8 +15,9 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
/**
|
/**
|
||||||
* Displays a dialog with a text box for filtering episodes and two radio buttons for exclusion/inclusion
|
* Displays a dialog with a text box for filtering episodes and two radio buttons for exclusion/inclusion
|
||||||
*/
|
*/
|
||||||
abstract class EpisodeFilterDialog(context: Context, filter: FeedFilter) : MaterialAlertDialogBuilder(
|
abstract class EpisodeFilterDialog(context: Context, filter: FeedFilter) :
|
||||||
context) {
|
MaterialAlertDialogBuilder(context) {
|
||||||
|
|
||||||
private val viewBinding = EpisodeFilterDialogBinding.inflate(LayoutInflater.from(context))
|
private val viewBinding = EpisodeFilterDialogBinding.inflate(LayoutInflater.from(context))
|
||||||
private val termList: MutableList<String>
|
private val termList: MutableList<String>
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,11 @@ import ac.mdiq.podcini.R
|
||||||
import ac.mdiq.podcini.databinding.SortDialogBinding
|
import ac.mdiq.podcini.databinding.SortDialogBinding
|
||||||
import ac.mdiq.podcini.databinding.SortDialogItemActiveBinding
|
import ac.mdiq.podcini.databinding.SortDialogItemActiveBinding
|
||||||
import ac.mdiq.podcini.databinding.SortDialogItemBinding
|
import ac.mdiq.podcini.databinding.SortDialogItemBinding
|
||||||
|
import ac.mdiq.podcini.preferences.UserPreferences
|
||||||
import ac.mdiq.podcini.storage.model.feed.SortOrder
|
import ac.mdiq.podcini.storage.model.feed.SortOrder
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.WindowManager
|
||||||
|
|
||||||
open class ItemSortDialog : BottomSheetDialogFragment() {
|
open class ItemSortDialog : BottomSheetDialogFragment() {
|
||||||
protected var _binding: SortDialogBinding? = null
|
protected var _binding: SortDialogBinding? = null
|
||||||
|
@ -30,6 +34,11 @@ open class ItemSortDialog : BottomSheetDialogFragment() {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
dialog?.window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
|
||||||
|
}
|
||||||
|
|
||||||
private fun populateList() {
|
private fun populateList() {
|
||||||
binding.gridLayout.removeAllViews()
|
binding.gridLayout.removeAllViews()
|
||||||
onAddItem(R.string.episode_title, SortOrder.EPISODE_TITLE_A_Z, SortOrder.EPISODE_TITLE_Z_A, true)
|
onAddItem(R.string.episode_title, SortOrder.EPISODE_TITLE_A_Z, SortOrder.EPISODE_TITLE_Z_A, true)
|
||||||
|
|
|
@ -36,6 +36,9 @@ import org.greenrobot.eventbus.ThreadMode
|
||||||
|
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
class ChaptersFragment : AppCompatDialogFragment() {
|
class ChaptersFragment : AppCompatDialogFragment() {
|
||||||
|
private var _binding: SimpleListFragmentBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private lateinit var layoutManager: LinearLayoutManager
|
private lateinit var layoutManager: LinearLayoutManager
|
||||||
private lateinit var progressBar: ProgressBar
|
private lateinit var progressBar: ProgressBar
|
||||||
private lateinit var adapter: ChaptersListAdapter
|
private lateinit var adapter: ChaptersListAdapter
|
||||||
|
@ -63,12 +66,12 @@ class ChaptersFragment : AppCompatDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onCreateView(inflater: LayoutInflater): View {
|
fun onCreateView(inflater: LayoutInflater): View {
|
||||||
val viewBinding = SimpleListFragmentBinding.inflate(inflater)
|
_binding = SimpleListFragmentBinding.inflate(inflater)
|
||||||
viewBinding.toolbar.visibility = View.GONE
|
binding.toolbar.visibility = View.GONE
|
||||||
|
|
||||||
Log.d(TAG, "fragment onCreateView")
|
Log.d(TAG, "fragment onCreateView")
|
||||||
val recyclerView = viewBinding.recyclerView
|
val recyclerView = binding.recyclerView
|
||||||
progressBar = viewBinding.progLoading
|
progressBar = binding.progLoading
|
||||||
layoutManager = LinearLayoutManager(activity)
|
layoutManager = LinearLayoutManager(activity)
|
||||||
recyclerView.layoutManager = layoutManager
|
recyclerView.layoutManager = layoutManager
|
||||||
recyclerView.addItemDecoration(DividerItemDecoration(recyclerView.context, layoutManager.orientation))
|
recyclerView.addItemDecoration(DividerItemDecoration(recyclerView.context, layoutManager.orientation))
|
||||||
|
@ -100,11 +103,12 @@ class ChaptersFragment : AppCompatDialogFragment() {
|
||||||
EventBus.getDefault().register(this)
|
EventBus.getDefault().register(this)
|
||||||
loadMediaInfo(false)
|
loadMediaInfo(false)
|
||||||
|
|
||||||
return viewBinding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
controller?.release()
|
controller?.release()
|
||||||
controller = null
|
controller = null
|
||||||
EventBus.getDefault().unregister(this)
|
EventBus.getDefault().unregister(this)
|
||||||
|
|
|
@ -25,9 +25,7 @@ import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
|
||||||
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
|
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
|
||||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||||
import ac.mdiq.podcini.util.FeedItemUtil
|
import ac.mdiq.podcini.util.FeedItemUtil
|
||||||
import ac.mdiq.podcini.util.event.EpisodeDownloadEvent
|
import ac.mdiq.podcini.util.event.*
|
||||||
import ac.mdiq.podcini.util.event.FeedItemEvent
|
|
||||||
import ac.mdiq.podcini.util.event.SwipeActionsChangedEvent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.*
|
import android.view.*
|
||||||
|
@ -55,12 +53,12 @@ import java.util.*
|
||||||
* Displays all completed downloads and provides a button to delete them.
|
* Displays all completed downloads and provides a button to delete them.
|
||||||
*/
|
*/
|
||||||
class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeListener, Toolbar.OnMenuItemClickListener {
|
class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeListener, Toolbar.OnMenuItemClickListener {
|
||||||
private var runningDownloads: Set<String>? = HashSet()
|
|
||||||
private var items: MutableList<FeedItem> = mutableListOf()
|
|
||||||
|
|
||||||
private var _binding: SimpleListFragmentBinding? = null
|
private var _binding: SimpleListFragmentBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private var runningDownloads: Set<String> = HashSet()
|
||||||
|
private var items: MutableList<FeedItem> = mutableListOf()
|
||||||
|
|
||||||
private lateinit var infoBar: TextView
|
private lateinit var infoBar: TextView
|
||||||
private lateinit var adapter: CompletedDownloadsListAdapter
|
private lateinit var adapter: CompletedDownloadsListAdapter
|
||||||
private lateinit var toolbar: MaterialToolbar
|
private lateinit var toolbar: MaterialToolbar
|
||||||
|
@ -105,12 +103,12 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
|
||||||
swipeActions = SwipeActions(this, TAG).attachTo(recyclerView)
|
swipeActions = SwipeActions(this, TAG).attachTo(recyclerView)
|
||||||
swipeActions.setFilter(FeedItemFilter(FeedItemFilter.DOWNLOADED))
|
swipeActions.setFilter(FeedItemFilter(FeedItemFilter.DOWNLOADED))
|
||||||
refreshSwipeTelltale()
|
refreshSwipeTelltale()
|
||||||
binding.leftActionIcon.setOnClickListener({
|
binding.leftActionIcon.setOnClickListener {
|
||||||
swipeActions.showDialog()
|
swipeActions.showDialog()
|
||||||
})
|
}
|
||||||
binding.rightActionIcon.setOnClickListener({
|
binding.rightActionIcon.setOnClickListener {
|
||||||
swipeActions.showDialog()
|
swipeActions.showDialog()
|
||||||
})
|
}
|
||||||
|
|
||||||
val animator: RecyclerView.ItemAnimator? = recyclerView.itemAnimator
|
val animator: RecyclerView.ItemAnimator? = recyclerView.itemAnimator
|
||||||
if (animator is SimpleItemAnimator) {
|
if (animator is SimpleItemAnimator) {
|
||||||
|
@ -127,8 +125,8 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
|
||||||
speedDialView.overlayLayout = multiSelectDial.fabSDOverlay
|
speedDialView.overlayLayout = multiSelectDial.fabSDOverlay
|
||||||
speedDialView.inflate(R.menu.episodes_apply_action_speeddial)
|
speedDialView.inflate(R.menu.episodes_apply_action_speeddial)
|
||||||
speedDialView.removeActionItemById(R.id.download_batch)
|
speedDialView.removeActionItemById(R.id.download_batch)
|
||||||
speedDialView.removeActionItemById(R.id.mark_read_batch)
|
// speedDialView.removeActionItemById(R.id.mark_read_batch)
|
||||||
speedDialView.removeActionItemById(R.id.mark_unread_batch)
|
// speedDialView.removeActionItemById(R.id.mark_unread_batch)
|
||||||
speedDialView.removeActionItemById(R.id.remove_from_queue_batch)
|
speedDialView.removeActionItemById(R.id.remove_from_queue_batch)
|
||||||
speedDialView.setOnChangeListener(object : SpeedDialView.OnChangeListener {
|
speedDialView.setOnChangeListener(object : SpeedDialView.OnChangeListener {
|
||||||
override fun onMainActionSelected(): Boolean {
|
override fun onMainActionSelected(): Boolean {
|
||||||
|
@ -286,17 +284,17 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onPlayerStatusChanged(event: ac.mdiq.podcini.util.event.PlayerStatusEvent?) {
|
fun onPlayerStatusChanged(event: PlayerStatusEvent?) {
|
||||||
loadItems()
|
loadItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onDownloadLogChanged(event: ac.mdiq.podcini.util.event.DownloadLogEvent?) {
|
fun onDownloadLogChanged(event: DownloadLogEvent?) {
|
||||||
loadItems()
|
loadItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onUnreadItemsChanged(event: ac.mdiq.podcini.util.event.UnreadItemsUpdateEvent?) {
|
fun onUnreadItemsChanged(event: UnreadItemsUpdateEvent?) {
|
||||||
loadItems()
|
loadItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,10 +322,10 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
|
||||||
FeedItemFilter(FeedItemFilter.DOWNLOADED), sortOrder)
|
FeedItemFilter(FeedItemFilter.DOWNLOADED), sortOrder)
|
||||||
|
|
||||||
val mediaUrls: MutableList<String> = ArrayList()
|
val mediaUrls: MutableList<String> = ArrayList()
|
||||||
if (runningDownloads == null) {
|
if (runningDownloads.isEmpty()) {
|
||||||
return@fromCallable downloadedItems
|
return@fromCallable downloadedItems
|
||||||
}
|
}
|
||||||
for (url in runningDownloads!!) {
|
for (url in runningDownloads) {
|
||||||
if (FeedItemUtil.indexOfItemWithDownloadUrl(downloadedItems, url) != -1) {
|
if (FeedItemUtil.indexOfItemWithDownloadUrl(downloadedItems, url) != -1) {
|
||||||
continue // Already in list
|
continue // Already in list
|
||||||
}
|
}
|
||||||
|
@ -409,7 +407,11 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
|
||||||
descending: SortOrder,
|
descending: SortOrder,
|
||||||
ascendingIsDefault: Boolean
|
ascendingIsDefault: Boolean
|
||||||
) {
|
) {
|
||||||
if (ascending == SortOrder.DATE_OLD_NEW || ascending == SortOrder.DURATION_SHORT_LONG || ascending == SortOrder.EPISODE_TITLE_A_Z || ascending == SortOrder.SIZE_SMALL_LARGE) {
|
if (ascending == SortOrder.DATE_OLD_NEW ||
|
||||||
|
ascending == SortOrder.DURATION_SHORT_LONG ||
|
||||||
|
ascending == SortOrder.EPISODE_TITLE_A_Z ||
|
||||||
|
ascending == SortOrder.SIZE_SMALL_LARGE ||
|
||||||
|
ascending == SortOrder.FEED_TITLE_A_Z) {
|
||||||
super.onAddItem(title, ascending, descending, ascendingIsDefault)
|
super.onAddItem(title, ascending, descending, ascendingIsDefault)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,7 +419,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis
|
||||||
override fun onSelectionChanged() {
|
override fun onSelectionChanged() {
|
||||||
super.onSelectionChanged()
|
super.onSelectionChanged()
|
||||||
UserPreferences.downloadsSortedOrder = sortOrder
|
UserPreferences.downloadsSortedOrder = sortOrder
|
||||||
EventBus.getDefault().post(ac.mdiq.podcini.util.event.DownloadLogEvent.listUpdated())
|
EventBus.getDefault().post(DownloadLogEvent.listUpdated())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,9 @@ import java.util.*
|
||||||
* Searches iTunes store for top podcasts and displays results in a list.
|
* Searches iTunes store for top podcasts and displays results in a list.
|
||||||
*/
|
*/
|
||||||
class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
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 gridView: GridView
|
||||||
private lateinit var progressBar: ProgressBar
|
private lateinit var progressBar: ProgressBar
|
||||||
|
@ -94,15 +97,15 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
val viewBinding = FragmentItunesSearchBinding.inflate(inflater)
|
_binding = FragmentItunesSearchBinding.inflate(inflater)
|
||||||
// val root = inflater.inflate(R.layout.fragment_itunes_search, container, false)
|
// val root = inflater.inflate(R.layout.fragment_itunes_search, container, false)
|
||||||
|
|
||||||
Log.d(TAG, "fragment onCreateView")
|
Log.d(TAG, "fragment onCreateView")
|
||||||
gridView = viewBinding.gridView
|
gridView = binding.gridView
|
||||||
adapter = OnlineFeedsAdapter(requireActivity(), ArrayList())
|
adapter = OnlineFeedsAdapter(requireActivity(), ArrayList())
|
||||||
gridView.setAdapter(adapter)
|
gridView.setAdapter(adapter)
|
||||||
|
|
||||||
toolbar = viewBinding.toolbar
|
toolbar = binding.toolbar
|
||||||
toolbar.setNavigationOnClickListener { parentFragmentManager.popBackStack() }
|
toolbar.setNavigationOnClickListener { parentFragmentManager.popBackStack() }
|
||||||
toolbar.inflateMenu(R.menu.countries_menu)
|
toolbar.inflateMenu(R.menu.countries_menu)
|
||||||
val discoverHideItem = toolbar.menu.findItem(R.id.discover_hide_item)
|
val discoverHideItem = toolbar.menu.findItem(R.id.discover_hide_item)
|
||||||
|
@ -121,17 +124,18 @@ class DiscoveryFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar = viewBinding.progressBar
|
progressBar = binding.progressBar
|
||||||
txtvError = viewBinding.txtvError
|
txtvError = binding.txtvError
|
||||||
butRetry = viewBinding.butRetry
|
butRetry = binding.butRetry
|
||||||
txtvEmpty = viewBinding.empty
|
txtvEmpty = binding.empty
|
||||||
|
|
||||||
loadToplist(countryCode)
|
loadToplist(countryCode)
|
||||||
return viewBinding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
_binding = null
|
||||||
disposable?.dispose()
|
disposable?.dispose()
|
||||||
|
|
||||||
adapter = null
|
adapter = null
|
||||||
|
|
|
@ -23,6 +23,7 @@ import ac.mdiq.podcini.util.DateFormatter
|
||||||
import ac.mdiq.podcini.util.PlaybackStatus
|
import ac.mdiq.podcini.util.PlaybackStatus
|
||||||
import ac.mdiq.podcini.util.event.EpisodeDownloadEvent
|
import ac.mdiq.podcini.util.event.EpisodeDownloadEvent
|
||||||
import ac.mdiq.podcini.util.event.FeedItemEvent
|
import ac.mdiq.podcini.util.event.FeedItemEvent
|
||||||
|
import ac.mdiq.podcini.util.event.PlayerStatusEvent
|
||||||
import ac.mdiq.podcini.util.event.UnreadItemsUpdateEvent
|
import ac.mdiq.podcini.util.event.UnreadItemsUpdateEvent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -409,7 +410,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onPlayerStatusChanged(event: ac.mdiq.podcini.util.event.PlayerStatusEvent?) {
|
fun onPlayerStatusChanged(event: PlayerStatusEvent?) {
|
||||||
updateButtons()
|
updateButtons()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,12 +105,12 @@ abstract class EpisodesListFragment : Fragment(), SelectableAdapter.OnSelectMode
|
||||||
swipeActions = SwipeActions(this, getFragmentTag()).attachTo(recyclerView)
|
swipeActions = SwipeActions(this, getFragmentTag()).attachTo(recyclerView)
|
||||||
swipeActions.setFilter(getFilter())
|
swipeActions.setFilter(getFilter())
|
||||||
refreshSwipeTelltale()
|
refreshSwipeTelltale()
|
||||||
binding.leftActionIcon.setOnClickListener({
|
binding.leftActionIcon.setOnClickListener {
|
||||||
swipeActions.showDialog()
|
swipeActions.showDialog()
|
||||||
})
|
}
|
||||||
binding.rightActionIcon.setOnClickListener({
|
binding.rightActionIcon.setOnClickListener {
|
||||||
swipeActions.showDialog()
|
swipeActions.showDialog()
|
||||||
})
|
}
|
||||||
|
|
||||||
val animator: RecyclerView.ItemAnimator? = recyclerView.itemAnimator
|
val animator: RecyclerView.ItemAnimator? = recyclerView.itemAnimator
|
||||||
if (animator is SimpleItemAnimator) {
|
if (animator is SimpleItemAnimator) {
|
||||||
|
|
|
@ -54,6 +54,9 @@ import kotlin.math.max
|
||||||
* Fragment which is supposed to be displayed outside of the MediaplayerActivity.
|
* Fragment which is supposed to be displayed outside of the MediaplayerActivity.
|
||||||
*/
|
*/
|
||||||
class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
|
private var _binding: ExternalPlayerFragmentBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private lateinit var imgvCover: ImageView
|
private lateinit var imgvCover: ImageView
|
||||||
private lateinit var butPlay: PlayButton
|
private lateinit var butPlay: PlayButton
|
||||||
|
|
||||||
|
@ -79,22 +82,22 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?): View {
|
savedInstanceState: Bundle?): View {
|
||||||
val viewBinding = ExternalPlayerFragmentBinding.inflate(inflater)
|
_binding = ExternalPlayerFragmentBinding.inflate(inflater)
|
||||||
Log.d(TAG, "fragment onCreateView")
|
Log.d(TAG, "fragment onCreateView")
|
||||||
|
|
||||||
episodeTitle = viewBinding.titleView
|
episodeTitle = binding.titleView
|
||||||
butPlaybackSpeed = viewBinding.butPlaybackSpeed
|
butPlaybackSpeed = binding.butPlaybackSpeed
|
||||||
txtvPlaybackSpeed = viewBinding.txtvPlaybackSpeed
|
txtvPlaybackSpeed = binding.txtvPlaybackSpeed
|
||||||
imgvCover = viewBinding.imgvCover
|
imgvCover = binding.imgvCover
|
||||||
butPlay = viewBinding.butPlay
|
butPlay = binding.butPlay
|
||||||
butRev = viewBinding.butRev
|
butRev = binding.butRev
|
||||||
txtvRev = viewBinding.txtvRev
|
txtvRev = binding.txtvRev
|
||||||
butFF = viewBinding.butFF
|
butFF = binding.butFF
|
||||||
txtvFF = viewBinding.txtvFF
|
txtvFF = binding.txtvFF
|
||||||
butSkip = viewBinding.butSkip
|
butSkip = binding.butSkip
|
||||||
sbPosition = viewBinding.sbPosition
|
sbPosition = binding.sbPosition
|
||||||
txtvPosition = viewBinding.txtvPosition
|
txtvPosition = binding.txtvPosition
|
||||||
txtvLength = viewBinding.txtvLength
|
txtvLength = binding.txtvLength
|
||||||
|
|
||||||
setupLengthTextView()
|
setupLengthTextView()
|
||||||
setupControlButtons()
|
setupControlButtons()
|
||||||
|
@ -103,7 +106,7 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
}
|
}
|
||||||
sbPosition.setOnSeekBarChangeListener(this)
|
sbPosition.setOnSeekBarChangeListener(this)
|
||||||
|
|
||||||
viewBinding.externalPlayerFragment.setOnClickListener {
|
binding.externalPlayerFragment.setOnClickListener {
|
||||||
Log.d(TAG, "externalPlayerFragment was clicked")
|
Log.d(TAG, "externalPlayerFragment was clicked")
|
||||||
val media = controller?.getMedia()
|
val media = controller?.getMedia()
|
||||||
if (media != null) {
|
if (media != null) {
|
||||||
|
@ -118,13 +121,14 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
|
|
||||||
controller = setupPlaybackController()
|
controller = setupPlaybackController()
|
||||||
controller!!.init()
|
controller!!.init()
|
||||||
loadMediaInfo()
|
// loadMediaInfo()
|
||||||
EventBus.getDefault().register(this)
|
EventBus.getDefault().register(this)
|
||||||
return viewBinding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(UnstableApi::class) override fun onDestroyView() {
|
@OptIn(UnstableApi::class) override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
controller?.release()
|
controller?.release()
|
||||||
controller = null
|
controller = null
|
||||||
EventBus.getDefault().unregister(this)
|
EventBus.getDefault().unregister(this)
|
||||||
|
@ -134,11 +138,9 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
butPlay.setOnClickListener {
|
butPlay.setOnClickListener {
|
||||||
if (controller == null) {
|
if (controller == null) return@setOnClickListener
|
||||||
return@setOnClickListener
|
|
||||||
}
|
|
||||||
val media = controller!!.getMedia()
|
|
||||||
|
|
||||||
|
val media = controller!!.getMedia()
|
||||||
if (media?.getMediaType() == MediaType.VIDEO && controller!!.status != PlayerStatus.PLAYING) {
|
if (media?.getMediaType() == MediaType.VIDEO && controller!!.status != PlayerStatus.PLAYING) {
|
||||||
controller!!.playPause()
|
controller!!.playPause()
|
||||||
requireContext().startActivity(getPlayerActivityIntent(requireContext(), media))
|
requireContext().startActivity(getPlayerActivityIntent(requireContext(), media))
|
||||||
|
@ -161,10 +163,10 @@ class ExternalPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
SkipPreferenceDialog.SkipDirection.SKIP_REWIND, txtvRev)
|
SkipPreferenceDialog.SkipDirection.SKIP_REWIND, txtvRev)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
butPlay.setOnClickListener {
|
// butPlay.setOnClickListener {
|
||||||
controller?.init()
|
// controller?.init()
|
||||||
controller?.playPause()
|
// controller?.playPause()
|
||||||
}
|
// }
|
||||||
butFF.setOnClickListener {
|
butFF.setOnClickListener {
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
val curr: Int = controller!!.position
|
val curr: Int = controller!!.position
|
||||||
|
|
|
@ -71,10 +71,11 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
||||||
|
|
||||||
private var _binding: FeedItemListFragmentBinding? = null
|
private var _binding: FeedItemListFragmentBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
private var _speedDialBinding: MultiSelectSpeedDialBinding? = null
|
||||||
|
private val speedDialBinding get() = _speedDialBinding!!
|
||||||
|
|
||||||
private lateinit var adapter: FeedItemListAdapter
|
private lateinit var adapter: FeedItemListAdapter
|
||||||
private lateinit var swipeActions: SwipeActions
|
private lateinit var swipeActions: SwipeActions
|
||||||
private lateinit var speedDialBinding: MultiSelectSpeedDialBinding
|
|
||||||
private lateinit var nextPageLoader: MoreContentListFooterUtil
|
private lateinit var nextPageLoader: MoreContentListFooterUtil
|
||||||
|
|
||||||
private var displayUpArrow = false
|
private var displayUpArrow = false
|
||||||
|
@ -96,7 +97,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
||||||
Log.d(TAG, "fragment onCreateView")
|
Log.d(TAG, "fragment onCreateView")
|
||||||
|
|
||||||
_binding = FeedItemListFragmentBinding.inflate(inflater)
|
_binding = FeedItemListFragmentBinding.inflate(inflater)
|
||||||
speedDialBinding = MultiSelectSpeedDialBinding.bind(binding.root)
|
_speedDialBinding = MultiSelectSpeedDialBinding.bind(binding.root)
|
||||||
|
|
||||||
binding.toolbar.inflateMenu(R.menu.feedlist)
|
binding.toolbar.inflateMenu(R.menu.feedlist)
|
||||||
binding.toolbar.setOnMenuItemClickListener(this)
|
binding.toolbar.setOnMenuItemClickListener(this)
|
||||||
|
@ -198,6 +199,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
_binding = null
|
_binding = null
|
||||||
|
_speedDialBinding
|
||||||
EventBus.getDefault().unregister(this)
|
EventBus.getDefault().unregister(this)
|
||||||
disposable?.dispose()
|
disposable?.dispose()
|
||||||
adapter.endSelectMode()
|
adapter.endSelectMode()
|
||||||
|
@ -209,9 +211,8 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateToolbar() {
|
private fun updateToolbar() {
|
||||||
if (feed == null) {
|
if (feed == null) return
|
||||||
return
|
|
||||||
}
|
|
||||||
binding.toolbar.menu.findItem(R.id.visit_website_item).setVisible(feed!!.link != null)
|
binding.toolbar.menu.findItem(R.id.visit_website_item).setVisible(feed!!.link != null)
|
||||||
binding.toolbar.menu.findItem(R.id.refresh_complete_item).setVisible(feed!!.isPaged)
|
binding.toolbar.menu.findItem(R.id.refresh_complete_item).setVisible(feed!!.isPaged)
|
||||||
if (StringUtils.isBlank(feed!!.link)) {
|
if (StringUtils.isBlank(feed!!.link)) {
|
||||||
|
@ -620,8 +621,11 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
||||||
descending: SortOrder,
|
descending: SortOrder,
|
||||||
ascendingIsDefault: Boolean
|
ascendingIsDefault: Boolean
|
||||||
) {
|
) {
|
||||||
if (ascending == SortOrder.DATE_OLD_NEW || ascending == SortOrder.DURATION_SHORT_LONG || ascending == SortOrder.EPISODE_TITLE_A_Z || (requireArguments().getBoolean(
|
if (ascending == SortOrder.DATE_OLD_NEW ||
|
||||||
ARG_FEED_IS_LOCAL) && ascending == SortOrder.EPISODE_FILENAME_A_Z)) {
|
ascending == SortOrder.DURATION_SHORT_LONG ||
|
||||||
|
ascending == SortOrder.RANDOM ||
|
||||||
|
ascending == SortOrder.EPISODE_TITLE_A_Z ||
|
||||||
|
(requireArguments().getBoolean(ARG_FEED_IS_LOCAL) && ascending == SortOrder.EPISODE_FILENAME_A_Z)) {
|
||||||
super.onAddItem(title, ascending, descending, ascendingIsDefault)
|
super.onAddItem(title, ascending, descending, ascendingIsDefault)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ import ac.mdiq.podcini.ui.dialog.*
|
||||||
import ac.mdiq.podcini.ui.menuhandler.MenuItemUtils
|
import ac.mdiq.podcini.ui.menuhandler.MenuItemUtils
|
||||||
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
|
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
|
||||||
import ac.mdiq.podcini.util.event.FeedListUpdateEvent
|
import ac.mdiq.podcini.util.event.FeedListUpdateEvent
|
||||||
|
import ac.mdiq.podcini.util.event.QueueEvent
|
||||||
|
import ac.mdiq.podcini.util.event.UnreadItemsUpdateEvent
|
||||||
import android.R.attr
|
import android.R.attr
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -195,7 +197,7 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onUnreadItemsChanged(event: ac.mdiq.podcini.util.event.UnreadItemsUpdateEvent?) {
|
fun onUnreadItemsChanged(event: UnreadItemsUpdateEvent?) {
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +208,7 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onQueueChanged(event: ac.mdiq.podcini.util.event.QueueEvent) {
|
fun onQueueChanged(event: QueueEvent) {
|
||||||
Log.d(TAG, "onQueueChanged($event)")
|
Log.d(TAG, "onQueueChanged($event)")
|
||||||
// we are only interested in the number of queue items, not download status or position
|
// we are only interested in the number of queue items, not download status or position
|
||||||
if (event.action == ac.mdiq.podcini.util.event.QueueEvent.Action.DELETED_MEDIA || event.action == ac.mdiq.podcini.util.event.QueueEvent.Action.SORTED || event.action == ac.mdiq.podcini.util.event.QueueEvent.Action.MOVED) {
|
if (event.action == ac.mdiq.podcini.util.event.QueueEvent.Action.DELETED_MEDIA || event.action == ac.mdiq.podcini.util.event.QueueEvent.Action.SORTED || event.action == ac.mdiq.podcini.util.event.QueueEvent.Action.MOVED) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import ac.mdiq.podcini.playback.PlaybackController
|
||||||
import ac.mdiq.podcini.playback.event.PlaybackPositionEvent
|
import ac.mdiq.podcini.playback.event.PlaybackPositionEvent
|
||||||
import ac.mdiq.podcini.storage.DBReader
|
import ac.mdiq.podcini.storage.DBReader
|
||||||
import ac.mdiq.podcini.storage.model.feed.Chapter
|
import ac.mdiq.podcini.storage.model.feed.Chapter
|
||||||
|
import ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage
|
||||||
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
||||||
import ac.mdiq.podcini.storage.model.playback.Playable
|
import ac.mdiq.podcini.storage.model.playback.Playable
|
||||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||||
|
@ -279,7 +280,7 @@ class PlayerDetailsFragment : Fragment() {
|
||||||
cover.into(binding.imgvCover)
|
cover.into(binding.imgvCover)
|
||||||
} else {
|
} else {
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.load(ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage.getModelFor(media!!, displayedChapterIndex))
|
.load(EmbeddedChapterImage.getModelFor(media!!, displayedChapterIndex))
|
||||||
.apply(options)
|
.apply(options)
|
||||||
.thumbnail(cover)
|
.thumbnail(cover)
|
||||||
.error(cover)
|
.error(cover)
|
||||||
|
|
|
@ -1,6 +1,34 @@
|
||||||
package ac.mdiq.podcini.ui.fragment
|
package ac.mdiq.podcini.ui.fragment
|
||||||
|
|
||||||
|
import ac.mdiq.podcini.R
|
||||||
|
import ac.mdiq.podcini.databinding.CheckboxDoNotShowAgainBinding
|
||||||
|
import ac.mdiq.podcini.databinding.MultiSelectSpeedDialBinding
|
||||||
|
import ac.mdiq.podcini.databinding.QueueFragmentBinding
|
||||||
|
import ac.mdiq.podcini.feed.util.PlaybackSpeedUtils
|
||||||
|
import ac.mdiq.podcini.net.download.FeedUpdateManager
|
||||||
|
import ac.mdiq.podcini.playback.event.PlaybackPositionEvent
|
||||||
|
import ac.mdiq.podcini.preferences.UserPreferences
|
||||||
|
import ac.mdiq.podcini.storage.DBReader
|
||||||
|
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.storage.model.feed.SortOrder
|
||||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||||
|
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.fragment.actions.EpisodeMultiSelectActionHandler
|
||||||
|
import ac.mdiq.podcini.ui.fragment.swipeactions.SwipeActions
|
||||||
|
import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler
|
||||||
|
import ac.mdiq.podcini.ui.menuhandler.MenuItemUtils
|
||||||
|
import ac.mdiq.podcini.ui.view.EmptyViewHandler
|
||||||
|
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
|
||||||
|
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
|
||||||
|
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||||
|
import ac.mdiq.podcini.util.Converter
|
||||||
|
import ac.mdiq.podcini.util.FeedItemUtil
|
||||||
|
import ac.mdiq.podcini.util.event.*
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
@ -22,35 +50,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.leinardi.android.speeddial.SpeedDialActionItem
|
import com.leinardi.android.speeddial.SpeedDialActionItem
|
||||||
import com.leinardi.android.speeddial.SpeedDialView
|
import com.leinardi.android.speeddial.SpeedDialView
|
||||||
import ac.mdiq.podcini.R
|
|
||||||
import ac.mdiq.podcini.databinding.CheckboxDoNotShowAgainBinding
|
|
||||||
import ac.mdiq.podcini.databinding.MultiSelectSpeedDialBinding
|
|
||||||
import ac.mdiq.podcini.databinding.QueueFragmentBinding
|
|
||||||
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.feed.util.PlaybackSpeedUtils
|
|
||||||
import ac.mdiq.podcini.ui.menuhandler.MenuItemUtils
|
|
||||||
import ac.mdiq.podcini.storage.DBReader
|
|
||||||
import ac.mdiq.podcini.storage.DBWriter
|
|
||||||
import ac.mdiq.podcini.util.FeedItemUtil
|
|
||||||
import ac.mdiq.podcini.net.download.FeedUpdateManager
|
|
||||||
import ac.mdiq.podcini.ui.dialog.ItemSortDialog
|
|
||||||
import ac.mdiq.podcini.util.event.*
|
|
||||||
import ac.mdiq.podcini.playback.event.PlaybackPositionEvent
|
|
||||||
import ac.mdiq.podcini.ui.fragment.actions.EpisodeMultiSelectActionHandler
|
|
||||||
import ac.mdiq.podcini.ui.fragment.swipeactions.SwipeActions
|
|
||||||
import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler
|
|
||||||
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 ac.mdiq.podcini.preferences.UserPreferences
|
|
||||||
import ac.mdiq.podcini.ui.dialog.SwipeActionsDialog
|
|
||||||
import ac.mdiq.podcini.ui.view.EmptyViewHandler
|
|
||||||
import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView
|
|
||||||
import ac.mdiq.podcini.ui.view.LiftOnScrollListener
|
|
||||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
|
||||||
import ac.mdiq.podcini.util.Converter
|
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
|
@ -126,12 +125,12 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda
|
||||||
swipeActions.setFilter(FeedItemFilter(FeedItemFilter.QUEUED))
|
swipeActions.setFilter(FeedItemFilter(FeedItemFilter.QUEUED))
|
||||||
swipeActions.attachTo(recyclerView)
|
swipeActions.attachTo(recyclerView)
|
||||||
refreshSwipeTelltale()
|
refreshSwipeTelltale()
|
||||||
binding.leftActionIcon.setOnClickListener({
|
binding.leftActionIcon.setOnClickListener {
|
||||||
swipeActions.showDialog()
|
swipeActions.showDialog()
|
||||||
})
|
}
|
||||||
binding.rightActionIcon.setOnClickListener({
|
binding.rightActionIcon.setOnClickListener {
|
||||||
swipeActions.showDialog()
|
swipeActions.showDialog()
|
||||||
})
|
}
|
||||||
|
|
||||||
recyclerAdapter = object : QueueRecyclerAdapter(activity as MainActivity, swipeActions) {
|
recyclerAdapter = object : QueueRecyclerAdapter(activity as MainActivity, swipeActions) {
|
||||||
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
|
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
|
||||||
|
|
|
@ -33,6 +33,9 @@ import org.greenrobot.eventbus.ThreadMode
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
|
class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
|
||||||
|
private var _binding: QuickFeedDiscoveryBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private var disposable: Disposable? = null
|
private var disposable: Disposable? = null
|
||||||
|
|
||||||
private lateinit var adapter: FeedDiscoverAdapter
|
private lateinit var adapter: FeedDiscoverAdapter
|
||||||
|
@ -44,18 +47,17 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
|
||||||
|
|
||||||
@OptIn(UnstableApi::class) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
@OptIn(UnstableApi::class) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
super.onCreateView(inflater, container, savedInstanceState)
|
super.onCreateView(inflater, container, savedInstanceState)
|
||||||
val viewBinding = QuickFeedDiscoveryBinding.inflate(inflater)
|
_binding = QuickFeedDiscoveryBinding.inflate(inflater)
|
||||||
// val root: View = inflater.inflate(R.layout.quick_feed_discovery, container, false)
|
|
||||||
|
|
||||||
Log.d(TAG, "fragment onCreateView")
|
Log.d(TAG, "fragment onCreateView")
|
||||||
val discoverMore = viewBinding.discoverMore
|
val discoverMore = binding.discoverMore
|
||||||
discoverMore.setOnClickListener { (activity as MainActivity).loadChildFragment(DiscoveryFragment()) }
|
discoverMore.setOnClickListener { (activity as MainActivity).loadChildFragment(DiscoveryFragment()) }
|
||||||
|
|
||||||
discoverGridLayout = viewBinding.discoverGrid
|
discoverGridLayout = binding.discoverGrid
|
||||||
errorView = viewBinding.discoverError
|
errorView = binding.discoverError
|
||||||
errorTextView = viewBinding.discoverErrorTxtV
|
errorTextView = binding.discoverErrorTxtV
|
||||||
errorRetry = viewBinding.discoverErrorRetryBtn
|
errorRetry = binding.discoverErrorRetryBtn
|
||||||
poweredByTextView = viewBinding.discoverPoweredByItunes
|
poweredByTextView = binding.discoverPoweredByItunes
|
||||||
|
|
||||||
adapter = FeedDiscoverAdapter(activity as MainActivity)
|
adapter = FeedDiscoverAdapter(activity as MainActivity)
|
||||||
discoverGridLayout.setAdapter(adapter)
|
discoverGridLayout.setAdapter(adapter)
|
||||||
|
@ -80,11 +82,12 @@ class QuickFeedDiscoveryFragment : Fragment(), AdapterView.OnItemClickListener {
|
||||||
loadToplist()
|
loadToplist()
|
||||||
|
|
||||||
EventBus.getDefault().register(this)
|
EventBus.getDefault().register(this)
|
||||||
return viewBinding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
_binding = null
|
||||||
EventBus.getDefault().unregister(this)
|
EventBus.getDefault().unregister(this)
|
||||||
disposable?.dispose()
|
disposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,9 @@ import org.greenrobot.eventbus.ThreadMode
|
||||||
* Performs a search operation on all feeds or one specific feed and displays the search result.
|
* Performs a search operation on all feeds or one specific feed and displays the search result.
|
||||||
*/
|
*/
|
||||||
class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
|
class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
|
||||||
|
private var _binding: SearchFragmentBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private lateinit var adapter: EpisodeItemListAdapter
|
private lateinit var adapter: EpisodeItemListAdapter
|
||||||
private lateinit var adapterFeeds: HorizontalFeedListAdapter
|
private lateinit var adapterFeeds: HorizontalFeedListAdapter
|
||||||
private lateinit var progressBar: ProgressBar
|
private lateinit var progressBar: ProgressBar
|
||||||
|
@ -87,14 +90,13 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
|
||||||
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
val viewBinding = SearchFragmentBinding.inflate(inflater)
|
_binding = SearchFragmentBinding.inflate(inflater)
|
||||||
// val layout: View = inflater.inflate(R.layout.search_fragment, container, false)
|
|
||||||
|
|
||||||
Log.d(TAG, "fragment onCreateView")
|
Log.d(TAG, "fragment onCreateView")
|
||||||
setupToolbar(viewBinding.toolbar)
|
setupToolbar(binding.toolbar)
|
||||||
speedDialBinding = MultiSelectSpeedDialBinding.bind(viewBinding.root)
|
speedDialBinding = MultiSelectSpeedDialBinding.bind(binding.root)
|
||||||
progressBar = viewBinding.progressBar
|
progressBar = binding.progressBar
|
||||||
recyclerView = viewBinding.recyclerView
|
recyclerView = binding.recyclerView
|
||||||
recyclerView.setRecycledViewPool((activity as MainActivity).recycledViewPool)
|
recyclerView.setRecycledViewPool((activity as MainActivity).recycledViewPool)
|
||||||
registerForContextMenu(recyclerView)
|
registerForContextMenu(recyclerView)
|
||||||
adapter = object : EpisodeItemListAdapter(activity as MainActivity) {
|
adapter = object : EpisodeItemListAdapter(activity as MainActivity) {
|
||||||
|
@ -109,9 +111,9 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
|
||||||
}
|
}
|
||||||
adapter.setOnSelectModeListener(this)
|
adapter.setOnSelectModeListener(this)
|
||||||
recyclerView.adapter = adapter
|
recyclerView.adapter = adapter
|
||||||
recyclerView.addOnScrollListener(LiftOnScrollListener(viewBinding.appbar))
|
recyclerView.addOnScrollListener(LiftOnScrollListener(binding.appbar))
|
||||||
|
|
||||||
val recyclerViewFeeds = viewBinding.recyclerViewFeeds
|
val recyclerViewFeeds = binding.recyclerViewFeeds
|
||||||
val layoutManagerFeeds = LinearLayoutManager(activity)
|
val layoutManagerFeeds = LinearLayoutManager(activity)
|
||||||
layoutManagerFeeds.orientation = RecyclerView.HORIZONTAL
|
layoutManagerFeeds.orientation = RecyclerView.HORIZONTAL
|
||||||
recyclerViewFeeds.layoutManager = layoutManagerFeeds
|
recyclerViewFeeds.layoutManager = layoutManagerFeeds
|
||||||
|
@ -133,7 +135,7 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
|
||||||
emptyViewHandler.setMessage(R.string.type_to_search)
|
emptyViewHandler.setMessage(R.string.type_to_search)
|
||||||
EventBus.getDefault().register(this)
|
EventBus.getDefault().register(this)
|
||||||
|
|
||||||
chip = viewBinding.feedTitleChip
|
chip = binding.feedTitleChip
|
||||||
chip.setOnCloseIconClickListener {
|
chip.setOnCloseIconClickListener {
|
||||||
requireArguments().putLong(ARG_FEED, 0)
|
requireArguments().putLong(ARG_FEED, 0)
|
||||||
searchWithProgressBar()
|
searchWithProgressBar()
|
||||||
|
@ -178,11 +180,12 @@ class SearchFragment : Fragment(), SelectableAdapter.OnSelectModeListener {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
return viewBinding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
EventBus.getDefault().unregister(this)
|
EventBus.getDefault().unregister(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class ApGlideModule : AppGlideModule() {
|
||||||
registry.append(String::class.java, InputStream::class.java, ApOkHttpUrlLoader.Factory())
|
registry.append(String::class.java, InputStream::class.java, ApOkHttpUrlLoader.Factory())
|
||||||
registry.append(String::class.java, InputStream::class.java, NoHttpStringLoader.StreamFactory())
|
registry.append(String::class.java, InputStream::class.java, NoHttpStringLoader.StreamFactory())
|
||||||
|
|
||||||
registry.append(ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage::class.java, ByteBuffer::class.java, ChapterImageModelLoader.Factory())
|
registry.append(EmbeddedChapterImage::class.java, ByteBuffer::class.java, ChapterImageModelLoader.Factory())
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ac.mdiq.podcini.ui.glide
|
package ac.mdiq.podcini.ui.glide
|
||||||
|
|
||||||
import ac.mdiq.podcini.service.download.PodciniHttpClient.getHttpClient
|
import ac.mdiq.podcini.service.download.PodciniHttpClient.getHttpClient
|
||||||
|
import ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage
|
||||||
import com.bumptech.glide.Priority
|
import com.bumptech.glide.Priority
|
||||||
import com.bumptech.glide.load.DataSource
|
import com.bumptech.glide.load.DataSource
|
||||||
import com.bumptech.glide.load.Options
|
import com.bumptech.glide.load.Options
|
||||||
|
@ -17,9 +18,9 @@ import java.io.FileInputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
class ChapterImageModelLoader : ModelLoader<ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage?, ByteBuffer?> {
|
class ChapterImageModelLoader : ModelLoader<EmbeddedChapterImage?, ByteBuffer?> {
|
||||||
class Factory : ModelLoaderFactory<ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage?, ByteBuffer?> {
|
class Factory : ModelLoaderFactory<EmbeddedChapterImage?, ByteBuffer?> {
|
||||||
override fun build(unused: MultiModelLoaderFactory): ModelLoader<ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage?, ByteBuffer?> {
|
override fun build(unused: MultiModelLoaderFactory): ModelLoader<EmbeddedChapterImage?, ByteBuffer?> {
|
||||||
return ChapterImageModelLoader()
|
return ChapterImageModelLoader()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ class ChapterImageModelLoader : ModelLoader<ac.mdiq.podcini.storage.model.feed.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun buildLoadData(model: ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage,
|
override fun buildLoadData(model: EmbeddedChapterImage,
|
||||||
width: Int,
|
width: Int,
|
||||||
height: Int,
|
height: Int,
|
||||||
options: Options
|
options: Options
|
||||||
|
@ -36,11 +37,11 @@ class ChapterImageModelLoader : ModelLoader<ac.mdiq.podcini.storage.model.feed.E
|
||||||
return ModelLoader.LoadData(ObjectKey(model), EmbeddedImageFetcher(model))
|
return ModelLoader.LoadData(ObjectKey(model), EmbeddedImageFetcher(model))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handles(model: ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage): Boolean {
|
override fun handles(model: EmbeddedChapterImage): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class EmbeddedImageFetcher(private val image: ac.mdiq.podcini.storage.model.feed.EmbeddedChapterImage) : DataFetcher<ByteBuffer?> {
|
internal class EmbeddedImageFetcher(private val image: EmbeddedChapterImage) : DataFetcher<ByteBuffer?> {
|
||||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in ByteBuffer?>) {
|
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in ByteBuffer?>) {
|
||||||
var stream: BufferedInputStream? = null
|
var stream: BufferedInputStream? = null
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import ac.mdiq.podcini.ui.dialog.ConfirmationDialog
|
||||||
import ac.mdiq.podcini.ui.statistics.downloads.DownloadStatisticsFragment
|
import ac.mdiq.podcini.ui.statistics.downloads.DownloadStatisticsFragment
|
||||||
import ac.mdiq.podcini.ui.statistics.subscriptions.SubscriptionStatisticsFragment
|
import ac.mdiq.podcini.ui.statistics.subscriptions.SubscriptionStatisticsFragment
|
||||||
import ac.mdiq.podcini.ui.statistics.years.YearsStatisticsFragment
|
import ac.mdiq.podcini.ui.statistics.years.YearsStatisticsFragment
|
||||||
|
import ac.mdiq.podcini.util.event.StatisticsEvent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -106,7 +107,7 @@ class StatisticsFragment : PagedToolbarFragment() {
|
||||||
val disposable = Completable.fromFuture(DBWriter.resetStatistics())
|
val disposable = Completable.fromFuture(DBWriter.resetStatistics())
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe({ EventBus.getDefault().post(ac.mdiq.podcini.util.event.StatisticsEvent()) },
|
.subscribe({ EventBus.getDefault().post(StatisticsEvent()) },
|
||||||
{ error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
|
{ error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,19 +17,21 @@ import io.reactivex.schedulers.Schedulers
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class FeedStatisticsFragment : Fragment() {
|
class FeedStatisticsFragment : Fragment() {
|
||||||
|
private var _binding: FeedStatisticsBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private var feedId: Long = 0
|
private var feedId: Long = 0
|
||||||
private var disposable: Disposable? = null
|
private var disposable: Disposable? = null
|
||||||
private var viewBinding: FeedStatisticsBinding? = null
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
feedId = requireArguments().getLong(EXTRA_FEED_ID)
|
feedId = requireArguments().getLong(EXTRA_FEED_ID)
|
||||||
viewBinding = FeedStatisticsBinding.inflate(inflater)
|
_binding = FeedStatisticsBinding.inflate(inflater)
|
||||||
|
|
||||||
if (!requireArguments().getBoolean(EXTRA_DETAILED)) {
|
if (!requireArguments().getBoolean(EXTRA_DETAILED)) {
|
||||||
for (i in 0 until viewBinding!!.root.childCount) {
|
for (i in 0 until binding.root.childCount) {
|
||||||
val child = viewBinding!!.root.getChildAt(i)
|
val child = binding.root.getChildAt(i)
|
||||||
if ("detailed" == child.tag) {
|
if ("detailed" == child.tag) {
|
||||||
child.visibility = View.GONE
|
child.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
@ -37,7 +39,7 @@ class FeedStatisticsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadStatistics()
|
loadStatistics()
|
||||||
return viewBinding!!.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadStatistics() {
|
private fun loadStatistics() {
|
||||||
|
@ -62,21 +64,20 @@ class FeedStatisticsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showStats(s: StatisticsItem?) {
|
private fun showStats(s: StatisticsItem?) {
|
||||||
viewBinding!!.startedTotalLabel.text = String.format(Locale.getDefault(), "%d / %d",
|
binding.startedTotalLabel.text = String.format(Locale.getDefault(), "%d / %d",
|
||||||
s!!.episodesStarted, s.episodes)
|
s!!.episodesStarted, s.episodes)
|
||||||
viewBinding!!.timePlayedLabel.text =
|
binding.timePlayedLabel.text =
|
||||||
shortLocalizedDuration(requireContext(), s.timePlayed)
|
shortLocalizedDuration(requireContext(), s.timePlayed)
|
||||||
viewBinding!!.totalDurationLabel.text =
|
binding.totalDurationLabel.text =
|
||||||
shortLocalizedDuration(requireContext(), s.time)
|
shortLocalizedDuration(requireContext(), s.time)
|
||||||
viewBinding!!.onDeviceLabel.text = String.format(Locale.getDefault(), "%d", s.episodesDownloadCount)
|
binding.onDeviceLabel.text = String.format(Locale.getDefault(), "%d", s.episodesDownloadCount)
|
||||||
viewBinding!!.spaceUsedLabel.text = Formatter.formatShortFileSize(context, s.totalDownloadSize)
|
binding.spaceUsedLabel.text = Formatter.formatShortFileSize(context, s.totalDownloadSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
if (disposable != null) {
|
_binding = null
|
||||||
disposable!!.dispose()
|
disposable?.dispose()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import ac.mdiq.podcini.storage.DBReader
|
||||||
import ac.mdiq.podcini.storage.DBReader.StatisticsResult
|
import ac.mdiq.podcini.storage.DBReader.StatisticsResult
|
||||||
import ac.mdiq.podcini.storage.StatisticsItem
|
import ac.mdiq.podcini.storage.StatisticsItem
|
||||||
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
|
import ac.mdiq.podcini.ui.statistics.StatisticsFragment
|
||||||
|
import ac.mdiq.podcini.util.event.StatisticsEvent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -67,7 +68,7 @@ class SubscriptionStatisticsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun statisticsEvent(event: ac.mdiq.podcini.util.event.StatisticsEvent?) {
|
fun statisticsEvent(event: StatisticsEvent?) {
|
||||||
refreshStatistics()
|
refreshStatistics()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ac.mdiq.podcini.R
|
||||||
import ac.mdiq.podcini.databinding.StatisticsFragmentBinding
|
import ac.mdiq.podcini.databinding.StatisticsFragmentBinding
|
||||||
import ac.mdiq.podcini.storage.DBReader
|
import ac.mdiq.podcini.storage.DBReader
|
||||||
import ac.mdiq.podcini.storage.DBReader.MonthlyStatisticsItem
|
import ac.mdiq.podcini.storage.DBReader.MonthlyStatisticsItem
|
||||||
|
import ac.mdiq.podcini.util.event.StatisticsEvent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -59,7 +60,7 @@ class YearsStatisticsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun statisticsEvent(event: ac.mdiq.podcini.util.event.StatisticsEvent?) {
|
fun statisticsEvent(event: StatisticsEvent?) {
|
||||||
refreshStatistics()
|
refreshStatistics()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ac.mdiq.podcini.util
|
||||||
|
|
||||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||||
import ac.mdiq.podcini.storage.model.feed.SortOrder
|
import ac.mdiq.podcini.storage.model.feed.SortOrder
|
||||||
|
import android.util.Log
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,7 +97,8 @@ object FeedItemPermutors {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun feedTitle(item: FeedItem?): String {
|
private fun feedTitle(item: FeedItem?): String {
|
||||||
return if (item?.feed != null && item.feed!!.title != null) item.feed!!.title!!.lowercase(Locale.getDefault()) else ""
|
Log.d("permutors", "feedTitle ${item?.feed?.title}")
|
||||||
|
return if (item?.feed?.title != null) item.feed!!.title!!.lowercase(Locale.getDefault()) else ""
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,6 +17,7 @@ import ac.mdiq.podcini.net.ssl.SslProviderInstaller
|
||||||
import ac.mdiq.podcini.storage.database.PodDBAdapter
|
import ac.mdiq.podcini.storage.database.PodDBAdapter
|
||||||
import ac.mdiq.podcini.preferences.UserPreferences
|
import ac.mdiq.podcini.preferences.UserPreferences
|
||||||
import ac.mdiq.podcini.preferences.UserPreferences.proxyConfig
|
import ac.mdiq.podcini.preferences.UserPreferences.proxyConfig
|
||||||
|
import ac.mdiq.podcini.service.download.DownloadServiceInterfaceImpl
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
|
@ -35,7 +36,7 @@ object ClientConfigurator {
|
||||||
SslProviderInstaller.install(context)
|
SslProviderInstaller.install(context)
|
||||||
NetworkUtils.init(context)
|
NetworkUtils.init(context)
|
||||||
NetworkConnectionChangeHandler.init(context)
|
NetworkConnectionChangeHandler.init(context)
|
||||||
DownloadServiceInterface.setImpl(ac.mdiq.podcini.service.download.DownloadServiceInterfaceImpl())
|
DownloadServiceInterface.setImpl(DownloadServiceInterfaceImpl())
|
||||||
SynchronizationQueueSink.setServiceStarterImpl { SyncService.sync(context) }
|
SynchronizationQueueSink.setServiceStarterImpl { SyncService.sync(context) }
|
||||||
setCacheDirectory(File(context.cacheDir, "okhttp"))
|
setCacheDirectory(File(context.cacheDir, "okhttp"))
|
||||||
setProxyConfig(proxyConfig)
|
setProxyConfig(proxyConfig)
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/sort_items"
|
android:id="@+id/sort_items"
|
||||||
|
android:icon="@drawable/arrows_sort"
|
||||||
android:menuCategory="container"
|
android:menuCategory="container"
|
||||||
android:title="@string/sort"
|
android:title="@string/sort"
|
||||||
custom:showAsAction="never">
|
custom:showAsAction="always">
|
||||||
</item>
|
</item>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/refresh_item"
|
android:id="@+id/refresh_item"
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
android:id="@+id/visit_website_item"
|
android:id="@+id/visit_website_item"
|
||||||
android:icon="@drawable/ic_web"
|
android:icon="@drawable/ic_web"
|
||||||
android:menuCategory="container"
|
android:menuCategory="container"
|
||||||
custom:showAsAction="collapseActionView"
|
custom:showAsAction="ifRoom|collapseActionView"
|
||||||
android:title="@string/visit_website_label"
|
android:title="@string/visit_website_label"
|
||||||
android:visible="true">
|
android:visible="true">
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -58,8 +58,8 @@ class LocalFeedUpdaterTest {
|
||||||
init(context)
|
init(context)
|
||||||
|
|
||||||
val app = context as Application?
|
val app = context as Application?
|
||||||
ac.mdiq.podcini.util.config.ClientConfig.applicationCallbacks = Mockito.mock(ac.mdiq.podcini.util.config.ApplicationCallbacks::class.java)
|
ClientConfig.applicationCallbacks = Mockito.mock(ApplicationCallbacks::class.java)
|
||||||
Mockito.`when`(ac.mdiq.podcini.util.config.ClientConfig.applicationCallbacks?.getApplicationInstance()).thenReturn(app)
|
Mockito.`when`(ClientConfig.applicationCallbacks?.getApplicationInstance()).thenReturn(app)
|
||||||
DownloadServiceInterface.setImpl(DownloadServiceInterfaceStub())
|
DownloadServiceInterface.setImpl(DownloadServiceInterfaceStub())
|
||||||
|
|
||||||
// Initialize database
|
// Initialize database
|
||||||
|
|
|
@ -72,8 +72,8 @@ open class DbCleanupTests {
|
||||||
init(context)
|
init(context)
|
||||||
|
|
||||||
val app = context as Application?
|
val app = context as Application?
|
||||||
ac.mdiq.podcini.util.config.ClientConfig.applicationCallbacks = Mockito.mock(ac.mdiq.podcini.util.config.ApplicationCallbacks::class.java)
|
ClientConfig.applicationCallbacks = Mockito.mock(ApplicationCallbacks::class.java)
|
||||||
Mockito.`when`(ac.mdiq.podcini.util.config.ClientConfig.applicationCallbacks?.getApplicationInstance()).thenReturn(app)
|
Mockito.`when`(ClientConfig.applicationCallbacks?.getApplicationInstance()).thenReturn(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
@ -40,8 +40,8 @@ class DbTasksTest {
|
||||||
init(context)
|
init(context)
|
||||||
|
|
||||||
val app = context as Application?
|
val app = context as Application?
|
||||||
ac.mdiq.podcini.util.config.ClientConfig.applicationCallbacks = Mockito.mock(ac.mdiq.podcini.util.config.ApplicationCallbacks::class.java)
|
ClientConfig.applicationCallbacks = Mockito.mock(ApplicationCallbacks::class.java)
|
||||||
Mockito.`when`(ac.mdiq.podcini.util.config.ClientConfig.applicationCallbacks?.getApplicationInstance()).thenReturn(app)
|
Mockito.`when`(ClientConfig.applicationCallbacks?.getApplicationInstance()).thenReturn(app)
|
||||||
|
|
||||||
// create new database
|
// create new database
|
||||||
PodDBAdapter.init(context!!)
|
PodDBAdapter.init(context!!)
|
||||||
|
|
|
@ -64,8 +64,8 @@ class DbWriterTest {
|
||||||
init(context)
|
init(context)
|
||||||
|
|
||||||
val app = context as Application?
|
val app = context as Application?
|
||||||
ac.mdiq.podcini.util.config.ClientConfig.applicationCallbacks = Mockito.mock(ac.mdiq.podcini.util.config.ApplicationCallbacks::class.java)
|
ClientConfig.applicationCallbacks = Mockito.mock(ApplicationCallbacks::class.java)
|
||||||
Mockito.`when`(ac.mdiq.podcini.util.config.ClientConfig.applicationCallbacks?.getApplicationInstance()).thenReturn(app)
|
Mockito.`when`(ClientConfig.applicationCallbacks?.getApplicationInstance()).thenReturn(app)
|
||||||
DownloadServiceInterface.setImpl(DownloadServiceInterfaceStub())
|
DownloadServiceInterface.setImpl(DownloadServiceInterfaceStub())
|
||||||
|
|
||||||
// create new database
|
// create new database
|
||||||
|
|
12
changelog.md
12
changelog.md
|
@ -136,4 +136,14 @@
|
||||||
* vertical swipe no longer collapses the expanded view
|
* vertical swipe no longer collapses the expanded view
|
||||||
* only the down arrow on top left page collapses the expanded view
|
* only the down arrow on top left page collapses the expanded view
|
||||||
* share notes directly from expanded view of the player
|
* share notes directly from expanded view of the player
|
||||||
* in episode info, changed rendering of description, removed nested scroll
|
* in episode info, changed rendering of description, removed nested scroll
|
||||||
|
|
||||||
|
# 4.3.4
|
||||||
|
|
||||||
|
* fixed bug player disappear on first play
|
||||||
|
* more viewbinding GC enhancements
|
||||||
|
* added sort by feed title in downloads view
|
||||||
|
* more items on action bar in feed item list view
|
||||||
|
* some cleaning of redundant qualifiers
|
||||||
|
* sort dialog no longer dims the main view
|
||||||
|
* added random sort to feed items view
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
Version 4.3.4 brings several changes:
|
||||||
|
|
||||||
|
* fixed bug player disappear on first play
|
||||||
|
* more viewbinding GC enhancements
|
||||||
|
* added sort by feed title in downloads view
|
||||||
|
* more items on action bar in feed item list view
|
||||||
|
* some cleaning of redundant qualifiers
|
||||||
|
* sort dialog no longer dims the main view
|
||||||
|
* added random sort to feed items view
|
Loading…
Reference in New Issue