mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-20 01:08:29 +00:00
Use MutableSharedFlow
This commit is contained in:
parent
71e7dfb131
commit
90ddc9805a
@ -18,7 +18,8 @@ import javax.inject.Inject
|
|||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class LandingActivity: BaseActionBarActivity() {
|
class LandingActivity: BaseActionBarActivity() {
|
||||||
|
|
||||||
@Inject lateinit var prefs: TextSecurePreferences
|
@Inject
|
||||||
|
internal lateinit var prefs: TextSecurePreferences
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
@ -20,8 +20,10 @@ import javax.inject.Inject
|
|||||||
@androidx.annotation.OptIn(ExperimentalGetImage::class)
|
@androidx.annotation.OptIn(ExperimentalGetImage::class)
|
||||||
class LoadAccountActivity : BaseActionBarActivity() {
|
class LoadAccountActivity : BaseActionBarActivity() {
|
||||||
|
|
||||||
@Inject lateinit var prefs: TextSecurePreferences
|
@Inject
|
||||||
@Inject lateinit var loadingManager: LoadingManager
|
internal lateinit var prefs: TextSecurePreferences
|
||||||
|
@Inject
|
||||||
|
internal lateinit var loadingManager: LoadingManager
|
||||||
|
|
||||||
private val viewModel: LinkDeviceViewModel by viewModels()
|
private val viewModel: LinkDeviceViewModel by viewModels()
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ class LoadAccountActivity : BaseActionBarActivity() {
|
|||||||
prefs.setLastProfileUpdateTime(0)
|
prefs.setLastProfileUpdateTime(0)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.eventFlow.collect {
|
viewModel.events.collect {
|
||||||
loadingManager.load(it.mnemonic)
|
loadingManager.load(it.mnemonic)
|
||||||
startMessageNotificationsActivity()
|
startMessageNotificationsActivity()
|
||||||
finish()
|
finish()
|
||||||
@ -43,7 +45,7 @@ class LoadAccountActivity : BaseActionBarActivity() {
|
|||||||
|
|
||||||
setComposeContent {
|
setComposeContent {
|
||||||
val state by viewModel.stateFlow.collectAsState()
|
val state by viewModel.stateFlow.collectAsState()
|
||||||
LoadAccountScreen(state, viewModel.qrErrorsFlow, viewModel::onChange, viewModel::onContinue, viewModel::onScanQrCode)
|
LoadAccountScreen(state, viewModel.qrErrors, viewModel::onChange, viewModel::onContinue, viewModel::onScanQrCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,11 @@ import android.app.Application
|
|||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.mapNotNull
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
|
||||||
import kotlinx.coroutines.flow.take
|
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
@ -20,7 +19,7 @@ import org.session.libsignal.utilities.Hex
|
|||||||
import org.thoughtcrime.securesms.crypto.MnemonicUtilities
|
import org.thoughtcrime.securesms.crypto.MnemonicUtilities
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LinkDeviceEvent(val mnemonic: ByteArray)
|
class LoadAccountEvent(val mnemonic: ByteArray)
|
||||||
|
|
||||||
internal data class State(
|
internal data class State(
|
||||||
val recoveryPhrase: String = "",
|
val recoveryPhrase: String = "",
|
||||||
@ -34,12 +33,11 @@ internal class LinkDeviceViewModel @Inject constructor(
|
|||||||
private val state = MutableStateFlow(State())
|
private val state = MutableStateFlow(State())
|
||||||
val stateFlow = state.asStateFlow()
|
val stateFlow = state.asStateFlow()
|
||||||
|
|
||||||
private val event = Channel<LinkDeviceEvent>()
|
private val _events = MutableSharedFlow<LoadAccountEvent>()
|
||||||
val eventFlow = event.receiveAsFlow().take(1)
|
val events = _events.asSharedFlow()
|
||||||
|
|
||||||
private val qrErrors = Channel<Throwable>()
|
private val _qrErrors = MutableSharedFlow<Throwable>()
|
||||||
|
val qrErrors = _qrErrors.asSharedFlow()
|
||||||
val qrErrorsFlow = qrErrors.receiveAsFlow()
|
|
||||||
.mapNotNull { application.getString(R.string.qrNotRecoveryPassword) }
|
.mapNotNull { application.getString(R.string.qrNotRecoveryPassword) }
|
||||||
|
|
||||||
private val codec by lazy { MnemonicCodec { MnemonicUtilities.loadFileContents(getApplication(), it) } }
|
private val codec by lazy { MnemonicCodec { MnemonicUtilities.loadFileContents(getApplication(), it) } }
|
||||||
@ -64,7 +62,7 @@ internal class LinkDeviceViewModel @Inject constructor(
|
|||||||
state.value = State(recoveryPhrase)
|
state.value = State(recoveryPhrase)
|
||||||
}
|
}
|
||||||
private fun onSuccess(seed: ByteArray) {
|
private fun onSuccess(seed: ByteArray) {
|
||||||
viewModelScope.launch { event.send(LinkDeviceEvent(seed)) }
|
viewModelScope.launch { _events.emit(LoadAccountEvent(seed)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onFailure(error: Throwable) {
|
private fun onFailure(error: Throwable) {
|
||||||
@ -80,7 +78,7 @@ internal class LinkDeviceViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onQrCodeScanFailure(error: Throwable) {
|
private fun onQrCodeScanFailure(error: Throwable) {
|
||||||
viewModelScope.launch { qrErrors.send(error) }
|
viewModelScope.launch { _qrErrors.emit(error) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runDecodeCatching(mnemonic: String) = runCatching {
|
private fun runDecodeCatching(mnemonic: String) = runCatching {
|
||||||
|
@ -22,10 +22,10 @@ import javax.inject.Inject
|
|||||||
class LoadingActivity: BaseActionBarActivity() {
|
class LoadingActivity: BaseActionBarActivity() {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var configFactory: ConfigFactory
|
internal lateinit var configFactory: ConfigFactory
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var prefs: TextSecurePreferences
|
internal lateinit var prefs: TextSecurePreferences
|
||||||
|
|
||||||
private val viewModel: LoadingViewModel by viewModels()
|
private val viewModel: LoadingViewModel by viewModels()
|
||||||
|
|
||||||
@ -52,14 +52,14 @@ class LoadingActivity: BaseActionBarActivity() {
|
|||||||
ApplicationContext.getInstance(this).newAccount = false
|
ApplicationContext.getInstance(this).newAccount = false
|
||||||
|
|
||||||
setComposeContent {
|
setComposeContent {
|
||||||
val state by viewModel.stateFlow.collectAsState()
|
val state by viewModel.states.collectAsState()
|
||||||
LoadingScreen(state)
|
LoadingScreen(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
setUpActionBarSessionLogo(true)
|
setUpActionBarSessionLogo(true)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.eventFlow.collect {
|
viewModel.events.collect {
|
||||||
when (it) {
|
when (it) {
|
||||||
Event.TIMEOUT -> register(loadFailed = true)
|
Event.TIMEOUT -> register(loadFailed = true)
|
||||||
Event.SUCCESS -> register(loadFailed = false)
|
Event.SUCCESS -> register(loadFailed = false)
|
||||||
|
@ -17,12 +17,10 @@ import javax.inject.Singleton
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class LoadingManager @Inject constructor(
|
class LoadingManager @Inject constructor(
|
||||||
@dagger.hilt.android.qualifiers.ApplicationContext val context: Context,
|
@dagger.hilt.android.qualifiers.ApplicationContext private val context: Context,
|
||||||
val configFactory: ConfigFactory,
|
private val configFactory: ConfigFactory,
|
||||||
val prefs: TextSecurePreferences
|
private val prefs: TextSecurePreferences
|
||||||
) {
|
) {
|
||||||
val isLoading: Boolean get() = restoreJob?.isActive == true
|
|
||||||
|
|
||||||
private val database: LokiAPIDatabaseProtocol
|
private val database: LokiAPIDatabaseProtocol
|
||||||
get() = SnodeModule.shared.storage
|
get() = SnodeModule.shared.storage
|
||||||
|
|
||||||
|
@ -5,14 +5,14 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.channels.Channel
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
|
||||||
import kotlinx.coroutines.flow.timeout
|
import kotlinx.coroutines.flow.timeout
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
@ -29,15 +29,15 @@ private val TIMEOUT_TIME = 15.seconds
|
|||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class LoadingViewModel @Inject constructor(
|
internal class LoadingViewModel @Inject constructor(
|
||||||
val prefs: TextSecurePreferences
|
val prefs: TextSecurePreferences
|
||||||
): ViewModel() {
|
): ViewModel() {
|
||||||
|
|
||||||
private val state = MutableStateFlow(State(TIMEOUT_TIME))
|
private val _states = MutableStateFlow(State(TIMEOUT_TIME))
|
||||||
val stateFlow = state.asStateFlow()
|
val states = _states.asStateFlow()
|
||||||
|
|
||||||
private val event = Channel<Event>()
|
private val _events = MutableSharedFlow<Event>()
|
||||||
val eventFlow = event.receiveAsFlow()
|
val events = _events.asSharedFlow()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
@ -56,13 +56,13 @@ class LoadingViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onSuccess() {
|
private suspend fun onSuccess() {
|
||||||
state.value = State(ANIMATE_TO_DONE_TIME)
|
_states.value = State(ANIMATE_TO_DONE_TIME)
|
||||||
delay(IDLE_DONE_TIME)
|
delay(IDLE_DONE_TIME)
|
||||||
event.send(Event.SUCCESS)
|
_events.emit(Event.SUCCESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onFail() {
|
private fun onFail() {
|
||||||
event.trySend(Event.TIMEOUT)
|
_events.tryEmit(Event.TIMEOUT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,12 +39,12 @@ class MessageNotificationsActivity : BaseActionBarActivity() {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun MessageNotificationsScreen() {
|
private fun MessageNotificationsScreen() {
|
||||||
val state by viewModel.stateFlow.collectAsState()
|
val state by viewModel.states.collectAsState()
|
||||||
MessageNotificationsScreen(state, viewModel::setEnabled, ::register)
|
MessageNotificationsScreen(state, viewModel::setEnabled, ::register)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register() {
|
private fun register() {
|
||||||
prefs.setPushEnabled(viewModel.stateFlow.value.pushEnabled)
|
prefs.setPushEnabled(viewModel.states.value.pushEnabled)
|
||||||
ApplicationContext.getInstance(this).startPollingIfNeeded()
|
ApplicationContext.getInstance(this).startPollingIfNeeded()
|
||||||
pushRegistry.refresh(true)
|
pushRegistry.refresh(true)
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@ import kotlinx.coroutines.flow.update
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class MessageNotificationsViewModel @Inject constructor(): ViewModel() {
|
internal class MessageNotificationsViewModel @Inject constructor(): ViewModel() {
|
||||||
private val state = MutableStateFlow(MessageNotificationsState())
|
private val _states = MutableStateFlow(MessageNotificationsState())
|
||||||
val stateFlow = state.asStateFlow()
|
val states = _states.asStateFlow()
|
||||||
|
|
||||||
fun setEnabled(enabled: Boolean) {
|
fun setEnabled(enabled: Boolean) {
|
||||||
state.update { MessageNotificationsState(pushEnabled = enabled) }
|
_states.update { MessageNotificationsState(pushEnabled = enabled) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,10 @@ private const val EXTRA_LOAD_FAILED = "extra_load_failed"
|
|||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PickDisplayNameActivity : BaseActionBarActivity() {
|
class PickDisplayNameActivity : BaseActionBarActivity() {
|
||||||
|
|
||||||
@Inject lateinit var viewModelFactory: PickDisplayNameViewModel.AssistedFactory
|
@Inject
|
||||||
@Inject lateinit var prefs: TextSecurePreferences
|
internal lateinit var viewModelFactory: PickDisplayNameViewModel.AssistedFactory
|
||||||
|
@Inject
|
||||||
|
internal lateinit var prefs: TextSecurePreferences
|
||||||
|
|
||||||
private val loadFailed get() = intent.getBooleanExtra(EXTRA_LOAD_FAILED, false)
|
private val loadFailed get() = intent.getBooleanExtra(EXTRA_LOAD_FAILED, false)
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ class PickDisplayNameActivity : BaseActionBarActivity() {
|
|||||||
if (!loadFailed) prefs.setHasViewedSeed(false)
|
if (!loadFailed) prefs.setHasViewedSeed(false)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.eventFlow.collect {
|
viewModel.events.collect {
|
||||||
if (loadFailed) startHomeActivity() else startMessageNotificationsActivity()
|
if (loadFailed) startHomeActivity() else startMessageNotificationsActivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,7 +51,7 @@ class PickDisplayNameActivity : BaseActionBarActivity() {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DisplayNameScreen(viewModel: PickDisplayNameViewModel) {
|
private fun DisplayNameScreen(viewModel: PickDisplayNameViewModel) {
|
||||||
val state = viewModel.stateFlow.collectAsState()
|
val state = viewModel.states.collectAsState()
|
||||||
DisplayName(state.value, viewModel::onChange) { viewModel.onContinue(this) }
|
DisplayName(state.value, viewModel::onChange) { viewModel.onContinue(this) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,10 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
@ -23,28 +23,28 @@ import org.session.libsignal.utilities.hexEncodedPublicKey
|
|||||||
import org.thoughtcrime.securesms.crypto.KeyPairUtilities
|
import org.thoughtcrime.securesms.crypto.KeyPairUtilities
|
||||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
|
|
||||||
class PickDisplayNameViewModel(
|
internal class PickDisplayNameViewModel(
|
||||||
pickNewName: Boolean,
|
pickNewName: Boolean,
|
||||||
private val prefs: TextSecurePreferences,
|
private val prefs: TextSecurePreferences,
|
||||||
private val configFactory: ConfigFactory
|
private val configFactory: ConfigFactory
|
||||||
): ViewModel() {
|
): ViewModel() {
|
||||||
private val state = MutableStateFlow(if (pickNewName) pickNewNameState() else State())
|
private val _states = MutableStateFlow(if (pickNewName) pickNewNameState() else State())
|
||||||
val stateFlow = state.asStateFlow()
|
val states = _states.asStateFlow()
|
||||||
|
|
||||||
private val event = Channel<Event>()
|
private val _events = MutableSharedFlow<Event>()
|
||||||
val eventFlow = event.receiveAsFlow()
|
val events = _events.asSharedFlow()
|
||||||
|
|
||||||
private val database: LokiAPIDatabaseProtocol
|
private val database: LokiAPIDatabaseProtocol
|
||||||
get() = SnodeModule.shared.storage
|
get() = SnodeModule.shared.storage
|
||||||
|
|
||||||
fun onContinue(context: Context) {
|
fun onContinue(context: Context) {
|
||||||
state.update { it.copy(displayName = it.displayName.trim()) }
|
_states.update { it.copy(displayName = it.displayName.trim()) }
|
||||||
|
|
||||||
val displayName = state.value.displayName
|
val displayName = _states.value.displayName
|
||||||
|
|
||||||
when {
|
when {
|
||||||
displayName.isEmpty() -> { state.update { it.copy(error = R.string.displayNameErrorDescription) } }
|
displayName.isEmpty() -> { _states.update { it.copy(error = R.string.displayNameErrorDescription) } }
|
||||||
displayName.length > NAME_PADDED_LENGTH -> { state.update { it.copy(error = R.string.displayNameErrorDescriptionShorter) } }
|
displayName.length > NAME_PADDED_LENGTH -> { _states.update { it.copy(error = R.string.displayNameErrorDescriptionShorter) } }
|
||||||
else -> {
|
else -> {
|
||||||
prefs.setProfileName(displayName)
|
prefs.setProfileName(displayName)
|
||||||
|
|
||||||
@ -66,13 +66,13 @@ class PickDisplayNameViewModel(
|
|||||||
prefs.setLocalNumber(userHexEncodedPublicKey)
|
prefs.setLocalNumber(userHexEncodedPublicKey)
|
||||||
prefs.setRestorationTime(0)
|
prefs.setRestorationTime(0)
|
||||||
|
|
||||||
viewModelScope.launch { event.send(Event.DONE) }
|
viewModelScope.launch { _events.emit(Event.DONE) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onChange(value: String) {
|
fun onChange(value: String) {
|
||||||
state.update { state ->
|
_states.update { state ->
|
||||||
state.copy(
|
state.copy(
|
||||||
displayName = value,
|
displayName = value,
|
||||||
error = value.takeIf { it.length > NAME_PADDED_LENGTH }?.let { R.string.displayNameErrorDescriptionShorter }
|
error = value.takeIf { it.length > NAME_PADDED_LENGTH }?.let { R.string.displayNameErrorDescriptionShorter }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user