mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Listen for recipient changes in conversations and group updates.
Closes #4079 // FREEBIE
This commit is contained in:
parent
a7e05c4cd6
commit
0794380ca8
@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.thoughtcrime.securesms.ConversationItem
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/conversation_item"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView android:id="@+id/conversation_item_body"
|
||||
android:autoLink="all"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:linksClickable="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:gravity="center"
|
||||
android:textStyle="italic"
|
||||
android:textColor="?attr/conversation_group_member_name"
|
||||
android:textSize="14sp" />
|
||||
<TextView android:id="@+id/conversation_item_date"
|
||||
android:autoLink="all"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:linksClickable="false"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_gravity="right"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:textColor="?conversation_item_sent_text_secondary_color"
|
||||
android:text="date"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</org.thoughtcrime.securesms.ConversationItem>
|
30
res/layout/conversation_item_update.xml
Normal file
30
res/layout/conversation_item_update.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.thoughtcrime.securesms.ConversationUpdateItem
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/conversation_update_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="20dp">
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView android:id="@+id/conversation_update_icon"
|
||||
android:layout_marginRight="7dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView android:id="@+id/conversation_update_body"
|
||||
android:autoLink="all"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:linksClickable="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textStyle="italic"
|
||||
android:textColor="?attr/conversation_group_member_name"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.thoughtcrime.securesms.ConversationUpdateItem>
|
@ -57,7 +57,7 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
|
||||
|
||||
public static final int MESSAGE_TYPE_OUTGOING = 0;
|
||||
public static final int MESSAGE_TYPE_INCOMING = 1;
|
||||
public static final int MESSAGE_TYPE_GROUP_ACTION = 2;
|
||||
public static final int MESSAGE_TYPE_UPDATE = 2;
|
||||
|
||||
private final Set<MessageRecord> batchSelected = Collections.synchronizedSet(new HashSet<MessageRecord>());
|
||||
|
||||
@ -85,13 +85,22 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
ConversationItem item = (ConversationItem)view;
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.ID));
|
||||
String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
|
||||
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
|
||||
|
||||
item.set(masterSecret, messageRecord, locale, batchSelected, selectionClickListener,
|
||||
groupThread, pushDestination);
|
||||
switch (getItemViewType(cursor)) {
|
||||
case MESSAGE_TYPE_INCOMING:
|
||||
case MESSAGE_TYPE_OUTGOING:
|
||||
((ConversationItem) view).set(masterSecret, messageRecord, locale, batchSelected,
|
||||
selectionClickListener, groupThread, pushDestination);
|
||||
break;
|
||||
case MESSAGE_TYPE_UPDATE:
|
||||
((ConversationUpdateItem)view).set(messageRecord);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unknown type!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,8 +122,8 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
|
||||
case ConversationAdapter.MESSAGE_TYPE_INCOMING:
|
||||
view = inflater.inflate(R.layout.conversation_item_received, parent, false);
|
||||
break;
|
||||
case ConversationAdapter.MESSAGE_TYPE_GROUP_ACTION:
|
||||
view = inflater.inflate(R.layout.conversation_item_activity, parent, false);
|
||||
case ConversationAdapter.MESSAGE_TYPE_UPDATE:
|
||||
view = inflater.inflate(R.layout.conversation_item_update, parent, false);
|
||||
break;
|
||||
default: throw new IllegalArgumentException("unsupported item view type given to ConversationAdapter");
|
||||
}
|
||||
@ -138,7 +147,7 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
|
||||
String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
|
||||
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
|
||||
|
||||
if (messageRecord.isGroupAction()) return MESSAGE_TYPE_GROUP_ACTION;
|
||||
if (messageRecord.isGroupAction()) return MESSAGE_TYPE_UPDATE;
|
||||
else if (messageRecord.isOutgoing()) return MESSAGE_TYPE_OUTGOING;
|
||||
else return MESSAGE_TYPE_INCOMING;
|
||||
}
|
||||
@ -181,6 +190,6 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
|
||||
|
||||
@Override
|
||||
public void onMovedToScrapHeap(View view) {
|
||||
((ConversationItem)view).unbind();
|
||||
((Unbindable) view).unbind();
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -73,7 +74,7 @@ import java.util.Set;
|
||||
*
|
||||
*/
|
||||
|
||||
public class ConversationItem extends LinearLayout implements Recipient.RecipientModifiedListener {
|
||||
public class ConversationItem extends LinearLayout implements Recipient.RecipientModifiedListener, Unbindable {
|
||||
private final static String TAG = ConversationItem.class.getSimpleName();
|
||||
|
||||
private MessageRecord messageRecord;
|
||||
@ -181,16 +182,13 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
||||
|
||||
setSelectionBackgroundDrawables(messageRecord);
|
||||
setBodyText(messageRecord);
|
||||
|
||||
if (hasConversationBubble(messageRecord)) {
|
||||
setBubbleState(messageRecord, recipient);
|
||||
setStatusIcons(messageRecord);
|
||||
setContactPhoto(recipient);
|
||||
setGroupMessageStatus(messageRecord, recipient);
|
||||
setEvents(messageRecord);
|
||||
setMinimumWidth();
|
||||
setMediaAttributes(messageRecord);
|
||||
}
|
||||
setBubbleState(messageRecord, recipient);
|
||||
setStatusIcons(messageRecord);
|
||||
setContactPhoto(recipient);
|
||||
setGroupMessageStatus(messageRecord, recipient);
|
||||
setEvents(messageRecord);
|
||||
setMinimumWidth();
|
||||
setMediaAttributes(messageRecord);
|
||||
}
|
||||
|
||||
private void initializeAttributes() {
|
||||
@ -205,6 +203,7 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
||||
attrs.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (recipient != null) {
|
||||
recipient.removeListener(this);
|
||||
@ -236,10 +235,6 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasConversationBubble(MessageRecord messageRecord) {
|
||||
return !messageRecord.isGroupAction();
|
||||
}
|
||||
|
||||
private boolean isCaptionlessMms(MessageRecord messageRecord) {
|
||||
return TextUtils.isEmpty(messageRecord.getDisplayBody()) && messageRecord.isMms();
|
||||
}
|
||||
@ -403,12 +398,15 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipient recipient) {
|
||||
if (hasConversationBubble(messageRecord)) {
|
||||
setBubbleState(messageRecord, recipient);
|
||||
setContactPhoto(recipient);
|
||||
setGroupMessageStatus(messageRecord, recipient);
|
||||
}
|
||||
public void onModified(final Recipient recipient) {
|
||||
Util.runOnMain(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setBubbleState(messageRecord, recipient);
|
||||
setContactPhoto(recipient);
|
||||
setGroupMessageStatus(messageRecord, recipient);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class ThumbnailDownloadClickListener implements ThumbnailView.ThumbnailClickListener {
|
||||
@ -416,6 +414,7 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
||||
DatabaseFactory.getPartDatabase(context).setTransferState(messageRecord.getId(), slide.getPart().getPartId(), PartDatabase.TRANSFER_PROGRESS_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
private class ThumbnailClickListener implements ThumbnailView.ThumbnailClickListener {
|
||||
private void fireIntent(Slide slide) {
|
||||
Log.w(TAG, "Clicked: " + slide.getUri() + " , " + slide.getContentType());
|
||||
|
98
src/org/thoughtcrime/securesms/ConversationUpdateItem.java
Normal file
98
src/org/thoughtcrime/securesms/ConversationUpdateItem.java
Normal file
@ -0,0 +1,98 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class ConversationUpdateItem extends LinearLayout
|
||||
implements Recipients.RecipientsModifiedListener, Recipient.RecipientModifiedListener, Unbindable, View.OnClickListener
|
||||
{
|
||||
private static final String TAG = ConversationUpdateItem.class.getSimpleName();
|
||||
|
||||
private ImageView icon;
|
||||
private TextView body;
|
||||
private Recipient sender;
|
||||
private MessageRecord messageRecord;
|
||||
|
||||
public ConversationUpdateItem(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ConversationUpdateItem(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
this.icon = (ImageView)findViewById(R.id.conversation_update_icon);
|
||||
this.body = (TextView)findViewById(R.id.conversation_update_body);
|
||||
|
||||
setOnClickListener(this);
|
||||
}
|
||||
|
||||
public void set(MessageRecord messageRecord) {
|
||||
this.messageRecord = messageRecord;
|
||||
this.sender = messageRecord.getIndividualRecipient();
|
||||
|
||||
this.sender.addListener(this);
|
||||
|
||||
if (messageRecord.isGroupAction()) {
|
||||
icon.setImageDrawable(getContext().getResources().getDrawable(R.drawable.ic_group_grey600_24dp));
|
||||
|
||||
if (messageRecord.isGroupQuit() && messageRecord.isOutgoing()) {
|
||||
body.setText(R.string.MessageRecord_left_group);
|
||||
} else if (messageRecord.isGroupQuit()) {
|
||||
body.setText(getContext().getString(R.string.ConversationItem_group_action_left, sender.toShortString()));
|
||||
} else {
|
||||
GroupUtil.GroupDescription description = GroupUtil.getDescription(getContext(), messageRecord.getBody().getBody());
|
||||
description.addListener(this);
|
||||
body.setText(description.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipients recipients) {
|
||||
onModified(recipients.getPrimaryRecipient());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(Recipient recipient) {
|
||||
Util.runOnMain(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
set(messageRecord);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (messageRecord.isIdentityUpdate()) {
|
||||
Intent intent = new Intent(getContext(), RecipientPreferenceActivity.class);
|
||||
intent.putExtra(RecipientPreferenceActivity.RECIPIENTS_EXTRA,
|
||||
new long[] {messageRecord.getIndividualRecipient().getRecipientId()});
|
||||
|
||||
getContext().startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {
|
||||
if (sender != null) {
|
||||
sender.removeListener(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -184,7 +184,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
||||
private void inflateMessageViewIfAbsent(MessageRecord messageRecord) {
|
||||
if (conversationItem == null) {
|
||||
if (messageRecord.isGroupAction()) {
|
||||
conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_activity, itemParent, false);
|
||||
conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_update, itemParent, false);
|
||||
} else if (messageRecord.isOutgoing()) {
|
||||
conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_sent, itemParent, false);
|
||||
} else {
|
||||
|
5
src/org/thoughtcrime/securesms/Unbindable.java
Normal file
5
src/org/thoughtcrime/securesms/Unbindable.java
Normal file
@ -0,0 +1,5 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
public interface Unbindable {
|
||||
public void unbind();
|
||||
}
|
@ -110,7 +110,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
if (isGroupUpdate() && isOutgoing()) {
|
||||
return emphasisAdded(context.getString(R.string.MessageRecord_updated_group));
|
||||
} else if (isGroupUpdate()) {
|
||||
return emphasisAdded(GroupUtil.getDescription(context, getBody().getBody()));
|
||||
return emphasisAdded(GroupUtil.getDescription(context, getBody().getBody()).toString());
|
||||
} else if (isGroupQuit() && isOutgoing()) {
|
||||
return emphasisAdded(context.getString(R.string.MessageRecord_left_group));
|
||||
} else if (isGroupQuit()) {
|
||||
|
@ -57,7 +57,7 @@ public class ThreadRecord extends DisplayRecord {
|
||||
if (SmsDatabase.Types.isDecryptInProgressType(type)) {
|
||||
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_decrypting_please_wait));
|
||||
} else if (isGroupUpdate()) {
|
||||
return emphasisAdded(GroupUtil.getDescription(context, getBody().getBody()));
|
||||
return emphasisAdded(GroupUtil.getDescription(context, getBody().getBody()).toString());
|
||||
} else if (isGroupQuit()) {
|
||||
return emphasisAdded(context.getString(R.string.ThreadRecord_left_the_group));
|
||||
} else if (isKeyExchange()) {
|
||||
|
@ -179,7 +179,7 @@ public class Recipient {
|
||||
}
|
||||
|
||||
for (RecipientModifiedListener listener : localListeners)
|
||||
listener.onModified(Recipient.this);
|
||||
listener.onModified(this);
|
||||
}
|
||||
|
||||
public interface RecipientModifiedListener {
|
||||
|
@ -185,9 +185,7 @@ public class Recipients implements Iterable<Recipient>, RecipientModifiedListene
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public synchronized void removeListener(RecipientsModifiedListener listener) {
|
||||
|
@ -29,14 +29,4 @@ public class IncomingGroupMessage extends IncomingTextMessage {
|
||||
return groupContext.getType().getNumber() == GroupContext.Type.QUIT_VALUE;
|
||||
}
|
||||
|
||||
// public static IncomingGroupMessage createForQuit(String groupId, String user) throws IOException {
|
||||
// IncomingTextMessage base = new IncomingTextMessage(user, groupId);
|
||||
// GroupContext context = GroupContext.newBuilder()
|
||||
// .setType(GroupContext.Type.QUIT)
|
||||
// .setId(ByteString.copyFrom(GroupUtil.getDecodedId(groupId)))
|
||||
// .build();
|
||||
//
|
||||
// return new IncomingGroupMessage(base, context, "");
|
||||
// }
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,22 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import static org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext;
|
||||
|
||||
public class GroupUtil {
|
||||
|
||||
private static final String ENCODED_GROUP_PREFIX = "__textsecure_group__!";
|
||||
private static final String TAG = GroupUtil.class.getSimpleName();
|
||||
|
||||
public static String getEncodedId(byte[] groupId) {
|
||||
return ENCODED_GROUP_PREFIX + Hex.toStringCondensed(groupId);
|
||||
@ -31,19 +34,47 @@ public class GroupUtil {
|
||||
return groupId.startsWith(ENCODED_GROUP_PREFIX);
|
||||
}
|
||||
|
||||
public static String getDescription(Context context, String encodedGroup) {
|
||||
public static @NonNull GroupDescription getDescription(@NonNull Context context, @Nullable String encodedGroup) {
|
||||
if (encodedGroup == null) {
|
||||
return context.getString(R.string.GroupUtil_group_updated);
|
||||
return new GroupDescription(context, null);
|
||||
}
|
||||
|
||||
try {
|
||||
StringBuilder description = new StringBuilder();
|
||||
GroupContext groupContext = GroupContext.parseFrom(Base64.decode(encodedGroup));
|
||||
List<String> members = groupContext.getMembersList();
|
||||
String title = groupContext.getName();
|
||||
return new GroupDescription(context, groupContext);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return new GroupDescription(context, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (!members.isEmpty()) {
|
||||
description.append(context.getString(R.string.GroupUtil_joined_the_group, Util.join(members, ", ")));
|
||||
public static class GroupDescription {
|
||||
|
||||
@NonNull private final Context context;
|
||||
@Nullable private final GroupContext groupContext;
|
||||
@Nullable private final Recipients members;
|
||||
|
||||
public GroupDescription(@NonNull Context context, @Nullable GroupContext groupContext) {
|
||||
this.context = context.getApplicationContext();
|
||||
this.groupContext = groupContext;
|
||||
|
||||
if (groupContext == null || groupContext.getMembersList().isEmpty()) {
|
||||
this.members = null;
|
||||
} else {
|
||||
this.members = RecipientFactory.getRecipientsFromString(context, Util.join(groupContext.getMembersList(), ", "), true);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (groupContext == null) {
|
||||
return context.getString(R.string.GroupUtil_group_updated);
|
||||
}
|
||||
|
||||
StringBuilder description = new StringBuilder();
|
||||
String title = groupContext.getName();
|
||||
|
||||
if (members != null) {
|
||||
description.append(context.getString(R.string.GroupUtil_joined_the_group, members.toShortString()));
|
||||
}
|
||||
|
||||
if (title != null && !title.trim().isEmpty()) {
|
||||
@ -56,12 +87,12 @@ public class GroupUtil {
|
||||
} else {
|
||||
return context.getString(R.string.GroupUtil_group_updated);
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
Log.w("GroupUtil", e);
|
||||
return context.getString(R.string.GroupUtil_group_updated);
|
||||
} catch (IOException e) {
|
||||
Log.w("GroupUtil", e);
|
||||
return context.getString(R.string.GroupUtil_group_updated);
|
||||
}
|
||||
|
||||
public void addListener(Recipients.RecipientsModifiedListener listener) {
|
||||
if (this.members != null) {
|
||||
this.members.addListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user