安全子
,前提是整个消息都已正确加密和签名。
例如,“分离签名”不被视为安全。
-OpenPGP 本身并不不安全。
-大多数公开讨论的 OpenPGP 安全问题
-实际上都源于工具或应用的糟糕可用性或糟糕实现(或两者兼而有之)。
-区分 OpenPGP(IETF 加密标准)
-和 GnuPG (GPG)(实现 OpenPGP 的命令行工具)尤为重要。
-许多对 OpenPGP 的公开批评实际上是在讨论 GnuPG,而 Delta Chat 从未使用过 GnuPG。
-Delta Chat 而是使用 OpenPGP Rust 实现 rPGP,
-作为 独立的“pgp”软件包 提供,
-并且 在 2019 年进行了安全审计。
+OpenPGP is not insecure by itself.
+Most publically discussed OpenPGP security problems
+actually stem from bad usability or bad implementations of tools or apps (or both).
+It is particularly important to distinguish between OpenPGP, the IETF encryption standard,
+and GnuPG (GPG), a command line tool implementing OpenPGP.
+Many public critiques of OpenPGP actually discuss GnuPG which Delta Chat has never used.
+Delta Chat rather uses the OpenPGP Rust implementation rPGP,
+available as an independent “pgp” package,
+and security-audited in 2019 and 2024.
我们的目标是与其他 OpenPGP 实现者一起,
通过实施 新的 IETF OpenPGP Crypto-Refresh
diff --git a/src/main/java/com/b44t/messenger/DcContext.java b/src/main/java/com/b44t/messenger/DcContext.java
index 6636514b7..1b2ee753b 100644
--- a/src/main/java/com/b44t/messenger/DcContext.java
+++ b/src/main/java/com/b44t/messenger/DcContext.java
@@ -51,8 +51,8 @@ public class DcContext {
public final static int DC_QR_FPR_MISMATCH = 220;
public final static int DC_QR_FPR_WITHOUT_ADDR = 230;
public final static int DC_QR_ACCOUNT = 250;
- public final static int DC_QR_BACKUP = 251;
public final static int DC_QR_BACKUP2 = 252;
+ public final static int DC_QR_BACKUP_TOO_NEW = 255;
public final static int DC_QR_WEBRTC = 260;
public final static int DC_QR_PROXY = 271;
public final static int DC_QR_ADDR = 320;
@@ -188,6 +188,7 @@ public class DcContext {
public native void blockChat (int chat_id);
public native void acceptChat (int chat_id);
public DcMsg getMsg (int msg_id) { return new DcMsg(getMsgCPtr(msg_id)); }
+ public native void sendEditRequest (int msg_id, String text);
public native String getMsgInfo (int id);
public native String getMsgHtml (int msg_id);
public native void downloadFullMsg (int msg_id);
diff --git a/src/main/java/com/b44t/messenger/DcMsg.java b/src/main/java/com/b44t/messenger/DcMsg.java
index 1873fe4bc..7733f6204 100644
--- a/src/main/java/com/b44t/messenger/DcMsg.java
+++ b/src/main/java/com/b44t/messenger/DcMsg.java
@@ -170,6 +170,7 @@ public class DcMsg {
public native String getError ();
public native String getOverrideSenderName();
public native int getSenderColor();
+ public native boolean isEdited ();
public String getSenderName(DcContact dcContact) {
String overrideName = getOverrideSenderName();
diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationActivity.java b/src/main/java/org/thoughtcrime/securesms/ConversationActivity.java
index cb6c3e90a..0ac786492 100644
--- a/src/main/java/org/thoughtcrime/securesms/ConversationActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/ConversationActivity.java
@@ -195,6 +195,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private boolean isDefaultSms = true;
private boolean isSecurityInitialized = false;
private boolean successfulForwardingAttempt = false;
+ private boolean isEditing = false;
@Override
protected void onCreate(Bundle state, boolean ready) {
@@ -728,6 +729,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
* @return
*/
private ListenableFuture initializeDraft() {
+ isEditing = false;
final SettableFuture future = new SettableFuture<>();
DcMsg draft = dcContext.getDraft(chatId);
final String sharedText = RelayUtil.getSharedText(this);
@@ -1013,6 +1015,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
DcMsg msg = null;
Optional quote = inputPanel.getQuote();
Integer recompress = 0;
+ boolean editing = isEditing;
// for a quick ui feedback, we clear the related controls immediately on sending messages.
// for drafts, however, we do not change the controls, the activity may be resumed.
@@ -1021,6 +1024,18 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
inputPanel.clearQuote();
}
+ if (editing) {
+ int msgId = quote.get().getQuotedMsg().getId();
+ Util.runOnAnyBackgroundThread(() -> {
+ if (action == ACTION_SEND_OUT) {
+ dcContext.sendEditRequest(msgId, body);
+ } else {
+ dcContext.setDraft(chatId, null);
+ }
+ });
+ return future;
+ }
+
if(slideDeck!=null) {
if (action==ACTION_SEND_OUT) {
@@ -1159,7 +1174,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
return;
}
- if (composeText.getText().length() == 0 && !attachmentManager.isAttachmentPresent()) {
+ if (!isEditing && composeText.getText().length() == 0 && !attachmentManager.isAttachmentPresent()) {
buttonToggle.display(attachButton);
quickAttachmentToggle.show();
} else {
@@ -1277,9 +1292,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
}
+ @Override
+ public void onQuoteDismissed() {
+ if (isEditing) composeText.setText("");
+ isEditing = false;
+ }
+
// media selected by the system keyboard
@Override
public void onMediaSelected(@NonNull Uri uri, String contentType) {
+ if (isEditing) return;
if (MediaUtil.isImageType(contentType)) {
sendSticker(uri, contentType);
} else if (MediaUtil.isVideoType(contentType)) {
@@ -1411,6 +1433,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
public void handleReplyMessage(DcMsg msg) {
+ if (isEditing) composeText.setText("");
+ isEditing = false;
// If you modify these lines you may also want to modify ConversationItem.setQuote():
Recipient author = new Recipient(this, dcContext.getContact(msg.getFromId()));
@@ -1426,11 +1450,32 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
msg.getTimestamp(),
author,
text,
- slideDeck);
+ slideDeck,
+ false);
inputPanel.clickOnComposeInput();
}
+ @Override
+ public void handleEditMessage(DcMsg msg) {
+ isEditing = true;
+ Recipient author = new Recipient(this, dcContext.getContact(msg.getFromId()));
+
+ SlideDeck slideDeck = new SlideDeck();
+ String text = msg.getSummarytext(500);
+
+ inputPanel.setQuote(GlideApp.with(this),
+ msg,
+ msg.getTimestamp(),
+ author,
+ text,
+ slideDeck,
+ true);
+
+ setDraftText(msg.getText());
+ inputPanel.clickOnComposeInput();
+ }
+
@Override
public void onAttachmentChanged() {
handleSecurityChange(isSecureText, isDefaultSms);
diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java b/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java
index ee34cd2fc..efa7f4bab 100644
--- a/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java
+++ b/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java
@@ -325,6 +325,7 @@ public class ConversationFragment extends MessageSelectorFragment
menu.findItem(R.id.menu_context_details).setVisible(false);
menu.findItem(R.id.menu_context_share).setVisible(false);
menu.findItem(R.id.menu_context_reply).setVisible(false);
+ menu.findItem(R.id.menu_context_edit).setVisible(false);
menu.findItem(R.id.menu_context_reply_privately).setVisible(false);
menu.findItem(R.id.menu_add_to_home_screen).setVisible(false);
} else {
@@ -334,6 +335,8 @@ public class ConversationFragment extends MessageSelectorFragment
menu.findItem(R.id.menu_context_share).setVisible(messageRecord.hasFile());
boolean canReply = canReplyToMsg(messageRecord);
menu.findItem(R.id.menu_context_reply).setVisible(chat.canSend() && canReply);
+ boolean canEdit = canEditMsg(messageRecord);
+ menu.findItem(R.id.menu_context_edit).setVisible(chat.canSend() && canEdit);
boolean showReplyPrivately = !dcContext.isCommunity() && chat.isMultiUser() && !messageRecord.isOutgoing() && canReply;
menu.findItem(R.id.menu_context_reply_privately).setVisible(showReplyPrivately);
menu.findItem(R.id.menu_add_to_home_screen).setVisible(messageRecord.getType() == DcMsg.DC_MSG_WEBXDC);
@@ -377,6 +380,10 @@ public class ConversationFragment extends MessageSelectorFragment
return canReply;
}
+ static boolean canEditMsg(DcMsg dcMsg) {
+ return dcMsg.isOutgoing() && !dcMsg.isInfo() && dcMsg.getType() != DcMsg.DC_MSG_VIDEOCHAT_INVITATION && !dcMsg.hasHtml() && !dcMsg.getText().isEmpty();
+ }
+
public void handleClearChat() {
handleDeleteMessages((int) chatId, getListAdapter().getMessageIds());
}
@@ -477,6 +484,16 @@ public class ConversationFragment extends MessageSelectorFragment
listener.handleReplyMessage(message);
}
+ @SuppressLint("RestrictedApi")
+ private void handleEditMessage(final DcMsg message) {
+ if (getActivity() != null) {
+ //noinspection ConstantConditions
+ ((AppCompatActivity) getActivity()).getSupportActionBar().collapseActionView();
+ }
+
+ listener.handleEditMessage(message);
+ }
+
private void handleReplyMessagePrivately(final DcMsg msg) {
if (getActivity() != null) {
@@ -607,6 +624,7 @@ public class ConversationFragment extends MessageSelectorFragment
public interface ConversationFragmentListener {
void handleReplyMessage(DcMsg messageRecord);
+ void handleEditMessage(DcMsg messageRecord);
}
private class ConversationScrollListener extends OnScrollListener {
@@ -926,6 +944,7 @@ public class ConversationFragment extends MessageSelectorFragment
statusBarColor = window.getStatusBarColor();
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
+ Util.redMenuItem(menu, R.id.menu_context_delete_message);
setCorrectMenuVisibility(menu);
ConversationAdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth());
return true;
@@ -980,6 +999,10 @@ public class ConversationFragment extends MessageSelectorFragment
handleReplyMessage(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
actionMode.finish();
return true;
+ } else if (itemId == R.id.menu_context_edit) {
+ handleEditMessage(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
+ actionMode.finish();
+ return true;
} else if (itemId == R.id.menu_context_reply_privately) {
handleReplyMessagePrivately(getSelectedMessageRecord(getListAdapter().getSelectedItems()));
return true;
diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationItem.java b/src/main/java/org/thoughtcrime/securesms/ConversationItem.java
index 57ba34b20..77f466428 100644
--- a/src/main/java/org/thoughtcrime/securesms/ConversationItem.java
+++ b/src/main/java/org/thoughtcrime/securesms/ConversationItem.java
@@ -720,7 +720,8 @@ public class ConversationItem extends BaseConversationItem
author,
quoteTxt,
slideDeck,
- current.getType() == DcMsg.DC_MSG_STICKER);
+ current.getType() == DcMsg.DC_MSG_STICKER,
+ false);
quoteView.setVisibility(View.VISIBLE);
quoteView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
diff --git a/src/main/java/org/thoughtcrime/securesms/WelcomeActivity.java b/src/main/java/org/thoughtcrime/securesms/WelcomeActivity.java
index 75b0b06f7..12927135a 100644
--- a/src/main/java/org/thoughtcrime/securesms/WelcomeActivity.java
+++ b/src/main/java/org/thoughtcrime/securesms/WelcomeActivity.java
@@ -349,7 +349,6 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
}
DcLot qrParsed = dcContext.checkQr(qrRaw);
switch (qrParsed.getState()) {
- case DcContext.DC_QR_BACKUP:
case DcContext.DC_QR_BACKUP2:
final String finalQrRaw = qrRaw;
new AlertDialog.Builder(this)
@@ -361,6 +360,14 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
.show();
break;
+ case DcContext.DC_QR_BACKUP_TOO_NEW:
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.multidevice_receiver_title)
+ .setMessage(R.string.multidevice_receiver_needs_update)
+ .setPositiveButton(R.string.ok, null)
+ .show();
+ break;
+
default:
new AlertDialog.Builder(this)
.setMessage(R.string.qraccount_qr_code_cannot_be_used)
diff --git a/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java b/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java
index 30aa9dcd4..9b354fb53 100644
--- a/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java
+++ b/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java
@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.util.DateUtils;
public class ConversationItemFooter extends LinearLayout {
private TextView dateView;
+ private TextView editedView;
private ImageView bookmarkIndicatorView;
private ImageView secureIndicatorView;
private ImageView locationIndicatorView;
@@ -45,6 +46,7 @@ public class ConversationItemFooter extends LinearLayout {
inflate(getContext(), R.layout.conversation_item_footer, this);
dateView = findViewById(R.id.footer_date);
+ editedView = findViewById(R.id.footer_edited);
bookmarkIndicatorView = findViewById(R.id.footer_bookmark_indicator);
secureIndicatorView = findViewById(R.id.footer_secure_indicator);
locationIndicatorView = findViewById(R.id.footer_location_indicator);
@@ -62,6 +64,7 @@ public class ConversationItemFooter extends LinearLayout {
presentDate(messageRecord);
boolean bookmark = messageRecord.getOriginalMsgId() != 0 || messageRecord.getSavedMsgId() != 0;
bookmarkIndicatorView.setVisibility(bookmark ? View.VISIBLE : View.GONE);
+ editedView.setVisibility(messageRecord.isEdited() ? View.VISIBLE : View.GONE);
secureIndicatorView.setVisibility(messageRecord.isSecure() ? View.VISIBLE : View.GONE);
locationIndicatorView.setVisibility(messageRecord.hasLocation() ? View.VISIBLE : View.GONE);
presentDeliveryStatus(messageRecord);
@@ -69,6 +72,7 @@ public class ConversationItemFooter extends LinearLayout {
private void setTextColor(int color) {
dateView.setTextColor(color);
+ editedView.setTextColor(color);
bookmarkIndicatorView.setColorFilter(color);
secureIndicatorView.setColorFilter(color);
locationIndicatorView.setColorFilter(color);
diff --git a/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java b/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java
index c8c0c22b9..afa0c191f 100644
--- a/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java
+++ b/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java
@@ -120,9 +120,10 @@ public class InputPanel extends ConstraintLayout
long id,
@NonNull Recipient author,
@NonNull CharSequence body,
- @NonNull SlideDeck attachments)
+ @NonNull SlideDeck attachments,
+ @NonNull boolean isEdit)
{
- this.quoteView.setQuote(glideRequests, msg, author, body, attachments, false);
+ this.quoteView.setQuote(glideRequests, msg, author, body, attachments, false, isEdit);
int originalHeight = this.quoteView.getVisibility() == VISIBLE ? this.quoteView.getMeasuredHeight()
: 0;
@@ -141,6 +142,7 @@ public class InputPanel extends ConstraintLayout
public void clearQuoteWithoutAnimation() {
quoteView.dismiss();
+ if (listener != null) listener.onQuoteDismissed();
}
public void clearQuote() {
@@ -152,6 +154,7 @@ public class InputPanel extends ConstraintLayout
@Override
public void onAnimationEnd(@NonNull Animator animation) {
quoteView.dismiss();
+ if (listener != null) listener.onQuoteDismissed();
}
});
@@ -329,6 +332,7 @@ public class InputPanel extends ConstraintLayout
void onRecorderCanceled();
void onRecorderPermissionRequired();
void onEmojiToggle();
+ void onQuoteDismissed();
}
private static class SlideToCancel {
diff --git a/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java b/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java
index 54ab326ea..7c097aa5e 100644
--- a/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java
+++ b/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java
@@ -62,6 +62,7 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
private SlideDeck attachments;
private int messageType;
private boolean hasSticker;
+ private boolean isEdit;
public QuoteView(Context context) {
super(context);
@@ -116,13 +117,15 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
@Nullable Recipient author,
@Nullable CharSequence body,
@NonNull SlideDeck attachments,
- boolean hasSticker)
+ boolean hasSticker,
+ boolean isEdit)
{
quotedMsg = msg;
this.author = author != null ? author.getDcContact() : null;
this.body = body;
this.attachments = attachments;
this.hasSticker = hasSticker;
+ this.isEdit = isEdit;
if (hasSticker) {
this.setBackgroundResource(R.drawable.conversation_item_update_background);
@@ -146,7 +149,12 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
}
private void setQuoteAuthor(@Nullable Recipient author) {
- if (author == null) {
+ if (isEdit) {
+ authorView.setVisibility(VISIBLE);
+ authorView.setTextColor(getEditColor());
+ quoteBarView.setBackgroundColor(getEditColor());
+ authorView.setText(getContext().getString(R.string.edit_message));
+ } else if (author == null) {
authorView.setVisibility(GONE);
quoteBarView.setBackgroundColor(getForwardedColor());
} else if (quotedMsg.isForwarded()) {
@@ -275,4 +283,8 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
private int getForwardedColor() {
return getResources().getColor(hasSticker? R.color.core_dark_05 : R.color.unknown_sender);
}
+
+ private int getEditColor() {
+ return getResources().getColor(R.color.delta_accent);
+ }
}
diff --git a/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java b/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java
index b6d551130..2dd098c71 100644
--- a/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java
+++ b/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java
@@ -47,7 +47,7 @@ import java.util.Set;
*
* @author Jake McGinty
*/
-public class ContactSelectionListAdapter extends RecyclerView.Adapter
+public class ContactSelectionListAdapter extends RecyclerView.Adapter
{
private static final int VIEW_TYPE_CONTACT = 0;
private static final int MAX_CACHE_SIZE = 100;
@@ -157,7 +157,7 @@ public class ContactSelectionListAdapter extends RecyclerView.Adapter
if (!longPressSelect) {
return;
}
- int adapterPosition = getAdapterPosition();
+ int adapterPosition = getBindingAdapterPosition();
if (adapterPosition < 0) return;
int contactId = getContactId(adapterPosition);
boolean enabled = actionModeSelection.indexOfKey(adapterPosition) > -1;
@@ -244,8 +244,9 @@ public class ContactSelectionListAdapter extends RecyclerView.Adapter
this.longPressSelect = longPressSelect;
}
+ @NonNull
@Override
- public ContactSelectionListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ public ContactSelectionListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_CONTACT) {
return new ContactViewHolder(li.inflate(R.layout.contact_selection_list_item, parent, false), clickListener);
} else {
@@ -254,11 +255,10 @@ public class ContactSelectionListAdapter extends RecyclerView.Adapter
}
@Override
- public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
+ public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
int id = dcContactList[i];
DcContact dcContact = null;
- String label = null;
String name;
String addr = null;
boolean itemMultiSelect = multiSelect;
@@ -278,22 +278,21 @@ public class ContactSelectionListAdapter extends RecyclerView.Adapter
addr = dcContact.getAddr();
}
- ViewHolder holder = (ViewHolder) viewHolder;
- holder.unbind(glideRequests);
+ viewHolder.unbind(glideRequests);
boolean enabled = true;
if (dcContact == null) {
- holder.setSelected(false);
- holder.setEnabled(!isActionModeEnabled());
+ viewHolder.setSelected(false);
+ viewHolder.setEnabled(!isActionModeEnabled());
if (isActionModeEnabled()) {
enabled = false;
}
} else {
boolean selected = actionModeSelection.indexOfValue(id) > -1;
- holder.setSelected(selected);
+ viewHolder.setSelected(selected);
enabled = !(dcContact.getId() == DcContact.DC_CONTACT_ID_SELF && itemMultiSelect);
}
- holder.bind(glideRequests, id, dcContact, name, addr, label, itemMultiSelect, enabled);
- holder.setChecked(selectedContacts.contains(addr));
+ viewHolder.bind(glideRequests, id, dcContact, name, addr, null, itemMultiSelect, enabled);
+ viewHolder.setChecked(selectedContacts.contains(addr));
}
@Override
diff --git a/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java b/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java
index af8189f08..25e430456 100644
--- a/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java
+++ b/src/main/java/org/thoughtcrime/securesms/qr/QrCodeHandler.java
@@ -74,7 +74,6 @@ public class QrCodeHandler {
builder.setCancelable(false);
break;
- case DcContext.DC_QR_BACKUP:
case DcContext.DC_QR_BACKUP2:
builder.setTitle(R.string.multidevice_receiver_title);
builder.setMessage(activity.getString(R.string.multidevice_receiver_scanning_ask) + "\n\n" + activity.getString(R.string.multidevice_same_network_hint));
@@ -89,6 +88,12 @@ public class QrCodeHandler {
BackupTransferActivity.appendSSID(activity, alertDialog.findViewById(android.R.id.message));
return;
+ case DcContext.DC_QR_BACKUP_TOO_NEW:
+ builder.setTitle(R.string.multidevice_receiver_title);
+ builder.setMessage(activity.getString(R.string.multidevice_receiver_needs_update));
+ builder.setNegativeButton(R.string.ok, null);
+ break;
+
case DcContext.DC_QR_PROXY:
builder.setTitle(R.string.proxy_use_proxy);
builder.setMessage(activity.getString(R.string.proxy_use_proxy_confirm, qrParsed.getText1()));
diff --git a/src/main/java/org/thoughtcrime/securesms/util/views/ConversationAdaptiveActionsToolbar.java b/src/main/java/org/thoughtcrime/securesms/util/views/ConversationAdaptiveActionsToolbar.java
index d0c82c250..350932b67 100644
--- a/src/main/java/org/thoughtcrime/securesms/util/views/ConversationAdaptiveActionsToolbar.java
+++ b/src/main/java/org/thoughtcrime/securesms/util/views/ConversationAdaptiveActionsToolbar.java
@@ -23,11 +23,10 @@ public class ConversationAdaptiveActionsToolbar extends Toolbar {
private static final int ACTION_VIEW_WIDTH_DP = 48;
private static final int OVERFLOW_VIEW_WIDTH_DP = 36;
- private static final int ID_NEVER_SHOW_AS_ACTION_1 = R.id.menu_context_reply_privately;
- private static final int ID_NEVER_SHOW_AS_ACTION_2 = R.id.menu_context_save_attachment;
- private static final int ID_NEVER_SHOW_AS_ACTION_3 = R.id.menu_resend;
- private static final int ID_NEVER_SHOW_AS_ACTION_4 = R.id.menu_add_to_home_screen;
- private static final int ID_ALWAYS_SHOW_AS_ACTION = R.id.menu_context_forward;
+ private static final int ID_ACTION_1 = R.id.menu_context_edit;
+ private static final int ID_ACTION_2 = R.id.menu_context_copy;
+ private static final int ID_ACTION_3 = R.id.menu_context_share;
+ private static final int ID_ACTION_4 = R.id.menu_context_forward;
private final int maxShown;
@@ -74,21 +73,15 @@ public class ConversationAdaptiveActionsToolbar extends Toolbar {
nItemsToShow = Math.min(maxToShow, widthAllowed / ViewUtil.dpToPx(ACTION_VIEW_WIDTH_DP));
- menu.findItem(ID_ALWAYS_SHOW_AS_ACTION).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
- nItemsToShow--;
-
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
- boolean neverShowAsAction = item.getItemId() == ID_NEVER_SHOW_AS_ACTION_1
- || item.getItemId() == ID_NEVER_SHOW_AS_ACTION_2
- || item.getItemId() == ID_NEVER_SHOW_AS_ACTION_3
- || item.getItemId() == ID_NEVER_SHOW_AS_ACTION_4;
- boolean alwaysShowAsAction = item.getItemId() == ID_ALWAYS_SHOW_AS_ACTION;
+ boolean showAsAction = item.getItemId() == ID_ACTION_1
+ || item.getItemId() == ID_ACTION_2
+ || item.getItemId() == ID_ACTION_3
+ || item.getItemId() == ID_ACTION_4;
- if (alwaysShowAsAction) continue;
-
- if (item.isVisible() && nItemsToShow > 0 && !neverShowAsAction) {
+ if (showAsAction && item.isVisible() && nItemsToShow > 0) {
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
nItemsToShow--;
} else {
diff --git a/src/main/res/layout/conversation_item_footer.xml b/src/main/res/layout/conversation_item_footer.xml
index 30f2cca35..43ed98cb0 100644
--- a/src/main/res/layout/conversation_item_footer.xml
+++ b/src/main/res/layout/conversation_item_footer.xml
@@ -28,6 +28,19 @@
android:importantForAccessibility="no"
tools:visibility="visible"/>
+
+
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index 2d629d492..d67921878 100644
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -551,6 +551,7 @@
Als Zweitgerät hinzufügen
Auf dem ersten Gerät, gehe zu \"Einstellungen / Zweitgerät hinzufügen\" und scanne den dort angezeigten Code
Das Profil vom anderen Gerät auf dieses Gerät kopieren?
+ Das Profil, das Sie importieren möchten, stammt aus einer neueren Delta-Chat-Version.\n\nUm Fortzufahren, aktualisieren Sie dieses Gerät bitte auf die neueste Version von Delta Chat.
Einrichtung des Zweitgeräts beenden?
Dadurch wird der auf die Zwischenablage kopierte QR-Code ungültig.
(experimentell, Version 1.36 erforderlich)
diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml
index bd49c504c..7cfe7e8c0 100644
--- a/src/main/res/values-fr/strings.xml
+++ b/src/main/res/values-fr/strings.xml
@@ -7,6 +7,8 @@
Effacer la recherche
Lien
+
+ Scanner
Oui
Non
Sélectionner
@@ -26,6 +28,8 @@
Rejoindre
Réintégrer
Supprimer
+ Supprimer pour moi
+ Supprimer pour tout le monde
Info
Mise à jour
Émoji
@@ -35,9 +39,12 @@
Fermer la fenêtre
Faire suivre
Créer
+ Réinitialiser
Plus tard
Renvoyer
+ Modifié
+ Modifier le message
Archiver
@@ -193,6 +200,7 @@
Jeux
Outils
Taille
+ Publié
Ajouter à la discussion
Explorer
@@ -291,6 +299,8 @@
Sélectionner plus
Modifier le nom
+ Choisir un surnom qui s\'affichera à la place de « %1$s ». Laisser cet espace vide pour utiliser le nom choisi par le contact.
+
Surnom de \"%1$s\"
Paramètres
Avancé
@@ -308,6 +318,7 @@
Messages de l\'appareil
Messages générés localement
Les messages dans cette discussion sont générés localement par votre application Delta Chat. Cela vous permet de recevoir des informations concernant les mises à jour et problèmes rencontrés à l\'utilisation.
+ Gardez contact !\n\n🙌 Cliquez sur « code QR » sur la page d\'accueil des deux appareils. Sélectionnez « Scanner le code QR » sur un des appareils et positionnez les deux appareils l\'un vers l\'autre\n\n🌍 Si vous n\'êtes pas dans la même pièce, vous pouvez scanner le code QR pendant un appel vidéo ou partager un lien d\'invitation à partir de « Scanner le code QR »\n\n Profitez ensuite de votre expérience de messagerie sur le plus grand réseau décentralisé du monde : les emails. Contrairement aux autres applications populaires, tout cela se fait sans contrôle centralisé, suivi ou revente de vos données, celles de vos amis, collègues ou famille à de grandes entreprises.
Mettre à jour le contact
Épingler la discussion
@@ -369,6 +380,11 @@
Voulez-vous vraiment supprimer « %1$s » ?
Voulez-vous vraiment supprimer ce message ?
+
+ - Effacer %d message ici et sur le serveur ?
+ - Effacer %d messages ici et sur le serveur ?
+ - Effacer %d messages ici et sur le serveur ?
+
- Supprimer %d message ?
@@ -461,6 +477,9 @@
Envoyer \"%1$s\" à
Envoyer un message à
+ Applications temps réel
+ Activez les connexions temps réel pour les applications partagées dans les discussions. Les interlocuteurs pourront voir votre adresse IP lorsque vous lancerez l\'app.
+
Afficher les positions pour une période
Afficher les traces
@@ -637,6 +656,7 @@
Proxy invalide ou non supporté
Sauver les proxy
Effacer le proxy
+ Voulez-vous vraiment supprimer « %1$s » ?
Vos amis peuvent ajouter ce proxy en scannant le code QR.
Partager le lien
@@ -659,6 +679,8 @@
Tag privé
Travail ou famille par exemple
Tag seulement visible par vous pour vous aider à différencier les profils.
+
+ Remonter l\'élément
Supprimer le compte
Voulez-vous vraiment supprimer les données de votre compte ?
Toutes les données de compte de « %s » sur cet appareil seront effacées, y compris votre configuration de chiffrement de bout en bout, vos contacts, discussions, messages et médias. Cette action est irrévocable.
@@ -672,6 +694,8 @@
Transférer à …
+
+ Envoyer %1$d fichiers à « %2$s » ?
Envoyer %1$d fichier(s) à %2$d discussions ?
Envoyer ce texte à %1$d discussions ?\n\n« %2$s »
Partage annulé en raison de permissions manquantes.
@@ -702,6 +726,7 @@
Pour appliquer les paramètres de sécurité de l\'écran, veuillez redémarrer l\'application.
Notifications
Mentions
+ Dans les groupes passés en muet, des notifications vous sont envoyées, comme des réponses ou des réactions
Afficher
Priorité
Activer les notifications système pour les nouveaux messages
@@ -719,6 +744,7 @@
Apparence
Thème
Langue
+ Utiliser la police système
Clavier anonyme
Demander que le clavier désactive l\'apprentissage personnalisé
@@ -729,6 +755,8 @@
Gérer les clés
Utiliser les émojis système
Désactiver la prise en charge des émojis intégrés de Delta Chat
+ Lire le carnet d\'adresses du système
+ Permet de créer des conversations avec des contacts du carnet d\'adresse. Certains fournisseurs doivent d\'abord mettre en place un chiffrement de bout-en-bout.
Accès à l\'application
Discussions
Sons de messages entrants
@@ -817,6 +845,9 @@
Réactions
Réagir
+
+ %1$s a réagi %2$s à « %3$s »
+
Supprimer les anciens messages
Supprimer les messages de l\'appareil
@@ -827,6 +858,8 @@
Voulez-vous supprimer %1$d messages maintenant ainsi que tous les futurs nouveaux messages reçus « %2$s » ?\n\n⚠️ Cela inclut les courriels, les fichiers multimédia et les « Messages sauvegardés » dans tous les répertoires du serveur\n\n⚠️ N\'utilisez pas cette fonction si vous utilisez d\'autres clients de messagerie électronique en plus de Delta Chat
Cela inclus les courriels, médias et les « Messages sauvegardés » dans tous les répertoires du serveur. N\'utilisez pas cette fonction si vous voulez garder les données sur le serveur ou si vous utilisez d\'autres clients de messagerie électronique en plus de Delta Chat.
+ Activer la suppression immédiate
+ Si vous activez la suppression immédiate, vous ne pourrez pas utiliser plusieurs appareils sur ce profil.
J\'ai compris, supprimer tous ces messages
Immédiatement
@@ -929,6 +962,7 @@
Il n\'est pas garanti que tous les messages de cette discussion sont chiffrés de bout en bout.\n\nLe chiffrement de bout en bout assure la confidentialité des messages échangés par les membres d\'une discussion. Même votre fournisseur de courriel ne peut pas les lire.
%1$s a envoyé un message depuis un nouvel appareil. Appuyez pour en savoir plus.
Le chiffrement de bout en bout ne peut plus être garanti, probablement parce que %1$s a réinstallé Delta Chat ou envoyé un message depuis un nouvel appareil.\n\nVous pouvez convenir d\'une rencontre physique afin de scanner à nouveau son code QR pour ré-instaurer la garantie du chiffrement de bout en bout.
+ ⚠️ %1$s nécessite un chiffrement de bout en bout qui n\'est pas encore configuré sur cette discussion. Appuyez pour en savoir plus.
Pour établir un chiffrement de bout en bout vous pouvez rencontrer vos contacts en personne et scanner leur code QR.
En savoir plus
@@ -1071,6 +1105,8 @@
MMM D
Retirer
Sauvegardez
+
+ Annuler la sauvegarde
Nom
Choisir l\'image de groupe
Exporter la sauvegarde
diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml
index bf516090e..9dac19254 100644
--- a/src/main/res/values-it/strings.xml
+++ b/src/main/res/values-it/strings.xml
@@ -28,6 +28,8 @@
Partecipa
Ripartecipa
Elimina
+ Cancella per Me
+ Cancella per Tutti
Informazioni
Aggiorna
Emoji
@@ -381,6 +383,11 @@
Elimina chat \"%1$s\"?
Sei sicuro di voler eliminare questo messaggio?
+
+ - Cancella %d messaggio su tutti i tuoi dispositivi?
+ - Cancella %d messaggi su tutti i tuoi dispositivi?
+ - Cancella %d messaggi su tutti i tuoi dispositivi?
+
- Eliminare %d messaggio?
@@ -551,7 +558,7 @@
Aggiungi Secondo Dispositivo
Assicurati che entrambi i dispositivi siano sulla stessa rete o Wi-Fi.
- Questo crea un codice QR che il secondo dispositivo può scansionare per copiare il profilo.
+ Questo crea un codice QR che il secondo dispositivo può scansionare per copiare il profilo.\n\nAssicurati che nessun osservatore o telecamera indesiderata possa vedere la schermata seguente.
Installa Delta Chat sull\'altro tuo dispositivo (https://get.delta.chat)
Avvia Delta Chat, tocca \"Ho già un Profilo / Aggiungi come Secondo Dispositivo\" e scansiona il codice mostrato qui
diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml
index f2ef27d4c..ffc68f0b3 100644
--- a/src/main/res/values-nl/strings.xml
+++ b/src/main/res/values-nl/strings.xml
@@ -541,7 +541,7 @@
Secundair apparaat toevoegen
Zorg ervoor dat beide apparaten verbonden zijn met hetzelfde (wifi)netwerk
- Hiermee wordt een QR-code samengesteld die door het tweede apparaat kan worden gescand om het account te kopiëren.
+ Hiermee wordt een QR-code samengesteld die door het tweede apparaat kan worden gescand om het account te kopiëren.\n\nZorg dat er geen vreemden meekijken, al dan niet door een camera.
Installeer Delta Chat op je andere apparaat (https://get.delta.chat)
Start Delta Chat, druk op ‘Ik heb al een profiel → Toevoegen als secundair apparaat’ en scan de hier getoonde code
diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml
index cac41b1b2..187f616e7 100644
--- a/src/main/res/values-pl/strings.xml
+++ b/src/main/res/values-pl/strings.xml
@@ -28,6 +28,8 @@
Dołącz
Dołącz ponownie
Usuń
+ Usuń u mnie
+ Usuń u wszystkich
Informacje
Aktualizacja
Emoji
@@ -391,6 +393,12 @@
Usunąć czat „%1$s”? Nie będzie on już wyświetlany na liście czatów. Jego wiadomości pozostaną na serwerze.
Czy na pewno chcesz usunąć tę wiadomość?
+
+ - Usunąć %d wiadomość ze wszystkich urządzeń?
+ - Usunąć %d wiadomości ze wszystkich urządzeń?
+ - Usunąć %d wiadomości ze wszystkich urządzeń?
+ - Usunąć %d wiadomości ze wszystkich urządzeń?
+
- Usunąć %d wiadomość?
diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml
index 0474f5288..85163b26d 100644
--- a/src/main/res/values-ru/strings.xml
+++ b/src/main/res/values-ru/strings.xml
@@ -28,6 +28,8 @@
Присоединиться
Присоединиться снова
Удалить
+ Удалить для меня
+ Удалить для всех
Информация
Обновить
Эмодзи
@@ -391,6 +393,12 @@
Удалить чат \"%1$s\"?
Вы уверены, что хотите удалить это сообщение?
+
+ - Удалить %d сообщение на всех ваших устройствах?
+ - Удалить %d сообщения на всех ваших устройствах?
+ - Удалить %d сообщений на всех ваших устройствах?
+ - Удалить %d сообщений на всех ваших устройствах?
+
- Удалить %d сообщение?
@@ -565,7 +573,7 @@
Добавить второе устройство
Убедитесь, что оба устройства подключены к одной и той же локальной или Wi-Fi сети.
- Это создает QR-код, который можно отсканировать на втором устройстве, чтобы скопировать профиль.
+ Это позволяет создать QR-код, который можно отсканировать на втором устройстве, чтобы скопировать профиль.\n\nУбедитесь, что посторонние люди или камера не видят следующий экран.
Установите Delta Chat на другом устройстве (https://get.delta.chat)
Запустите Delta Chat, выберите \"У меня уже есть профиль / Добавить как второе устройство\" и отсканируйте код, показанный здесь
diff --git a/src/main/res/values-sq/strings.xml b/src/main/res/values-sq/strings.xml
index e162e8957..adb96a7fe 100644
--- a/src/main/res/values-sq/strings.xml
+++ b/src/main/res/values-sq/strings.xml
@@ -28,6 +28,8 @@
Hyni
Rihyni
Fshije
+ Fshije për Mua
+ Fshije për Gjithkënd
Hollësi
Përditësoje
Emoji
@@ -365,6 +367,10 @@
Jeni i sigurt se doni të fshihet “%1$s”?
Jeni i sigurt se doni të fshihet ky mesazh?
+
+ - Të fshihet %d mesazh në krejt pajisjet tuaja?
+ - Të fshihen %d mesazhe në krejt pajisjet tuaja?
+
- Të fshihet %d mesazh?
diff --git a/src/main/res/values-tr/strings.xml b/src/main/res/values-tr/strings.xml
index e7becbfc2..9dd8dbd17 100644
--- a/src/main/res/values-tr/strings.xml
+++ b/src/main/res/values-tr/strings.xml
@@ -541,7 +541,7 @@
İkinci Aygıt Ekle
Her iki aygıtın da aynı Wi-Fi\'da ya da ağda olduğundan emin olun
- Bu, ikinci aygıtın profili kopyalamak için tarayabileceği bir QR kodu oluşturur.
+ Bu, ikinci aygıtın profili kopyalamak için tarayabileceği bir QR kodu oluşturur.\n\nİstenmeyen gözlemcinin ya da kameranın aşağıdaki ekranı göremediğinden emin olun.
Delta Chat\'i diğer aygıtınıza kurun (https://get.delta.chat)
Delta Chat\'i başlatın, “Zaten Bir Profilim Var / İkinci Aygıt Olarak Ekle”ye dokunun ve burada gösterilen kodu tarayın
diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml
index 67b4ea205..2c888c44c 100644
--- a/src/main/res/values-zh-rCN/strings.xml
+++ b/src/main/res/values-zh-rCN/strings.xml
@@ -28,6 +28,8 @@
加入
重新加入
删除
+ 为我删除
+ 为所有人删除
信息
更新
Emoji
@@ -358,6 +360,9 @@
删除聊天“%1$s”?它将不再显示在聊天列表中,其消息将保留在服务器上。
您确定要删除这条消息吗?
+
+ - 是否删除所有设备上的 %d 条消息?
+
- 删除 %d 条消息吗?
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 4c768c796..f70b73d6a 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -569,6 +569,7 @@
Add as Second Device
On the first device, go to “Settings / Add Second Device“ and scan the code shown there
Copy the profile from the other device to this device?
+ The profile you want to import is from a newer Delta Chat version.\n\nTo continue setting up second device, please update this device to the latest version of Delta Chat.
Abort setting up second device?
This will invalidate the QR code copied to clipboard.
(experimental, version 1.36 required)