Merge branch 'refactor/trackDisplayLinear' into 'develop'

Use Linear layout in Track display

See merge request ultrasonic/ultrasonic!859
This commit is contained in:
birdbird 2022-10-20 10:59:28 +00:00
commit 065f5253ea
5 changed files with 180 additions and 162 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 7.3.0" type="baseline" client="gradle" dependencies="true" name="AGP (7.3.0)" variant="all" version="7.3.0">
<issues format="6" by="lint 7.3.1" type="baseline" client="gradle" dependencies="true" name="AGP (7.3.1)" variant="all" version="7.3.1">
<issue
id="PluralsCandidate"

View File

@ -13,6 +13,7 @@ import org.koin.core.component.KoinComponent
import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.domain.Track
import timber.log.Timber
@Suppress("LongParameterList")
class TrackViewBinder(
@ -62,6 +63,8 @@ class TrackViewBinder(
diffAdapter.isSelected(item.longId)
)
Timber.v("Setting listeners")
holder.itemView.setOnLongClickListener {
if (onContextMenuClick != null) {
val popup = createContextMenu(holder.itemView, track)
@ -114,6 +117,8 @@ class TrackViewBinder(
if (newStatus != holder.check.isChecked) holder.check.isChecked = newStatus
}
Timber.v("Setting listeners done")
}
override fun onViewRecycled(holder: TrackViewHolder) {

View File

@ -7,11 +7,15 @@ import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.lifecycle.MutableLiveData
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.progressindicator.CircularProgressIndicator
import io.reactivex.rxjava3.disposables.CompositeDisposable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider
@ -31,7 +35,11 @@ const val INDICATOR_THICKNESS_DEFINITE = 10
/**
* Used to display songs and videos in a `ListView`.
*/
class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable, KoinComponent {
class TrackViewHolder(val view: View) :
RecyclerView.ViewHolder(view),
Checkable,
KoinComponent,
CoroutineScope by CoroutineScope(Dispatchers.IO) {
var entry: Track? = null
private set
@ -39,7 +47,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
var drag: ImageView = view.findViewById(R.id.song_drag)
var observableChecked = MutableLiveData(false)
private var rating: LinearLayout = view.findViewById(R.id.song_five_star)
private var rating: LinearLayout = view.findViewById(R.id.song_rating)
private var fiveStar1: ImageView = view.findViewById(R.id.song_five_star_1)
private var fiveStar2: ImageView = view.findViewById(R.id.song_five_star_2)
private var fiveStar3: ImageView = view.findViewById(R.id.song_five_star_3)
@ -62,12 +70,18 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
private var rxBusSubscription: CompositeDisposable? = null
init {
Timber.v("New ViewHolder created")
}
@Suppress("ComplexMethod")
fun setSong(
song: Track,
checkable: Boolean,
draggable: Boolean,
isSelected: Boolean = false
) {
Timber.v("Setting song")
val useFiveStarRating = Settings.useFiveStarRating
entry = song
@ -80,21 +94,28 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
if (Settings.shouldShowTrackNumber && song.track != null && song.track!! > 0) {
track.text = entryDescription.trackNumber
} else {
track.isVisible = false
if (!track.isGone) track.isGone = true
}
check.isVisible = (checkable && !song.isVideo)
initChecked(isSelected)
drag.isVisible = draggable
val checkValue = (checkable && !song.isVideo)
if (check.isVisible != checkValue) check.isVisible = checkValue
if (checkValue) initChecked(isSelected)
if (drag.isVisible != draggable) drag.isVisible = draggable
if (ActiveServerProvider.isOffline()) {
star.isVisible = false
rating.isVisible = false
star.isGone = true
} else {
setupStarButtons(song, useFiveStarRating)
}
updateStatus(DownloadService.getDownloadState(song), null)
// Instead of blocking the UI thread while looking up the current state,
// launch the request in an IO thread and propagate the result through RX
launch {
val state = DownloadService.getDownloadState(song)
RxBus.trackDownloadStatePublisher.onNext(
RxBus.TrackDownloadState(song.id, state, null)
)
}
if (useFiveStarRating) {
setFiveStars(entry?.userRating ?: 0)
@ -103,8 +124,8 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
}
if (song.isVideo) {
artist.isVisible = false
progressIndicator.isVisible = false
artist.isGone = true
progressIndicator.isGone = true
}
// Create new Disposable for the new Subscriptions
@ -117,6 +138,8 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
if (it.id != song.id) return@subscribe
updateStatus(it.state, it.progress)
}
Timber.v("Setting song done")
}
// This is called when the Holder is recycled and receives a new Song
@ -145,13 +168,13 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
private fun setupStarButtons(song: Track, useFiveStarRating: Boolean) {
if (useFiveStarRating) {
// Hide single star
star.visibility = View.INVISIBLE
star.isGone = true
rating.isVisible = true
val rating = if (song.userRating == null) 0 else song.userRating!!
setFiveStars(rating)
} else {
// Hide five stars
rating.isVisible = false
star.isVisible = true
rating.isGone = true
setSingleStar(song.starred)
star.setOnClickListener {
val isStarred = song.starred
@ -241,7 +264,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
}
private fun showStatusImage(image: Int?) {
progressIndicator.isVisible = false
progressIndicator.isGone = true
statusImage.isVisible = true
if (image != null) {
statusImage.setImageResource(image)
@ -251,7 +274,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
}
private fun showIndefiniteProgress() {
statusImage.isVisible = false
statusImage.isGone = true
progressIndicator.isVisible = true
progressIndicator.isIndeterminate = true
progressIndicator.indicatorDirection =
@ -260,7 +283,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
}
private fun showProgress() {
statusImage.isVisible = false
statusImage.isGone = true
progressIndicator.isVisible = true
progressIndicator.isIndeterminate = false
progressIndicator.indicatorDirection =

View File

@ -1,169 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<!-- DON'T CONVERT TO ConstraintLayout! We have been there and it was slower than LinearLayout :) -->
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
a:id="@+id/song_layout"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:minHeight="?android:attr/listPreferredItemHeight">
a:layout_height="?android:attr/listPreferredItemHeight"
a:minHeight="?android:attr/listPreferredItemHeight"
a:orientation="horizontal">
<ImageView
a:id="@+id/song_drag"
a:layout_width="wrap_content"
a:layout_height="0dp"
a:layout_width="38dp"
a:layout_height="fill_parent"
a:background="@android:color/transparent"
a:focusable="false"
a:gravity="center_vertical"
a:importantForAccessibility="no"
a:paddingStart="5dip"
a:paddingEnd="6dip"
a:paddingStart="7dip"
a:paddingEnd="4dip"
a:src="@drawable/ic_drag_vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/song_check"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
a:visibility="gone" />
<CheckedTextView
a:id="@+id/song_check"
a:layout_width="wrap_content"
a:layout_height="0dp"
a:layout_marginStart="4dp"
a:layout_width="38dp"
a:layout_height="fill_parent"
a:checkMark="@drawable/btn_check_custom"
a:gravity="center_vertical"
a:paddingEnd="4dip"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/song_drag"
app:layout_constraintTop_toTopOf="parent" />
a:visibility="gone" />
<TextView
a:id="@+id/song_track"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginTop="8dp"
a:paddingEnd="6dip"
a:textAppearance="?android:attr/textAppearanceMedium"
a:visibility="visible"
app:layout_constraintEnd_toStartOf="@+id/song_title"
app:layout_constraintStart_toEndOf="@+id/song_check"
app:layout_constraintTop_toTopOf="parent"
tools:text="Track"
tools:visibility="visible" />
<TextView
a:id="@+id/song_title"
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_marginTop="8dp"
a:drawablePadding="4dip"
a:ellipsize="end"
a:paddingEnd="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceMedium"
app:layout_constraintEnd_toStartOf="@id/barrier"
app:layout_constraintStart_toEndOf="@+id/song_track"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title" />
<TextView
a:id="@+id/song_artist"
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_marginBottom="10dp"
a:ellipsize="middle"
a:paddingStart="1dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/barrier"
app:layout_constraintStart_toEndOf="@+id/song_check"
tools:text="Artist" />
<ImageView
a:id="@+id/song_status_image"
a:layout_width="25dp"
a:layout_height="0dp"
a:layout_marginTop="8dp"
a:layout_marginEnd="10dip"
a:importantForAccessibility="no"
app:layout_constraintBottom_toTopOf="@id/song_duration"
app:layout_constraintEnd_toEndOf="@id/star_barrier"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.progressindicator.CircularProgressIndicator
a:id="@+id/song_status_progress"
a:layout_width="wrap_content"
a:layout_height="0dp"
a:layout_marginTop="8dp"
a:layout_marginEnd="10dip"
a:indeterminate="true"
app:indicatorColor="?attr/colorOnSurface"
app:indicatorSize="20dp"
app:layout_constraintBottom_toTopOf="@id/song_duration"
app:layout_constraintEnd_toEndOf="@id/star_barrier"
app:layout_constraintTop_toTopOf="parent"
app:trackColor="?attr/colorSurfaceVariant" />
<TextView
a:id="@+id/song_duration"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginBottom="10dp"
a:paddingStart="3dip"
a:paddingEnd="9dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/star_barrier"
tools:text="Duration" />
<androidx.constraintlayout.widget.Barrier
a:id="@+id/barrier"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
app:barrierDirection="left"
app:constraint_referenced_ids="song_duration"
tools:layout_editor_absoluteX="289dp" />
<androidx.constraintlayout.widget.Barrier
a:id="@+id/star_barrier"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
app:barrierDirection="left"
app:constraint_referenced_ids="song_five_star,song_star"
tools:layout_editor_absoluteX="354dp" />
<ImageView
a:id="@+id/song_star"
a:layout_width="wrap_content"
a:layout_height="0dp"
a:background="@android:color/transparent"
a:contentDescription="@string/download.menu_star"
a:focusable="false"
a:gravity="center_vertical"
a:importantForAccessibility="no"
a:paddingStart="5dip"
a:paddingEnd="6dip"
a:src="@drawable/ic_star_hollow"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/star_barrier"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="invisible" />
<include layout="@layout/list_item_track_details" />
<LinearLayout
a:id="@+id/song_five_star"
a:id="@+id/song_rating"
a:layout_width="wrap_content"
a:layout_height="0dp"
a:layout_height="fill_parent"
a:layout_gravity="center_vertical"
a:orientation="horizontal"
a:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/star_barrier"
app:layout_constraintTop_toTopOf="parent">
a:visibility="gone"
tools:visibility="visible">
<ImageView
a:id="@+id/song_five_star_1"
@ -223,4 +99,16 @@
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
a:id="@+id/song_star"
a:layout_width="38dp"
a:layout_height="fill_parent"
a:background="@android:color/transparent"
a:contentDescription="@string/download.menu_star"
a:focusable="false"
a:gravity="center_vertical"
a:paddingEnd="8dip"
a:src="@drawable/ic_star_hollow"
a:visibility="gone" />
</LinearLayout>

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- DON'T CONVERT TO ConstraintLayout! We have been there and it was slower than LinearLayout :) -->
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
a:layout_width="0dp"
a:layout_height="?android:attr/listPreferredItemHeight"
a:layout_gravity="center_vertical"
a:layout_marginStart="4dp"
a:layout_weight="1"
a:orientation="vertical"
tools:layout_height="?android:attr/listPreferredItemHeight"
tools:layout_width="match_parent">
<LinearLayout
a:layout_width="fill_parent"
a:layout_height="0dp"
a:layout_weight="3"
a:orientation="horizontal">
<TextView
a:id="@+id/song_track"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_gravity="left|center_vertical"
a:paddingEnd="6dip"
a:textAppearance="?android:attr/textAppearanceMedium"
a:visibility="gone"
tools:text="0/1" />
<TextView
a:id="@+id/song_title"
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_gravity="bottom|left"
a:layout_weight="1"
a:drawablePadding="4dip"
a:ellipsize="end"
a:paddingEnd="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceMedium"
tools:text="Title"
tools:ignore="NestedWeights" />
<ImageView
a:id="@+id/song_status_image"
a:layout_width="wrap_content"
a:layout_height="match_parent"
a:layout_marginTop="8dp"
a:layout_marginEnd="10dip"
a:importantForAccessibility="no"
a:visibility="gone" />
<com.google.android.material.progressindicator.CircularProgressIndicator
a:id="@+id/song_status_progress"
a:layout_width="wrap_content"
a:layout_height="match_parent"
a:layout_gravity="bottom|right"
a:layout_marginTop="8dp"
a:layout_marginEnd="10dip"
a:indeterminate="true"
a:visibility="gone"
app:indicatorColor="?attr/colorOnSurface"
app:indicatorSize="20dp"
app:trackColor="?attr/colorSurfaceVariant"
tools:visibility="visible" />
</LinearLayout>
<LinearLayout
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_gravity="center_vertical"
a:layout_weight="1"
a:orientation="horizontal">
<TextView
a:id="@+id/song_artist"
a:layout_width="0dip"
a:layout_height="wrap_content"
a:layout_gravity="top|left"
a:layout_weight="1"
a:ellipsize="middle"
a:paddingStart="1dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Artist"
tools:ignore="NestedWeights" />
<TextView
a:id="@+id/song_duration"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_gravity="right|top"
a:paddingStart="3dip"
a:paddingEnd="9dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"
tools:text="00:00" />
</LinearLayout>
</LinearLayout>