reproduccion de audio en lista de audios y fixes varios

This commit is contained in:
erik-everardo 2024-02-17 21:37:25 -06:00
parent bfa0fdcecf
commit cd10aced57
7 changed files with 165 additions and 26 deletions

View File

@ -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,25 +93,53 @@ 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.audioAuthor.text = audio.userName
holder.binding.thumbnail.load(audio.thumbnail)
holder.binding.audioItemOptionsButton.setOnClickListener { holder.binding.audioName.text = audio.name
onOptionsClick(audio, it) holder.binding.audioAuthor.text = audio.userName
holder.binding.thumbnail.load(audio.thumbnail)
holder.binding.audioItemOptionsButton.setOnClickListener {
onOptionsClick(audio, it)
}
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
)
holder.binding.loading.visibility = if(audio.isLoading) View.VISIBLE else View.GONE
holder.binding.playButton.setOnClickListener {
onPlayClick(audio)
}
return
} }
holder.binding.playButton.icon = ResourcesCompat.getDrawable( // only updates play button
holder.itemView.resources, if(payloads.contains(Payload.PlayStateChanged)) {
if(audio.isPlaying) R.drawable.baseline_pause_24 else R.drawable.baseline_play_arrow_24, holder.binding.playButton.icon = ResourcesCompat.getDrawable(
null holder.itemView.resources,
) if(audio.isPlaying) R.drawable.baseline_pause_24 else R.drawable.baseline_play_arrow_24,
null
)
}
holder.binding.playButton.setOnClickListener { if(payloads.contains(Payload.IsLoadingChanged)) {
onPlayClick(audio) holder.binding.loading.visibility = if(audio.isLoading) View.VISIBLE else View.GONE
} }
} }
override fun onBindViewHolder(holder: AudiosViewHolder, position: Int) {
}
} }

View File

@ -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() {

View File

@ -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
} }
} }

View File

@ -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 {

View File

@ -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
} }

View File

@ -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?
} }

View File

@ -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"