mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 16:30:31 +05:30
Merge pull request #5112 from Bnyro/master
refactor: make audio player more accessible and redesign
This commit is contained in:
commit
124bff117d
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user