MoreActivity -
Completed implementing progressive timing for each song played. Songs playing issue related to progress view solved, Completed full implementations of woka songs completed
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package com.woka.modules.wokasongs
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -9,34 +12,92 @@ import com.google.android.exoplayer2.ExoPlayer
|
||||
import com.google.android.exoplayer2.MediaItem
|
||||
import com.google.android.exoplayer2.PlaybackException
|
||||
import com.google.android.exoplayer2.Player
|
||||
import com.google.android.exoplayer2.Player.EVENT_IS_LOADING_CHANGED
|
||||
import com.woka.R
|
||||
import com.woka.databinding.WokaSongViewHolderBinding
|
||||
import com.woka.modules.wokasongs.models.SongData
|
||||
import com.woka.utils.TAG
|
||||
import com.woka.utils.formatTime
|
||||
import com.woka.utils.hide
|
||||
import com.woka.utils.show
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.log
|
||||
|
||||
class WokaSongsAdapter(context: Context): RecyclerView.Adapter<WokaSongsAdapter.SongViewHolder>() {
|
||||
|
||||
companion object{
|
||||
private const val CURRENT_TIME_CHANGED = 123
|
||||
private const val PLAY_BACK_CHANGED = 124
|
||||
}
|
||||
|
||||
inner class SongViewHolder(val binding: WokaSongViewHolderBinding): ViewHolder(binding.root)
|
||||
|
||||
private var player: ExoPlayer
|
||||
private var player = ExoPlayer.Builder(context).build()
|
||||
private var currentPlayingPos = -1
|
||||
|
||||
private var songList = mutableListOf<SongData>()
|
||||
|
||||
private val lock = Any()
|
||||
|
||||
private val handler: Handler = Handler(Looper.getMainLooper())
|
||||
private val updateProgressAction: Runnable = object : Runnable {
|
||||
override fun run() {
|
||||
if (currentPlayingPos >= 0 && player.isPlaying){
|
||||
notifyItemChanged(currentPlayingPos, CURRENT_TIME_CHANGED)
|
||||
}
|
||||
|
||||
handler.postDelayed(this, 1000)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
init {
|
||||
player = ExoPlayer.Builder(context).build()
|
||||
player.addListener(object : Player.Listener{
|
||||
override fun onEvents(player: Player, events: Player.Events) {
|
||||
super.onEvents(player, events)
|
||||
if (currentPlayingPos >= 0)
|
||||
notifyItemChanged(currentPlayingPos)
|
||||
if (currentPlayingPos >= 0){
|
||||
if (events.containsAny(ExoPlayer.EVENT_IS_LOADING_CHANGED,
|
||||
ExoPlayer.EVENT_IS_PLAYING_CHANGED)){
|
||||
|
||||
notifyItemChanged(currentPlayingPos, PLAY_BACK_CHANGED)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
super.onPlaybackStateChanged(playbackState)
|
||||
if (playbackState == ExoPlayer.STATE_ENDED){
|
||||
player.removeListener(this)
|
||||
player.pause()
|
||||
player.addListener(this)
|
||||
|
||||
val lastPosition = currentPlayingPos
|
||||
currentPlayingPos = -1
|
||||
notifyItemChanged(lastPosition, PLAY_BACK_CHANGED)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
||||
super.onMediaItemTransition(mediaItem, reason)
|
||||
if (reason == ExoPlayer.MEDIA_ITEM_TRANSITION_REASON_AUTO){
|
||||
player.removeListener(this)
|
||||
player.pause()
|
||||
player.addListener(this)
|
||||
|
||||
val lastPosition = currentPlayingPos
|
||||
currentPlayingPos = -1
|
||||
notifyItemChanged(lastPosition, PLAY_BACK_CHANGED)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
super.onPlayerError(error)
|
||||
if (currentPlayingPos >= 0)
|
||||
notifyItemChanged(currentPlayingPos)
|
||||
if (currentPlayingPos >= 0) {
|
||||
notifyItemChanged(currentPlayingPos, PLAY_BACK_CHANGED)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -44,6 +105,8 @@ class WokaSongsAdapter(context: Context): RecyclerView.Adapter<WokaSongsAdapter.
|
||||
fun releasePlayer(){
|
||||
player.stop()
|
||||
player.release()
|
||||
|
||||
handler.removeCallbacks(updateProgressAction)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongViewHolder {
|
||||
@@ -55,12 +118,59 @@ class WokaSongsAdapter(context: Context): RecyclerView.Adapter<WokaSongsAdapter.
|
||||
|
||||
override fun getItemCount(): Int = songList.size
|
||||
|
||||
override fun onBindViewHolder(
|
||||
holder: SongViewHolder,
|
||||
position: Int,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
if (payloads.isNotEmpty()){
|
||||
synchronized(lock){
|
||||
holder.binding.apply {
|
||||
when (payloads[0]){
|
||||
CURRENT_TIME_CHANGED -> {
|
||||
if (currentPlayingPos == position){
|
||||
currentTime.text = player.currentPosition.formatTime()
|
||||
}else{
|
||||
currentTime.text = root.context.getString(R.string._00_00)
|
||||
}
|
||||
}
|
||||
PLAY_BACK_CHANGED -> {
|
||||
if (currentPlayingPos == holder.absoluteAdapterPosition){
|
||||
if (player.isPlaying){
|
||||
progressBar.post {
|
||||
progressBar.show()
|
||||
playBtn.setImageResource(R.drawable.ic_pause)
|
||||
playBtn.show()
|
||||
progressBar.hide()
|
||||
}
|
||||
}else if (player.isLoading){
|
||||
playBtn.hide()
|
||||
progressBar.show()
|
||||
}else{
|
||||
playBtn.show()
|
||||
playBtn.setImageResource(R.drawable.ic_play)
|
||||
progressBar.hide()
|
||||
}
|
||||
}else{
|
||||
playBtn.show()
|
||||
playBtn.setImageResource(R.drawable.ic_play)
|
||||
progressBar.hide()
|
||||
}
|
||||
}
|
||||
else -> super.onBindViewHolder(holder, position, payloads)
|
||||
}
|
||||
}
|
||||
}
|
||||
}else super.onBindViewHolder(holder, position, payloads)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SongViewHolder, position: Int) {
|
||||
if (position >= songList.size) return
|
||||
|
||||
val songData = songList[position]
|
||||
holder.binding.apply {
|
||||
title.text = songData.title
|
||||
|
||||
totalTime.text = try {
|
||||
if (songData.song_duration?.split(":")?.get(0)?.toInt() == 0)
|
||||
songData.song_duration.substring(3)
|
||||
@@ -70,6 +180,12 @@ class WokaSongsAdapter(context: Context): RecyclerView.Adapter<WokaSongsAdapter.
|
||||
songData.song_duration
|
||||
}
|
||||
|
||||
if (currentPlayingPos == position){
|
||||
currentTime.text = player.currentPosition.formatTime()
|
||||
}else{
|
||||
currentTime.text = root.context.getString(R.string._00_00)
|
||||
}
|
||||
|
||||
root.setOnClickListener {
|
||||
if (currentPlayingPos == holder.absoluteAdapterPosition){
|
||||
if (player.isLoading){
|
||||
@@ -81,11 +197,11 @@ class WokaSongsAdapter(context: Context): RecyclerView.Adapter<WokaSongsAdapter.
|
||||
player.play()
|
||||
}
|
||||
}else{
|
||||
player.pause()
|
||||
if (currentPlayingPos >= 0) notifyItemChanged(currentPlayingPos)
|
||||
|
||||
val lastPlayingPos = currentPlayingPos
|
||||
currentPlayingPos = holder.absoluteAdapterPosition
|
||||
|
||||
if (lastPlayingPos >= 0) {
|
||||
notifyItemChanged(lastPlayingPos, PLAY_BACK_CHANGED)
|
||||
}
|
||||
player.seekTo(holder.absoluteAdapterPosition, 0)
|
||||
player.play()
|
||||
}
|
||||
@@ -96,18 +212,20 @@ class WokaSongsAdapter(context: Context): RecyclerView.Adapter<WokaSongsAdapter.
|
||||
progressBar.show()
|
||||
playBtn.hide()
|
||||
}else if (player.isPlaying){
|
||||
progressBar.hide()
|
||||
playBtn.show()
|
||||
playBtn.setImageResource(R.drawable.ic_pause)
|
||||
progressBar.post {
|
||||
playBtn.setImageResource(R.drawable.ic_pause)
|
||||
playBtn.show()
|
||||
progressBar.hide()
|
||||
}
|
||||
}else{
|
||||
progressBar.hide()
|
||||
playBtn.show()
|
||||
playBtn.setImageResource(R.drawable.ic_play)
|
||||
progressBar.hide()
|
||||
}
|
||||
}else{
|
||||
progressBar.hide()
|
||||
playBtn.show()
|
||||
playBtn.setImageResource(R.drawable.ic_play)
|
||||
progressBar.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,6 +241,9 @@ class WokaSongsAdapter(context: Context): RecyclerView.Adapter<WokaSongsAdapter.
|
||||
player.addMediaItems(mediaItems)
|
||||
player.prepare()
|
||||
|
||||
handler.removeCallbacks(updateProgressAction)
|
||||
handler.post(updateProgressAction)
|
||||
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import android.animation.ObjectAnimator
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
@@ -15,6 +16,9 @@ import androidx.core.view.WindowCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.woka.WokaApp.Companion.userPrefs
|
||||
import java.util.Locale
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.round
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
fun Window.lightStatusBar(lightStatus: Boolean = false){
|
||||
WindowCompat.getInsetsController(this, decorView).isAppearanceLightStatusBars = lightStatus
|
||||
@@ -69,4 +73,17 @@ fun Context.toast(text: String?, length: Int = Toast.LENGTH_SHORT){
|
||||
|
||||
fun Fragment.toast(text: String?, length: Int = Toast.LENGTH_SHORT){
|
||||
activity?.toast(text, length)
|
||||
}
|
||||
|
||||
fun Long.formatTime(): String {
|
||||
val totalSeconds = ceil(this / 1000.0).toLong()
|
||||
val hours = totalSeconds / 3600
|
||||
val minutes = (totalSeconds % 3600) / 60
|
||||
val seconds = totalSeconds % 60
|
||||
|
||||
return if (hours > 0) {
|
||||
String.format("%02d:%02d:%02d", hours, minutes, seconds)
|
||||
} else {
|
||||
String.format("%02d:%02d", minutes, seconds)
|
||||
}
|
||||
}
|
||||
@@ -29,16 +29,16 @@
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
|
||||
android:layout_centerVertical="true"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/play_btn"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@string/image"
|
||||
android:src="@drawable/ic_play"
|
||||
android:scaleType="fitXY"
|
||||
@@ -47,8 +47,8 @@
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
android:indeterminate="true"
|
||||
android:indeterminateTint="@color/white"
|
||||
@@ -64,6 +64,7 @@
|
||||
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
|
||||
android:layout_toStartOf="@+id/ll"
|
||||
android:layout_toEndOf="@id/view"
|
||||
@@ -89,7 +90,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
tools:text="00:00"
|
||||
android:text="@string/_00_00"
|
||||
android:textColor="@color/white"
|
||||
android:fontFamily="@font/exo_2"
|
||||
|
||||
@@ -99,7 +100,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
tools:text="/"
|
||||
android:text="@string/slash"
|
||||
android:textColor="@color/white"
|
||||
android:fontFamily="@font/exo_2"
|
||||
|
||||
|
||||
@@ -163,4 +163,6 @@
|
||||
<string name="woka_songs">WOKA Songs</string>
|
||||
<string name="app_name_caps" translatable="false">WOKA</string>
|
||||
<string name="do_you_want_to_exit_from_the_woka_app">Do you want to exit from the WOKA app?</string>
|
||||
<string name="_00_00">00:00</string>
|
||||
<string name="slash">/</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user