Added audio file viewer

This commit is contained in:
Sylvain Berfini 2021-04-02 15:43:29 +02:00
parent 094caa1fa2
commit c3f5a39007
15 changed files with 276 additions and 20 deletions

View file

@ -387,7 +387,7 @@ internal fun DetailChatRoomFragment.navigateToVideoFileViewer(secure: Boolean) {
internal fun DetailChatRoomFragment.navigateToAudioFileViewer(secure: Boolean) { internal fun DetailChatRoomFragment.navigateToAudioFileViewer(secure: Boolean) {
val bundle = bundleOf("Secure" to secure) val bundle = bundleOf("Secure" to secure)
findMasterNavController().navigate( findMasterNavController().navigate(
R.id.action_global_videoViewerFragment, R.id.action_global_audioViewerFragment,
bundle, bundle,
getRightToLeftAnimationNavOptions() getRightToLeftAnimationNavOptions()
) )

View file

@ -25,13 +25,13 @@ import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.linphone.R import org.linphone.R
import org.linphone.activities.main.files.viewmodels.PdfFileViewModel import org.linphone.activities.main.files.viewmodels.PdfFileViewModel
import org.linphone.databinding.PdfViewerCellBinding import org.linphone.databinding.FilePdfViewerCellBinding
class PdfPagesListAdapter(private val pdfViewModel: PdfFileViewModel) : RecyclerView.Adapter<PdfPagesListAdapter.PdfPageViewHolder>() { class PdfPagesListAdapter(private val pdfViewModel: PdfFileViewModel) : RecyclerView.Adapter<PdfPagesListAdapter.PdfPageViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PdfPageViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PdfPageViewHolder {
val binding: PdfViewerCellBinding = DataBindingUtil.inflate( val binding: FilePdfViewerCellBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
R.layout.pdf_viewer_cell, parent, false R.layout.file_pdf_viewer_cell, parent, false
) )
return PdfPageViewHolder(binding) return PdfPageViewHolder(binding)
} }
@ -44,7 +44,7 @@ class PdfPagesListAdapter(private val pdfViewModel: PdfFileViewModel) : Recycler
holder.bind(position) holder.bind(position)
} }
inner class PdfPageViewHolder(private val binding: PdfViewerCellBinding) : RecyclerView.ViewHolder(binding.root) { inner class PdfPageViewHolder(private val binding: FilePdfViewerCellBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(index: Int) { fun bind(index: Int) {
with(binding) { with(binding) {
pdfViewModel.loadPdfPageInto(index, pdfImage) pdfViewModel.loadPdfPageInto(index, pdfImage)

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2010-2021 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.activities.main.files.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.KeyEvent
import android.widget.MediaController
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import org.linphone.R
import org.linphone.activities.main.files.viewmodels.AudioFileViewModel
import org.linphone.activities.main.files.viewmodels.AudioFileViewModelFactory
import org.linphone.activities.main.fragments.SecureFragment
import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.databinding.FileAudioViewerFragmentBinding
class AudioViewerFragment : SecureFragment<FileAudioViewerFragmentBinding>() {
private lateinit var viewModel: AudioFileViewModel
private lateinit var sharedViewModel: SharedMainViewModel
private lateinit var mediaController: MediaController
override fun getLayoutId(): Int = R.layout.file_audio_viewer_fragment
@SuppressLint("ClickableViewAccessibility")
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding.lifecycleOwner = this
sharedViewModel = requireActivity().run {
ViewModelProvider(this).get(SharedMainViewModel::class.java)
}
val content = sharedViewModel.contentToOpen.value
content ?: return
val filePath = content.filePath
filePath ?: return
(childFragmentManager.findFragmentById(R.id.top_bar_fragment) as? TopBarFragment)
?.setContent(content)
viewModel = ViewModelProvider(
this,
AudioFileViewModelFactory(filePath)
)[AudioFileViewModel::class.java]
binding.viewModel = viewModel
isSecure = arguments?.getBoolean("Secure") ?: false
mediaController = object : MediaController(requireContext()) {
// This hack is even if media controller is showed with timeout=0
// Once a control is touched, it will disappear 3 seconds later anyway
override fun show(timeout: Int) {
super.show(0)
}
// This is to prevent the first back key press to only hide to media controls
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
if (event?.keyCode == KeyEvent.KEYCODE_BACK) {
findNavController().popBackStack()
return true
}
return super.dispatchKeyEvent(event)
}
}
mediaController.setMediaPlayer(viewModel)
viewModel.mediaPlayer.setOnPreparedListener {
mediaController.setAnchorView(binding.anchor)
// This will make the controls visible forever
mediaController.show(0)
}
}
override fun onPause() {
mediaController.hide()
viewModel.mediaPlayer.pause()
super.onPause()
}
override fun onResume() {
super.onResume()
mediaController.show(0)
}
}

View file

@ -27,13 +27,13 @@ import org.linphone.activities.main.files.viewmodels.ImageFileViewModel
import org.linphone.activities.main.files.viewmodels.ImageFileViewModelFactory import org.linphone.activities.main.files.viewmodels.ImageFileViewModelFactory
import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.fragments.SecureFragment
import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.databinding.ImageViewerFragmentBinding import org.linphone.databinding.FileImageViewerFragmentBinding
class ImageViewerFragment : SecureFragment<ImageViewerFragmentBinding>() { class ImageViewerFragment : SecureFragment<FileImageViewerFragmentBinding>() {
private lateinit var viewModel: ImageFileViewModel private lateinit var viewModel: ImageFileViewModel
private lateinit var sharedViewModel: SharedMainViewModel private lateinit var sharedViewModel: SharedMainViewModel
override fun getLayoutId(): Int = R.layout.image_viewer_fragment override fun getLayoutId(): Int = R.layout.file_image_viewer_fragment
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {

View file

@ -27,14 +27,14 @@ import org.linphone.activities.main.files.viewmodels.PdfFileViewModel
import org.linphone.activities.main.files.viewmodels.PdfFileViewModelFactory import org.linphone.activities.main.files.viewmodels.PdfFileViewModelFactory
import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.fragments.SecureFragment
import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.databinding.PdfViewerFragmentBinding import org.linphone.databinding.FilePdfViewerFragmentBinding
class PdfViewerFragment : SecureFragment<PdfViewerFragmentBinding>() { class PdfViewerFragment : SecureFragment<FilePdfViewerFragmentBinding>() {
private lateinit var viewModel: PdfFileViewModel private lateinit var viewModel: PdfFileViewModel
private lateinit var sharedViewModel: SharedMainViewModel private lateinit var sharedViewModel: SharedMainViewModel
private lateinit var adapter: PdfPagesListAdapter private lateinit var adapter: PdfPagesListAdapter
override fun getLayoutId(): Int = R.layout.pdf_viewer_fragment override fun getLayoutId(): Int = R.layout.file_pdf_viewer_fragment
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)

View file

@ -26,13 +26,13 @@ import org.linphone.activities.main.files.viewmodels.TextFileViewModel
import org.linphone.activities.main.files.viewmodels.TextFileViewModelFactory import org.linphone.activities.main.files.viewmodels.TextFileViewModelFactory
import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.fragments.SecureFragment
import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.databinding.TextViewerFragmentBinding import org.linphone.databinding.FileTextViewerFragmentBinding
class TextViewerFragment : SecureFragment<TextViewerFragmentBinding>() { class TextViewerFragment : SecureFragment<FileTextViewerFragmentBinding>() {
private lateinit var viewModel: TextFileViewModel private lateinit var viewModel: TextFileViewModel
private lateinit var sharedViewModel: SharedMainViewModel private lateinit var sharedViewModel: SharedMainViewModel
override fun getLayoutId(): Int = R.layout.text_viewer_fragment override fun getLayoutId(): Int = R.layout.file_text_viewer_fragment
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)

View file

@ -20,23 +20,25 @@
package org.linphone.activities.main.files.fragments package org.linphone.activities.main.files.fragments
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent
import android.widget.MediaController import android.widget.MediaController
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import org.linphone.R import org.linphone.R
import org.linphone.activities.main.files.viewmodels.VideoFileViewModel import org.linphone.activities.main.files.viewmodels.VideoFileViewModel
import org.linphone.activities.main.files.viewmodels.VideoFileViewModelFactory import org.linphone.activities.main.files.viewmodels.VideoFileViewModelFactory
import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.fragments.SecureFragment
import org.linphone.activities.main.viewmodels.SharedMainViewModel import org.linphone.activities.main.viewmodels.SharedMainViewModel
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
import org.linphone.databinding.VideoViewerFragmentBinding import org.linphone.databinding.FileVideoViewerFragmentBinding
class VideoViewerFragment : SecureFragment<VideoViewerFragmentBinding>() { class VideoViewerFragment : SecureFragment<FileVideoViewerFragmentBinding>() {
private lateinit var viewModel: VideoFileViewModel private lateinit var viewModel: VideoFileViewModel
private lateinit var sharedViewModel: SharedMainViewModel private lateinit var sharedViewModel: SharedMainViewModel
private lateinit var mediaController: MediaController private lateinit var mediaController: MediaController
override fun getLayoutId(): Int = R.layout.video_viewer_fragment override fun getLayoutId(): Int = R.layout.file_video_viewer_fragment
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
@ -61,10 +63,19 @@ class VideoViewerFragment : SecureFragment<VideoViewerFragmentBinding>() {
)[VideoFileViewModel::class.java] )[VideoFileViewModel::class.java]
binding.viewModel = viewModel binding.viewModel = viewModel
mediaController = MediaController(requireContext())
initMediaController()
isSecure = arguments?.getBoolean("Secure") ?: false isSecure = arguments?.getBoolean("Secure") ?: false
mediaController = object : MediaController(requireContext()) {
// This is to prevent the first back key press to only hide to media controls
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
if (event?.keyCode == KeyEvent.KEYCODE_BACK) {
findNavController().popBackStack()
return true
}
return super.dispatchKeyEvent(event)
}
}
initMediaController()
} }
override fun onResume() { override fun onResume() {

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2010-2021 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.activities.main.files.viewmodels
import android.media.AudioAttributes
import android.media.MediaPlayer
import android.widget.MediaController
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import java.lang.IllegalStateException
class AudioFileViewModelFactory(private val filePath: String) :
ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return AudioFileViewModel(filePath) as T
}
}
class AudioFileViewModel(val filePath: String) : ViewModel(), MediaController.MediaPlayerControl {
val mediaPlayer = MediaPlayer()
init {
mediaPlayer.apply {
setAudioAttributes(AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).setUsage(AudioAttributes.USAGE_MEDIA).build())
setDataSource(filePath)
prepare()
start()
}
}
override fun onCleared() {
mediaPlayer.release()
super.onCleared()
}
override fun start() {
mediaPlayer.start()
}
override fun pause() {
mediaPlayer.pause()
}
override fun getDuration(): Int {
return mediaPlayer.duration
}
override fun getCurrentPosition(): Int {
try {
return mediaPlayer.currentPosition
} catch (ise: IllegalStateException) {}
return 0
}
override fun seekTo(pos: Int) {
mediaPlayer.seekTo(pos)
}
override fun isPlaying(): Boolean {
return mediaPlayer.isPlaying
}
override fun getBufferPercentage(): Int {
return 0
}
override fun canPause(): Boolean {
return true
}
override fun canSeekBackward(): Boolean {
return true
}
override fun canSeekForward(): Boolean {
return true
}
override fun getAudioSessionId(): Int {
return mediaPlayer.audioSessionId
}
}

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View"/>
<variable
name="viewModel"
type="org.linphone.activities.main.files.viewmodels.AudioFileViewModel" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/backgroundColor">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/top_bar_fragment"
android:name="org.linphone.activities.main.files.fragments.TopBarFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
tools:layout="@layout/file_viewer_top_bar_fragment" />
<RelativeLayout
android:id="@+id/anchor"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/top_bar_fragment" />
</RelativeLayout>
</layout>

View file

@ -340,5 +340,10 @@
android:name="org.linphone.activities.main.files.fragments.VideoViewerFragment" android:name="org.linphone.activities.main.files.fragments.VideoViewerFragment"
android:label="VideoViewerFragment" /> android:label="VideoViewerFragment" />
<action android:id="@+id/action_global_videoViewerFragment" app:destination="@id/videoViewerFragment"/> <action android:id="@+id/action_global_videoViewerFragment" app:destination="@id/videoViewerFragment"/>
<fragment
android:id="@+id/audioViewerFragment"
android:name="org.linphone.activities.main.files.fragments.AudioViewerFragment"
android:label="AudioViewerFragment" />
<action android:id="@+id/action_global_audioViewerFragment" app:destination="@id/audioViewerFragment"/>
</navigation> </navigation>