From f016d036d87c85cd5a1b13d88fd37378337837c1 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Fri, 18 Apr 2025 12:19:05 +0300 Subject: [PATCH] Improved pulltorefresh look and implementation --- .../com/tutpro/baresip/CustomElements.kt | 34 ---- .../kotlin/com/tutpro/baresip/MainActivity.kt | 166 +++++++++--------- 2 files changed, 87 insertions(+), 113 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt b/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt index eccfb544..73491224 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt @@ -12,7 +12,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope @@ -45,9 +44,6 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Surface import androidx.compose.material3.TextButton -import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults.Indicator -import androidx.compose.material3.pulltorefresh.pullToRefresh -import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState @@ -161,36 +157,6 @@ object CustomElements { } } - @OptIn(ExperimentalMaterial3Api::class) - @Composable - fun PullToRefreshBox( - isRefreshing: Boolean, - onRefresh: () -> Unit, - modifier: Modifier = Modifier, - contentAlignment: Alignment = Alignment.TopStart, - enabled: Boolean = true, - content: @Composable BoxScope.() -> Unit, - ) { - val refreshState = rememberPullToRefreshState() - - Box( - modifier.pullToRefresh( - state = refreshState, - isRefreshing = isRefreshing, - onRefresh = onRefresh, - enabled = enabled, - ), - contentAlignment = contentAlignment, - ) { - content() - Indicator( - modifier = Modifier.align(Alignment.TopCenter), - isRefreshing = isRefreshing, - state = refreshState, - ) - } - } - @Composable fun DropdownMenu( expanded: Boolean, diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index 9e4036f4..d1f858fc 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -99,6 +99,9 @@ import androidx.compose.material3.TextButton import androidx.compose.material3.TextField import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults.Indicator +import androidx.compose.material3.pulltorefresh.pullToRefresh +import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -140,7 +143,6 @@ import com.tutpro.baresip.CustomElements.Checkbox import com.tutpro.baresip.CustomElements.DropdownMenu import com.tutpro.baresip.CustomElements.LabelText import com.tutpro.baresip.CustomElements.PasswordDialog -import com.tutpro.baresip.CustomElements.PullToRefreshBox import com.tutpro.baresip.CustomElements.SelectableAlertDialog import com.tutpro.baresip.CustomElements.Text import com.tutpro.baresip.CustomElements.verticalScrollbar @@ -520,6 +522,10 @@ class MainActivity : ComponentActivity() { fun MainContent(ctx: Context, contentPadding: PaddingValues) { var isRefreshing by remember { mutableStateOf(false) } + val refreshState = rememberPullToRefreshState() + var offset by remember { mutableFloatStateOf(0f) } + val swipeThreshold = 200 + LaunchedEffect(isRefreshing) { if (isRefreshing) { delay(1000) @@ -527,14 +533,13 @@ class MainActivity : ComponentActivity() { } } - if (showAlert.value) { + if (showAlert.value) AlertDialog( showDialog = showAlert, title = alertTitle.value, message = alertMessage.value, positiveButtonText = stringResource(R.string.ok), ) - } if (showDialog.value) AlertDialog( @@ -547,87 +552,90 @@ class MainActivity : ComponentActivity() { onNegativeClicked = onNegativeClicked.value ) - PullToRefreshBox( - isRefreshing = isRefreshing, - modifier = Modifier.fillMaxSize(), - enabled = pullToRefreshEnabled, - onRefresh = { - isRefreshing = true - if (uas.value.isNotEmpty()) { - if (viewModel.selectedAor.value == "") - spinToAor(uas.value.first().account.aor) - val ua = UserAgent.ofAor(viewModel.selectedAor.value)!! - if (ua.account.regint > 0) - Api.ua_register(ua.uap) - } - } - ) { - SelectableAlertDialog( - openDialog = showSelectItemDialog, - title = getString(R.string.choose_destination_uri), - items = items.value, - onItemClicked = itemAction.value, - neutralButtonText = getString(R.string.cancel), - onNeutralClicked = {} - ) - var offset by remember { mutableFloatStateOf(0f) } - val swipeThreshold = 200 - Column( - modifier = Modifier - .imePadding() - .fillMaxWidth() - .padding(contentPadding) - .padding(top = 18.dp, bottom = 6.dp, start = 16.dp, end = 16.dp) - .fillMaxSize() - .pointerInput(Unit) { - detectHorizontalDragGestures( - onDragStart = { offset = 0f }, - onDragEnd = { - if (offset < -swipeThreshold) { - if (uas.value.isNotEmpty()) { - val curPos = UserAgent.findAorIndex(viewModel.selectedAor.value) - val newPos = if (curPos == null) - 0 - else - (curPos + 1) % uas.value.size - if (curPos != newPos) { - val ua = uas.value[newPos] - spinToAor(ua.account.aor) - showCall(ua) - } - } - } - else if (offset > swipeThreshold) { - if (uas.value.isNotEmpty()) { - val curPos = UserAgent.findAorIndex(viewModel.selectedAor.value) - val newPos = when (curPos) { - null -> 0 - 0 -> uas.value.size - 1 - else -> curPos - 1 - } - if (curPos != newPos) { - val ua = uas.value[newPos] - spinToAor(ua.account.aor) - showCall(ua) - } + SelectableAlertDialog( + openDialog = showSelectItemDialog, + title = getString(R.string.choose_destination_uri), + items = items.value, + onItemClicked = itemAction.value, + neutralButtonText = getString(R.string.cancel), + onNeutralClicked = {} + ) + + Column( + modifier = Modifier + .imePadding() + .fillMaxWidth() + .padding(contentPadding) + .padding(top = 18.dp, bottom = 6.dp, start = 16.dp, end = 16.dp) + .fillMaxSize() + .pullToRefresh( + state = refreshState, + isRefreshing = isRefreshing, + onRefresh = { + isRefreshing = true + if (uas.value.isNotEmpty()) { + if (viewModel.selectedAor.value == "") + spinToAor(uas.value.first().account.aor) + val ua = UserAgent.ofAor(viewModel.selectedAor.value)!! + if (ua.account.regint > 0) + Api.ua_register(ua.uap) + } + }, + enabled = pullToRefreshEnabled, + ) + .pointerInput(Unit) { + detectHorizontalDragGestures( + onDragStart = { offset = 0f }, + onDragEnd = { + if (offset < -swipeThreshold) { + if (uas.value.isNotEmpty()) { + val curPos = UserAgent.findAorIndex(viewModel.selectedAor.value) + val newPos = if (curPos == null) + 0 + else + (curPos + 1) % uas.value.size + if (curPos != newPos) { + val ua = uas.value[newPos] + spinToAor(ua.account.aor) + showCall(ua) + } + } + } + else if (offset > swipeThreshold) { + if (uas.value.isNotEmpty()) { + val curPos = UserAgent.findAorIndex(viewModel.selectedAor.value) + val newPos = when (curPos) { + null -> 0 + 0 -> uas.value.size - 1 + else -> curPos - 1 + } + if (curPos != newPos) { + val ua = uas.value[newPos] + spinToAor(ua.account.aor) + showCall(ua) } } } - ) { _, dragAmount -> - offset += dragAmount } + ) { _, dragAmount -> + offset += dragAmount } - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.Top, - horizontalAlignment = Alignment.CenterHorizontally, - ) { - AccountSpinner(ctx) - CallUriRow() - CallRow(ctx) - OnHoldNotice() - AskPasswords(ctx) - AskPassword(ctx) - } + } + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + AccountSpinner(ctx) + CallUriRow() + CallRow(ctx) + OnHoldNotice() + AskPasswords(ctx) + AskPassword(ctx) + Indicator( + modifier = Modifier.align(Alignment.CenterHorizontally), + isRefreshing = isRefreshing, + state = refreshState, + ) } }