mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-08-08 06:46:11 +00:00
Stop nearby notes while app is backgrounded
This commit is contained in:
parent
6fad768a3d
commit
416dc989e8
@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
*
|
||||
* Merely rendering the mesh timeline must not open a building-precision Nostr
|
||||
* subscription. A subscription is eligible only after an explicit reveal and
|
||||
* while at least one nearby-notes surface is active.
|
||||
* while the app is foregrounded and at least one nearby-notes surface is active.
|
||||
*/
|
||||
@MainThread
|
||||
class NearbyNotesController internal constructor(
|
||||
@ -25,6 +25,7 @@ class NearbyNotesController internal constructor(
|
||||
private var activeHolders = 0
|
||||
private var locationEnabled = false
|
||||
private var locationAuthorized = false
|
||||
private var appForeground = false
|
||||
private var buildingGeohash: String? = null
|
||||
private var subscribedGeohash: String? = null
|
||||
|
||||
@ -50,6 +51,12 @@ class NearbyNotesController internal constructor(
|
||||
reconcileSubscription()
|
||||
}
|
||||
|
||||
/** Closes the live subscription whenever the process leaves the foreground. */
|
||||
fun updateAppForeground(isForeground: Boolean) {
|
||||
appForeground = isForeground
|
||||
reconcileSubscription()
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the privacy-sensitive inputs independently of view activation.
|
||||
* Permission revocation, location disable, or loss of the building cell
|
||||
@ -78,6 +85,7 @@ class NearbyNotesController internal constructor(
|
||||
private fun reconcileSubscription() {
|
||||
val target = buildingGeohash.takeIf {
|
||||
activeHolders > 0 &&
|
||||
appForeground &&
|
||||
_revealed.value &&
|
||||
locationEnabled &&
|
||||
locationAuthorized
|
||||
|
||||
@ -29,6 +29,10 @@ import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bitchat.android.R
|
||||
import com.bitchat.android.geohash.ChannelID
|
||||
@ -117,6 +121,30 @@ fun ChatScreen(viewModel: ChatViewModel) {
|
||||
selectedPrivatePeer == null &&
|
||||
privateChatSheetPeer == null
|
||||
|
||||
val processLifecycleOwner = remember { ProcessLifecycleOwner.get() }
|
||||
DisposableEffect(processLifecycleOwner, nearbyNotesController) {
|
||||
val lifecycle = processLifecycleOwner.lifecycle
|
||||
val observer = object : DefaultLifecycleObserver {
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
nearbyNotesController.updateAppForeground(true)
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
nearbyNotesController.updateAppForeground(false)
|
||||
}
|
||||
}
|
||||
|
||||
lifecycle.addObserver(observer)
|
||||
nearbyNotesController.updateAppForeground(
|
||||
lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED),
|
||||
)
|
||||
|
||||
onDispose {
|
||||
lifecycle.removeObserver(observer)
|
||||
nearbyNotesController.updateAppForeground(false)
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(
|
||||
isMeshTimeline,
|
||||
locationEnabled,
|
||||
|
||||
@ -16,9 +16,13 @@ class NearbyNotesControllerTest {
|
||||
unsubscribe = { unsubscribeCount += 1 },
|
||||
)
|
||||
|
||||
private fun foregroundController() = controller().also {
|
||||
it.updateAppForeground(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `active mesh timeline does not subscribe before explicit reveal`() {
|
||||
val controller = controller()
|
||||
val controller = foregroundController()
|
||||
|
||||
controller.updateAvailability(
|
||||
locationEnabled = true,
|
||||
@ -38,7 +42,7 @@ class NearbyNotesControllerTest {
|
||||
|
||||
@Test
|
||||
fun `reveal remains dormant until a nearby notes surface is active`() {
|
||||
val controller = controller()
|
||||
val controller = foregroundController()
|
||||
controller.updateAvailability(true, true, "u4pruydq")
|
||||
|
||||
controller.reveal()
|
||||
@ -52,7 +56,7 @@ class NearbyNotesControllerTest {
|
||||
|
||||
@Test
|
||||
fun `last deactivate unsubscribes exactly once`() {
|
||||
val controller = controller()
|
||||
val controller = foregroundController()
|
||||
controller.updateAvailability(true, true, "u4pruydq")
|
||||
controller.reveal()
|
||||
controller.activate()
|
||||
@ -67,9 +71,28 @@ class NearbyNotesControllerTest {
|
||||
assertEquals(1, unsubscribeCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `backgrounding closes the subscription and foregrounding restores it`() {
|
||||
val controller = foregroundController()
|
||||
controller.updateAvailability(true, true, "u4pruydq")
|
||||
controller.activate()
|
||||
controller.reveal()
|
||||
|
||||
controller.updateAppForeground(false)
|
||||
|
||||
assertEquals(1, unsubscribeCount)
|
||||
assertTrue(controller.revealed.value)
|
||||
|
||||
controller.updateAppForeground(false)
|
||||
assertEquals(1, unsubscribeCount)
|
||||
|
||||
controller.updateAppForeground(true)
|
||||
assertEquals(listOf("u4pruydq", "u4pruydq"), subscriptions)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `disable and permission revocation close the live subscription`() {
|
||||
val controller = controller()
|
||||
val controller = foregroundController()
|
||||
controller.updateAvailability(true, true, "u4pruydq")
|
||||
controller.activate()
|
||||
controller.reveal()
|
||||
@ -91,6 +114,7 @@ class NearbyNotesControllerTest {
|
||||
subscribe = { events += "subscribe:$it" },
|
||||
unsubscribe = { events += "unsubscribe" },
|
||||
)
|
||||
controller.updateAppForeground(true)
|
||||
controller.updateAvailability(true, true, "u4pruydq")
|
||||
controller.activate()
|
||||
controller.reveal()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user