This commit is contained in:
erik-everardo 2024-01-29 00:07:36 -06:00
parent 96fd70556b
commit 3ff49d73ce
17 changed files with 211 additions and 32 deletions

View File

@ -3,14 +3,16 @@ package com.isolaatti.audio.audios_list.presentation
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import coil.load
import com.isolaatti.R
import com.isolaatti.audio.common.domain.Audio
import com.isolaatti.databinding.AudioListItemBinding
class AudiosAdapter(
private val onClick: ((audio: Audio) -> Unit),
private val onPlayClick: ((audio: Audio) -> Unit),
private val onOptionsClick: ((audio: Audio, button: View) -> Boolean)
) : RecyclerView.Adapter<AudiosAdapter.AudiosViewHolder>() {
@ -39,12 +41,18 @@ class AudiosAdapter(
holder.binding.audioAuthor.text = audio.userName
holder.binding.thumbnail.load(audio.thumbnail)
holder.binding.root.setOnClickListener {
onClick(audio)
}
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.playButton.setOnClickListener {
onPlayClick(audio)
}
}
}

View File

@ -18,6 +18,7 @@ import com.isolaatti.common.ErrorMessageViewModel
import com.isolaatti.databinding.FragmentAudiosBinding
import com.isolaatti.utils.Resource
import dagger.hilt.android.AndroidEntryPoint
import kotlin.properties.Delegates
@AndroidEntryPoint
class AudiosFragment : Fragment() {
@ -26,6 +27,7 @@ class AudiosFragment : Fragment() {
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
private val arguments: AudiosFragmentArgs by navArgs()
private lateinit var adapter: AudiosAdapter
private var privilegedUserId by Delegates.notNull<Int>()
private var loadedFirstTime = false
override fun onCreateView(
@ -42,20 +44,25 @@ class AudiosFragment : Fragment() {
val popup = PopupMenu(requireContext(), button)
popup.menuInflater.inflate(R.menu.audio_item_menu, popup.menu)
if(audio.userId != privilegedUserId) {
popup.menu.removeItem(R.id.rename_item)
popup.menu.removeItem(R.id.delete_item)
popup.menu.removeItem(R.id.set_as_profile_audio)
}
popup.show()
true
}
private val onAudioClick: ((audio: Audio) -> Unit) = {
private val onAudioPlayClick: ((audio: Audio) -> Unit) = {
// Play audio
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = AudiosAdapter(onClick = onAudioClick, onOptionsClick = onOptionsClick)
adapter = AudiosAdapter(onPlayClick = onAudioPlayClick, onOptionsClick = onOptionsClick)
viewBinding.recyclerAudios.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
viewBinding.recyclerAudios.adapter = adapter
@ -63,7 +70,8 @@ class AudiosFragment : Fragment() {
setupObservers()
if(arguments.source == SOURCE_PROFILE) {
viewModel.loadAudios(arguments.sourceId.toInt())
privilegedUserId = arguments.sourceId.toInt()
viewModel.loadAudios(privilegedUserId)
}
}

View File

@ -1,5 +1,7 @@
package com.isolaatti.audio.common.domain
import android.net.Uri
import androidx.core.net.toUri
import com.isolaatti.audio.common.data.AudioDto
import com.isolaatti.common.Ownable
import com.isolaatti.connectivity.RetrofitClient.Companion.BASE_URL
@ -13,17 +15,16 @@ data class Audio(
val creationTime: ZonedDateTime,
override val userId: Int,
val userName: String
): Ownable, Serializable {
var playing: Boolean = false
val downloadUrl: String get() {
return "${BASE_URL}audios/$id.webm"
): Ownable, Playable(), Serializable {
override val uri: Uri get() {
return "${BASE_URL}audios/$id.webm".toUri()
}
val thumbnail: String get() {
override val thumbnail: String get() {
return UrlGen.userProfileImage(userId)
}
companion object {
fun fromDto(audioDto: AudioDto): Audio {
return Audio(

View File

@ -0,0 +1,13 @@
package com.isolaatti.audio.common.domain
import android.net.Uri
abstract class Playable {
var isPlaying: Boolean = false
abstract val uri: Uri
/**
* Image url, null indicating no image should be shown
*/
abstract val thumbnail: String?
}

View File

@ -1,4 +1,4 @@
package com.isolaatti.audio.recorder.data
package com.isolaatti.audio.drafts.data
import androidx.room.Entity
import androidx.room.PrimaryKey

View File

@ -1,4 +1,4 @@
package com.isolaatti.audio.recorder.data
package com.isolaatti.audio.drafts.data
import androidx.room.Dao
import androidx.room.Delete

View File

@ -0,0 +1,18 @@
package com.isolaatti.audio.drafts.domain
import android.net.Uri
import androidx.core.net.toUri
import com.isolaatti.MyApplication
import com.isolaatti.audio.common.domain.Playable
import java.io.File
data class AudioDraft(val id: Long, val name: String, val localStorageRelativePath: String) : Playable() {
override val thumbnail: String?
get() = null
override val uri: Uri
get() {
val appFiles = MyApplication.myApp.applicationContext.filesDir
return File(appFiles, localStorageRelativePath).toUri()
}
}

View File

@ -0,0 +1,55 @@
package com.isolaatti.audio.drafts.presentation
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.isolaatti.R
import com.isolaatti.audio.drafts.domain.AudioDraft
import com.isolaatti.databinding.AudioListItemBinding
class AudioDraftsAdapter(
private val onOptionsClicked: (item: AudioDraft, view: View) -> Unit = { _,_ -> },
private val onPlayClicked: (item: AudioDraft , view: View) -> Unit = { _,_ -> },
private val onItemClicked: (item: AudioDraft , view: View) -> Unit = { _,_ -> }
) : ListAdapter<AudioDraft, AudioDraftsAdapter.AudioDraftViewHolder>(diffCallback) {
inner class AudioDraftViewHolder(val audioListItemBinding: AudioListItemBinding) : ViewHolder(audioListItemBinding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AudioDraftViewHolder {
return AudioDraftViewHolder(
AudioListItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: AudioDraftViewHolder, position: Int) {
val item = getItem(position)
holder.audioListItemBinding.apply {
audioName.text = item.name
audioItemOptionsButton.setOnClickListener { onOptionsClicked(item, it) }
playButton.icon = ResourcesCompat.getDrawable(
holder.itemView.resources,
if(item.isPlaying) R.drawable.baseline_pause_24 else R.drawable.baseline_play_arrow_24,
null
)
}
}
companion object {
val diffCallback = object: DiffUtil.ItemCallback<AudioDraft>() {
override fun areItemsTheSame(oldItem: AudioDraft, newItem: AudioDraft): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: AudioDraft, newItem: AudioDraft): Boolean {
return oldItem == newItem
}
}
}
}

View File

@ -0,0 +1,6 @@
package com.isolaatti.audio.drafts.presentation
import androidx.lifecycle.ViewModel
class AudioDraftsViewModel : ViewModel() {
}

View File

@ -0,0 +1,49 @@
package com.isolaatti.audio.drafts.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import com.isolaatti.audio.drafts.domain.AudioDraft
import com.isolaatti.audio.drafts.presentation.AudioDraftsAdapter
import com.isolaatti.audio.drafts.presentation.AudioDraftsViewModel
import com.isolaatti.databinding.FragmentAudioDraftsBinding
class AudioDraftsFragment : Fragment() {
private lateinit var binding: FragmentAudioDraftsBinding
private val viewModel: AudioDraftsViewModel by viewModels()
private var adapter: AudioDraftsAdapter? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentAudioDraftsBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = AudioDraftsAdapter(
onPlayClicked = { item: AudioDraft, view: View ->
},
onOptionsClicked = { item, button ->
}
)
binding.recycler.adapter = adapter
binding.recycler.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
}
}

View File

@ -157,7 +157,7 @@ class AudioPlayerConnector(
return
}
this.audio = audio
mediaItem = MediaItem.fromUri(Uri.parse(audio.downloadUrl))
mediaItem = MediaItem.fromUri(audio.uri)
player?.setMediaItem(mediaItem!!)
}

View File

@ -1,11 +0,0 @@
package com.isolaatti.audio.recorder.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class AudioDraftsFragment : Fragment() {
}

View File

@ -2,8 +2,8 @@ package com.isolaatti.database
import androidx.room.Database
import androidx.room.RoomDatabase
import com.isolaatti.audio.recorder.data.AudioDraftEntity
import com.isolaatti.audio.recorder.data.AudiosDraftsDao
import com.isolaatti.audio.drafts.data.AudioDraftEntity
import com.isolaatti.audio.drafts.data.AudiosDraftsDao
import com.isolaatti.auth.data.local.UserInfoDao
import com.isolaatti.auth.data.local.UserInfoEntity
import com.isolaatti.settings.data.KeyValueDao

View File

@ -11,12 +11,23 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/play_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.IconButton"
android:layout_marginStart="4dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/thumbnail"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_margin="16dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="4dp"
app:layout_constraintStart_toEndOf="@id/play_button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:src="@drawable/baseline_image_24" />

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -6,4 +6,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:title="@string/delete" />
<item
android:id="@+id/rename_item"
android:title="@string/rename"/>
<item
android:id="@+id/set_as_profile_audio"
android:title="@string/set_as_profile_audio"/>
</menu>

View File

@ -177,4 +177,6 @@
<string name="recover_password">Recover password</string>
<string name="old_password_not_correct">Password not changed, old password did not match. If you don\'t remember your password, you can always recover it.</string>
<string name="new_password_is_invalid">New password is invalid. Please check it meets the requirements</string>
<string name="rename">Rename</string>
<string name="set_as_profile_audio">Set as profile audio</string>
</resources>