home: make loading indicator less intrusive

This commit is contained in:
Alexander Capehart 2024-12-28 14:54:20 -07:00
parent 64ce312976
commit 9ccc4cf2ae
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
2 changed files with 43 additions and 140 deletions

View file

@ -20,13 +20,12 @@ package org.oxycblt.auxio.home
import android.annotation.SuppressLint
import android.os.Bundle
import android.os.SystemClock
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.MenuCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
@ -313,75 +312,32 @@ class HomeFragment :
}
private fun updateIndexerState(state: IndexingState?) {
// TODO: Reduce intrusiveness of current loading state:
// 1. "Dry" loads
val binding = requireBinding()
when (state) {
is IndexingState.Completed -> setupCompleteState(binding, state.error)
is IndexingState.Indexing -> setupIndexingState(binding, state.progress)
null -> {
L.d("Indexer is in indeterminate state")
binding.homeIndexingContainer.visibility = View.INVISIBLE
is IndexingState.Completed -> {
binding.homeIndexingContainer.isInvisible = state.error == null
binding.homeIndexingProgress.isInvisible = state.error != null
binding.homeIndexingError.isInvisible = state.error == null
}
}
}
private fun setupCompleteState(binding: FragmentHomeBinding, error: Exception?) {
if (error == null) {
L.d("Received ok response")
binding.homeIndexingContainer.visibility = View.INVISIBLE
return
}
L.d("Received non-ok response")
val context = requireContext()
binding.homeIndexingContainer.visibility = View.VISIBLE
binding.homeIndexingProgress.visibility = View.INVISIBLE
binding.homeIndexingActions.visibility = View.VISIBLE
L.d("Showing generic error")
binding.homeIndexingStatus.setText(R.string.err_index_failed)
// Configure the action to act as a reload trigger.
binding.homeIndexingTry.apply {
visibility = View.VISIBLE
text = context.getString(R.string.lbl_retry)
setOnClickListener { musicModel.rescan() }
}
binding.homeIndexingMore.apply {
visibility = View.VISIBLE
setOnClickListener {
findNavController().navigateSafe(HomeFragmentDirections.reportError(error))
}
}
}
private fun setupIndexingState(binding: FragmentHomeBinding, progress: IndexingProgress) {
// Remove all content except for the progress indicator.
binding.homeIndexingContainer.visibility = View.VISIBLE
binding.homeIndexingProgress.visibility = View.VISIBLE
binding.homeIndexingActions.visibility = View.INVISIBLE
when (progress) {
is IndexingProgress.Indeterminate -> {
// In a query/initialization state, show a generic loading status.
binding.homeIndexingStatus.text = getString(R.string.lng_indexing)
binding.homeIndexingProgress.isIndeterminate = true
}
is IndexingProgress.Songs -> {
// Actively loading songs, show the current progress.
is IndexingState.Indexing -> {
binding.homeIndexingContainer.isInvisible = false
binding.homeIndexingProgress.apply {
isIndeterminate = false
max = progress.explored
this.progress = progress.loaded
isInvisible = false
when (state.progress) {
is IndexingProgress.Songs -> {
isIndeterminate = false
progress = state.progress.loaded
max = state.progress.explored
}
is IndexingProgress.Indeterminate -> {
isIndeterminate = true
}
}
}
// Avoid aggressively updating the UI for rapid progress updates.
val now = SystemClock.elapsedRealtime()
if (lastUpdateTime > -1 && (now - lastUpdateTime) < 250) {
return
}
lastUpdateTime = SystemClock.elapsedRealtime()
binding.homeIndexingStatus.text =
getString(R.string.fmt_indexing, progress.loaded, progress.explored)
binding.homeIndexingError.isInvisible = true
}
null -> {
binding.homeIndexingContainer.isInvisible = true
}
}
}

View file

@ -65,86 +65,33 @@
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
tools:layout="@layout/fragment_home_list" />
<org.oxycblt.auxio.home.EdgeFrameLayout
<com.google.android.material.card.MaterialCardView
android:id="@+id/home_indexing_container"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/spacing_medium"
android:fitsSystemWindows="true"
android:visibility="invisible">
android:layout_gravity="top|start"
android:transitionGroup="true"
android:layout_margin="@dimen/spacing_medium">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/home_indexing_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
android:layout_margin="@dimen/spacing_tiny" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<ImageView
android:id="@+id/home_indexing_error"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:contentDescription="@string/err_index_failed"
android:scaleType="centerInside"
android:src="@drawable/ic_feature_request_24"
app:tint="?attr/colorError"
tools:visibility="invisible" />
<TextView
android:id="@+id/home_indexing_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_medium"
android:gravity="center"
android:text="@string/lng_indexing"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
app:layout_constraintBottom_toTopOf="@+id/home_indexing_actions"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Status" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/home_indexing_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:indeterminate="true"
app:indeterminateAnimationType="disjoint"
app:layout_constraintBottom_toBottomOf="@+id/home_indexing_actions"
app:layout_constraintTop_toTopOf="@+id/home_indexing_actions" />
<LinearLayout
android:id="@+id/home_indexing_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
android:orientation="horizontal"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
tools:layout_editor_absoluteX="16dp">
<org.oxycblt.auxio.ui.RippleFixMaterialButton
android:id="@+id/home_indexing_try"
style="@style/Widget.Auxio.Button.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_small"
android:layout_weight="1"
android:text="@string/lbl_retry" />
<org.oxycblt.auxio.ui.RippleFixMaterialButton
android:id="@+id/home_indexing_more"
style="@style/Widget.Auxio.Button.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:layout_weight="1"
android:text="@string/lbl_show_error_info" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</org.oxycblt.auxio.home.EdgeFrameLayout>
</com.google.android.material.card.MaterialCardView>
</FrameLayout>