mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-16 19:26:12 -04:00
Merge pull request #408 from d4rken-org/fix/profile-unsaved-changes-false-positive
Fix false-positive unsaved changes dialog and popup notifications
This commit is contained in:
@@ -33,7 +33,7 @@ class PopUpReaction @Inject constructor(
|
|||||||
private val bluetoothManager: BluetoothManager2,
|
private val bluetoothManager: BluetoothManager2,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val caseCoolDowns = mutableMapOf<PodDevice.Id, Instant>()
|
private val caseCoolDowns = mutableMapOf<String, Instant>()
|
||||||
|
|
||||||
private fun monitorCase(): Flow<Event> = reactionSettings.showPopUpOnCaseOpen.flow
|
private fun monitorCase(): Flow<Event> = reactionSettings.showPopUpOnCaseOpen.flow
|
||||||
.flatMapLatest { isEnabled ->
|
.flatMapLatest { isEnabled ->
|
||||||
@@ -56,10 +56,10 @@ class PopUpReaction @Inject constructor(
|
|||||||
}
|
}
|
||||||
log(TAG, VERBOSE) { "previous-id=${previous?.identifier}, current-id=${current.identifier}" }
|
log(TAG, VERBOSE) { "previous-id=${previous?.identifier}, current-id=${current.identifier}" }
|
||||||
|
|
||||||
val isSameDeviceWithCaseNowOpen =
|
val isSameDeviceOrProfile = previous?.identifier == current.identifier ||
|
||||||
previous?.identifier == current.identifier && previous.caseLidState != current.caseLidState
|
(previous?.meta?.profile?.id != null && previous.meta.profile?.id == current.meta.profile?.id)
|
||||||
val isNewDeviceWithJustOpenedCase =
|
val isSameDeviceWithCaseNowOpen = isSameDeviceOrProfile && previous?.caseLidState != current.caseLidState
|
||||||
previous?.identifier != current.identifier && previous?.caseLidState != current.caseLidState
|
val isNewDeviceWithJustOpenedCase = !isSameDeviceOrProfile && previous?.caseLidState != current.caseLidState
|
||||||
|
|
||||||
if (!isSameDeviceWithCaseNowOpen && !isNewDeviceWithJustOpenedCase) {
|
if (!isSameDeviceWithCaseNowOpen && !isNewDeviceWithJustOpenedCase) {
|
||||||
return@mapNotNull null
|
return@mapNotNull null
|
||||||
@@ -69,43 +69,46 @@ class PopUpReaction @Inject constructor(
|
|||||||
throttleCasePopUps(current)
|
throttleCasePopUps(current)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun throttleCasePopUps(current: DualApplePods): Event? = when {
|
private fun throttleCasePopUps(current: DualApplePods): Event? {
|
||||||
current.caseLidState == DualApplePods.LidState.OPEN -> {
|
val cooldownKey = current.meta.profile?.id ?: current.identifier.toString()
|
||||||
log(TAG, INFO) { "Show popup" }
|
return when {
|
||||||
|
current.caseLidState == DualApplePods.LidState.OPEN -> {
|
||||||
|
log(TAG, INFO) { "Show popup" }
|
||||||
|
|
||||||
val now = Instant.now()
|
val now = Instant.now()
|
||||||
val lastShown = caseCoolDowns[current.identifier] ?: Instant.MIN
|
val lastShown = caseCoolDowns[cooldownKey] ?: Instant.MIN
|
||||||
val sinceLastPop = Duration.between(lastShown, now)
|
val sinceLastPop = Duration.between(lastShown, now)
|
||||||
log(TAG) { "Time since last case popup: $sinceLastPop" }
|
log(TAG) { "Time since last case popup: $sinceLastPop" }
|
||||||
|
|
||||||
if (sinceLastPop >= Duration.ofSeconds(10)) {
|
if (sinceLastPop >= Duration.ofSeconds(10)) {
|
||||||
caseCoolDowns[current.identifier] = Instant.now()
|
caseCoolDowns[cooldownKey] = Instant.now()
|
||||||
Event.PopupShow(device = current)
|
Event.PopupShow(device = current)
|
||||||
} else {
|
} else {
|
||||||
log(TAG, INFO) { "Case popup is still on cooldown: $sinceLastPop" }
|
log(TAG, INFO) { "Case popup is still on cooldown: $sinceLastPop" }
|
||||||
null
|
null
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current.caseLidState != DualApplePods.LidState.OPEN -> {
|
|
||||||
when (current.caseLidState) {
|
|
||||||
DualApplePods.LidState.CLOSED -> {
|
|
||||||
log(TAG, INFO) { "Lid was actively closed, resetting cooldown." }
|
|
||||||
caseCoolDowns.remove(current.identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
log(TAG, WARN) { "Lid was was not actively closed, refreshing cooldown." }
|
|
||||||
caseCoolDowns[current.identifier] = Instant.now()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log(TAG, INFO) { "Hide popup" }
|
current.caseLidState != DualApplePods.LidState.OPEN -> {
|
||||||
|
when (current.caseLidState) {
|
||||||
|
DualApplePods.LidState.CLOSED -> {
|
||||||
|
log(TAG, INFO) { "Lid was actively closed, resetting cooldown." }
|
||||||
|
caseCoolDowns.remove(cooldownKey)
|
||||||
|
}
|
||||||
|
|
||||||
Event.PopupHide()
|
else -> {
|
||||||
|
log(TAG, WARN) { "Lid was was not actively closed, refreshing cooldown." }
|
||||||
|
caseCoolDowns[cooldownKey] = Instant.now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log(TAG, INFO) { "Hide popup" }
|
||||||
|
|
||||||
|
Event.PopupHide()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val connectionCoolDowns = mutableMapOf<BluetoothAddress, Instant>()
|
private val connectionCoolDowns = mutableMapOf<BluetoothAddress, Instant>()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package eu.darken.capod.reaction.ui.popup
|
|||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@@ -49,65 +50,67 @@ fun PopUpContent(
|
|||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
Card(
|
Box(modifier = modifier.padding(start = 12.dp, top = 12.dp, end = 12.dp, bottom = 16.dp)) {
|
||||||
modifier = modifier.fillMaxWidth(),
|
Card(
|
||||||
shape = RoundedCornerShape(24.dp),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
elevation = CardDefaults.cardElevation(defaultElevation = 8.dp),
|
shape = RoundedCornerShape(24.dp),
|
||||||
) {
|
elevation = CardDefaults.cardElevation(defaultElevation = 8.dp),
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 20.dp)
|
|
||||||
.padding(top = 20.dp, bottom = 16.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
) {
|
||||||
// Header: label + signal quality
|
Column(
|
||||||
Row(
|
modifier = Modifier
|
||||||
modifier = Modifier.fillMaxWidth(),
|
.fillMaxWidth()
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
.padding(horizontal = 20.dp)
|
||||||
horizontalArrangement = Arrangement.Center,
|
.padding(top = 20.dp, bottom = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Text(
|
// Header: label + signal quality
|
||||||
text = device.getLabel(context),
|
Row(
|
||||||
style = MaterialTheme.typography.titleLarge,
|
modifier = Modifier.fillMaxWidth(),
|
||||||
maxLines = 1,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
overflow = TextOverflow.Ellipsis,
|
horizontalArrangement = Arrangement.Center,
|
||||||
modifier = Modifier.weight(1f, fill = false),
|
) {
|
||||||
)
|
|
||||||
|
|
||||||
val signalText = device.getSignalQuality(context)
|
|
||||||
if (signalText.isNotBlank()) {
|
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.TwoTone.SignalCellularAlt,
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.size(12.dp),
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
|
||||||
Text(
|
Text(
|
||||||
text = signalText,
|
text = device.getLabel(context),
|
||||||
style = MaterialTheme.typography.labelSmall,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.weight(1f, fill = false),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val signalText = device.getSignalQuality(context)
|
||||||
|
if (signalText.isNotBlank()) {
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.TwoTone.SignalCellularAlt,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(12.dp),
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Text(
|
||||||
|
text = signalText,
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
// Device-specific content
|
// Device-specific content
|
||||||
when (device) {
|
when (device) {
|
||||||
is DualPodDevice -> DualPodContent(device)
|
is DualPodDevice -> DualPodContent(device)
|
||||||
is SinglePodDevice -> SinglePodContent(device)
|
is SinglePodDevice -> SinglePodContent(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(20.dp))
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
// Close button
|
// Close button
|
||||||
Button(
|
Button(
|
||||||
onClick = onClose,
|
onClick = onClose,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
shape = RoundedCornerShape(24.dp),
|
shape = RoundedCornerShape(24.dp),
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(R.string.general_close_action))
|
Text(text = stringResource(R.string.general_close_action))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class PopUpWindow @Inject constructor(
|
|||||||
val dm = appContext.resources.displayMetrics
|
val dm = appContext.resources.displayMetrics
|
||||||
val margin = (24 * dm.density).toInt()
|
val margin = (24 * dm.density).toInt()
|
||||||
width = minOf(dm.widthPixels - margin * 2, (400 * dm.density).toInt())
|
width = minOf(dm.widthPixels - margin * 2, (400 * dm.density).toInt())
|
||||||
|
y = (8 * dm.density).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var composeView: ComposeView? = null
|
private var composeView: ComposeView? = null
|
||||||
|
|||||||
Reference in New Issue
Block a user