Merge pull request #5112 from Bnyro/master

refactor: make audio player more accessible and redesign
This commit is contained in:
Bnyro 2023-11-05 13:55:27 +01:00 committed by GitHub
commit 124bff117d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 128 additions and 99 deletions

View File

@ -32,4 +32,5 @@ object IntentData {
const val url = "url" const val url = "url"
const val videoStats = "videoStats" const val videoStats = "videoStats"
const val bitmapUrl = "bitmapUrl" const val bitmapUrl = "bitmapUrl"
const val isCurrentlyPlaying = "isCurrentlyPlaying"
} }

View File

@ -27,7 +27,6 @@ import com.github.libretube.R
import com.github.libretube.api.obj.StreamItem import com.github.libretube.api.obj.StreamItem
import com.github.libretube.constants.IntentData import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.FragmentAudioPlayerBinding import com.github.libretube.databinding.FragmentAudioPlayerBinding
import com.github.libretube.enums.ShareObjectType
import com.github.libretube.extensions.normalize import com.github.libretube.extensions.normalize
import com.github.libretube.extensions.seekBy import com.github.libretube.extensions.seekBy
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
@ -37,11 +36,8 @@ import com.github.libretube.helpers.ImageHelper
import com.github.libretube.helpers.NavigationHelper import com.github.libretube.helpers.NavigationHelper
import com.github.libretube.helpers.PlayerHelper import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.ThemeHelper import com.github.libretube.helpers.ThemeHelper
import com.github.libretube.obj.ShareData
import com.github.libretube.services.OnlinePlayerService import com.github.libretube.services.OnlinePlayerService
import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.dialogs.DownloadDialog
import com.github.libretube.ui.dialogs.ShareDialog
import com.github.libretube.ui.interfaces.AudioPlayerOptions import com.github.libretube.ui.interfaces.AudioPlayerOptions
import com.github.libretube.ui.listeners.AudioPlayerThumbnailListener import com.github.libretube.ui.listeners.AudioPlayerThumbnailListener
import com.github.libretube.ui.models.PlayerViewModel import com.github.libretube.ui.models.PlayerViewModel
@ -168,28 +164,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
) )
} }
binding.download.setOnClickListener { binding.openChapters.setOnClickListener {
val videoId = PlayingQueue.getCurrent()?.url?.toID() ?: return@setOnClickListener
val newFragment = DownloadDialog()
newFragment.arguments = bundleOf(IntentData.videoId to videoId)
newFragment.show(childFragmentManager, DownloadDialog::class.java.name)
}
binding.share.setOnClickListener {
val currentVideo = PlayingQueue.getCurrent() ?: return@setOnClickListener
val bundle = bundleOf(
IntentData.id to currentVideo.url!!.toID(),
IntentData.shareObjectType to ShareObjectType.VIDEO,
IntentData.shareData to ShareData(currentVideo = currentVideo.title)
)
val newShareDialog = ShareDialog()
newShareDialog.arguments = bundle
newShareDialog.show(childFragmentManager, null)
}
binding.chapters.setOnClickListener {
val playerService = playerService ?: return@setOnClickListener val playerService = playerService ?: return@setOnClickListener
viewModel.chaptersLiveData.value = playerService.streams?.chapters.orEmpty() viewModel.chaptersLiveData.value = playerService.streams?.chapters.orEmpty()
@ -197,6 +172,12 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
.show(childFragmentManager) .show(childFragmentManager)
} }
binding.close.setOnClickListener {
activity?.unbindService(connection)
BackgroundHelper.stopBackgroundPlay(requireContext())
killFragment()
}
binding.miniPlayerClose.setOnClickListener { binding.miniPlayerClose.setOnClickListener {
activity?.unbindService(connection) activity?.unbindService(connection)
BackgroundHelper.stopBackgroundPlay(requireContext()) BackgroundHelper.stopBackgroundPlay(requireContext())
@ -214,6 +195,10 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
if (isPaused) playerService?.play() else playerService?.pause() if (isPaused) playerService?.play() else playerService?.pause()
} }
binding.showMore.setOnClickListener {
onLongTap()
}
// load the stream info into the UI // load the stream info into the UI
updateStreamInfo() updateStreamInfo()
@ -371,7 +356,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
} }
playerService?.onNewVideo = { streams, videoId -> playerService?.onNewVideo = { streams, videoId ->
updateStreamInfo(streams.toStreamItem(videoId)) updateStreamInfo(streams.toStreamItem(videoId))
_binding?.chapters?.isVisible = streams.chapters.isNotEmpty() _binding?.openChapters?.isVisible = streams.chapters.isNotEmpty()
} }
initializeSeekBar() initializeSeekBar()
} }
@ -400,7 +385,12 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
override fun onLongTap() { override fun onLongTap() {
val current = PlayingQueue.getCurrent() ?: return val current = PlayingQueue.getCurrent() ?: return
VideoOptionsBottomSheet() VideoOptionsBottomSheet()
.apply { arguments = bundleOf(IntentData.shareData to current) } .apply {
arguments = bundleOf(
IntentData.streamItem to current,
IntentData.isCurrentlyPlaying to true
)
}
.show(childFragmentManager) .show(childFragmentManager)
} }

