From 3849d7bc1687a9e5132989ab77a1a96d2b977cd8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 16 Jan 2020 13:03:51 +0100 Subject: [PATCH] Forward & ephemeral messages feature --- .../java/org/linphone/chat/ChatActivity.java | 33 +++ .../linphone/chat/ChatMessageViewHolder.java | 65 ++++++ .../linphone/chat/ChatMessagesAdapter.java | 50 ++++ .../linphone/chat/ChatMessagesFragment.java | 216 ++++++++++++------ .../chat/ChatMessagesGenericAdapter.java | 2 + .../org/linphone/chat/ChatRoomViewHolder.java | 4 + .../org/linphone/chat/EphemeralFragment.java | 160 +++++++++++++ .../org/linphone/utils/SelectableHelper.java | 4 + .../ephemeral_messages_default.png | Bin 0 -> 9243 bytes .../ephemeral_messages_small_default.png | Bin 0 -> 1553 bytes .../forwarded_message_default.png | Bin 0 -> 1081 bytes .../drawable-xhdpi/menu_delete_default.png | Bin 0 -> 2346 bytes .../menu_ephemeral_messages_default.png | Bin 0 -> 3669 bytes .../menu_group_info_default.png | Bin 0 -> 3294 bytes .../drawable-xhdpi/menu_security_default.png | Bin 0 -> 3625 bytes .../res/drawable-xhdpi/more_menu_default.png | Bin 0 -> 2738 bytes .../res/drawable/chat_room_menu_delete.xml | 7 + .../res/drawable/chat_room_menu_ephemeral.xml | 7 + .../drawable/chat_room_menu_group_info.xml | 7 + .../res/drawable/chat_room_menu_security.xml | 7 + .../drawable/chat_send_ephemeral_message.xml | 11 + app/src/main/res/drawable/menu_more.xml | 15 ++ app/src/main/res/layout/chat.xml | 35 ++- app/src/main/res/layout/chat_bubble.xml | 51 +++++ app/src/main/res/layout/chat_ephemeral.xml | 89 ++++++++ .../main/res/layout/chat_ephemeral_item.xml | 32 +++ app/src/main/res/layout/chatlist_cell.xml | 11 + app/src/main/res/menu/chat_bubble_menu.xml | 4 + .../res/menu/chat_bubble_menu_with_resend.xml | 4 + app/src/main/res/menu/chat_room_menu.xml | 24 ++ app/src/main/res/values/strings.xml | 21 ++ app/src/main/res/values/styles.xml | 33 +++ 32 files changed, 807 insertions(+), 85 deletions(-) create mode 100644 app/src/main/java/org/linphone/chat/EphemeralFragment.java create mode 100644 app/src/main/res/drawable-xhdpi/ephemeral_messages_default.png create mode 100644 app/src/main/res/drawable-xhdpi/ephemeral_messages_small_default.png create mode 100644 app/src/main/res/drawable-xhdpi/forwarded_message_default.png create mode 100644 app/src/main/res/drawable-xhdpi/menu_delete_default.png create mode 100644 app/src/main/res/drawable-xhdpi/menu_ephemeral_messages_default.png create mode 100644 app/src/main/res/drawable-xhdpi/menu_group_info_default.png create mode 100644 app/src/main/res/drawable-xhdpi/menu_security_default.png create mode 100644 app/src/main/res/drawable-xhdpi/more_menu_default.png create mode 100644 app/src/main/res/drawable/chat_room_menu_delete.xml create mode 100644 app/src/main/res/drawable/chat_room_menu_ephemeral.xml create mode 100644 app/src/main/res/drawable/chat_room_menu_group_info.xml create mode 100644 app/src/main/res/drawable/chat_room_menu_security.xml create mode 100644 app/src/main/res/drawable/chat_send_ephemeral_message.xml create mode 100644 app/src/main/res/drawable/menu_more.xml create mode 100644 app/src/main/res/layout/chat_ephemeral.xml create mode 100644 app/src/main/res/layout/chat_ephemeral_item.xml create mode 100644 app/src/main/res/menu/chat_room_menu.xml diff --git a/app/src/main/java/org/linphone/chat/ChatActivity.java b/app/src/main/java/org/linphone/chat/ChatActivity.java index 0b72c846c..5fa43b0d6 100644 --- a/app/src/main/java/org/linphone/chat/ChatActivity.java +++ b/app/src/main/java/org/linphone/chat/ChatActivity.java @@ -27,10 +27,13 @@ import android.os.Bundle; import android.view.View; import android.widget.Toast; import java.util.ArrayList; +import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.activities.MainActivity; import org.linphone.contacts.ContactAddress; import org.linphone.core.Address; +import org.linphone.core.ChatMessage; +import org.linphone.core.ChatRoom; import org.linphone.core.Factory; import org.linphone.core.tools.Log; import org.linphone.utils.FileUtils; @@ -39,6 +42,7 @@ public class ChatActivity extends MainActivity { public static final String NAME = "Chat"; private String mSharedText, mSharedFiles; + private ChatMessage mForwardMessage; @Override protected void onCreate(Bundle savedInstanceState) { @@ -212,6 +216,18 @@ public class ChatActivity extends MainActivity { mSharedFiles = null; } + if (mForwardMessage != null) { + Log.i("[Chat] Found message to forward"); + ChatRoom room = LinphoneManager.getCore().getChatRoom(peerAddress, localAddress); + if (room != null) { + Log.i("[Chat] Found chat room in which to forward message"); + ChatMessage message = room.createForwardMessage(mForwardMessage); + message.send(); + mForwardMessage = null; + Log.i("[Chat] Message forwarded"); + } + } + ChatMessagesFragment fragment = new ChatMessagesFragment(); fragment.setArguments(extras); changeFragment(fragment, "Chat room", isChild); @@ -302,4 +318,21 @@ public class ChatActivity extends MainActivity { fragment.setArguments(extras); changeFragment(fragment, "Chat room group info", true); } + + public void showChatRoomEphemeral(Address peerAddress) { + Bundle extras = new Bundle(); + if (peerAddress != null) { + extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly()); + } + EphemeralFragment fragment = new EphemeralFragment(); + fragment.setArguments(extras); + changeFragment(fragment, "Chat room ephemeral", true); + } + + public void forwardMessage(ChatMessage message) { + Log.i("[Chat] Message forwarding enabled"); + goBack(); + mForwardMessage = message; + Toast.makeText(this, R.string.toast_choose_chat_room_for_sharing, Toast.LENGTH_LONG).show(); + } } diff --git a/app/src/main/java/org/linphone/chat/ChatMessageViewHolder.java b/app/src/main/java/org/linphone/chat/ChatMessageViewHolder.java index 5c59fa274..5f0cac129 100644 --- a/app/src/main/java/org/linphone/chat/ChatMessageViewHolder.java +++ b/app/src/main/java/org/linphone/chat/ChatMessageViewHolder.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.CountDownTimer; import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; @@ -81,6 +82,11 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi private final FlexboxLayout multiFileContents; private final RelativeLayout singleFileContent; + private final LinearLayout forwardLayout; + private final LinearLayout ephemeralLayout; + private final TextView ephemeralCountdown; + private CountDownTimer countDownTimer; + public final CheckBox delete; public boolean isEditionEnabled; @@ -117,6 +123,11 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi singleFileContent = view.findViewById(R.id.single_content); multiFileContents = view.findViewById(R.id.multi_content); + forwardLayout = view.findViewById(R.id.forward_layout); + ephemeralLayout = view.findViewById(R.id.ephemeral_layout); + ephemeralCountdown = view.findViewById(R.id.ephemeral_time); + countDownTimer = null; + delete = view.findViewById(R.id.delete_event); } @@ -141,6 +152,10 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi singleFileContent.setVisibility(View.GONE); multiFileContents.setVisibility(View.GONE); + forwardLayout.setVisibility(message.isForward() ? View.VISIBLE : View.GONE); + ephemeralLayout.setVisibility(message.isEphemeral() ? View.VISIBLE : View.GONE); + updateEphemeralTimer(message); + ChatMessage.State status = message.getState(); Address remoteSender = message.getFromAddress(); String displayName; @@ -411,4 +426,54 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi private void loadBitmap(String path, ImageView imageView) { Glide.with(mContext).load(path).into(imageView); } + + private void updateEphemeralTimer(ChatMessage message) { + if (!message.isEphemeral()) { + if (countDownTimer != null) { + countDownTimer.cancel(); + countDownTimer = null; + } + return; + } + + if (message.getEphemeralExpireTime() == 0) { + // This means the message hasn't been read by all participants yet, so the countdown + // hasn't started + // In this case we simply display the configured value for lifetime + ephemeralCountdown.setText(formatLifetime(message.getEphemeralLifetime())); + if (countDownTimer != null) { + countDownTimer.cancel(); + countDownTimer = null; + } + } else { + // Countdown has started, display remaining time + long remaining = message.getEphemeralExpireTime() - (System.currentTimeMillis() / 1000); + ephemeralCountdown.setText(formatLifetime(remaining)); + + if (countDownTimer == null) { + countDownTimer = + new CountDownTimer(remaining * 1000, 1000) { + @Override + public void onTick(long millisUntilFinished) { + ephemeralCountdown.setText( + formatLifetime(millisUntilFinished / 1000)); + } + + @Override + public void onFinish() {} + }; + countDownTimer.start(); + } + } + } + + private String formatLifetime(long seconds) { + long days = seconds / 86400; + if (days == 0) { + return String.format( + "%02d:%02d:%02d", seconds / 3600, (seconds % 3600) / 60, (seconds % 60)); + } else { + return mContext.getResources().getQuantityString(R.plurals.days, (int) days, days); + } + } } diff --git a/app/src/main/java/org/linphone/chat/ChatMessagesAdapter.java b/app/src/main/java/org/linphone/chat/ChatMessagesAdapter.java index c4d5ff848..dcd0b3e45 100644 --- a/app/src/main/java/org/linphone/chat/ChatMessagesAdapter.java +++ b/app/src/main/java/org/linphone/chat/ChatMessagesAdapter.java @@ -214,6 +214,30 @@ public class ChatMessagesAdapter extends SelectableAdapter= 0) { + removeItem(index); + } + } + private void changeBackgroundDependingOnPreviousAndNextEvents( ChatMessage message, ChatMessageViewHolder holder, int position) { boolean hasPrevious = false, hasNext = false; diff --git a/app/src/main/java/org/linphone/chat/ChatMessagesFragment.java b/app/src/main/java/org/linphone/chat/ChatMessagesFragment.java index ad3885033..3ec842396 100644 --- a/app/src/main/java/org/linphone/chat/ChatMessagesFragment.java +++ b/app/src/main/java/org/linphone/chat/ChatMessagesFragment.java @@ -50,6 +50,8 @@ import android.widget.CheckBox; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.appcompat.view.menu.MenuBuilder; +import androidx.appcompat.view.menu.MenuPopupHelper; import androidx.core.view.inputmethod.InputConnectionCompat; import androidx.core.view.inputmethod.InputContentInfoCompat; import androidx.recyclerview.widget.LinearLayoutManager; @@ -102,8 +104,8 @@ public class ChatMessagesFragment extends Fragment private ImageView mCallButton; private ImageView mBackToCallButton; - private ImageView mGroupInfosButton; - private ImageView mAttachImageButton, mSendMessageButton; + private ImageView mPopupMenu; + private ImageView mAttachImageButton, mSendMessageButton, mSendEphemeralIcon; private TextView mRoomLabel, mParticipantsLabel, mSipUriLabel, mRemoteComposing; private RichEditText mMessageTextToSend; private LayoutInflater mInflater; @@ -153,30 +155,7 @@ public class ChatMessagesFragment extends Fragment new View.OnClickListener() { @Override public void onClick(View view) { - boolean oneParticipantOneDevice = false; - if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { - ParticipantDevice[] devices = - mChatRoom.getParticipants()[0].getDevices(); - // Only start a call automatically if both ourselves and the remote - // have 1 device exactly, otherwise show devices list. - oneParticipantOneDevice = - devices.length == 1 - && mChatRoom.getMe().getDevices().length == 1; - } - - if (LinphonePreferences.instance().isLimeSecurityPopupEnabled()) { - showSecurityDialog(oneParticipantOneDevice); - } else { - if (oneParticipantOneDevice) { - ParticipantDevice device = - mChatRoom.getParticipants()[0].getDevices()[0]; - LinphoneManager.getCallManager() - .inviteAddress(device.getAddress(), true); - } else { - ((ChatActivity) getActivity()) - .showDevices(mLocalSipAddress, mRemoteSipAddress); - } - } + goToDevices(); } }); @@ -210,35 +189,12 @@ public class ChatMessagesFragment extends Fragment } }); - mGroupInfosButton = view.findViewById(R.id.group_infos); - mGroupInfosButton.setOnClickListener( + mPopupMenu = view.findViewById(R.id.menu); + mPopupMenu.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { - if (mChatRoom == null) return; - ArrayList participants = new ArrayList<>(); - for (Participant p : mChatRoom.getParticipants()) { - Address a = p.getAddress(); - LinphoneContact c = - ContactsManager.getInstance().findContactFromAddress(a); - if (c == null) { - c = new LinphoneContact(); - String displayName = LinphoneUtils.getAddressDisplayName(a); - c.setFullName(displayName); - } - ContactAddress ca = - new ContactAddress(c, a.asString(), "", p.isAdmin()); - participants.add(ca); - } - - boolean encrypted = - mChatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt()); - ((ChatActivity) getActivity()) - .showChatRoomGroupInfo( - mRemoteSipAddress, - participants, - mChatRoom.getSubject(), - encrypted); + showPopupMenu(); } }); @@ -265,8 +221,10 @@ public class ChatMessagesFragment extends Fragment mAttachImageButton.setVisibility(View.GONE); } + mSendEphemeralIcon = view.findViewById(R.id.send_ephemeral_message); mSendMessageButton = view.findViewById(R.id.send_message); mSendMessageButton.setEnabled(false); + mSendEphemeralIcon.setEnabled(mSendMessageButton.isEnabled()); mSendMessageButton.setOnClickListener( new View.OnClickListener() { @Override @@ -287,6 +245,7 @@ public class ChatMessagesFragment extends Fragment mSendMessageButton.setEnabled( mMessageTextToSend.getText().length() > 0 || mFilesUploadLayout.getChildCount() > 0); + mSendEphemeralIcon.setEnabled(mSendMessageButton.isEnabled()); if (mChatRoom != null && mMessageTextToSend.getText().length() > 0) { if (!getResources().getBoolean(R.bool.allow_multiple_images_and_text)) { mAttachImageButton.setEnabled(false); @@ -511,13 +470,8 @@ public class ChatMessagesFragment extends Fragment EventLog eventLog = (EventLog) obj; eventLog.deleteFromDatabase(); } - if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { - ((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()) - .refresh(mChatRoom.getHistoryMessageEvents(MESSAGES_PER_PAGE)); - } else { - ((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()) - .refresh(mChatRoom.getHistoryEvents(MESSAGES_PER_PAGE)); - } + ((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()) + .refresh(mChatRoom.getHistoryEvents(MESSAGES_PER_PAGE)); } @Override @@ -590,6 +544,10 @@ public class ChatMessagesFragment extends Fragment ((ChatActivity) getActivity()).showImdn(mLocalSipAddress, mRemoteSipAddress, messageId); return true; } + if (item.getItemId() == R.id.forward) { + ((ChatActivity) getActivity()).forwardMessage(message); + return true; + } if (item.getItemId() == R.id.copy_text) { if (message.hasTextContent()) { ClipboardManager clipboard = @@ -636,27 +594,14 @@ public class ChatMessagesFragment extends Fragment new Runnable() { @Override public void run() { - int maxSize; - if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { - maxSize = mChatRoom.getHistorySize(); - } else { - maxSize = mChatRoom.getHistoryEventsSize(); - } + int maxSize = mChatRoom.getHistoryEventsSize(); if (totalItemsCount < maxSize) { int upperBound = totalItemsCount + MESSAGES_PER_PAGE; if (upperBound > maxSize) { upperBound = maxSize; } EventLog[] newLogs; - if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { - newLogs = - mChatRoom.getHistoryRangeMessageEvents( - totalItemsCount, upperBound); - } else { - newLogs = - mChatRoom.getHistoryRangeEvents( - totalItemsCount, upperBound); - } + newLogs = mChatRoom.getHistoryRangeEvents(totalItemsCount, upperBound); ArrayList logsList = new ArrayList<>(Arrays.asList(newLogs)); ((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()) .addAllToHistory(logsList); @@ -722,6 +667,7 @@ public class ChatMessagesFragment extends Fragment mMessageTextToSend.setEnabled(false); mAttachImageButton.setEnabled(false); mSendMessageButton.setEnabled(false); + mSendEphemeralIcon.setEnabled(mSendMessageButton.isEnabled()); } private void getContactsForParticipants() { @@ -798,7 +744,15 @@ public class ChatMessagesFragment extends Fragment if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { mCallButton.setVisibility(View.VISIBLE); - mGroupInfosButton.setVisibility(View.GONE); + + if (mChatRoom.hasCapability(ChatRoomCapabilities.Basic.toInt())) { + mPopupMenu.setVisibility(View.GONE); + mSelectionHelper.setEditButtonVisibility(true); + } else { + mPopupMenu.setVisibility(View.VISIBLE); + mSelectionHelper.setEditButtonVisibility(false); + } + mParticipantsLabel.setVisibility(View.GONE); if (mContext.getResources().getBoolean(R.bool.show_sip_uri_in_chat)) { @@ -827,7 +781,8 @@ public class ChatMessagesFragment extends Fragment mSipUriLabel.setText(mRemoteParticipantAddress.asStringUriOnly()); } else { mCallButton.setVisibility(View.GONE); - mGroupInfosButton.setVisibility(View.VISIBLE); + mPopupMenu.setVisibility(View.VISIBLE); + mSelectionHelper.setEditButtonVisibility(false); mRoomLabel.setText(mChatRoom.getSubject()); mParticipantsLabel.setVisibility(View.VISIBLE); mSipUriLabel.setVisibility(View.GONE); @@ -838,6 +793,7 @@ public class ChatMessagesFragment extends Fragment mBackToCallButton.setVisibility(View.VISIBLE); } + mSendEphemeralIcon.setVisibility(mChatRoom.ephemeralEnabled() ? View.VISIBLE : View.GONE); if (mChatRoom.hasBeenLeft()) { setReadOnly(); } @@ -1044,6 +1000,7 @@ public class ChatMessagesFragment extends Fragment mSendMessageButton.setEnabled( mMessageTextToSend.getText().length() > 0 || mFilesUploadLayout.getChildCount() > 0); + mSendEphemeralIcon.setEnabled(mSendMessageButton.isEnabled()); } }); @@ -1054,6 +1011,7 @@ public class ChatMessagesFragment extends Fragment mMessageTextToSend.setEnabled(false); } mSendMessageButton.setEnabled(true); + mSendEphemeralIcon.setEnabled(mSendMessageButton.isEnabled()); } private void addImageToPendingList(String path) { @@ -1083,6 +1041,7 @@ public class ChatMessagesFragment extends Fragment mSendMessageButton.setEnabled( mMessageTextToSend.getText().length() > 0 || mFilesUploadLayout.getChildCount() > 0); + mSendEphemeralIcon.setEnabled(mSendMessageButton.isEnabled()); } }); @@ -1093,6 +1052,7 @@ public class ChatMessagesFragment extends Fragment mMessageTextToSend.setEnabled(false); } mSendMessageButton.setEnabled(true); + mSendEphemeralIcon.setEnabled(mSendMessageButton.isEnabled()); } /** Message sending */ @@ -1160,6 +1120,97 @@ public class ChatMessagesFragment extends Fragment mMessageTextToSend.setText(""); } + private void showPopupMenu() { + MenuBuilder builder = new MenuBuilder(getActivity()); + MenuPopupHelper popupMenu = new MenuPopupHelper(getActivity(), builder, mPopupMenu); + popupMenu.setForceShowIcon(true); + + new MenuInflater(getActivity()).inflate(R.menu.chat_room_menu, builder); + + if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { + builder.removeItem(R.id.chat_room_group_info); + } + + if (!mChatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt())) { + builder.removeItem(R.id.chat_room_participants_devices); + builder.removeItem(R.id.chat_room_ephemeral_messages); + } + + builder.setCallback( + new MenuBuilder.Callback() { + @Override + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + if (item.getItemId() == R.id.chat_room_group_info) { + goToGroupInfo(); + return true; + } else if (item.getItemId() == R.id.chat_room_participants_devices) { + goToDevices(); + return true; + } else if (item.getItemId() == R.id.chat_room_ephemeral_messages) { + goToEphemeral(); + return true; + } else if (item.getItemId() == R.id.chat_room_delete_messages) { + mSelectionHelper.enterEditionMode(); + return true; + } + return false; + } + + @Override + public void onMenuModeChange(MenuBuilder menu) {} + }); + + popupMenu.show(); + } + + private void goToDevices() { + boolean oneParticipantOneDevice = false; + if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { + ParticipantDevice[] devices = mChatRoom.getParticipants()[0].getDevices(); + // Only start a call automatically if both ourselves and the remote + // have 1 device exactly, otherwise show devices list. + oneParticipantOneDevice = + devices.length == 1 && mChatRoom.getMe().getDevices().length == 1; + } + + if (LinphonePreferences.instance().isLimeSecurityPopupEnabled()) { + showSecurityDialog(oneParticipantOneDevice); + } else { + if (oneParticipantOneDevice) { + ParticipantDevice device = mChatRoom.getParticipants()[0].getDevices()[0]; + LinphoneManager.getCallManager().inviteAddress(device.getAddress(), true); + } else { + ((ChatActivity) getActivity()).showDevices(mLocalSipAddress, mRemoteSipAddress); + } + } + } + + private void goToGroupInfo() { + if (mChatRoom == null) return; + ArrayList participants = new ArrayList<>(); + for (Participant p : mChatRoom.getParticipants()) { + Address a = p.getAddress(); + LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(a); + if (c == null) { + c = new LinphoneContact(); + String displayName = LinphoneUtils.getAddressDisplayName(a); + c.setFullName(displayName); + } + ContactAddress ca = new ContactAddress(c, a.asString(), "", p.isAdmin()); + participants.add(ca); + } + + boolean encrypted = mChatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt()); + ((ChatActivity) getActivity()) + .showChatRoomGroupInfo( + mRemoteSipAddress, participants, mChatRoom.getSubject(), encrypted); + } + + private void goToEphemeral() { + if (mChatRoom == null) return; + ((ChatActivity) getActivity()).showChatRoomEphemeral(mRemoteSipAddress); + } + /* * Chat room callbacks */ @@ -1334,6 +1385,19 @@ public class ChatMessagesFragment extends Fragment scrollToBottom(); } + @Override + public void onEphemeralEvent(ChatRoom chatRoom, EventLog eventLog) { + ((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()).addToHistory(eventLog); + } + + @Override + public void onEphemeralMessageTimerStarted(ChatRoom chatRoom, EventLog eventLog) {} + + @Override + public void onEphemeralMessageDeleted(ChatRoom chatRoom, EventLog eventLog) { + ((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()).removeFromHistory(eventLog); + } + @Override public void onParticipantAdminStatusChanged(ChatRoom cr, EventLog event) { if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) return; diff --git a/app/src/main/java/org/linphone/chat/ChatMessagesGenericAdapter.java b/app/src/main/java/org/linphone/chat/ChatMessagesGenericAdapter.java index 4a5c976fe..aeb47ca2b 100644 --- a/app/src/main/java/org/linphone/chat/ChatMessagesGenericAdapter.java +++ b/app/src/main/java/org/linphone/chat/ChatMessagesGenericAdapter.java @@ -37,4 +37,6 @@ interface ChatMessagesGenericAdapter { Object getItem(int i); void removeItem(int i); + + void removeFromHistory(EventLog eventLog); } diff --git a/app/src/main/java/org/linphone/chat/ChatRoomViewHolder.java b/app/src/main/java/org/linphone/chat/ChatRoomViewHolder.java index 0d0693542..b02d146cc 100644 --- a/app/src/main/java/org/linphone/chat/ChatRoomViewHolder.java +++ b/app/src/main/java/org/linphone/chat/ChatRoomViewHolder.java @@ -22,6 +22,7 @@ package org.linphone.chat; import android.content.Context; import android.view.View; import android.widget.CheckBox; +import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; @@ -45,6 +46,7 @@ public class ChatRoomViewHolder extends RecyclerView.ViewHolder public final TextView unreadMessages; public final CheckBox delete; private final RelativeLayout avatarLayout; + public final ImageView ephemeral; private final Context mContext; private final ClickListener mListener; @@ -59,6 +61,7 @@ public class ChatRoomViewHolder extends RecyclerView.ViewHolder unreadMessages = itemView.findViewById(R.id.unreadMessages); delete = itemView.findViewById(R.id.delete_chatroom); avatarLayout = itemView.findViewById(R.id.avatar_layout); + ephemeral = itemView.findViewById(R.id.ephemeral); mListener = listener; itemView.setOnClickListener(this); @@ -88,6 +91,7 @@ public class ChatRoomViewHolder extends RecyclerView.ViewHolder lastMessageView.setText(""); } + ephemeral.setVisibility(room.ephemeralEnabled() ? View.VISIBLE : View.GONE); displayName.setText(getContact(room)); unreadMessages.setText(String.valueOf(room.getUnreadMessagesCount())); getAvatar(room); diff --git a/app/src/main/java/org/linphone/chat/EphemeralFragment.java b/app/src/main/java/org/linphone/chat/EphemeralFragment.java new file mode 100644 index 000000000..8f5553671 --- /dev/null +++ b/app/src/main/java/org/linphone/chat/EphemeralFragment.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010-2019 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.linphone.chat; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.annotation.Nullable; +import org.linphone.LinphoneManager; +import org.linphone.R; +import org.linphone.core.Address; +import org.linphone.core.ChatRoom; +import org.linphone.core.Factory; +import org.linphone.core.tools.Log; + +public class EphemeralFragment extends Fragment { + private ChatRoom mChatRoom; + private long mCurrentValue; + + private LayoutInflater mInflater; + private ViewGroup mContainer; + private LinearLayout mItems; + + @Nullable + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + View view = inflater.inflate(R.layout.chat_ephemeral, container, false); + mInflater = inflater; + mContainer = container; + + if (getArguments() == null || getArguments().isEmpty()) { + return null; + } + + String address = getArguments().getString("RemoteSipUri"); + Address peerAddress = null; + mChatRoom = null; + if (address != null && address.length() > 0) { + peerAddress = Factory.instance().createAddress(address); + } + if (peerAddress != null) { + mChatRoom = LinphoneManager.getCore().getChatRoom(peerAddress); + } + if (mChatRoom == null) { + return null; + } + mCurrentValue = mChatRoom.ephemeralEnabled() ? mChatRoom.getEphemeralLifetime() : 0; + Log.i( + "[Ephemeral Messages] Current duration is ", + mCurrentValue, + ", ephemeral enabled? ", + mChatRoom.ephemeralEnabled()); + + view.findViewById(R.id.back) + .setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + getFragmentManager().popBackStack(); + } + }); + + view.findViewById(R.id.valid) + .setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.i("[Ephemeral Messages] Selected value is ", mCurrentValue); + if (mCurrentValue > 0) { + if (mChatRoom.getEphemeralLifetime() != mCurrentValue) { + Log.i( + "[Ephemeral Messages] Setting new lifetime for ephemeral messages to ", + mCurrentValue); + mChatRoom.setEphemeralLifetime(mCurrentValue); + } else { + Log.i( + "[Ephemeral Messages] Configured lifetime for ephemeral messages was already ", + mCurrentValue); + } + + if (!mChatRoom.ephemeralEnabled()) { + Log.i( + "[Ephemeral Messages] Ephemeral messages were disabled, enable them"); + mChatRoom.enableEphemeral(true); + } + } else if (mChatRoom.ephemeralEnabled()) { + Log.i( + "[Ephemeral Messages] Ephemeral messages were enabled, disable them"); + mChatRoom.enableEphemeral(false); + } + + getFragmentManager().popBackStack(); + } + }); + + mItems = view.findViewById(R.id.items); + + computeItems(); + + return view; + } + + private View getView(int id, final long value) { + View view = mInflater.inflate(R.layout.chat_ephemeral_item, mContainer, false); + ((TextView) view.findViewById(R.id.text)).setText(id); + ((TextView) view.findViewById(R.id.text)) + .setTextAppearance( + getActivity(), + mCurrentValue == value + ? R.style.chat_room_ephemeral_selected_item_font + : R.style.chat_room_ephemeral_item_font); + view.findViewById(R.id.selected) + .setVisibility(mCurrentValue == value ? View.VISIBLE : View.GONE); + view.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mCurrentValue != value) { + mCurrentValue = value; + computeItems(); + } + } + }); + return view; + } + + private void computeItems() { + mItems.removeAllViews(); + mItems.addView(getView(R.string.chat_room_ephemeral_message_disabled, 0)); + mItems.addView(getView(R.string.chat_room_ephemeral_message_one_minute, 60)); + mItems.addView(getView(R.string.chat_room_ephemeral_message_one_hour, 3600)); + mItems.addView(getView(R.string.chat_room_ephemeral_message_one_day, 86400)); + mItems.addView(getView(R.string.chat_room_ephemeral_message_three_days, 259200)); + mItems.addView(getView(R.string.chat_room_ephemeral_message_one_week, 604800)); + } +} diff --git a/app/src/main/java/org/linphone/utils/SelectableHelper.java b/app/src/main/java/org/linphone/utils/SelectableHelper.java index c5146b6d9..cf6367889 100644 --- a/app/src/main/java/org/linphone/utils/SelectableHelper.java +++ b/app/src/main/java/org/linphone/utils/SelectableHelper.java @@ -187,6 +187,10 @@ public class SelectableHelper { return objects; } + public void setEditButtonVisibility(boolean visible) { + mEditButton.setVisibility(visible ? View.VISIBLE : View.GONE); + } + public interface DeleteListener { void onDeleteSelection(Object[] objectsToDelete); } diff --git a/app/src/main/res/drawable-xhdpi/ephemeral_messages_default.png b/app/src/main/res/drawable-xhdpi/ephemeral_messages_default.png new file mode 100644 index 0000000000000000000000000000000000000000..7b7ae1c7f954a3be3486431d08c974f887791c9a GIT binary patch literal 9243 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ephemeral_messages_small_default.png b/app/src/main/res/drawable-xhdpi/ephemeral_messages_small_default.png new file mode 100644 index 0000000000000000000000000000000000000000..dc5bb984e38ceda2161b23c3965fb2642abd8aed GIT binary patch literal 1553 zcmV+s2JZQZP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91AfN*P1ONa40RR91CIA2c03*hiQvd)3dr3q=R9FeMm}`htRTRhn`#Pp( zC6W1<)GVb069mhGzSM_`Fw+R7Q1VqaHTb2d$SkEoB9szQ!*Db)5)stieF*DAP#*$C zvV=m*SCN(vEFH(${nkGFoO_P<&YclX8}{9Mt-aRzuf6tbo$J)Y;%DhzM7PLmKm(Ny zRrIRcpw}A66ox7VsxdLC8*tNZLS|ZHGsV$MaiFN#73Jl+8mh-H-+_844R}3w!0V3& zcB(_JhjLM)sj6A*c|z$NE1H(RdRympSe?2RZY%6!sGUB8^D(>N!&IdwZA}FHeD(H^ zX}MPN2dG^d%XFMR!I?GC&FF2Vf0Ftv$FnWUWKGe5S^5$1G1;hf z9AWpmF5@{&dhLNeNKI!ul>TsJ$1#?V>UsFRsY!AATsLTnTcY-qRonw!KQoYbz-Qo2 z-vH1?{m8A?pQ(X->*wfN4AOX}xGl3+QU9zTJNfkz%8xSp2g6uJE3`om zyJb3au~GxNKl(F>%3e;;8=6Qou)#D}1f5PT3>Y~B*%EO4Mj-wZWBqKM*(_7pEOxxQ zEdFr~W;^}frGWGW_rf$RpV5A8$GOSK{;R$k!?6zgpc;X5;RWl5z<$W`VfuX5o?~wBun5qG6}V@aQ_Ep2|u1y@6?OIc10V5#fVu6q3{|R znKfs<1o*^+*Ta4Z6ZY{w0n@N80%Ie{A@`nsDGjjJ&>)_$i4o&a93E>9G)Llatxm}t zuTd9aHCqm64~bpMN37vK7|7WkX#H->`EFmvq6x2IfnivdX@K1X@P$B#({JS*nSc*> zcpyvtaomwfNwC1SO%Y~Jn=VB{mx`PjD`J6Nb--~>tvGUm|Er|7Q>@@XZ|w?rUW4se z@SN_#iG!v4fK9V)7({z;un%^{ts@C>+8donE+obKyIe1lHzB?Bz%=aSCRCPe%(kRd zSLjWgI$0XN*}`V9EzOR0!=;xv;ItNIJE0lHDVXn8={OE7EYX35!RA>#888eh!A#x) z*5&|=)e&$p>of$O(KT7@B|GJ`&TN@YFkT7zUYU`)TqzOS_%E)m6HSXmpaK ztb+GMP`vb?cX@_d)rX0m(pSv>4on;;le{@Z1R~u73XEQw4zD8!p5h~B)rNG%hprCcyXM-85UM$;0F@ zDV9ar&Xf8*ZA~HLodDCmCuic&$S81(b~?+kGtz~oO9xCUhTV?i0u1)aG?P2x5On%( zG}E_e49LlxqrZ|bhox?fY){lJ4IM}|Sj!Ov-#)jdP{*hIx~&UW`3@GLEls`a%0*_6 z9LO8stLJ*wb{w^tJzz5@R7Aq|K}CDGUVqKYch~<9^~;-#>++Et00000NkvXXu0mjf D{wUVi literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/forwarded_message_default.png b/app/src/main/res/drawable-xhdpi/forwarded_message_default.png new file mode 100644 index 0000000000000000000000000000000000000000..55c5d617fed7614edb3d15e822e9f1d0418f4184 GIT binary patch literal 1081 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/menu_security_default.png b/app/src/main/res/drawable-xhdpi/menu_security_default.png new file mode 100644 index 0000000000000000000000000000000000000000..51ee24fd9523557a600a61fb894e5b464c41262d GIT binary patch literal 3625 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/more_menu_default.png b/app/src/main/res/drawable-xhdpi/more_menu_default.png new file mode 100644 index 0000000000000000000000000000000000000000..51162a31ab58fe2da536bf8e442e1442af060e6d GIT binary patch literal 2738 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/chat_room_menu_delete.xml b/app/src/main/res/drawable/chat_room_menu_delete.xml new file mode 100644 index 000000000..cb9f81675 --- /dev/null +++ b/app/src/main/res/drawable/chat_room_menu_delete.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/drawable/chat_room_menu_ephemeral.xml b/app/src/main/res/drawable/chat_room_menu_ephemeral.xml new file mode 100644 index 000000000..f539c09c1 --- /dev/null +++ b/app/src/main/res/drawable/chat_room_menu_ephemeral.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/drawable/chat_room_menu_group_info.xml b/app/src/main/res/drawable/chat_room_menu_group_info.xml new file mode 100644 index 000000000..d15e39140 --- /dev/null +++ b/app/src/main/res/drawable/chat_room_menu_group_info.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/drawable/chat_room_menu_security.xml b/app/src/main/res/drawable/chat_room_menu_security.xml new file mode 100644 index 000000000..cc587a19e --- /dev/null +++ b/app/src/main/res/drawable/chat_room_menu_security.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/drawable/chat_send_ephemeral_message.xml b/app/src/main/res/drawable/chat_send_ephemeral_message.xml new file mode 100644 index 000000000..c3aaa77a4 --- /dev/null +++ b/app/src/main/res/drawable/chat_send_ephemeral_message.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/menu_more.xml b/app/src/main/res/drawable/menu_more.xml new file mode 100644 index 000000000..8e9603b3f --- /dev/null +++ b/app/src/main/res/drawable/menu_more.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/chat.xml b/app/src/main/res/layout/chat.xml index 68198a465..16892ce8e 100644 --- a/app/src/main/res/layout/chat.xml +++ b/app/src/main/res/layout/chat.xml @@ -79,17 +79,17 @@ android:src="@drawable/call_alt_start" /> + android:src="@drawable/menu_more"/> + @@ -159,13 +160,29 @@ android:textColor="@color/black_color" android:textCursorDrawable="@null" /> - + android:layout_height="wrap_content"> + + + + + + diff --git a/app/src/main/res/layout/chat_bubble.xml b/app/src/main/res/layout/chat_bubble.xml index 7c862a693..0165c3122 100644 --- a/app/src/main/res/layout/chat_bubble.xml +++ b/app/src/main/res/layout/chat_bubble.xml @@ -88,6 +88,31 @@ android:paddingTop="5dp" android:paddingBottom="5dp"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/chat_ephemeral_item.xml b/app/src/main/res/layout/chat_ephemeral_item.xml new file mode 100644 index 000000000..5b52a093c --- /dev/null +++ b/app/src/main/res/layout/chat_ephemeral_item.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/chatlist_cell.xml b/app/src/main/res/layout/chatlist_cell.xml index 7799328eb..df4e1f134 100644 --- a/app/src/main/res/layout/chatlist_cell.xml +++ b/app/src/main/res/layout/chatlist_cell.xml @@ -90,6 +90,17 @@ + + diff --git a/app/src/main/res/menu/chat_bubble_menu.xml b/app/src/main/res/menu/chat_bubble_menu.xml index 069cf404e..eb9bd1ec8 100644 --- a/app/src/main/res/menu/chat_bubble_menu.xml +++ b/app/src/main/res/menu/chat_bubble_menu.xml @@ -5,6 +5,10 @@ android:id="@+id/copy_text" android:title="@string/copy_text" /> + + diff --git a/app/src/main/res/menu/chat_bubble_menu_with_resend.xml b/app/src/main/res/menu/chat_bubble_menu_with_resend.xml index 9b8c8076e..8a02e0f36 100644 --- a/app/src/main/res/menu/chat_bubble_menu_with_resend.xml +++ b/app/src/main/res/menu/chat_bubble_menu_with_resend.xml @@ -9,6 +9,10 @@ android:id="@+id/copy_text" android:title="@string/copy_text" /> + + diff --git a/app/src/main/res/menu/chat_room_menu.xml b/app/src/main/res/menu/chat_room_menu.xml new file mode 100644 index 000000000..a0e509e5e --- /dev/null +++ b/app/src/main/res/menu/chat_room_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ebd054773..baf341304 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -256,6 +256,27 @@ Select a conversation or create a new one Trust has been denied. Make a call to start the authentication process again. Can\'t open file, no application available for this format. + Forwarded + Group info + Conversation\'s devices + Ephemeral messages + Delete messages + Forward + Ephemeral messages + This message will be deleted on both ends once it has been read and after the selected timeout. + Disabled + 1 minute + 1 hour + 1 day + 3 days + 1 week + + %d day + %d days + + You disabled ephemeral messages + You enabled ephemeral messages: %s + Ephemeral messages expiry date: %s Connected diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 27a435916..c107ee48b 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -101,6 +101,39 @@ 0sp + + + + + + + + + +