Feature/calls kee updates (#1007)

* SES-3469 Fixing shortcut activity

* Reduce the time shown from 00:00:00 to 00:00 expand as needed when call exceeds the time which can be shown in 00:00

* Moved the voice setting to the top of the privacy page, and allowed for auto toggle of settings

* Disabling the switch camera butotn when not in video

* Moving logic into VM and adding step counter

* comments

* PR feedback - not exposing a mutable set
pull/1710/head
ThomasSession 4 weeks ago committed by GitHub
parent 0445ebeb57
commit 01c3003b36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,54 +0,0 @@
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.TaskStackBuilder;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Toast;
import org.session.libsession.utilities.Address;
import org.thoughtcrime.securesms.home.HomeActivity;
import org.session.libsession.utilities.recipients.Recipient;
import org.thoughtcrime.securesms.util.CommunicationActions;
import network.loki.messenger.R;
public class ShortcutLauncherActivity extends AppCompatActivity {
private static final String KEY_SERIALIZED_ADDRESS = "serialized_address";
public static Intent createIntent(@NonNull Context context, @NonNull Address address) {
Intent intent = new Intent(context, ShortcutLauncherActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.putExtra(KEY_SERIALIZED_ADDRESS, address.toString());
return intent;
}
@SuppressLint("StaticFieldLeak")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String serializedAddress = getIntent().getStringExtra(KEY_SERIALIZED_ADDRESS);
if (serializedAddress == null) {
Toast.makeText(this, R.string.invalidShortcut, Toast.LENGTH_SHORT).show();
startActivity(new Intent(this, HomeActivity.class));
finish();
return;
}
Address address = Address.fromSerialized(serializedAddress);
Recipient recipient = Recipient.from(this, address, true);
TaskStackBuilder backStack = TaskStackBuilder.create(this)
.addNextIntent(new Intent(this, HomeActivity.class));
CommunicationActions.startConversation(this, recipient, null, backStack);
finish();
}
}

@ -0,0 +1,68 @@
package org.thoughtcrime.securesms
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.TaskStackBuilder
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.home.HomeActivity
import org.thoughtcrime.securesms.util.CommunicationActions
class ShortcutLauncherActivity : AppCompatActivity() {
@SuppressLint("StaticFieldLeak")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val serializedAddress = intent.getStringExtra(KEY_SERIALIZED_ADDRESS)
if (serializedAddress == null) {
Toast.makeText(this, R.string.invalidShortcut, Toast.LENGTH_SHORT).show()
startActivity(Intent(this, HomeActivity::class.java))
finish()
return
}
val backStack = TaskStackBuilder.create(this)
.addNextIntent(Intent(this, HomeActivity::class.java))
// start the appropriate conversation activity and finish this one
lifecycleScope.launch(Dispatchers.Default) {
val context = this@ShortcutLauncherActivity
val address = fromSerialized(serializedAddress)
val recipient = Recipient.from(context, address, true)
val threadId = DatabaseComponent.get(context).threadDatabase().getOrCreateThreadIdFor(recipient)
val intent = Intent(context, ConversationActivityV2::class.java)
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
intent.putExtra(ConversationActivityV2.THREAD_ID, threadId)
backStack.addNextIntent(intent)
backStack.startActivities()
finish()
}
}
companion object {
private const val KEY_SERIALIZED_ADDRESS = "serialized_address"
fun createIntent(context: Context, address: Address): Intent {
val intent = Intent(context, ShortcutLauncherActivity::class.java)
intent.setAction(Intent.ACTION_MAIN)
intent.putExtra(KEY_SERIALIZED_ADDRESS, address.toString())
return intent
}
}
}