View File

@ -36,41 +36,17 @@ import kotlinx.coroutines.withContext
*/ */
class VideoOptionsBottomSheet : BaseBottomSheet() { class VideoOptionsBottomSheet : BaseBottomSheet() {
private lateinit var streamItem: StreamItem private lateinit var streamItem: StreamItem
private var isCurrentlyPlaying = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
streamItem = arguments?.parcelable(IntentData.streamItem)!! streamItem = arguments?.parcelable(IntentData.streamItem)!!
isCurrentlyPlaying = arguments?.getBoolean(IntentData.isCurrentlyPlaying) ?: false
val videoId = streamItem.url?.toID() ?: return val videoId = streamItem.url?.toID() ?: return
// List that stores the different menu options. In the future could be add more options here.
val optionsList = mutableListOf(
getString(R.string.playOnBackground)
)
// Check whether the player is running and add queue options val optionsList = mutableListOf<String>()
if (PlayingQueue.isNotEmpty()) { if (!isCurrentlyPlaying) {
optionsList += getString(R.string.play_next) optionsList += getOptionsForNotActivePlayback(videoId)
optionsList += getString(R.string.add_to_queue)
}
// show the mark as watched or unwatched option if watch positions are enabled
if (PlayerHelper.watchPositionsVideo || PlayerHelper.watchHistoryEnabled) {
val watchPositionEntry = runBlocking(Dispatchers.IO) {
DatabaseHolder.Database.watchPositionDao().findById(videoId)
}
val watchHistoryEntry = runBlocking(Dispatchers.IO) {
DatabaseHolder.Database.watchHistoryDao().findById(videoId)
}
if (streamItem.duration == null ||
watchPositionEntry == null ||
watchPositionEntry.position < streamItem.duration!! * 1000 * 0.9
) {
optionsList += getString(R.string.mark_as_watched)
}
if (watchHistoryEntry != null || watchPositionEntry != null) {
optionsList += getString(R.string.mark_as_unwatched)
}
} }
optionsList += listOf( optionsList += listOf(
@ -155,6 +131,42 @@ class VideoOptionsBottomSheet : BaseBottomSheet() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
private fun getOptionsForNotActivePlayback(videoId: String): List<String> {
// List that stores the different menu options. In the future could be add more options here.
val optionsList = mutableListOf(
getString(R.string.playOnBackground)
)
// Check whether the player is running and add queue options
if (PlayingQueue.isNotEmpty()) {
optionsList += getString(R.string.play_next)
optionsList += getString(R.string.add_to_queue)
}
// show the mark as watched or unwatched option if watch positions are enabled
if (PlayerHelper.watchPositionsVideo || PlayerHelper.watchHistoryEnabled) {
val watchPositionEntry = runBlocking(Dispatchers.IO) {
DatabaseHolder.Database.watchPositionDao().findById(videoId)
}
val watchHistoryEntry = runBlocking(Dispatchers.IO) {
DatabaseHolder.Database.watchHistoryDao().findById(videoId)
}
if (streamItem.duration == null ||
watchPositionEntry == null ||
watchPositionEntry.position < streamItem.duration!! * 1000 * 0.9
) {
optionsList += getString(R.string.mark_as_watched)
}
if (watchHistoryEntry != null || watchPositionEntry != null) {
optionsList += getString(R.string.mark_as_unwatched)
}
}
return optionsList
}
companion object { companion object {
const val VIDEO_OPTIONS_SHEET_REQUEST_KEY = "video_options_sheet_request_key" const val VIDEO_OPTIONS_SHEET_REQUEST_KEY = "video_options_sheet_request_key"
} }

View File

@ -56,6 +56,22 @@
app:track="@drawable/player_switch_track" app:track="@drawable/player_switch_track"
app:trackTint="?colorControlNormal" /> app:trackTint="?colorControlNormal" />
<ImageView
android:id="@+id/open_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginHorizontal="6dp"
android:src="@drawable/ic_video" />
<ImageView
android:id="@+id/close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginHorizontal="6dp"
android:src="@drawable/ic_close" />
</LinearLayout> </LinearLayout>
<FrameLayout <FrameLayout
@ -259,52 +275,64 @@
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
style="@style/Widget.Material3.CardView.Elevated" style="@style/Widget.Material3.CardView.Elevated"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginBottom="30dp" android:layout_marginTop="30dp"
app:cardCornerRadius="18dp"> app:shapeAppearanceOverlay="@style/CardOnlyBottomCorners">
<LinearLayout <FrameLayout
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:padding="15dp"> android:padding="15dp">
<ImageView
android:id="@+id/open_queue"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_queue" />
<ImageView <ImageView
android:id="@+id/playback_options" android:id="@+id/playback_options"
style="@style/AudioPlayerButton" android:layout_width="wrap_content"
android:layout_width="27dp" android:layout_height="wrap_content"
android:layout_height="27dp" android:layout_gravity="start|center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleX="0.9"
android:scaleY="0.9"
android:src="@drawable/ic_speed" /> android:src="@drawable/ic_speed" />
<ImageView <LinearLayout
android:id="@+id/open_video" android:layout_width="wrap_content"
style="@style/AudioPlayerButton" android:layout_height="wrap_content"
android:src="@drawable/ic_video" /> android:layout_gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/open_chapters"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleX="0.9"
android:scaleY="0.9"
android:src="@drawable/ic_frame" />
<ImageView
android:id="@+id/open_queue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_queue" />
</LinearLayout>
<ImageView <ImageView
android:id="@+id/download" android:id="@+id/show_more"
style="@style/AudioPlayerButton" android:layout_width="wrap_content"
android:src="@drawable/ic_download" /> android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleX="0.9"
android:scaleY="0.9"
android:src="@drawable/ic_three_dots" />
<ImageView </FrameLayout>
android:id="@+id/share"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_share" />
<ImageView
android:id="@+id/chapters"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_frame"
android:visibility="gone" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View File

@ -196,6 +196,14 @@
<item name="android:drawableTint" tools:targetApi="m">?android:attr/textColorPrimary</item> <item name="android:drawableTint" tools:targetApi="m">?android:attr/textColorPrimary</item>
</style> </style>
<style name="CardOnlyBottomCorners">
<item name="cornerFamily">rounded</item>
<item name="cornerSizeTopRight">0dp</item>
<item name="cornerSizeTopLeft">0dp</item>
<item name="cornerSizeBottomRight">18dp</item>
<item name="cornerSizeBottomLeft">18dp</item>
</style>
<style name="HomeCategoryTitle"> <style name="HomeCategoryTitle">
<item name="android:layout_width">match_parent</item> <item name="android:layout_width">match_parent</item>
@ -209,16 +217,6 @@
</style> </style>
<style name="AudioPlayerButton">
<item name="android:layout_width">30dp</item>
<item name="android:layout_height">30dp</item>
<item name="android:background">?attr/selectableItemBackgroundBorderless</item>
<item name="android:layout_marginStart">10dp</item>
<item name="android:layout_marginEnd">10dp</item>
</style>
<style name="TextViewMarquee"> <style name="TextViewMarquee">
<item name="android:singleLine">true</item> <item name="android:singleLine">true</item>