aboutsummaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
authorChristian S <christian@pix-art.de>2016-02-20 15:28:01 +0100
committerChristian S <christian@pix-art.de>2016-02-20 15:28:01 +0100
commitfe52f30c5bbd6f4403b1fe97964488611a3c7276 (patch)
tree562388d395f2547b85c49d8979dbab6193d08199 /src/main
parent2879ddadca409d05eb71ca0863980ed0ec6b1023 (diff)
parent3bde4dbedb80a8e1de89c09f58d842d7382598e8 (diff)
Merge branch 'siacs/master' into development
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Conversation.java38
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Message.java53
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Presence.java26
-rw-r--r--src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java6
-rw-r--r--src/main/java/eu/siacs/conversations/generator/IqGenerator.java1
-rw-r--r--src/main/java/eu/siacs/conversations/generator/MessageGenerator.java3
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java88
-rw-r--r--src/main/java/eu/siacs/conversations/parser/PresenceParser.java2
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java14
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java56
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java7
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java84
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java16
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditMessage.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/SettingsActivity.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java15
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java2
-rw-r--r--src/main/res/drawable-hdpi/ic_lock_black_18dp.pngbin0 -> 368 bytes
-rw-r--r--src/main/res/drawable-hdpi/ic_lock_white_18dp.pngbin0 -> 371 bytes
-rw-r--r--src/main/res/drawable-hdpi/ic_mode_edit_black_18dp.pngbin0 -> 264 bytes
-rw-r--r--src/main/res/drawable-hdpi/ic_mode_edit_white_18dp.pngbin0 -> 299 bytes
-rw-r--r--src/main/res/drawable-hdpi/ic_secure_indicator.pngbin294 -> 384 bytes
-rw-r--r--src/main/res/drawable-hdpi/ic_secure_indicator_white.pngbin322 -> 0 bytes
-rw-r--r--src/main/res/drawable-mdpi/ic_lock_black_18dp.pngbin0 -> 293 bytes
-rw-r--r--src/main/res/drawable-mdpi/ic_lock_white_18dp.pngbin0 -> 298 bytes
-rw-r--r--src/main/res/drawable-mdpi/ic_mode_edit_black_18dp.pngbin0 -> 229 bytes
-rw-r--r--src/main/res/drawable-mdpi/ic_mode_edit_white_18dp.pngbin0 -> 249 bytes
-rw-r--r--src/main/res/drawable-mdpi/ic_secure_indicator.pngbin295 -> 0 bytes
-rw-r--r--src/main/res/drawable-mdpi/ic_secure_indicator_white.pngbin306 -> 0 bytes
-rw-r--r--src/main/res/drawable-xhdpi/ic_lock_black_18dp.pngbin0 -> 397 bytes
-rw-r--r--src/main/res/drawable-xhdpi/ic_lock_white_18dp.pngbin0 -> 399 bytes
-rw-r--r--src/main/res/drawable-xhdpi/ic_mode_edit_black_18dp.pngbin0 -> 291 bytes
-rw-r--r--src/main/res/drawable-xhdpi/ic_mode_edit_white_18dp.pngbin0 -> 351 bytes
-rw-r--r--src/main/res/drawable-xhdpi/ic_secure_indicator.pngbin410 -> 0 bytes
-rw-r--r--src/main/res/drawable-xhdpi/ic_secure_indicator_white.pngbin434 -> 0 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/ic_lock_black_18dp.pngbin0 -> 559 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/ic_lock_white_18dp.pngbin0 -> 558 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/ic_mode_edit_black_18dp.pngbin0 -> 336 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/ic_mode_edit_white_18dp.pngbin0 -> 436 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/ic_secure_indicator.pngbin380 -> 0 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/ic_secure_indicator_white.pngbin441 -> 0 bytes
-rw-r--r--src/main/res/drawable-xxxhdpi/ic_lock_black_18dp.pngbin0 -> 636 bytes
-rw-r--r--src/main/res/drawable-xxxhdpi/ic_lock_white_18dp.pngbin0 -> 760 bytes
-rw-r--r--src/main/res/drawable-xxxhdpi/ic_mode_edit_black_18dp.pngbin0 -> 366 bytes
-rw-r--r--src/main/res/drawable-xxxhdpi/ic_mode_edit_white_18dp.pngbin0 -> 490 bytes
-rw-r--r--src/main/res/layout/message_received.xml12
-rw-r--r--src/main/res/layout/message_sent.xml12
-rw-r--r--src/main/res/menu/message_context.xml4
-rw-r--r--src/main/res/values-de/strings.xml37
-rw-r--r--src/main/res/values-pt-rBR/strings.xml0
-rw-r--r--src/main/res/values/strings.xml31
-rw-r--r--src/main/res/xml/preferences.xml7
52 files changed, 398 insertions, 121 deletions
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index 1e18f6967..2e97dc8d5 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -83,6 +83,7 @@ public class Conversation extends AbstractEntity implements Blockable {
private ChatState mIncomingChatState = Config.DEFAULT_CHATSTATE;
private String mLastReceivedOtrMessageId = null;
private String mFirstMamReference = null;
+ private Message correctingMessage;
public boolean hasMessagesLeftOnServer() {
return messagesLeftOnServer;
@@ -227,6 +228,24 @@ public class Conversation extends AbstractEntity implements Blockable {
return null;
}
+ public Message findMessageWithRemoteIdAndCounterpart(String id, Jid counterpart, boolean received, boolean carbon) {
+ synchronized (this.messages) {
+ for(int i = this.messages.size() - 1; i >= 0; --i) {
+ Message message = messages.get(i);
+ if (counterpart.equals(message.getCounterpart())
+ && ((message.getStatus() == Message.STATUS_RECEIVED) == received)
+ && (carbon == message.isCarbon() || received) ) {
+ if (id.equals(message.getRemoteMsgId())) {
+ return message;
+ } else {
+ return null;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
public Message findSentMessageWithUuid(String id) {
synchronized (this.messages) {
for (Message message : this.messages) {
@@ -295,6 +314,14 @@ public class Conversation extends AbstractEntity implements Blockable {
return getLongAttribute("last_clear_history", 0);
}
+ public void setCorrectingMessage(Message correctingMessage) {
+ this.correctingMessage = correctingMessage;
+ }
+
+ public Message getCorrectingMessage() {
+ return this.correctingMessage;
+ }
+
public interface OnMessageFound {
void onMessageFound(final Message message);
}
@@ -511,15 +538,18 @@ public class Conversation extends AbstractEntity implements Blockable {
return mSmp;
}
- public void startOtrIfNeeded() {
- if (this.otrSession != null
- && this.otrSession.getSessionStatus() != SessionStatus.ENCRYPTED) {
+ public boolean startOtrIfNeeded() {
+ if (this.otrSession != null && this.otrSession.getSessionStatus() != SessionStatus.ENCRYPTED) {
try {
this.otrSession.startSession();
+ return true;
} catch (OtrException e) {
this.resetOtrSession();
+ return false;
}
- }
+ } else {
+ return true;
+ }
}
public boolean endOtrIfNeeded() {
diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java
index f37ae4271..63db9a447 100644
--- a/src/main/java/eu/siacs/conversations/entities/Message.java
+++ b/src/main/java/eu/siacs/conversations/entities/Message.java
@@ -52,6 +52,7 @@ public class Message extends AbstractEntity {
public static final String STATUS = "status";
public static final String TYPE = "type";
public static final String CARBON = "carbon";
+ public static final String EDITED = "edited";
public static final String REMOTE_MSG_ID = "remoteMsgId";
public static final String SERVER_MSG_ID = "serverMsgId";
public static final String RELATIVE_FILE_PATH = "relativeFilePath";
@@ -71,6 +72,7 @@ public class Message extends AbstractEntity {
protected int status;
protected int type;
protected boolean carbon = false;
+ protected String edited = null;
protected String relativeFilePath;
protected boolean read = true;
protected String remoteMsgId = null;
@@ -104,7 +106,8 @@ public class Message extends AbstractEntity {
null,
null,
null,
- true);
+ true,
+ null);
this.conversation = conversation;
}
@@ -112,7 +115,8 @@ public class Message extends AbstractEntity {
final Jid trueCounterpart, final String body, final long timeSent,
final int encryption, final int status, final int type, final boolean carbon,
final String remoteMsgId, final String relativeFilePath,
- final String serverMsgId, final String fingerprint, final boolean read) {
+ final String serverMsgId, final String fingerprint, final boolean read,
+ final String edited) {
this.uuid = uuid;
this.conversationUuid = conversationUUid;
this.counterpart = counterpart;
@@ -128,6 +132,7 @@ public class Message extends AbstractEntity {
this.serverMsgId = serverMsgId;
this.axolotlFingerprint = fingerprint;
this.read = read;
+ this.edited = edited;
}
public static Message fromCursor(Cursor cursor) {
@@ -162,12 +167,13 @@ public class Message extends AbstractEntity {
cursor.getInt(cursor.getColumnIndex(ENCRYPTION)),
cursor.getInt(cursor.getColumnIndex(STATUS)),
cursor.getInt(cursor.getColumnIndex(TYPE)),
- cursor.getInt(cursor.getColumnIndex(CARBON))>0,
+ cursor.getInt(cursor.getColumnIndex(CARBON)) > 0,
cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)),
cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)),
cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)),
cursor.getString(cursor.getColumnIndex(FINGERPRINT)),
- cursor.getInt(cursor.getColumnIndex(READ)) > 0);
+ cursor.getInt(cursor.getColumnIndex(READ)) > 0,
+ cursor.getString(cursor.getColumnIndex(EDITED)));
}
public static Message createStatusMessage(Conversation conversation, String body) {
@@ -211,7 +217,8 @@ public class Message extends AbstractEntity {
values.put(RELATIVE_FILE_PATH, relativeFilePath);
values.put(SERVER_MSG_ID, serverMsgId);
values.put(FINGERPRINT, axolotlFingerprint);
- values.put(READ,read);
+ values.put(READ,read ? 1 : 0);
+ values.put(EDITED, edited);
return values;
}
@@ -340,10 +347,22 @@ public class Message extends AbstractEntity {
this.carbon = carbon;
}
+ public void setEdited(String edited) {
+ this.edited = edited;
+ }
+
+ public boolean edited() {
+ return this.edited != null;
+ }
+
public void setTrueCounterpart(Jid trueCounterpart) {
this.trueCounterpart = trueCounterpart;
}
+ public Jid getTrueCounterpart() {
+ return this.trueCounterpart;
+ }
+
public Transferable getTransferable() {
return this.transferable;
}
@@ -409,6 +428,21 @@ public class Message extends AbstractEntity {
}
}
+ public boolean isLastCorrectableMessage() {
+ Message next = next();
+ while(next != null) {
+ if (next.isCorrectable()) {
+ return false;
+ }
+ next = next.next();
+ }
+ return isCorrectable();
+ }
+
+ private boolean isCorrectable() {
+ return getStatus() != STATUS_RECEIVED && !isCarbon();
+ }
+
public boolean mergeable(final Message message) {
return message != null &&
(message.getType() == Message.TYPE_TEXT &&
@@ -421,6 +455,7 @@ public class Message extends AbstractEntity {
this.getEncryption() == message.getEncryption() &&
this.getCounterpart() != null &&
this.getCounterpart().equals(message.getCounterpart()) &&
+ this.edited() == message.edited() &&
(message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) &&
!GeoHelper.isGeoUri(message.getBody()) &&
!GeoHelper.isGeoUri(this.body) &&
@@ -510,6 +545,14 @@ public class Message extends AbstractEntity {
}
}
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getEditedId() {
+ return edited;
+ }
+
public enum Decision {
MUST,
SHOULD,
diff --git a/src/main/java/eu/siacs/conversations/entities/Presence.java b/src/main/java/eu/siacs/conversations/entities/Presence.java
index 69cde8327..442f1bcac 100644
--- a/src/main/java/eu/siacs/conversations/entities/Presence.java
+++ b/src/main/java/eu/siacs/conversations/entities/Presence.java
@@ -1,6 +1,7 @@
package eu.siacs.conversations.entities;
import java.lang.Comparable;
+import java.util.Locale;
import eu.siacs.conversations.xml.Element;
@@ -32,21 +33,24 @@ public class Presence implements Comparable {
this.hash = hash;
}
- public static Presence parse(Element show, Element caps) {
+ public static Presence parse(String show, Element caps) {
final String hash = caps == null ? null : caps.getAttribute("hash");
final String ver = caps == null ? null : caps.getAttribute("ver");
- if ((show == null) || (show.getContent() == null)) {
+ if (show == null) {
return new Presence(Status.ONLINE, ver, hash);
- } else if (show.getContent().equals("away")) {
- return new Presence(Status.AWAY, ver, hash);
- } else if (show.getContent().equals("xa")) {
- return new Presence(Status.XA, ver, hash);
- } else if (show.getContent().equals("chat")) {
- return new Presence(Status.CHAT, ver, hash);
- } else if (show.getContent().equals("dnd")) {
- return new Presence(Status.DND, ver, hash);
} else {
- return new Presence(Status.OFFLINE, ver, hash);
+ switch (show.toLowerCase(Locale.US)) {
+ case "away":
+ return new Presence(Status.AWAY, ver, hash);
+ case "xa":
+ return new Presence(Status.XA, ver, hash);
+ case "dnd":
+ return new Presence(Status.DND, ver, hash);
+ case "chat":
+ return new Presence(Status.CHAT, ver, hash);
+ default:
+ return new Presence(Status.ONLINE, ver, hash);
+ }
}
}
diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
index b9c95e6e5..f63b4d092 100644
--- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -38,6 +38,9 @@ public abstract class AbstractGenerator {
"urn:xmpp:chat-markers:0",
"urn:xmpp:receipts"
};
+ private final String[] MESSAGE_CORRECTION_FEATURES = {
+ "urn:xmpp:message-correct:0"
+ };
private String mVersion = null;
private String mVersionOs = null;
@@ -99,6 +102,9 @@ public abstract class AbstractGenerator {
if (mXmppConnectionService.confirmMessages()) {
features.addAll(Arrays.asList(MESSAGE_CONFIRMATION_FEATURES));
}
+ if (mXmppConnectionService.allowMessageCorrection()) {
+ features.addAll(Arrays.asList(MESSAGE_CORRECTION_FEATURES));
+ }
Collections.sort(features);
return features;
}
diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
index bb373c75c..c6b4a4502 100644
--- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
@@ -332,6 +332,7 @@ public class IqGenerator extends AbstractGenerator {
Data data = new Data();
data.setFormType("http://jabber.org/protocol/pubsub#publish-options");
data.put("secret",secret);
+ data.submit();
enable.addChild(data);
return packet;
}
diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
index b849f56f4..0e7a8ce6e 100644
--- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
@@ -47,6 +47,9 @@ public class MessageGenerator extends AbstractGenerator {
}
packet.setFrom(account.getJid());
packet.setId(message.getUuid());
+ if (message.edited()) {
+ packet.addChild("replace","urn:xmpp:message-correct:0").setAttribute("id",message.getEditedId());
+ }
return packet;
}
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index 3bf488316..f01e7ce1f 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -9,6 +9,7 @@ import net.java.otr4j.session.SessionStatus;
import java.util.ArrayList;
import java.util.Set;
+import java.util.UUID;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
@@ -117,13 +118,6 @@ public class MessageParser extends AbstractParser implements
return finishedMessage;
}
- private Message parsePGPChat(final Conversation conversation, String pgpEncrypted, int status) {
- final Message message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
- PgpDecryptionService pgpDecryptionService = conversation.getAccount().getPgpDecryptionService();
- pgpDecryptionService.add(message);
- return message;
- }
-
private class Invite {
Jid jid;
String password;
@@ -297,6 +291,8 @@ public class MessageParser extends AbstractParser implements
final String body = packet.getBody();
final Element mucUserElement = packet.findChild("x", "http://jabber.org/protocol/muc#user");
final String pgpEncrypted = packet.findChildContent("x", "jabber:x:encrypted");
+ final Element replaceElement = packet.findChild("replace","urn:xmpp:message-correct:0");
+ final String replacementId = replaceElement == null ? null : replaceElement.getAttribute("id");
final Element axolotlEncrypted = packet.findChild(XmppAxolotlMessage.CONTAINERTAG, AxolotlService.PEP_PREFIX);
int status;
final Jid counterpart;
@@ -310,7 +306,7 @@ public class MessageParser extends AbstractParser implements
}
boolean isTypeGroupChat = packet.getType() == MessagePacket.TYPE_GROUPCHAT;
- boolean isProperlyAddressed = (to != null ) && (!to.isBareJid() || account.countPresences() == 1);
+ boolean isProperlyAddressed = (to != null ) && (!to.isBareJid() || account.countPresences() <= 1);
boolean isMucStatusMessage = from.isBareJid() && mucUserElement != null && mucUserElement.hasChild("status");
if (packet.fromAccount(account)) {
status = Message.STATUS_SEND;
@@ -334,6 +330,7 @@ public class MessageParser extends AbstractParser implements
if (isTypeGroupChat) {
if (counterpart.getResourcepart().equals(conversation.getMucOptions().getActualNick())) {
status = Message.STATUS_SEND_RECEIVED;
+ isCarbon = true; //not really carbon but received from another resource
if (mXmppConnectionService.markMessage(conversation, remoteMsgId, status)) {
return;
} else if (remoteMsgId == null || Config.IGNORE_ID_REWRITE_IN_MUC) {
@@ -355,10 +352,11 @@ public class MessageParser extends AbstractParser implements
return;
}
} else {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": ignoring OTR message from "+from+" isForwarded="+Boolean.toString(isForwarded)+", isProperlyAddressed="+Boolean.valueOf(isProperlyAddressed));
message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
}
} else if (pgpEncrypted != null) {
- message = parsePGPChat(conversation, pgpEncrypted, status);
+ message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
} else if (axolotlEncrypted != null) {
message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation, status);
if (message == null) {
@@ -390,6 +388,42 @@ public class MessageParser extends AbstractParser implements
} else {
updateLastseen(timestamp, account, packet.getFrom(), true);
}
+
+ if (replacementId != null && mXmppConnectionService.allowMessageCorrection()) {
+ Message replacedMessage = conversation.findMessageWithRemoteIdAndCounterpart(replacementId,
+ counterpart,
+ message.getStatus() == Message.STATUS_RECEIVED,
+ message.isCarbon());
+ if (replacedMessage != null) {
+ final boolean fingerprintsMatch = replacedMessage.getAxolotlFingerprint() == null
+ || replacedMessage.getAxolotlFingerprint().equals(message.getAxolotlFingerprint());
+ final boolean trueCountersMatch = replacedMessage.getTrueCounterpart() != null
+ && replacedMessage.getTrueCounterpart().equals(message.getTrueCounterpart());
+ if (fingerprintsMatch && (trueCountersMatch || conversation.getMode() == Conversation.MODE_SINGLE)) {
+ Log.d(Config.LOGTAG, "replaced message '" + replacedMessage.getBody() + "' with '" + message.getBody() + "'");
+ final String uuid = replacedMessage.getUuid();
+ replacedMessage.setUuid(UUID.randomUUID().toString());
+ replacedMessage.setBody(message.getBody());
+ replacedMessage.setEdited(replacedMessage.getRemoteMsgId());
+ replacedMessage.setRemoteMsgId(remoteMsgId);
+ replacedMessage.setEncryption(message.getEncryption());
+ if (replacedMessage.getStatus() == Message.STATUS_RECEIVED) {
+ replacedMessage.markUnread();
+ }
+ mXmppConnectionService.updateMessage(replacedMessage, uuid);
+ if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) {
+ sendMessageReceipts(account, packet);
+ }
+ if (replacedMessage.getEncryption() == Message.ENCRYPTION_PGP) {
+ conversation.getAccount().getPgpDecryptionService().add(replacedMessage);
+ }
+ return;
+ } else {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": received message correction but verification didn't check out");
+ }
+ }
+ }
+
boolean checkForDuplicates = query != null
|| (isTypeGroupChat && packet.hasChild("delay","urn:xmpp:delay"))
|| message.getType() == Message.TYPE_PRIVATE;
@@ -404,6 +438,10 @@ public class MessageParser extends AbstractParser implements
conversation.add(message);
}
+ if (message.getEncryption() == Message.ENCRYPTION_PGP) {
+ conversation.getAccount().getPgpDecryptionService().add(message);
+ }
+
if (query == null || query.getWith() == null) { //either no mam or catchup
if (status == Message.STATUS_SEND || status == Message.STATUS_SEND_RECEIVED) {
mXmppConnectionService.markRead(conversation);
@@ -420,20 +458,7 @@ public class MessageParser extends AbstractParser implements
}
if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) {
- ArrayList<String> receiptsNamespaces = new ArrayList<>();
- if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
- receiptsNamespaces.add("urn:xmpp:chat-markers:0");
- }
- if (packet.hasChild("request", "urn:xmpp:receipts")) {
- receiptsNamespaces.add("urn:xmpp:receipts");
- }
- if (receiptsNamespaces.size() > 0) {
- MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account,
- packet,
- receiptsNamespaces,
- packet.getType());
- mXmppConnectionService.sendMessagePacket(account, receipt);
- }
+ sendMessageReceipts(account, packet);
}
if (message.getStatus() == Message.STATUS_RECEIVED
@@ -524,4 +549,21 @@ public class MessageParser extends AbstractParser implements
contact.setPresenceName(nick);
}
}
+
+ private void sendMessageReceipts(Account account, MessagePacket packet) {
+ ArrayList<String> receiptsNamespaces = new ArrayList<>();
+ if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
+ receiptsNamespaces.add("urn:xmpp:chat-markers:0");
+ }
+ if (packet.hasChild("request", "urn:xmpp:receipts")) {
+ receiptsNamespaces.add("urn:xmpp:receipts");
+ }
+ if (receiptsNamespaces.size() > 0) {
+ MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account,
+ packet,
+ receiptsNamespaces,
+ packet.getType());
+ mXmppConnectionService.sendMessagePacket(account, receipt);
+ }
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
index 45c31e2b0..dc02eda8f 100644
--- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
@@ -186,7 +186,7 @@ public class PresenceParser extends AbstractParser implements
}
int sizeBefore = contact.getPresences().size();
- final Element show = packet.findChild("show");
+ final String show = packet.findChildContent("show");
final Element caps = packet.findChild("c", "http://jabber.org/protocol/caps");
final Presence presence = Presence.parse(show, caps);
contact.updatePresence(resource, presence);
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
index 2f28a30ff..dcba4f748 100644
--- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -51,7 +51,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
private static DatabaseBackend instance = null;
private static final String DATABASE_NAME = "history";
- private static final int DATABASE_VERSION = 23;
+ private static final int DATABASE_VERSION = 24;
private static String CREATE_CONTATCS_STATEMENT = "create table "
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
@@ -161,6 +161,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ Message.SERVER_MSG_ID + " TEXT, "
+ Message.FINGERPRINT + " TEXT, "
+ Message.CARBON + " INTEGER, "
+ + Message.EDITED + " TEXT, "
+ Message.READ + " NUMBER DEFAULT 1, "
+ Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY("
+ Message.CONVERSATION + ") REFERENCES "
@@ -370,6 +371,10 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (oldVersion < 23 && newVersion >= 23) {
db.execSQL(CREATE_DISCOVERY_RESULTS_STATEMENT);
}
+
+ if (oldVersion < 24 && newVersion >= 24) {
+ db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.EDITED + " TEXT");
+ }
}
public static synchronized DatabaseBackend getInstance(Context context) {
@@ -586,6 +591,13 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ "=?", args);
}
+ public void updateMessage(Message message, String uuid) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ String[] args = {uuid};
+ db.update(Message.TABLENAME, message.getContentValues(), Message.UUID
+ + "=?", args);
+ }
+
public void readRoster(Roster roster) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor;
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 16d7f139c..b836e780a 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -287,8 +287,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
List<Conversation> conversations = getConversations();
for (Conversation conversation : conversations) {
- if (conversation.getAccount() == account && conversation.getMode() == Conversation.MODE_SINGLE) {
- conversation.startOtrIfNeeded();
+ if (conversation.getAccount() == account
+ && !account.pendingConferenceJoins.contains(conversation)) {
+ if (!conversation.startOtrIfNeeded()) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": couldn't start OTR with "+conversation.getContact().getJid()+" when needed");
+ }
sendUnsentMessages(conversation);
}
}
@@ -474,7 +477,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
final String action = intent == null ? null : intent.getAction();
boolean interactive = false;
if (action != null) {
- Log.d(Config.LOGTAG,"start reason: "+action);
switch (action) {
case ConnectivityManager.CONNECTIVITY_ACTION:
if (hasInternetConnection() && Config.RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE) {
@@ -841,8 +843,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
final Conversation conversation = message.getConversation();
account.deactivateGracePeriod();
MessagePacket packet = null;
- final boolean addToConversation = conversation.getMode() != Conversation.MODE_MULTI
- || account.getServerIdentity() != XmppConnection.Identity.SLACK;
+ final boolean addToConversation = (conversation.getMode() != Conversation.MODE_MULTI
+ || account.getServerIdentity() != XmppConnection.Identity.SLACK)
+ && !message.edited();
boolean saveInDb = addToConversation;
message.setStatus(Message.STATUS_WAITING);
@@ -899,8 +902,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (message.fixCounterpart()) {
conversation.startOtrSession(message.getCounterpart().getResourcepart(), true);
} else {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not fix counterpart for OTR message to contact "+message.getContact().getJid());
break;
}
+ } else {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+" OTR session with "+message.getContact()+" is in wrong state: "+otrSession.getSessionStatus().toString());
}
break;
case Message.ENCRYPTION_AXOLOTL:
@@ -945,6 +951,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
break;
case Message.ENCRYPTION_OTR:
if (!conversation.hasValidOtrSession() && message.getCounterpart() != null) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": create otr session without starting for "+message.getContact().getJid());
conversation.startOtrSession(message.getCounterpart().getResourcepart(), false);
}
break;
@@ -966,8 +973,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (addToConversation) {
conversation.add(message);
}
- if (saveInDb && (message.getEncryption() == Message.ENCRYPTION_NONE || saveEncryptedMessages())) {
- databaseBackend.createMessage(message);
+ if (message.getEncryption() == Message.ENCRYPTION_NONE || saveEncryptedMessages()) {
+ if (saveInDb) {
+ databaseBackend.createMessage(message);
+ } else if (message.edited()) {
+ databaseBackend.updateMessage(message, message.getEditedId());
+ }
}
updateConversationUi();
}
@@ -1746,20 +1757,20 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
List<Conversation> conversations = getConversations();
for (Conversation conversation : conversations) {
if (conversation.getMode() == Conversation.MODE_MULTI && conversation.getAccount() == account) {
- joinMuc(conversation, true, null);
+ joinMuc(conversation);
}
}
}
public void joinMuc(Conversation conversation) {
- joinMuc(conversation, false, null);
+ joinMuc(conversation, null);
}
- private void joinMuc(Conversation conversation, boolean now, final OnConferenceJoined onConferenceJoined) {
+ private void joinMuc(Conversation conversation, final OnConferenceJoined onConferenceJoined) {
Account account = conversation.getAccount();
account.pendingConferenceJoins.remove(conversation);
account.pendingConferenceLeaves.remove(conversation);
- if (account.getStatus() == Account.State.ONLINE || now) {
+ if (account.getStatus() == Account.State.ONLINE) {
conversation.resetMucOptions();
fetchConferenceConfiguration(conversation, new OnConferenceConfigurationFetched() {
@@ -1938,7 +1949,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
String name = new BigInteger(75, getRNG()).toString(32);
Jid jid = Jid.fromParts(name, server, null);
final Conversation conversation = findOrCreateConversation(account, jid, true);
- joinMuc(conversation, true, new OnConferenceJoined() {
+ joinMuc(conversation, new OnConferenceJoined() {
@Override
public void onConferenceJoined(final Conversation conversation) {
Bundle options = new Bundle();
@@ -2148,6 +2159,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
updateConversationUi();
}
+ public void updateMessage(Message message, String uuid) {
+ databaseBackend.updateMessage(message, uuid);
+ updateConversationUi();
+ }
+
protected void syncDirtyContacts(Account account) {
for (Contact contact : account.getRoster().getContacts()) {
if (contact.getOption(Contact.Options.DIRTY_PUSH)) {
@@ -2604,6 +2620,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return getPreferences().getBoolean("confirm_messages", true);
}
+ public boolean allowMessageCorrection() {
+ return getPreferences().getBoolean("allow_message_correction", true);
+ }
+
public boolean sendChatStates() {
return getPreferences().getBoolean("chat_states", false);
}
@@ -2711,7 +2731,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return null;
}
- public void markRead(final Conversation conversation) {
+ public boolean markRead(final Conversation conversation) {
mNotificationService.clear(conversation);
final List<Message> readMessages = conversation.markRead();
if (readMessages.size() > 0) {
@@ -2724,8 +2744,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
};
mDatabaseExecutor.execute(runnable);
+ updateUnreadCountBadge();
+ return true;
+ } else {
+ return false;
}
- updateUnreadCountBadge();
}
public synchronized void updateUnreadCountBadge() {
@@ -2743,7 +2766,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void sendReadMarker(final Conversation conversation) {
final Message markable = conversation.getLatestMarkableMessage();
- this.markRead(conversation);
+ if (this.markRead(conversation)) {
+ updateConversationUi();
+ }
if (confirmMessages() && markable != null && markable.getRemoteMsgId() != null) {
Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid() + ": sending read marker to " + markable.getCounterpart().toString());
Account account = conversation.getAccount();
@@ -2751,7 +2776,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
MessagePacket packet = mMessageGenerator.confirm(account, to, markable.getRemoteMsgId());
this.sendMessagePacket(conversation.getAccount(), packet);
}
- updateConversationUi();
}
public SecureRandom getRNG() {
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index e95efc3de..2d5c7f8b3 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -446,11 +446,7 @@ public class ConversationActivity extends XmppActivity
public void sendReadMarkerIfNecessary(final Conversation conversation) {
if (!mActivityPaused && conversation != null) {
- if (!conversation.isRead()) {
- xmppConnectionService.sendReadMarker(conversation);
- } else {
- xmppConnectionService.markRead(conversation);
- }
+ xmppConnectionService.sendReadMarker(conversation);
}
}
@@ -1713,6 +1709,7 @@ public class ConversationActivity extends XmppActivity
public void setMessagesLoaded() {
if (mConversationFragment != null) {
mConversationFragment.setMessagesLoaded();
+ mConversationFragment.updateMessages();
}
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index b4a0e743d..a16f8c8df 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -8,7 +8,6 @@ import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.os.Bundle;
import android.support.annotation.Nullable;
@@ -40,6 +39,7 @@ import net.java.otr4j.session.SessionStatus;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.UUID;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -51,7 +51,6 @@ import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.Presence;
-import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.services.XmppConnectionService;
@@ -62,6 +61,7 @@ import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jid.Jid;
@@ -293,8 +293,14 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
activity.attachFile(ConversationActivity.ATTACHMENT_CHOICE_CHOOSE_IMAGE);
break;
case CANCEL:
- if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) {
- conversation.setNextCounterpart(null);
+ if (conversation != null) {
+ if (conversation.getCorrectingMessage() != null) {
+ conversation.setCorrectingMessage(null);
+ mEditMessage.getEditableText().clear();
+ }
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ conversation.setNextCounterpart(null);
+ }
updateChatMsgHint();
updateSendButton();
}
@@ -329,12 +335,21 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (body.length() == 0 || this.conversation == null) {
return;
}
- Message message = new Message(conversation, body, conversation.getNextEncryption());
- if (conversation.getMode() == Conversation.MODE_MULTI) {
- if (conversation.getNextCounterpart() != null) {
- message.setCounterpart(conversation.getNextCounterpart());
- message.setType(Message.TYPE_PRIVATE);
+ final Message message;
+ if (conversation.getCorrectingMessage() == null) {
+ message = new Message(conversation, body, conversation.getNextEncryption());
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ if (conversation.getNextCounterpart() != null) {
+ message.setCounterpart(conversation.getNextCounterpart());
+ message.setType(Message.TYPE_PRIVATE);
+ }
}
+ } else {
+ message = conversation.getCorrectingMessage();
+ message.setBody(body);
+ message.setEdited(message.getUuid());
+ message.setUuid(UUID.randomUUID().toString());
+ conversation.setCorrectingMessage(null);
}
switch (conversation.getNextEncryption()) {
case Message.ENCRYPTION_OTR:
@@ -355,7 +370,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
public void updateChatMsgHint() {
final boolean multi = conversation.getMode() == Conversation.MODE_MULTI;
- if (multi && conversation.getNextCounterpart() != null) {
+ if (conversation.getCorrectingMessage() != null) {
+ this.mEditMessage.setHint(R.string.send_corrected_message);
+ } else if (multi && conversation.getNextCounterpart() != null) {
this.mEditMessage.setHint(getString(
R.string.send_private_message_to,
conversation.getNextCounterpart().getResourcepart()));
@@ -486,8 +503,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
@Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
synchronized (this.messageList) {
super.onCreateContextMenu(menu, v, menuInfo);
AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
@@ -498,10 +514,15 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
private void populateContextMenu(ContextMenu menu) {
final Message m = this.selectedMessage;
+ Message relevantForCorrection = m;
+ while(relevantForCorrection.mergeable(relevantForCorrection.next())) {
+ relevantForCorrection = relevantForCorrection.next();
+ }
if (m.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 correctMessage = menu.findItem(R.id.correct_message);
MenuItem shareWith = menu.findItem(R.id.share_with);
MenuItem sendAgain = menu.findItem(R.id.send_again);
MenuItem copyUrl = menu.findItem(R.id.copy_url);
@@ -513,6 +534,10 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
&& m.treatAsDownloadable() != Message.Decision.MUST) {
copyText.setVisible(true);
}
+ if (relevantForCorrection.getType() == Message.TYPE_TEXT
+ && relevantForCorrection.isLastCorrectableMessage()) {
+ correctMessage.setVisible(true);
+ }
if ((m.getType() != Message.TYPE_TEXT
&& m.getType() != Message.TYPE_PRIVATE
&& m.getTransferable() == null)
@@ -549,6 +574,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
case R.id.copy_text:
copyText(selectedMessage);
return true;
+ case R.id.correct_message:
+ correctMessage(selectedMessage);
+ return true;
case R.id.send_again:
resendMessage(selectedMessage);
return true;
@@ -651,6 +679,16 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
updateSendButton();
}
+ private void correctMessage(Message message) {
+ while(message.mergeable(message.next())) {
+ message = message.next();
+ }
+ this.conversation.setCorrectingMessage(message);
+ this.mEditMessage.getEditableText().clear();
+ this.mEditMessage.getEditableText().append(message.getBody());
+
+ }
+
protected void highlightInConference(String nick) {
String oldString = mEditMessage.getText().toString().trim();
if (oldString.isEmpty() || mEditMessage.getSelectionStart() == 0) {
@@ -700,9 +738,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
this.keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
this.conversation = conversation;
- if (this.conversation.getMode() == Conversation.MODE_MULTI) {
- this.conversation.setNextCounterpart(null);
- }
boolean canWrite = this.conversation.getMode() == Conversation.MODE_SINGLE || this.conversation.getMucOptions().participating();
this.mEditMessage.setEnabled(canWrite);
this.mSendButton.setEnabled(canWrite);
@@ -958,9 +993,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
final Conversation c = this.conversation;
final SendButtonAction action;
final Presence.Status status;
- final boolean empty = this.mEditMessage == null || this.mEditMessage.getText().length() == 0;
+ final String text = this.mEditMessage == null ? "" : this.mEditMessage.getText().toString();
+ final boolean empty = text.length() == 0;
final boolean conference = c.getMode() == Conversation.MODE_MULTI;
- if (conference && !c.getAccount().httpUploadAvailable()) {
+ if (c.getCorrectingMessage() != null && (empty || text.equals(c.getCorrectingMessage().getBody()))) {
+ action = SendButtonAction.CANCEL;
+ } else if (conference && !c.getAccount().httpUploadAvailable()) {
if (empty && c.getNextCounterpart() != null) {
action = SendButtonAction.CANCEL;
} else {
@@ -1015,7 +1053,10 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
protected void updateStatusMessages() {
synchronized (this.messageList) {
- if (conversation.getLastClearHistory() != 0) {
+ final XmppConnection connection = conversation.getAccount().getXmppConnection();
+ if (conversation.getLastClearHistory() != 0
+ && connection != null
+ && connection.getFeatures().mam()) {
this.messageList.add(0, Message.createLoadMoreMessage(conversation));
}
if (conversation.getMode() == Conversation.MODE_SINGLE) {
@@ -1235,6 +1276,13 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
updateSendButton();
}
+ @Override
+ public void onTextChanged() {
+ if (conversation != null && conversation.getCorrectingMessage() != null) {
+ updateSendButton();
+ }
+ }
+
private int completionIndex = 0;
private int lastCompletionLength = 0;
private String incomplete;
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index d3899c29f..7b6167178 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -50,6 +50,7 @@ import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
+import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.XmppConnection.Features;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
@@ -304,15 +305,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
@Override
public void run() {
final Intent intent;
- if (avatar != null) {
- intent = new Intent(getApplicationContext(),
- StartConversationActivity.class);
+ final XmppConnection connection = mAccount.getXmppConnection();
+ if (avatar != null || (connection != null && !connection.getFeatures().pep())) {
+ intent = new Intent(getApplicationContext(), StartConversationActivity.class);
if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) {
intent.putExtra("init", true);
}
} else {
- intent = new Intent(getApplicationContext(),
- PublishProfilePictureActivity.class);
+ intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toBareJid().toString());
intent.putExtra("setup", true);
}
@@ -686,9 +686,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
this.mServerInfoHttpUpload.setText(R.string.server_info_unavailable);
}
- this.mPushRow.setVisibility(xmppConnectionService.getPushManagementService().available(mAccount) ? View.VISIBLE : View.GONE);
+ this.mPushRow.setVisibility(xmppConnectionService.getPushManagementService().isStub() ? View.GONE : View.VISIBLE);
- if (features.push()) {
+ if (xmppConnectionService.getPushManagementService().available(mAccount)) {
this.mServerInfoPush.setText(R.string.server_info_available);
} else {
this.mServerInfoPush.setText(R.string.server_info_unavailable);
@@ -918,7 +918,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
mFetchingMamPrefsToast.cancel();
}
AlertDialog.Builder builder = new Builder(EditAccountActivity.this);
- builder.setTitle(R.string.mam_prefs);
+ builder.setTitle(R.string.server_side_mam_prefs);
String defaultAttr = prefs.getAttribute("default");
final List<String> defaults = Arrays.asList("never", "roster", "always");
final AtomicInteger choice = new AtomicInteger(Math.max(0,defaults.indexOf(defaultAttr)));
diff --git a/src/main/java/eu/siacs/conversations/ui/EditMessage.java b/src/main/java/eu/siacs/conversations/ui/EditMessage.java
index fc655b0ce..e3841d1d5 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditMessage.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditMessage.java
@@ -69,6 +69,7 @@ public class EditMessage extends EditText {
this.isUserTyping = false;
this.keyboardListener.onTextDeleted();
}
+ this.keyboardListener.onTextChanged();
}
}
@@ -84,6 +85,7 @@ public class EditMessage extends EditText {
void onTypingStarted();
void onTypingStopped();
void onTextDeleted();
+ void onTextChanged();
boolean onTabPressed(boolean repeated);
}
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
index aa23e36db..07c328b9a 100644
--- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
@@ -162,7 +162,8 @@ public class SettingsActivity extends XmppActivity implements
xmppConnectionService.toggleForegroundService();
} else if (name.equals("confirm_messages")
|| name.equals("xa_on_silent_mode")
- || name.equals("away_when_screen_off")) {
+ || name.equals("away_when_screen_off")
+ || name.equals("allow_message_correction")) {
if (xmppConnectionServiceBound) {
if (name.equals("away_when_screen_off")) {
xmppConnectionService.toggleScreenEventReceiver();
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index 7755ef08c..45e54ded5 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -124,6 +124,16 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.indicatorReceived.setVisibility(View.GONE);
viewHolder.indicatorRead.setVisibility(View.GONE);
}
+
+ if (viewHolder.edit_indicator != null) {
+ if (message.edited()) {
+ viewHolder.edit_indicator.setVisibility(View.VISIBLE);
+ viewHolder.edit_indicator.setImageResource(darkBackground ? R.drawable.ic_mode_edit_white_18dp : R.drawable.ic_mode_edit_black_18dp);
+ viewHolder.edit_indicator.setAlpha(darkBackground ? 0.7f : 0.57f);
+ } else {
+ viewHolder.edit_indicator.setVisibility(View.GONE);
+ }
+ }
boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
&& message.getMergedStatus() <= Message.STATUS_RECEIVED;
if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE || message.getTransferable() != null) {
@@ -181,7 +191,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
if (message.getEncryption() == Message.ENCRYPTION_NONE) {
viewHolder.indicator.setVisibility(View.GONE);
} else {
- viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_secure_indicator_white : R.drawable.ic_secure_indicator);
+ viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_lock_white_18dp : R.drawable.ic_lock_black_18dp);
viewHolder.indicator.setVisibility(View.VISIBLE);
if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
XmppAxolotlSession.Trust trust = message.getConversation()
@@ -465,6 +475,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
.findViewById(R.id.download_button);
viewHolder.indicator = (ImageView) view
.findViewById(R.id.security_indicator);
+ viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator);
viewHolder.image = (ImageView) view
.findViewById(R.id.message_image);
viewHolder.messageBody = (TextView) view
@@ -487,6 +498,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
.findViewById(R.id.download_button);
viewHolder.indicator = (ImageView) view
.findViewById(R.id.security_indicator);
+ viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator);
viewHolder.image = (ImageView) view
.findViewById(R.id.message_image);
viewHolder.messageBody = (TextView) view
@@ -706,6 +718,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
protected TextView status_message;
protected TextView encryption;
public Button load_more_messages;
+ public ImageView edit_indicator;
}
class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index 3ddad1fdb..dc6021284 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -1077,10 +1077,10 @@ public class XmppConnection implements Runnable {
if (mPendingServiceDiscoveries == 0) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": done with service discovery");
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource());
- changeStatus(Account.State.ONLINE);
if (bindListener != null) {
bindListener.onBind(account);
}
+ changeStatus(Account.State.ONLINE);
}
}
}
diff --git a/src/main/res/drawable-hdpi/ic_lock_black_18dp.png b/src/main/res/drawable-hdpi/ic_lock_black_18dp.png
new file mode 100644
index 000000000..4c7a7c59f
--- /dev/null
+++ b/src/main/res/drawable-hdpi/ic_lock_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-hdpi/ic_lock_white_18dp.png b/src/main/res/drawable-hdpi/ic_lock_white_18dp.png
new file mode 100644
index 000000000..29e8bfd32
--- /dev/null
+++ b/src/main/res/drawable-hdpi/ic_lock_white_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-hdpi/ic_mode_edit_black_18dp.png b/src/main/res/drawable-hdpi/ic_mode_edit_black_18dp.png
new file mode 100644
index 000000000..00e7d0743
--- /dev/null
+++ b/src/main/res/drawable-hdpi/ic_mode_edit_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-hdpi/ic_mode_edit_white_18dp.png b/src/main/res/drawable-hdpi/ic_mode_edit_white_18dp.png
new file mode 100644
index 000000000..558f0ea32
--- /dev/null
+++ b/src/main/res/drawable-hdpi/ic_mode_edit_white_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-hdpi/ic_secure_indicator.png b/src/main/res/drawable-hdpi/ic_secure_indicator.png
index 220463fc7..4439d1aec 100644
--- a/src/main/res/drawable-hdpi/ic_secure_indicator.png
+++ b/src/main/res/drawable-hdpi/ic_secure_indicator.png
Binary files differ
diff --git a/src/main/res/drawable-hdpi/ic_secure_indicator_white.png b/src/main/res/drawable-hdpi/ic_secure_indicator_white.png
deleted file mode 100644
index 46eb1195b..000000000
--- a/src/main/res/drawable-hdpi/ic_secure_indicator_white.png
+++ /dev/null
Binary files differ
diff --git a/src/main/res/drawable-mdpi/ic_lock_black_18dp.png b/src/main/res/drawable-mdpi/ic_lock_black_18dp.png
new file mode 100644
index 000000000..c8b6fe712
--- /dev/null
+++ b/src/main/res/drawable-mdpi/ic_lock_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-mdpi/ic_lock_white_18dp.png b/src/main/res/drawable-mdpi/ic_lock_white_18dp.png
new file mode 100644
index 000000000..1265e98e1
--- /dev/null
+++ b/src/main/res/drawable-mdpi/ic_lock_white_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-mdpi/ic_mode_edit_black_18dp.png b/src/main/res/drawable-mdpi/ic_mode_edit_black_18dp.png
new file mode 100644
index 000000000..ebd96073b
--- /dev/null
+++ b/src/main/res/drawable-mdpi/ic_mode_edit_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-mdpi/ic_mode_edit_white_18dp.png b/src/main/res/drawable-mdpi/ic_mode_edit_white_18dp.png
new file mode 100644
index 000000000..e23c42db9
--- /dev/null
+++ b/src/main/res/drawable-mdpi/ic_mode_edit_white_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-mdpi/ic_secure_indicator.png b/src/main/res/drawable-mdpi/ic_secure_indicator.png
deleted file mode 100644
index 690d4d03d..000000000
--- a/src/main/res/drawable-mdpi/ic_secure_indicator.png
+++ /dev/null
Binary files differ
diff --git a/src/main/res/drawable-mdpi/ic_secure_indicator_white.png b/src/main/res/drawable-mdpi/ic_secure_indicator_white.png
deleted file mode 100644
index e2f894ef4..000000000
--- a/src/main/res/drawable-mdpi/ic_secure_indicator_white.png
+++ /dev/null
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/ic_lock_black_18dp.png b/src/main/res/drawable-xhdpi/ic_lock_black_18dp.png
new file mode 100644
index 000000000..0888c6173
--- /dev/null
+++ b/src/main/res/drawable-xhdpi/ic_lock_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/ic_lock_white_18dp.png b/src/main/res/drawable-xhdpi/ic_lock_white_18dp.png
new file mode 100644
index 000000000..b94735ecb
--- /dev/null
+++ b/src/main/res/drawable-xhdpi/ic_lock_white_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/ic_mode_edit_black_18dp.png b/src/main/res/drawable-xhdpi/ic_mode_edit_black_18dp.png
new file mode 100644
index 000000000..b33c964d2
--- /dev/null
+++ b/src/main/res/drawable-xhdpi/ic_mode_edit_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/ic_mode_edit_white_18dp.png b/src/main/res/drawable-xhdpi/ic_mode_edit_white_18dp.png
new file mode 100644
index 000000000..3ee3e1720
--- /dev/null
+++ b/src/main/res/drawable-xhdpi/ic_mode_edit_white_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/ic_secure_indicator.png b/src/main/res/drawable-xhdpi/ic_secure_indicator.png
deleted file mode 100644
index cd0d1391a..000000000
--- a/src/main/res/drawable-xhdpi/ic_secure_indicator.png
+++ /dev/null
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/ic_secure_indicator_white.png b/src/main/res/drawable-xhdpi/ic_secure_indicator_white.png
deleted file mode 100644
index b624a8ce6..000000000
--- a/src/main/res/drawable-xhdpi/ic_secure_indicator_white.png
+++ /dev/null
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/ic_lock_black_18dp.png b/src/main/res/drawable-xxhdpi/ic_lock_black_18dp.png
new file mode 100644
index 000000000..dbcf3f33d
--- /dev/null
+++ b/src/main/res/drawable-xxhdpi/ic_lock_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/ic_lock_white_18dp.png b/src/main/res/drawable-xxhdpi/ic_lock_white_18dp.png
new file mode 100644
index 000000000..895aabbfa
--- /dev/null
+++ b/src/main/res/drawable-xxhdpi/ic_lock_white_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/ic_mode_edit_black_18dp.png b/src/main/res/drawable-xxhdpi/ic_mode_edit_black_18dp.png
new file mode 100644
index 000000000..66d25296d
--- /dev/null
+++ b/src/main/res/drawable-xxhdpi/ic_mode_edit_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/ic_mode_edit_white_18dp.png b/src/main/res/drawable-xxhdpi/ic_mode_edit_white_18dp.png
new file mode 100644
index 000000000..9d7f2ff90
--- /dev/null
+++ b/src/main/res/drawable-xxhdpi/ic_mode_edit_white_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/ic_secure_indicator.png b/src/main/res/drawable-xxhdpi/ic_secure_indicator.png
deleted file mode 100644
index 6a74ccbef..000000000
--- a/src/main/res/drawable-xxhdpi/ic_secure_indicator.png
+++ /dev/null
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/ic_secure_indicator_white.png b/src/main/res/drawable-xxhdpi/ic_secure_indicator_white.png
deleted file mode 100644
index 4945c9595..000000000
--- a/src/main/res/drawable-xxhdpi/ic_secure_indicator_white.png
+++ /dev/null
Binary files differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_lock_black_18dp.png b/src/main/res/drawable-xxxhdpi/ic_lock_black_18dp.png
new file mode 100644
index 000000000..c49d420e0
--- /dev/null
+++ b/src/main/res/drawable-xxxhdpi/ic_lock_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_lock_white_18dp.png b/src/main/res/drawable-xxxhdpi/ic_lock_white_18dp.png
new file mode 100644
index 000000000..0dcada814
--- /dev/null
+++ b/src/main/res/drawable-xxxhdpi/ic_lock_white_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_mode_edit_black_18dp.png b/src/main/res/drawable-xxxhdpi/ic_mode_edit_black_18dp.png
new file mode 100644
index 000000000..827b68480
--- /dev/null
+++ b/src/main/res/drawable-xxxhdpi/ic_mode_edit_black_18dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_18dp.png b/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_18dp.png
new file mode 100644
index 000000000..34ec7092f
--- /dev/null
+++ b/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_18dp.png
Binary files differ
diff --git a/src/main/res/layout/message_received.xml b/src/main/res/layout/message_received.xml
index 7d4a0993b..f8a8853ab 100644
--- a/src/main/res/layout/message_received.xml
+++ b/src/main/res/layout/message_received.xml
@@ -93,7 +93,17 @@
android:layout_marginRight="4sp"
android:alpha="0.70"
android:gravity="center_vertical"
- android:src="@drawable/ic_secure_indicator_white" />
+ android:src="@drawable/ic_lock_white_18dp" />
+
+ <ImageView
+ android:id="@+id/edit_indicator"
+ android:layout_width="?attr/TextSizeInfo"
+ android:layout_height="?attr/TextSizeInfo"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="4sp"
+ android:alpha="0.70"
+ android:gravity="center_vertical"
+ android:src="@drawable/ic_mode_edit_white_18dp" />
<TextView
android:id="@+id/message_time"
diff --git a/src/main/res/layout/message_sent.xml b/src/main/res/layout/message_sent.xml
index c3aa62528..5ffb33114 100644
--- a/src/main/res/layout/message_sent.xml
+++ b/src/main/res/layout/message_sent.xml
@@ -93,7 +93,17 @@
android:layout_marginLeft="4sp"
android:alpha="0.54"
android:gravity="center_vertical"
- android:src="@drawable/ic_secure_indicator" />
+ android:src="@drawable/ic_lock_black_18dp" />
+
+ <ImageView
+ android:id="@+id/edit_indicator"
+ android:layout_width="?attr/TextSizeInfo"
+ android:layout_height="?attr/TextSizeInfo"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="4sp"
+ android:alpha="0.54"
+ android:gravity="center_vertical"
+ android:src="@drawable/ic_mode_edit_black_18dp" />
<ImageView
android:id="@+id/indicator_received"
diff --git a/src/main/res/menu/message_context.xml b/src/main/res/menu/message_context.xml
index 4e1316d39..0d4e66efc 100644
--- a/src/main/res/menu/message_context.xml
+++ b/src/main/res/menu/message_context.xml
@@ -6,6 +6,10 @@
android:title="@string/copy_text"
android:visible="false"/>
<item
+ android:id="@+id/correct_message"
+ android:title="@string/correct_message"
+ android:visible="false"/>
+ <item
android:id="@+id/share_with"
android:title="@string/share_with"
android:visible="false"/>
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index 44c64261f..697ddcdb0 100644
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -101,7 +101,7 @@
<string name="pref_xmpp_resource_summary">Der Name, mit dem sich der Client selbst identifiziert</string>
<string name="pref_accept_files">Dateien annehmen</string>
<string name="pref_accept_files_summary">Dateien automatisch annehmen, die kleiner sind als …</string>
- <string name="pref_notification_settings">Benachrichtigungen</string>
+ <string name="pref_notification_settings">Benachrichtigung</string>
<string name="pref_notifications">Benachrichtigungen</string>
<string name="pref_notifications_summary">Benachrichtigen bei Erhalt einer neuen Nachricht</string>
<string name="pref_vibrate">Vibrieren</string>
@@ -110,7 +110,7 @@
<string name="pref_sound_summary">Benachrichtigungston wiedergeben</string>
<string name="pref_notification_grace_period">Gnadenfrist</string>
<string name="pref_notification_grace_period_summary">Deaktiviere Benachrichtigungen für eine kurze Zeit nach Erhalt einer Nachricht, die von einem anderen deiner Clients kommt.</string>
- <string name="pref_advanced_options">Erweiterte Optionen</string>
+ <string name="pref_advanced_options">Erweitert</string>
<string name="pref_never_send_crash">Niemals Absturzberichte senden</string>
<string name="pref_never_send_crash_summary">Wenn du Absturzberichte einschickst, hilfst du Pix-Art Messenger stetig zu verbessern</string>
<string name="pref_confirm_messages">Lese- und Empfangsbestätigung senden</string>
@@ -190,6 +190,7 @@
<string name="server_info_stream_management">XEP-0198: Stream Management</string>
<string name="server_info_pep">XEP-0163: PEP (Avatare/OMEMO)</string>
<string name="server_info_http_upload">XEP-0363: HTTP File Upload</string>
+ <string name="server_info_push">XEP-0357: Push</string>
<string name="server_info_available">ja</string>
<string name="server_info_unavailable">nein</string>
<string name="missing_public_keys">Öffentlicher Schlüssel fehlt</string>
@@ -237,6 +238,7 @@
<string name="you">Du</string>
<string name="action_edit_subject">Konferenz-Thema bearbeiten</string>
<string name="conference_not_found">Konferenz nicht gefunden</string>
+ <string name="conference_unknown_error">Unbekannter Fehler</string>
<string name="leave">Verlassen</string>
<string name="contact_added_you">Der Kontakt hat dich zur Kontaktliste hinzugefügt</string>
<string name="add_back">Auch hinzufügen</string>
@@ -271,12 +273,14 @@
<string name="sure_delete_fingerprint">Soll dieser Fingerabdruck wirklich gelöscht werden?</string>
<string name="ignore">Ignorieren</string>
<string name="without_mutual_presence_updates"><b>Achtung:</b> Ohne gegenseitige Kenntnis des Online-Status kann es zu unerwarteten Problemen kommen.\n\n<small>Bitte die Einstellungen in den Kontakt-Details prüfen.</small></string>
- <string name="pref_encryption_settings">Verschlüsselungs-Einstellungen</string>
+ <string name="pref_security_settings">Sicherheit</string>
<string name="pref_force_encryption">Ende-zu-Ende-Verschlüsselung erzwingen</string>
<string name="pref_force_encryption_summary">Nachrichten immer verschlüsseln (außer für Konferenzen)</string>
+ <string name="pref_allow_message_correction">Nachrichtenkorrektur erlauben</string>
+ <string name="pref_allow_message_correction_summary">Erlaube Deinen Kontakten das nachträgliche Korrigieren ihrer Nachrichten</string>
<string name="pref_dont_save_encrypted">Verschlüsselte Nachrichten nicht speichern</string>
<string name="pref_dont_save_encrypted_summary">Achtung: kann zu Nachrichtenverlust führen</string>
- <string name="pref_expert_options">Einstellungen für Experten</string>
+ <string name="pref_expert_options">Experteneinstellungen</string>
<string name="pref_expert_options_summary">Hier bitte vorsichtig sein</string>
<string name="title_activity_about">Über Pix-Art Messenger</string>
<string name="pref_about_conversations_summary">Versions- und Lizenzinformationen</string>
@@ -294,6 +298,8 @@
<string name="pref_expert_options_other">Sonstiges</string>
<string name="pref_conference_name">Konferenz-Name</string>
<string name="pref_conference_name_summary">Konferenz-Thema statt Raum-JID als Namen verwenden</string>
+ <string name="pref_autojoin">Unterhaltung automatisch beitreten</string>
+ <string name="pref_autojoin_summary">Autojoin-Flag in Konferenzlesezeichen beachten</string>
<string name="toast_message_otr_fingerprint">OTR-Fingerabdruck in die Zwischenablage kopiert!</string>
<string name="toast_message_omemo_fingerprint">OMEMO-Fingerabdruck in die Zwischenablage kopiert!</string>
<string name="conference_banned">Du wurdest von der Konferenz ausgeschlossen</string>
@@ -424,7 +430,7 @@
<string name="two_hours">2 Stunden</string>
<string name="eight_hours">8 Stunden</string>
<string name="until_further_notice">Bis auf Weiteres</string>
- <string name="pref_input_options">Eingabe-Optionen</string>
+ <string name="pref_input_options">Eingabe</string>
<string name="pref_enter_is_send">Eingabe-Taste (Enter) sendet Nachricht</string>
<string name="pref_enter_is_send_summary">Eingabe-Taste (Enter) zum Versenden einer Nachricht verwenden</string>
<string name="pref_display_enter_key">Zeige Eingabe-Taste (Enter)</string>
@@ -501,14 +507,21 @@
<string name="account_status_tor_unavailable">Tor-Netzwerk nicht verfügbar</string>
<string name="server_info_broken">Fehlerhaft</string>
<string name="update_info">Conversation prüft auf eine neuere Version. Wenn ein Update verfügbar ist, wirst du gefragt, ob du deine Version aktualisieren möchtest. Der Update Dienst lädt und installiert die neue Version automatisch.</string>
- <string name="pref_presence_settings">Status Einstellungen</string>
+ <string name="pref_presence_settings">Status</string>
<string name="pref_away_when_screen_off">Abwesend bei abgeschaltetem Bildschirm</string>
<string name="pref_away_when_screen_off_summary">Setzt deinen Status auf \"abwesend\", solange dein Bildschirm abgeschaltet ist</string>
<string name="pref_xa_on_silent_mode">Nicht verfügbar bei Stummschaltung</string>
<string name="pref_xa_on_silent_mode_summary">Setzt deinen Status auf \"nicht verfügbar\", solange dein Telefon lautlos ist</string>
+ <string name="pref_show_connection_options">Erweiterte Verbindungs-Optionen</string>
+ <string name="pref_show_connection_options_summary">Hostname- und Port-Optionen bei Kontoeinrichtung anzeigen</string>
+ <string name="hostname_example">xmpp.domain.de</string>
<string name="action_add_account_with_certificate">Konto mit Zertifikat hinzufügen</string>
<string name="unable_to_parse_certificate">Zertifikat kann nicht gelesen werden</string>
<string name="authenticate_with_certificate">Leer lassen, um mit Zertifikat anzumelden</string>
+ <string name="mam_prefs">Archivierungseinstellungen</string>
+ <string name="server_side_mam_prefs">Archivierungseinstellungen des Servers</string>
+ <string name="fetching_mam_prefs">Archivierungseinstellungen werden abgerufen. Bitte warten …</string>
+ <string name="unable_to_fetch_mam_prefs">Archivierungseinstellungen konnten nicht abgerufen werden</string>
<string name="captcha_ocr">Captcha Text</string>
<string name="captcha_required">Captcha erforderlich</string>
<string name="captcha_hint">Text aus Captcha eintragen</string>
@@ -531,7 +544,8 @@
<string name="omemo_fingerprint_x509_selected_message">v\\OMEMO-Fingerabdruck der Nachricht</string>
<string name="send_omemo_x509_message">v\\OMEMO-verschlüsselte Nachricht senden</string>
<string name="verified_omemo_key_with_certificate">OMEMO Schlüssel mit Zertifikat bestätigt!</string>
- <string name="pref_connection_options">Verbindungs-Optionen</string>
+ <string name="device_does_not_support_certificates">Dein Gerät unterstützt das Auswählen von Client-Zertifikaten nicht!</string>
+ <string name="pref_connection_options">Verbindung</string>
<string name="pref_use_tor">Über TOR verbinden</string>
<string name="pref_use_tor_summary">Alle Verbindungen über das Tor-Netzwerk tunneln. Benötigt Orbot</string>
<string name="account_settings_hostname">Hostname</string>
@@ -544,6 +558,7 @@
<item quantity="one">%d Nachricht</item>
<item quantity="other">%d Nachrichten</item>
</plurals>
+ <string name="load_more_messages">Weitere Nachrichten laden</string>
<string name="shared_file_with_x">Datei mit %s geteilt</string>
<string name="shared_image_with_x">Bild mit %s geteilt</string>
<string name="no_storage_permission">Pix-Art Messenger benötigt Zugriff auf externen Speicher</string>
@@ -552,9 +567,9 @@
<string name="certificate_information">Zertifikatinformationen</string>
<string name="certificate_subject">Betreff</string>
<string name="certificate_issuer">Aussteller</string>
- <string name="certificate_cn">Gemeinsamer Name</string>
+ <string name="certificate_cn">Name</string>
<string name="certificate_o">Organisation</string>
- <string name="certificate_sha1">SHA1</string>
+ <string name="certificate_sha1">SHA-1</string>
<string name="certicate_info_not_available">(Nicht verfügbar)</string>
<string name="certificate_not_found">Kein Zertifikat gefunden</string>
<string name="notify_on_all_messages">Bei allen Nachrichten benachrichtigen</string>
@@ -575,11 +590,13 @@
<string name="selection_too_large">Der ausgewählte Bereich ist zu groß</string>
<string name="conference_unknown_error">Unbekannter Fehler</string>
<string name="load_more_messages">weitere Nachrichten laden</string>
- <string name="no_accounts">(keine aktiven Konten)</string>
<string name="no_participants">Keine Mitglieder</string>
<string name="pref_autojoin">Konferenzen automatisch beitreten</string>
<string name="pref_autojoin_summary">Konferenzen automatisch beitreten, wenn in der Kontaktliste aktiviert.</string>
<string name="pref_show_connection_options">Erweiterte Verbindungs-Optionen</string>
<string name="pref_show_connection_options_summary">Zeige Hostname- und Port-Optionen</string>
+ <string name="no_accounts">(Keine aktivierten Konten)</string>
<string name="this_field_is_required">Dieses Feld ist erforderlich</string>
+ <string name="correct_message">Nachricht korrigieren</string>
+ <string name="send_corrected_message">Korrigierte Nachricht senden</string>
</resources>
diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/main/res/values-pt-rBR/strings.xml
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 404e7a02a..982c3ab84 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
-
<string name="app_name" translatable="false">Pix-Art Messenger</string>
<string name="action_settings">Settings</string>
<string name="action_add">New conversation</string>
@@ -104,7 +103,7 @@
<string name="pref_xmpp_resource_summary">The name this client identifies itself with</string>
<string name="pref_accept_files">Accept files</string>
<string name="pref_accept_files_summary">Automatically accept files smaller than…</string>
- <string name="pref_notification_settings">Notification Settings</string>
+ <string name="pref_notification_settings">Notification</string>
<string name="pref_notifications">Notifications</string>
<string name="pref_notifications_summary">Notify when a new message arrives</string>
<string name="pref_vibrate">Vibrate</string>
@@ -113,12 +112,12 @@
<string name="pref_sound_summary">Play ringtone with notification</string>
<string name="pref_notification_grace_period">Notification grace period</string>
<string name="pref_notification_grace_period_summary">Disable notifications for a short time after a carbon copy was received</string>
- <string name="pref_advanced_options">Advanced Options</string>
+ <string name="pref_advanced_options">Advanced</string>
<string name="pref_never_send_crash">Never send crash reports</string>
<string name="pref_never_send_crash_summary">By sending in stack traces you are helping the ongoing development of Pix-Art Messenger</string>
<string name="pref_confirm_messages">Confirm Messages</string>
<string name="pref_confirm_messages_summary">Let your contact know when you have received and read a message</string>
- <string name="pref_ui_options">UI Options</string>
+ <string name="pref_ui_options">UI</string>
<string name="openpgp_error">OpenKeychain reported an error</string>
<string name="error_decrypting_file">I/O Error decrypting file</string>
<string name="accept">Accept</string>
@@ -278,12 +277,14 @@
<string name="sure_delete_fingerprint">Are you sure you would like to delete this fingerprint?</string>
<string name="ignore">Ignore</string>
<string name="without_mutual_presence_updates"><b>Warning:</b> Sending this without mutual presence updates could cause unexpected problems.\n\n<small>Go to contact details to verify your presence subscriptions.</small></string>
- <string name="pref_encryption_settings">Encryption settings</string>
+ <string name="pref_security_settings">Security</string>
<string name="pref_force_encryption">Force end-to-end encryption</string>
<string name="pref_force_encryption_summary">Always send messages encrypted (except for conferences)</string>
+ <string name="pref_allow_message_correction">Allow message correction</string>
+ <string name="pref_allow_message_correction_summary">Allow your contacts to retroactively edit their messages</string>
<string name="pref_dont_save_encrypted">Don’t save encrypted messages</string>
<string name="pref_dont_save_encrypted_summary">Warning: This could lead to message loss</string>
- <string name="pref_expert_options">Expert options</string>
+ <string name="pref_expert_options">Expert settings</string>
<string name="pref_expert_options_summary">Please be careful with these</string>
<string name="title_activity_about">About Pix-Art Messenger</string>
<string name="pref_about_conversations_summary">Build and licensing information</string>
@@ -465,7 +466,7 @@
<string name="two_hours">2 hours</string>
<string name="eight_hours">8 hours</string>
<string name="until_further_notice">Until further notice</string>
- <string name="pref_input_options">Input options</string>
+ <string name="pref_input_options">Input</string>
<string name="pref_enter_is_send">Enter is send</string>
<string name="pref_enter_is_send_summary">Use enter key to send message</string>
<string name="pref_display_enter_key">Show enter key</string>
@@ -541,19 +542,20 @@
<string name="download_started">Download started</string>
<string name="account_status_tor_unavailable">Tor network unavailable</string>
<string name="server_info_broken">Broken</string>
- <string name="pref_presence_settings">Presence settings</string>
+ <string name="pref_presence_settings">Presence</string>
<string name="pref_away_when_screen_off">Away when screen is off</string>
<string name="pref_away_when_screen_off_summary">Marks your resource as away when the screen is turned off</string>
<string name="pref_xa_on_silent_mode">Not available in silent mode</string>
<string name="update_info">Pix-Art Messenger is checking for an update. If an update is available you will be asked, if you want to update your version. The update process is downloading and installing the new version automatically.</string>
<string name="pref_xa_on_silent_mode_summary">Marks your resource as not available when device is in silent mode</string>
- <string name="pref_show_connection_options">Extended connection options</string>
- <string name="pref_show_connection_options_summary">Show hostname and port options when setting up an account</string>
+ <string name="pref_show_connection_options">Extended connection settings</string>
+ <string name="pref_show_connection_options_summary">Show hostname and port settings when setting up an account</string>
<string name="hostname_example">xmpp.example.com</string>
<string name="action_add_account_with_certificate">Add account with certificate</string>
<string name="unable_to_parse_certificate">Unable to parse certificate</string>
<string name="authenticate_with_certificate">Leave empty to authenticate w/ certificate</string>
<string name="mam_prefs">Archiving preferences</string>
+ <string name="server_side_mam_prefs">Server-side archiving preferences</string>
<string name="fetching_mam_prefs">Fetching archiving preferences. Please wait…</string>
<string name="unable_to_fetch_mam_prefs">Unable to fetch archiving preferences</string>
<string name="captcha_ocr">Captcha text</string>
@@ -570,7 +572,7 @@
<string name="pref_plugins_summary">Download plugins for Pix-Art Messenger</string>
<string name="pref_plugin_location">Share-Location</string>
<string name="pref_plugin_location_summary">Send and receive locations</string>
- <string name="pref_connection_options">Connection options</string>
+ <string name="pref_connection_options">Connection</string>
<string name="pref_use_tor">Connect via Tor</string>
<string name="pref_use_tor_summary">Tunnel all connections through the Tor network. Requires Orbot</string>
<string name="account_settings_hostname">Hostname</string>
@@ -594,7 +596,7 @@
<string name="certificate_issuer">Issuer</string>
<string name="certificate_cn">Common Name</string>
<string name="certificate_o">Organization</string>
- <string name="certificate_sha1">SHA1</string>
+ <string name="certificate_sha1">SHA-1</string>
<string name="certicate_info_not_available">(Not available)</string>
<string name="certificate_not_found">No certificate found</string>
<string name="notify_on_all_messages">Notify on all messages</string>
@@ -602,7 +604,7 @@
<string name="notify_never">Notifications disabled</string>
<string name="notify_paused">Notifications paused</string>
<string name="pref_picture_compression">Compress Pictures</string>
- <string name="pref_picture_compression_summary">Resize and compressed pictures</string>
+ <string name="pref_picture_compression_summary">Resize and compress pictures</string>
<string name="always">Always</string>
<string name="automatically">Automatically</string>
<string name="battery_optimizations_enabled">Battery optimizations enabled</string>
@@ -616,4 +618,7 @@
<string name="no_accounts">(No activated accounts)</string>
<string name="this_field_is_required">This field is required</string>
<string name="no_participants">No participants</string>
+ <string name="correct_message">Correct message</string>
+ <string name="send_corrected_message">Send corrected message</string>
+>>>>>>> refs/heads/pr/73
</resources>
diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml
index 83d019fc7..ca8847cba 100644
--- a/src/main/res/xml/preferences.xml
+++ b/src/main/res/xml/preferences.xml
@@ -151,7 +151,7 @@
android:summary="@string/pref_show_dynamic_tags_summary"
android:title="@string/pref_show_dynamic_tags"/>
</PreferenceCategory>
- <PreferenceCategory android:title="@string/pref_encryption_settings">
+ <PreferenceCategory android:title="@string/pref_security_settings">
<CheckBoxPreference
android:defaultValue="false"
android:key="dont_save_encrypted"
@@ -166,6 +166,11 @@
android:key="remove_trusted_certificates"
android:summary="@string/pref_remove_trusted_certificates_summary"
android:title="@string/pref_remove_trusted_certificates_title"/>
+ <CheckBoxPreference
+ android:defaultValue="true"
+ android:key="allow_message_correction"
+ android:title="@string/pref_allow_message_correction"
+ android:summary="@string/pref_allow_message_correction_summary"/>
</PreferenceCategory>
<PreferenceCategory
android:key="connection_options"