From 3c576053a3e5717b7beeef2286837be4951e355f Mon Sep 17 00:00:00 2001 From: alansley Date: Mon, 26 Aug 2024 17:11:45 +1000 Subject: [PATCH] Moved into libsession for ease of access to control message view creation --- app/build.gradle | 1 - .../conversation/v2/ConversationActivityV2.kt | 20 +------ .../v2/utilities/TextUtilities.kt | 4 ++ .../securesms/util/SaveAttachmentTask.kt | 2 +- .../utilities/UpdateMessageBuilder.kt | 55 ++++++++++--------- .../org/session/libsession/utilities/Util.kt | 20 +++++++ 6 files changed, 56 insertions(+), 46 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index dd69ffecc8..19357e704a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -227,7 +227,6 @@ dependencies { ksp("com.google.dagger:hilt-compiler:$daggerHiltVersion") ksp("com.github.bumptech.glide:ksp:$glideVersion") - implementation 'androidx.compose.material3:material3-android:1.2.1' implementation("com.google.dagger:hilt-android:$daggerHiltVersion") implementation "androidx.appcompat:appcompat:$appcompatVersion" implementation 'androidx.recyclerview:recyclerview:1.2.1' diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 92aaa44543..989be7880b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -1072,24 +1072,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe updateUnreadCountIndicator() } - // Method that takes a char sequence that contains one or more elements surrounded in bold tags - // like "Hello world" and returns a SpannableString that will display the appropriate - // elements in bold. If there are no such or elements then the original string is returned - // as a SpannableString without any bold highlighting. - private fun makeBoldBetweenTags(input: CharSequence): SpannableString { - val spannable = SpannableString(input) - var startIndex = 0 - while (true) { - startIndex = input.indexOf("", startIndex) - if (startIndex == -1) break - val endIndex = input.indexOf("", startIndex + 3) - if (endIndex == -1) break - spannable.setSpan(StyleSpan(Typeface.BOLD),startIndex + 3, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) - startIndex = endIndex + 4 - } - return spannable - } - // Update placeholder / control messages in a conversation private fun updatePlaceholder() { val recipient = viewModel.recipient ?: return Log.w("Loki", "recipient was null in placeholder update") @@ -1134,7 +1116,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe binding.placeholderText.isVisible = showPlaceholder if (showPlaceholder) { if (!isNoteToSelf) { - binding.placeholderText.text = makeBoldBetweenTags(txtCS) + binding.placeholderText.text = org.session.libsession.utilities.Util.makeBoldBetweenTags(txtCS) } else { binding.placeholderText.text = txtCS } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt index 7a47b92756..23d81e2513 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt @@ -1,9 +1,13 @@ package org.thoughtcrime.securesms.conversation.v2.utilities import android.graphics.Rect +import android.graphics.Typeface import android.text.Layout +import android.text.SpannableString +import android.text.Spanned import android.text.StaticLayout import android.text.TextPaint +import android.text.style.StyleSpan import android.view.MotionEvent import android.widget.TextView import androidx.core.text.getSpans diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentTask.kt b/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentTask.kt index 89d61e5c22..bd39f5f079 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentTask.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentTask.kt @@ -78,7 +78,7 @@ class SaveAttachmentTask @JvmOverloads constructor(context: Context, count: Int // for unknown reasons it provides us with an empty filename when saving files. // TODO: Further investigation into root cause and fix! if (fileName.isNullOrEmpty()) fileName = generateOutputFileName(contentType, attachment.date) - + fileName = sanitizeOutputFileName(fileName) val outputUri: Uri = getMediaStoreContentUriForType(contentType) val mediaUri = createOutputUri(context, outputUri, contentType, fileName) diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt index 85d502f1b5..f20ba1ec16 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -1,6 +1,7 @@ package org.session.libsession.messaging.utilities import android.content.Context +import android.text.SpannableString import com.squareup.phrase.Phrase import org.session.libsession.R import org.session.libsession.messaging.MessagingModuleConfiguration @@ -23,6 +24,7 @@ import org.session.libsession.utilities.StringSubstitutionConstants.GROUP_NAME_K import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY import org.session.libsession.utilities.StringSubstitutionConstants.OTHER_NAME_KEY import org.session.libsession.utilities.StringSubstitutionConstants.TIME_KEY +import org.session.libsession.utilities.Util object UpdateMessageBuilder { const val TAG = "libsession" @@ -33,29 +35,34 @@ object UpdateMessageBuilder { ?.displayName(Contact.ContactContext.REGULAR) ?: truncateIdForDisplay(senderId) - fun buildGroupUpdateMessage(context: Context, updateMessageData: UpdateMessageData, senderId: String? = null, isOutgoing: Boolean = false): String { + //@RequiresApi(Build.VERSION_CODES.P) + fun buildGroupUpdateMessage(context: Context, updateMessageData: UpdateMessageData, senderId: String? = null, isOutgoing: Boolean = false): CharSequence { val updateData = updateMessageData.kind if (updateData == null || !isOutgoing && senderId == null) return "" - val senderName: String = if (isOutgoing) context.getString(R.string.you) else getSenderName(senderId!!) return when (updateData) { // --- Group created or joined --- is UpdateMessageData.Kind.GroupCreation -> { - if (!isOutgoing) context.getString(R.string.groupInviteYou) - else "" // We no longer add a string like `disappearingMessagesNewGroup` ("You created a new group") and leave the group with its default empty state + if (!isOutgoing) { + Util.makeBoldBetweenTags(SpannableString(context.getString(R.string.groupInviteYou))) + } else { + "" // We no longer add a string like `disappearingMessagesNewGroup` ("You created a new group") and leave the group with its default empty state + } } // --- Group name changed --- is UpdateMessageData.Kind.GroupNameChange -> { if (isOutgoing) { - Phrase.from(context, R.string.groupNameNew) + val cs = Phrase.from(context, R.string.groupNameNew) .put(GROUP_NAME_KEY, updateData.name) - .format().toString() + .format() + Util.makeBoldBetweenTags(cs) } else { - Phrase.from(context, R.string.groupNameNew) + val cs = Phrase.from(context, R.string.groupNameNew) .put(GROUP_NAME_KEY, updateData.name) - .format().toString() + .format() + Util.makeBoldBetweenTags(cs) } } @@ -74,20 +81,20 @@ object UpdateMessageBuilder { 1 -> { Phrase.from(context, R.string.groupMemberNew) .put(NAME_KEY, updateData.updatedMembers.elementAtOrNull(0)) - .format().toString() + .format() } 2 -> { Phrase.from(context, R.string.groupMemberTwoNew) .put(NAME_KEY, updateData.updatedMembers.elementAtOrNull(0)) .put(OTHER_NAME_KEY, updateData.updatedMembers.elementAtOrNull(1)) - .format().toString() + .format() } else -> { val newMemberCountMinusOne = newMemberCount - 1 Phrase.from(context, R.string.groupMemberMoreNew) .put(NAME_KEY, updateData.updatedMembers.elementAtOrNull(0)) .put(COUNT_KEY, newMemberCountMinusOne) - .format().toString() + .format() } } } @@ -98,15 +105,13 @@ object UpdateMessageBuilder { // 1st case: you are part of the removed members return if (userPublicKey in updateData.updatedMembers) { - if (isOutgoing) context.getString(R.string.groupMemberYouLeft) // You chose to leave - else Phrase.from(context, R.string.groupRemovedYou) // You were forced to leave + if (isOutgoing) context.getString(R.string.groupMemberYouLeft) // You chose to leave + else Phrase.from(context, R.string.groupRemovedYou) // You were forced to leave .put(GROUP_NAME_KEY, updateData.groupName) - .format().toString() + .format() } else // 2nd case: you are not part of the removed members { - val members = updateData.updatedMembers.joinToString(", ", transform = ::getSenderName) - // a.) You are the person doing the removing of one or more members if (isOutgoing) { when (updateData.updatedMembers.size) { @@ -116,15 +121,15 @@ object UpdateMessageBuilder { } 1 -> Phrase.from(context, R.string.groupRemoved) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) - .format().toString() + .format() 2 -> Phrase.from(context, R.string.groupRemovedTwo) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) .put(OTHER_NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(1))) - .format().toString() + .format() else -> Phrase.from(context, R.string.groupRemovedMore) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) .put(COUNT_KEY, updateData.updatedMembers.size - 1) - .format().toString() + .format() } } else // b.) Someone else is the person doing the removing of one or more members @@ -140,15 +145,15 @@ object UpdateMessageBuilder { } 1 -> Phrase.from(context, R.string.groupRemoved) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) - .format().toString() + .format() 2 -> Phrase.from(context, R.string.groupRemovedTwo) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) .put(OTHER_NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(1))) - .format().toString() + .format() else -> Phrase.from(context, R.string.groupRemovedMore) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) .put(COUNT_KEY, updateData.updatedMembers.size - 1) - .format().toString() + .format() } } } @@ -165,15 +170,15 @@ object UpdateMessageBuilder { } 1 -> Phrase.from(context, R.string.groupMemberLeft) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) - .format().toString() + .format() 2 -> Phrase.from(context, R.string.groupMemberLeftTwo) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) .put(OTHER_NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(1))) - .format().toString() + .format() else -> Phrase.from(context, R.string.groupMemberLeftMore) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) .put(COUNT_KEY, updateData.updatedMembers.size - 1) - .format().toString() + .format() } } } diff --git a/libsession/src/main/java/org/session/libsession/utilities/Util.kt b/libsession/src/main/java/org/session/libsession/utilities/Util.kt index ae42d51068..9110066a45 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/Util.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/Util.kt @@ -9,6 +9,7 @@ import android.os.Looper import android.provider.Telephony import android.text.Spannable import android.text.SpannableString +import android.text.Spanned import android.text.TextUtils import android.text.style.StyleSpan import org.session.libsignal.utilities.Log @@ -358,6 +359,25 @@ object Util { val digitGroups = (Math.log10(sizeBytes.toDouble()) / Math.log10(1024.0)).toInt() return DecimalFormat("#,##0.#").format(sizeBytes / Math.pow(1024.0, digitGroups.toDouble())) + " " + units[digitGroups] } + + // Method that takes a char sequence that contains one or more elements surrounded in bold tags + // like "Hello world" and returns a SpannableString that will display the appropriate + // elements in bold. If there are no such or elements then the original string is returned + // as a SpannableString without any bold highlighting. + @JvmStatic + fun makeBoldBetweenTags(input: CharSequence): SpannableString { + val spannable = SpannableString(input) + var startIndex = 0 + while (true) { + startIndex = input.indexOf("", startIndex) + if (startIndex == -1) break + val endIndex = input.indexOf("", startIndex + 3) + if (endIndex == -1) break + spannable.setSpan(StyleSpan(Typeface.BOLD),startIndex + 3, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + startIndex = endIndex + 4 + } + return spannable + } } fun T.runIf(condition: Boolean, block: T.() -> R): R where T: R = if (condition) block() else this