mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-11 17:48:23 +00:00
Merge dev (#1468)
* Remove unused sizeResId * Fix caching * Prefix message with name in HomeActivity * Hide sender prefix for note to self * Hide sender prefix for control messages * Remove problematic getLastMessage() * Refactor snippet formatting * Remove unused RecoveryPhraseRestoreActivity * Fix unresolved theme attributes exception * Fix dialog button style * Investigation in progress * Working fix push before cleanup * Fixes #1346 * Removed unused logging imports * Put back some whitespace * Minor cleanup * Fix NPE on null display name * fix: disappearing viewmodel tests (#1432) * SES-1354 - Video call self viewer not mirrored (#1397) * Fixes #874 * Removed accidentally left in line * Fixed issue - push before cleanup * Cleaned up * Removed cruft --------- Co-authored-by: = <=> Co-authored-by: AL-Session <160798022+AL-Session@users.noreply.github.com> * SES-1145 - New messages are hidden under keyboard - MK3 (#1415) * WIP * Working - push before cleanup * Fixes #1316 * Cleanup * PR review adjustments * Fixed scrolling when receiving an image based message while keyboard is up * Prevent auto-scroll to last seen item pos in conversation view if <= 3 * Put back <=3 check to scroll --------- Co-authored-by: = <=> Co-authored-by: AL-Session <160798022+AL-Session@users.noreply.github.com> * Fix missing parenthesis * SES-789 - Scroll to bottom of long new message(s) (#1426) * WIP * Working - push before cleanup * Fixes #1316 * Cleanup * PR review adjustments * Fixed scrolling when receiving an image based message while keyboard is up * Prevent auto-scroll to last seen item pos in conversation view if <= 3 * Put back <=3 check to scroll * Forced scrolling to bottom of long messages (both sent and received) when already at the bottom of the RecyclerView * Fixes #1364 --------- Co-authored-by: = <=> Co-authored-by: AL-Session <160798022+AL-Session@users.noreply.github.com> * SES-1352 - User and group names allowing multi-line strings (#1395) * Fix WIP * Resolved issue - pushing before cleanup & PR tomorrow morning * Enforced single line for new closed group names * Fixes #1394 * Final cleanup prior to PR * Added code to restore a previous contact nickname if an empty one is given * Added initial limits to nicknames and group names, both creation and display * Minor adjustments * Adjusted max nickname and group name to 35 chars as per Kee's instructions * Fixed closed group edit text able to get too wide and cut off buttons --------- Co-authored-by: = <=> Co-authored-by: AL-Session <160798022+AL-Session@users.noreply.github.com> Co-authored-by: Al Lansley <al@oxen.io> * SES-212 - Always show delivery status of last sent message - FINAL! (#1418) * Fixes #1408 * Addressed PR feedback * Cleanup * PR adjustments * Further PR adjustments * Updated libsession-util * Added fix for crash when no messages * Ignoring dirty submodules so they don't show up in git * Re-fixed display of delivery status on last sent message (got broken by disappearing messages) * Removed ignore dirty modules line in .gitmodules as it all seems to be playing nice now --------- Co-authored-by: AL-Session <160798022+AL-Session@users.noreply.github.com> Co-authored-by: Al Lansley <al@oxen.io> * fix: use a set for the from/to serialized lists (#1370) * Fixes #1347 (#1396) Co-authored-by: AL-Session <160798022+AL-Session@users.noreply.github.com> Co-authored-by: Al Lansley <al@oxen.io> * SES-1156 - Ban and delete functionality fix (#1428) * WIP * Investigation in progress * End of day push * WIP * Fixes #1416 * Cleanup * Added code to remove zombie messages caught in limbo during a ban & delete - still chock full o' debug while finding root cause * Root cause debug WIP * Push prior to cleanup * Cleaned up for PR * fix: mms delete, remove unnecessary values from sms * Addressed PR feedback * fix: fix unit tests * Added '.run' folder with test setup * Update README.md Test commit for CI * Re-added accidentally removed closing brace --------- Co-authored-by: alansley <aclansley@gmail.com> Co-authored-by: Al Lansley <alansley@users.noreply.github.com> Co-authored-by: 0x330a <92654767+0x330a@users.noreply.github.com> * SES-1356 - List of recently used reaction emojis is not accurate (#1400) * WIP * Further WIP * Push prior to cleanup * Fixes #1015 * Added limiting to the count of recently used emoji that we store * Put back adjusted reaction pill layout to standard * Adjusted recently used reaction emojis already in list to go to start of list --------- Co-authored-by: = <=> * SES-697 - Add loading state when exporting logs (#1402) * WIP * Fixes #1401 * Cleanup from PR view * Final cleanup * Removed commented line of code & re-ordered comment * Addressed PR feedback * Re-allowed loading of avatars to throw exceptions rather than return null on failure --------- Co-authored-by: = <=> * SES-1251 - App crash on non alphanumeric first char search (#1393) * Investigation in progress * Working fix push before cleanup * Fixes #1346 * Removed unused logging imports * Put back some whitespace * Minor cleanup * Push before cleanup * Fixes #1346 - properly this time! * SES1567 - Community message delivery status fix (#1442) * Initial investigation * WIP * Continued work to track down cause of delivery status issue * Fixes #1438 * Cleanup for PR * Further cleanup * Fixed merge conflict * Addressed PR feedback --------- Co-authored-by: alansley <aclansley@gmail.com> * Tiny adjustment to center user name in Settings activity (#1446) * Addressed PR feedback * Cleanup * Initial fix implemented * Fixes #1448 * Addressed PR feedback * SES1688 - Deleting last message in conversation, group, or community leaves the RecyclerView in a broken state (#1449) * Initial fix implemented * Fixes #1448 * Addressed PR feedback * Handle case where there are no messages * build: update build number * Fix spacing when title is absent * Hide reply button in MessageDetails for group invitations * Remove reply from context menu for open group invitations * Ignore swipe reply to open group invitation * Fix multiple quote previews * Fix message menu icons not visible in light theme * Hide reply app bar menu item for open group invite * SES-1727 Mentions text is the wrong colour (#1454) * Fixes #1453 * Cleanup * Code review adjustments * Adjusted mentions to use the accent colour as their background colour when using light themes --------- Co-authored-by: alansley <aclansley@gmail.com> * Disable swipe to reply on open group invites * Fix multiple link previews * SES1718 - Message Sending Status (#1462) * Investigation in progress * Initial push for PR * Fixes #1461 * Removed leftover debug comments * Added minor optimisation to showMessageStatus method (bail early if the message isn't one we care about displaying details of to the user) * Minor cleanup * Tiny cleanup * Addressed PR feedback * Removed forgotten debug log line & forced delivery status elements to be removed on non-visible messages just in case * Minor refactor to simplify 'VisibleMessageView.showStatusMessage' --------- Co-authored-by: alansley <aclansley@gmail.com> * Fix margins * WIP * Commit before converting SmsDatabase from Java to Kotlin * Remove old expiration config strings from UpdateMessageBuilder * Fix group expiration update config messages * Fixed conversation view closing + hopefully wrong status text displayed + deletion of contact on removal of last message in 1-on-1 convo * Cleanup for PR review * Implemented PR feedback * Don't start expiration for group expiration update messages * Fix expiry update message for groups * Correctly don't start disappear timer on group timer updates * SES1813 - Fix regression test failures (#1473) * Initial fix for regression test failure 1.1 * Added permissions fix for sharing documents which should allow for thumbnail generation * Minor touch-up prior to merge into dev * Fixes #1813 * Fixes #1472 - please ignore previous fixes 1813 statement, I'd used the Jira ticket number rather than creating a GitHub issue and using that --------- Co-authored-by: alansley <aclansley@gmail.com> --------- Co-authored-by: alansley <aclansley@gmail.com> Co-authored-by: 0x330a <92654767+0x330a@users.noreply.github.com> Co-authored-by: Al Lansley <alansley@users.noreply.github.com> Co-authored-by: AL-Session <160798022+AL-Session@users.noreply.github.com> Co-authored-by: Al Lansley <al@oxen.io>
This commit is contained in:
@@ -8,9 +8,11 @@ import androidx.annotation.Nullable;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.session.libsession.utilities.Address;
|
||||
import org.session.libsignal.utilities.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -22,9 +24,9 @@ public class AvatarHelper {
|
||||
private static final String AVATAR_DIRECTORY = "avatars";
|
||||
|
||||
public static InputStream getInputStreamFor(@NonNull Context context, @NonNull Address address)
|
||||
throws IOException
|
||||
throws FileNotFoundException
|
||||
{
|
||||
return new FileInputStream(getAvatarFile(context, address));
|
||||
return new FileInputStream(getAvatarFile(context, address));
|
||||
}
|
||||
|
||||
public static List<File> getAvatarFiles(@NonNull Context context) {
|
||||
|
@@ -8,6 +8,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import org.session.libsession.utilities.Address;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
@@ -24,7 +25,7 @@ public class ProfileContactPhoto implements ContactPhoto {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openInputStream(Context context) throws IOException {
|
||||
public InputStream openInputStream(Context context) throws FileNotFoundException {
|
||||
return AvatarHelper.getInputStreamFor(context, address);
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@ import android.graphics.drawable.LayerDrawable;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
|
||||
import com.amulyakhare.textdrawable.TextDrawable;
|
||||
import com.makeramen.roundedimageview.RoundedDrawable;
|
||||
@@ -31,7 +32,7 @@ public class ResourceContactPhoto implements FallbackContactPhoto {
|
||||
@Override
|
||||
public Drawable asDrawable(Context context, int color, boolean inverted) {
|
||||
Drawable background = TextDrawable.builder().buildRound(" ", inverted ? Color.WHITE : color);
|
||||
RoundedDrawable foreground = (RoundedDrawable) RoundedDrawable.fromDrawable(context.getResources().getDrawable(resourceId));
|
||||
RoundedDrawable foreground = (RoundedDrawable) RoundedDrawable.fromDrawable(AppCompatResources.getDrawable(context, resourceId));
|
||||
|
||||
foreground.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
|
||||
@@ -39,8 +40,10 @@ public class ResourceContactPhoto implements FallbackContactPhoto {
|
||||
foreground.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
Drawable gradient = context.getResources().getDrawable(ThemeUtil.isDarkTheme(context) ? R.drawable.avatar_gradient_dark
|
||||
: R.drawable.avatar_gradient_light);
|
||||
Drawable gradient = AppCompatResources.getDrawable(
|
||||
context,
|
||||
ThemeUtil.isDarkTheme(context) ? R.drawable.avatar_gradient_dark : R.drawable.avatar_gradient_light
|
||||
);
|
||||
|
||||
return new ExpandingLayerDrawable(new Drawable[] {background, foreground, gradient});
|
||||
}
|
||||
|
@@ -120,7 +120,9 @@ interface StorageProtocol {
|
||||
fun markAsSyncing(timestamp: Long, author: String)
|
||||
fun markAsSending(timestamp: Long, author: String)
|
||||
fun markAsSent(timestamp: Long, author: String)
|
||||
fun markAsSentToCommunity(threadID: Long, messageID: Long)
|
||||
fun markUnidentified(timestamp: Long, author: String)
|
||||
fun markUnidentifiedInCommunity(threadID: Long, messageID: Long)
|
||||
fun markAsSyncFailed(timestamp: Long, author: String, error: Exception)
|
||||
fun markAsSentFailed(timestamp: Long, author: String, error: Exception)
|
||||
fun clearErrorMessage(messageID: Long)
|
||||
|
@@ -77,7 +77,7 @@ class Contact(val sessionID: String) {
|
||||
companion object {
|
||||
|
||||
fun contextForRecipient(recipient: Recipient): ContactContext {
|
||||
return if (recipient.isOpenGroupRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
|
||||
return if (recipient.isCommunityRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,7 +22,7 @@ class OpenGroupDeleteJob(private val messageServerIds: LongArray, private val th
|
||||
override suspend fun execute(dispatcherName: String) {
|
||||
val dataProvider = MessagingModuleConfiguration.shared.messageDataProvider
|
||||
val numberToDelete = messageServerIds.size
|
||||
Log.d(TAG, "Deleting $numberToDelete messages")
|
||||
Log.d(TAG, "About to attempt to delete $numberToDelete messages")
|
||||
|
||||
// FIXME: This entire process should probably run in a transaction (with the attachment deletion happening only if it succeeded)
|
||||
try {
|
||||
@@ -42,6 +42,7 @@ class OpenGroupDeleteJob(private val messageServerIds: LongArray, private val th
|
||||
delegate?.handleJobSucceeded(this, dispatcherName)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
Log.w(TAG, "OpenGroupDeleteJob failed: $e")
|
||||
delegate?.handleJobFailed(this, dispatcherName, e)
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@ package org.session.libsession.messaging.mentions
|
||||
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
|
||||
object MentionsManager {
|
||||
var userPublicKeyCache = mutableMapOf<Long, Set<String>>() // Thread ID to set of user hex encoded public keys
|
||||
|
@@ -43,14 +43,14 @@ sealed class Destination {
|
||||
val groupPublicKey = GroupUtil.doubleDecodeGroupID(groupID).toHexString()
|
||||
ClosedGroup(groupPublicKey)
|
||||
}
|
||||
address.isOpenGroup -> {
|
||||
address.isCommunity -> {
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val threadID = storage.getThreadId(address)!!
|
||||
storage.getOpenGroup(threadID)?.let {
|
||||
OpenGroup(roomToken = it.room, server = it.server, fileIds = fileIds)
|
||||
} ?: throw Exception("Missing open group for thread with ID: $threadID.")
|
||||
}
|
||||
address.isOpenGroupInbox -> {
|
||||
address.isCommunityInbox -> {
|
||||
val groupInboxId = GroupUtil.getDecodedGroupID(address.serialize()).split("!")
|
||||
OpenGroupInbox(
|
||||
groupInboxId.dropLast(2).joinToString("!"),
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package org.session.libsession.messaging.messages
|
||||
|
||||
import network.loki.messenger.libsession_util.util.ExpiryMode
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
|
||||
data class ExpirationConfiguration(
|
||||
val threadId: Long = -1,
|
||||
@@ -11,7 +10,7 @@ data class ExpirationConfiguration(
|
||||
val isEnabled = expiryMode.expirySeconds > 0
|
||||
|
||||
companion object {
|
||||
val isNewConfigEnabled = SnodeAPI.nowWithOffset >= 1710284400000
|
||||
val isNewConfigEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,10 +4,11 @@ import com.google.protobuf.ByteString
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
|
||||
class Profile() {
|
||||
var displayName: String? = null
|
||||
var profileKey: ByteArray? = null
|
||||
class Profile(
|
||||
var displayName: String? = null,
|
||||
var profileKey: ByteArray? = null,
|
||||
var profilePictureURL: String? = null
|
||||
) {
|
||||
|
||||
companion object {
|
||||
const val TAG = "Profile"
|
||||
@@ -25,12 +26,6 @@ class Profile() {
|
||||
}
|
||||
}
|
||||
|
||||
constructor(displayName: String, profileKey: ByteArray? = null, profilePictureURL: String? = null) : this() {
|
||||
this.displayName = displayName
|
||||
this.profileKey = profileKey
|
||||
this.profilePictureURL = profilePictureURL
|
||||
}
|
||||
|
||||
fun toProto(): SignalServiceProtos.DataMessage? {
|
||||
val displayName = displayName
|
||||
if (displayName == null) {
|
||||
|
@@ -602,8 +602,7 @@ object OpenGroupApi {
|
||||
// region Message Deletion
|
||||
@JvmStatic
|
||||
fun deleteMessage(serverID: Long, room: String, server: String): Promise<Unit, Exception> {
|
||||
val request =
|
||||
Request(verb = DELETE, room = room, server = server, endpoint = Endpoint.RoomMessageIndividual(room, serverID))
|
||||
val request = Request(verb = DELETE, room = room, server = server, endpoint = Endpoint.RoomMessageIndividual(room, serverID))
|
||||
return send(request).map {
|
||||
Log.d("Loki", "Message deletion successful.")
|
||||
}
|
||||
@@ -659,7 +658,9 @@ object OpenGroupApi {
|
||||
}
|
||||
|
||||
fun banAndDeleteAll(publicKey: String, room: String, server: String): Promise<Unit, Exception> {
|
||||
|
||||
val requests = mutableListOf<BatchRequestInfo<*>>(
|
||||
// Ban request
|
||||
BatchRequestInfo(
|
||||
request = BatchRequest(
|
||||
method = POST,
|
||||
@@ -669,6 +670,7 @@ object OpenGroupApi {
|
||||
endpoint = Endpoint.UserBan(publicKey),
|
||||
responseType = object: TypeReference<Any>(){}
|
||||
),
|
||||
// Delete request
|
||||
BatchRequestInfo(
|
||||
request = BatchRequest(DELETE, "/room/$room/all/$publicKey"),
|
||||
endpoint = Endpoint.RoomDeleteMessages(room, publicKey),
|
||||
|
@@ -39,6 +39,7 @@ import org.session.libsignal.crypto.PushTransportDetails
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.Base64
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.Namespace
|
||||
import org.session.libsignal.utilities.defaultRequiresAuth
|
||||
import org.session.libsignal.utilities.hasNamespaces
|
||||
@@ -370,7 +371,7 @@ object MessageSender {
|
||||
}
|
||||
|
||||
// Result Handling
|
||||
fun handleSuccessfulMessageSend(message: Message, destination: Destination, isSyncMessage: Boolean = false, openGroupSentTimestamp: Long = -1) {
|
||||
private fun handleSuccessfulMessageSend(message: Message, destination: Destination, isSyncMessage: Boolean = false, openGroupSentTimestamp: Long = -1) {
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val userPublicKey = storage.getUserPublicKey()!!
|
||||
val timestamp = message.sentTimestamp!!
|
||||
@@ -392,8 +393,10 @@ object MessageSender {
|
||||
|
||||
// in case any errors from previous sends
|
||||
storage.clearErrorMessage(messageID)
|
||||
|
||||
// Track the open group server message ID
|
||||
if (message.openGroupServerMessageID != null && (destination is Destination.LegacyOpenGroup || destination is Destination.OpenGroup)) {
|
||||
val messageIsAddressedToCommunity = message.openGroupServerMessageID != null && (destination is Destination.LegacyOpenGroup || destination is Destination.OpenGroup)
|
||||
if (messageIsAddressedToCommunity) {
|
||||
val server: String
|
||||
val room: String
|
||||
when (destination) {
|
||||
@@ -415,9 +418,26 @@ object MessageSender {
|
||||
storage.setOpenGroupServerMessageID(messageID, message.openGroupServerMessageID!!, threadID, !(message as VisibleMessage).isMediaMessage())
|
||||
}
|
||||
}
|
||||
// Mark the message as sent
|
||||
storage.markAsSent(timestamp, userPublicKey)
|
||||
storage.markUnidentified(timestamp, userPublicKey)
|
||||
|
||||
// Mark the message as sent.
|
||||
// Note: When sending a message to a community the server modifies the message timestamp
|
||||
// so when we go to look up the message in the local database by timestamp it fails and
|
||||
// we're left with the message delivery status as "Sending" forever! As such, we use a
|
||||
// pair of modified "markAsSentToCommunity" and "markUnidentifiedInCommunity" methods
|
||||
// to retrieve the local message by thread & message ID rather than timestamp when
|
||||
// handling community messages only so we can tick the delivery status over to 'Sent'.
|
||||
// Fixed in: https://optf.atlassian.net/browse/SES-1567
|
||||
if (messageIsAddressedToCommunity)
|
||||
{
|
||||
storage.markAsSentToCommunity(message.threadID!!, message.id!!)
|
||||
storage.markUnidentifiedInCommunity(message.threadID!!, message.id!!)
|
||||
}
|
||||
else
|
||||
{
|
||||
storage.markAsSent(timestamp, userPublicKey)
|
||||
storage.markUnidentified(timestamp, userPublicKey)
|
||||
}
|
||||
|
||||
// Start the disappearing messages timer if needed
|
||||
SSKEnvironment.shared.messageExpirationManager.maybeStartExpiration(message, startDisappearAfterRead = true)
|
||||
} ?: run {
|
||||
|
@@ -10,11 +10,11 @@ import org.session.libsession.messaging.calls.CallMessageType.CALL_INCOMING
|
||||
import org.session.libsession.messaging.calls.CallMessageType.CALL_MISSED
|
||||
import org.session.libsession.messaging.calls.CallMessageType.CALL_OUTGOING
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.messages.ExpirationConfiguration.Companion.isNewConfigEnabled
|
||||
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
|
||||
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED
|
||||
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage.Kind.SCREENSHOT
|
||||
import org.session.libsession.utilities.ExpirationUtil
|
||||
import org.session.libsession.utilities.getExpirationTypeDisplayValue
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.truncateIdForDisplay
|
||||
|
||||
object UpdateMessageBuilder {
|
||||
@@ -31,47 +31,35 @@ object UpdateMessageBuilder {
|
||||
else getSenderName(senderId!!)
|
||||
|
||||
return when (updateData) {
|
||||
is UpdateMessageData.Kind.GroupCreation -> if (isOutgoing) {
|
||||
context.getString(R.string.MessageRecord_you_created_a_new_group)
|
||||
} else {
|
||||
context.getString(R.string.MessageRecord_s_added_you_to_the_group, senderName)
|
||||
is UpdateMessageData.Kind.GroupCreation -> {
|
||||
if (isOutgoing) context.getString(R.string.MessageRecord_you_created_a_new_group)
|
||||
else context.getString(R.string.MessageRecord_s_added_you_to_the_group, senderName)
|
||||
}
|
||||
is UpdateMessageData.Kind.GroupNameChange -> if (isOutgoing) {
|
||||
context.getString(R.string.MessageRecord_you_renamed_the_group_to_s, updateData.name)
|
||||
} else {
|
||||
context.getString(R.string.MessageRecord_s_renamed_the_group_to_s, senderName, updateData.name)
|
||||
is UpdateMessageData.Kind.GroupNameChange -> {
|
||||
if (isOutgoing) context.getString(R.string.MessageRecord_you_renamed_the_group_to_s, updateData.name)
|
||||
else context.getString(R.string.MessageRecord_s_renamed_the_group_to_s, senderName, updateData.name)
|
||||
}
|
||||
is UpdateMessageData.Kind.GroupMemberAdded -> {
|
||||
val members = updateData.updatedMembers.joinToString(", ", transform = ::getSenderName)
|
||||
if (isOutgoing) {
|
||||
context.getString(R.string.MessageRecord_you_added_s_to_the_group, members)
|
||||
} else {
|
||||
context.getString(R.string.MessageRecord_s_added_s_to_the_group, senderName, members)
|
||||
}
|
||||
if (isOutgoing) context.getString(R.string.MessageRecord_you_added_s_to_the_group, members)
|
||||
else context.getString(R.string.MessageRecord_s_added_s_to_the_group, senderName, members)
|
||||
}
|
||||
is UpdateMessageData.Kind.GroupMemberRemoved -> {
|
||||
val userPublicKey = storage.getUserPublicKey()!!
|
||||
// 1st case: you are part of the removed members
|
||||
return if (userPublicKey in updateData.updatedMembers) {
|
||||
if (isOutgoing) {
|
||||
context.getString(R.string.MessageRecord_left_group)
|
||||
} else {
|
||||
context.getString(R.string.MessageRecord_you_were_removed_from_the_group)
|
||||
}
|
||||
if (isOutgoing) context.getString(R.string.MessageRecord_left_group)
|
||||
else context.getString(R.string.MessageRecord_you_were_removed_from_the_group)
|
||||
} else {
|
||||
// 2nd case: you are not part of the removed members
|
||||
val members = updateData.updatedMembers.joinToString(", ", transform = ::getSenderName)
|
||||
if (isOutgoing) {
|
||||
context.getString(R.string.MessageRecord_you_removed_s_from_the_group, members)
|
||||
} else {
|
||||
context.getString(R.string.MessageRecord_s_removed_s_from_the_group, senderName, members)
|
||||
}
|
||||
if (isOutgoing) context.getString(R.string.MessageRecord_you_removed_s_from_the_group, members)
|
||||
else context.getString(R.string.MessageRecord_s_removed_s_from_the_group, senderName, members)
|
||||
}
|
||||
}
|
||||
is UpdateMessageData.Kind.GroupMemberLeft -> if (isOutgoing) {
|
||||
context.getString(R.string.MessageRecord_left_group)
|
||||
} else {
|
||||
context.getString(R.string.ConversationItem_group_action_left, senderName)
|
||||
is UpdateMessageData.Kind.GroupMemberLeft -> {
|
||||
if (isOutgoing) context.getString(R.string.MessageRecord_left_group)
|
||||
else context.getString(R.string.ConversationItem_group_action_left, senderName)
|
||||
}
|
||||
else -> return ""
|
||||
}
|
||||
@@ -80,7 +68,7 @@ object UpdateMessageBuilder {
|
||||
fun buildExpirationTimerMessage(
|
||||
context: Context,
|
||||
duration: Long,
|
||||
recipient: Recipient,
|
||||
isGroup: Boolean,
|
||||
senderId: String? = null,
|
||||
isOutgoing: Boolean = false,
|
||||
timestamp: Long,
|
||||
@@ -89,44 +77,28 @@ object UpdateMessageBuilder {
|
||||
if (!isOutgoing && senderId == null) return ""
|
||||
val senderName = if (isOutgoing) context.getString(R.string.MessageRecord_you) else getSenderName(senderId!!)
|
||||
return if (duration <= 0) {
|
||||
if (isOutgoing) {
|
||||
if (!isNewConfigEnabled) context.getString(R.string.MessageRecord_you_disabled_disappearing_messages)
|
||||
else context.getString(if (recipient.is1on1) R.string.MessageRecord_you_turned_off_disappearing_messages_1_on_1 else R.string.MessageRecord_you_turned_off_disappearing_messages)
|
||||
} else {
|
||||
if (!isNewConfigEnabled) context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, senderName)
|
||||
else context.getString(if (recipient.is1on1) R.string.MessageRecord_s_turned_off_disappearing_messages_1_on_1 else R.string.MessageRecord_s_turned_off_disappearing_messages, senderName)
|
||||
}
|
||||
if (isOutgoing) context.getString(if (isGroup) R.string.MessageRecord_you_turned_off_disappearing_messages else R.string.MessageRecord_you_turned_off_disappearing_messages_1_on_1)
|
||||
else context.getString(if (isGroup) R.string.MessageRecord_s_turned_off_disappearing_messages else R.string.MessageRecord_s_turned_off_disappearing_messages_1_on_1, senderName)
|
||||
} else {
|
||||
val time = ExpirationUtil.getExpirationDisplayValue(context, duration.toInt())
|
||||
val action = context.getExpirationTypeDisplayValue(timestamp == expireStarted)
|
||||
if (isOutgoing) {
|
||||
if (!isNewConfigEnabled) context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time)
|
||||
else context.getString(
|
||||
if (recipient.is1on1) R.string.MessageRecord_you_set_messages_to_disappear_s_after_s_1_on_1 else R.string.MessageRecord_you_set_messages_to_disappear_s_after_s,
|
||||
time,
|
||||
action
|
||||
)
|
||||
} else {
|
||||
if (!isNewConfigEnabled) context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, senderName, time)
|
||||
else context.getString(
|
||||
if (recipient.is1on1) R.string.MessageRecord_s_set_messages_to_disappear_s_after_s_1_on_1 else R.string.MessageRecord_s_set_messages_to_disappear_s_after_s,
|
||||
senderName,
|
||||
time,
|
||||
action
|
||||
)
|
||||
}
|
||||
val action = context.getExpirationTypeDisplayValue(timestamp >= expireStarted)
|
||||
if (isOutgoing) context.getString(
|
||||
if (isGroup) R.string.MessageRecord_you_set_messages_to_disappear_s_after_s else R.string.MessageRecord_you_set_messages_to_disappear_s_after_s_1_on_1,
|
||||
time,
|
||||
action
|
||||
) else context.getString(
|
||||
if (isGroup) R.string.MessageRecord_s_set_messages_to_disappear_s_after_s else R.string.MessageRecord_s_set_messages_to_disappear_s_after_s_1_on_1,
|
||||
senderName,
|
||||
time,
|
||||
action
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun buildDataExtractionMessage(context: Context, kind: DataExtractionNotificationInfoMessage.Kind, senderId: String? = null): String {
|
||||
val senderName = getSenderName(senderId!!)
|
||||
return when (kind) {
|
||||
DataExtractionNotificationInfoMessage.Kind.SCREENSHOT ->
|
||||
context.getString(R.string.MessageRecord_s_took_a_screenshot, senderName)
|
||||
DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED ->
|
||||
context.getString(R.string.MessageRecord_media_saved_by_s, senderName)
|
||||
}
|
||||
}
|
||||
fun buildDataExtractionMessage(context: Context, kind: DataExtractionNotificationInfoMessage.Kind, senderId: String? = null) = when (kind) {
|
||||
SCREENSHOT -> R.string.MessageRecord_s_took_a_screenshot
|
||||
MEDIA_SAVED -> R.string.MessageRecord_media_saved_by_s
|
||||
}.let { context.getString(it, getSenderName(senderId!!)) }
|
||||
|
||||
fun buildCallMessage(context: Context, type: CallMessageType, sender: String): String =
|
||||
when (type) {
|
||||
|
@@ -8,7 +8,6 @@ import androidx.annotation.VisibleForTesting
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.Util
|
||||
import org.session.libsignal.utilities.guava.Optional
|
||||
import java.util.Collections
|
||||
import java.util.LinkedList
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.regex.Matcher
|
||||
@@ -23,17 +22,17 @@ class Address private constructor(address: String) : Parcelable, Comparable<Addr
|
||||
get() = GroupUtil.isEncodedGroup(address)
|
||||
val isClosedGroup: Boolean
|
||||
get() = GroupUtil.isClosedGroup(address)
|
||||
val isOpenGroup: Boolean
|
||||
get() = GroupUtil.isOpenGroup(address)
|
||||
val isOpenGroupInbox: Boolean
|
||||
get() = GroupUtil.isOpenGroupInbox(address)
|
||||
val isOpenGroupOutbox: Boolean
|
||||
val isCommunity: Boolean
|
||||
get() = GroupUtil.isCommunity(address)
|
||||
val isCommunityInbox: Boolean
|
||||
get() = GroupUtil.isCommunityInbox(address)
|
||||
val isCommunityOutbox: Boolean
|
||||
get() = address.startsWith(IdPrefix.BLINDED.value) || address.startsWith(IdPrefix.BLINDEDV2.value)
|
||||
val isContact: Boolean
|
||||
get() = !(isGroup || isOpenGroupInbox)
|
||||
get() = !(isGroup || isCommunityInbox)
|
||||
|
||||
fun contactIdentifier(): String {
|
||||
if (!isContact && !isOpenGroup) {
|
||||
if (!isContact && !isCommunity) {
|
||||
if (isGroup) throw AssertionError("Not e164, is group")
|
||||
throw AssertionError("Not e164, unknown")
|
||||
}
|
||||
@@ -168,8 +167,9 @@ class Address private constructor(address: String) : Parcelable, Comparable<Addr
|
||||
@JvmStatic
|
||||
fun fromSerializedList(serialized: String, delimiter: Char): List<Address> {
|
||||
val escapedAddresses = DelimiterUtil.split(serialized, delimiter)
|
||||
val set = escapedAddresses.toSet().sorted()
|
||||
val addresses: MutableList<Address> = LinkedList()
|
||||
for (escapedAddress in escapedAddresses) {
|
||||
for (escapedAddress in set) {
|
||||
addresses.add(fromSerialized(DelimiterUtil.unescape(escapedAddress, delimiter)))
|
||||
}
|
||||
return addresses
|
||||
@@ -177,9 +177,9 @@ class Address private constructor(address: String) : Parcelable, Comparable<Addr
|
||||
|
||||
@JvmStatic
|
||||
fun toSerializedList(addresses: List<Address>, delimiter: Char): String {
|
||||
Collections.sort(addresses)
|
||||
val set = addresses.toSet().sorted()
|
||||
val escapedAddresses: MutableList<String> = LinkedList()
|
||||
for (address in addresses) {
|
||||
for (address in set) {
|
||||
escapedAddresses.add(DelimiterUtil.escape(address.serialize(), delimiter))
|
||||
}
|
||||
return Util.join(escapedAddresses, delimiter.toString() + "")
|
||||
|
@@ -22,7 +22,7 @@ class GroupRecord(
|
||||
}
|
||||
|
||||
val isOpenGroup: Boolean
|
||||
get() = Address.fromSerialized(encodedId).isOpenGroup
|
||||
get() = Address.fromSerialized(encodedId).isCommunity
|
||||
val isClosedGroup: Boolean
|
||||
get() = Address.fromSerialized(encodedId).isClosedGroup
|
||||
|
||||
|
@@ -8,12 +8,12 @@ import java.io.IOException
|
||||
|
||||
object GroupUtil {
|
||||
const val CLOSED_GROUP_PREFIX = "__textsecure_group__!"
|
||||
const val OPEN_GROUP_PREFIX = "__loki_public_chat_group__!"
|
||||
const val OPEN_GROUP_INBOX_PREFIX = "__open_group_inbox__!"
|
||||
const val COMMUNITY_PREFIX = "__loki_public_chat_group__!"
|
||||
const val COMMUNITY_INBOX_PREFIX = "__open_group_inbox__!"
|
||||
|
||||
@JvmStatic
|
||||
fun getEncodedOpenGroupID(groupID: ByteArray): String {
|
||||
return OPEN_GROUP_PREFIX + Hex.toStringCondensed(groupID)
|
||||
return COMMUNITY_PREFIX + Hex.toStringCondensed(groupID)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@@ -25,7 +25,7 @@ object GroupUtil {
|
||||
|
||||
@JvmStatic
|
||||
fun getEncodedOpenGroupInboxID(groupInboxID: ByteArray): Address {
|
||||
return Address.fromSerialized(OPEN_GROUP_INBOX_PREFIX + Hex.toStringCondensed(groupInboxID))
|
||||
return Address.fromSerialized(COMMUNITY_INBOX_PREFIX + Hex.toStringCondensed(groupInboxID))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@@ -69,17 +69,17 @@ object GroupUtil {
|
||||
}
|
||||
|
||||
fun isEncodedGroup(groupId: String): Boolean {
|
||||
return groupId.startsWith(CLOSED_GROUP_PREFIX) || groupId.startsWith(OPEN_GROUP_PREFIX)
|
||||
return groupId.startsWith(CLOSED_GROUP_PREFIX) || groupId.startsWith(COMMUNITY_PREFIX)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isOpenGroup(groupId: String): Boolean {
|
||||
return groupId.startsWith(OPEN_GROUP_PREFIX)
|
||||
fun isCommunity(groupId: String): Boolean {
|
||||
return groupId.startsWith(COMMUNITY_PREFIX)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isOpenGroupInbox(groupId: String): Boolean {
|
||||
return groupId.startsWith(OPEN_GROUP_INBOX_PREFIX)
|
||||
fun isCommunityInbox(groupId: String): Boolean {
|
||||
return groupId.startsWith(COMMUNITY_INBOX_PREFIX)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@@ -842,7 +842,7 @@ interface TextSecurePreferences {
|
||||
getDefaultSharedPreferences(context).edit().putString(key, value).apply()
|
||||
}
|
||||
|
||||
private fun getIntegerPreference(context: Context, key: String, defaultValue: Int): Int {
|
||||
fun getIntegerPreference(context: Context, key: String, defaultValue: Int): Int {
|
||||
return getDefaultSharedPreferences(context).getInt(key, defaultValue)
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,10 @@ public class ThemeUtil {
|
||||
return getAttributeText(context, R.attr.theme_type, "light").equals("dark");
|
||||
}
|
||||
|
||||
public static boolean isLightTheme(@NonNull Context context) {
|
||||
return getAttributeText(context, R.attr.theme_type, "light").equals("light");
|
||||
}
|
||||
|
||||
public static boolean getThemedBoolean(@NonNull Context context, @AttrRes int attr) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = context.getTheme();
|
||||
|
@@ -459,16 +459,16 @@ public class Recipient implements RecipientModifiedListener {
|
||||
}
|
||||
public boolean is1on1() { return address.isContact() && !isLocalNumber; }
|
||||
|
||||
public boolean isOpenGroupRecipient() {
|
||||
return address.isOpenGroup();
|
||||
public boolean isCommunityRecipient() {
|
||||
return address.isCommunity();
|
||||
}
|
||||
|
||||
public boolean isOpenGroupOutboxRecipient() {
|
||||
return address.isOpenGroupOutbox();
|
||||
return address.isCommunityOutbox();
|
||||
}
|
||||
|
||||
public boolean isOpenGroupInboxRecipient() {
|
||||
return address.isOpenGroupInbox();
|
||||
return address.isCommunityInbox();
|
||||
}
|
||||
|
||||
public boolean isClosedGroupRecipient() {
|
||||
|
@@ -15,10 +15,6 @@
|
||||
<string name="MessageRecord_s_called_you">%s vous a appelé·e</string>
|
||||
<string name="MessageRecord_called_s">Vous avez appelé %s</string>
|
||||
<string name="MessageRecord_missed_call_from">Appel manqué de %s</string>
|
||||
<string name="MessageRecord_you_disabled_disappearing_messages">Vous avez désactivé les messages éphémères.</string>
|
||||
<string name="MessageRecord_s_disabled_disappearing_messages">%1$s a désactivé les messages éphémères.</string>
|
||||
<string name="MessageRecord_you_set_disappearing_message_time_to_s">Vous avez défini l’expiration des messages éphémères à %1$s</string>
|
||||
<string name="MessageRecord_s_set_disappearing_message_time_to_s">%1$s a défini l’expiration des messages éphémères à %2$s</string>
|
||||
<string name="MessageRecord_s_took_a_screenshot">%1$s a pris une capture d\'écran.</string>
|
||||
<string name="MessageRecord_media_saved_by_s">%1$s a enregistré le média.</string>
|
||||
<!-- expiration -->
|
||||
|
@@ -15,10 +15,6 @@
|
||||
<string name="MessageRecord_s_called_you">%s vous a appelé·e</string>
|
||||
<string name="MessageRecord_called_s">Vous avez appelé %s</string>
|
||||
<string name="MessageRecord_missed_call_from">Appel manqué de %s</string>
|
||||
<string name="MessageRecord_you_disabled_disappearing_messages">Vous avez désactivé les messages éphémères.</string>
|
||||
<string name="MessageRecord_s_disabled_disappearing_messages">%1$s a désactivé les messages éphémères.</string>
|
||||
<string name="MessageRecord_you_set_disappearing_message_time_to_s">Vous avez défini l’expiration des messages éphémères à %1$s</string>
|
||||
<string name="MessageRecord_s_set_disappearing_message_time_to_s">%1$s a défini l’expiration des messages éphémères à %2$s</string>
|
||||
<string name="MessageRecord_s_took_a_screenshot">%1$s a pris une capture d\'écran.</string>
|
||||
<string name="MessageRecord_media_saved_by_s">%1$s a enregistré le média.</string>
|
||||
<!-- expiration -->
|
||||
|
@@ -17,17 +17,13 @@
|
||||
<string name="MessageRecord_missed_call_from">Missed call from %s</string>
|
||||
<string name="MessageRecord_follow_setting">Follow Setting</string>
|
||||
<string name="AccessibilityId_follow_setting">Follow setting</string>
|
||||
<string name="MessageRecord_you_disabled_disappearing_messages">You disabled disappearing messages.</string>
|
||||
<string name="MessageRecord_you_turned_off_disappearing_messages">You have turned off disappearing messages.</string>
|
||||
<string name="MessageRecord_you_turned_off_disappearing_messages_1_on_1">You turned off disappearing messages. Messages you send will no longer disappear.</string>
|
||||
<string name="MessageRecord_s_disabled_disappearing_messages">%1$s disabled disappearing messages.</string>
|
||||
<string name="MessageRecord_s_turned_off_disappearing_messages">%1$s turned off disappearing messages.</string>
|
||||
<string name="MessageRecord_s_turned_off_disappearing_messages_1_on_1">%1$s has turned off disappearing messages. Messages they send will no longer disappear.</string>
|
||||
<string name="MessageRecord_you_set_disappearing_message_time_to_s">You set the disappearing message timer to %1$s</string>
|
||||
<string name="MessageRecord_you_set_messages_to_disappear_s_after_s">You have set messages to disappear %1$s after they have been %2$s</string>
|
||||
<string name="MessageRecord_you_set_messages_to_disappear_s_after_s_1_on_1">You set your messages to disappear %1$s after they have been %2$s.</string>
|
||||
<string name="MessageRecord_you_changed_messages_to_disappear_s_after_s">You have changed messages to disappear %1$s after they have been %2$s</string>
|
||||
<string name="MessageRecord_s_set_disappearing_message_time_to_s">%1$s set the disappearing message timer to %2$s</string>
|
||||
<string name="MessageRecord_s_set_messages_to_disappear_s_after_s">%1$s has set messages to disappear %2$s after they have been %3$s</string>
|
||||
<string name="MessageRecord_s_set_messages_to_disappear_s_after_s_1_on_1">%1$s has set their messages to disappear %2$s after they have been %3$s.</string>
|
||||
<string name="MessageRecord_s_changed_messages_to_disappear_s_after_s">%1$s has changed messages to disappear %2$s after they have been %3$s</string>
|
||||
|
Reference in New Issue
Block a user