notes share and faster episode open
This commit is contained in:
parent
b4badaf059
commit
d5b5734712
|
@ -149,8 +149,8 @@ android {
|
|||
// Version code schema (not used):
|
||||
// "1.2.3-beta4" -> 1020304
|
||||
// "1.2.3" -> 1020395
|
||||
versionCode 3020109
|
||||
versionName "4.2.6"
|
||||
versionCode 3020110
|
||||
versionName "4.2.7"
|
||||
|
||||
def commit = ""
|
||||
try {
|
||||
|
@ -168,10 +168,9 @@ android {
|
|||
buildConfigField "String", "PODCASTINDEX_API_KEY", '"' + podcastindexApiKey + '"'
|
||||
buildConfigField "String", "PODCASTINDEX_API_SECRET", '"' + podcastindexApiSecret + '"'
|
||||
} else {
|
||||
buildConfigField "String", "PODCASTINDEX_API_KEY", '"XTMMQGA2YZ4WJUBYY4HK"'
|
||||
buildConfigField "String", "PODCASTINDEX_API_SECRET", '"XAaAhk4^2YBsTE33vdbwbZNj82ZRLABDDqFdKe7x"'
|
||||
buildConfigField "String", "PODCASTINDEX_API_KEY", '"QT2RYHSUZ3UC9GDJ5MFY"'
|
||||
buildConfigField "String", "PODCASTINDEX_API_SECRET", '"Zw2NL74ht5aCtx5zFL$#MY$##qdVCX7x37jq95Sz"'
|
||||
}
|
||||
|
||||
}
|
||||
signingConfigs {
|
||||
releaseConfig {
|
||||
|
@ -295,7 +294,6 @@ dependencies {
|
|||
testImplementation "org.robolectric:robolectric:4.11.1"
|
||||
testImplementation 'javax.inject:javax.inject:1'
|
||||
|
||||
|
||||
playImplementation 'com.google.android.gms:play-services-base:18.3.0'
|
||||
freeImplementation 'org.conscrypt:conscrypt-android:2.5.2'
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ import org.greenrobot.eventbus.ThreadMode
|
|||
@UnstableApi
|
||||
class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
||||
|
||||
private lateinit var viewBinding: VideoplayerActivityBinding
|
||||
private lateinit var binding: VideoplayerActivityBinding
|
||||
|
||||
/**
|
||||
* True if video controls are currently visible.
|
||||
|
@ -89,14 +89,17 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
setTheme(R.style.Theme_Podcini_VideoPlayer)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
Log.d(TAG, "onCreate()")
|
||||
|
||||
window.setFormat(PixelFormat.TRANSPARENT)
|
||||
viewBinding = VideoplayerActivityBinding.inflate(LayoutInflater.from(this))
|
||||
setContentView(viewBinding.root)
|
||||
binding = VideoplayerActivityBinding.inflate(LayoutInflater.from(this))
|
||||
setContentView(binding.root)
|
||||
setupView()
|
||||
supportActionBar?.setBackgroundDrawable(ColorDrawable(-0x80000000))
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
controller = newPlaybackController()
|
||||
controller!!.init()
|
||||
loadMediaInfo()
|
||||
// EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
@UnstableApi
|
||||
|
@ -105,7 +108,7 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
switchToAudioOnly = false
|
||||
if (isCasting) {
|
||||
val intent = getPlayerActivityIntent(this)
|
||||
if (intent.component!!.className != VideoplayerActivity::class.java.name) {
|
||||
if (intent.component?.className != VideoplayerActivity::class.java.name) {
|
||||
destroyingDueToReload = true
|
||||
finish()
|
||||
startActivity(intent)
|
||||
|
@ -113,19 +116,28 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
}
|
||||
}
|
||||
|
||||
@UnstableApi
|
||||
override fun onStop() {
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
controller?.release()
|
||||
controller = null // prevent leak
|
||||
disposable?.dispose()
|
||||
|
||||
// EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
@UnstableApi
|
||||
override fun onStop() {
|
||||
// controller?.release()
|
||||
// controller = null // prevent leak
|
||||
// disposable?.dispose()
|
||||
|
||||
EventBus.getDefault().unregister(this)
|
||||
super.onStop()
|
||||
if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||
videoControlsHider.removeCallbacks(hideVideoControls)
|
||||
}
|
||||
// Controller released; we will not receive buffering updates
|
||||
viewBinding.progressBar.visibility = View.GONE
|
||||
binding.progressBar.visibility = View.GONE
|
||||
}
|
||||
|
||||
public override fun onUserLeaveHint() {
|
||||
|
@ -137,9 +149,6 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
@UnstableApi
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
controller = newPlaybackController()
|
||||
controller!!.init()
|
||||
loadMediaInfo()
|
||||
onPositionObserverUpdate()
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
@ -147,7 +156,7 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
@UnstableApi
|
||||
override fun onPause() {
|
||||
if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||
if (controller != null && controller!!.status == PlayerStatus.PLAYING) {
|
||||
if (controller?.status == PlayerStatus.PLAYING) {
|
||||
controller!!.pause()
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +177,7 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
private fun newPlaybackController(): PlaybackController {
|
||||
return object : PlaybackController(this@VideoplayerActivity) {
|
||||
override fun updatePlayButtonShowsPlay(showPlay: Boolean) {
|
||||
viewBinding.playButton.setIsShowPlay(showPlay)
|
||||
binding.playButton.setIsShowPlay(showPlay)
|
||||
if (showPlay) {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
} else {
|
||||
|
@ -176,7 +185,7 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
setupVideoAspectRatio()
|
||||
if (videoSurfaceCreated && controller != null) {
|
||||
Log.d(TAG, "Videosurface already created, setting videosurface now")
|
||||
controller!!.setVideoSurface(viewBinding.videoView.holder)
|
||||
controller!!.setVideoSurface(binding.videoView.holder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,11 +204,11 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
@Suppress("unused")
|
||||
fun bufferUpdate(event: BufferUpdateEvent) {
|
||||
if (event.hasStarted()) {
|
||||
viewBinding.progressBar.visibility = View.VISIBLE
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
} else if (event.hasEnded()) {
|
||||
viewBinding.progressBar.visibility = View.INVISIBLE
|
||||
binding.progressBar.visibility = View.INVISIBLE
|
||||
} else {
|
||||
viewBinding.sbPosition.secondaryProgress = (event.progress * viewBinding.sbPosition.max).toInt()
|
||||
binding.sbPosition.secondaryProgress = (event.progress * binding.sbPosition.max).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,9 +223,8 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
@UnstableApi
|
||||
private fun loadMediaInfo() {
|
||||
Log.d(TAG, "loadMediaInfo()")
|
||||
if (controller?.getMedia() == null) {
|
||||
return
|
||||
}
|
||||
if (controller?.getMedia() == null) return
|
||||
|
||||
if (controller!!.status == PlayerStatus.PLAYING && !controller!!.isPlayingVideoLocally) {
|
||||
Log.d(TAG, "Closing, no longer video")
|
||||
destroyingDueToReload = true
|
||||
|
@ -238,7 +246,7 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
private fun setupView() {
|
||||
showTimeLeft = shouldShowRemainingTime()
|
||||
Log.d("timeleft", if (showTimeLeft) "true" else "false")
|
||||
viewBinding.durationLabel.setOnClickListener {
|
||||
binding.durationLabel.setOnClickListener {
|
||||
showTimeLeft = !showTimeLeft
|
||||
val media = controller?.getMedia() ?: return@setOnClickListener
|
||||
|
||||
|
@ -251,41 +259,41 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
val duration = converter.convert(media.getDuration())
|
||||
length = getDurationStringLong(duration)
|
||||
}
|
||||
viewBinding.durationLabel.text = length
|
||||
binding.durationLabel.text = length
|
||||
|
||||
setShowRemainTimeSetting(showTimeLeft)
|
||||
Log.d("timeleft on click", if (showTimeLeft) "true" else "false")
|
||||
}
|
||||
|
||||
viewBinding.sbPosition.setOnSeekBarChangeListener(this)
|
||||
viewBinding.rewindButton.setOnClickListener { onRewind() }
|
||||
viewBinding.rewindButton.setOnLongClickListener {
|
||||
binding.sbPosition.setOnSeekBarChangeListener(this)
|
||||
binding.rewindButton.setOnClickListener { onRewind() }
|
||||
binding.rewindButton.setOnLongClickListener {
|
||||
SkipPreferenceDialog.showSkipPreference(this@VideoplayerActivity,
|
||||
SkipPreferenceDialog.SkipDirection.SKIP_REWIND, null)
|
||||
true
|
||||
}
|
||||
viewBinding.playButton.setIsVideoScreen(true)
|
||||
viewBinding.playButton.setOnClickListener { onPlayPause() }
|
||||
viewBinding.fastForwardButton.setOnClickListener { onFastForward() }
|
||||
viewBinding.fastForwardButton.setOnLongClickListener {
|
||||
binding.playButton.setIsVideoScreen(true)
|
||||
binding.playButton.setOnClickListener { onPlayPause() }
|
||||
binding.fastForwardButton.setOnClickListener { onFastForward() }
|
||||
binding.fastForwardButton.setOnLongClickListener {
|
||||
SkipPreferenceDialog.showSkipPreference(this@VideoplayerActivity,
|
||||
SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, null)
|
||||
false
|
||||
}
|
||||
// To suppress touches directly below the slider
|
||||
viewBinding.bottomControlsContainer.setOnTouchListener { _: View?, _: MotionEvent? -> true }
|
||||
viewBinding.bottomControlsContainer.fitsSystemWindows = true
|
||||
viewBinding.videoView.holder.addCallback(surfaceHolderCallback)
|
||||
viewBinding.videoView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
binding.bottomControlsContainer.setOnTouchListener { _: View?, _: MotionEvent? -> true }
|
||||
binding.bottomControlsContainer.fitsSystemWindows = true
|
||||
binding.videoView.holder.addCallback(surfaceHolderCallback)
|
||||
binding.videoView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
|
||||
setupVideoControlsToggler()
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
|
||||
viewBinding.videoPlayerContainer.setOnTouchListener(onVideoviewTouched)
|
||||
viewBinding.videoPlayerContainer.viewTreeObserver.addOnGlobalLayoutListener {
|
||||
viewBinding.videoView.setAvailableSize(
|
||||
viewBinding.videoPlayerContainer.width.toFloat(), viewBinding.videoPlayerContainer.height.toFloat())
|
||||
binding.videoPlayerContainer.setOnTouchListener(onVideoviewTouched)
|
||||
binding.videoPlayerContainer.viewTreeObserver.addOnGlobalLayoutListener {
|
||||
binding.videoView.setAvailableSize(
|
||||
binding.videoPlayerContainer.width.toFloat(), binding.videoPlayerContainer.height.toFloat())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,24 +348,24 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
skipAnimation.fillAfter = false
|
||||
skipAnimation.duration = 800
|
||||
|
||||
val params = viewBinding.skipAnimationImage.layoutParams as FrameLayout.LayoutParams
|
||||
val params = binding.skipAnimationImage.layoutParams as FrameLayout.LayoutParams
|
||||
if (isForward) {
|
||||
viewBinding.skipAnimationImage.setImageResource(R.drawable.ic_fast_forward_video_white)
|
||||
binding.skipAnimationImage.setImageResource(R.drawable.ic_fast_forward_video_white)
|
||||
params.gravity = Gravity.RIGHT or Gravity.CENTER_VERTICAL
|
||||
} else {
|
||||
viewBinding.skipAnimationImage.setImageResource(R.drawable.ic_fast_rewind_video_white)
|
||||
binding.skipAnimationImage.setImageResource(R.drawable.ic_fast_rewind_video_white)
|
||||
params.gravity = Gravity.LEFT or Gravity.CENTER_VERTICAL
|
||||
}
|
||||
|
||||
viewBinding.skipAnimationImage.visibility = View.VISIBLE
|
||||
viewBinding.skipAnimationImage.layoutParams = params
|
||||
viewBinding.skipAnimationImage.startAnimation(skipAnimation)
|
||||
binding.skipAnimationImage.visibility = View.VISIBLE
|
||||
binding.skipAnimationImage.layoutParams = params
|
||||
binding.skipAnimationImage.startAnimation(skipAnimation)
|
||||
skipAnimation.setAnimationListener(object : Animation.AnimationListener {
|
||||
override fun onAnimationStart(animation: Animation) {
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animation) {
|
||||
viewBinding.skipAnimationImage.visibility = View.GONE
|
||||
binding.skipAnimationImage.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animation: Animation) {
|
||||
|
@ -376,7 +384,7 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
val videoSize = controller!!.videoSize
|
||||
if (videoSize != null && videoSize.first > 0 && videoSize.second > 0) {
|
||||
Log.d(TAG, "Width,height of video: " + videoSize.first + ", " + videoSize.second)
|
||||
viewBinding.videoView.setVideoSize(videoSize.first, videoSize.second)
|
||||
binding.videoView.setVideoSize(videoSize.first, videoSize.second)
|
||||
} else {
|
||||
Log.e(TAG, "Could not determine video size")
|
||||
}
|
||||
|
@ -396,9 +404,8 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
|
||||
@UnstableApi
|
||||
fun onRewind() {
|
||||
if (controller == null) {
|
||||
return
|
||||
}
|
||||
if (controller == null) return
|
||||
|
||||
val curr = controller!!.position
|
||||
controller!!.seekTo(curr - rewindSecs * 1000)
|
||||
setupVideoControlsToggler()
|
||||
|
@ -406,18 +413,16 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
|
||||
@UnstableApi
|
||||
fun onPlayPause() {
|
||||
if (controller == null) {
|
||||
return
|
||||
}
|
||||
if (controller == null) return
|
||||
|
||||
controller!!.playPause()
|
||||
setupVideoControlsToggler()
|
||||
}
|
||||
|
||||
@UnstableApi
|
||||
fun onFastForward() {
|
||||
if (controller == null) {
|
||||
return
|
||||
}
|
||||
if (controller == null) return
|
||||
|
||||
val curr = controller!!.position
|
||||
controller!!.seekTo(curr + fastForwardSecs * 1000)
|
||||
setupVideoControlsToggler()
|
||||
|
@ -448,31 +453,31 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
}
|
||||
|
||||
private fun showVideoControls() {
|
||||
viewBinding.bottomControlsContainer.visibility = View.VISIBLE
|
||||
viewBinding.controlsContainer.visibility = View.VISIBLE
|
||||
binding.bottomControlsContainer.visibility = View.VISIBLE
|
||||
binding.controlsContainer.visibility = View.VISIBLE
|
||||
val animation = AnimationUtils.loadAnimation(this, R.anim.fade_in)
|
||||
if (animation != null) {
|
||||
viewBinding.bottomControlsContainer.startAnimation(animation)
|
||||
viewBinding.controlsContainer.startAnimation(animation)
|
||||
binding.bottomControlsContainer.startAnimation(animation)
|
||||
binding.controlsContainer.startAnimation(animation)
|
||||
}
|
||||
viewBinding.videoView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
|
||||
binding.videoView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
|
||||
}
|
||||
|
||||
private fun hideVideoControls(showAnimation: Boolean) {
|
||||
if (showAnimation) {
|
||||
val animation = AnimationUtils.loadAnimation(this, R.anim.fade_out)
|
||||
if (animation != null) {
|
||||
viewBinding.bottomControlsContainer.startAnimation(animation)
|
||||
viewBinding.controlsContainer.startAnimation(animation)
|
||||
binding.bottomControlsContainer.startAnimation(animation)
|
||||
binding.controlsContainer.startAnimation(animation)
|
||||
}
|
||||
}
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)
|
||||
viewBinding.bottomControlsContainer.fitsSystemWindows = true
|
||||
binding.bottomControlsContainer.fitsSystemWindows = true
|
||||
|
||||
viewBinding.bottomControlsContainer.visibility = View.GONE
|
||||
viewBinding.controlsContainer.visibility = View.GONE
|
||||
binding.bottomControlsContainer.visibility = View.GONE
|
||||
binding.controlsContainer.visibility = View.GONE
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
@ -515,9 +520,8 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
@UnstableApi
|
||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
if (controller == null) {
|
||||
return false
|
||||
}
|
||||
if (controller == null) return false
|
||||
|
||||
val media = controller!!.getMedia()
|
||||
val isFeedMedia = (media is FeedMedia)
|
||||
|
||||
|
@ -573,33 +577,42 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
else -> {
|
||||
val media = controller?.getMedia() ?: return false
|
||||
val feedItem = getFeedItem(media) // some options option requires FeedItem
|
||||
if (item.itemId == R.id.add_to_favorites_item && feedItem != null) {
|
||||
DBWriter.addFavoriteItem(feedItem)
|
||||
isFavorite = true
|
||||
invalidateOptionsMenu()
|
||||
} else if (item.itemId == R.id.remove_from_favorites_item && feedItem != null) {
|
||||
DBWriter.removeFavoriteItem(feedItem)
|
||||
isFavorite = false
|
||||
invalidateOptionsMenu()
|
||||
} else if (item.itemId == R.id.disable_sleeptimer_item
|
||||
|| item.itemId == R.id.set_sleeptimer_item) {
|
||||
SleepTimerDialog().show(supportFragmentManager, "SleepTimerDialog")
|
||||
} else if (item.itemId == R.id.audio_controls) {
|
||||
val dialog = PlaybackControlsDialog.newInstance()
|
||||
dialog.show(supportFragmentManager, "playback_controls")
|
||||
} else if (item.itemId == R.id.open_feed_item && feedItem != null) {
|
||||
val intent = MainActivity.getIntentToOpenFeed(this, feedItem.feedId)
|
||||
startActivity(intent)
|
||||
} else if (item.itemId == R.id.visit_website_item) {
|
||||
val url = getWebsiteLinkWithFallback(media)
|
||||
if (url != null) openInBrowser(this@VideoplayerActivity, url)
|
||||
} else if (item.itemId == R.id.share_item && feedItem != null) {
|
||||
val shareDialog = ShareDialog.newInstance(feedItem)
|
||||
shareDialog.show(supportFragmentManager, "ShareEpisodeDialog")
|
||||
} else if (item.itemId == R.id.playback_speed) {
|
||||
VariableSpeedDialog().show(supportFragmentManager, null)
|
||||
} else {
|
||||
return false
|
||||
when {
|
||||
item.itemId == R.id.add_to_favorites_item && feedItem != null -> {
|
||||
DBWriter.addFavoriteItem(feedItem)
|
||||
isFavorite = true
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
item.itemId == R.id.remove_from_favorites_item && feedItem != null -> {
|
||||
DBWriter.removeFavoriteItem(feedItem)
|
||||
isFavorite = false
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
item.itemId == R.id.disable_sleeptimer_item || item.itemId == R.id.set_sleeptimer_item -> {
|
||||
SleepTimerDialog().show(supportFragmentManager, "SleepTimerDialog")
|
||||
}
|
||||
item.itemId == R.id.audio_controls -> {
|
||||
val dialog = PlaybackControlsDialog.newInstance()
|
||||
dialog.show(supportFragmentManager, "playback_controls")
|
||||
}
|
||||
item.itemId == R.id.open_feed_item && feedItem != null -> {
|
||||
val intent = MainActivity.getIntentToOpenFeed(this, feedItem.feedId)
|
||||
startActivity(intent)
|
||||
}
|
||||
item.itemId == R.id.visit_website_item -> {
|
||||
val url = getWebsiteLinkWithFallback(media)
|
||||
if (url != null) openInBrowser(this@VideoplayerActivity, url)
|
||||
}
|
||||
item.itemId == R.id.share_item && feedItem != null -> {
|
||||
val shareDialog = ShareDialog.newInstance(feedItem)
|
||||
shareDialog.show(supportFragmentManager, "ShareEpisodeDialog")
|
||||
}
|
||||
item.itemId == R.id.playback_speed -> {
|
||||
VariableSpeedDialog().show(supportFragmentManager, null)
|
||||
}
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -607,9 +620,7 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
}
|
||||
|
||||
fun onPositionObserverUpdate() {
|
||||
if (controller == null) {
|
||||
return
|
||||
}
|
||||
if (controller == null) return
|
||||
|
||||
val converter = TimeSpeedConverter(controller!!.currentPlaybackSpeedMultiplier)
|
||||
val currentPosition = converter.convert(controller!!.position)
|
||||
|
@ -617,16 +628,15 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
val remainingTime = converter.convert(
|
||||
controller!!.duration - controller!!.position)
|
||||
// Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
|
||||
if (currentPosition == Playable.INVALID_TIME
|
||||
|| duration == Playable.INVALID_TIME) {
|
||||
if (currentPosition == Playable.INVALID_TIME || duration == Playable.INVALID_TIME) {
|
||||
Log.w(TAG, "Could not react to position observer update because of invalid time")
|
||||
return
|
||||
}
|
||||
viewBinding.positionLabel.text = getDurationStringLong(currentPosition)
|
||||
binding.positionLabel.text = getDurationStringLong(currentPosition)
|
||||
if (showTimeLeft) {
|
||||
viewBinding.durationLabel.text = "-" + getDurationStringLong(remainingTime)
|
||||
binding.durationLabel.text = "-" + getDurationStringLong(remainingTime)
|
||||
} else {
|
||||
viewBinding.durationLabel.text = getDurationStringLong(duration)
|
||||
binding.durationLabel.text = getDurationStringLong(duration)
|
||||
}
|
||||
updateProgressbarPosition(currentPosition, duration)
|
||||
}
|
||||
|
@ -634,25 +644,24 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
private fun updateProgressbarPosition(position: Int, duration: Int) {
|
||||
Log.d(TAG, "updateProgressbarPosition($position, $duration)")
|
||||
val progress = (position.toFloat()) / duration
|
||||
viewBinding.sbPosition.progress = (progress * viewBinding.sbPosition.max).toInt()
|
||||
binding.sbPosition.progress = (progress * binding.sbPosition.max).toInt()
|
||||
}
|
||||
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
if (controller == null) {
|
||||
return
|
||||
}
|
||||
if (controller == null) return
|
||||
|
||||
if (fromUser) {
|
||||
prog = progress / (seekBar.max.toFloat())
|
||||
val converter = TimeSpeedConverter(controller!!.currentPlaybackSpeedMultiplier)
|
||||
val position = converter.convert((prog * controller!!.duration).toInt())
|
||||
viewBinding.seekPositionLabel.text = getDurationStringLong(position)
|
||||
binding.seekPositionLabel.text = getDurationStringLong(position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||
viewBinding.seekCardView.scaleX = .8f
|
||||
viewBinding.seekCardView.scaleY = .8f
|
||||
viewBinding.seekCardView.animate()
|
||||
binding.seekCardView.scaleX = .8f
|
||||
binding.seekCardView.scaleY = .8f
|
||||
binding.seekCardView.animate()
|
||||
.setInterpolator(FastOutSlowInInterpolator())
|
||||
.alpha(1f).scaleX(1f).scaleY(1f)
|
||||
.setDuration(200)
|
||||
|
@ -664,9 +673,9 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
if (controller != null) {
|
||||
controller!!.seekTo((prog * controller!!.duration).toInt())
|
||||
}
|
||||
viewBinding.seekCardView.scaleX = 1f
|
||||
viewBinding.seekCardView.scaleY = 1f
|
||||
viewBinding.seekCardView.animate()
|
||||
binding.seekCardView.scaleX = 1f
|
||||
binding.seekCardView.scaleY = 1f
|
||||
binding.seekCardView.animate()
|
||||
.setInterpolator(FastOutSlowInInterpolator())
|
||||
.alpha(0f).scaleX(.8f).scaleY(.8f)
|
||||
.setDuration(200)
|
||||
|
@ -763,14 +772,18 @@ class VideoplayerActivity : CastEnabledActivity(), OnSeekBarChangeListener {
|
|||
private const val TAG = "VideoplayerActivity"
|
||||
|
||||
private fun getWebsiteLinkWithFallback(media: Playable?): String? {
|
||||
if (media == null) {
|
||||
return null
|
||||
} else if (!media.getWebsiteLink().isNullOrBlank()) {
|
||||
return media.getWebsiteLink()
|
||||
} else if (media is FeedMedia) {
|
||||
return getLinkWithFallback(media.getItem())
|
||||
when {
|
||||
media == null -> {
|
||||
return null
|
||||
}
|
||||
!media.getWebsiteLink().isNullOrBlank() -> {
|
||||
return media.getWebsiteLink()
|
||||
}
|
||||
media is FeedMedia -> {
|
||||
return getLinkWithFallback(media.getItem())
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getFeedItem(playable: Playable?): FeedItem? {
|
||||
|
|
|
@ -7,6 +7,7 @@ import ac.mdiq.podcini.ui.fragment.ItemPagerFragment
|
|||
import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.ui.common.ThemeUtils
|
||||
import ac.mdiq.podcini.ui.fragment.ItemPageFragment
|
||||
import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder
|
||||
import android.R.color
|
||||
import android.app.Activity
|
||||
|
@ -83,7 +84,7 @@ open class EpisodeItemListAdapter(mainActivity: MainActivity) :
|
|||
if (!inActionMode()) {
|
||||
val ids: LongArray = FeedItemUtil.getIds(episodes)
|
||||
val position = ArrayUtils.indexOf(ids, item.id)
|
||||
activity?.loadChildFragment(ItemPagerFragment.newInstance(ids, position))
|
||||
activity?.loadChildFragment(ItemPageFragment.newInstance(ids, position))
|
||||
} else {
|
||||
toggleSelection(holder.bindingAdapterPosition)
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import ac.mdiq.podcini.util.FeedItemUtil
|
|||
import ac.mdiq.podcini.ui.fragment.ItemPagerFragment
|
||||
import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.ui.fragment.ItemPageFragment
|
||||
import ac.mdiq.podcini.ui.view.viewholder.HorizontalItemViewHolder
|
||||
import org.apache.commons.lang3.ArrayUtils
|
||||
import java.lang.ref.WeakReference
|
||||
|
@ -65,7 +66,7 @@ open class HorizontalItemListAdapter(mainActivity: MainActivity) : RecyclerView.
|
|||
if (activity != null) {
|
||||
val ids: LongArray = FeedItemUtil.getIds(data)
|
||||
val clickPosition = ArrayUtils.indexOf(ids, item.id)
|
||||
activity.loadChildFragment(ItemPagerFragment.newInstance(ids, clickPosition))
|
||||
activity.loadChildFragment(ItemPageFragment.newInstance(ids, clickPosition))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ open class QueueRecyclerAdapter(mainActivity: MainActivity, private val swipeAct
|
|||
|
||||
@UnstableApi @SuppressLint("ClickableViewAccessibility")
|
||||
override fun afterBindViewHolder(holder: EpisodeItemViewHolder, pos: Int) {
|
||||
if (!dragDropEnabled) {
|
||||
if (inActionMode() || !dragDropEnabled) {
|
||||
holder.dragHandle.setVisibility(View.GONE)
|
||||
holder.dragHandle.setOnTouchListener(null)
|
||||
// holder.coverHolder.setOnTouchListener(null)
|
||||
|
@ -38,17 +38,15 @@ open class QueueRecyclerAdapter(mainActivity: MainActivity, private val swipeAct
|
|||
holder.dragHandle.setVisibility(View.VISIBLE)
|
||||
holder.dragHandle.setOnTouchListener { _: View?, event: MotionEvent ->
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
Log.d(TAG, "startDrag()")
|
||||
swipeActions.startDrag(holder)
|
||||
}
|
||||
false
|
||||
}
|
||||
holder.coverHolder.setOnTouchListener { v1, event ->
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
if (!inActionMode() && event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
val isLtr = holder.itemView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
|
||||
val factor = (if (isLtr) 1 else -1).toFloat()
|
||||
if (factor * event.x < factor * 0.5 * v1.width) {
|
||||
Log.d(TAG, "startDrag()")
|
||||
swipeActions.startDrag(holder)
|
||||
} else {
|
||||
Log.d(TAG, "Ignoring drag in right half of the image")
|
||||
|
|
|
@ -90,19 +90,18 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
val viewBinding = FeedinfoBinding.inflate(inflater)
|
||||
// val root: View = inflater.inflate(R.layout.feedinfo, null)
|
||||
val binding = FeedinfoBinding.inflate(inflater)
|
||||
|
||||
Log.d(TAG, "fragment onCreateView")
|
||||
toolbar = viewBinding.toolbar
|
||||
toolbar = binding.toolbar
|
||||
toolbar.title = ""
|
||||
toolbar.inflateMenu(R.menu.feedinfo)
|
||||
toolbar.setNavigationOnClickListener { parentFragmentManager.popBackStack() }
|
||||
toolbar.setOnMenuItemClickListener(this)
|
||||
refreshToolbarState()
|
||||
|
||||
val appBar: AppBarLayout = viewBinding.appBar
|
||||
val collapsingToolbar: CollapsingToolbarLayout = viewBinding.collapsingToolbar
|
||||
val appBar: AppBarLayout = binding.appBar
|
||||
val collapsingToolbar: CollapsingToolbarLayout = binding.collapsingToolbar
|
||||
val iconTintManager: ToolbarIconTintManager =
|
||||
object : ToolbarIconTintManager(requireContext(), toolbar, collapsingToolbar) {
|
||||
override fun doTint(themedContext: Context) {
|
||||
|
@ -115,22 +114,22 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
iconTintManager.updateTint()
|
||||
appBar.addOnOffsetChangedListener(iconTintManager)
|
||||
|
||||
imgvCover = viewBinding.header.imgvCover
|
||||
txtvTitle = viewBinding.header.txtvTitle
|
||||
txtvAuthorHeader = viewBinding.header.txtvAuthor
|
||||
imgvBackground = viewBinding.imgvBackground
|
||||
header = viewBinding.header.root
|
||||
infoContainer = viewBinding.infoContainer
|
||||
// viewBinding.header.butShowInfo.visibility = View.INVISIBLE
|
||||
viewBinding.header.butShowSettings.visibility = View.INVISIBLE
|
||||
viewBinding.header.butFilter.visibility = View.INVISIBLE
|
||||
imgvCover = binding.header.imgvCover
|
||||
txtvTitle = binding.header.txtvTitle
|
||||
txtvAuthorHeader = binding.header.txtvAuthor
|
||||
imgvBackground = binding.imgvBackground
|
||||
header = binding.header.root
|
||||
infoContainer = binding.infoContainer
|
||||
// binding.header.butShowInfo.visibility = View.INVISIBLE
|
||||
binding.header.butShowSettings.visibility = View.INVISIBLE
|
||||
binding.header.butFilter.visibility = View.INVISIBLE
|
||||
// https://github.com/bumptech/glide/issues/529
|
||||
imgvBackground.colorFilter = LightingColorFilter(-0x7d7d7e, 0x000000)
|
||||
|
||||
txtvDescription = viewBinding.txtvDescription
|
||||
txtvUrl = viewBinding.txtvUrl
|
||||
lblSupport = viewBinding.lblSupport
|
||||
txtvFundingUrl = viewBinding.txtvFundingUrl
|
||||
txtvDescription = binding.txtvDescription
|
||||
txtvUrl = binding.txtvUrl
|
||||
lblSupport = binding.lblSupport
|
||||
txtvFundingUrl = binding.txtvFundingUrl
|
||||
|
||||
txtvUrl.setOnClickListener(copyUrlToClipboard)
|
||||
|
||||
|
@ -139,12 +138,12 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
FeedStatisticsFragment.newInstance(feedId, false), "feed_statistics_fragment")
|
||||
.commitAllowingStateLoss()
|
||||
|
||||
viewBinding.btnvOpenStatistics.setOnClickListener {
|
||||
binding.btnvOpenStatistics.setOnClickListener {
|
||||
val fragment = StatisticsFragment()
|
||||
(activity as MainActivity).loadChildFragment(fragment, TransitionEffect.SLIDE)
|
||||
}
|
||||
|
||||
return viewBinding.root
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
|
|
@ -63,7 +63,6 @@ import org.greenrobot.eventbus.ThreadMode
|
|||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
|
||||
/**
|
||||
* Displays a list of FeedItems.
|
||||
*/
|
||||
|
@ -72,7 +71,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
|
||||
private lateinit var adapter: FeedItemListAdapter
|
||||
private lateinit var swipeActions: SwipeActions
|
||||
private lateinit var viewBinding: FeedItemListFragmentBinding
|
||||
private lateinit var binding: FeedItemListFragmentBinding
|
||||
private lateinit var speedDialBinding: MultiSelectSpeedDialBinding
|
||||
private lateinit var nextPageLoader: MoreContentListFooterUtil
|
||||
|
||||
|
@ -94,43 +93,44 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
): View {
|
||||
Log.d(TAG, "fragment onCreateView")
|
||||
|
||||
viewBinding = FeedItemListFragmentBinding.inflate(inflater)
|
||||
speedDialBinding = MultiSelectSpeedDialBinding.bind(viewBinding.root)
|
||||
viewBinding.toolbar.inflateMenu(R.menu.feedlist)
|
||||
viewBinding.toolbar.setOnMenuItemClickListener(this)
|
||||
viewBinding.toolbar.setOnLongClickListener {
|
||||
viewBinding.recyclerView.scrollToPosition(5)
|
||||
viewBinding.recyclerView.post { viewBinding.recyclerView.smoothScrollToPosition(0) }
|
||||
viewBinding.appBar.setExpanded(true)
|
||||
binding = FeedItemListFragmentBinding.inflate(inflater)
|
||||
speedDialBinding = MultiSelectSpeedDialBinding.bind(binding.root)
|
||||
|
||||
binding.toolbar.inflateMenu(R.menu.feedlist)
|
||||
binding.toolbar.setOnMenuItemClickListener(this)
|
||||
binding.toolbar.setOnLongClickListener {
|
||||
binding.recyclerView.scrollToPosition(5)
|
||||
binding.recyclerView.post { binding.recyclerView.smoothScrollToPosition(0) }
|
||||
binding.appBar.setExpanded(true)
|
||||
false
|
||||
}
|
||||
displayUpArrow = parentFragmentManager.backStackEntryCount != 0
|
||||
if (savedInstanceState != null) {
|
||||
displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW)
|
||||
}
|
||||
(activity as MainActivity).setupToolbarToggle(viewBinding.toolbar, displayUpArrow)
|
||||
(activity as MainActivity).setupToolbarToggle(binding.toolbar, displayUpArrow)
|
||||
updateToolbar()
|
||||
|
||||
viewBinding.recyclerView.setRecycledViewPool((activity as MainActivity).recycledViewPool)
|
||||
binding.recyclerView.setRecycledViewPool((activity as MainActivity).recycledViewPool)
|
||||
adapter = FeedItemListAdapter(activity as MainActivity)
|
||||
adapter.setOnSelectModeListener(this)
|
||||
viewBinding.recyclerView.adapter = adapter
|
||||
swipeActions = SwipeActions(this, TAG).attachTo(viewBinding.recyclerView)
|
||||
viewBinding.progressBar.visibility = View.VISIBLE
|
||||
binding.recyclerView.adapter = adapter
|
||||
swipeActions = SwipeActions(this, TAG).attachTo(binding.recyclerView)
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
|
||||
val iconTintManager: ToolbarIconTintManager = object : ToolbarIconTintManager(
|
||||
requireContext(), viewBinding.toolbar, viewBinding.collapsingToolbar) {
|
||||
requireContext(), binding.toolbar, binding.collapsingToolbar) {
|
||||
override fun doTint(themedContext: Context) {
|
||||
viewBinding.toolbar.menu.findItem(R.id.refresh_item)
|
||||
binding.toolbar.menu.findItem(R.id.refresh_item)
|
||||
.setIcon(AppCompatResources.getDrawable(themedContext, R.drawable.ic_refresh))
|
||||
viewBinding.toolbar.menu.findItem(R.id.action_search)
|
||||
binding.toolbar.menu.findItem(R.id.action_search)
|
||||
.setIcon(AppCompatResources.getDrawable(themedContext, R.drawable.ic_search))
|
||||
}
|
||||
}
|
||||
iconTintManager.updateTint()
|
||||
viewBinding.appBar.addOnOffsetChangedListener(iconTintManager)
|
||||
binding.appBar.addOnOffsetChangedListener(iconTintManager)
|
||||
|
||||
nextPageLoader = MoreContentListFooterUtil(viewBinding.moreContent.moreContentListFooter)
|
||||
nextPageLoader = MoreContentListFooterUtil(binding.moreContent.moreContentListFooter)
|
||||
nextPageLoader.setClickListener(object : MoreContentListFooterUtil.Listener {
|
||||
override fun onClick() {
|
||||
if (feed != null) {
|
||||
|
@ -138,22 +138,22 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
}
|
||||
}
|
||||
})
|
||||
viewBinding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(view: RecyclerView, deltaX: Int, deltaY: Int) {
|
||||
super.onScrolled(view, deltaX, deltaY)
|
||||
val hasMorePages = feed != null && feed!!.isPaged && feed!!.nextPageLink != null
|
||||
val pageLoaderVisible = viewBinding.recyclerView.isScrolledToBottom && hasMorePages
|
||||
val pageLoaderVisible = binding.recyclerView.isScrolledToBottom && hasMorePages
|
||||
nextPageLoader.root.visibility = if (pageLoaderVisible) View.VISIBLE else View.GONE
|
||||
viewBinding.recyclerView.setPadding(
|
||||
viewBinding.recyclerView.paddingLeft, 0, viewBinding.recyclerView.paddingRight,
|
||||
binding.recyclerView.setPadding(
|
||||
binding.recyclerView.paddingLeft, 0, binding.recyclerView.paddingRight,
|
||||
if (pageLoaderVisible) nextPageLoader.root.measuredHeight else 0)
|
||||
}
|
||||
})
|
||||
|
||||
EventBus.getDefault().register(this)
|
||||
|
||||
viewBinding.swipeRefresh.setDistanceToTriggerSync(resources.getInteger(R.integer.swipe_refresh_distance))
|
||||
viewBinding.swipeRefresh.setOnRefreshListener {
|
||||
binding.swipeRefresh.setDistanceToTriggerSync(resources.getInteger(R.integer.swipe_refresh_distance))
|
||||
binding.swipeRefresh.setOnRefreshListener {
|
||||
FeedUpdateManager.runOnceOrAsk(requireContext(), feed)
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
adapter.endSelectMode()
|
||||
true
|
||||
}
|
||||
return viewBinding.root
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -201,22 +201,22 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
if (feed == null) {
|
||||
return
|
||||
}
|
||||
viewBinding.toolbar.menu.findItem(R.id.visit_website_item).setVisible(feed!!.link != null)
|
||||
viewBinding.toolbar.menu.findItem(R.id.refresh_complete_item).setVisible(feed!!.isPaged)
|
||||
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)
|
||||
if (StringUtils.isBlank(feed!!.link)) {
|
||||
viewBinding.toolbar.menu.findItem(R.id.visit_website_item).setVisible(false)
|
||||
binding.toolbar.menu.findItem(R.id.visit_website_item).setVisible(false)
|
||||
}
|
||||
if (feed!!.isLocalFeed) {
|
||||
viewBinding.toolbar.menu.findItem(R.id.share_item).setVisible(false)
|
||||
binding.toolbar.menu.findItem(R.id.share_item).setVisible(false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
val horizontalSpacing = resources.getDimension(R.dimen.additional_horizontal_spacing).toInt()
|
||||
viewBinding.header.headerContainer.setPadding(
|
||||
horizontalSpacing, viewBinding.header.headerContainer.paddingTop,
|
||||
horizontalSpacing, viewBinding.header.headerContainer.paddingBottom)
|
||||
binding.header.headerContainer.setPadding(
|
||||
horizontalSpacing, binding.header.headerContainer.paddingTop,
|
||||
horizontalSpacing, binding.header.headerContainer.paddingBottom)
|
||||
}
|
||||
|
||||
@UnstableApi override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
|
@ -288,7 +288,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
val activity: MainActivity = activity as MainActivity
|
||||
if (feed != null) {
|
||||
val ids: LongArray = FeedItemUtil.getIds(feed!!.items)
|
||||
activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position))
|
||||
activity.loadChildFragment(ItemPageFragment.newInstance(ids, position))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,7 +339,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
Log.d(TAG, "onEventMainThread() called with: event = [$event]")
|
||||
for (i in 0 until adapter.itemCount) {
|
||||
val holder: EpisodeItemViewHolder? =
|
||||
viewBinding.recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
binding.recyclerView.findViewHolderForAdapterPosition(i) as? EpisodeItemViewHolder
|
||||
if (holder != null && holder.isCurrentlyPlayingItem) {
|
||||
holder.notifyPlaybackPositionUpdated(event)
|
||||
break
|
||||
|
@ -372,7 +372,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
override fun onEndSelectMode() {
|
||||
speedDialBinding.fabSD.close()
|
||||
speedDialBinding.fabSD.visibility = View.GONE
|
||||
swipeActions.attachTo(viewBinding.recyclerView)
|
||||
swipeActions.attachTo(binding.recyclerView)
|
||||
}
|
||||
|
||||
@UnstableApi private fun updateUi() {
|
||||
|
@ -405,7 +405,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
if (!event.isFeedUpdateRunning) {
|
||||
nextPageLoader.root.visibility = View.GONE
|
||||
}
|
||||
viewBinding.swipeRefresh.isRefreshing = event.isFeedUpdateRunning
|
||||
binding.swipeRefresh.isRefreshing = event.isFeedUpdateRunning
|
||||
}
|
||||
|
||||
@UnstableApi private fun refreshHeaderView() {
|
||||
|
@ -416,34 +416,34 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
}
|
||||
loadFeedImage()
|
||||
if (feed!!.hasLastUpdateFailed()) {
|
||||
viewBinding.header.txtvFailure.visibility = View.VISIBLE
|
||||
binding.header.txtvFailure.visibility = View.VISIBLE
|
||||
} else {
|
||||
viewBinding.header.txtvFailure.visibility = View.GONE
|
||||
binding.header.txtvFailure.visibility = View.GONE
|
||||
}
|
||||
if (feed!!.preferences != null && !feed!!.preferences!!.keepUpdated) {
|
||||
viewBinding.header.txtvUpdatesDisabled.text = ("{md-pause-circle-outline} "
|
||||
binding.header.txtvUpdatesDisabled.text = ("{md-pause-circle-outline} "
|
||||
+ this.getString(R.string.updates_disabled_label))
|
||||
Iconify.addIcons(viewBinding.header.txtvUpdatesDisabled)
|
||||
viewBinding.header.txtvUpdatesDisabled.visibility = View.VISIBLE
|
||||
Iconify.addIcons(binding.header.txtvUpdatesDisabled)
|
||||
binding.header.txtvUpdatesDisabled.visibility = View.VISIBLE
|
||||
} else {
|
||||
viewBinding.header.txtvUpdatesDisabled.visibility = View.GONE
|
||||
binding.header.txtvUpdatesDisabled.visibility = View.GONE
|
||||
}
|
||||
viewBinding.header.txtvTitle.text = feed!!.title
|
||||
viewBinding.header.txtvAuthor.text = feed!!.author
|
||||
binding.header.txtvTitle.text = feed!!.title
|
||||
binding.header.txtvAuthor.text = feed!!.author
|
||||
if (feed != null && feed!!.itemFilter != null) {
|
||||
val filter: FeedItemFilter? = feed!!.itemFilter
|
||||
if (filter != null && filter.values.isNotEmpty()) {
|
||||
viewBinding.header.txtvInformation.text = ("{md-info-outline} " + this.getString(R.string.filtered_label))
|
||||
Iconify.addIcons(viewBinding.header.txtvInformation)
|
||||
viewBinding.header.txtvInformation.setOnClickListener {
|
||||
binding.header.txtvInformation.text = ("{md-info-outline} " + this.getString(R.string.filtered_label))
|
||||
Iconify.addIcons(binding.header.txtvInformation)
|
||||
binding.header.txtvInformation.setOnClickListener {
|
||||
FeedItemFilterDialog.newInstance(feed!!).show(childFragmentManager, null)
|
||||
}
|
||||
viewBinding.header.txtvInformation.visibility = View.VISIBLE
|
||||
binding.header.txtvInformation.visibility = View.VISIBLE
|
||||
} else {
|
||||
viewBinding.header.txtvInformation.visibility = View.GONE
|
||||
binding.header.txtvInformation.visibility = View.GONE
|
||||
}
|
||||
} else {
|
||||
viewBinding.header.txtvInformation.visibility = View.GONE
|
||||
binding.header.txtvInformation.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,20 +451,19 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
if (feed == null || headerCreated) return
|
||||
|
||||
// https://github.com/bumptech/glide/issues/529
|
||||
viewBinding.imgvBackground.colorFilter = LightingColorFilter(-0x99999a, 0x000000)
|
||||
// viewBinding.header.butShowInfo.setOnClickListener { showFeedInfo() }
|
||||
viewBinding.header.imgvCover.setOnClickListener { showFeedInfo() }
|
||||
viewBinding.header.butShowSettings.setOnClickListener {
|
||||
binding.imgvBackground.colorFilter = LightingColorFilter(-0x99999a, 0x000000)
|
||||
binding.header.imgvCover.setOnClickListener { showFeedInfo() }
|
||||
binding.header.butShowSettings.setOnClickListener {
|
||||
if (feed != null) {
|
||||
val fragment = FeedSettingsFragment.newInstance(feed!!)
|
||||
(activity as MainActivity).loadChildFragment(fragment, TransitionEffect.SLIDE)
|
||||
}
|
||||
}
|
||||
viewBinding.header.butFilter.setOnClickListener {
|
||||
binding.header.butFilter.setOnClickListener {
|
||||
if (feed != null) FeedItemFilterDialog.newInstance(feed!!).show(childFragmentManager, null)
|
||||
}
|
||||
viewBinding.header.txtvFailure.setOnClickListener { showErrorDetails() }
|
||||
viewBinding.header.counts.text = adapter.itemCount.toString()
|
||||
binding.header.txtvFailure.setOnClickListener { showErrorDetails() }
|
||||
binding.header.counts.text = adapter.itemCount.toString()
|
||||
headerCreated = true
|
||||
}
|
||||
|
||||
|
@ -504,7 +503,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
.error(R.color.image_readability_tint)
|
||||
.transform(FastBlurTransformation())
|
||||
.dontAnimate())
|
||||
.into(viewBinding.imgvBackground)
|
||||
.into(binding.imgvBackground)
|
||||
|
||||
Glide.with(this)
|
||||
.load(feed!!.imageUrl)
|
||||
|
@ -513,7 +512,7 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
.error(R.color.light_gray)
|
||||
.fitCenter()
|
||||
.dontAnimate())
|
||||
.into(viewBinding.header.imgvCover)
|
||||
.into(binding.header.imgvCover)
|
||||
}
|
||||
|
||||
@UnstableApi private fun loadItems() {
|
||||
|
@ -528,10 +527,10 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
Log.d(TAG, "loadItems subscribe called ${feed?.title}")
|
||||
swipeActions.setFilter(feed?.itemFilter)
|
||||
refreshHeaderView()
|
||||
viewBinding.progressBar.visibility = View.GONE
|
||||
binding.progressBar.visibility = View.GONE
|
||||
adapter.setDummyViews(0)
|
||||
if (feed != null) adapter.updateItems(feed!!.items)
|
||||
viewBinding.header.counts.text = (feed?.items?.size?:0).toString()
|
||||
binding.header.counts.text = (feed?.items?.size?:0).toString()
|
||||
updateToolbar()
|
||||
}, { error: Throwable? ->
|
||||
feed = null
|
||||
|
@ -563,8 +562,8 @@ class FeedItemlistFragment : Fragment(), AdapterView.OnItemClickListener, Toolba
|
|||
return
|
||||
}
|
||||
when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_T -> viewBinding.recyclerView.smoothScrollToPosition(0)
|
||||
KeyEvent.KEYCODE_B -> viewBinding.recyclerView.smoothScrollToPosition(adapter.itemCount - 1)
|
||||
KeyEvent.KEYCODE_T -> binding.recyclerView.smoothScrollToPosition(0)
|
||||
KeyEvent.KEYCODE_B -> binding.recyclerView.smoothScrollToPosition(adapter.itemCount - 1)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ class ItemDescriptionFragment : Fragment() {
|
|||
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
Log.d(TAG, "Creating view")
|
||||
val binding = ItemDescriptionFragmentBinding.inflate(inflater)
|
||||
// val root = inflater.inflate(R.layout.item_description_fragment, container, false)
|
||||
|
||||
Log.d(TAG, "fragment onCreateView")
|
||||
webvDescription = binding.webview
|
||||
|
|
|
@ -16,6 +16,7 @@ import ac.mdiq.podcini.ui.adapter.actionbutton.*
|
|||
import ac.mdiq.podcini.ui.common.CircularProgressBar
|
||||
import ac.mdiq.podcini.ui.common.ThemeUtils
|
||||
import ac.mdiq.podcini.ui.gui.ShownotesCleaner
|
||||
import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler
|
||||
import ac.mdiq.podcini.ui.view.ShownotesWebView
|
||||
import ac.mdiq.podcini.util.Converter
|
||||
import ac.mdiq.podcini.util.DateFormatter
|
||||
|
@ -25,6 +26,7 @@ import ac.mdiq.podcini.util.event.FeedItemEvent
|
|||
import ac.mdiq.podcini.util.event.UnreadItemsUpdateEvent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.text.Layout
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
|
@ -32,11 +34,12 @@ import android.view.LayoutInflater
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.app.ShareCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.bumptech.glide.Glide
|
||||
|
@ -98,20 +101,20 @@ class ItemFragment : Fragment() {
|
|||
|
||||
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
val viewBinding = FeeditemFragmentBinding.inflate(inflater)
|
||||
root = viewBinding.root
|
||||
val binding = FeeditemFragmentBinding.inflate(inflater)
|
||||
root = binding.root
|
||||
|
||||
Log.d(TAG, "fragment onCreateView")
|
||||
txtvPodcast = viewBinding.txtvPodcast
|
||||
txtvPodcast = binding.txtvPodcast
|
||||
txtvPodcast.setOnClickListener { openPodcast() }
|
||||
txtvTitle = viewBinding.txtvTitle
|
||||
txtvTitle = binding.txtvTitle
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
txtvTitle.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL)
|
||||
}
|
||||
txtvDuration = viewBinding.txtvDuration
|
||||
txtvPublished = viewBinding.txtvPublished
|
||||
txtvDuration = binding.txtvDuration
|
||||
txtvPublished = binding.txtvPublished
|
||||
txtvTitle.ellipsize = TextUtils.TruncateAt.END
|
||||
webvDescription = viewBinding.webvDescription
|
||||
webvDescription = binding.webvDescription
|
||||
webvDescription.setTimecodeSelectedListener { time: Int? ->
|
||||
val cMedia = controller?.getMedia()
|
||||
if (item?.media?.getIdentifier() == cMedia?.getIdentifier()) {
|
||||
|
@ -123,17 +126,17 @@ class ItemFragment : Fragment() {
|
|||
}
|
||||
registerForContextMenu(webvDescription)
|
||||
|
||||
imgvCover = viewBinding.imgvCover
|
||||
imgvCover = binding.imgvCover
|
||||
imgvCover.setOnClickListener { openPodcast() }
|
||||
progbarDownload = viewBinding.circularProgressBar
|
||||
progbarLoading = viewBinding.progbarLoading
|
||||
butAction1 = viewBinding.butAction1
|
||||
butAction2 = viewBinding.butAction2
|
||||
butAction1Icon = viewBinding.butAction1Icon
|
||||
butAction2Icon = viewBinding.butAction2Icon
|
||||
butAction1Text = viewBinding.butAction1Text
|
||||
butAction2Text = viewBinding.butAction2Text
|
||||
noMediaLabel = viewBinding.noMediaLabel
|
||||
progbarDownload = binding.circularProgressBar
|
||||
progbarLoading = binding.progbarLoading
|
||||
butAction1 = binding.butAction1
|
||||
butAction2 = binding.butAction2
|
||||
butAction1Icon = binding.butAction1Icon
|
||||
butAction2Icon = binding.butAction2Icon
|
||||
butAction1Text = binding.butAction1Text
|
||||
butAction2Text = binding.butAction2Text
|
||||
noMediaLabel = binding.noMediaLabel
|
||||
|
||||
butAction1.setOnClickListener(View.OnClickListener {
|
||||
if (actionButton1 is StreamActionButton && !UserPreferences.isStreamOverDownload
|
||||
|
@ -165,7 +168,7 @@ class ItemFragment : Fragment() {
|
|||
controller?.init()
|
||||
load()
|
||||
|
||||
return viewBinding.root
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class) private fun showOnDemandConfigBalloon(offerStreaming: Boolean) {
|
||||
|
@ -393,6 +396,9 @@ class ItemFragment : Fragment() {
|
|||
DBReader.loadDescriptionOfFeedItem(feedItem)
|
||||
val t = ShownotesCleaner(context, feedItem.description?:"", duration)
|
||||
webviewData = t.processShownotes()
|
||||
val bundle = Bundle()
|
||||
bundle.putString("description", feedItem.description?:"")
|
||||
this.arguments = bundle
|
||||
}
|
||||
return feedItem
|
||||
}
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
package ac.mdiq.podcini.ui.fragment
|
||||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.databinding.FeeditemPageFragmentBinding
|
||||
import ac.mdiq.podcini.storage.DBReader
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler
|
||||
import ac.mdiq.podcini.util.event.FeedItemEvent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.app.ShareCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import kotlin.math.max
|
||||
|
||||
/**
|
||||
* Displays information about a list of FeedItems.
|
||||
*/
|
||||
class ItemPageFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
||||
private lateinit var page: View
|
||||
private lateinit var toolbar: MaterialToolbar
|
||||
|
||||
private lateinit var itemFragment: ItemFragment
|
||||
|
||||
private var feedItems: LongArray? = null
|
||||
private var item: FeedItem? = null
|
||||
private var disposable: Disposable? = null
|
||||
|
||||
@UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
val binding = FeeditemPageFragmentBinding.inflate(inflater)
|
||||
|
||||
Log.d(TAG, "fragment onCreateView")
|
||||
toolbar = binding.toolbar
|
||||
toolbar.title = ""
|
||||
toolbar.inflateMenu(R.menu.feeditem_options)
|
||||
toolbar.setNavigationOnClickListener { parentFragmentManager.popBackStack() }
|
||||
toolbar.setOnMenuItemClickListener(this)
|
||||
|
||||
feedItems = requireArguments().getLongArray(ARG_FEEDITEMS)
|
||||
val feedItemPos = max(0.0, requireArguments().getInt(ARG_FEEDITEM_POS).toDouble()).toInt()
|
||||
|
||||
page = binding.fragmentView
|
||||
loadItem(feedItems!![feedItemPos])
|
||||
val transaction = requireActivity().supportFragmentManager.beginTransaction()
|
||||
itemFragment = ItemFragment.newInstance(if (feedItems!= null) feedItems!![feedItemPos] else 0L)
|
||||
transaction.replace(R.id.fragment_view, itemFragment)
|
||||
transaction.commit()
|
||||
|
||||
EventBus.getDefault().register(this)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putInt(KEY_PAGER_ID, page.id)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
EventBus.getDefault().unregister(this)
|
||||
disposable?.dispose()
|
||||
}
|
||||
|
||||
@UnstableApi private fun loadItem(itemId: Long) {
|
||||
disposable?.dispose()
|
||||
|
||||
disposable = Observable.fromCallable { DBReader.getFeedItem(itemId) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ result: FeedItem? ->
|
||||
item = result
|
||||
refreshToolbarState()
|
||||
}, { obj: Throwable -> obj.printStackTrace() })
|
||||
}
|
||||
|
||||
@UnstableApi fun refreshToolbarState() {
|
||||
if (item == null) return
|
||||
|
||||
if (item!!.hasMedia()) {
|
||||
FeedItemMenuHandler.onPrepareMenu(toolbar.menu, item)
|
||||
} else {
|
||||
// these are already available via button1 and button2
|
||||
FeedItemMenuHandler.onPrepareMenu(toolbar.menu, item,
|
||||
R.id.mark_read_item, R.id.visit_website_item)
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableApi override fun onMenuItemClick(menuItem: MenuItem): Boolean {
|
||||
when (menuItem.itemId) {
|
||||
R.id.open_podcast -> {
|
||||
openPodcast()
|
||||
return true
|
||||
}
|
||||
R.id.share_notes -> {
|
||||
if (item == null) return false
|
||||
val bundle = itemFragment.arguments
|
||||
val notes = bundle?.getString("description", "")
|
||||
if (!notes.isNullOrEmpty()) {
|
||||
val shareText = if (Build.VERSION.SDK_INT >= 24) Html.fromHtml(notes, Html.FROM_HTML_MODE_LEGACY).toString()
|
||||
else Html.fromHtml(notes).toString()
|
||||
val context = requireContext()
|
||||
val intent = ShareCompat.IntentBuilder(context)
|
||||
.setType("text/plain")
|
||||
.setText(shareText)
|
||||
.setChooserTitle(R.string.share_notes_label)
|
||||
.createChooserIntent()
|
||||
context.startActivity(intent)
|
||||
}
|
||||
return true
|
||||
}
|
||||
else -> {
|
||||
if (item == null) return false
|
||||
return FeedItemMenuHandler.onMenuItemClicked(this, menuItem.itemId, item!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(event: FeedItemEvent) {
|
||||
for (item in event.items) {
|
||||
if (this.item != null && this.item!!.id == item.id) {
|
||||
this.item = item
|
||||
refreshToolbarState()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableApi private fun openPodcast() {
|
||||
if (item == null) {
|
||||
return
|
||||
}
|
||||
val fragment: Fragment = FeedItemlistFragment.newInstance(item!!.feedId)
|
||||
(activity as MainActivity).loadChildFragment(fragment)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG: String = "ItemPageFragment"
|
||||
private const val ARG_FEEDITEMS = "feeditems"
|
||||
private const val ARG_FEEDITEM_POS = "feeditem_pos"
|
||||
private const val KEY_PAGER_ID = "pager_id"
|
||||
|
||||
/**
|
||||
* Creates a new instance of an ItemPageFragment.
|
||||
*
|
||||
* @param feeditems The IDs of the FeedItems that belong to the same list
|
||||
* @param feedItemPos The position of the FeedItem that is currently shown
|
||||
* @return The ItemFragment instance
|
||||
*/
|
||||
fun newInstance(feeditems: LongArray?, feedItemPos: Int): ItemPageFragment {
|
||||
val fragment = ItemPageFragment()
|
||||
val args = Bundle()
|
||||
if (feeditems != null) args.putLongArray(ARG_FEEDITEMS, feeditems)
|
||||
args.putInt(ARG_FEEDITEM_POS, max(0.0, feedItemPos.toDouble()).toInt())
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,13 +7,16 @@ import ac.mdiq.podcini.storage.model.feed.FeedItem
|
|||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler
|
||||
import ac.mdiq.podcini.util.event.FeedItemEvent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.app.ShareCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
|
@ -43,7 +46,6 @@ class ItemPagerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
): View {
|
||||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
val binding = FeeditemPagerFragmentBinding.inflate(inflater)
|
||||
// val layout: View = inflater.inflate(R.layout.feeditem_pager_fragment, container, false)
|
||||
|
||||
Log.d(TAG, "fragment onCreateView")
|
||||
toolbar = binding.toolbar
|
||||
|
@ -107,9 +109,8 @@ class ItemPagerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
|
||||
@UnstableApi fun refreshToolbarState() {
|
||||
if (item == null) {
|
||||
return
|
||||
}
|
||||
if (item == null) return
|
||||
|
||||
if (item!!.hasMedia()) {
|
||||
FeedItemMenuHandler.onPrepareMenu(toolbar.menu, item)
|
||||
} else {
|
||||
|
@ -120,12 +121,33 @@ class ItemPagerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
|
||||
@UnstableApi override fun onMenuItemClick(menuItem: MenuItem): Boolean {
|
||||
if (menuItem.itemId == R.id.open_podcast) {
|
||||
openPodcast()
|
||||
return true
|
||||
when (menuItem.itemId) {
|
||||
R.id.open_podcast -> {
|
||||
openPodcast()
|
||||
return true
|
||||
}
|
||||
R.id.share_notes -> {
|
||||
if (item == null) return false
|
||||
DBReader.loadDescriptionOfFeedItem(item!!)
|
||||
if (!item!!.description.isNullOrEmpty()) {
|
||||
val shareText = if (Build.VERSION.SDK_INT >= 24) Html.fromHtml(item!!.description,
|
||||
Html.FROM_HTML_MODE_LEGACY).toString()
|
||||
else Html.fromHtml(item!!.description).toString()
|
||||
val context = requireContext()
|
||||
val intent = ShareCompat.IntentBuilder(context)
|
||||
.setType("text/plain")
|
||||
.setText(shareText)
|
||||
.setChooserTitle(R.string.share_notes_label)
|
||||
.createChooserIntent()
|
||||
context.startActivity(intent)
|
||||
}
|
||||
return true
|
||||
}
|
||||
else -> {
|
||||
if (item == null) return false
|
||||
return FeedItemMenuHandler.onMenuItemClicked(this, menuItem.itemId, item!!)
|
||||
}
|
||||
}
|
||||
if (item == null) return false
|
||||
return FeedItemMenuHandler.onMenuItemClicked(this, menuItem.itemId, item!!)
|
||||
}
|
||||
|
||||
@UnstableApi @Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
@ -149,6 +171,7 @@ class ItemPagerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
|
||||
private inner class ItemPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
Log.d(TAG, "createFragment $position")
|
||||
return ItemFragment.newInstance(if (feedItems!= null) feedItems!![position] else 0L)
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
}
|
||||
|
||||
@UnstableApi override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {
|
||||
if (!actions!!.hasActions()) {
|
||||
if (actions != null && !actions!!.hasActions()) {
|
||||
//open settings dialog if no prefs are set
|
||||
SwipeActionsDialog(fragment.requireContext(), tag).show(object : SwipeActionsDialog.Callback {
|
||||
override fun onCall() {
|
||||
|
@ -80,7 +80,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
|
||||
val item = (viewHolder as EpisodeItemViewHolder).feedItem
|
||||
|
||||
if (item != null && filter != null)
|
||||
if (actions != null && item != null && filter != null)
|
||||
(if (swipeDir == ItemTouchHelper.RIGHT) actions!!.right else actions!!.left)?.performAction(item, fragment, filter!!)
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
var dx = dx
|
||||
val right: SwipeAction
|
||||
val left: SwipeAction
|
||||
if (actions!!.hasActions()) {
|
||||
if (actions != null && actions!!.hasActions()) {
|
||||
right = actions!!.right!!
|
||||
left = actions!!.left!!
|
||||
} else {
|
||||
|
@ -182,7 +182,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
|
|||
}
|
||||
|
||||
fun startDrag(holder: EpisodeItemViewHolder?) {
|
||||
itemTouchHelper.startDrag(holder!!)
|
||||
if (holder != null) itemTouchHelper.startDrag(holder)
|
||||
}
|
||||
|
||||
class Actions(prefs: String?) {
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
package ac.mdiq.podcini.ui.menuhandler
|
||||
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.net.sync.SynchronizationSettings
|
||||
import ac.mdiq.podcini.net.sync.model.EpisodeAction
|
||||
import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
|
||||
import ac.mdiq.podcini.preferences.PlaybackPreferences
|
||||
import ac.mdiq.podcini.receiver.MediaButtonReceiver
|
||||
import ac.mdiq.podcini.service.playback.PlaybackServiceInterface
|
||||
import ac.mdiq.podcini.storage.DBWriter
|
||||
import ac.mdiq.podcini.net.sync.SynchronizationSettings
|
||||
import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
|
||||
import ac.mdiq.podcini.util.*
|
||||
import ac.mdiq.podcini.ui.dialog.ShareDialog
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedItem
|
||||
import ac.mdiq.podcini.storage.model.feed.FeedMedia
|
||||
import ac.mdiq.podcini.net.sync.model.EpisodeAction
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.dialog.ShareDialog
|
||||
import ac.mdiq.podcini.ui.view.LocalDeleteModal
|
||||
import ac.mdiq.podcini.util.*
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlin.math.ceil
|
||||
|
||||
|
||||
/**
|
||||
* Handles interactions with the FeedItemMenu.
|
||||
*/
|
||||
|
@ -57,7 +58,6 @@ object FeedItemMenuHandler {
|
|||
setItemVisibility(menu, R.id.visit_website_item, !(selectedItem.feed?.isLocalFeed?:false)
|
||||
&& ShareUtils.hasLinkToShare(selectedItem))
|
||||
setItemVisibility(menu, R.id.share_item, !(selectedItem.feed?.isLocalFeed?:false))
|
||||
// setItemVisibility(menu, R.id.remove_inbox_item, selectedItem.isNew)
|
||||
setItemVisibility(menu, R.id.mark_read_item, !selectedItem.isPlayed())
|
||||
setItemVisibility(menu, R.id.mark_unread_item, selectedItem.isPlayed())
|
||||
setItemVisibility(menu, R.id.reset_position, hasMedia && selectedItem.media?.getPosition() != 0)
|
||||
|
@ -144,9 +144,6 @@ object FeedItemMenuHandler {
|
|||
selectedItem.media!!.id)
|
||||
}
|
||||
}
|
||||
// R.id.remove_inbox_item -> {
|
||||
// removeNewFlagWithUndo(fragment, selectedItem)
|
||||
// }
|
||||
R.id.mark_read_item -> {
|
||||
selectedItem.setPlayed(true)
|
||||
DBWriter.markItemPlayed(selectedItem, FeedItem.PLAYED, true)
|
||||
|
@ -258,7 +255,7 @@ object FeedItemMenuHandler {
|
|||
if (showSnackbar) {
|
||||
(fragment.activity as MainActivity).showSnackbarAbovePlayer(
|
||||
playStateStringRes, duration)
|
||||
.setAction(fragment.getString(R.string.undo)) { v ->
|
||||
.setAction(fragment.getString(R.string.undo)) {
|
||||
DBWriter.markItemPlayed(item.playState, item.id)
|
||||
// don't forget to cancel the thing that's going to remove the media
|
||||
h.removeCallbacks(r)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/feeditem_page_fragment"
|
||||
android:fitsSystemWindows="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:navigationContentDescription="@string/toolbar_back_button_content_description"
|
||||
app:navigationIcon="?homeAsUpIndicator" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragment_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:foreground="?android:windowContentOverlay"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
|
@ -28,19 +28,6 @@
|
|||
android:layout_width="148dp"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<!-- <ImageButton-->
|
||||
<!-- android:id="@+id/butShowInfo"-->
|
||||
<!-- android:layout_width="40dp"-->
|
||||
<!-- android:layout_height="40dp"-->
|
||||
<!-- android:background="?attr/selectableItemBackground"-->
|
||||
<!-- android:contentDescription="@string/show_info_label"-->
|
||||
<!-- android:layout_marginLeft="-8dp"-->
|
||||
<!-- android:layout_marginStart="-8dp"-->
|
||||
<!-- android:scaleType="fitXY"-->
|
||||
<!-- android:padding="8dp"-->
|
||||
<!-- app:srcCompat="@drawable/ic_info_white"-->
|
||||
<!-- tools:visibility="visible" />-->
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/butFilter"
|
||||
android:layout_width="40dp"
|
||||
|
|
|
@ -56,7 +56,11 @@
|
|||
android:menuCategory="container"
|
||||
android:title="@string/share_label">
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/share_notes"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/share_notes_label">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/open_podcast"
|
||||
custom:showAsAction="collapseActionView"
|
||||
|
|
|
@ -166,8 +166,6 @@
|
|||
|
||||
<!-- Actions on feeds -->
|
||||
|
||||
|
||||
|
||||
<string name="multi_select_mark_played_confirmation">Please confirm that you want to mark all selected items as played.</string>
|
||||
<string name="multi_select_mark_unplayed_confirmation">Please confirm that you want to mark all selected items as unplayed.</string>
|
||||
<string name="show_info_label">Show information</string>
|
||||
|
@ -177,6 +175,7 @@
|
|||
<string name="remove_feed_label">Remove podcast</string>
|
||||
<string name="share_label">Share</string>
|
||||
<string name="share_file_label">Share file</string>
|
||||
<string name="share_notes_label">Share notes</string>
|
||||
<string name="feed_delete_confirmation_msg">Please confirm that you want to delete the podcast \"%1$s\", ALL its episodes (including downloaded episodes), and its statistics.</string>
|
||||
<string name="feed_delete_confirmation_msg_batch">Please confirm that you want to remove the selected podcasts, ALL their episodes (including downloaded episodes), and its statistics.</string>
|
||||
<string name="feed_delete_confirmation_local_msg">Please confirm that you want to remove the podcast \"%1$s\" and its statistics. The files in the local source folder will not be deleted.</string>
|
||||
|
|
10
changelog.md
10
changelog.md
|
@ -85,4 +85,12 @@
|
|||
* corrected action icons for themes
|
||||
* revealed info bar in Downloads view
|
||||
* revealed info bar in Subscriptions view
|
||||
* reset tags list in Subscriptions when new tag is added
|
||||
* reset tags list in Subscriptions when new tag is added
|
||||
|
||||
## 4.2.7
|
||||
|
||||
* disabled drag actions when in multi-select mode (fixed crash bug)
|
||||
* renewed PodcastIndex API keys
|
||||
* added share notes menu option in episode view
|
||||
* press on title area of an episode now opens the episode info faster and more economically - without horizontal swipe
|
||||
* press on the icon of an episode opens the episode info the original way - with horizontal swipe
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
Version 4.2.7 brings several changes:
|
||||
|
||||
* disabled drag actions when in multi-select mode (fixed crash bug)
|
||||
* renewed PodcastIndex API keys
|
||||
* added share notes menu option in episode view
|
||||
* press on title area of an episode now opens the episode info faster and more economically - without horizontal swipe
|
||||
* press on the icon of an episode opens the episode info the original way - with horizontal swipe
|
Loading…
Reference in New Issue