mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-25 02:55:23 +00:00
feat: update dependencies and support outdated config messages, refactor config factory to return null configs if new configs not supported
This commit is contained in:
parent
d8f8ab8fe1
commit
5acaffda56
@ -260,6 +260,7 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
|
||||
CALL_CONNECTED -> {
|
||||
wantsToAnswer = false
|
||||
}
|
||||
else -> { /* do nothing */ }
|
||||
}
|
||||
updateControls(state)
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class ConversationViewModel(
|
||||
private val storage: Storage
|
||||
) : ViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow(ConversationUiState(conversationExists = recipient != null))
|
||||
private val _uiState = MutableStateFlow(ConversationUiState(conversationExists = true))
|
||||
val uiState: StateFlow<ConversationUiState> = _uiState
|
||||
|
||||
private var _recipient: RetrieveOnce<Recipient> = RetrieveOnce {
|
||||
|
@ -67,13 +67,14 @@ object ConversationMenuHelper {
|
||||
if (thread.expireMessages > 0) {
|
||||
inflater.inflate(R.menu.menu_conversation_expiration_on, menu)
|
||||
val item = menu.findItem(R.id.menu_expiring_messages)
|
||||
val actionView = item.actionView
|
||||
val iconView = actionView.findViewById<ImageView>(R.id.menu_badge_icon)
|
||||
val badgeView = actionView.findViewById<TextView>(R.id.expiration_badge)
|
||||
@ColorInt val color = context.getColorFromAttr(android.R.attr.textColorPrimary)
|
||||
iconView.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)
|
||||
badgeView.text = ExpirationUtil.getExpirationAbbreviatedDisplayValue(context, thread.expireMessages)
|
||||
actionView.setOnClickListener { onOptionsItemSelected(item) }
|
||||
item.actionView?.let { actionView ->
|
||||
val iconView = actionView.findViewById<ImageView>(R.id.menu_badge_icon)
|
||||
val badgeView = actionView.findViewById<TextView>(R.id.expiration_badge)
|
||||
@ColorInt val color = context.getColorFromAttr(android.R.attr.textColorPrimary)
|
||||
iconView.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)
|
||||
badgeView.text = ExpirationUtil.getExpirationAbbreviatedDisplayValue(context, thread.expireMessages)
|
||||
actionView.setOnClickListener { onOptionsItemSelected(item) }
|
||||
}
|
||||
} else {
|
||||
inflater.inflate(R.menu.menu_conversation_expiration_off, menu)
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ class ConfigFactory(private val context: Context,
|
||||
fun unregisterListener(listener: ConfigFactoryUpdateListener) { listeners -= listener }
|
||||
|
||||
override val user: UserProfile? get() = synchronized(userLock) {
|
||||
if (!ConfigBase.isNewConfigEnabled) return null
|
||||
if (_userConfig == null) {
|
||||
val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null
|
||||
val userDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.USER_PROFILE.name, publicKey)
|
||||
@ -58,6 +59,7 @@ class ConfigFactory(private val context: Context,
|
||||
}
|
||||
|
||||
override val contacts: Contacts? get() = synchronized(contactsLock) {
|
||||
if (!ConfigBase.isNewConfigEnabled) return null
|
||||
if (_contacts == null) {
|
||||
val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null
|
||||
val contactsDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.CONTACTS.name, publicKey)
|
||||
@ -73,6 +75,7 @@ class ConfigFactory(private val context: Context,
|
||||
}
|
||||
|
||||
override val convoVolatile: ConversationVolatileConfig? get() = synchronized(convoVolatileLock) {
|
||||
if (!ConfigBase.isNewConfigEnabled) return null
|
||||
if (_convoVolatileConfig == null) {
|
||||
val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null
|
||||
val convoDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.CONVO_INFO_VOLATILE.name, publicKey)
|
||||
@ -88,6 +91,7 @@ class ConfigFactory(private val context: Context,
|
||||
}
|
||||
|
||||
override val userGroups: UserGroupsConfig? get() = synchronized(userGroupsLock) {
|
||||
if (!ConfigBase.isNewConfigEnabled) return null
|
||||
if (_userGroups == null) {
|
||||
val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null
|
||||
val userGroupsDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.GROUPS.name, publicKey)
|
||||
|
@ -98,7 +98,7 @@ class NewMessageFragment : Fragment() {
|
||||
private fun hideLoader() {
|
||||
binding.loader.animate().setDuration(150).alpha(0.0f).setListener(object : AnimatorListenerAdapter() {
|
||||
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
super.onAnimationEnd(animation)
|
||||
binding.loader.visibility = View.GONE
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class JoinCommunityFragment : Fragment() {
|
||||
fun hideLoader() {
|
||||
binding.loader.animate().setDuration(150).alpha(0.0f).setListener(object : AnimatorListenerAdapter() {
|
||||
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
super.onAnimationEnd(animation)
|
||||
binding.loader.visibility = View.GONE
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import kotlinx.coroutines.withContext
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.ActivityHomeBinding
|
||||
import network.loki.messenger.databinding.ViewMessageRequestBannerBinding
|
||||
import network.loki.messenger.libsession_util.ConfigBase
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
@ -182,6 +183,11 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
binding.recyclerView.adapter = homeAdapter
|
||||
binding.globalSearchRecycler.adapter = globalSearchAdapter
|
||||
|
||||
binding.configOutdatedView.setOnClickListener {
|
||||
textSecurePreferences.setHasLegacyConfig(false)
|
||||
updateLegacyConfigView()
|
||||
}
|
||||
|
||||
// Set up empty state view
|
||||
binding.createNewPrivateChatButton.setOnClickListener { showNewConversation() }
|
||||
IP2Country.configureIfNeeded(this@HomeActivity)
|
||||
@ -335,6 +341,10 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateLegacyConfigView() {
|
||||
binding.configOutdatedView.isVisible = ConfigBase.isNewConfigEnabled && textSecurePreferences.getHasLegacyConfig()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
ApplicationContext.getInstance(this).messageNotifier.setHomeScreenVisible(true)
|
||||
@ -345,7 +355,12 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
if (textSecurePreferences.getHasViewedSeed()) {
|
||||
binding.seedReminderView.isVisible = false
|
||||
}
|
||||
if (textSecurePreferences.getConfigurationMessageSynced()) {
|
||||
|
||||
updateLegacyConfigView()
|
||||
|
||||
// TODO: remove this after enough updates that we can rely on ConfigBase.isNewConfigEnabled to always return true
|
||||
// This will only run if we aren't using new configs, as they are schedule to sync when there are changes applied
|
||||
if (textSecurePreferences.getConfigurationMessageSynced() && !ConfigBase.isNewConfigEnabled) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
ConfigurationMessageUtilities.syncConfigurationIfNeeded(this@HomeActivity)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.ContentView
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.GroupConversation
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.Header
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.Message
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.SavedMessages
|
||||
import org.thoughtcrime.securesms.util.DateUtils
|
||||
@ -76,6 +77,8 @@ fun ContentView.bindQuery(query: String, model: GlobalSearchAdapter.Model) {
|
||||
}
|
||||
binding.searchResultSubtitle.text = getHighlight(query, membersString)
|
||||
}
|
||||
is Header, // do nothing for header
|
||||
is SavedMessages -> Unit // do nothing for saved messages (displays note to self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ class KeyboardPageSearchView @JvmOverloads constructor(
|
||||
.setDuration(REVEAL_DURATION)
|
||||
.alpha(0f)
|
||||
.setListener(object : AnimationCompleteListener() {
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
visibility = INVISIBLE
|
||||
}
|
||||
})
|
||||
|
@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
class ProfileManager(private val context: Context, private val configFactory: ConfigFactory) : SSKEnvironment.ProfileManagerProtocol {
|
||||
|
||||
override fun setNickname(context: Context, recipient: Recipient, nickname: String?) {
|
||||
if (recipient.isLocalNumber) return
|
||||
val sessionID = recipient.address.serialize()
|
||||
val contactDatabase = DatabaseComponent.get(context).sessionContactDatabase()
|
||||
var contact = contactDatabase.getContactWithSessionID(sessionID)
|
||||
@ -31,6 +32,7 @@ class ProfileManager(private val context: Context, private val configFactory: Co
|
||||
|
||||
override fun setName(context: Context, recipient: Recipient, name: String?) {
|
||||
// New API
|
||||
if (recipient.isLocalNumber) return
|
||||
val sessionID = recipient.address.serialize()
|
||||
val contactDatabase = DatabaseComponent.get(context).sessionContactDatabase()
|
||||
var contact = contactDatabase.getContactWithSessionID(sessionID)
|
||||
@ -48,6 +50,7 @@ class ProfileManager(private val context: Context, private val configFactory: Co
|
||||
}
|
||||
|
||||
override fun setProfilePictureURL(context: Context, recipient: Recipient, profilePictureURL: String) {
|
||||
if (recipient.isLocalNumber) return
|
||||
val job = RetrieveProfileAvatarJob(recipient, profilePictureURL)
|
||||
val jobManager = ApplicationContext.getInstance(context).jobManager
|
||||
jobManager.add(job)
|
||||
@ -64,6 +67,7 @@ class ProfileManager(private val context: Context, private val configFactory: Co
|
||||
}
|
||||
|
||||
override fun setProfileKey(context: Context, recipient: Recipient, profileKey: ByteArray?) {
|
||||
if (recipient.isLocalNumber) return
|
||||
// New API
|
||||
val sessionID = recipient.address.serialize()
|
||||
val contactDatabase = DatabaseComponent.get(context).sessionContactDatabase()
|
||||
|
@ -8,11 +8,11 @@ import android.content.Context
|
||||
import android.graphics.PointF
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DimenRes
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.utilities.getColorFromAttr
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
|
||||
fun View.contains(point: PointF): Boolean {
|
||||
return hitRect.contains(point.x.toInt(), point.y.toInt())
|
||||
@ -54,7 +54,7 @@ fun View.fadeIn(duration: Long = 150) {
|
||||
|
||||
fun View.fadeOut(duration: Long = 150) {
|
||||
animate().setDuration(duration).alpha(0.0f).setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
super.onAnimationEnd(animation)
|
||||
visibility = View.GONE
|
||||
}
|
||||
|
@ -27,8 +27,9 @@
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp">
|
||||
|
||||
<include layout="@layout/view_profile_picture"
|
||||
<include
|
||||
android:id="@+id/profileButton"
|
||||
layout="@layout/view_profile_picture"
|
||||
android:layout_width="@dimen/small_profile_picture_size"
|
||||
android:layout_height="@dimen/small_profile_picture_size"
|
||||
android:layout_alignParentLeft="true"
|
||||
@ -37,10 +38,10 @@
|
||||
|
||||
<org.thoughtcrime.securesms.home.PathStatusView
|
||||
android:id="@+id/pathStatusView"
|
||||
android:layout_alignBottom="@+id/profileButton"
|
||||
android:layout_alignEnd="@+id/profileButton"
|
||||
android:layout_width="@dimen/path_status_view_size"
|
||||
android:layout_height="@dimen/path_status_view_size"/>
|
||||
android:layout_height="@dimen/path_status_view_size"
|
||||
android:layout_alignEnd="@+id/profileButton"
|
||||
android:layout_alignBottom="@+id/profileButton" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/sessionHeaderImage"
|
||||
@ -72,16 +73,17 @@
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:visibility="gone"
|
||||
android:id="@+id/search_toolbar"
|
||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize">
|
||||
android:layout_height="?actionBarSize"
|
||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
||||
android:visibility="gone">
|
||||
|
||||
<org.thoughtcrime.securesms.home.search.GlobalSearchInputLayout
|
||||
android:layout_centerVertical="true"
|
||||
android:id="@+id/globalSearchInputLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true" />
|
||||
</RelativeLayout>
|
||||
|
||||
<View
|
||||
@ -95,15 +97,29 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:visibility="gone"
|
||||
android:textColor="?message_sent_text_color"
|
||||
android:background="?colorAccent"
|
||||
android:id="@+id/configOutdatedView"
|
||||
android:textSize="9sp"
|
||||
android:paddingVertical="4dp"
|
||||
android:paddingHorizontal="64dp"
|
||||
android:gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/activity_home_outdated_client_config"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
<RelativeLayout
|
||||
android:focusable="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false">
|
||||
android:clipChildren="false"
|
||||
android:focusable="false">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
@ -116,14 +132,14 @@
|
||||
tools:listitem="@layout/view_conversation" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:visibility="gone"
|
||||
android:scrollbars="vertical"
|
||||
android:id="@+id/globalSearchRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:visibility="gone"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/view_global_search_result"
|
||||
tools:itemCount="6"
|
||||
android:layout_height="match_parent"/>
|
||||
tools:listitem="@layout/view_global_search_result" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/emptyStateContainer"
|
||||
@ -159,6 +175,7 @@
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="@drawable/new_conversation_button_background"
|
||||
android:contentDescription="@string/activity_appearance_follow_system_category"
|
||||
android:layout_marginBottom="@dimen/new_conversation_button_bottom_offset"
|
||||
android:src="@drawable/ic_plus"
|
||||
app:tint="@color/white" />
|
||||
|
@ -873,4 +873,5 @@
|
||||
<string name="delivery_status_failed">Failed to send</string>
|
||||
<string name="giphy_permission_title">Search GIFs?</string>
|
||||
<string name="giphy_permission_message">Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs.</string>
|
||||
<string name="activity_home_outdated_client_config">Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.</string>
|
||||
</resources>
|
||||
|
@ -389,6 +389,8 @@
|
||||
<item name="message_selected">@color/classic_dark_2</item>
|
||||
</style>
|
||||
|
||||
<style name="Classic.Dark.Test" parent="Theme.Session.DayNight.NoActionBar"/>
|
||||
|
||||
<style name="Classic.Light">
|
||||
<!-- Main styles -->
|
||||
<item name="sessionLogoTint">@color/classic_light_0</item>
|
||||
|
@ -51,7 +51,7 @@ allprojects {
|
||||
|
||||
project.ext {
|
||||
androidMinimumSdkVersion = 23
|
||||
androidTargetSdkVersion = 31
|
||||
androidCompileSdkVersion = 32
|
||||
androidTargetSdkVersion = 33
|
||||
androidCompileSdkVersion = 33
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx8g
|
||||
|
||||
gradlePluginVersion=7.3.1
|
||||
googleServicesVersion=4.3.12
|
||||
kotlinVersion=1.7.20
|
||||
kotlinVersion=1.6.21
|
||||
coroutinesVersion=1.6.4
|
||||
kotlinxJsonVersion=1.3.3
|
||||
lifecycleVersion=2.5.1
|
||||
@ -15,8 +15,8 @@ curve25519Version=0.6.0
|
||||
protobufVersion=2.5.0
|
||||
okhttpVersion=3.12.1
|
||||
jacksonDatabindVersion=2.9.8
|
||||
appcompatVersion=1.5.1
|
||||
materialVersion=1.7.0
|
||||
appcompatVersion=1.6.1
|
||||
materialVersion=1.8.0
|
||||
preferenceVersion=1.2.0
|
||||
coreVersion=1.8.0
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import android.text.TextUtils
|
||||
import network.loki.messenger.libsession_util.ConfigBase
|
||||
import org.session.libsession.avatars.AvatarHelper
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.jobs.BackgroundGroupAddJob
|
||||
@ -148,6 +149,9 @@ private fun handleConfigurationMessage(message: ConfigurationMessage) {
|
||||
|
||||
TextSecurePreferences.setConfigurationMessageSynced(context, true)
|
||||
TextSecurePreferences.setLastProfileUpdateTime(context, message.sentTimestamp!!)
|
||||
if (ConfigBase.isNewConfigEnabled) {
|
||||
TextSecurePreferences.setHasLegacyConfig(context, true)
|
||||
}
|
||||
val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys()
|
||||
for (closedGroup in message.closedGroups) {
|
||||
if (allClosedGroupPublicKeys.contains(closedGroup.publicKey)) {
|
||||
|
@ -103,6 +103,8 @@ interface TextSecurePreferences {
|
||||
fun setUpdateApkDigest(value: String?)
|
||||
fun getUpdateApkDigest(): String?
|
||||
fun getLocalNumber(): String?
|
||||
fun getHasLegacyConfig(): Boolean
|
||||
fun setHasLegacyConfig(newValue: Boolean)
|
||||
fun setLocalNumber(localNumber: String)
|
||||
fun removeLocalNumber()
|
||||
fun isEnterSendsEnabled(): Boolean
|
||||
@ -264,6 +266,9 @@ interface TextSecurePreferences {
|
||||
const val AUTOPLAY_AUDIO_MESSAGES = "pref_autoplay_audio"
|
||||
const val FINGERPRINT_KEY_GENERATED = "fingerprint_key_generated"
|
||||
const val SELECTED_ACCENT_COLOR = "selected_accent_color"
|
||||
|
||||
const val HAS_RECEIVED_LEGACY_CONFIG = "has_received_legacy_config"
|
||||
|
||||
const val GREEN_ACCENT = "accent_green"
|
||||
const val BLUE_ACCENT = "accent_blue"
|
||||
const val PURPLE_ACCENT = "accent_purple"
|
||||
@ -625,6 +630,16 @@ interface TextSecurePreferences {
|
||||
return getStringPreference(context, LOCAL_NUMBER_PREF, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getHasLegacyConfig(context: Context): Boolean {
|
||||
return getBooleanPreference(context, HAS_RECEIVED_LEGACY_CONFIG, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setHasLegacyConfig(context: Context, newValue: Boolean) {
|
||||
setBooleanPreference(context, HAS_RECEIVED_LEGACY_CONFIG, newValue)
|
||||
}
|
||||
|
||||
fun setLocalNumber(context: Context, localNumber: String) {
|
||||
setStringPreference(context, LOCAL_NUMBER_PREF, localNumber.toLowerCase())
|
||||
}
|
||||
@ -1279,6 +1294,14 @@ class AppTextSecurePreferences @Inject constructor(
|
||||
return getStringPreference(TextSecurePreferences.LOCAL_NUMBER_PREF, null)
|
||||
}
|
||||
|
||||
override fun getHasLegacyConfig(): Boolean {
|
||||
return getBooleanPreference(TextSecurePreferences.HAS_RECEIVED_LEGACY_CONFIG, false)
|
||||
}
|
||||
|
||||
override fun setHasLegacyConfig(newValue: Boolean) {
|
||||
return setBooleanPreference(TextSecurePreferences.HAS_RECEIVED_LEGACY_CONFIG, newValue)
|
||||
}
|
||||
|
||||
override fun setLocalNumber(localNumber: String) {
|
||||
setStringPreference(TextSecurePreferences.LOCAL_NUMBER_PREF, localNumber.toLowerCase())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user