@ -240,7 +240,7 @@ object ConversationMenuHelper {
button(R.string.sessionSettings, R.string.AccessibilityId_sessionSettings) {
val intent = Intent(context, PrivacySettingsActivity::class.java)
// allow the screen to auto scroll to the appropriate toggle
intent.putExtra(PrivacySettingsActivity.SCROLL_KEY, CALL_NOTIFICATIONS_ENABLED)
intent.putExtra(PrivacySettingsActivity.SCROLL_AND_TOGGLE_KEY, CALL_NOTIFICATIONS_ENABLED)
context.startActivity(intent)
}
cancelButton()

@ -198,7 +198,7 @@ class ControlMessageView : LinearLayout {
button(R.string.sessionSettings) {
val intent = Intent(context, PrivacySettingsActivity::class.java)
// allow the screen to auto scroll to the appropriate toggle
intent.putExtra(PrivacySettingsActivity.SCROLL_KEY, CALL_NOTIFICATIONS_ENABLED)
intent.putExtra(PrivacySettingsActivity.SCROLL_AND_TOGGLE_KEY, CALL_NOTIFICATIONS_ENABLED)
context.startActivity(intent)
}
cancelButton()

@ -1,15 +1,21 @@
package org.thoughtcrime.securesms.preferences
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.ScreenLockActionBarActivity
import javax.inject.Inject
@AndroidEntryPoint
class PrivacySettingsActivity : ScreenLockActionBarActivity() {
companion object{
const val SCROLL_KEY = "privacy_scroll_key"
const val SCROLL_AND_TOGGLE_KEY = "privacy_scroll_and_toggle_key"
}
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
@ -22,6 +28,9 @@ class PrivacySettingsActivity : ScreenLockActionBarActivity() {
if(intent.hasExtra(SCROLL_KEY)) {
fragment.scrollToKey(intent.getStringExtra(SCROLL_KEY)!!)
} else if(intent.hasExtra(SCROLL_AND_TOGGLE_KEY)) {
fragment.scrollAndAutoToggle(intent.getStringExtra(SCROLL_AND_TOGGLE_KEY)!!)
}
}
}

@ -5,10 +5,13 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.provider.Settings
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceDataStore
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject
import network.loki.messenger.BuildConfig
import network.loki.messenger.R
@ -27,7 +30,11 @@ import org.thoughtcrime.securesms.util.IntentUtils
@AndroidEntryPoint
class PrivacySettingsPreferenceFragment : CorrectedPreferenceFragment() {
@Inject lateinit var configFactory: ConfigFactory
@Inject
lateinit var configFactory: ConfigFactory
@Inject
lateinit var textSecurePreferences: TextSecurePreferences
override fun onCreate(paramBundle: Bundle?) {
super.onCreate(paramBundle)
@ -73,6 +80,25 @@ class PrivacySettingsPreferenceFragment : CorrectedPreferenceFragment() {
scrollToPreference(key)
}
fun scrollAndAutoToggle(key: String){
lifecycleScope.launch {
scrollToKey(key)
delay(500) // slight delay to make the transition less jarring
// Find the preference based on the provided key.
val pref = findPreference<Preference>(key)
// auto toggle for prefs that are switches
pref?.let {
// Check if it's a switch preference so we can toggle its checked state.
if (it is SwitchPreferenceCompat) {
// force set to true here, and call the onPreferenceChangeListener
// defined further up so that custom behaviours are still applied
// Invoke the onPreferenceChangeListener with the new value.
it.onPreferenceChangeListener?.onPreferenceChange(it, true)
}
}
}
}
private fun setCall(isEnabled: Boolean) {
(findPreference<Preference>(TextSecurePreferences.CALL_NOTIFICATIONS_ENABLED) as SwitchPreferenceCompat?)!!.isChecked =
isEnabled

@ -1,7 +1,7 @@
package org.thoughtcrime.securesms.webrtc
import android.content.Context
import android.content.Intent
import androidx.annotation.StringRes
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
@ -10,10 +10,26 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.stateIn
import network.loki.messenger.R
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.UsernameUtils
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.ViewUtil
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_ANSWER_INCOMING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_ANSWER_OUTGOING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_CONNECTED
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_DISCONNECTED
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_HANDLING_ICE
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_OFFER_INCOMING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_OFFER_OUTGOING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_PRE_OFFER_INCOMING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_PRE_OFFER_OUTGOING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_RECONNECTING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_SENDING_ICE
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.NETWORK_FAILURE
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.RECIPIENT_UNAVAILABLE
import org.webrtc.SurfaceViewRenderer
import javax.inject.Inject
@ -69,13 +85,106 @@ class CallViewModel @Inject constructor(
}
val currentCallState get() = callManager.currentCallState
val callState: StateFlow<CallState> = callManager.callStateEvents.combine(rtcCallBridge.hasAcceptedCall){
state, accepted -> CallState(state = state, hasAcceptedCall = accepted)
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), CallState(State.CALL_INITIALIZING, false))
val initialCallState = CallState("", "", false, false, false)
val initialAccumulator = CallAccumulator(emptySet(), initialCallState)
val callState: StateFlow<CallState> = callManager.callStateEvents
.combine(rtcCallBridge.hasAcceptedCall) { state, accepted ->
Pair(state, accepted)
}
.scan(initialAccumulator) { acc, (state, accepted) ->
// reset the set on preoffers
val newSteps = if (state in listOf(
CALL_PRE_OFFER_OUTGOING,
CALL_PRE_OFFER_INCOMING
)
) {
setOf(state)
} else {
acc.callSteps + state
}
val callTitle = when (state) {
CALL_PRE_OFFER_OUTGOING, CALL_PRE_OFFER_INCOMING,
CALL_OFFER_OUTGOING, CALL_OFFER_INCOMING ->
context.getString(R.string.callsRinging)
CALL_ANSWER_INCOMING, CALL_ANSWER_OUTGOING ->
context.getString(R.string.callsConnecting)
CALL_CONNECTED -> ""
CALL_RECONNECTING -> context.getString(R.string.callsReconnecting)
RECIPIENT_UNAVAILABLE, CALL_DISCONNECTED ->
context.getString(R.string.callsEnded)
NETWORK_FAILURE -> context.getString(R.string.callsErrorStart)
else -> acc.callState.callLabelTitle // keep previous title
}
val callSubtitle = when (state) {
CALL_PRE_OFFER_OUTGOING -> constructCallLabel(R.string.creatingCall, newSteps.size)
CALL_PRE_OFFER_INCOMING -> constructCallLabel(R.string.receivingPreOffer, newSteps.size)
CALL_OFFER_OUTGOING -> constructCallLabel(R.string.sendingCallOffer, newSteps.size)
CALL_OFFER_INCOMING -> constructCallLabel(R.string.receivingCallOffer, newSteps.size)
CALL_ANSWER_OUTGOING, CALL_ANSWER_INCOMING -> constructCallLabel(R.string.receivedAnswer, newSteps.size)
CALL_SENDING_ICE -> constructCallLabel(R.string.sendingConnectionCandidates, newSteps.size)
CALL_HANDLING_ICE -> constructCallLabel(R.string.handlingConnectionCandidates, newSteps.size)
else -> ""
}
val showCallControls = state in listOf(
CALL_CONNECTED,
CALL_PRE_OFFER_OUTGOING,
CALL_OFFER_OUTGOING,
CALL_ANSWER_OUTGOING,
CALL_ANSWER_INCOMING
) || (state in listOf(
CALL_PRE_OFFER_INCOMING,
CALL_OFFER_INCOMING,
CALL_HANDLING_ICE,
CALL_SENDING_ICE
) && accepted)
val showEndCallButton = showCallControls || state == CALL_RECONNECTING
val showPreCallButtons = state in listOf(
CALL_PRE_OFFER_INCOMING,
CALL_OFFER_INCOMING,
CALL_HANDLING_ICE,
CALL_SENDING_ICE
) && !accepted
val newCallState = CallState(
callLabelTitle = callTitle,
callLabelSubtitle = callSubtitle,
showCallButtons = showCallControls,
showPreCallButtons = showPreCallButtons,
showEndCallButton = showEndCallButton
)
CallAccumulator(newSteps, newCallState)
}
.map { it.callState }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialCallState)
val recipient get() = callManager.recipientEvents
val callStartTime: Long get() = callManager.callStartTime
data class CallAccumulator(
val callSteps: Set<CallViewModel.State>,
val callState: CallState
)
private val MAX_CALL_STEPS: Int = 5
private fun constructCallLabel(@StringRes label: Int, stepsCount: Int): String {
return if(ViewUtil.isLtr(context)) {
"${context.getString(label)} $stepsCount/$MAX_CALL_STEPS"
} else {
"$MAX_CALL_STEPS/$stepsCount ${context.getString(label)}"
}
}
fun swapVideos() = callManager.swapVideos()
fun toggleMute() = callManager.toggleMuteAudio()
@ -100,8 +209,10 @@ class CallViewModel @Inject constructor(
fun getCurrentUsername() = usernameUtils.getCurrentUsernameWithAccountIdFallback()
data class CallState(
val state: State,
val hasAcceptedCall: Boolean
val callLabelTitle: String?,
val callLabelSubtitle: String,
val showCallButtons: Boolean,
val showPreCallButtons: Boolean,
val showEndCallButton: Boolean
)
}

@ -6,6 +6,7 @@ import android.content.Context
import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.IntentFilter
import android.content.res.ColorStateList
import android.graphics.Outline
import android.media.AudioManager
import android.os.Build
@ -15,6 +16,7 @@ import android.view.View
import android.view.ViewOutlineProvider
import android.view.WindowManager
import androidx.activity.viewModels
import androidx.annotation.StringRes
import androidx.core.content.IntentCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
@ -27,13 +29,12 @@ import kotlinx.coroutines.launch
import network.loki.messenger.R
import network.loki.messenger.databinding.ActivityWebrtcBinding
import org.apache.commons.lang3.time.DurationFormatUtils
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.truncateIdForDisplay
import org.session.libsession.utilities.getColorFromAttr
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.ScreenLockActionBarActivity
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.conversation.v2.ViewUtil
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_ANSWER_INCOMING
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_ANSWER_OUTGOING
@ -49,6 +50,7 @@ import org.thoughtcrime.securesms.webrtc.CallViewModel.State.CALL_SENDING_ICE
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.NETWORK_FAILURE
import org.thoughtcrime.securesms.webrtc.CallViewModel.State.RECIPIENT_UNAVAILABLE
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager.AudioDevice.SPEAKER_PHONE
import java.time.Duration
@AndroidEntryPoint
class WebRtcCallActivity : ScreenLockActionBarActivity() {
@ -61,8 +63,6 @@ class WebRtcCallActivity : ScreenLockActionBarActivity() {
const val EXTRA_RECIPIENT_ADDRESS = "RECIPIENT_ID"
private const val CALL_DURATION_FORMAT = "HH:mm:ss"
fun getCallActivityIntent(context: Context): Intent{
return Intent(context, WebRtcCallActivity::class.java)
.setFlags(FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
@ -74,14 +74,12 @@ class WebRtcCallActivity : ScreenLockActionBarActivity() {
private var uiJob: Job? = null
private var hangupReceiver: BroadcastReceiver? = null
//todo PHONE TEMP STRINGS THAT WILL NEED TO BE REPLACED WITH CS STRINGS - putting them all here to easily discard them later
val TEMP_SEND_PRE_OFFER = "Creating Call"
val TEMP_RECEIVE_PRE_OFFER = "Receiving Pre Offer"
val TEMP_SENDING_OFFER = "Sending Call Offer"
val TEMP_RECEIVING_OFFER = "Receiving Call Offer"
val TEMP_SENDING_CANDIDATES = "Sending Connection Candidates"
val TEMP_RECEIVED_ANSWER = "Received Answer"
val TEMP_HANDLING_CANDIDATES = "Handling Connection Candidates"
private val CALL_DURATION_FORMAT_HOURS = "HH:mm:ss"
private val CALL_DURATION_FORMAT_MINS = "mm:ss"
private val ONE_HOUR: Long = Duration.ofHours(1).toMillis()
private val buttonColorEnabled by lazy { getColor(R.color.white) }
private val buttonColorDisabled by lazy { getColorFromAttr(R.attr.disabled) }
/**
* We need to track the device's orientation so we can calculate whether or not to rotate the video streams
@ -290,69 +288,18 @@ class WebRtcCallActivity : ScreenLockActionBarActivity() {
}
}
private fun updateControls(state: CallViewModel.State, hasAcceptedCall: Boolean) {
private fun updateControls(callState: CallViewModel.CallState) {
with(binding) {
// set up title and subtitle
callTitle.text = when (state) {
CALL_PRE_OFFER_OUTGOING, CALL_PRE_OFFER_INCOMING,
CALL_OFFER_OUTGOING, CALL_OFFER_INCOMING,
-> getString(R.string.callsRinging)
CALL_ANSWER_INCOMING,
CALL_ANSWER_OUTGOING,
-> getString(R.string.callsConnecting)
CALL_CONNECTED -> ""
callTitle.text = callState.callLabelTitle ?: callTitle.text // keep existing text if null
CALL_RECONNECTING -> getString(R.string.callsReconnecting)
RECIPIENT_UNAVAILABLE,
CALL_DISCONNECTED -> getString(R.string.callsEnded)
NETWORK_FAILURE -> getString(R.string.callsErrorStart)
else -> callTitle.text
}
callSubtitle.text = when (state) {
CALL_PRE_OFFER_OUTGOING -> TEMP_SEND_PRE_OFFER
CALL_PRE_OFFER_INCOMING -> TEMP_RECEIVE_PRE_OFFER
CALL_OFFER_OUTGOING -> TEMP_SENDING_OFFER
CALL_OFFER_INCOMING -> TEMP_RECEIVING_OFFER
CALL_ANSWER_OUTGOING, CALL_ANSWER_INCOMING -> TEMP_RECEIVED_ANSWER
CALL_SENDING_ICE -> TEMP_SENDING_CANDIDATES
CALL_HANDLING_ICE -> TEMP_HANDLING_CANDIDATES
else -> ""
}
callSubtitle.text = callState.callLabelSubtitle
callSubtitle.isVisible = callSubtitle.text.isNotEmpty()
// buttons visibility
val showCallControls = state in listOf(
CALL_CONNECTED,
CALL_PRE_OFFER_OUTGOING,
CALL_OFFER_OUTGOING,
CALL_ANSWER_OUTGOING,
CALL_ANSWER_INCOMING,
) || (state in listOf(
CALL_PRE_OFFER_INCOMING,
CALL_OFFER_INCOMING,
CALL_HANDLING_ICE,
CALL_SENDING_ICE
) && hasAcceptedCall)
controlGroup.isVisible = showCallControls
endCallButton.isVisible = showCallControls || state == CALL_RECONNECTING
incomingControlGroup.isVisible =
state in listOf(
CALL_PRE_OFFER_INCOMING,
CALL_OFFER_INCOMING,
CALL_HANDLING_ICE,
CALL_SENDING_ICE
) && !hasAcceptedCall
controlGroup.isVisible = callState.showCallButtons
endCallButton.isVisible = callState.showEndCallButton
incomingControlGroup.isVisible = callState.showPreCallButtons
}
}
@ -371,7 +318,7 @@ class WebRtcCallActivity : ScreenLockActionBarActivity() {
launch {
viewModel.callState.collect { data ->
updateControls(data.state, data.hasAcceptedCall)
updateControls(data)
}
}
@ -400,9 +347,12 @@ class WebRtcCallActivity : ScreenLockActionBarActivity() {
val startTime = viewModel.callStartTime
if (startTime != -1L) {
if(viewModel.currentCallState == CALL_CONNECTED) {
val duration = System.currentTimeMillis() - startTime
// apply format based on whether the call is more than 1h long
val durationFormat = if (duration > ONE_HOUR) CALL_DURATION_FORMAT_HOURS else CALL_DURATION_FORMAT_MINS
binding.callTitle.text = DurationFormatUtils.formatDuration(
System.currentTimeMillis() - startTime,
CALL_DURATION_FORMAT
duration,
durationFormat
)
}
}
@ -458,6 +408,12 @@ class WebRtcCallActivity : ScreenLockActionBarActivity() {
// handle buttons
binding.enableCameraButton.isSelected = state.userVideoEnabled
binding.switchCameraButton.isEnabled = state.userVideoEnabled
binding.switchCameraButton.imageTintList =
ColorStateList.valueOf(
if(state.userVideoEnabled) buttonColorEnabled
else buttonColorDisabled
)
}
}
}

@ -21,6 +21,7 @@
<attr name="onInvertedBackgroundPrimary" format="reference|color"/>
<attr name="warning" format="reference|color"/>
<attr name="danger" format="reference|color"/>
<attr name="disabled" format="reference|color"/>
<attr name="backgroundSecondary" format="reference|color"/>
<attr name="prominentButtonColor" format="reference|color"/>
<attr name="textColorAlert" format="reference|color"/>

@ -219,6 +219,7 @@
<item name="colorControlActivated">?colorAccent</item>
<item name="warning">@color/accent_orange</item>
<item name="danger">@color/danger_dark</item>
<item name="disabled">@color/classic_light_1</item>
<item name="android:textColorPrimary">@color/classic_dark_6</item>
<item name="android:textColorSecondary">?android:textColorPrimary</item>
<item name="android:textColorTertiary">@color/classic_dark_5</item>
@ -303,6 +304,7 @@
<item name="colorControlActivated">?colorAccent</item>
<item name="warning">@color/rust</item>
<item name="danger">@color/danger_light</item>
<item name="disabled">@color/classic_dark_5</item>
<item name="android:textColorPrimary">@color/classic_light_0</item>
<item name="android:textColorSecondary">@color/classic_light_1</item>
<item name="android:textColorTertiary">@color/classic_light_1</item>
@ -395,6 +397,7 @@
<item name="colorControlActivated">?colorAccent</item>
<item name="warning">@color/accent_orange</item>
<item name="danger">@color/danger_dark</item>
<item name="disabled">@color/classic_light_1</item>
<item name="android:textColorPrimary">@color/ocean_dark_7</item>
<item name="android:textColorSecondary">@color/ocean_dark_5</item>
<item name="android:textColorTertiary">@color/ocean_dark_5</item>
@ -482,6 +485,7 @@
<item name="colorControlActivated">?colorAccent</item>
<item name="warning">@color/rust</item>
<item name="danger">@color/danger_light</item>
<item name="disabled">@color/classic_dark_5</item>
<item name="android:textColorPrimary">@color/ocean_light_1</item>
<item name="android:textColorSecondary">@color/ocean_light_2</item>
<item name="android:textColorTertiary">@color/ocean_light_2</item>
@ -596,6 +600,7 @@
<item name="elementBorderColor">@color/classic_dark_3</item>
<item name="warning">@color/accent_orange</item>
<item name="danger">@color/danger_dark</item>
<item name="disabled">@color/classic_light_1</item>
<item name="textColorAlert">@color/classic_dark_6</item>
<!-- Home screen -->

@ -2,6 +2,14 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/callsVoiceAndVideoBeta">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_call_notifications_enabled"
android:title="@string/callsVoiceAndVideo"
android:summary="@string/callsVoiceAndVideoToggleDescription"/>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/screenSecurity">
@ -46,14 +54,6 @@
android:title="@string/linkPreviewsSend" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/callsVoiceAndVideoBeta">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_call_notifications_enabled"
android:title="@string/callsVoiceAndVideo"
android:summary="@string/callsVoiceAndVideoToggleDescription"/>
</PreferenceCategory>
<!-- <PreferenceCategory android:layout="@layout/preference_divider"/>
<PreferenceCategory android:title="@string/preferences_communication__category_sealed_sender">

@ -62,6 +62,8 @@ object SnodeAPI {
get() = SnodeModule.shared.broadcaster
private var snodeFailureCount: MutableMap<Snode, Int> = mutableMapOf()
// the list of "generic" nodes we use to make non swarm specific api calls
internal var snodePool: Set<Snode>
get() = database.getSnodePool()
set(newValue) { database.setSnodePool(newValue) }
@ -306,6 +308,7 @@ object SnodeAPI {
}
}.unwrap()
// the list of snodes that represent the swarm for that pubkey
fun getSwarm(publicKey: String): Promise<Set<Snode>, Exception> =
database.getSwarm(publicKey)?.takeIf { it.size >= minimumSwarmSnodeCount }?.let(Promise.Companion::of)
?: getRandomSnode().bind {

Loading…
Cancel
Save