mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 18:15:22 +00:00
Start loading account while user chooses notifications
This commit is contained in:
parent
b18561acb4
commit
3e8701d10f
@ -264,7 +264,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
|||||||
|
|
||||||
// If the user account hasn't been created or onboarding wasn't finished then don't start
|
// If the user account hasn't been created or onboarding wasn't finished then don't start
|
||||||
// the pollers
|
// the pollers
|
||||||
if (TextSecurePreferences.getLocalNumber(this) == null || !TextSecurePreferences.hasSeenWelcomeScreen(this)) {
|
if (textSecurePreferences.getLocalNumber() == null || !textSecurePreferences.hasSeenWelcomeScreen()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import android.Manifest
|
|||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -789,3 +790,10 @@ private fun EmptyView(newAccount: Boolean) {
|
|||||||
Spacer(modifier = Modifier.weight(2f))
|
Spacer(modifier = Modifier.weight(2f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Context.startHomeActivity() {
|
||||||
|
Intent(this, HomeActivity::class.java).apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
putExtra(HomeActivity.FROM_ONBOARDING, true)
|
||||||
|
}.also(::startActivity)
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
@ -46,10 +47,9 @@ import org.thoughtcrime.securesms.onboarding.pickname.startPickDisplayNameActivi
|
|||||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||||
import org.thoughtcrime.securesms.showOpenUrlDialog
|
import org.thoughtcrime.securesms.showOpenUrlDialog
|
||||||
import org.thoughtcrime.securesms.ui.LocalDimensions
|
import org.thoughtcrime.securesms.ui.LocalDimensions
|
||||||
import org.thoughtcrime.securesms.ui.color.LocalColors
|
|
||||||
import org.thoughtcrime.securesms.ui.color.Colors
|
|
||||||
import org.thoughtcrime.securesms.ui.PreviewTheme
|
import org.thoughtcrime.securesms.ui.PreviewTheme
|
||||||
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
|
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
|
||||||
|
import org.thoughtcrime.securesms.ui.color.Colors
|
||||||
import org.thoughtcrime.securesms.ui.color.LocalColors
|
import org.thoughtcrime.securesms.ui.color.LocalColors
|
||||||
import org.thoughtcrime.securesms.ui.components.BorderlessHtmlButton
|
import org.thoughtcrime.securesms.ui.components.BorderlessHtmlButton
|
||||||
import org.thoughtcrime.securesms.ui.components.PrimaryFillButton
|
import org.thoughtcrime.securesms.ui.components.PrimaryFillButton
|
||||||
@ -60,21 +60,13 @@ import org.thoughtcrime.securesms.ui.large
|
|||||||
import org.thoughtcrime.securesms.ui.setComposeContent
|
import org.thoughtcrime.securesms.ui.setComposeContent
|
||||||
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
||||||
import org.thoughtcrime.securesms.util.start
|
import org.thoughtcrime.securesms.util.start
|
||||||
|
import javax.inject.Inject
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
private data class TextData(
|
@AndroidEntryPoint
|
||||||
@StringRes val stringId: Int,
|
class LandingActivity: BaseActionBarActivity() {
|
||||||
val isOutgoing: Boolean = false
|
|
||||||
)
|
|
||||||
|
|
||||||
private val MESSAGES = listOf(
|
@Inject lateinit var prefs: TextSecurePreferences
|
||||||
TextData(R.string.onboardingBubbleWelcomeToSession),
|
|
||||||
TextData(R.string.onboardingBubbleSessionIsEngineered, isOutgoing = true),
|
|
||||||
TextData(R.string.onboardingBubbleNoPhoneNumber),
|
|
||||||
TextData(R.string.onboardingBubbleCreatingAnAccountIsEasy, isOutgoing = true)
|
|
||||||
)
|
|
||||||
|
|
||||||
class LandingActivity : BaseActionBarActivity() {
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -85,7 +77,14 @@ class LandingActivity : BaseActionBarActivity() {
|
|||||||
|
|
||||||
setUpActionBarSessionLogo(true)
|
setUpActionBarSessionLogo(true)
|
||||||
|
|
||||||
setComposeContent { LandingScreen() }
|
setComposeContent {
|
||||||
|
LandingScreen(
|
||||||
|
createAccount = {
|
||||||
|
prefs.setHasViewedSeed(false)
|
||||||
|
startPickDisplayNameActivity()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
IdentityKeyUtil.generateIdentityKeyPair(this)
|
IdentityKeyUtil.generateIdentityKeyPair(this)
|
||||||
TextSecurePreferences.setPasswordDisabled(this, true)
|
TextSecurePreferences.setPasswordDisabled(this, true)
|
||||||
@ -99,12 +98,12 @@ class LandingActivity : BaseActionBarActivity() {
|
|||||||
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
|
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
|
||||||
) {
|
) {
|
||||||
PreviewTheme(colors) {
|
PreviewTheme(colors) {
|
||||||
LandingScreen()
|
LandingScreen {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun LandingScreen() {
|
private fun LandingScreen(createAccount: () -> Unit) {
|
||||||
var count by remember { mutableStateOf(0) }
|
var count by remember { mutableStateOf(0) }
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
@ -159,7 +158,7 @@ class LandingActivity : BaseActionBarActivity() {
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.align(Alignment.CenterHorizontally)
|
.align(Alignment.CenterHorizontally)
|
||||||
.contentDescription(R.string.AccessibilityId_create_account_button),
|
.contentDescription(R.string.AccessibilityId_create_account_button),
|
||||||
onClick = ::startPickDisplayNameActivity
|
onClick = createAccount
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(LocalDimensions.current.itemSpacingExtraSmall))
|
Spacer(modifier = Modifier.height(LocalDimensions.current.itemSpacingExtraSmall))
|
||||||
PrimaryOutlineButton(
|
PrimaryOutlineButton(
|
||||||
@ -252,3 +251,15 @@ private fun MessageText(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class TextData(
|
||||||
|
@StringRes val stringId: Int,
|
||||||
|
val isOutgoing: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
private val MESSAGES = listOf(
|
||||||
|
TextData(R.string.onboardingBubbleWelcomeToSession),
|
||||||
|
TextData(R.string.onboardingBubbleSessionIsEngineered, isOutgoing = true),
|
||||||
|
TextData(R.string.onboardingBubbleNoPhoneNumber),
|
||||||
|
TextData(R.string.onboardingBubbleCreatingAnAccountIsEasy, isOutgoing = true)
|
||||||
|
)
|
||||||
|
@ -30,7 +30,7 @@ import kotlinx.coroutines.launch
|
|||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
import org.thoughtcrime.securesms.onboarding.loading.startLoadingActivity
|
import org.thoughtcrime.securesms.onboarding.loading.LoadingManager
|
||||||
import org.thoughtcrime.securesms.onboarding.messagenotifications.startMessageNotificationsActivity
|
import org.thoughtcrime.securesms.onboarding.messagenotifications.startMessageNotificationsActivity
|
||||||
import org.thoughtcrime.securesms.ui.LocalDimensions
|
import org.thoughtcrime.securesms.ui.LocalDimensions
|
||||||
import org.thoughtcrime.securesms.ui.PreviewTheme
|
import org.thoughtcrime.securesms.ui.PreviewTheme
|
||||||
@ -52,8 +52,8 @@ private val TITLES = listOf(R.string.sessionRecoveryPassword, R.string.qrScan)
|
|||||||
@androidx.annotation.OptIn(ExperimentalGetImage::class)
|
@androidx.annotation.OptIn(ExperimentalGetImage::class)
|
||||||
class LinkDeviceActivity : BaseActionBarActivity() {
|
class LinkDeviceActivity : BaseActionBarActivity() {
|
||||||
|
|
||||||
@Inject
|
@Inject lateinit var prefs: TextSecurePreferences
|
||||||
lateinit var prefs: TextSecurePreferences
|
@Inject lateinit var loadingManager: LoadingManager
|
||||||
|
|
||||||
val viewModel: LinkDeviceViewModel by viewModels()
|
val viewModel: LinkDeviceViewModel by viewModels()
|
||||||
|
|
||||||
@ -67,8 +67,8 @@ class LinkDeviceActivity : BaseActionBarActivity() {
|
|||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.eventFlow.collect {
|
viewModel.eventFlow.collect {
|
||||||
|
loadingManager.load(it.mnemonic)
|
||||||
startMessageNotificationsActivity()
|
startMessageNotificationsActivity()
|
||||||
startLoadingActivity(it.mnemonic)
|
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.thoughtcrime.securesms.onboarding.loading
|
package org.thoughtcrime.securesms.onboarding.loading
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
@ -13,14 +12,12 @@ import org.session.libsession.utilities.TextSecurePreferences
|
|||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
import org.thoughtcrime.securesms.onboarding.messagenotifications.startMessageNotificationsActivity
|
import org.thoughtcrime.securesms.home.startHomeActivity
|
||||||
import org.thoughtcrime.securesms.onboarding.pickname.startPickDisplayNameActivity
|
import org.thoughtcrime.securesms.onboarding.pickname.startPickDisplayNameActivity
|
||||||
import org.thoughtcrime.securesms.ui.setComposeContent
|
import org.thoughtcrime.securesms.ui.setComposeContent
|
||||||
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private const val EXTRA_MNEMONIC = "mnemonic"
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class LoadingActivity: BaseActionBarActivity() {
|
class LoadingActivity: BaseActionBarActivity() {
|
||||||
|
|
||||||
@ -40,11 +37,12 @@ class LoadingActivity: BaseActionBarActivity() {
|
|||||||
private fun register(skipped: Boolean) {
|
private fun register(skipped: Boolean) {
|
||||||
prefs.setLastConfigurationSyncTime(System.currentTimeMillis())
|
prefs.setLastConfigurationSyncTime(System.currentTimeMillis())
|
||||||
|
|
||||||
val flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
|
||||||
|
|
||||||
when {
|
when {
|
||||||
skipped -> startPickDisplayNameActivity(true, flags)
|
skipped -> startPickDisplayNameActivity(
|
||||||
else -> startMessageNotificationsActivity(flags)
|
failedToLoad = true,
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
)
|
||||||
|
else -> startHomeActivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,8 +58,6 @@ class LoadingActivity: BaseActionBarActivity() {
|
|||||||
|
|
||||||
setUpActionBarSessionLogo(true)
|
setUpActionBarSessionLogo(true)
|
||||||
|
|
||||||
viewModel.restore(application, intent.getByteArrayExtra(EXTRA_MNEMONIC)!!)
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.eventFlow.collect {
|
viewModel.eventFlow.collect {
|
||||||
when (it) {
|
when (it) {
|
||||||
@ -72,9 +68,3 @@ class LoadingActivity: BaseActionBarActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.startLoadingActivity(mnemonic: ByteArray) {
|
|
||||||
Intent(this, LoadingActivity::class.java)
|
|
||||||
.apply { putExtra(EXTRA_MNEMONIC, mnemonic) }
|
|
||||||
.also(::startActivity)
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
package org.thoughtcrime.securesms.onboarding.loading
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.session.libsession.snode.SnodeModule
|
||||||
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsignal.database.LokiAPIDatabaseProtocol
|
||||||
|
import org.session.libsignal.utilities.hexEncodedPublicKey
|
||||||
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class LoadingManager @Inject constructor(
|
||||||
|
@dagger.hilt.android.qualifiers.ApplicationContext val context: Context,
|
||||||
|
val configFactory: ConfigFactory,
|
||||||
|
val prefs: TextSecurePreferences
|
||||||
|
) {
|
||||||
|
val isLoading: Boolean get() = restoreJob?.isActive == true
|
||||||
|
|
||||||
|
private val database: LokiAPIDatabaseProtocol
|
||||||
|
get() = SnodeModule.shared.storage
|
||||||
|
|
||||||
|
private var restoreJob: Job? = null
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
|
|
||||||
|
fun load(seed: ByteArray) {
|
||||||
|
// only have one sync job running at a time (prevent QR from trying to spawn a new job)
|
||||||
|
if (restoreJob?.isActive == true) return
|
||||||
|
|
||||||
|
restoreJob = scope.launch {
|
||||||
|
// This is here to resolve a case where the app restarts before a user completes onboarding
|
||||||
|
// which can result in an invalid database state
|
||||||
|
database.clearAllLastMessageHashes()
|
||||||
|
database.clearReceivedMessageHashValues()
|
||||||
|
|
||||||
|
// RestoreActivity handles seed this way
|
||||||
|
val keyPairGenerationResult = org.thoughtcrime.securesms.crypto.KeyPairUtilities.generate(seed)
|
||||||
|
val x25519KeyPair = keyPairGenerationResult.x25519KeyPair
|
||||||
|
org.thoughtcrime.securesms.crypto.KeyPairUtilities.store(context, seed, keyPairGenerationResult.ed25519KeyPair, x25519KeyPair)
|
||||||
|
configFactory.keyPairChanged()
|
||||||
|
val userHexEncodedPublicKey = x25519KeyPair.hexEncodedPublicKey
|
||||||
|
val registrationID = org.session.libsignal.utilities.KeyHelper.generateRegistrationId(false)
|
||||||
|
prefs.apply {
|
||||||
|
setLocalRegistrationId(registrationID)
|
||||||
|
setLocalNumber(userHexEncodedPublicKey)
|
||||||
|
setRestorationTime(System.currentTimeMillis())
|
||||||
|
setHasViewedSeed(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationContext.getInstance(context).apply { startPollingIfNeeded() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,21 @@
|
|||||||
package org.thoughtcrime.securesms.onboarding.loading
|
package org.thoughtcrime.securesms.onboarding.loading
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
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.Job
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
|
import kotlinx.coroutines.flow.timeout
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.session.libsession.snode.SnodeModule
|
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsignal.database.LokiAPIDatabaseProtocol
|
|
||||||
import org.session.libsignal.utilities.KeyHelper
|
|
||||||
import org.session.libsignal.utilities.hexEncodedPublicKey
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
|
||||||
import org.thoughtcrime.securesms.crypto.KeyPairUtilities
|
|
||||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
@ -31,67 +26,44 @@ data class State(val duration: Duration)
|
|||||||
private val ANIMATE_TO_DONE_TIME = 500.milliseconds
|
private val ANIMATE_TO_DONE_TIME = 500.milliseconds
|
||||||
private val IDLE_DONE_TIME = 1.seconds
|
private val IDLE_DONE_TIME = 1.seconds
|
||||||
private val TIMEOUT_TIME = 15.seconds
|
private val TIMEOUT_TIME = 15.seconds
|
||||||
private val TOTAL_ANIMATION_TIME = TIMEOUT_TIME - IDLE_DONE_TIME
|
|
||||||
|
|
||||||
|
@OptIn(FlowPreview::class)
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class LoadingViewModel @Inject constructor(
|
class LoadingViewModel @Inject constructor(
|
||||||
private val configFactory: ConfigFactory,
|
val prefs: TextSecurePreferences
|
||||||
private val prefs: TextSecurePreferences,
|
): ViewModel() {
|
||||||
) : ViewModel() {
|
|
||||||
|
|
||||||
private val state = MutableStateFlow(State(TOTAL_ANIMATION_TIME))
|
private val state = MutableStateFlow(State(TIMEOUT_TIME))
|
||||||
val stateFlow = state.asStateFlow()
|
val stateFlow = state.asStateFlow()
|
||||||
|
|
||||||
private val event = Channel<Event>()
|
private val event = Channel<Event>()
|
||||||
val eventFlow = event.receiveAsFlow()
|
val eventFlow = event.receiveAsFlow()
|
||||||
|
|
||||||
private var restoreJob: Job? = null
|
init {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
internal val database: LokiAPIDatabaseProtocol
|
try {
|
||||||
get() = SnodeModule.shared.storage
|
TextSecurePreferences.events
|
||||||
|
.filter { it == TextSecurePreferences.CONFIGURATION_SYNCED }
|
||||||
fun restore(context: Context, seed: ByteArray) {
|
.timeout(TIMEOUT_TIME)
|
||||||
|
.onStart { emit(TextSecurePreferences.CONFIGURATION_SYNCED) }
|
||||||
// only have one sync job running at a time (prevent QR from trying to spawn a new job)
|
.collectLatest {
|
||||||
if (restoreJob?.isActive == true) return
|
if (prefs.getConfigurationMessageSynced()) onSuccess()
|
||||||
|
}
|
||||||
restoreJob = viewModelScope.launch(Dispatchers.IO) {
|
} catch (e: Exception) {
|
||||||
// This is here to resolve a case where the app restarts before a user completes onboarding
|
onFail()
|
||||||
// which can result in an invalid database state
|
|
||||||
database.clearAllLastMessageHashes()
|
|
||||||
database.clearReceivedMessageHashValues()
|
|
||||||
|
|
||||||
// RestoreActivity handles seed this way
|
|
||||||
val keyPairGenerationResult = KeyPairUtilities.generate(seed)
|
|
||||||
val x25519KeyPair = keyPairGenerationResult.x25519KeyPair
|
|
||||||
KeyPairUtilities.store(context, seed, keyPairGenerationResult.ed25519KeyPair, x25519KeyPair)
|
|
||||||
configFactory.keyPairChanged()
|
|
||||||
val userHexEncodedPublicKey = x25519KeyPair.hexEncodedPublicKey
|
|
||||||
val registrationID = KeyHelper.generateRegistrationId(false)
|
|
||||||
prefs.apply {
|
|
||||||
setLocalRegistrationId(registrationID)
|
|
||||||
setLocalNumber(userHexEncodedPublicKey)
|
|
||||||
setRestorationTime(System.currentTimeMillis())
|
|
||||||
setHasViewedSeed(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
val skipJob = launch(Dispatchers.IO) {
|
|
||||||
delay(TIMEOUT_TIME)
|
|
||||||
event.send(Event.TIMEOUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
// start polling and wait for updated message
|
|
||||||
ApplicationContext.getInstance(context).apply { startPollingIfNeeded() }
|
|
||||||
TextSecurePreferences.events.filter { it == TextSecurePreferences.CONFIGURATION_SYNCED }.collect {
|
|
||||||
// handle we've synced
|
|
||||||
skipJob.cancel()
|
|
||||||
|
|
||||||
state.value = State(ANIMATE_TO_DONE_TIME)
|
|
||||||
delay(IDLE_DONE_TIME)
|
|
||||||
event.send(Event.SUCCESS)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun onSuccess() {
|
||||||
|
state.value = State(ANIMATE_TO_DONE_TIME)
|
||||||
|
delay(IDLE_DONE_TIME)
|
||||||
|
event.send(Event.SUCCESS)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onFail() {
|
||||||
|
event.trySend(Event.TIMEOUT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface Event {
|
sealed interface Event {
|
||||||
|
@ -12,22 +12,28 @@ import org.session.libsession.utilities.TextSecurePreferences
|
|||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
import org.thoughtcrime.securesms.home.HomeActivity
|
import org.thoughtcrime.securesms.home.HomeActivity
|
||||||
|
import org.thoughtcrime.securesms.home.startHomeActivity
|
||||||
import org.thoughtcrime.securesms.notifications.PushRegistry
|
import org.thoughtcrime.securesms.notifications.PushRegistry
|
||||||
|
import org.thoughtcrime.securesms.onboarding.loading.LoadingActivity
|
||||||
|
import org.thoughtcrime.securesms.onboarding.loading.LoadingManager
|
||||||
import org.thoughtcrime.securesms.ui.setComposeContent
|
import org.thoughtcrime.securesms.ui.setComposeContent
|
||||||
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
||||||
|
import org.thoughtcrime.securesms.util.start
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MessageNotificationsActivity : BaseActionBarActivity() {
|
class MessageNotificationsActivity : BaseActionBarActivity() {
|
||||||
|
|
||||||
@Inject lateinit var pushRegistry: PushRegistry
|
@Inject lateinit var pushRegistry: PushRegistry
|
||||||
|
@Inject lateinit var prefs: TextSecurePreferences
|
||||||
|
@Inject lateinit var loadingManager: LoadingManager
|
||||||
|
|
||||||
private val viewModel: MessageNotificationsViewModel by viewModels()
|
private val viewModel: MessageNotificationsViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setUpActionBarSessionLogo(true)
|
setUpActionBarSessionLogo(true)
|
||||||
TextSecurePreferences.setHasSeenWelcomeScreen(this, true)
|
prefs.setHasSeenWelcomeScreen(true)
|
||||||
|
|
||||||
setComposeContent { MessageNotificationsScreen() }
|
setComposeContent { MessageNotificationsScreen() }
|
||||||
}
|
}
|
||||||
@ -39,13 +45,15 @@ class MessageNotificationsActivity : BaseActionBarActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun register() {
|
private fun register() {
|
||||||
TextSecurePreferences.setPushEnabled(this, viewModel.stateFlow.value.pushEnabled)
|
prefs.setPushEnabled(viewModel.stateFlow.value.pushEnabled)
|
||||||
ApplicationContext.getInstance(this).startPollingIfNeeded()
|
ApplicationContext.getInstance(this).startPollingIfNeeded()
|
||||||
pushRegistry.refresh(true)
|
pushRegistry.refresh(true)
|
||||||
Intent(this, HomeActivity::class.java).apply {
|
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
when {
|
||||||
putExtra(HomeActivity.FROM_ONBOARDING, true)
|
prefs.getHasViewedSeed() && !prefs.getConfigurationMessageSynced() -> start<LoadingActivity>()
|
||||||
}.also(::startActivity)
|
prefs.getProfileName() != null -> startHomeActivity()
|
||||||
|
else -> startHomeActivity()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,8 +22,10 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
|
import org.thoughtcrime.securesms.home.startHomeActivity
|
||||||
import org.thoughtcrime.securesms.onboarding.messagenotifications.startMessageNotificationsActivity
|
import org.thoughtcrime.securesms.onboarding.messagenotifications.startMessageNotificationsActivity
|
||||||
import org.thoughtcrime.securesms.ui.PreviewTheme
|
import org.thoughtcrime.securesms.ui.PreviewTheme
|
||||||
import org.thoughtcrime.securesms.ui.base
|
import org.thoughtcrime.securesms.ui.base
|
||||||
@ -35,17 +37,18 @@ import org.thoughtcrime.securesms.ui.setComposeContent
|
|||||||
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private const val EXTRA_PICK_NEW_NAME = "extra_pick_new_name"
|
private const val EXTRA_FAILED_TO_LOAD = "extra_failed_to_load"
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PickDisplayNameActivity : BaseActionBarActivity() {
|
class PickDisplayNameActivity : BaseActionBarActivity() {
|
||||||
|
|
||||||
@Inject
|
@Inject lateinit var viewModelFactory: PickDisplayNameViewModel.AssistedFactory
|
||||||
lateinit var viewModelFactory: PickDisplayNameViewModel.AssistedFactory
|
@Inject lateinit var prefs: TextSecurePreferences
|
||||||
|
|
||||||
|
val failedToLoad get() = intent.getBooleanExtra(EXTRA_FAILED_TO_LOAD, false)
|
||||||
|
|
||||||
private val viewModel: PickDisplayNameViewModel by viewModels {
|
private val viewModel: PickDisplayNameViewModel by viewModels {
|
||||||
val pickNewName = intent.getBooleanExtra(EXTRA_PICK_NEW_NAME, false)
|
viewModelFactory.create(failedToLoad)
|
||||||
viewModelFactory.create(pickNewName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -54,9 +57,11 @@ class PickDisplayNameActivity : BaseActionBarActivity() {
|
|||||||
|
|
||||||
setComposeContent { DisplayNameScreen(viewModel) }
|
setComposeContent { DisplayNameScreen(viewModel) }
|
||||||
|
|
||||||
|
if (!failedToLoad) prefs.setHasViewedSeed(false)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.eventFlow.collect {
|
viewModel.eventFlow.collect {
|
||||||
startMessageNotificationsActivity()
|
if (failedToLoad) startHomeActivity() else startMessageNotificationsActivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +124,7 @@ fun Context.startPickDisplayNameActivity(failedToLoad: Boolean = false, flags: I
|
|||||||
ApplicationContext.getInstance(this).newAccount = !failedToLoad
|
ApplicationContext.getInstance(this).newAccount = !failedToLoad
|
||||||
|
|
||||||
Intent(this, PickDisplayNameActivity::class.java)
|
Intent(this, PickDisplayNameActivity::class.java)
|
||||||
.apply { putExtra(EXTRA_PICK_NEW_NAME, failedToLoad) }
|
.apply { putExtra(EXTRA_FAILED_TO_LOAD, failedToLoad) }
|
||||||
.also { it.flags = flags }
|
.also { it.flags = flags }
|
||||||
.also(::startActivity)
|
.also(::startActivity)
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,6 @@ class PickDisplayNameViewModel(
|
|||||||
prefs.setLocalRegistrationId(registrationID)
|
prefs.setLocalRegistrationId(registrationID)
|
||||||
prefs.setLocalNumber(userHexEncodedPublicKey)
|
prefs.setLocalNumber(userHexEncodedPublicKey)
|
||||||
prefs.setRestorationTime(0)
|
prefs.setRestorationTime(0)
|
||||||
prefs.setHasViewedSeed(false)
|
|
||||||
|
|
||||||
viewModelScope.launch { event.send(Event.DONE) }
|
viewModelScope.launch { event.send(Event.DONE) }
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,185 @@
|
|||||||
|
package org.thoughtcrime.securesms.onboarding.recoverypassword
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import network.loki.messenger.R
|
||||||
|
import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
|
||||||
|
import org.thoughtcrime.securesms.ui.LocalDimensions
|
||||||
|
import org.thoughtcrime.securesms.ui.PreviewTheme
|
||||||
|
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
|
||||||
|
import org.thoughtcrime.securesms.ui.SessionShieldIcon
|
||||||
|
import org.thoughtcrime.securesms.ui.base
|
||||||
|
import org.thoughtcrime.securesms.ui.color.Colors
|
||||||
|
import org.thoughtcrime.securesms.ui.color.LocalColors
|
||||||
|
import org.thoughtcrime.securesms.ui.components.QrImage
|
||||||
|
import org.thoughtcrime.securesms.ui.components.SlimOutlineButton
|
||||||
|
import org.thoughtcrime.securesms.ui.components.SlimOutlineCopyButton
|
||||||
|
import org.thoughtcrime.securesms.ui.contentDescription
|
||||||
|
import org.thoughtcrime.securesms.ui.extraSmallMonospace
|
||||||
|
import org.thoughtcrime.securesms.ui.h8
|
||||||
|
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewRecoveryPasswordScreen(
|
||||||
|
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
|
||||||
|
) {
|
||||||
|
PreviewTheme(colors) {
|
||||||
|
RecoveryPasswordScreen(seed = "Voyage urban toyed maverick peculiar tuxedo penguin tree grass building listen speak withdraw terminal plane")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RecoveryPasswordScreen(
|
||||||
|
seed: String = "",
|
||||||
|
copySeed:() -> Unit = {},
|
||||||
|
onHide:() -> Unit = {}
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.marginExtraSmall),
|
||||||
|
modifier = Modifier
|
||||||
|
.contentDescription(R.string.AccessibilityId_recovery_password)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(bottom = LocalDimensions.current.marginExtraSmall)
|
||||||
|
) {
|
||||||
|
RecoveryPasswordCell(seed, copySeed)
|
||||||
|
HideRecoveryPasswordCell(onHide)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RecoveryPasswordCell(seed: String, copySeed:() -> Unit = {}) {
|
||||||
|
var showQr by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
CellWithPaddingAndMargin {
|
||||||
|
Column {
|
||||||
|
Row {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.sessionRecoveryPassword),
|
||||||
|
style = h8
|
||||||
|
)
|
||||||
|
Spacer(Modifier.width(LocalDimensions.current.itemSpacingExtraSmall))
|
||||||
|
SessionShieldIcon()
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(LocalDimensions.current.marginTiny))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.recoveryPasswordDescription),
|
||||||
|
style = base
|
||||||
|
)
|
||||||
|
|
||||||
|
AnimatedVisibility(!showQr) {
|
||||||
|
RecoveryPassword(seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedVisibility(
|
||||||
|
showQr,
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
|
) {
|
||||||
|
QrImage(
|
||||||
|
seed,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = LocalDimensions.current.marginSmall)
|
||||||
|
.contentDescription(R.string.AccessibilityId_qr_code),
|
||||||
|
icon = R.drawable.session_shield
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedVisibility(!showQr) {
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.marginMedium)) {
|
||||||
|
SlimOutlineCopyButton(
|
||||||
|
Modifier.weight(1f),
|
||||||
|
onClick = copySeed
|
||||||
|
)
|
||||||
|
SlimOutlineButton(
|
||||||
|
stringResource(R.string.qrView),
|
||||||
|
Modifier.weight(1f),
|
||||||
|
) { showQr = !showQr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedVisibility(showQr, modifier = Modifier.align(Alignment.CenterHorizontally)) {
|
||||||
|
SlimOutlineButton(
|
||||||
|
stringResource(R.string.recoveryPasswordView),
|
||||||
|
onClick = { showQr = !showQr }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RecoveryPassword(seed: String) {
|
||||||
|
Text(
|
||||||
|
seed,
|
||||||
|
modifier = Modifier
|
||||||
|
.contentDescription(R.string.AccessibilityId_recovery_password_container)
|
||||||
|
.padding(vertical = LocalDimensions.current.marginSmall)
|
||||||
|
.border(
|
||||||
|
width = 1.dp,
|
||||||
|
color = LocalColors.current.borders,
|
||||||
|
shape = RoundedCornerShape(11.dp)
|
||||||
|
)
|
||||||
|
.padding(LocalDimensions.current.marginSmall),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = extraSmallMonospace,
|
||||||
|
color = LocalColors.current.run { if (isLight) text else primary },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun HideRecoveryPasswordCell(onHide: () -> Unit = {}) {
|
||||||
|
CellWithPaddingAndMargin {
|
||||||
|
Row {
|
||||||
|
Column(
|
||||||
|
Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.recoveryPasswordHideRecoveryPassword),
|
||||||
|
style = h8
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.recoveryPasswordHideRecoveryPasswordDescription),
|
||||||
|
style = base
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(LocalDimensions.current.marginExtraExtraSmall))
|
||||||
|
SlimOutlineButton(
|
||||||
|
text = stringResource(R.string.hide),
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentWidth()
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
|
.contentDescription(R.string.AccessibilityId_hide_recovery_password_button),
|
||||||
|
color = LocalColors.current.danger,
|
||||||
|
onClick = onHide
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,49 +2,9 @@ package org.thoughtcrime.securesms.onboarding.recoverypassword
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.foundation.border
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.layout.wrapContentWidth
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||||
import org.thoughtcrime.securesms.showSessionDialog
|
import org.thoughtcrime.securesms.showSessionDialog
|
||||||
import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
|
|
||||||
import org.thoughtcrime.securesms.ui.LocalDimensions
|
|
||||||
import org.thoughtcrime.securesms.ui.color.LocalColors
|
|
||||||
import org.thoughtcrime.securesms.ui.color.Colors
|
|
||||||
import org.thoughtcrime.securesms.ui.PreviewTheme
|
|
||||||
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
|
|
||||||
import org.thoughtcrime.securesms.ui.SessionShieldIcon
|
|
||||||
import org.thoughtcrime.securesms.ui.base
|
|
||||||
import org.thoughtcrime.securesms.ui.components.QrImage
|
|
||||||
import org.thoughtcrime.securesms.ui.components.SlimOutlineButton
|
|
||||||
import org.thoughtcrime.securesms.ui.components.SlimOutlineCopyButton
|
|
||||||
import org.thoughtcrime.securesms.ui.contentDescription
|
|
||||||
import org.thoughtcrime.securesms.ui.extraSmallMonospace
|
|
||||||
import org.thoughtcrime.securesms.ui.h8
|
|
||||||
import org.thoughtcrime.securesms.ui.setComposeContent
|
import org.thoughtcrime.securesms.ui.setComposeContent
|
||||||
|
|
||||||
class RecoveryPasswordActivity : BaseActionBarActivity() {
|
class RecoveryPasswordActivity : BaseActionBarActivity() {
|
||||||
@ -87,144 +47,3 @@ class RecoveryPasswordActivity : BaseActionBarActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun PreviewRecoveryPasswordScreen(
|
|
||||||
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
|
|
||||||
) {
|
|
||||||
PreviewTheme(colors) {
|
|
||||||
RecoveryPasswordScreen(seed = "Voyage urban toyed maverick peculiar tuxedo penguin tree grass building listen speak withdraw terminal plane")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun RecoveryPasswordScreen(
|
|
||||||
seed: String = "",
|
|
||||||
copySeed:() -> Unit = {},
|
|
||||||
onHide:() -> Unit = {}
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.marginExtraSmall),
|
|
||||||
modifier = Modifier
|
|
||||||
.contentDescription(R.string.AccessibilityId_recovery_password)
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
.padding(bottom = LocalDimensions.current.marginExtraSmall)
|
|
||||||
) {
|
|
||||||
RecoveryPasswordCell(seed, copySeed)
|
|
||||||
HideRecoveryPasswordCell(onHide)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun RecoveryPasswordCell(seed: String, copySeed:() -> Unit = {}) {
|
|
||||||
var showQr by remember {
|
|
||||||
mutableStateOf(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
CellWithPaddingAndMargin {
|
|
||||||
Column {
|
|
||||||
Row {
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.sessionRecoveryPassword),
|
|
||||||
style = h8
|
|
||||||
)
|
|
||||||
Spacer(Modifier.width(LocalDimensions.current.itemSpacingExtraSmall))
|
|
||||||
SessionShieldIcon()
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(LocalDimensions.current.marginTiny))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.recoveryPasswordDescription),
|
|
||||||
style = base
|
|
||||||
)
|
|
||||||
|
|
||||||
AnimatedVisibility(!showQr) {
|
|
||||||
RecoveryPassword(seed)
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(
|
|
||||||
showQr,
|
|
||||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
|
||||||
) {
|
|
||||||
QrImage(
|
|
||||||
seed,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(vertical = LocalDimensions.current.marginSmall)
|
|
||||||
.contentDescription(R.string.AccessibilityId_qr_code),
|
|
||||||
icon = R.drawable.session_shield
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(!showQr) {
|
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.marginMedium)) {
|
|
||||||
SlimOutlineCopyButton(
|
|
||||||
Modifier.weight(1f),
|
|
||||||
onClick = copySeed
|
|
||||||
)
|
|
||||||
SlimOutlineButton(
|
|
||||||
stringResource(R.string.qrView),
|
|
||||||
Modifier.weight(1f),
|
|
||||||
) { showQr = !showQr }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(showQr, modifier = Modifier.align(Alignment.CenterHorizontally)) {
|
|
||||||
SlimOutlineButton(
|
|
||||||
stringResource(R.string.recoveryPasswordView),
|
|
||||||
onClick = { showQr = !showQr }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun RecoveryPassword(seed: String) {
|
|
||||||
Text(
|
|
||||||
seed,
|
|
||||||
modifier = Modifier
|
|
||||||
.contentDescription(R.string.AccessibilityId_recovery_password_container)
|
|
||||||
.padding(vertical = LocalDimensions.current.marginSmall)
|
|
||||||
.border(
|
|
||||||
width = 1.dp,
|
|
||||||
color = LocalColors.current.borders,
|
|
||||||
shape = RoundedCornerShape(11.dp)
|
|
||||||
)
|
|
||||||
.padding(LocalDimensions.current.marginSmall),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
style = extraSmallMonospace,
|
|
||||||
color = LocalColors.current.run { if (isLight) text else primary },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun HideRecoveryPasswordCell(onHide: () -> Unit = {}) {
|
|
||||||
CellWithPaddingAndMargin {
|
|
||||||
Row {
|
|
||||||
Column(
|
|
||||||
Modifier.weight(1f)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.recoveryPasswordHideRecoveryPassword),
|
|
||||||
style = h8
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.recoveryPasswordHideRecoveryPasswordDescription),
|
|
||||||
style = base
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.width(LocalDimensions.current.marginExtraExtraSmall))
|
|
||||||
SlimOutlineButton(
|
|
||||||
text = stringResource(R.string.hide),
|
|
||||||
modifier = Modifier
|
|
||||||
.wrapContentWidth()
|
|
||||||
.align(Alignment.CenterVertically)
|
|
||||||
.contentDescription(R.string.AccessibilityId_hide_recovery_password_button),
|
|
||||||
color = LocalColors.current.danger,
|
|
||||||
onClick = onHide
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -19,10 +19,10 @@ import org.session.libsession.utilities.TextSecurePreferences.Companion.YELLOW_A
|
|||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun TextSecurePreferences.colors(): Colors = lightDarkColors().colors()
|
fun TextSecurePreferences.colors(): Colors = lightDarkColors().colors()
|
||||||
fun TextSecurePreferences.lightDarkColors() = LightDarkColors(isClassic(), isLight(), getFollowSystemSettings(), primaryColor())
|
private fun TextSecurePreferences.lightDarkColors() = LightDarkColors(isClassic(), isLight(), getFollowSystemSettings(), primaryColor())
|
||||||
fun TextSecurePreferences.isLight(): Boolean = getThemeStyle() in setOf(CLASSIC_LIGHT, OCEAN_LIGHT)
|
private fun TextSecurePreferences.isLight(): Boolean = getThemeStyle() in setOf(CLASSIC_LIGHT, OCEAN_LIGHT)
|
||||||
fun TextSecurePreferences.isClassic(): Boolean = getThemeStyle() in setOf(CLASSIC_DARK, CLASSIC_LIGHT)
|
private fun TextSecurePreferences.isClassic(): Boolean = getThemeStyle() in setOf(CLASSIC_DARK, CLASSIC_LIGHT)
|
||||||
fun TextSecurePreferences.primaryColor(): Color = when(getSelectedAccentColor()) {
|
private fun TextSecurePreferences.primaryColor(): Color = when(getSelectedAccentColor()) {
|
||||||
GREEN_ACCENT -> primaryGreen
|
GREEN_ACCENT -> primaryGreen
|
||||||
BLUE_ACCENT -> primaryBlue
|
BLUE_ACCENT -> primaryBlue
|
||||||
PURPLE_ACCENT -> primaryPurple
|
PURPLE_ACCENT -> primaryPurple
|
||||||
|
Loading…
Reference in New Issue
Block a user