reproduccion de audio en lista de audios y fixes varios
This commit is contained in:
parent
bfa0fdcecf
commit
cd10aced57
@ -16,13 +16,72 @@ class AudiosAdapter(
|
|||||||
private val onOptionsClick: ((audio: Audio, button: View) -> Boolean)
|
private val onOptionsClick: ((audio: Audio, button: View) -> Boolean)
|
||||||
) : RecyclerView.Adapter<AudiosAdapter.AudiosViewHolder>() {
|
) : RecyclerView.Adapter<AudiosAdapter.AudiosViewHolder>() {
|
||||||
|
|
||||||
|
enum class Payload {
|
||||||
|
PlayStateChanged, IsLoadingChanged
|
||||||
|
}
|
||||||
|
|
||||||
private var data: List<Audio> = listOf()
|
private var data: List<Audio> = listOf()
|
||||||
|
private var currentPlaying: Audio? = null
|
||||||
|
|
||||||
fun setData(audios: List<Audio>) {
|
fun setData(audios: List<Audio>) {
|
||||||
data = audios
|
data = audios
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setIsPlaying(isPlaying: Boolean, audio: Audio) {
|
||||||
|
if(audio == currentPlaying) {
|
||||||
|
val index = data.indexOf(audio)
|
||||||
|
if(index == -1) return
|
||||||
|
|
||||||
|
data[index].isPlaying = isPlaying
|
||||||
|
|
||||||
|
notifyItemChanged(index, Payload.PlayStateChanged)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val prevIndex = data.indexOf(currentPlaying)
|
||||||
|
|
||||||
|
if(prevIndex != -1) {
|
||||||
|
data[prevIndex].isPlaying = false
|
||||||
|
notifyItemChanged(prevIndex, Payload.PlayStateChanged)
|
||||||
|
}
|
||||||
|
val newIndex = data.indexOf(audio)
|
||||||
|
if(newIndex != -1) {
|
||||||
|
data[newIndex].isPlaying = isPlaying
|
||||||
|
notifyItemChanged(newIndex, Payload.PlayStateChanged)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPlaying = audio
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setIsLoadingAudio(isLoading: Boolean, audio: Audio) {
|
||||||
|
if(audio == currentPlaying) {
|
||||||
|
val index = data.indexOf(audio)
|
||||||
|
if(index == -1) return
|
||||||
|
|
||||||
|
data[index].isLoading = isLoading
|
||||||
|
|
||||||
|
notifyItemChanged(index, Payload.IsLoadingChanged)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val prevIndex = data.indexOf(currentPlaying)
|
||||||
|
|
||||||
|
if(prevIndex != -1) {
|
||||||
|
data[prevIndex].isLoading = false
|
||||||
|
notifyItemChanged(prevIndex, Payload.IsLoadingChanged)
|
||||||
|
}
|
||||||
|
val newIndex = data.indexOf(audio)
|
||||||
|
if(newIndex != -1) {
|
||||||
|
data[newIndex].isLoading = isLoading
|
||||||
|
notifyItemChanged(newIndex, Payload.IsLoadingChanged)
|
||||||
|
}
|
||||||
|
currentPlaying = audio
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateAudioProgress(total: Int, progress: Int, audio: Audio) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
inner class AudiosViewHolder(val binding: AudioListItemBinding) : ViewHolder(binding.root)
|
inner class AudiosViewHolder(val binding: AudioListItemBinding) : ViewHolder(binding.root)
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AudiosViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AudiosViewHolder {
|
||||||
@ -34,8 +93,14 @@ class AudiosAdapter(
|
|||||||
return data.size
|
return data.size
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: AudiosViewHolder, position: Int) {
|
override fun onBindViewHolder(
|
||||||
|
holder: AudiosViewHolder,
|
||||||
|
position: Int,
|
||||||
|
payloads: MutableList<Any>
|
||||||
|
) {
|
||||||
val audio = data[position]
|
val audio = data[position]
|
||||||
|
if(payloads.isEmpty()) {
|
||||||
|
|
||||||
|
|
||||||
holder.binding.audioName.text = audio.name
|
holder.binding.audioName.text = audio.name
|
||||||
holder.binding.audioAuthor.text = audio.userName
|
holder.binding.audioAuthor.text = audio.userName
|
||||||
@ -51,8 +116,30 @@ class AudiosAdapter(
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
holder.binding.loading.visibility = if(audio.isLoading) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
holder.binding.playButton.setOnClickListener {
|
holder.binding.playButton.setOnClickListener {
|
||||||
onPlayClick(audio)
|
onPlayClick(audio)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// only updates play button
|
||||||
|
if(payloads.contains(Payload.PlayStateChanged)) {
|
||||||
|
holder.binding.playButton.icon = ResourcesCompat.getDrawable(
|
||||||
|
holder.itemView.resources,
|
||||||
|
if(audio.isPlaying) R.drawable.baseline_pause_24 else R.drawable.baseline_play_arrow_24,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(payloads.contains(Payload.IsLoadingChanged)) {
|
||||||
|
holder.binding.loading.visibility = if(audio.isLoading) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: AudiosViewHolder, position: Int) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8,12 +8,15 @@ import androidx.appcompat.widget.PopupMenu
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.audio.audios_list.presentation.AudiosAdapter
|
import com.isolaatti.audio.audios_list.presentation.AudiosAdapter
|
||||||
import com.isolaatti.audio.audios_list.presentation.AudiosViewModel
|
import com.isolaatti.audio.audios_list.presentation.AudiosViewModel
|
||||||
import com.isolaatti.audio.common.domain.Audio
|
import com.isolaatti.audio.common.domain.Audio
|
||||||
|
import com.isolaatti.audio.common.domain.Playable
|
||||||
|
import com.isolaatti.audio.player.AudioPlayerConnector
|
||||||
import com.isolaatti.common.ErrorMessageViewModel
|
import com.isolaatti.common.ErrorMessageViewModel
|
||||||
import com.isolaatti.databinding.FragmentAudiosBinding
|
import com.isolaatti.databinding.FragmentAudiosBinding
|
||||||
import com.isolaatti.utils.Resource
|
import com.isolaatti.utils.Resource
|
||||||
@ -29,6 +32,8 @@ class AudiosFragment : Fragment() {
|
|||||||
private lateinit var adapter: AudiosAdapter
|
private lateinit var adapter: AudiosAdapter
|
||||||
private var privilegedUserId by Delegates.notNull<Int>()
|
private var privilegedUserId by Delegates.notNull<Int>()
|
||||||
|
|
||||||
|
private lateinit var audioPlayerConnector: AudioPlayerConnector
|
||||||
|
|
||||||
private var loadedFirstTime = false
|
private var loadedFirstTime = false
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
@ -55,13 +60,44 @@ class AudiosFragment : Fragment() {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
private val onAudioPlayClick: ((audio: Audio) -> Unit) = {
|
private val onAudioPlayClick: (audio: Audio) -> Unit = {
|
||||||
// Play audio
|
audioPlayerConnector.playPauseAudio(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val audioPlayerConnectorListener: AudioPlayerConnector.Listener = object: AudioPlayerConnector.Listener {
|
||||||
|
override fun onPlaying(isPlaying: Boolean, audio: Playable) {
|
||||||
|
if(audio is Audio)
|
||||||
|
adapter.setIsPlaying(isPlaying, audio)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isLoading(isLoading: Boolean, audio: Playable) {
|
||||||
|
if(audio is Audio)
|
||||||
|
adapter.setIsLoadingAudio(isLoading, audio)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun progressChanged(second: Int, audio: Playable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun durationChanged(duration: Int, audio: Playable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnded(audio: Playable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
audioPlayerConnector = AudioPlayerConnector(requireContext())
|
||||||
|
|
||||||
|
audioPlayerConnector.addListener(audioPlayerConnectorListener)
|
||||||
|
|
||||||
|
viewLifecycleOwner.lifecycle.addObserver(audioPlayerConnector)
|
||||||
|
|
||||||
adapter = AudiosAdapter(onPlayClick = onAudioPlayClick, onOptionsClick = onOptionsClick)
|
adapter = AudiosAdapter(onPlayClick = onAudioPlayClick, onOptionsClick = onOptionsClick)
|
||||||
|
|
||||||
viewBinding.recyclerAudios.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
viewBinding.recyclerAudios.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||||
@ -73,6 +109,10 @@ class AudiosFragment : Fragment() {
|
|||||||
privilegedUserId = arguments.sourceId.toInt()
|
privilegedUserId = arguments.sourceId.toInt()
|
||||||
viewModel.loadAudios(privilegedUserId)
|
viewModel.loadAudios(privilegedUserId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewBinding.topAppBar.setNavigationOnClickListener {
|
||||||
|
findNavController().popBackStack()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupObservers() {
|
private fun setupObservers() {
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import android.net.Uri
|
|||||||
abstract class Playable {
|
abstract class Playable {
|
||||||
var isPlaying: Boolean = false
|
var isPlaying: Boolean = false
|
||||||
abstract val uri: Uri
|
abstract val uri: Uri
|
||||||
|
var isLoading: Boolean = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image url, null indicating no image should be shown
|
* Image url, null indicating no image should be shown
|
||||||
@ -26,5 +27,4 @@ abstract class Playable {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ class AudioDraftsRepositoryImpl(private val audiosDraftsDao: AudiosDraftsDao) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteDrafts(draftIds: LongArray): Flow<Boolean> = flow {
|
override fun deleteDrafts(draftIds: LongArray): Flow<Boolean> = flow {
|
||||||
val drafts = audiosDraftsDao.getAudioDraftsByIds(draftIds)
|
val drafts = audiosDraftsDao.getAudioDraftsByIds(*draftIds)
|
||||||
audiosDraftsDao.deleteDrafts(drafts)
|
audiosDraftsDao.deleteDrafts(drafts)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -9,20 +9,20 @@ import androidx.room.Update
|
|||||||
@Dao
|
@Dao
|
||||||
interface AudiosDraftsDao {
|
interface AudiosDraftsDao {
|
||||||
@Insert
|
@Insert
|
||||||
suspend fun insertAudioDraft(audioDraftEntity: AudioDraftEntity): Long
|
fun insertAudioDraft(audioDraftEntity: AudioDraftEntity): Long
|
||||||
|
|
||||||
@Query("SELECT * FROM audio_drafts WHERE id = :draftId")
|
@Query("SELECT * FROM audio_drafts WHERE id = :draftId")
|
||||||
suspend fun getAudioDraftById(draftId: Long): AudioDraftEntity?
|
fun getAudioDraftById(draftId: Long): AudioDraftEntity?
|
||||||
|
|
||||||
@Query("SELECT * FROM audio_drafts WHERE id in (:draftId)")
|
@Query("SELECT * FROM audio_drafts WHERE id in (:draftId)")
|
||||||
suspend fun getAudioDraftsByIds(draftId: LongArray): Array<AudioDraftEntity>
|
fun getAudioDraftsByIds(vararg draftId: Long): Array<AudioDraftEntity>
|
||||||
|
|
||||||
@Query("SELECT * FROM audio_drafts ORDER BY id DESC")
|
@Query("SELECT * FROM audio_drafts ORDER BY id DESC")
|
||||||
suspend fun getDrafts(): List<AudioDraftEntity>
|
fun getDrafts(): List<AudioDraftEntity>
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
suspend fun deleteDrafts(draft: Array<AudioDraftEntity>)
|
fun deleteDrafts(draft: Array<AudioDraftEntity>)
|
||||||
|
|
||||||
@Query("UPDATE audio_drafts SET name = :name WHERE id = :id")
|
@Query("UPDATE audio_drafts SET name = :name WHERE id = :id")
|
||||||
suspend fun renameDraft(id: Long, name: String): Int
|
fun renameDraft(id: Long, name: String): Int
|
||||||
}
|
}
|
||||||
@ -12,8 +12,8 @@ interface KeyValueDao {
|
|||||||
fun getValue(key: String): Flow<String>
|
fun getValue(key: String): Flow<String>
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun setValue(entity: KeyValueEntity)
|
fun setValue(entity: KeyValueEntity)
|
||||||
|
|
||||||
@Query("SELECT value FROM key_values WHERE id = :key")
|
@Query("SELECT value FROM key_values WHERE id = :key")
|
||||||
suspend fun getValueAsync(key: String): String?
|
fun getValueAsync(key: String): String?
|
||||||
}
|
}
|
||||||
@ -12,6 +12,18 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/loading"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:translationZ="5dp"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/play_button"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/play_button"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/play_button"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/play_button"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/play_button"
|
android:id="@+id/play_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user