Skip to content

Commit

Permalink
Replace Refresh Buttons with Pull to Refresh & change Top Bar scroll …
Browse files Browse the repository at this point in the history
…behavior (#276)

Co-authored-by: Martin Felber <[email protected]>
  • Loading branch information
julian-wls and FelberMartin authored Jan 10, 2025
1 parent a56ead7 commit 9ce9282
Show file tree
Hide file tree
Showing 19 changed files with 142 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults.Indicator
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -16,6 +20,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import de.tum.informatics.www1.artemis.native_app.core.data.DataState


/**
* Displays ui for each data state.
* For loading, a progress bar with text on top of it
Expand All @@ -28,44 +33,97 @@ inline fun <T> BasicDataStateUi(
loadingText: String,
failureText: String,
retryButtonText: String,
enablePullToRefresh: Boolean = true,
noinline onClickRetry: () -> Unit,
crossinline successUi: @Composable (BoxScope.(data: T) -> Unit)
) {
Box(
modifier = modifier,
contentAlignment = Alignment.Center
) {
when (dataState) {
is DataState.Failure -> {
Column(
modifier = Modifier.align(Alignment.Center)
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = failureText,
textAlign = TextAlign.Center,
fontSize = 18.sp
)
val pullToRefreshState = rememberPullToRefreshState()

TextButton(
onClick = onClickRetry,
content = { Text(text = retryButtonText) },
modifier = Modifier
.padding(top = 0.dp)
.align(Alignment.CenterHorizontally)
)
}
if (enablePullToRefresh) {
PullToRefreshBox(
modifier = modifier,
isRefreshing = dataState is DataState.Loading,
onRefresh = onClickRetry,
state = pullToRefreshState,
indicator = {
Indicator(
modifier = Modifier.align(Alignment.TopCenter),
isRefreshing = dataState is DataState.Loading,
color = MaterialTheme.colorScheme.primary,
state = pullToRefreshState
)
},
contentAlignment = Alignment.Center
) {
Content(
dataState = dataState,
loadingText = loadingText,
failureText = failureText,
retryButtonText = retryButtonText,
onClickRetry = onClickRetry,
successUi = successUi
)
}
} else {
Box(
modifier = modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
Content(
dataState = dataState,
loadingText = loadingText,
failureText = failureText,
retryButtonText = retryButtonText,
enablePullToRefresh = false,
onClickRetry = onClickRetry,
successUi = successUi
)
}
}
}

@Composable
inline fun <T> Content(
dataState: DataState<T>?,
loadingText: String,
failureText: String,
retryButtonText: String,
enablePullToRefresh: Boolean = true,
noinline onClickRetry: () -> Unit,
crossinline successUi: @Composable (BoxScope.(data: T) -> Unit)
) {
when (dataState) {
is DataState.Failure -> {
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = failureText,
textAlign = TextAlign.Center,
fontSize = 18.sp
)

TextButton(
onClick = onClickRetry,
content = { Text(text = retryButtonText) },
modifier = Modifier
.padding(top = 0.dp)
.align(Alignment.CenterHorizontally)
)
}
}

is DataState.Loading -> {
Column(modifier = Modifier.align(Alignment.Center)) {
Text(
modifier = Modifier.fillMaxWidth(),
text = loadingText,
textAlign = TextAlign.Center,
fontSize = 20.sp,
)
is DataState.Loading -> {
Column(modifier = Modifier) {
Text(
modifier = Modifier.fillMaxWidth(),
text = loadingText,
textAlign = TextAlign.Center,
fontSize = 20.sp,
)

if (!enablePullToRefresh) {
LinearProgressIndicator(
modifier = Modifier
.fillMaxWidth(0.5f)
Expand All @@ -74,13 +132,15 @@ inline fun <T> BasicDataStateUi(
)
}
}
}

is DataState.Success -> {
is DataState.Success -> {
Box {
successUi(dataState.data)
}

null -> {}
}

null -> {}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ fun CourseItemGrid(
courseItem(course, courseItemModifier, isCompact)
}
}

}

fun Modifier.computeCourseItemModifier(isCompact: Boolean): Modifier {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ fun `Metis - Conversation Overview`() {
onRequestCreatePersonalConversation = {},
onRequestAddChannel = {},
onRequestBrowseChannel = {},
canCreateChannel = false,
canCreateChannel = false
)
},
onNavigateBack = { },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ internal fun <T> WeeklyItemsLazyColumn(
}
}


/**
* Display a title with the time range of the week or a text indicating that no time is bound.
* Displays an icon button that lets the user expand and collapse the weekly items
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@ package de.tum.informatics.www1.artemis.native_app.feature.courseview.ui.course_
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Chat
import androidx.compose.material.icons.filled.ListAlt
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.School
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
Expand All @@ -30,33 +28,29 @@ import io.github.fornewid.placeholder.material3.placeholder
internal fun CourseTopAppBar(
selectedTabIndex: Int,
courseDataState: DataState<Course>,
scrollBehavior: TopAppBarScrollBehavior,
changeTab: (Int) -> Unit,
onReloadCourse: () -> Unit,
onNavigateBack: () -> Unit
) {
val courseTitle = courseDataState.bind<String?> { it.title }.orElse(null)

Column {
TopAppBar(
title = {
Text(
modifier = Modifier.placeholder(visible = !courseDataState.isSuccess),
text = courseDataState.bind { it.title }
.orElse("Placeholder course title"),
text = courseTitle.orEmpty(),
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
},
navigationIcon = {
IconButton(onClick = onNavigateBack) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null)
}
},
actions = {
IconButton(onClick = onReloadCourse) {
Icon(imageVector = Icons.Default.Refresh, contentDescription = null)
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = null
)
}
},
scrollBehavior = scrollBehavior
}
)
TabRow(
modifier = Modifier.fillMaxWidth(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import androidx.compose.foundation.layout.systemBars
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
Expand All @@ -24,7 +22,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -309,22 +306,14 @@ internal fun CourseUiScreen(
onNavigateBack: () -> Unit,
onReloadCourse: () -> Unit
) {
val topAppBarState = rememberTopAppBarState()

val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
topAppBarState
)

Scaffold(
modifier = modifier.then(Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)),
modifier = modifier,
topBar = {
CourseTopAppBar(
courseDataState = courseDataState,
onNavigateBack = onNavigateBack,
scrollBehavior = scrollBehavior,
selectedTabIndex = selectedTabIndex,
changeTab = updateSelectedTabIndex,
onReloadCourse = onReloadCourse
changeTab = updateSelectedTabIndex
)
}
) { padding ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
Expand All @@ -25,8 +24,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
Expand All @@ -37,7 +34,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
Expand Down Expand Up @@ -102,12 +98,6 @@ internal fun CoursesOverview(
) {
val coursesDataState by viewModel.dashboard.collectAsState()

val topAppBarState = rememberTopAppBarState()

val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(
topAppBarState
)

val shouldDisplayBetaDialog by betaHintService.shouldShowBetaHint.collectAsState(initial = false)
var displayBetaDialog by rememberSaveable { mutableStateOf(false) }

Expand All @@ -117,7 +107,7 @@ internal fun CoursesOverview(
}

Scaffold(
modifier = modifier.then(Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)),
modifier = modifier,
topBar = {
TopAppBar(
title = {
Expand Down Expand Up @@ -145,13 +135,6 @@ internal fun CoursesOverview(
}
},
actions = {
IconButton(onClick = viewModel::requestReloadDashboard) {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = null
)
}

IconButton(onClick = onClickRegisterForCourse) {
Icon(
imageVector = Icons.Default.Add,
Expand All @@ -162,8 +145,7 @@ internal fun CoursesOverview(
IconButton(onClick = onOpenSettings) {
Icon(imageVector = Icons.Default.Settings, contentDescription = null)
}
},
scrollBehavior = scrollBehavior
}
)
}
) { padding ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="course_overview_title">Your current courses</string>
<string name="course_overview_title">Courses</string>

<!-- The placeholders are digits, but are supplied as strings, as the number formatting is handled in code. -->
<string name="course_overview_course_progress">%1$sP/%2$sP (%3$s)</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ internal fun LectureScreen(
TopAppBar(
title = {
Text(
text = lectureTitle ?: "Placeholder",
text = lectureTitle.orEmpty(),
modifier = Modifier.placeholder(lectureTitle == null),
maxLines = 2,
overflow = TextOverflow.Ellipsis
Expand Down
Loading

0 comments on commit 9ce9282

Please sign in to comment.