Remove ComposeText and SendButton sms/mms transport complexity.

This commit is contained in:
Cody Henthorne
2023-08-03 13:19:34 -04:00
committed by Alex Hart
parent 2f9498e137
commit b30f47bac4
6 changed files with 19 additions and 196 deletions

View File

@@ -9,13 +9,11 @@ import android.text.Annotation;
import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.text.style.RelativeSizeSpan;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.Menu;
@@ -49,7 +47,6 @@ import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.List;
@@ -65,7 +62,6 @@ public class ComposeText extends EmojiEditText {
private static final Pattern TIME_PATTERN = Pattern.compile("^[0-9]{1,2}:[0-9]{1,2}$");
private CharSequence hint;
private SpannableString subHint;
private MentionRendererDelegate mentionRendererDelegate;
private SpoilerRendererDelegate spoilerRendererDelegate;
private MentionValidatorWatcher mentionValidatorWatcher;
@@ -106,13 +102,7 @@ public class ComposeText extends EmojiEditText {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getLayout() != null && !TextUtils.isEmpty(hint)) {
if (!TextUtils.isEmpty(subHint)) {
setHintWithChecks(new SpannableStringBuilder().append(ellipsizeToWidth(hint))
.append("\n")
.append(ellipsizeToWidth(subHint)));
} else {
setHintWithChecks(ellipsizeToWidth(hint));
}
setHintWithChecks(ellipsizeToWidth(hint));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@@ -173,25 +163,9 @@ public class ComposeText extends EmojiEditText {
TruncateAt.END);
}
public void setHint(@NonNull String hint, @Nullable CharSequence subHint) {
public void setHint(@NonNull String hint) {
this.hint = hint;
if (subHint != null) {
this.subHint = new SpannableString(subHint);
this.subHint.setSpan(new RelativeSizeSpan(0.5f), 0, subHint.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
} else {
this.subHint = null;
}
if (this.subHint != null) {
setHintWithChecks(new SpannableStringBuilder().append(ellipsizeToWidth(this.hint))
.append("\n")
.append(ellipsizeToWidth(this.subHint)));
} else {
setHintWithChecks(ellipsizeToWidth(this.hint));
}
setHintWithChecks(hint);
setHintWithChecks(ellipsizeToWidth(this.hint));
}
public void setDraftText(@Nullable CharSequence draftText) {
@@ -249,10 +223,7 @@ public class ComposeText extends EmojiEditText {
}
setImeOptions(imeOptions);
setHint(getContext().getString(messageSendType.getComposeHintRes()),
messageSendType.getSimName() != null
? getContext().getString(R.string.conversation_activity__from_sim_name, messageSendType.getSimName())
: null);
setHint(getContext().getString(messageSendType.getComposeHintRes()));
setInputType(inputType);
}

View File

@@ -6,13 +6,7 @@ import android.view.View
import android.view.View.OnLongClickListener
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatImageButton
import com.google.android.material.snackbar.Snackbar
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.menu.ActionItem
import org.thoughtcrime.securesms.components.menu.SignalContextMenu
import org.thoughtcrime.securesms.conversation.MessageSendType
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.ViewUtil
/**
@@ -21,83 +15,21 @@ import org.thoughtcrime.securesms.util.ViewUtil
*/
class SendButton(context: Context, attributeSet: AttributeSet?) : AppCompatImageButton(context, attributeSet), OnLongClickListener {
companion object {
private val TAG = Log.tag(SendButton::class.java)
}
private var scheduledSendListener: ScheduledSendListener? = null
private var availableSendTypes: List<MessageSendType> = MessageSendType.getAllAvailable(context, false)
private var activeMessageSendType: MessageSendType? = null
private var defaultTransportType: MessageSendType.TransportType = MessageSendType.TransportType.SIGNAL
private var defaultSubscriptionId: Int? = null
var snackbarContainer: View? = null
private var popupContainer: ViewGroup? = null
init {
setOnLongClickListener(this)
ViewUtil.mirrorIfRtl(this, getContext())
}
/**
* The actively-selected send type.
*/
private val selectedSendType: MessageSendType
get() {
activeMessageSendType?.let {
return it
}
if (defaultTransportType === MessageSendType.TransportType.SMS) {
for (type in availableSendTypes) {
if (type.usesSmsTransport && (defaultSubscriptionId == null || type.simSubscriptionId == defaultSubscriptionId)) {
return type
}
}
}
for (type in availableSendTypes) {
if (type.transportType === defaultTransportType) {
return type
}
}
Log.w(TAG, "No options of default type! Resetting. DefaultTransportType: $defaultTransportType, AllAvailable: ${availableSendTypes.map { it.transportType }}")
val signalType: MessageSendType? = availableSendTypes.firstOrNull { it.usesSignalTransport }
if (signalType != null) {
Log.w(TAG, "No options of default type, but Signal type is available. Switching. DefaultTransportType: $defaultTransportType, AllAvailable: ${availableSendTypes.map { it.transportType }}")
defaultTransportType = MessageSendType.TransportType.SIGNAL
onSelectionChanged(signalType)
return signalType
} else if (availableSendTypes.isEmpty()) {
Log.w(TAG, "No send types available at all! Enabling the Signal transport.")
defaultTransportType = MessageSendType.TransportType.SIGNAL
availableSendTypes = listOf(MessageSendType.SignalMessageSendType)
onSelectionChanged(MessageSendType.SignalMessageSendType)
return MessageSendType.SignalMessageSendType
} else {
throw AssertionError("No options of default type! DefaultTransportType: $defaultTransportType, AllAvailable: ${availableSendTypes.map { it.transportType }}")
}
}
fun triggerSelectedChangedEvent() {
onSelectionChanged(newType = selectedSendType)
setImageResource(MessageSendType.SignalMessageSendType.buttonDrawableRes)
contentDescription = context.getString(MessageSendType.SignalMessageSendType.titleRes)
}
fun setScheduledSendListener(listener: ScheduledSendListener?) {
this.scheduledSendListener = listener
}
private fun setSendType(sendType: MessageSendType?) {
if (activeMessageSendType == sendType) {
return
}
activeMessageSendType = sendType
onSelectionChanged(newType = selectedSendType)
}
/**
* Must be called with a view that is acceptable for determining the bounds of the popup selector.
*/
@@ -105,58 +37,19 @@ class SendButton(context: Context, attributeSet: AttributeSet?) : AppCompatImage
popupContainer = container
}
private fun onSelectionChanged(newType: MessageSendType) {
setImageResource(newType.buttonDrawableRes)
contentDescription = context.getString(newType.titleRes)
}
override fun onLongClick(v: View): Boolean {
if (!isEnabled) {
return false
}
val scheduleListener = scheduledSendListener
if (availableSendTypes.size == 1) {
return if (scheduleListener?.canSchedule() == true && selectedSendType.transportType != MessageSendType.TransportType.SMS) {
scheduleListener.onSendScheduled()
true
} else if (snackbarContainer != null && !SignalStore.misc().smsExportPhase.allowSmsFeatures()) {
Snackbar.make(snackbarContainer!!, R.string.InputPanel__sms_messaging_is_no_longer_supported_in_signal, Snackbar.LENGTH_SHORT).show()
true
} else {
false
}
return if (scheduleListener?.canSchedule() == true) {
scheduleListener.onSendScheduled()
true
} else {
false
}
showSendTypeContextMenu(selectedSendType.transportType != MessageSendType.TransportType.SMS)
return true
}
private fun showSendTypeContextMenu(allowScheduling: Boolean) {
val currentlySelected: MessageSendType = selectedSendType
val listener = scheduledSendListener
val items = availableSendTypes
.filterNot { it == currentlySelected }
.map { option ->
ActionItem(
iconRes = option.menuDrawableRes,
title = option.getTitle(context),
action = { setSendType(option) }
)
}.toMutableList()
if (allowScheduling && listener?.canSchedule() == true) {
items += ActionItem(
iconRes = R.drawable.symbol_calendar_24,
title = context.getString(R.string.conversation_activity__option_schedule_message),
action = { listener.onSendScheduled() }
)
}
SignalContextMenu.Builder((parent as View), popupContainer!!)
.preferredVerticalPosition(SignalContextMenu.VerticalPosition.ABOVE)
.offsetY(ViewUtil.dpToPx(8))
.show(items)
}
interface ScheduledSendListener {

View File

@@ -1,21 +1,16 @@
package org.thoughtcrime.securesms.conversation
import android.Manifest
import android.content.Context
import android.os.Parcelable
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import kotlinx.parcelize.Parcelize
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.CharacterCalculator
import org.thoughtcrime.securesms.util.MmsCharacterCalculator
import org.thoughtcrime.securesms.util.PushCharacterCalculator
import org.thoughtcrime.securesms.util.SmsCharacterCalculator
import org.thoughtcrime.securesms.util.dualsim.SubscriptionInfoCompat
import org.thoughtcrime.securesms.util.dualsim.SubscriptionManagerCompat
import java.lang.IllegalArgumentException
/**
@@ -51,10 +46,6 @@ sealed class MessageSendType(
return characterCalculator.calculateCharacters(body)
}
fun getSimSubscriptionIdOr(fallback: Int): Int {
return simSubscriptionId ?: fallback
}
open fun getTitle(context: Context): String {
return context.getString(titleRes)
}
@@ -126,45 +117,14 @@ sealed class MessageSendType(
}
companion object {
private val TAG = Log.tag(MessageSendType::class.java)
/**
* Returns a list of all available [MessageSendType]s. Requires [Manifest.permission.READ_PHONE_STATE] in order to get available
* SMS options.
*/
@JvmStatic
fun getAllAvailable(context: Context, isMedia: Boolean = false): List<MessageSendType> {
val options: MutableList<MessageSendType> = mutableListOf()
options += SignalMessageSendType
if (SignalStore.misc().smsExportPhase.allowSmsFeatures()) {
try {
val subscriptions: Collection<SubscriptionInfoCompat> = SubscriptionManagerCompat(context).activeAndReadySubscriptionInfos
if (subscriptions.size < 2) {
options += if (isMedia) MmsMessageSendType() else SmsMessageSendType()
} else {
options += subscriptions.map {
if (isMedia) {
MmsMessageSendType(simName = it.displayName, simSubscriptionId = it.subscriptionId)
} else {
SmsMessageSendType(simName = it.displayName, simSubscriptionId = it.subscriptionId)
}
}
}
} catch (e: SecurityException) {
Log.w(TAG, "Did not have permission to get SMS subscription details!")
}
}
return options
fun getAllAvailable(): List<MessageSendType> {
return listOf(SignalMessageSendType)
}
@JvmStatic
fun getFirstForTransport(context: Context, isMedia: Boolean, transportType: TransportType): MessageSendType {
return getAllAvailable(context, isMedia).firstOrNull { it.transportType == transportType } ?: throw IllegalArgumentException("No options available for desired type $transportType!")
fun getFirstForTransport(transportType: TransportType): MessageSendType {
return getAllAvailable().firstOrNull { it.transportType == transportType } ?: throw IllegalArgumentException("No options available for desired type $transportType!")
}
}
}

View File

@@ -84,7 +84,7 @@ object Multiselect {
return false
}
val sendType: MessageSendType = MessageSendType.getFirstForTransport(context, true, MessageSendType.TransportType.SMS)
val sendType: MessageSendType = MessageSendType.getFirstForTransport(MessageSendType.TransportType.SMS)
val mmsConstraints = MediaConstraints.getMmsMediaConstraints(sendType.simSubscriptionId ?: -1)
return mmsConstraints.isSatisfied(context, mediaUri, mediaType, mediaSize) || mmsConstraints.canResize(mediaType)
@@ -107,7 +107,7 @@ object Multiselect {
return false
}
val sendType: MessageSendType = MessageSendType.getFirstForTransport(context, true, MessageSendType.TransportType.SMS)
val sendType: MessageSendType = MessageSendType.getFirstForTransport(MessageSendType.TransportType.SMS)
val mmsConstraints = MediaConstraints.getMmsMediaConstraints(sendType.simSubscriptionId ?: -1)
return mmsConstraints.isSatisfied(context, attachment) || mmsConstraints.canResize(attachment)

View File

@@ -913,7 +913,6 @@ class ConversationFragment :
setOnClickListener(sendButtonListener)
setScheduledSendListener(sendButtonListener)
isEnabled = true
sendButton.triggerSelectedChangedEvent()
}
sendEditButton.setOnClickListener { handleSendEditMessage() }

View File

@@ -191,7 +191,7 @@ class ShareRepository(context: Context) {
return false
}
val sendType: MessageSendType = MessageSendType.getFirstForTransport(context, true, MessageSendType.TransportType.SMS)
val sendType: MessageSendType = MessageSendType.getFirstForTransport(MessageSendType.TransportType.SMS)
val mmsConstraints = MediaConstraints.getMmsMediaConstraints(sendType.simSubscriptionId ?: -1)
return mmsConstraints.isSatisfied(context, attachment) || mmsConstraints.canResize(attachment)
}