4.5.4 commit

This commit is contained in:
Xilin Jia 2024-04-04 17:30:30 +00:00
parent 15321d51e5
commit 9233a443de
17 changed files with 117 additions and 53 deletions

View File

@ -149,8 +149,8 @@ android {
// Version code schema (not used):
// "1.2.3-beta4" -> 1020304
// "1.2.3" -> 1020395
versionCode 3020123
versionName "4.5.3"
versionCode 3020124
versionName "4.5.4"
def commit = ""
try {

View File

@ -31,6 +31,8 @@ class TypeGetter {
reader = createReader(feed)
xpp.setInput(reader)
var eventType = xpp.eventType
// TODO: need to check about handling webpage
// return return Type.ATOM
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
@ -63,7 +65,9 @@ class TypeGetter {
Log.d(TAG, "Recognized type RSS 0.91/0.92")
return Type.RSS091
}
else -> throw UnsupportedFeedtypeException("Unsupported rss version")
else -> {
throw UnsupportedFeedtypeException("Unsupported rss version")
}
}
}
else -> {

View File

@ -26,8 +26,7 @@ object PlaybackSpeedUtils {
mediaType = media.getMediaType()
playbackSpeed = PlaybackPreferences.currentlyPlayingTemporaryPlaybackSpeed
// if (playbackSpeed == FeedPreferences.SPEED_USE_GLOBAL && media is FeedMedia) {
if (media is FeedMedia) {
if (playbackSpeed == FeedPreferences.SPEED_USE_GLOBAL && media is FeedMedia) {
val item = media.item
if (item != null) {
val feed = item.feed

View File

@ -13,6 +13,7 @@ import ac.mdiq.podcini.storage.model.feed.FeedMedia
import ac.mdiq.podcini.storage.model.playback.MediaType
import ac.mdiq.podcini.storage.model.playback.Playable
import ac.mdiq.podcini.playback.base.PlayerStatus
import ac.mdiq.podcini.preferences.UserPreferences
import android.content.*
import android.os.Build
import android.os.IBinder
@ -152,6 +153,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
if (service is LocalBinder) {
playbackService = service.service
onPlaybackServiceConnected()
if (!released) {
queryService()
Log.d(TAG, "Connection to Service established")
@ -243,6 +245,8 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
abstract fun loadMediaInfo()
open fun onPlaybackServiceConnected() { }
/**
* Called when connection to playback service has been established or
* information has to be refreshed
@ -342,10 +346,11 @@ abstract class PlaybackController(private val activity: FragmentActivity) {
playbackService?.setVideoSurface(holder)
}
fun setPlaybackSpeed(speed: Float, codeArray: Array<Int>? = null) {
fun setPlaybackSpeed(speed: Float, codeArray: BooleanArray? = null) {
if (playbackService != null) {
playbackService!!.setSpeed(speed, codeArray)
} else {
UserPreferences.setPlaybackSpeed(speed)
EventBus.getDefault().post(SpeedChangedEvent(speed))
}
}

View File

@ -1617,18 +1617,18 @@ class PlaybackService : MediaBrowserServiceCompat() {
val playable: Playable?
get() = mediaPlayer?.getPlayable()
fun setSpeed(speed: Float, codeArray: Array<Int>? = null) {
fun setSpeed(speed: Float, codeArray: BooleanArray? = null) {
isSpeedForward = false
isFallbackSpeed = false
currentlyPlayingTemporaryPlaybackSpeed = speed
if (currentMediaType == MediaType.VIDEO) {
currentlyPlayingTemporaryPlaybackSpeed = speed
videoPlaybackSpeed = speed
mediaPlayer?.setPlaybackParams(speed, isSkipSilence)
} else {
if (codeArray != null && codeArray.size == 3) {
if (codeArray[2] == 1) setPlaybackSpeed(speed)
if (codeArray[1] == 1 && playable is FeedMedia) {
if (codeArray[2]) setPlaybackSpeed(speed)
if (codeArray[1] && playable is FeedMedia) {
var item = (playable as FeedMedia).item
if (item == null) {
val itemId = (playable as FeedMedia).itemId
@ -1651,10 +1651,15 @@ class PlaybackService : MediaBrowserServiceCompat() {
}
}
}
if (codeArray[0]) {
currentlyPlayingTemporaryPlaybackSpeed = speed
mediaPlayer?.setPlaybackParams(speed, isSkipSilence)
}
} else {
currentlyPlayingTemporaryPlaybackSpeed = speed
mediaPlayer?.setPlaybackParams(speed, isSkipSilence)
}
}
mediaPlayer?.setPlaybackParams(speed, isSkipSilence)
}
fun speedForward(speed: Float) {

View File

@ -11,8 +11,8 @@ class PlaybackSpeedDialogActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(getTranslucentTheme(this))
super.onCreate(savedInstanceState)
val speedDialog: VariableSpeedDialog = InnerVariableSpeedDialog()
speedDialog.show(supportFragmentManager, null)
val speedDialog: VariableSpeedDialog? = VariableSpeedDialog.newInstance(booleanArrayOf(false, false, true), 2)
speedDialog?.show(supportFragmentManager, null)
}
class InnerVariableSpeedDialog : VariableSpeedDialog() {

View File

@ -609,7 +609,7 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
shareDialog.show(supportFragmentManager, "ShareEpisodeDialog")
}
item.itemId == R.id.playback_speed -> {
VariableSpeedDialog().show(supportFragmentManager, null)
VariableSpeedDialog.newInstance(booleanArrayOf(true, false, true))?.show(supportFragmentManager, null)
}
else -> {
return false

View File

@ -12,6 +12,7 @@ import android.view.LayoutInflater
import androidx.media3.common.util.UnstableApi
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.lang.ref.WeakReference
import kotlin.math.round
@UnstableApi
class EditFallbackSpeedDialog(activity: Activity) {
@ -32,7 +33,7 @@ import java.lang.ref.WeakReference
speed < 0.0f -> speed = 0.0f
speed > 3.0f -> speed = 3.0f
}
fallbackSpeed = String.format("%.2f", speed).toFloat()
fallbackSpeed = round(100 * speed) / 100
}
.setNegativeButton(R.string.cancel_label, null)
.show()

View File

@ -12,6 +12,7 @@ import android.view.LayoutInflater
import androidx.media3.common.util.UnstableApi
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.lang.ref.WeakReference
import kotlin.math.round
@UnstableApi
class EditForwardSpeedDialog(activity: Activity) {
@ -33,7 +34,7 @@ import java.lang.ref.WeakReference
speed < 0.0f -> speed = 0.0f
speed > 10.0f -> speed = 10.0f
}
speedforwardSpeed = String.format("%.1f", speed).toFloat()
speedforwardSpeed = round(10 * speed) / 10
}
.setNegativeButton(R.string.cancel_label, null)
.show()

View File

@ -11,6 +11,7 @@ import ac.mdiq.podcini.ui.view.PlaybackSpeedSeekBar
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -40,7 +41,7 @@ open class VariableSpeedDialog : BottomSheetDialogFragment() {
private var controller: PlaybackController? = null
private val selectedSpeeds: MutableList<Float>
private val settingCode: Array<Int> = Array(3) { 0 }
private lateinit var settingCode: BooleanArray
init {
val format = DecimalFormatSymbols(Locale.US)
@ -50,14 +51,23 @@ open class VariableSpeedDialog : BottomSheetDialogFragment() {
@UnstableApi override fun onStart() {
super.onStart()
if (controller == null) {
controller = object : PlaybackController(requireActivity()) {
override fun loadMediaInfo() {
if (controller != null) updateSpeed(SpeedChangedEvent(controller!!.currentPlaybackSpeedMultiplier))
}
controller = object : PlaybackController(requireActivity()) {
override fun loadMediaInfo() {
if (controller != null) updateSpeed(SpeedChangedEvent(controller!!.currentPlaybackSpeedMultiplier))
}
override fun onPlaybackServiceConnected() {
super.onPlaybackServiceConnected()
binding.currentAudio.visibility = View.VISIBLE
binding.currentPodcast.visibility = View.VISIBLE
if (!settingCode[0]) binding.currentAudio.visibility = View.INVISIBLE
if (!settingCode[1]) binding.currentPodcast.visibility = View.INVISIBLE
if (!settingCode[2]) binding.global.visibility = View.INVISIBLE
}
controller?.init()
}
controller?.init()
EventBus.getDefault().register(this)
if (controller != null) updateSpeed(SpeedChangedEvent(controller!!.currentPlaybackSpeedMultiplier))
}
@ -80,23 +90,28 @@ open class VariableSpeedDialog : BottomSheetDialogFragment() {
): View? {
_binding = SpeedSelectDialogBinding.inflate(inflater)
val argument = arguments?.getString("default_setting")
settingCode = (arguments?.getBooleanArray("settingCode") ?: BooleanArray(3) {true})
val index_default = arguments?.getInt("index_default")
when (argument) {
null, "Current" -> {
when (index_default) {
null, 0 -> {
binding.currentAudio.isChecked = true
}
"Feed" -> {
1 -> {
binding.currentPodcast.isChecked = true
}
else -> {
binding.global.isChecked = true
}
}
// if (!settingCode[0]) binding.currentAudio.visibility = View.INVISIBLE
// if (!settingCode[1]) binding.currentPodcast.visibility = View.INVISIBLE
// if (!settingCode[2]) binding.global.visibility = View.INVISIBLE
speedSeekBar = binding.speedSeekBar
speedSeekBar.setProgressChangedListener { multiplier: Float ->
controller?.setPlaybackSpeed(multiplier)
addCurrentSpeedChip.text = String.format(Locale.getDefault(), "%1$.2f", multiplier)
// controller?.setPlaybackSpeed(multiplier)
}
val selectedSpeedsGrid = binding.selectedSpeedsGrid
selectedSpeedsGrid.layoutManager = GridLayoutManager(context, 3)
@ -124,9 +139,13 @@ open class VariableSpeedDialog : BottomSheetDialogFragment() {
@OptIn(UnstableApi::class) override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// if (controller == null || !controller!!.isPlaybackServiceReady()) {
// binding.currentPodcast.visibility = View.INVISIBLE
// } else binding.currentPodcast.visibility = View.VISIBLE
if (controller == null || !controller!!.isPlaybackServiceReady()) {
binding.currentAudio.visibility = View.INVISIBLE
binding.currentPodcast.visibility = View.INVISIBLE
} else {
binding.currentAudio.visibility = View.VISIBLE
binding.currentPodcast.visibility = View.VISIBLE
}
}
override fun onDestroyView() {
@ -165,9 +184,9 @@ open class VariableSpeedDialog : BottomSheetDialogFragment() {
true
}
holder.chip.setOnClickListener { Handler(Looper.getMainLooper()).postDelayed({
if (binding.currentAudio.isChecked) settingCode[0] = 1
if (binding.currentPodcast.isChecked) settingCode[1] = 1
if (binding.global.isChecked) settingCode[2] = 1
if (binding.currentAudio.isChecked) settingCode[0] = true
if (binding.currentPodcast.isChecked) settingCode[1] = true
if (binding.global.isChecked) settingCode[2] = true
if (controller != null) {
dismiss()
@ -189,13 +208,18 @@ open class VariableSpeedDialog : BottomSheetDialogFragment() {
}
companion object {
fun newInstance(argument: String? = null): VariableSpeedDialog {
val dialog = VariableSpeedDialog()
if (argument != null) {
val args = Bundle()
args.putString("default_setting", argument)
dialog.arguments = args
fun newInstance(settingCode_: BooleanArray? = null, index_default: Int? = null): VariableSpeedDialog? {
val settingCode = settingCode_ ?: BooleanArray(3){false}
if (settingCode.size != 3) {
Log.e("VariableSpeedDialog", "wrong settingCode dimension")
return null
}
val dialog = VariableSpeedDialog()
val args = Bundle()
args.putBooleanArray("settingCode", settingCode)
if (index_default != null) args.putInt("index_default", index_default)
dialog.arguments = args
return dialog
}
}

View File

@ -500,7 +500,7 @@ class AudioPlayerFragment : Fragment(), SeekBar.OnSeekBarChangeListener, Toolbar
setupLengthTextView()
setupControlButtons()
butPlaybackSpeed.setOnClickListener {
VariableSpeedDialog.newInstance(null).show(childFragmentManager, null)
VariableSpeedDialog.newInstance(booleanArrayOf(true, true, true), null)?.show(childFragmentManager, null)
}
sbPosition.setOnSeekBarChangeListener(this)

View File

@ -64,6 +64,7 @@ import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.jsoup.Jsoup
import java.io.File
import java.io.IOException
import kotlin.concurrent.Volatile
@ -330,6 +331,16 @@ class OnlineFeedViewFragment : Fragment() {
Log.d(TAG, "Unsupported feed type detected")
if ("html".equals(e.rootElement, ignoreCase = true)) {
if (selectedDownloadUrl != null) {
val doc = Jsoup.connect(selectedDownloadUrl).get()
val linkElements = doc.select("link[type=application/rss+xml]")
for (element in linkElements) {
val rssUrl = element.attr("href")
Log.d(TAG, "RSS URL: $rssUrl")
val rc = destinationFile.delete()
Log.d(TAG, "Deleted feed source file. Result: $rc")
startFeedDownload(rssUrl)
return null
}
val dialogShown = showFeedDiscoveryDialog(destinationFile, selectedDownloadUrl!!)
if (dialogShown) {
null // Should not display an error message

View File

@ -39,7 +39,7 @@ class PlaybackPreferencesFragment : PreferenceFragmentCompat() {
findPreference<Preference>(PREF_PLAYBACK_SPEED_LAUNCHER)!!.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
VariableSpeedDialog.newInstance("Global").show(childFragmentManager, null)
VariableSpeedDialog.newInstance(booleanArrayOf(false, false, true),2)?.show(childFragmentManager, null)
true
}
findPreference<Preference>(PREF_PLAYBACK_REWIND_DELTA_LAUNCHER)!!.onPreferenceClickListener =

View File

@ -64,12 +64,12 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_height="80dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/imgvCover"
android:layout_width="75dp"
android:layout_width="80dp"
android:layout_height="match_parent"
android:cropToPadding="true"
android:scaleType="fitCenter"
@ -127,9 +127,8 @@
android:layout_alignLeft="@id/butRev"
android:layout_alignEnd="@id/butRev"
android:layout_alignRight="@id/butRev"
android:layout_marginBottom="5dp"
android:clickable="false"
android:gravity="center"
android:gravity="center_horizontal"
android:text="30"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp" />
@ -158,7 +157,6 @@
android:layout_alignLeft="@id/butPlaybackSpeed"
android:layout_alignEnd="@id/butPlaybackSpeed"
android:layout_alignRight="@id/butPlaybackSpeed"
android:layout_marginBottom="5dp"
android:clickable="false"
android:gravity="center"
android:text="1.00"
@ -191,7 +189,6 @@
android:layout_alignLeft="@id/butFF"
android:layout_alignEnd="@id/butFF"
android:layout_alignRight="@id/butFF"
android:layout_marginBottom="5dp"
android:clickable="false"
android:gravity="center"
android:text="30"
@ -224,7 +221,6 @@
android:layout_alignLeft="@id/butSkip"
android:layout_alignEnd="@id/butSkip"
android:layout_alignRight="@id/butSkip"
android:layout_marginBottom="5dp"
android:clickable="false"
android:gravity="center"
android:textColor="?android:attr/textColorSecondary"

View File

@ -5,7 +5,7 @@
<dimen name="drawer_corner_size">16dp</dimen>
<dimen name="widget_margin">0dp</dimen>
<dimen name="widget_inner_radius">4dp</dimen>
<dimen name="external_player_height">130dp</dimen>
<dimen name="external_player_height">135dp</dimen>
<dimen name="text_size_micro">12sp</dimen>
<dimen name="text_size_small">14sp</dimen>
<dimen name="text_size_navdrawer">16sp</dimen>

View File

@ -215,4 +215,13 @@
* corrected wrong caption of "Edit fallback speed"
* adjusted layout and button dimension and alignments in the bottom player control
* fallback speed setting is now capped at 0.0 and 3.0 and allows for 2-digit precision
* corrected episode count display in subscriptions list when the feed has 0 episodes
* corrected episode count display in subscriptions list when the feed has 0 episodes
## 4.5.4
* fixed crash bug when setting fallback or fast-forward speeds with some Locales
* further enlarged height of the bottom player control to improve on missing pixels at the bottom
* on speed setting dialog, only tap on a preset chip sets the speed, only selected options will be set
* corrected the handling of current audio speed:
* when speed for current audio is not set, podcast speed takes precedence
* when speed for current audio is set, it takes precedence for the current audio (episode), even with pause/re-play

View File

@ -0,0 +1,9 @@
Version 4.5.3 brings several changes:
* fixed crash bug when setting fallback or fast-forward speeds with some Locales
* further enlarged height of the bottom player control to improve on missing pixels at the bottom
* on speed setting dialog, only tap on a preset chip sets the speed, only selected options will be set
* corrected the handling of current audio speed:
* when speed for current audio is not set, podcast speed takes precedence
* when speed for current audio is set, it takes precedence for the current audio (episode), even with pause/re-play