mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
Reworked file viewer interface, improved video/audio player
This commit is contained in:
parent
26e30c6060
commit
376af91e88
13 changed files with 304 additions and 173 deletions
|
|
@ -53,17 +53,23 @@ class FileViewerActivity : GenericActivity() {
|
|||
binding.viewModel = viewModel
|
||||
|
||||
val args = intent.extras
|
||||
val path = args?.getString("path")
|
||||
if (args == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
val path = args.getString("path")
|
||||
if (path.isNullOrEmpty()) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
val timestamp = args.getLong("timestamp", -1)
|
||||
val preLoadedContent = args.getString("content")
|
||||
Log.i(
|
||||
"$TAG Path argument is [$path], pre loaded text content is ${if (preLoadedContent.isNullOrEmpty()) "not available" else "available, using it"}"
|
||||
)
|
||||
viewModel.loadFile(path, preLoadedContent)
|
||||
viewModel.loadFile(path, timestamp, preLoadedContent)
|
||||
|
||||
binding.setBackClickListener {
|
||||
finish()
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ class MediaViewerActivity : GenericActivity() {
|
|||
val list = viewModel.mediaList.value.orEmpty()
|
||||
if (position >= 0 && position < list.size) {
|
||||
val model = list[position]
|
||||
viewModel.currentlyDisplayedFileName.value = "${model.fileName}\n${model.dateTime}"
|
||||
viewModel.currentlyDisplayedFileName.value = model.fileName
|
||||
viewModel.currentlyDisplayedFileDateTime.value = model.dateTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,11 @@
|
|||
*/
|
||||
package org.linphone.ui.file_viewer.fragment
|
||||
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Surface
|
||||
import android.view.TextureView.SurfaceTextureListener
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.UiThread
|
||||
|
|
@ -81,24 +84,6 @@ class MediaViewerFragment : GenericMainFragment() {
|
|||
Log.i("$TAG Path argument is [$path], it ${if (exists) "exists" else "doesn't exist"}")
|
||||
viewModel.loadFile(path)
|
||||
|
||||
viewModel.isVideo.observe(viewLifecycleOwner) { isVideo ->
|
||||
if (isVideo) {
|
||||
initVideoPlayer(path)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.toggleVideoPlayPauseEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { play ->
|
||||
if (play) {
|
||||
Log.i("$TAG Starting video player")
|
||||
binding.videoPlayer.start()
|
||||
} else {
|
||||
Log.i("$TAG Pausing video player")
|
||||
binding.videoPlayer.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.setToggleFullScreenModeClickListener {
|
||||
viewModel.toggleFullScreen()
|
||||
fullScreenChanged?.invoke(viewModel.fullScreenMode.value == true)
|
||||
|
|
@ -108,40 +93,47 @@ class MediaViewerFragment : GenericMainFragment() {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
if (viewModel.isVideo.value == true) {
|
||||
Log.i("$TAG Resumed, starting video player")
|
||||
binding.videoPlayer.start()
|
||||
viewModel.isVideoPlaying.value = true
|
||||
val textureView = binding.videoPlayer
|
||||
if (textureView.isAvailable) {
|
||||
Log.i("$TAG Surface created, setting display in mediaPlayer")
|
||||
viewModel.mediaPlayer.setSurface((Surface(textureView.surfaceTexture)))
|
||||
} else {
|
||||
Log.i("$TAG Surface not available yet, setting listener")
|
||||
textureView.surfaceTextureListener = object : SurfaceTextureListener {
|
||||
override fun onSurfaceTextureAvailable(
|
||||
surfaceTexture: SurfaceTexture,
|
||||
p1: Int,
|
||||
p2: Int
|
||||
) {
|
||||
Log.i("$TAG Surface available, setting display in mediaPlayer")
|
||||
viewModel.mediaPlayer.setSurface(Surface(surfaceTexture))
|
||||
}
|
||||
|
||||
override fun onSurfaceTextureSizeChanged(
|
||||
surfaceTexture: SurfaceTexture,
|
||||
p1: Int,
|
||||
p2: Int
|
||||
) {
|
||||
}
|
||||
|
||||
override fun onSurfaceTextureDestroyed(surfaceTexture: SurfaceTexture): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSurfaceTextureUpdated(surfaceTexture: SurfaceTexture) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.play()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
if (binding.videoPlayer.isPlaying) {
|
||||
Log.i("$TAG Paused, stopping video player")
|
||||
binding.videoPlayer.pause()
|
||||
viewModel.isVideoPlaying.value = false
|
||||
}
|
||||
|
||||
if (viewModel.isAudioPlaying.value == true) {
|
||||
Log.i("$TAG Paused, stopping audio player")
|
||||
viewModel.pauseAudio()
|
||||
if (viewModel.isMediaPlaying.value == true) {
|
||||
Log.i("$TAG Paused, stopping media player")
|
||||
viewModel.pause()
|
||||
}
|
||||
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding.videoPlayer.stopPlayback()
|
||||
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun initVideoPlayer(path: String) {
|
||||
Log.i("$TAG Creating video player for file [$path]")
|
||||
binding.videoPlayer.setVideoPath(path)
|
||||
binding.videoPlayer.setOnCompletionListener {
|
||||
Log.i("$TAG End of file reached")
|
||||
viewModel.isVideoPlaying.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import org.linphone.core.tools.Log
|
|||
import org.linphone.ui.GenericViewModel
|
||||
import org.linphone.utils.Event
|
||||
import org.linphone.utils.FileUtils
|
||||
import org.linphone.utils.TimestampUtils
|
||||
|
||||
class FileViewModel @UiThread constructor() : GenericViewModel() {
|
||||
companion object {
|
||||
|
|
@ -64,6 +65,8 @@ class FileViewModel @UiThread constructor() : GenericViewModel() {
|
|||
|
||||
val fileReadyEvent = MutableLiveData<Event<Boolean>>()
|
||||
|
||||
val dateTime = MutableLiveData<String>()
|
||||
|
||||
val exportPlainTextFileEvent: MutableLiveData<Event<String>> by lazy {
|
||||
MutableLiveData<Event<String>>()
|
||||
}
|
||||
|
|
@ -98,12 +101,18 @@ class FileViewModel @UiThread constructor() : GenericViewModel() {
|
|||
}
|
||||
|
||||
@UiThread
|
||||
fun loadFile(file: String, content: String? = null) {
|
||||
fun loadFile(file: String, timestamp: Long, content: String? = null) {
|
||||
fullScreenMode.value = true
|
||||
|
||||
val name = FileUtils.getNameFromFilePath(file)
|
||||
fileName.value = name
|
||||
|
||||
dateTime.value = TimestampUtils.toString(
|
||||
timestamp,
|
||||
shortDate = false,
|
||||
hideYear = false
|
||||
)
|
||||
|
||||
if (!content.isNullOrEmpty()) {
|
||||
isText.value = true
|
||||
text.postValue(content!!)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ class MediaListViewModel @UiThread constructor() : AbstractConversationViewModel
|
|||
|
||||
val currentlyDisplayedFileName = MutableLiveData<String>()
|
||||
|
||||
val currentlyDisplayedFileDateTime = MutableLiveData<String>()
|
||||
|
||||
override fun beforeNotifyingChatRoomFound(sameOne: Boolean) {
|
||||
loadMediaList()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,10 +23,16 @@ import android.media.AudioAttributes
|
|||
import android.media.MediaPlayer
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.ticker
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.ui.GenericViewModel
|
||||
import org.linphone.utils.Event
|
||||
import org.linphone.utils.FileUtils
|
||||
import org.linphone.utils.TimestampUtils
|
||||
|
||||
class MediaViewModel @UiThread constructor() : GenericViewModel() {
|
||||
companion object {
|
||||
|
|
@ -43,24 +49,29 @@ class MediaViewModel @UiThread constructor() : GenericViewModel() {
|
|||
|
||||
val isVideo = MutableLiveData<Boolean>()
|
||||
|
||||
val isVideoPlaying = MutableLiveData<Boolean>()
|
||||
|
||||
val isAudio = MutableLiveData<Boolean>()
|
||||
|
||||
val isAudioPlaying = MutableLiveData<Boolean>()
|
||||
val isMediaPlaying = MutableLiveData<Boolean>()
|
||||
|
||||
val toggleVideoPlayPauseEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||
MutableLiveData<Event<Boolean>>()
|
||||
}
|
||||
val duration = MutableLiveData<Int>()
|
||||
|
||||
val formattedDuration = MutableLiveData<String>()
|
||||
|
||||
val position = MutableLiveData<Int>()
|
||||
|
||||
lateinit var mediaPlayer: MediaPlayer
|
||||
|
||||
private lateinit var filePath: String
|
||||
|
||||
private lateinit var mediaPlayer: MediaPlayer
|
||||
private val tickerChannel = ticker(1000, 1000)
|
||||
|
||||
private var updatePositionJob: Job? = null
|
||||
|
||||
override fun onCleared() {
|
||||
if (::mediaPlayer.isInitialized) {
|
||||
mediaPlayer.release()
|
||||
}
|
||||
stopUpdatePlaybackPosition()
|
||||
|
||||
super.onCleared()
|
||||
}
|
||||
|
|
@ -81,14 +92,13 @@ class MediaViewModel @UiThread constructor() : GenericViewModel() {
|
|||
}
|
||||
FileUtils.MimeType.Video -> {
|
||||
Log.d("$TAG File [$file] seems to be a video")
|
||||
initMediaPlayer()
|
||||
isVideo.value = true
|
||||
isVideoPlaying.value = false
|
||||
}
|
||||
FileUtils.MimeType.Audio -> {
|
||||
Log.d("$TAG File [$file] seems to be an audio file")
|
||||
isAudio.value = true
|
||||
|
||||
initMediaPlayer()
|
||||
isAudio.value = true
|
||||
}
|
||||
else -> {
|
||||
Log.e("$TAG Unexpected MIME type [$mime] for file at [$file]")
|
||||
|
|
@ -102,35 +112,44 @@ class MediaViewModel @UiThread constructor() : GenericViewModel() {
|
|||
}
|
||||
|
||||
@UiThread
|
||||
fun playPauseVideo() {
|
||||
val playVideo = isVideoPlaying.value == false
|
||||
isVideoPlaying.value = playVideo
|
||||
toggleVideoPlayPauseEvent.value = Event(playVideo)
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun playPauseAudio() {
|
||||
fun togglePlayPause() {
|
||||
if (::mediaPlayer.isInitialized) {
|
||||
if (mediaPlayer.isPlaying) {
|
||||
mediaPlayer.pause()
|
||||
isAudioPlaying.value = false
|
||||
|
||||
isMediaPlaying.value = false
|
||||
stopUpdatePlaybackPosition()
|
||||
} else {
|
||||
mediaPlayer.start()
|
||||
isAudioPlaying.value = true
|
||||
|
||||
isMediaPlaying.value = true
|
||||
startUpdatePlaybackPosition()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun pauseAudio() {
|
||||
fun play() {
|
||||
if (::mediaPlayer.isInitialized) {
|
||||
mediaPlayer.start()
|
||||
startUpdatePlaybackPosition()
|
||||
isMediaPlaying.value = true
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun pause() {
|
||||
if (::mediaPlayer.isInitialized) {
|
||||
isMediaPlaying.value = false
|
||||
stopUpdatePlaybackPosition()
|
||||
mediaPlayer.pause()
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private fun initMediaPlayer() {
|
||||
isAudioPlaying.value = false
|
||||
isMediaPlaying.value = false
|
||||
|
||||
mediaPlayer = MediaPlayer().apply {
|
||||
setAudioAttributes(
|
||||
AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).setUsage(
|
||||
|
|
@ -140,12 +159,39 @@ class MediaViewModel @UiThread constructor() : GenericViewModel() {
|
|||
setDataSource(filePath)
|
||||
setOnCompletionListener {
|
||||
Log.i("$TAG Media player reached the end of file")
|
||||
isAudioPlaying.postValue(false)
|
||||
isMediaPlaying.postValue(false)
|
||||
position.postValue(0)
|
||||
stopUpdatePlaybackPosition()
|
||||
|
||||
// Leave full screen when playback is done
|
||||
fullScreenMode.postValue(false)
|
||||
}
|
||||
prepare()
|
||||
start()
|
||||
isAudioPlaying.value = true
|
||||
}
|
||||
Log.i("$TAG Media player for file [$filePath] created")
|
||||
|
||||
val durationInMillis = mediaPlayer.duration
|
||||
position.value = 0
|
||||
duration.value = durationInMillis
|
||||
formattedDuration.value = TimestampUtils.durationToString(durationInMillis / 1000)
|
||||
Log.i("$TAG Media player for file [$filePath] created, let's start it")
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun startUpdatePlaybackPosition() {
|
||||
updatePositionJob = viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
for (tick in tickerChannel) {
|
||||
if (::mediaPlayer.isInitialized && mediaPlayer.isPlaying) {
|
||||
position.postValue(mediaPlayer.currentPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun stopUpdatePlaybackPosition() {
|
||||
updatePositionJob?.cancel()
|
||||
updatePositionJob = null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ class FileModel @AnyThread constructor(
|
|||
FileUtils.deleteFile(path)
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
private fun getDuration() {
|
||||
try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ class DebugFragment : GenericMainFragment() {
|
|||
val bundle = Bundle()
|
||||
bundle.putString("path", CorePreferences.CONFIG_FILE_NAME)
|
||||
bundle.putString("content", content)
|
||||
val nowInSeconds = System.currentTimeMillis() / 1000
|
||||
bundle.putLong("timestamp", nowInSeconds)
|
||||
intent.putExtras(bundle)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import androidx.lifecycle.MutableLiveData
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.media.AudioFocusRequestCompat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.channels.ticker
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -67,6 +68,7 @@ class RecordingsListViewModel @UiThread constructor() : GenericViewModel() {
|
|||
}
|
||||
|
||||
private val tickerChannel = ticker(1000, 1000)
|
||||
private var updatePositionJob: Job? = null
|
||||
|
||||
init {
|
||||
searchBarVisible.value = false
|
||||
|
|
@ -166,7 +168,7 @@ class RecordingsListViewModel @UiThread constructor() : GenericViewModel() {
|
|||
player?.start()
|
||||
model.isPlaying.postValue(true)
|
||||
|
||||
viewModelScope.launch {
|
||||
updatePositionJob = viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
for (tick in tickerChannel) {
|
||||
coreContext.postOnCoreThread {
|
||||
|
|
@ -193,6 +195,8 @@ class RecordingsListViewModel @UiThread constructor() : GenericViewModel() {
|
|||
|
||||
player?.pause()
|
||||
model.isPlaying.postValue(false)
|
||||
updatePositionJob?.cancel()
|
||||
updatePositionJob = null
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
|
|
|||
9
app/src/main/res/drawable/music_notes.xml
Normal file
9
app/src/main/res/drawable/music_notes.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="64dp"
|
||||
android:height="64dp"
|
||||
android:viewportWidth="256"
|
||||
android:viewportHeight="256">
|
||||
<path
|
||||
android:pathData="M212.92,17.69a8,8 0,0 0,-6.86 -1.45l-128,32A8,8 0,0 0,72 56V166.08A36,36 0,1 0,88 196V110.25l112,-28v51.83A36,36 0,1 0,216 164V24A8,8 0,0 0,212.92 17.69ZM52,216a20,20 0,1 1,20 -20A20,20 0,0 1,52 216ZM88,93.75V62.25l112,-28v31.5ZM180,184a20,20 0,1 1,20 -20A20,20 0,0 1,180 184Z"
|
||||
android:fillColor="#4e6074"/>
|
||||
</vector>
|
||||
|
|
@ -27,7 +27,14 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
|
||||
app:constraint_referenced_ids="back, title, share, save, file_name"/>
|
||||
app:constraint_referenced_ids="top_bar_background, back, file_name, share, save, date_time"/>
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/top_bar_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="back, date_time"
|
||||
app:barrierDirection="bottom" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/media_view_pager"
|
||||
|
|
@ -35,78 +42,85 @@
|
|||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
<View
|
||||
android:id="@+id/top_bar_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@color/white"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/top_bar_barrier"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:onClick="@{backClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/caret_left"
|
||||
android:contentDescription="@string/content_description_go_back_icon"
|
||||
app:tint="?attr/color_main1_500"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/title" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/main_page_title_style"
|
||||
android:id="@+id/title"
|
||||
style="@style/default_text_style_700"
|
||||
android:id="@+id/file_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{viewModel.currentlyDisplayedFileName, default=`nomdufichier.jpg`}"
|
||||
android:textSize="13sp"
|
||||
android:textColor="?attr/color_main2_600"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintEnd_toStartOf="@id/share"
|
||||
app:layout_constraintStart_toEndOf="@id/back"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/date_time"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style_300"
|
||||
android:id="@+id/date_time"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{viewModel.currentlyDisplayedFileDateTime, default=`envoyé le 02/05/2023 à 11h05`}"
|
||||
android:textSize="12sp"
|
||||
android:textColor="?attr/color_main2_500"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintTop_toBottomOf="@id/file_name"
|
||||
app:layout_constraintBottom_toBottomOf="@id/back"
|
||||
app:layout_constraintEnd_toStartOf="@id/share"
|
||||
app:layout_constraintStart_toEndOf="@id/back"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/share"
|
||||
android:onClick="@{shareClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/share_network"
|
||||
android:contentDescription="@string/content_description_share_file"
|
||||
app:tint="?attr/color_main1_500"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintEnd_toStartOf="@id/save"
|
||||
app:layout_constraintTop_toTopOf="@id/title" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/save"
|
||||
android:onClick="@{exportClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/download_simple"
|
||||
android:contentDescription="@string/content_description_save_file"
|
||||
app:tint="?attr/color_main1_500"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/title" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style_300"
|
||||
android:id="@+id/file_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:text="@{viewModel.currentlyDisplayedFileName, default=`nomdufichier.jpg\nenvoyé le 02/05/2023 à 11h05`}"
|
||||
android:textSize="12sp"
|
||||
android:textColor="?attr/color_main2_600"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/toasts_area"
|
||||
|
|
|
|||
|
|
@ -19,22 +19,13 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="@color/black">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/play_pause_audio_playback"
|
||||
android:onClick="@{() -> viewModel.playPauseAudio()}"
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:contentDescription="@string/content_description_play_pause_video_playback"
|
||||
android:src="@{viewModel.isAudioPlaying ? @drawable/pause_fill : @drawable/play_fill, default=@drawable/play_fill}"
|
||||
android:visibility="@{viewModel.isAudio ? View.VISIBLE : View.GONE, default=gone}"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:tint="@color/white"/>
|
||||
android:visibility="@{viewModel.fullScreenMode ? View.GONE : viewModel.isAudio || viewModel.isVideo ? View.VISIBLE : View.GONE}"
|
||||
app:constraint_referenced_ids="play_pause_audio_playback, progress, duration" />
|
||||
|
||||
<VideoView
|
||||
<TextureView
|
||||
android:id="@+id/video_player"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -45,31 +36,72 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/play_pause_video_playback"
|
||||
android:onClick="@{() -> viewModel.playPauseVideo()}"
|
||||
android:id="@+id/audio_file_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:contentDescription="@string/content_description_play_pause_video_playback"
|
||||
android:src="@{viewModel.isVideoPlaying ? @drawable/pause_fill : @drawable/play_fill, default=@drawable/play_fill}"
|
||||
android:visibility="@{viewModel.isVideo && !viewModel.fullScreenMode ? View.VISIBLE : View.GONE, default=gone}"
|
||||
android:src="@drawable/music_notes"
|
||||
android:contentDescription="@null"
|
||||
android:visibility="@{viewModel.isAudio ? View.VISIBLE : View.GONE, default=gone}"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:tint="@color/white"/>
|
||||
app:tint="@color/white" />
|
||||
|
||||
<com.github.chrisbanes.photoview.PhotoView
|
||||
android:id="@+id/image"
|
||||
android:onClick="@{toggleFullScreenModeClickListener}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:src="@drawable/illu"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
coilFile="@{viewModel.path}"
|
||||
android:visibility="@{viewModel.isImage ? View.VISIBLE : View.GONE, default=gone}" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/play_pause_audio_playback"
|
||||
android:onClick="@{() -> viewModel.togglePlayPause()}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginBottom="@dimen/screen_bottom_margin"
|
||||
android:padding="8dp"
|
||||
android:contentDescription="@string/content_description_play_pause_video_playback"
|
||||
android:src="@{viewModel.isMediaPlaying ? @drawable/pause_fill : @drawable/play_fill, default=@drawable/play_fill}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:tint="@color/white"/>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
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: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"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style_700"
|
||||
android:id="@+id/duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@{viewModel.formattedDuration, default=`00:42`}"
|
||||
android:textSize="13sp"
|
||||
android:textColor="@color/white"
|
||||
app:layout_constraintTop_toTopOf="@id/play_pause_audio_playback"
|
||||
app:layout_constraintBottom_toBottomOf="@id/play_pause_audio_playback"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</layout>
|
||||
|
|
@ -25,7 +25,14 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="@{viewModel.fullScreenMode ? View.GONE : View.VISIBLE}"
|
||||
app:constraint_referenced_ids="back, title, share, save, file_name"/>
|
||||
app:constraint_referenced_ids="top_bar_background, back, file_name, share, save, date_time"/>
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/top_bar_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="back, date_time"
|
||||
app:barrierDirection="bottom" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pdf_view_pager"
|
||||
|
|
@ -48,7 +55,7 @@
|
|||
android:text="@{viewModel.pdfCurrentPage + ` / ` + viewModel.pdfPages, default=`1 / 30`}"
|
||||
android:textColor="@color/white"
|
||||
android:background="#80000000"
|
||||
app:layout_constraintBottom_toTopOf="@id/file_name"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/pdf_view_pager"
|
||||
app:layout_constraintEnd_toEndOf="@id/pdf_view_pager" />
|
||||
|
||||
|
|
@ -75,79 +82,85 @@
|
|||
|
||||
</ScrollView>
|
||||
|
||||
<View
|
||||
android:id="@+id/top_bar_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@color/white"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/top_bar_barrier"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:onClick="@{backClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/caret_left"
|
||||
android:contentDescription="@string/content_description_go_back_icon"
|
||||
app:tint="?attr/color_main1_500"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/title" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/main_page_title_style"
|
||||
android:id="@+id/title"
|
||||
style="@style/default_text_style_700"
|
||||
android:id="@+id/file_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:text=""
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{viewModel.fileName, default=`nomdufichier.jpg`}"
|
||||
android:textSize="13sp"
|
||||
android:textColor="?attr/color_main2_600"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintEnd_toStartOf="@id/share"
|
||||
app:layout_constraintStart_toEndOf="@id/back"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/date_time"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style_300"
|
||||
android:id="@+id/date_time"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{viewModel.dateTime, default=`envoyé le 02/05/2023 à 11h05`}"
|
||||
android:textSize="12sp"
|
||||
android:textColor="?attr/color_main2_500"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintTop_toBottomOf="@id/file_name"
|
||||
app:layout_constraintBottom_toBottomOf="@id/back"
|
||||
app:layout_constraintEnd_toStartOf="@id/share"
|
||||
app:layout_constraintStart_toEndOf="@id/back"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/share"
|
||||
android:onClick="@{shareClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/share_network"
|
||||
android:contentDescription="@string/content_description_share_file"
|
||||
app:tint="?attr/color_main1_500"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintEnd_toStartOf="@id/save"
|
||||
app:layout_constraintTop_toTopOf="@id/title" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/save"
|
||||
android:onClick="@{() -> viewModel.exportToMediaStore()}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/download_simple"
|
||||
android:contentDescription="@string/content_description_save_file"
|
||||
app:tint="?attr/color_main1_500"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/title" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style_300"
|
||||
android:id="@+id/file_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/color_main2_000"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:text="@{viewModel.fileName, default=`nomdufichier.jpg\nenvoyé le 02/05/2023 à 11h05`}"
|
||||
android:textSize="12sp"
|
||||
android:textColor="?attr/color_main2_600"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/toasts_area"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue