mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 03:18:06 +00:00
Added seek to recordings player & media player
This commit is contained in:
parent
40d195e06b
commit
61c79a86f7
10 changed files with 122 additions and 22 deletions
|
|
@ -15,6 +15,7 @@ Group changes to describe their impact on the project, as follows:
|
|||
### Added
|
||||
- Added the ability to edit/delete chat messages sent less than 24 hours ago.
|
||||
- Added keyboard shortcuts on IncomingCallFragment: Ctrl + Shift + A to answer the call, Ctrl + Shift + D to decline it
|
||||
- Added seeking feature to recordings & media player within app
|
||||
- Added PDF preview in conversation (message bubble & documents list)
|
||||
- Added hover effect when using a mouse (useful for tablets or devices with desktop mode)
|
||||
- Support right click on some items to open bottom sheet/menu
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import android.view.Surface
|
|||
import android.view.TextureView.SurfaceTextureListener
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.SeekBar
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.linphone.core.tools.Log
|
||||
|
|
@ -45,6 +46,21 @@ class MediaViewerFragment : GenericMainFragment() {
|
|||
|
||||
private lateinit var viewModel: MediaViewModel
|
||||
|
||||
private val seekBarListener = object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||
viewModel.pause()
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||
val newPosition = seekBar.progress
|
||||
viewModel.seekTo(newPosition)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
@ -87,6 +103,8 @@ class MediaViewerFragment : GenericMainFragment() {
|
|||
sharedViewModel.mediaViewerFullScreenMode.value = fullScreenMode
|
||||
}
|
||||
|
||||
binding.setSeekBarListener(seekBarListener)
|
||||
|
||||
viewModel.videoSizeChangedEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { pair ->
|
||||
val width = pair.first
|
||||
|
|
|
|||
|
|
@ -161,6 +161,14 @@ class MediaViewModel
|
|||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun seekTo(position: Int) {
|
||||
if (::mediaPlayer.isInitialized) {
|
||||
mediaPlayer.seekTo(position)
|
||||
play()
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private fun initMediaPlayer() {
|
||||
isMediaPlaying.value = false
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import android.view.LayoutInflater
|
|||
import android.view.TextureView
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.SeekBar
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -52,6 +53,21 @@ class RecordingMediaPlayerFragment : GenericMainFragment() {
|
|||
|
||||
private lateinit var viewModel: RecordingMediaPlayerViewModel
|
||||
|
||||
private val seekBarListener = object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||
viewModel.pause()
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||
val newPosition = seekBar.progress
|
||||
viewModel.seekTo(newPosition)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
@ -84,6 +100,8 @@ class RecordingMediaPlayerFragment : GenericMainFragment() {
|
|||
exportFile(viewModel.recordingModel.filePath)
|
||||
}
|
||||
|
||||
binding.setSeekBarListener(seekBarListener)
|
||||
|
||||
val model = sharedViewModel.playingRecording
|
||||
if (model != null) {
|
||||
Log.i("$TAG Loading recording [${model.fileName}] from shared view model")
|
||||
|
|
|
|||
|
|
@ -175,6 +175,14 @@ class RecordingMediaPlayerViewModel
|
|||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun seekTo(position: Int) {
|
||||
coreContext.postOnCoreThread {
|
||||
seekPlaybackTo(position)
|
||||
startPlayback()
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun startPlayback() {
|
||||
if (!::player.isInitialized) return
|
||||
|
|
@ -232,6 +240,18 @@ class RecordingMediaPlayerViewModel
|
|||
updatePositionJob = null
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun seekPlaybackTo(position: Int) {
|
||||
if (!::player.isInitialized) return
|
||||
|
||||
if (player.state == Player.State.Closed) {
|
||||
player.open(recordingModel.filePath)
|
||||
}
|
||||
|
||||
Log.i("$TAG Seeking player to position [$position]")
|
||||
player.seek(position)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun stop() {
|
||||
if (!::player.isInitialized) return
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import android.view.ViewGroup
|
|||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.SeekBar
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DimenRes
|
||||
|
|
@ -633,6 +634,11 @@ fun setFlexboxLayoutWrapBefore(view: View, wrap: Boolean = false) {
|
|||
view.layoutParams = params
|
||||
}
|
||||
|
||||
@BindingAdapter("seekBarListener")
|
||||
fun setSeekBarListener(seekBar: SeekBar, listener: SeekBar.OnSeekBarChangeListener) {
|
||||
seekBar.setOnSeekBarChangeListener(listener)
|
||||
}
|
||||
|
||||
@BindingAdapter("emojiPickedListener")
|
||||
fun EmojiPickerView.setEmojiPickedListener(listener: EmojiPickedListener) {
|
||||
setOnEmojiPickedListener { emoji ->
|
||||
|
|
|
|||
19
app/src/main/res/drawable/media_player_seekbar.xml
Normal file
19
app/src/main/res/drawable/media_player_seekbar.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:gravity="center_vertical">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="?attr/color_main1_100" />
|
||||
<size android:height="10dp" />
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:gravity="center_vertical">
|
||||
<scale android:scaleWidth="100%">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="?attr/color_main1_500" />
|
||||
<size android:height="10dp" />
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
||||
</scale>
|
||||
</item>
|
||||
</layer-list>
|
||||
10
app/src/main/res/drawable/media_player_seekbar_thumb.xml
Normal file
10
app/src/main/res/drawable/media_player_seekbar_thumb.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="@color/bc_white" />
|
||||
<size android:height="20dp" android:width="20dp" />
|
||||
<corners android:radius="20dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
@ -5,9 +5,13 @@
|
|||
|
||||
<data>
|
||||
<import type="android.view.View" />
|
||||
<import type="android.widget.SeekBar" />
|
||||
<variable
|
||||
name="toggleFullScreenModeClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="seekBarListener"
|
||||
type="SeekBar.OnSeekBarChangeListener" />
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="org.linphone.ui.fileviewer.viewmodel.MediaViewModel" />
|
||||
|
|
@ -75,24 +79,20 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:tint="@color/bc_white"/>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
<SeekBar
|
||||
seekBarListener="@{seekBarListener}"
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_height="0dp"
|
||||
android:splitTrack="false"
|
||||
android:max="@{viewModel.duration, default=100}"
|
||||
android:progress="@{viewModel.position, default=75}"
|
||||
app:trackCornerRadius="5dp"
|
||||
app:trackThickness="10dp"
|
||||
app:trackColor="?attr/color_main1_100"
|
||||
app:indicatorColor="?attr/color_main1_500"
|
||||
app:trackStopIndicatorSize="0dp"
|
||||
app:indicatorTrackGapSize="0dp"
|
||||
android:progressDrawable="@drawable/media_player_seekbar"
|
||||
android:thumb="@drawable/media_player_seekbar_thumb"
|
||||
app:layout_constraintTop_toTopOf="@id/play_pause_audio_playback"
|
||||
app:layout_constraintBottom_toBottomOf="@id/play_pause_audio_playback"
|
||||
app:layout_constraintStart_toEndOf="@id/play_pause_audio_playback"
|
||||
app:layout_constraintEnd_toStartOf="@id/duration"/>
|
||||
app:layout_constraintEnd_toStartOf="@id/duration" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style_700"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
<data>
|
||||
<import type="android.view.View" />
|
||||
<import type="android.widget.SeekBar" />
|
||||
<variable
|
||||
name="backClickListener"
|
||||
type="View.OnClickListener" />
|
||||
|
|
@ -14,6 +15,9 @@
|
|||
<variable
|
||||
name="exportClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="seekBarListener"
|
||||
type="SeekBar.OnSeekBarChangeListener" />
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="org.linphone.ui.main.recordings.viewmodel.RecordingMediaPlayerViewModel" />
|
||||
|
|
@ -62,24 +66,20 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:tint="@color/bc_white"/>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
<SeekBar
|
||||
seekBarListener="@{seekBarListener}"
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_height="0dp"
|
||||
android:splitTrack="false"
|
||||
android:max="@{viewModel.duration, default=100}"
|
||||
android:progress="@{viewModel.position, default=75}"
|
||||
app:trackCornerRadius="5dp"
|
||||
app:trackThickness="10dp"
|
||||
app:trackColor="?attr/color_main1_100"
|
||||
app:indicatorColor="?attr/color_main1_500"
|
||||
app:trackStopIndicatorSize="0dp"
|
||||
app:indicatorTrackGapSize="0dp"
|
||||
android:progressDrawable="@drawable/media_player_seekbar"
|
||||
android:thumb="@drawable/media_player_seekbar_thumb"
|
||||
app:layout_constraintTop_toTopOf="@id/play_pause_audio_playback"
|
||||
app:layout_constraintBottom_toBottomOf="@id/play_pause_audio_playback"
|
||||
app:layout_constraintStart_toEndOf="@id/play_pause_audio_playback"
|
||||
app:layout_constraintEnd_toStartOf="@id/duration"/>
|
||||
app:layout_constraintEnd_toStartOf="@id/duration" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style_700"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue