diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/ControlWhenPlayerIsActive.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/ControlWhenPlayerIsActive.kt index fa78b283d..19fcc6482 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/ControlWhenPlayerIsActive.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/ControlWhenPlayerIsActive.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.service.playback.composable +import android.view.View import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -67,23 +68,30 @@ fun ControlWhenPlayerIsActive( // Keeps the screen on while playing and viewing videos. DisposableEffect(key1 = controller, key2 = view) { - val listener = - object : Player.Listener { - override fun onIsPlayingChanged(isPlaying: Boolean) { - // doesn't consider the mutex because the screen can turn off if the video - // being played in the mutex is not visible. - if (view.keepScreenOn != isPlaying) { - view.keepScreenOn = isPlaying - } - } - } + val listener = PlayerEventListener(view) controller.addListener(listener) onDispose { - if (view.keepScreenOn) { - view.keepScreenOn = false - } controller.removeListener(listener) + listener.destroy() + } + } +} + +class PlayerEventListener( + val view: View, +) : Player.Listener { + override fun onIsPlayingChanged(isPlaying: Boolean) { + // doesn't consider the mutex because the screen can turn off if the video + // being played in the mutex is not visible. + if (view.keepScreenOn != isPlaying) { + view.keepScreenOn = isPlaying + } + } + + fun destroy() { + if (view.keepScreenOn) { + view.keepScreenOn = false } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/GetVideoController.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/GetVideoController.kt index 52850fd07..f264bc9f5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/GetVideoController.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/GetVideoController.kt @@ -54,6 +54,10 @@ fun GetVideoController( val scope = rememberCoroutineScope() // Prepares a VideoPlayer from the foreground service. + // + // TODO: Review this code because a new Disposable Effect can run + // before the onDispose of the previous composable and the onDispose + // sometimes affects the new variables, not the old ones. DisposableEffect(key1 = mediaItem.src.videoUri) { // If it is not null, the user might have come back from a playing video, like clicking on // the notification of the video player. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/Waveform.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/Waveform.kt index 57da6b311..3307cbf99 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/Waveform.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/Waveform.kt @@ -56,21 +56,25 @@ fun Waveform( val restartFlow = remember { mutableIntStateOf(0) } + val myController = mediaControllerState.controller + // Keeps the screen on while playing and viewing videos. - DisposableEffect(key1 = mediaControllerState.controller) { - val listener = - object : Player.Listener { - override fun onIsPlayingChanged(isPlaying: Boolean) { - // doesn't consider the mutex because the screen can turn off if the video - // being played in the mutex is not visible. - if (isPlaying) { - restartFlow.intValue += 1 + if (myController != null) { + DisposableEffect(key1 = myController) { + val listener = + object : Player.Listener { + override fun onIsPlayingChanged(isPlaying: Boolean) { + // doesn't consider the mutex because the screen can turn off if the video + // being played in the mutex is not visible. + if (isPlaying) { + restartFlow.intValue += 1 + } } } - } - mediaControllerState.controller?.addListener(listener) - onDispose { mediaControllerState.controller?.removeListener(listener) } + myController.addListener(listener) + onDispose { myController.removeListener(listener) } + } } LaunchedEffect(key1 = restartFlow.intValue) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/BackgroundMedia.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/BackgroundMedia.kt index edddaf1ac..1649d665e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/BackgroundMedia.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/BackgroundMedia.kt @@ -39,7 +39,7 @@ object BackgroundMedia { fun removeBackgroundControllerAndReleaseIt() { bgInstance.value?.let { PlaybackServiceClient.removeController(it) - clearBackground() + bgInstance.tryEmit(null) } } @@ -47,7 +47,9 @@ object BackgroundMedia { bgInstance.tryEmit(mediaControllerState) } - fun clearBackground() { - bgInstance.tryEmit(null) + fun clearBackground(mediaControllerState: MediaControllerState) { + if (bgInstance.value == mediaControllerState) { + bgInstance.tryEmit(null) + } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PictureInPicture.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PictureInPicture.kt index 42ebcff9e..c2a2008b6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PictureInPicture.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PictureInPicture.kt @@ -58,9 +58,8 @@ fun rememberIsInPipMode(): Boolean { Consumer { info -> pipMode = info.isInPictureInPictureMode } - activity.addOnPictureInPictureModeChangedListener( - observer, - ) + + activity.addOnPictureInPictureModeChangedListener(observer) onDispose { activity.removeOnPictureInPictureModeChangedListener(observer) } } return pipMode diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt index 5a856db04..168e03897 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt @@ -81,7 +81,7 @@ fun PipVideo(controller: MediaControllerState) { DisposableEffect(controller) { BackgroundMedia.switchKeepPlaying(controller) onDispose { - BackgroundMedia.clearBackground() + BackgroundMedia.clearBackground(controller) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt index 26af4a4ce..7338a622c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt @@ -40,7 +40,6 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -74,12 +73,6 @@ fun NewUserMetadataScreen( postViewModel.load(accountViewModel.account) } - DisposableEffect(Unit) { - onDispose { - postViewModel.clear() - } - } - Scaffold( topBar = { TopAppBar( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt index c244e8116..dd57aefdc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt @@ -104,7 +104,6 @@ fun keyboardAsState(): State { } } view.viewTreeObserver.addOnGlobalLayoutListener(onGlobalListener) - onDispose { view.viewTreeObserver.removeOnGlobalLayoutListener(onGlobalListener) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt index 2d07e3c0a..87321b417 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModelStore import androidx.lifecycle.ViewModelStoreOwner @@ -55,11 +54,13 @@ fun SetAccountCentricViewModelStore( content() } - DisposableEffect(key1 = state) { - onDispose { - state.currentViewModelStore.viewModelStore.clear() - } - } + // moved this clearing activity to the viewmodel account + // because the new composable might run before the onDispose. + // DisposableEffect(key1 = state) { + // onDispose { + // state.currentViewModelStore.viewModelStore.clear() + // } + // } } class AccountCentricViewModelStore : ViewModelStoreOwner { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt index 65df1f06f..0c46ae6b9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import android.app.Activity +import android.content.Intent import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts @@ -216,25 +217,27 @@ private fun ListenToExternalSignerIfNeeded(accountViewModel: AccountViewModel) { } } + val launcher: (Intent) -> Unit = { + try { + launcher.launch(it) + } catch (e: Exception) { + if (e is CancellationException) throw e + Log.e("Signer", "Error opening Signer app", e) + accountViewModel.toastManager.toast( + R.string.error_opening_external_signer, + R.string.error_opening_external_signer_description, + ) + } + } + lifeCycleOwner.lifecycle.addObserver(observer) accountViewModel.account.signer.launcher.registerLauncher( - launcher = { - try { - launcher.launch(it) - } catch (e: Exception) { - if (e is CancellationException) throw e - Log.e("Signer", "Error opening Signer app", e) - accountViewModel.toastManager.toast( - R.string.error_opening_external_signer, - R.string.error_opening_external_signer_description, - ) - } - }, + launcher = launcher, contentResolver = Amethyst.instance::contentResolverFn, ) onDispose { accountViewModel.account.signer.launcher - .clearLauncher() + .clearLauncherIf(launcher) lifeCycleOwner.lifecycle.removeObserver(observer) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/TabRelays.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/TabRelays.kt index e55e66e2b..5e5c4864c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/TabRelays.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/TabRelays.kt @@ -64,8 +64,6 @@ fun TabRelays( lifeCycleOwner.lifecycle.addObserver(observer) onDispose { lifeCycleOwner.lifecycle.removeObserver(observer) - println("Profile Relay Dispose") - feedViewModel.unsubscribeTo(user) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index ac8621766..a46c60fa6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -641,26 +641,30 @@ private fun PrepareExternalSignerReceiver(onLogin: (pubkey: String, packageName: val activity = getActivity() as MainActivity DisposableEffect(launcher, activity, externalSignerLauncher) { - externalSignerLauncher.registerLauncher( - launcher = { - try { - launcher.launch(it) - } catch (e: Exception) { - if (e is CancellationException) throw e - Log.e("Signer", "Error opening Signer app", e) - scope.launch(Dispatchers.Main) { - Toast - .makeText( - Amethyst.instance, - R.string.error_opening_external_signer, - Toast.LENGTH_SHORT, - ).show() - } + val launcher: (Intent) -> Unit = { + try { + launcher.launch(it) + } catch (e: Exception) { + if (e is CancellationException) throw e + Log.e("Signer", "Error opening Signer app", e) + scope.launch(Dispatchers.Main) { + Toast + .makeText( + Amethyst.instance, + R.string.error_opening_external_signer, + Toast.LENGTH_SHORT, + ).show() } - }, + } + } + + externalSignerLauncher.registerLauncher( + launcher = launcher, contentResolver = Amethyst.instance::contentResolverFn, ) - onDispose { externalSignerLauncher.clearLauncher() } + onDispose { + externalSignerLauncher.clearLauncherIf(launcher) + } } LaunchedEffect(externalSignerLauncher) { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/ExternalSignerLauncher.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/ExternalSignerLauncher.kt index 2a5a7507c..ff7c5e4c4 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/ExternalSignerLauncher.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/ExternalSignerLauncher.kt @@ -114,9 +114,11 @@ class ExternalSignerLauncher( } /** Call this function when the activity is destroyed or is about to be replaced. */ - fun clearLauncher() { - this.signerAppLauncher = null - this.contentResolver = null + fun clearLauncherIf(launcher: ((Intent) -> Unit)) { + if (signerAppLauncher == launcher) { + this.signerAppLauncher = null + this.contentResolver = null + } } fun newResult(data: Intent) {