context menu for messages. allow to resend single messages
This commit is contained in:
parent
de3739970b
commit
d73a77643d
|
@ -15,7 +15,8 @@
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_toRightOf="@+id/message_photo"
|
android:layout_toRightOf="@+id/message_photo"
|
||||||
android:background="@drawable/message_border"
|
android:background="@drawable/message_border"
|
||||||
android:minHeight="48dp" >
|
android:minHeight="48dp"
|
||||||
|
android:longClickable="true">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -43,7 +44,6 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:autoLink="web"
|
android:autoLink="web"
|
||||||
android:textColor="@color/primarytext"
|
android:textColor="@color/primarytext"
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="?attr/TextSizeBody" />
|
android:textSize="?attr/TextSizeBody" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_toLeftOf="@+id/message_photo"
|
android:layout_toLeftOf="@+id/message_photo"
|
||||||
android:background="@drawable/message_border"
|
android:background="@drawable/message_border"
|
||||||
android:minHeight="48dp" >
|
android:minHeight="48dp"
|
||||||
|
android:longClickable="true">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -43,7 +44,6 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:autoLink="web"
|
android:autoLink="web"
|
||||||
android:textColor="@color/primarytext"
|
android:textColor="@color/primarytext"
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="?attr/TextSizeBody" />
|
android:textSize="?attr/TextSizeBody" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|
17
res/menu/message_context.xml
Normal file
17
res/menu/message_context.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/copy_text"
|
||||||
|
android:title="@string/copy_text"/>
|
||||||
|
<item
|
||||||
|
android:id="@+id/share_image"
|
||||||
|
android:title="@string/share_image"/>
|
||||||
|
<item
|
||||||
|
android:id="@+id/copy_url"
|
||||||
|
android:title="@string/copy_original_url" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/send_again"
|
||||||
|
android:title="@string/send_again"/>
|
||||||
|
|
||||||
|
</menu>
|
|
@ -272,5 +272,14 @@
|
||||||
<string name="image_file_deleted">The image file has been deleted</string>
|
<string name="image_file_deleted">The image file has been deleted</string>
|
||||||
<string name="not_connected_try_again">You are not connected. Try again later</string>
|
<string name="not_connected_try_again">You are not connected. Try again later</string>
|
||||||
<string name="check_image_filesize">Check image file size</string>
|
<string name="check_image_filesize">Check image file size</string>
|
||||||
|
<string name="message_options">Message options</string>
|
||||||
|
<string name="copy_text">Copy text</string>
|
||||||
|
<string name="share_image">Share image</string>
|
||||||
|
<string name="copy_original_url">Copy original URL</string>
|
||||||
|
<string name="send_again">Send again</string>
|
||||||
|
<string name="image_url">Image URL</string>
|
||||||
|
<string name="message_text">Message text</string>
|
||||||
|
<string name="url_copied_to_clipboard">URL copied to clipboard</string>
|
||||||
|
<string name="message_copied_to_clipboard">Message copied to clipboard</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
|
@ -431,6 +431,11 @@ public class Message extends AbstractEntity {
|
||||||
params.size = Long.parseLong(parts[0]);
|
params.size = Long.parseLong(parts[0]);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
params.origin = parts[0];
|
params.origin = parts[0];
|
||||||
|
try {
|
||||||
|
params.url = new URL(parts[0]);
|
||||||
|
} catch (MalformedURLException e1) {
|
||||||
|
params.url = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (parts.length == 3) {
|
} else if (parts.length == 3) {
|
||||||
try {
|
try {
|
||||||
|
@ -450,6 +455,11 @@ public class Message extends AbstractEntity {
|
||||||
}
|
}
|
||||||
} else if (parts.length == 4) {
|
} else if (parts.length == 4) {
|
||||||
params.origin = parts[0];
|
params.origin = parts[0];
|
||||||
|
try {
|
||||||
|
params.url = new URL(parts[0]);
|
||||||
|
} catch (MalformedURLException e1) {
|
||||||
|
params.url = null;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
params.size = Long.parseLong(parts[1]);
|
params.size = Long.parseLong(parts[1]);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
|
@ -470,6 +480,7 @@ public class Message extends AbstractEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImageParams {
|
public class ImageParams {
|
||||||
|
public URL url;
|
||||||
public long size = 0;
|
public long size = 0;
|
||||||
public int width = 0;
|
public int width = 0;
|
||||||
public int height = 0;
|
public int height = 0;
|
||||||
|
|
|
@ -1924,4 +1924,21 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resendFailedMessages(Message message) {
|
||||||
|
List<Message> messages = new ArrayList<Message>();
|
||||||
|
Message current = message;
|
||||||
|
while(current.getStatus() == Message.STATUS_SEND_FAILED) {
|
||||||
|
messages.add(current);
|
||||||
|
if (current.mergable(current.next())) {
|
||||||
|
current = current.next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(Message msg: messages) {
|
||||||
|
markMessage(msg, Message.STATUS_WAITING);
|
||||||
|
this.resendMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,7 @@ public class ConversationActivity extends XmppActivity implements
|
||||||
xmppConnectionService.getNotificationService()
|
xmppConnectionService.getNotificationService()
|
||||||
.setOpenConversation(null);
|
.setOpenConversation(null);
|
||||||
}
|
}
|
||||||
|
closeContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,6 +11,7 @@ import eu.siacs.conversations.crypto.PgpEngine;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Contact;
|
import eu.siacs.conversations.entities.Contact;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
|
import eu.siacs.conversations.entities.Downloadable;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
import eu.siacs.conversations.entities.MucOptions;
|
import eu.siacs.conversations.entities.MucOptions;
|
||||||
import eu.siacs.conversations.entities.Presences;
|
import eu.siacs.conversations.entities.Presences;
|
||||||
|
@ -33,9 +34,12 @@ import android.content.IntentSender.SendIntentException;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Selection;
|
import android.text.Selection;
|
||||||
|
import android.view.ContextMenu;
|
||||||
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -45,6 +49,8 @@ import android.widget.AbsListView.OnScrollListener;
|
||||||
import android.widget.TextView.OnEditorActionListener;
|
import android.widget.TextView.OnEditorActionListener;
|
||||||
import android.widget.AbsListView;
|
import android.widget.AbsListView;
|
||||||
|
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
|
@ -193,6 +199,7 @@ public class ConversationFragment extends Fragment {
|
||||||
};
|
};
|
||||||
|
|
||||||
private ConversationActivity activity;
|
private ConversationActivity activity;
|
||||||
|
private Message selectedMessage;
|
||||||
|
|
||||||
private void sendMessage() {
|
private void sendMessage() {
|
||||||
if (this.conversation == null) {
|
if (this.conversation == null) {
|
||||||
|
@ -326,9 +333,100 @@ public class ConversationFragment extends Fragment {
|
||||||
});
|
});
|
||||||
messagesView.setAdapter(messageListAdapter);
|
messagesView.setAdapter(messageListAdapter);
|
||||||
|
|
||||||
|
registerForContextMenu(messagesView);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||||
|
ContextMenuInfo menuInfo) {
|
||||||
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
|
AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
|
||||||
|
this.selectedMessage = this.messageList.get(acmi.position);
|
||||||
|
populateContextMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateContextMenu(ContextMenu menu) {
|
||||||
|
if (this.selectedMessage.getType() != Message.TYPE_STATUS) {
|
||||||
|
activity.getMenuInflater().inflate(R.menu.message_context, menu);
|
||||||
|
menu.setHeaderTitle(R.string.message_options);
|
||||||
|
MenuItem copyText = menu.findItem(R.id.copy_text);
|
||||||
|
MenuItem shareImage = menu.findItem(R.id.share_image);
|
||||||
|
MenuItem sendAgain = menu.findItem(R.id.send_again);
|
||||||
|
MenuItem copyUrl = menu.findItem(R.id.copy_url);
|
||||||
|
if (this.selectedMessage.getType() != Message.TYPE_TEXT
|
||||||
|
|| this.selectedMessage.getDownloadable() != null) {
|
||||||
|
copyText.setVisible(false);
|
||||||
|
}
|
||||||
|
if (this.selectedMessage.getType() != Message.TYPE_IMAGE
|
||||||
|
|| (this.selectedMessage.getDownloadable() != null && this.selectedMessage
|
||||||
|
.getDownloadable().getStatus() == Downloadable.STATUS_DELETED)) {
|
||||||
|
shareImage.setVisible(false);
|
||||||
|
}
|
||||||
|
if (this.selectedMessage.getStatus() != Message.STATUS_SEND_FAILED) {
|
||||||
|
sendAgain.setVisible(false);
|
||||||
|
}
|
||||||
|
if ((this.selectedMessage.getType() != Message.TYPE_IMAGE && this.selectedMessage
|
||||||
|
.getDownloadable() == null)
|
||||||
|
|| this.selectedMessage.getImageParams().url == null) {
|
||||||
|
copyUrl.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.share_image:
|
||||||
|
shareImage(selectedMessage);
|
||||||
|
return true;
|
||||||
|
case R.id.copy_text:
|
||||||
|
copyText(selectedMessage);
|
||||||
|
return true;
|
||||||
|
case R.id.send_again:
|
||||||
|
resendMessage(selectedMessage);
|
||||||
|
return true;
|
||||||
|
case R.id.copy_url:
|
||||||
|
copyUrl(selectedMessage);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return super.onContextItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shareImage(Message message) {
|
||||||
|
Intent shareIntent = new Intent();
|
||||||
|
shareIntent.setAction(Intent.ACTION_SEND);
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_STREAM,
|
||||||
|
activity.xmppConnectionService.getFileBackend()
|
||||||
|
.getJingleFileUri(message));
|
||||||
|
shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
shareIntent.setType("image/webp");
|
||||||
|
activity.startActivity(Intent.createChooser(shareIntent,
|
||||||
|
getText(R.string.share_with)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyText(Message message) {
|
||||||
|
if (activity.copyTextToClipboard(message.getMergedBody(),
|
||||||
|
R.string.message_text)) {
|
||||||
|
Toast.makeText(activity, R.string.message_copied_to_clipboard,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resendMessage(Message message) {
|
||||||
|
activity.xmppConnectionService.resendFailedMessages(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyUrl(Message message) {
|
||||||
|
if (activity.copyTextToClipboard(
|
||||||
|
message.getImageParams().url.toString(), R.string.image_url)) {
|
||||||
|
Toast.makeText(activity, R.string.url_copied_to_clipboard,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void privateMessageWith(String counterpart) {
|
protected void privateMessageWith(String counterpart) {
|
||||||
this.mEditMessage.setText("");
|
this.mEditMessage.setText("");
|
||||||
this.conversation.setNextPresence(counterpart);
|
this.conversation.setNextPresence(counterpart);
|
||||||
|
@ -437,7 +535,8 @@ public class ConversationFragment extends Fragment {
|
||||||
for (Message message : this.conversation.getMessages()) {
|
for (Message message : this.conversation.getMessages()) {
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_PGP
|
if (message.getEncryption() == Message.ENCRYPTION_PGP
|
||||||
&& (message.getStatus() == Message.STATUS_RECEIVED || message
|
&& (message.getStatus() == Message.STATUS_RECEIVED || message
|
||||||
.getStatus() >= Message.STATUS_SEND) && message.getDownloadable() == null) {
|
.getStatus() >= Message.STATUS_SEND)
|
||||||
|
&& message.getDownloadable() == null) {
|
||||||
if (!mEncryptedMessages.contains(message)) {
|
if (!mEncryptedMessages.contains(message)) {
|
||||||
mEncryptedMessages.add(message);
|
mEncryptedMessages.add(message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -389,7 +389,7 @@ public class EditAccountActivity extends XmppActivity {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
|
||||||
if (OtrFingerprintToClipBoard(fingerprint)) {
|
if (copyTextToClipboard(fingerprint,R.string.otr_fingerprint)) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
EditAccountActivity.this,
|
EditAccountActivity.this,
|
||||||
R.string.toast_message_otr_fingerprint,
|
R.string.toast_message_otr_fingerprint,
|
||||||
|
@ -409,15 +409,4 @@ public class EditAccountActivity extends XmppActivity {
|
||||||
this.mStats.setVisibility(View.GONE);
|
this.mStats.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean OtrFingerprintToClipBoard(String fingerprint) {
|
|
||||||
ClipboardManager mClipBoardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
|
||||||
String label = getResources().getString(R.string.otr_fingerprint);
|
|
||||||
if (mClipBoardManager != null) {
|
|
||||||
ClipData mClipData = ClipData.newPlainText(label, fingerprint);
|
|
||||||
mClipBoardManager.setPrimaryClip(mClipData);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.AlertDialog.Builder;
|
import android.app.AlertDialog.Builder;
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipboardManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
@ -532,6 +534,17 @@ public abstract class XmppActivity extends Activity {
|
||||||
return ((int) (dp * metrics.density));
|
return ((int) (dp * metrics.density));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean copyTextToClipboard(String text,int labelResId) {
|
||||||
|
ClipboardManager mClipBoardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||||
|
String label = getResources().getString(labelResId);
|
||||||
|
if (mClipBoardManager != null) {
|
||||||
|
ClipData mClipData = ClipData.newPlainText(label, text);
|
||||||
|
mClipBoardManager.setPrimaryClip(mClipData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public AvatarService avatarService() {
|
public AvatarService avatarService() {
|
||||||
return xmppConnectionService.getAvatarService();
|
return xmppConnectionService.getAvatarService();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,15 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
private OnContactPictureClicked mOnContactPictureClickedListener;
|
private OnContactPictureClicked mOnContactPictureClickedListener;
|
||||||
private OnContactPictureLongClicked mOnContactPictureLongClickedListener;
|
private OnContactPictureLongClicked mOnContactPictureLongClickedListener;
|
||||||
|
|
||||||
|
private OnLongClickListener openContextMenu = new OnLongClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View v) {
|
||||||
|
v.showContextMenu();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public MessageAdapter(ConversationActivity activity, List<Message> messages) {
|
public MessageAdapter(ConversationActivity activity, List<Message> messages) {
|
||||||
super(activity, 0, messages);
|
super(activity, 0, messages);
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
|
@ -259,6 +268,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
startDonwloadable(message);
|
startDonwloadable(message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
viewHolder.download_button.setOnLongClickListener(openContextMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayImageMessage(ViewHolder viewHolder,
|
private void displayImageMessage(ViewHolder viewHolder,
|
||||||
|
@ -292,23 +302,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
getContext().startActivity(intent);
|
getContext().startActivity(intent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
viewHolder.image.setOnLongClickListener(new OnLongClickListener() {
|
viewHolder.image.setOnLongClickListener(openContextMenu);
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onLongClick(View v) {
|
|
||||||
Intent shareIntent = new Intent();
|
|
||||||
shareIntent.setAction(Intent.ACTION_SEND);
|
|
||||||
shareIntent.putExtra(Intent.EXTRA_STREAM,
|
|
||||||
activity.xmppConnectionService.getFileBackend()
|
|
||||||
.getJingleFileUri(message));
|
|
||||||
shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
shareIntent.setType("image/webp");
|
|
||||||
getContext().startActivity(
|
|
||||||
Intent.createChooser(shareIntent,
|
|
||||||
getContext().getText(R.string.share_with)));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in a new issue