Forward & ephemeral messages feature
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,6 +214,30 @@ public class ChatMessagesAdapter extends SelectableAdapter<ChatMessageViewHolder
|
|||
holder.eventMessage.setText(
|
||||
mContext.getString(R.string.device_removed).replace("%s", displayName));
|
||||
break;
|
||||
|
||||
case ConferenceEphemeralMessageDisabled:
|
||||
holder.eventLayout.setVisibility(View.VISIBLE);
|
||||
holder.eventMessage.setText(
|
||||
mContext.getString(R.string.chat_event_ephemeral_disabled));
|
||||
break;
|
||||
case ConferenceEphemeralMessageEnabled:
|
||||
holder.eventLayout.setVisibility(View.VISIBLE);
|
||||
holder.eventMessage.setText(
|
||||
mContext.getString(R.string.chat_event_ephemeral_enabled)
|
||||
.replace(
|
||||
"%s",
|
||||
formatEphemeralExpiration(
|
||||
event.getEphemeralMessageLifetime())));
|
||||
break;
|
||||
case ConferenceEphemeralMessageLifetimeChanged:
|
||||
holder.eventLayout.setVisibility(View.VISIBLE);
|
||||
holder.eventMessage.setText(
|
||||
mContext.getString(R.string.chat_event_ephemeral_lifetime_changed)
|
||||
.replace(
|
||||
"%s",
|
||||
formatEphemeralExpiration(
|
||||
event.getEphemeralMessageLifetime())));
|
||||
break;
|
||||
case ConferenceSecurityEvent:
|
||||
holder.securityEventLayout.setVisibility(View.VISIBLE);
|
||||
|
||||
|
@ -255,6 +279,24 @@ public class ChatMessagesAdapter extends SelectableAdapter<ChatMessageViewHolder
|
|||
}
|
||||
}
|
||||
|
||||
private String formatEphemeralExpiration(long duration) {
|
||||
if (duration == 0) {
|
||||
return mContext.getString(R.string.chat_room_ephemeral_message_disabled);
|
||||
} else if (duration == 60) {
|
||||
return mContext.getString(R.string.chat_room_ephemeral_message_one_minute);
|
||||
} else if (duration == 3600) {
|
||||
return mContext.getString(R.string.chat_room_ephemeral_message_one_hour);
|
||||
} else if (duration == 86400) {
|
||||
return mContext.getString(R.string.chat_room_ephemeral_message_one_day);
|
||||
} else if (duration == 259200) {
|
||||
return mContext.getString(R.string.chat_room_ephemeral_message_three_days);
|
||||
} else if (duration == 604800) {
|
||||
return mContext.getString(R.string.chat_room_ephemeral_message_one_week);
|
||||
} else {
|
||||
return "Unexpected duration";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mHistory.size();
|
||||
|
@ -303,6 +345,14 @@ public class ChatMessagesAdapter extends SelectableAdapter<ChatMessageViewHolder
|
|||
notifyItemRemoved(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromHistory(EventLog eventLog) {
|
||||
int index = mHistory.indexOf(eventLog);
|
||||
if (index >= 0) {
|
||||
removeItem(index);
|
||||
}
|
||||
}
|
||||
|
||||
private void changeBackgroundDependingOnPreviousAndNextEvents(
|
||||
ChatMessage message, ChatMessageViewHolder holder, int position) {
|
||||
boolean hasPrevious = false, hasNext = false;
|
||||
|
|
|
@ -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<ContactAddress> 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<EventLog> 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<ContactAddress> 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;
|
||||
|
|
|
@ -37,4 +37,6 @@ interface ChatMessagesGenericAdapter {
|
|||
Object getItem(int i);
|
||||
|
||||
void removeItem(int i);
|
||||
|
||||
void removeFromHistory(EventLog eventLog);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
160
app/src/main/java/org/linphone/chat/EphemeralFragment.java
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
BIN
app/src/main/res/drawable-xhdpi/ephemeral_messages_default.png
Normal file
After Width: | Height: | Size: 9 KiB |
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-xhdpi/forwarded_message_default.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable-xhdpi/menu_delete_default.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 3.6 KiB |
BIN
app/src/main/res/drawable-xhdpi/menu_group_info_default.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
app/src/main/res/drawable-xhdpi/menu_security_default.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/drawable-xhdpi/more_menu_default.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
7
app/src/main/res/drawable/chat_room_menu_delete.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:src="@drawable/menu_delete_default"
|
||||
android:tint="?attr/drawableTintColor"/>
|
||||
</item>
|
||||
</selector>
|
7
app/src/main/res/drawable/chat_room_menu_ephemeral.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:src="@drawable/menu_ephemeral_messages_default"
|
||||
android:tint="?attr/drawableTintColor"/>
|
||||
</item>
|
||||
</selector>
|
7
app/src/main/res/drawable/chat_room_menu_group_info.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:src="@drawable/menu_group_info_default"
|
||||
android:tint="?attr/drawableTintColor"/>
|
||||
</item>
|
||||
</selector>
|
7
app/src/main/res/drawable/chat_room_menu_security.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:src="@drawable/menu_security_default"
|
||||
android:tint="?attr/drawableTintColor"/>
|
||||
</item>
|
||||
</selector>
|
11
app/src/main/res/drawable/chat_send_ephemeral_message.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false">
|
||||
<bitmap android:src="@drawable/ephemeral_messages_small_default"
|
||||
android:tint="?attr/drawableTintDisabledColor"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:src="@drawable/ephemeral_messages_small_default" />
|
||||
</item>
|
||||
</selector>
|
||||
|
15
app/src/main/res/drawable/menu_more.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<bitmap android:src="@drawable/more_menu_default"
|
||||
android:tint="?attr/drawableTintOverColor"/>
|
||||
</item>
|
||||
<item android:state_enabled="false">
|
||||
<bitmap android:src="@drawable/more_menu_default"
|
||||
android:tint="?attr/drawableTintDisabledColor"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:src="@drawable/more_menu_default"
|
||||
android:tint="?attr/drawableTintColor"/>
|
||||
</item>
|
||||
</selector>
|
|
@ -79,17 +79,17 @@
|
|||
android:src="@drawable/call_alt_start" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/group_infos"
|
||||
android:id="@+id/menu"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0.2"
|
||||
android:background="?attr/button_background_drawable"
|
||||
android:contentDescription="@string/content_description_conversation_infos"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/chat_room_group_infos" />
|
||||
android:src="@drawable/menu_more"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/edit"
|
||||
android:visibility="gone"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0.2"
|
||||
|
@ -97,6 +97,7 @@
|
|||
android:contentDescription="@string/content_description_edit_list"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/delete" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/edit_list" android:visibility="gone" />
|
||||
|
@ -159,13 +160,29 @@
|
|||
android:textColor="@color/black_color"
|
||||
android:textCursorDrawable="@null" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/send_message"
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/content_description_send_message"
|
||||
android:padding="5dp"
|
||||
android:src="@drawable/chat_send_message" />
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/send_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dp"
|
||||
android:src="@drawable/chat_send_message" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/send_ephemeral_message"
|
||||
android:clickable="false"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_alignRight="@id/send_message"
|
||||
android:layout_alignBottom="@id/send_message"
|
||||
android:padding="5dp"
|
||||
android:src="@drawable/chat_send_ephemeral_message" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
@ -88,6 +88,31 @@
|
|||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/forward_layout"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical|right"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginLeft="5dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:src="@drawable/forwarded_message_default"
|
||||
android:layout_marginRight="3dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/chat_bubble_forward_font"
|
||||
android:text="@string/chat_message_forwarded" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/multi_content"
|
||||
|
@ -118,6 +143,32 @@
|
|||
android:layout_marginBottom="5dp"
|
||||
android:textAppearance="@style/chat_bubble_message_font" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ephemeral_layout"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="right"
|
||||
android:gravity="center_vertical|right"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginLeft="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ephemeral_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="5dp"
|
||||
android:textAppearance="@style/chat_bubble_ephemeral_font" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="13dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:src="@drawable/ephemeral_messages_small_default"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
|
|
89
app/src/main/res/layout/chat_ephemeral.xml
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/top_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:background="?attr/lighToolbarBackgroundColor"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0.2"
|
||||
android:background="?attr/button_background_drawable"
|
||||
android:padding="18dp"
|
||||
android:src="@drawable/back" />
|
||||
|
||||
<TextView
|
||||
style="@style/toolbar_small_title_font"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0.6"
|
||||
android:gravity="center"
|
||||
android:padding="15dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/chat_room_ephemeral_fragment_title" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/valid"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0.2"
|
||||
android:background="?attr/button_background_drawable"
|
||||
android:padding="18dp"
|
||||
android:src="@drawable/valid" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/top_bar">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/ephemeral_messages_default" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/chat_room_ephemeral_desc_font"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:text="@string/chat_room_ephemeral_messages_desc"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="?attr/dividerColor" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/items"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</RelativeLayout>
|
32
app/src/main/res/layout/chat_ephemeral_item.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="@string/chat_room_ephemeral_message_disabled"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_toLeftOf="@id/selected"
|
||||
style="@style/chat_room_ephemeral_item_font" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:adjustViewBounds="true"
|
||||
android:src="@drawable/check_selected" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="?attr/dividerColor" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -90,6 +90,17 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ephemeral"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:src="@drawable/ephemeral_messages_small_default"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
android:id="@+id/copy_text"
|
||||
android:title="@string/copy_text" />
|
||||
|
||||
<item
|
||||
android:id="@+id/forward"
|
||||
android:title="@string/chat_message_context_menu_forward" />
|
||||
|
||||
<item
|
||||
android:id="@+id/imdn_infos"
|
||||
android:title="@string/imdn_info" />
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
android:id="@+id/copy_text"
|
||||
android:title="@string/copy_text" />
|
||||
|
||||
<item
|
||||
android:id="@+id/forward"
|
||||
android:title="@string/chat_message_context_menu_forward" />
|
||||
|
||||
<item
|
||||
android:id="@+id/imdn_infos"
|
||||
android:title="@string/imdn_info" />
|
||||
|
|
24
app/src/main/res/menu/chat_room_menu.xml
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/chat_room_group_info"
|
||||
android:icon="@drawable/chat_room_menu_group_info"
|
||||
android:title="@string/chat_room_context_menu_group_info" />
|
||||
|
||||
<item
|
||||
android:id="@+id/chat_room_participants_devices"
|
||||
android:icon="@drawable/chat_room_menu_security"
|
||||
android:title="@string/chat_room_context_menu_participants_devices" />
|
||||
|
||||
<item
|
||||
android:id="@+id/chat_room_ephemeral_messages"
|
||||
android:icon="@drawable/chat_room_menu_ephemeral"
|
||||
android:title="@string/chat_message_context_menu_ephemeral_messages" />
|
||||
|
||||
<item
|
||||
android:id="@+id/chat_room_delete_messages"
|
||||
android:icon="@drawable/chat_room_menu_delete"
|
||||
android:title="@string/chat_message_context_menu_delete_messages" />
|
||||
|
||||
</menu>
|
|
@ -256,6 +256,27 @@
|
|||
<string name="toast_choose_chat_room_for_sharing">Select a conversation or create a new one</string>
|
||||
<string name="trust_denied">Trust has been denied. Make a call to start the authentication process again.</string>
|
||||
<string name="cant_open_file_no_app_found">Can\'t open file, no application available for this format.</string>
|
||||
<string name="chat_message_forwarded">Forwarded</string>
|
||||
<string name="chat_room_context_menu_group_info">Group info</string>
|
||||
<string name="chat_room_context_menu_participants_devices">Conversation\'s devices</string>
|
||||
<string name="chat_message_context_menu_ephemeral_messages">Ephemeral messages</string>
|
||||
<string name="chat_message_context_menu_delete_messages">Delete messages</string>
|
||||
<string name="chat_message_context_menu_forward">Forward</string>
|
||||
<string name="chat_room_ephemeral_fragment_title">Ephemeral messages</string>
|
||||
<string name="chat_room_ephemeral_messages_desc">This message will be deleted on both ends once it has been read and after the selected timeout.</string>
|
||||
<string name="chat_room_ephemeral_message_disabled">Disabled</string>
|
||||
<string name="chat_room_ephemeral_message_one_minute">1 minute</string>
|
||||
<string name="chat_room_ephemeral_message_one_hour">1 hour</string>
|
||||
<string name="chat_room_ephemeral_message_one_day">1 day</string>
|
||||
<string name="chat_room_ephemeral_message_three_days">3 days</string>
|
||||
<string name="chat_room_ephemeral_message_one_week">1 week</string>
|
||||
<plurals name="days">
|
||||
<item quantity="one">%d day</item>
|
||||
<item quantity="other">%d days</item>
|
||||
</plurals>
|
||||
<string name="chat_event_ephemeral_disabled">You disabled ephemeral messages</string>
|
||||
<string name="chat_event_ephemeral_enabled">You enabled ephemeral messages: %s</string>
|
||||
<string name="chat_event_ephemeral_lifetime_changed">Ephemeral messages expiry date: %s</string>
|
||||
|
||||
<!-- Status Bar -->
|
||||
<string name="status_connected">Connected</string>
|
||||
|
|
|
@ -101,6 +101,39 @@
|
|||
<item name="android:lineSpacingExtra">0sp</item>
|
||||
</style>
|
||||
|
||||
<style name="chat_bubble_forward_font" parent="@android:style/TextAppearance.Small">
|
||||
<item name="android:textColor">@color/chat_bubble_text_color</item>
|
||||
<item name="android:textSize">10sp</item>
|
||||
<item name="android:fontFamily">sans-serif</item>
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:lineSpacingExtra">3.3sp</item>
|
||||
</style>
|
||||
|
||||
<style name="chat_bubble_ephemeral_font" parent="@android:style/TextAppearance.Small">
|
||||
<item name="android:textColor">@color/primary_color</item>
|
||||
<item name="android:textSize">10sp</item>
|
||||
<item name="android:fontFamily">sans-serif</item>
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:lineSpacingExtra">3.3sp</item>
|
||||
</style>
|
||||
|
||||
<style name="chat_room_ephemeral_desc_font" parent="android:style/TextAppearance.Large">
|
||||
<item name="android:textColor">?attr/primaryTextColor</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
</style>
|
||||
|
||||
<style name="chat_room_ephemeral_item_font" parent="android:style/TextAppearance.Large">
|
||||
<item name="android:textColor">?attr/primaryTextColor</item>
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
</style>
|
||||
|
||||
<style name="chat_room_ephemeral_selected_item_font" parent="android:style/TextAppearance.Large">
|
||||
<item name="android:textColor">?attr/primaryTextColor</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
</style>
|
||||
|
||||
<style name="chat_bubble_message_font" parent="@android:style/TextAppearance.Medium">
|
||||
<item name="android:textColor">@color/dark_grey_color</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
|
|