mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-27 22:34:51 +00:00
android, desktop, ios: change only the progress indicator timeout
Reverts the shared helper the timeout change was extracted into, leaving the effect where each view already had it. NewChatView and ViewModifiers are no longer touched by this branch at all - the first was already at 0.5s.
This commit is contained in:
@@ -76,7 +76,15 @@ struct CIGroupInvitationView: View {
|
||||
.background { chatItemFrameColor(chatItem, theme).modifier(ChatTailPadding()) }
|
||||
.textSelection(.disabled)
|
||||
.onPreferenceChange(DetermineWidth.Key.self) { frameWidth = $0 }
|
||||
.progressByTimeout(inProgress, $progressByTimeout)
|
||||
.onChange(of: inProgress) { inPrgrs in
|
||||
if inPrgrs {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
progressByTimeout = inProgress
|
||||
}
|
||||
} else {
|
||||
progressByTimeout = false
|
||||
}
|
||||
}
|
||||
|
||||
if action {
|
||||
v.simultaneousGesture(TapGesture().onEnded { joinGroup(groupInvitation.groupId) })
|
||||
|
||||
@@ -584,7 +584,15 @@ struct ComposeView: View {
|
||||
clearState()
|
||||
}
|
||||
}
|
||||
.progressByTimeout(composeState.inProgress, $composeState.progressByTimeout)
|
||||
.onChange(of: composeState.inProgress) { inProgress in
|
||||
if inProgress {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
composeState.progressByTimeout = composeState.inProgress
|
||||
}
|
||||
} else {
|
||||
composeState.progressByTimeout = false
|
||||
}
|
||||
}
|
||||
.confirmationDialog("Attach", isPresented: $showChooseSource, titleVisibility: .visible) {
|
||||
Button("Take picture") {
|
||||
showTakePhoto = true
|
||||
|
||||
@@ -46,7 +46,15 @@ struct ContextContactRequestActionsView: View {
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
}
|
||||
.progressByTimeout(inProgress, $progressByTimeout)
|
||||
.onChange(of: inProgress) { inPrgrs in
|
||||
if inPrgrs {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
progressByTimeout = inProgress
|
||||
}
|
||||
} else {
|
||||
progressByTimeout = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func showRejectRequestAlert() {
|
||||
|
||||
@@ -94,7 +94,15 @@ struct ChatListNavLink: View {
|
||||
invalidJSONPreview(json)
|
||||
}
|
||||
}
|
||||
.progressByTimeout(inProgress, $progressByTimeout)
|
||||
.onChange(of: inProgress) { inPrgrs in
|
||||
if inPrgrs {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
progressByTimeout = inProgress
|
||||
}
|
||||
} else {
|
||||
progressByTimeout = false
|
||||
}
|
||||
}
|
||||
.actionSheet(item: $actionSheet) { $0.actionSheet }
|
||||
}
|
||||
|
||||
|
||||
@@ -26,23 +26,8 @@ extension View {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
func progressByTimeout(_ inProgress: Bool, _ progressByTimeout: Binding<Bool>) -> some View {
|
||||
task(id: inProgress) {
|
||||
if inProgress {
|
||||
try? await Task.sleep(nanoseconds: progressTimeout)
|
||||
if !Task.isCancelled {
|
||||
progressByTimeout.wrappedValue = true
|
||||
}
|
||||
} else {
|
||||
progressByTimeout.wrappedValue = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let progressTimeout: UInt64 = 500_000000
|
||||
|
||||
extension Notification.Name {
|
||||
static let chatViewWillBeginScrolling = Notification.Name("chatWillBeginScrolling")
|
||||
}
|
||||
|
||||
+11
-1
@@ -7,6 +7,7 @@ import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
@@ -21,6 +22,7 @@ import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.res.MR
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@Composable
|
||||
fun ComposeContextContactRequestActionsView(
|
||||
@@ -28,7 +30,15 @@ fun ComposeContextContactRequestActionsView(
|
||||
contactRequestId: Long
|
||||
) {
|
||||
val inProgress = rememberAcceptingContactRequest(contactRequestId)
|
||||
val progressByTimeout by rememberProgressByTimeout(inProgress)
|
||||
var progressByTimeout by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(inProgress.value) {
|
||||
progressByTimeout = if (inProgress.value) {
|
||||
delay(500)
|
||||
inProgress.value
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
Modifier.height(60.dp),
|
||||
|
||||
+10
-1
@@ -28,11 +28,20 @@ fun ComposeContextMemberContactActionsView(
|
||||
groupDirectInv: GroupDirectInvitation
|
||||
) {
|
||||
val inProgress = rememberSaveable { mutableStateOf(false) }
|
||||
val progressByTimeout by rememberProgressByTimeout(inProgress)
|
||||
var progressByTimeout by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(inProgress.value) {
|
||||
progressByTimeout = if (inProgress.value) {
|
||||
delay(500)
|
||||
inProgress.value
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
KeyChangeEffect(chatModel.chatId.value) {
|
||||
if (inProgress.value) {
|
||||
inProgress.value = false
|
||||
progressByTimeout = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -1573,8 +1573,14 @@ fun ComposeView(
|
||||
chatModel.sharedContent.value = null
|
||||
}
|
||||
|
||||
ProgressByTimeoutEffect(composeState.value.inProgress) {
|
||||
composeState.value = composeState.value.copy(progressByTimeout = it)
|
||||
LaunchedEffect(composeState.value.inProgress) {
|
||||
val newProgressByTimeout = if (composeState.value.inProgress) {
|
||||
delay(500)
|
||||
composeState.value.inProgress
|
||||
} else {
|
||||
false
|
||||
}
|
||||
composeState.value = composeState.value.copy(progressByTimeout = newProgressByTimeout)
|
||||
}
|
||||
|
||||
val relayListExpanded = remember { mutableStateOf(false) }
|
||||
|
||||
+11
-1
@@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
@@ -20,6 +21,7 @@ import chat.simplex.common.views.chatlist.rememberJoiningGroup
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.res.MR
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@Composable
|
||||
fun CIGroupInvitationView(
|
||||
@@ -34,7 +36,15 @@ fun CIGroupInvitationView(
|
||||
val sent = ci.chatDir.sent
|
||||
val action = !sent && groupInvitation.status == CIGroupInvitationStatus.Pending
|
||||
val inProgress = rememberJoiningGroup(groupInvitation.groupId)
|
||||
val progressByTimeout by rememberProgressByTimeout(inProgress)
|
||||
var progressByTimeout by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(inProgress.value) {
|
||||
progressByTimeout = if (inProgress.value) {
|
||||
delay(500)
|
||||
inProgress.value
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun groupInfoView() {
|
||||
|
||||
+9
-1
@@ -73,7 +73,15 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>) {
|
||||
}
|
||||
is ChatInfo.Group -> {
|
||||
val inProgress = rememberJoiningGroup(chat.chatInfo.groupInfo.groupId)
|
||||
val progressByTimeout by rememberProgressByTimeout(inProgress)
|
||||
var progressByTimeout by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(inProgress.value) {
|
||||
progressByTimeout = if (inProgress.value) {
|
||||
delay(500)
|
||||
inProgress.value
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
val defaultClickAction = { if (!inProgress.value && chatModel.chatId.value != chat.id) scope.launch { groupChatAction(chat.remoteHostId, chat.chatInfo.groupInfo, chatModel) } }
|
||||
ChatListNavLinkLayout(
|
||||
chatLinkPreview = {
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package chat.simplex.common.views.helpers
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
private const val PROGRESS_TIMEOUT_MS = 500L
|
||||
|
||||
@Composable
|
||||
fun ProgressByTimeoutEffect(inProgress: Boolean, setProgressByTimeout: (Boolean) -> Unit) {
|
||||
LaunchedEffect(inProgress) {
|
||||
if (inProgress) {
|
||||
delay(PROGRESS_TIMEOUT_MS)
|
||||
setProgressByTimeout(true)
|
||||
} else {
|
||||
setProgressByTimeout(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberProgressByTimeout(inProgress: State<Boolean>): State<Boolean> {
|
||||
val progressByTimeout = remember { mutableStateOf(false) }
|
||||
ProgressByTimeoutEffect(inProgress.value) { progressByTimeout.value = it }
|
||||
return progressByTimeout
|
||||
}
|
||||
+10
-1
@@ -303,7 +303,16 @@ fun ActiveProfilePicker(
|
||||
filteredProfiles(chatModel.users.map { it.user }.sortedBy { !it.activeUser }, searchTextOrPassword.value)
|
||||
}
|
||||
|
||||
val progressByTimeout by rememberProgressByTimeout(switchingProfile)
|
||||
var progressByTimeout by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(switchingProfile.value) {
|
||||
progressByTimeout = if (switchingProfile.value) {
|
||||
delay(500)
|
||||
switchingProfile.value
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ProfilePickerUserOption(user: User) {
|
||||
|
||||
@@ -158,10 +158,10 @@ Join buttons. The connect composer belongs to the chat itself, not to a scope wi
|
||||
|
||||
**5. Client: the progress indicator appears after 0.5s instead of 1s** (android, desktop, ios).
|
||||
|
||||
The effect behind it was copied into 5 Kotlin and 4 Swift views; it is now one helper per platform,
|
||||
which is also what makes the threshold a single constant. Two of the Swift copies had drifted — the
|
||||
deferred write captured the value that started the delay rather than reading the current one, so an
|
||||
operation that finished before the delay elapsed left the indicator on with nothing to turn it off.
|
||||
Accepting a request or joining a group usually takes longer than 1s, so the button looked inert for
|
||||
a second before anything acknowledged the tap - which is what prompts a second tap. The threshold is
|
||||
per view; extracting the effect the views share was considered and left out, to keep the change to
|
||||
the timing.
|
||||
|
||||
## Alternatives considered and rejected
|
||||
|
||||
|
||||
Reference in New Issue
Block a user