UI Feedback
This commit is contained in:
@@ -3,6 +3,9 @@ package net.helcel.cowspent.android.main
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -69,13 +72,43 @@ fun EmptyProjectsState(onConfigureNextcloud: () -> Unit, onAddManually: () -> Un
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A full-height, centred state that a pull to refresh can still act on.
|
||||
*
|
||||
* PullRefresh reads the gesture from a nested scroll source, and a plain Column offers none - so
|
||||
* on an empty list, which is exactly when a refresh is wanted most, the pull never fires. A
|
||||
* single-item LazyColumn has nowhere to scroll but does provide that source.
|
||||
*/
|
||||
@Composable
|
||||
private fun RefreshableFullScreenState(content: @Composable ColumnScope.() -> Unit) {
|
||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||
item {
|
||||
Column(
|
||||
modifier = Modifier.fillParentMaxSize().padding(16.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LoadingBillsState() {
|
||||
RefreshableFullScreenState {
|
||||
CircularProgressIndicator()
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.error_loading),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EmptyMembersState() {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().padding(16.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
RefreshableFullScreenState {
|
||||
Text(
|
||||
text = stringResource(R.string.error_no_members).uppercase(),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
@@ -94,11 +127,7 @@ fun EmptyMembersState() {
|
||||
|
||||
@Composable
|
||||
fun EmptyBillsState() {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().padding(16.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
RefreshableFullScreenState {
|
||||
Text(
|
||||
text = stringResource(R.string.error_no_bills).uppercase(),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
@@ -203,11 +232,7 @@ fun SectionHeader(title: String) {
|
||||
|
||||
@Composable
|
||||
fun EmptyState() {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
RefreshableFullScreenState {
|
||||
Text(
|
||||
text = stringResource(R.string.error_no_bills).uppercase(),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
|
||||
@@ -409,6 +409,10 @@ fun BillsListScreen(
|
||||
when {
|
||||
viewModel.showNoProjects -> EmptyProjectsState(onAccountSwitcherClick, onAddProjectClick)
|
||||
viewModel.showNoMembers -> EmptyMembersState()
|
||||
// A large project takes a long time on its first sync. Until that finishes there
|
||||
// is nothing stored for it yet, and reporting that as "no bills" tells the user
|
||||
// the project is empty when it is still downloading.
|
||||
viewModel.isRefreshing && viewModel.bills.isEmpty() -> LoadingBillsState()
|
||||
viewModel.showNoBills -> EmptyBillsState()
|
||||
viewModel.bills.isEmpty() -> EmptyState()
|
||||
else -> {
|
||||
|
||||
@@ -94,14 +94,16 @@ class BillsListViewActivity :
|
||||
private val syncCallBack = object : ICallback {
|
||||
override fun onFinish() {
|
||||
mActionMode?.finish()
|
||||
refreshLists()
|
||||
viewModel.isRefreshing = false
|
||||
refreshLists()
|
||||
}
|
||||
|
||||
override fun onFinish(result: String, message: String) {}
|
||||
|
||||
override fun onScheduled() {
|
||||
viewModel.isRefreshing = false
|
||||
// Being queued is not being done. Clearing the indicator here stops the spinner while a
|
||||
// large project is still downloading; synchronize() already releases it when nothing
|
||||
// actually started.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user