diff options
37 files changed, 806 insertions, 149 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 16b53a3e..77a49e47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ ###Changelog +####Version 1.2.0 +* Send current location (requires plugin) +* bug fixes + +####Version 1.1.0 +* Typing notifications (must be turned on in settings) +* Various UI performance improvements +* bug fixes + ####Version 1.0.4 * load avatars asynchronously on start up * support for XEP-0092: Software Version diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 41e8971f..f38bcbfc 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -27,6 +27,7 @@ public final class Config { public static final int REFRESH_UI_INTERVAL = 500; public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb + public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; public static final long MAM_MAX_CATCHUP = MILLISECONDS_IN_DAY / 2; @@ -63,6 +64,15 @@ public final class Config { "TLS_RSA_WITH_AES_256_CBC_SHA", }; + public static final String WEAK_CIPHER_PATTERNS[] = { + "_NULL_", + "_EXPORT_", + "_anon_", + "_RC4_", + "_DES_", + "_MD5", + }; + private Config() { } diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 698e0322..cef03ebe 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -80,7 +80,7 @@ public class Contact implements ListItem, Blockable { cursor.getLong(cursor.getColumnIndex(LAST_TIME))); final Jid jid; try { - jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(JID))); + jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(JID)), true); } catch (final InvalidJidException e) { // TODO: Borked DB... handle this somehow? return null; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 99823e4e..c150fb91 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -2,10 +2,8 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.database.Cursor; -import android.os.SystemClock; import net.java.otr4j.OtrException; -import net.java.otr4j.crypto.OtrCryptoEngineImpl; import net.java.otr4j.crypto.OtrCryptoException; import net.java.otr4j.session.SessionID; import net.java.otr4j.session.SessionImpl; @@ -371,7 +369,7 @@ public class Conversation extends AbstractEntity implements Blockable { public static Conversation fromCursor(Cursor cursor) { Jid jid; try { - jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID))); + jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID)), true); } catch (final InvalidJidException e) { // Borked DB.. jid = null; diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 7ad43d53..8015eead 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -8,6 +8,7 @@ import java.net.URL; import java.util.Arrays; import eu.siacs.conversations.Config; +import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -49,6 +50,7 @@ public class Message extends AbstractEntity { public static final String RELATIVE_FILE_PATH = "relativeFilePath"; public static final String ME_COMMAND = "/me "; + public boolean markable = false; protected String conversationUuid; protected Jid counterpart; @@ -115,7 +117,7 @@ public class Message extends AbstractEntity { try { String value = cursor.getString(cursor.getColumnIndex(COUNTERPART)); if (value != null) { - jid = Jid.fromString(value); + jid = Jid.fromString(value, true); } else { jid = null; } @@ -126,7 +128,7 @@ public class Message extends AbstractEntity { try { String value = cursor.getString(cursor.getColumnIndex(TRUE_COUNTERPART)); if (value != null) { - trueCounterpart = Jid.fromString(value); + trueCounterpart = Jid.fromString(value, true); } else { trueCounterpart = null; } @@ -368,6 +370,8 @@ public class Message extends AbstractEntity { this.getCounterpart() != null && this.getCounterpart().equals(message.getCounterpart()) && (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) && + !GeoHelper.isGeoUri(message.getBody()) && + !GeoHelper.isGeoUri(this.body) && !message.bodyContainsDownloadable() && !this.bodyContainsDownloadable() && !message.getBody().startsWith(ME_COMMAND) && diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index ced81520..6652842d 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -143,7 +143,7 @@ public class MessageParser extends AbstractParser implements finishedMessage.setRemoteMsgId(packet.getId()); finishedMessage.markable = isMarkable(packet); finishedMessage.setCounterpart(from); - extractChatState(conversation,packet); + extractChatState(conversation, packet); return finishedMessage; } catch (Exception e) { conversation.resetOtrSession(); @@ -408,11 +408,11 @@ public class MessageParser extends AbstractParser implements .getAttribute("id"); updateLastseen(packet, account, true); final Message displayedMessage = mXmppConnectionService.markMessage(account, from.toBareJid(), id, Message.STATUS_SEND_DISPLAYED); - Message message = displayedMessage.prev(); - while(message != null + Message message = displayedMessage == null ? null :displayedMessage.prev(); + while (message != null && message.getStatus() == Message.STATUS_SEND_RECEIVED && message.getTimeSent() < displayedMessage.getTimeSent()) { - mXmppConnectionService.markMessage(message,Message.STATUS_SEND_DISPLAYED); + mXmppConnectionService.markMessage(message, Message.STATUS_SEND_DISPLAYED); message = message.prev(); } } else if (from != null diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 62987aaa..c499d499 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -318,39 +318,41 @@ public class FileBackend { } public boolean save(Avatar avatar) { + File file; if (isAvatarCached(avatar)) { - return true; - } - String filename = getAvatarPath(avatar.getFilename()); - File file = new File(filename + ".tmp"); - file.getParentFile().mkdirs(); - try { - file.createNewFile(); - FileOutputStream mFileOutputStream = new FileOutputStream(file); - MessageDigest digest = MessageDigest.getInstance("SHA-1"); - digest.reset(); - DigestOutputStream mDigestOutputStream = new DigestOutputStream( - mFileOutputStream, digest); - mDigestOutputStream.write(avatar.getImageAsBytes()); - mDigestOutputStream.flush(); - mDigestOutputStream.close(); - avatar.size = file.length(); - String sha1sum = CryptoHelper.bytesToHex(digest.digest()); - if (sha1sum.equals(avatar.sha1sum)) { - file.renameTo(new File(filename)); - return true; - } else { - Log.d(Config.LOGTAG, "sha1sum mismatch for " + avatar.owner); - file.delete(); + file = new File(getAvatarPath(avatar.getFilename())); + } else { + String filename = getAvatarPath(avatar.getFilename()); + file = new File(filename + ".tmp"); + file.getParentFile().mkdirs(); + try { + file.createNewFile(); + FileOutputStream mFileOutputStream = new FileOutputStream(file); + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + digest.reset(); + DigestOutputStream mDigestOutputStream = new DigestOutputStream( + mFileOutputStream, digest); + mDigestOutputStream.write(avatar.getImageAsBytes()); + mDigestOutputStream.flush(); + mDigestOutputStream.close(); + String sha1sum = CryptoHelper.bytesToHex(digest.digest()); + if (sha1sum.equals(avatar.sha1sum)) { + file.renameTo(new File(filename)); + } else { + Log.d(Config.LOGTAG, "sha1sum mismatch for " + avatar.owner); + file.delete(); + return false; + } + } catch (FileNotFoundException e) { + return false; + } catch (IOException e) { + return false; + } catch (NoSuchAlgorithmException e) { return false; } - } catch (FileNotFoundException e) { - return false; - } catch (IOException e) { - return false; - } catch (NoSuchAlgorithmException e) { - return false; } + avatar.size = file.length(); + return true; } public String getAvatarPath(String avatar) { diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 6e4f9981..7269a559 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -40,6 +40,7 @@ import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.ui.ConversationActivity; import eu.siacs.conversations.ui.ManageAccountActivity; import eu.siacs.conversations.ui.TimePreference; +import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.XmppConnection; @@ -279,6 +280,11 @@ public class NotificationService { createDownloadIntent(message) ); } + if ((message = getFirstLocationMessage(messages)) != null) { + mBuilder.addAction(R.drawable.ic_room_white_24dp, + mXmppConnectionService.getString(R.string.show_location), + createShowLocationIntent(message)); + } mBuilder.setContentIntent(createContentIntent(conversation)); } return mBuilder; @@ -342,6 +348,15 @@ public class NotificationService { return null; } + private Message getFirstLocationMessage(final Iterable<Message> messages) { + for(final Message message : messages) { + if (GeoHelper.isGeoUri(message.getBody())) { + return message; + } + } + return null; + } + private CharSequence getMergedBodies(final ArrayList<Message> messages) { final StringBuilder text = new StringBuilder(); for (int i = 0; i < messages.size(); ++i) { @@ -353,6 +368,16 @@ public class NotificationService { return text.toString(); } + private PendingIntent createShowLocationIntent(final Message message) { + Iterable<Intent> intents = GeoHelper.createGeoIntentsFromMessage(message); + for(Intent intent : intents) { + if (intent.resolveActivity(mXmppConnectionService.getPackageManager()) != null) { + return PendingIntent.getActivity(mXmppConnectionService,18,intent,PendingIntent.FLAG_UPDATE_CURRENT); + } + } + return createOpenConversationsIntent(); + } + private PendingIntent createContentIntent(final String conversationUuid, final String downloadMessageUuid) { final TaskStackBuilder stackBuilder = TaskStackBuilder .create(mXmppConnectionService); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index f6e479c7..188f1eb9 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -306,6 +306,24 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return this.mAvatarService; } + public void attachLocationToConversation(final Conversation conversation, + final Uri uri, + final UiCallback<Message> callback) { + int encryption = conversation.getNextEncryption(forceEncryption()); + if (encryption == Message.ENCRYPTION_PGP) { + encryption = Message.ENCRYPTION_DECRYPTED; + } + Message message = new Message(conversation,uri.toString(),encryption); + if (conversation.getNextCounterpart() != null) { + message.setCounterpart(conversation.getNextCounterpart()); + } + if (encryption == Message.ENCRYPTION_DECRYPTED) { + getPgpEngine().encrypt(message,callback); + } else { + callback.success(message); + } + } + public void attachFileToConversation(final Conversation conversation, final Uri uri, final UiCallback<Message> callback) { @@ -1136,7 +1154,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa account.initOtrEngine(this); databaseBackend.createAccount(account); this.accounts.add(account); - this.reconnectAccount(account, false); + this.reconnectAccountInBackground(account); updateAccountUi(); } @@ -1972,24 +1990,29 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public void reconnectAccount(final Account account, final boolean force) { - new Thread(new Runnable() { + synchronized (account) { + if (account.getXmppConnection() != null) { + disconnect(account, force); + } + if (!account.isOptionSet(Account.OPTION_DISABLED)) { + if (account.getXmppConnection() == null) { + account.setXmppConnection(createConnection(account)); + } + Thread thread = new Thread(account.getXmppConnection()); + thread.start(); + scheduleWakeUpCall(Config.CONNECT_TIMEOUT, account.getUuid().hashCode()); + } else { + account.getRoster().clearPresences(); + account.setXmppConnection(null); + } + } + } + public void reconnectAccountInBackground(final Account account) { + new Thread(new Runnable() { @Override public void run() { - if (account.getXmppConnection() != null) { - disconnect(account, force); - } - if (!account.isOptionSet(Account.OPTION_DISABLED)) { - if (account.getXmppConnection() == null) { - account.setXmppConnection(createConnection(account)); - } - Thread thread = new Thread(account.getXmppConnection()); - thread.start(); - scheduleWakeUpCall(Config.CONNECT_TIMEOUT, account.getUuid().hashCode()); - } else { - account.getRoster().clearPresences(); - account.setXmppConnection(null); - } + reconnectAccount(account,false); } }).start(); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index ad2aab56..82afda07 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -33,7 +33,6 @@ import java.util.ArrayList; import java.util.List; import eu.siacs.conversations.R; -import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Blockable; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; @@ -63,6 +62,7 @@ public class ConversationActivity extends XmppActivity private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302; private static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303; private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304; + private static final int ATTACHMENT_CHOICE_LOCATION = 0x0305; private static final String STATE_OPEN_CONVERSATION = "state_open_conversation"; private static final String STATE_PANEL_OPEN = "state_panel_open"; private static final String STATE_PENDING_URI = "state_pending_uri"; @@ -71,6 +71,7 @@ public class ConversationActivity extends XmppActivity private boolean mPanelOpen = true; private Uri mPendingImageUri = null; private Uri mPendingFileUri = null; + private Uri mPendingGeoUri = null; private View mContentView; @@ -313,7 +314,6 @@ public class ConversationActivity extends XmppActivity menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite()); } else { menuMucDetails.setVisible(false); - final Account account = this.getSelectedConversation().getAccount(); } if (this.getSelectedConversation().isMuted()) { menuMute.setVisible(false); @@ -325,50 +325,60 @@ public class ConversationActivity extends XmppActivity return true; } - private void selectPresenceToAttachFile(final int attachmentChoice) { - selectPresence(getSelectedConversation(), new OnPresenceSelected() { + private void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) { + if (attachmentChoice == ATTACHMENT_CHOICE_LOCATION && encryption != Message.ENCRYPTION_OTR) { + getSelectedConversation().setNextCounterpart(null); + Intent intent = new Intent("eu.siacs.conversations.location.request"); + startActivityForResult(intent,attachmentChoice); + } else { + selectPresence(getSelectedConversation(), new OnPresenceSelected() { - @Override - public void onPresenceSelected() { - Intent intent = new Intent(); - boolean chooser = false; - switch (attachmentChoice) { - case ATTACHMENT_CHOICE_CHOOSE_IMAGE: - intent.setAction(Intent.ACTION_GET_CONTENT); - intent.setType("image/*"); - chooser = true; - break; - case ATTACHMENT_CHOICE_TAKE_PHOTO: - mPendingImageUri = xmppConnectionService.getFileBackend().getTakePhotoUri(); - intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT,mPendingImageUri); - break; - case ATTACHMENT_CHOICE_CHOOSE_FILE: - chooser = true; - intent.setType("*/*"); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setAction(Intent.ACTION_GET_CONTENT); - break; - case ATTACHMENT_CHOICE_RECORD_VOICE: - intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION); - break; - } - if (intent.resolveActivity(getPackageManager()) != null) { - if (chooser) { - startActivityForResult( - Intent.createChooser(intent,getString(R.string.perform_action_with)), - attachmentChoice); - } else { - startActivityForResult(intent, attachmentChoice); + @Override + public void onPresenceSelected() { + Intent intent = new Intent(); + boolean chooser = false; + switch (attachmentChoice) { + case ATTACHMENT_CHOICE_CHOOSE_IMAGE: + intent.setAction(Intent.ACTION_GET_CONTENT); + intent.setType("image/*"); + chooser = true; + break; + case ATTACHMENT_CHOICE_TAKE_PHOTO: + mPendingImageUri = xmppConnectionService.getFileBackend().getTakePhotoUri(); + intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, mPendingImageUri); + break; + case ATTACHMENT_CHOICE_CHOOSE_FILE: + chooser = true; + intent.setType("*/*"); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setAction(Intent.ACTION_GET_CONTENT); + break; + case ATTACHMENT_CHOICE_RECORD_VOICE: + intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION); + break; + case ATTACHMENT_CHOICE_LOCATION: + intent.setAction("eu.siacs.conversations.location.request"); + break; + } + if (intent.resolveActivity(getPackageManager()) != null) { + if (chooser) { + startActivityForResult( + Intent.createChooser(intent, getString(R.string.perform_action_with)), + attachmentChoice); + } else { + startActivityForResult(intent, attachmentChoice); + } } } - } - }); + }); + } } private void attachFile(final int attachmentChoice) { final Conversation conversation = getSelectedConversation(); - if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { + final int encryption = conversation.getNextEncryption(forceEncryption()); + if (encryption == Message.ENCRYPTION_PGP) { if (hasPgp()) { if (conversation.getContact().getPgpKeyId() != 0) { xmppConnectionService.getPgpEngine().hasKey( @@ -378,13 +388,12 @@ public class ConversationActivity extends XmppActivity @Override public void userInputRequried(PendingIntent pi, Contact contact) { - ConversationActivity.this.runIntent(pi, - attachmentChoice); + ConversationActivity.this.runIntent(pi,attachmentChoice); } @Override public void success(Contact contact) { - selectPresenceToAttachFile(attachmentChoice); + selectPresenceToAttachFile(attachmentChoice,encryption); } @Override @@ -406,7 +415,7 @@ public class ConversationActivity extends XmppActivity .setNextEncryption(Message.ENCRYPTION_NONE); xmppConnectionService.databaseBackend .updateConversation(conversation); - selectPresenceToAttachFile(attachmentChoice); + selectPresenceToAttachFile(attachmentChoice,Message.ENCRYPTION_NONE); } }); } @@ -414,11 +423,8 @@ public class ConversationActivity extends XmppActivity } else { showInstallPgpDialog(); } - } else if (getSelectedConversation().getNextEncryption( - forceEncryption()) == Message.ENCRYPTION_NONE) { - selectPresenceToAttachFile(attachmentChoice); } else { - selectPresenceToAttachFile(attachmentChoice); + selectPresenceToAttachFile(attachmentChoice,encryption); } } @@ -526,6 +532,9 @@ public class ConversationActivity extends XmppActivity if (new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION).resolveActivity(getPackageManager()) == null) { attachFilePopup.getMenu().findItem(R.id.attach_record_voice).setVisible(false); } + if (new Intent("eu.siacs.conversations.location.request").resolveActivity(getPackageManager()) == null) { + attachFilePopup.getMenu().findItem(R.id.attach_location).setVisible(false); + } attachFilePopup.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override @@ -543,6 +552,9 @@ public class ConversationActivity extends XmppActivity case R.id.attach_record_voice: attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); break; + case R.id.attach_location: + attachFile(ATTACHMENT_CHOICE_LOCATION); + break; } return false; } @@ -809,6 +821,7 @@ public class ConversationActivity extends XmppActivity showConversationsOverview(); mPendingImageUri = null; mPendingFileUri = null; + mPendingGeoUri = null; setSelectedConversation(conversationList.get(0)); this.mConversationFragment.reInit(getSelectedConversation()); } @@ -819,6 +832,9 @@ public class ConversationActivity extends XmppActivity } else if (mPendingFileUri != null) { attachFileToConversation(getSelectedConversation(),mPendingFileUri); mPendingFileUri = null; + } else if (mPendingGeoUri != null) { + attachLocationToConversation(getSelectedConversation(),mPendingGeoUri); + mPendingGeoUri = null; } ExceptionHelper.checkForCrash(this, this.xmppConnectionService); setIntent(new Intent()); @@ -897,6 +913,14 @@ public class ConversationActivity extends XmppActivity Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(mPendingImageUri); sendBroadcast(intent); + } else if (requestCode == ATTACHMENT_CHOICE_LOCATION) { + double latitude = data.getDoubleExtra("latitude",0); + double longitude = data.getDoubleExtra("longitude",0); + this.mPendingGeoUri = Uri.parse("geo:"+String.valueOf(latitude)+","+String.valueOf(longitude)); + if (xmppConnectionServiceBound) { + attachLocationToConversation(getSelectedConversation(), mPendingGeoUri); + this.mPendingGeoUri = null; + } } } else { if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) { @@ -905,6 +929,26 @@ public class ConversationActivity extends XmppActivity } } + private void attachLocationToConversation(Conversation conversation, Uri uri) { + xmppConnectionService.attachLocationToConversation(conversation,uri, new UiCallback<Message>() { + + @Override + public void success(Message message) { + xmppConnectionService.sendMessage(message); + } + + @Override + public void error(int errorCode, Message object) { + + } + + @Override + public void userInputRequried(PendingIntent pi, Message object) { + + } + }); + } + private void attachFileToConversation(Conversation conversation, Uri uri) { prepareFileToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_file), Toast.LENGTH_LONG); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 3e0668be..d5f20e41 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -8,6 +8,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; +import android.net.Uri; import android.os.Bundle; import android.text.InputType; import android.view.ContextMenu; @@ -58,6 +59,7 @@ import eu.siacs.conversations.ui.XmppActivity.OnValueEdited; import eu.siacs.conversations.ui.adapter.MessageAdapter; 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.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.jid.Jid; @@ -410,19 +412,20 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa MenuItem downloadImage = menu.findItem(R.id.download_image); MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission); if ((m.getType() != Message.TYPE_TEXT && m.getType() != Message.TYPE_PRIVATE) - || m.getDownloadable() != null) { + || m.getDownloadable() != null || GeoHelper.isGeoUri(m.getBody())) { copyText.setVisible(false); } - if (m.getType() == Message.TYPE_TEXT + if ((m.getType() == Message.TYPE_TEXT || m.getType() == Message.TYPE_PRIVATE - || m.getDownloadable() != null) { + || m.getDownloadable() != null) + && (!GeoHelper.isGeoUri(m.getBody()))) { shareWith.setVisible(false); - } + } if (m.getStatus() != Message.STATUS_SEND_FAILED) { sendAgain.setVisible(false); } - if ((m.getType() != Message.TYPE_IMAGE && m.getDownloadable() == null) - || m.getImageParams().url == null) { + if (((m.getType() != Message.TYPE_IMAGE && m.getDownloadable() == null) + || m.getImageParams().url == null) && !GeoHelper.isGeoUri(m.getBody())) { copyUrl.setVisible(false); } if (m.getType() != Message.TYPE_TEXT @@ -467,16 +470,21 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa private void shareWith(Message message) { Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); - shareIntent.putExtra(Intent.EXTRA_STREAM, - activity.xmppConnectionService.getFileBackend() - .getJingleFileUri(message)); - shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - String path = message.getRelativeFilePath(); - String mime = path == null ? null :URLConnection.guessContentTypeFromName(path); - if (mime == null) { - mime = "image/webp"; + if (GeoHelper.isGeoUri(message.getBody())) { + shareIntent.putExtra(Intent.EXTRA_TEXT, message.getBody()); + shareIntent.setType("text/plain"); + } else { + shareIntent.putExtra(Intent.EXTRA_STREAM, + activity.xmppConnectionService.getFileBackend() + .getJingleFileUri(message)); + shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + String path = message.getRelativeFilePath(); + String mime = path == null ? null : URLConnection.guessContentTypeFromName(path); + if (mime == null) { + mime = "image/webp"; + } + shareIntent.setType(mime); } - shareIntent.setType(mime); activity.startActivity(Intent.createChooser(shareIntent,getText(R.string.share_with))); } @@ -501,8 +509,16 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } private void copyUrl(Message message) { - if (activity.copyTextToClipboard( - message.getImageParams().url.toString(), R.string.image_url)) { + final String url; + final int resId; + if (GeoHelper.isGeoUri(message.getBody())) { + resId = R.string.location; + url = message.getBody(); + } else { + resId = R.string.image_url; + url = message.getImageParams().url.toString(); + } + if (activity.copyTextToClipboard(url, resId)) { Toast.makeText(activity, R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT).show(); } @@ -1012,8 +1028,13 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } @Override - public void onEnterPressed() { - sendMessage(); + public boolean onEnterPressed() { + if (activity.enterIsSend()) { + sendMessage(); + return true; + } else { + return false; + } } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/EditMessage.java b/src/main/java/eu/siacs/conversations/ui/EditMessage.java index 57fa7285..a58cf2b8 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditMessage.java +++ b/src/main/java/eu/siacs/conversations/ui/EditMessage.java @@ -37,10 +37,9 @@ public class EditMessage extends EditText { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER) { - if (keyboardListener != null) { - keyboardListener.onEnterPressed(); + if (keyboardListener != null && keyboardListener.onEnterPressed()) { + return true; } - return true; } return super.onKeyDown(keyCode, event); } @@ -70,7 +69,7 @@ public class EditMessage extends EditText { } public interface KeyboardListener { - public void onEnterPressed(); + public boolean onEnterPressed(); public void onTypingStarted(); public void onTypingStopped(); public void onTextDeleted(); diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index 5bf3cdab..39e215f2 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -65,7 +65,7 @@ public class SettingsActivity extends XmppActivity implements for (Account account : xmppConnectionService.getAccounts()) { account.setResource(resource); if (!account.isOptionSet(Account.OPTION_DISABLED)) { - xmppConnectionService.reconnectAccount(account, false); + xmppConnectionService.reconnectAccountInBackground(account); } } } 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 58713534..da92fb18 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -34,6 +34,7 @@ import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message.ImageParams; import eu.siacs.conversations.ui.ConversationActivity; +import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.UIHelper; public class MessageAdapter extends ArrayAdapter<Message> { @@ -299,6 +300,21 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.download_button.setOnLongClickListener(openContextMenu); } + private void displayLocationMessage(ViewHolder viewHolder, final Message message) { + viewHolder.image.setVisibility(View.GONE); + viewHolder.messageBody.setVisibility(View.GONE); + viewHolder.download_button.setVisibility(View.VISIBLE); + viewHolder.download_button.setText(R.string.show_location); + viewHolder.download_button.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + showLocation(message); + } + }); + viewHolder.download_button.setOnLongClickListener(openContextMenu); + } + private void displayImageMessage(ViewHolder viewHolder, final Message message) { if (viewHolder.download_button != null) { @@ -509,7 +525,11 @@ public class MessageAdapter extends ArrayAdapter<Message> { } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { displayDecryptionFailed(viewHolder); } else { - displayTextMessage(viewHolder, message); + if (GeoHelper.isGeoUri(message.getBody())) { + displayLocationMessage(viewHolder,message); + } else { + displayTextMessage(viewHolder, message); + } } displayStatus(viewHolder, message); @@ -544,6 +564,16 @@ public class MessageAdapter extends ArrayAdapter<Message> { } } + public void showLocation(Message message) { + for(Intent intent : GeoHelper.createGeoIntentsFromMessage(message)) { + if (intent.resolveActivity(getContext().getPackageManager()) != null) { + getContext().startActivity(intent); + return; + } + } + Toast.makeText(activity,R.string.no_application_found_to_display_location,Toast.LENGTH_SHORT).show(); + } + public interface OnContactPictureClicked { public void onContactPictureClicked(Message message); } diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java index 31fe2c11..eb7e2c3c 100644 --- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java @@ -4,6 +4,7 @@ import java.security.SecureRandom; import java.text.Normalizer; import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; @@ -103,6 +104,21 @@ public final class CryptoHelper { final List<String> platformCiphers = Arrays.asList(platformSupportedCipherSuites); cipherSuites.retainAll(platformCiphers); cipherSuites.addAll(platformCiphers); + filterWeakCipherSuites(cipherSuites); return cipherSuites.toArray(new String[cipherSuites.size()]); } + + private static void filterWeakCipherSuites(final Collection<String> cipherSuites) { + final Iterator<String> it = cipherSuites.iterator(); + while (it.hasNext()) { + String cipherName = it.next(); + // remove all ciphers with no or very weak encryption or no authentication + for (String weakCipherPattern : Config.WEAK_CIPHER_PATTERNS) { + if (cipherName.contains(weakCipherPattern)) { + it.remove(); + break; + } + } + } + } } diff --git a/src/main/java/eu/siacs/conversations/utils/GeoHelper.java b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java new file mode 100644 index 00000000..f7dda936 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java @@ -0,0 +1,71 @@ +package eu.siacs.conversations.utils; + +import android.content.Intent; +import android.net.Uri; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; + +public class GeoHelper { + private static Pattern GEO_URI = Pattern.compile("geo:([\\-0-9.]+),([\\-0-9.]+)(?:,([\\-0-9.]+))?(?:\\?(.*))?", Pattern.CASE_INSENSITIVE); + + public static boolean isGeoUri(String body) { + return body != null && GEO_URI.matcher(body).matches(); + } + + public static ArrayList<Intent> createGeoIntentsFromMessage(Message message) { + final ArrayList<Intent> intents = new ArrayList(); + Matcher matcher = GEO_URI.matcher(message.getBody()); + if (!matcher.matches()) { + return intents; + } + double latitude; + double longitude; + try { + latitude = Double.parseDouble(matcher.group(1)); + if (latitude > 90.0 || latitude < -90.0) { + return intents; + } + longitude = Double.parseDouble(matcher.group(2)); + if (longitude > 180.0 || longitude < -180.0) { + return intents; + } + } catch (NumberFormatException nfe) { + return intents; + } + final Conversation conversation = message.getConversation(); + String label; + if (conversation.getMode() == Conversation.MODE_SINGLE && message.getStatus() == Message.STATUS_RECEIVED) { + try { + label = "(" + URLEncoder.encode(message.getConversation().getName(), "UTF-8") + ")"; + } catch (UnsupportedEncodingException e) { + label = ""; + } + } else { + label = ""; + } + + Intent locationPluginIntent = new Intent("eu.siacs.conversations.location.show"); + locationPluginIntent.putExtra("latitude",latitude); + locationPluginIntent.putExtra("longitude",longitude); + if (conversation.getMode() == Conversation.MODE_SINGLE && message.getStatus() == Message.STATUS_RECEIVED) { + locationPluginIntent.putExtra("name",conversation.getName()); + } + intents.add(locationPluginIntent); + + Intent geoIntent = new Intent(Intent.ACTION_VIEW); + geoIntent.setData(Uri.parse("geo:" + String.valueOf(latitude) + "," + String.valueOf(longitude) + "?q=" + String.valueOf(latitude) + "," + String.valueOf(longitude) + label)); + intents.add(geoIntent); + + Intent httpIntent = new Intent(Intent.ACTION_VIEW); + httpIntent.setData(Uri.parse("https://maps.google.com/maps?q=loc:"+String.valueOf(latitude) + "," + String.valueOf(longitude) +label)); + intents.add(httpIntent); + return intents; + } +} diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index e36c169b..c3195d86 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -153,7 +153,13 @@ public class UIHelper { if (message.getBody().startsWith(Message.ME_COMMAND)) { return new Pair<>(message.getBody().replaceAll("^" + Message.ME_COMMAND, UIHelper.getMessageDisplayName(message) + " "), false); - } else { + } else if (GeoHelper.isGeoUri(message.getBody())) { + if (message.getStatus() == Message.STATUS_RECEIVED) { + return new Pair<>(context.getString(R.string.received_location),true); + } else { + return new Pair<>(context.getString(R.string.location), true); + } + } else{ return new Pair<>(message.getBody().trim(), false); } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 44c367a6..57a64513 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -242,6 +242,13 @@ public class XmppConnection implements Runnable { @Override public void run() { + try { + if (socket != null) { + socket.close(); + } + } catch (final IOException ignored) { + + } connect(); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java index b8be527b..295e067a 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java @@ -1,9 +1,12 @@ package eu.siacs.conversations.xmpp.jid; +import android.util.LruCache; + import net.java.otr4j.session.SessionID; import java.net.IDN; +import eu.siacs.conversations.Config; import gnu.inet.encoding.Stringprep; import gnu.inet.encoding.StringprepException; @@ -12,6 +15,8 @@ import gnu.inet.encoding.StringprepException; */ public final class Jid { + private static LruCache<String,Jid> cache = new LruCache<>(1024); + private final String localpart; private final String domainpart; private final String resourcepart; @@ -41,7 +46,11 @@ public final class Jid { } public static Jid fromString(final String jid) throws InvalidJidException { - return new Jid(jid); + return Jid.fromString(jid, false); + } + + public static Jid fromString(final String jid, final boolean safe) throws InvalidJidException { + return new Jid(jid, safe); } public static Jid fromParts(final String localpart, @@ -56,12 +65,21 @@ public final class Jid { if (resourcepart != null && !resourcepart.isEmpty()) { out = out + "/" + resourcepart; } - return new Jid(out); + return new Jid(out, false); } - private Jid(final String jid) throws InvalidJidException { + private Jid(final String jid, final boolean safe) throws InvalidJidException { if (jid == null) throw new InvalidJidException(InvalidJidException.IS_NULL); + Jid fromCache = Jid.cache.get(jid); + if (fromCache != null) { + displayjid = fromCache.displayjid; + localpart = fromCache.localpart; + domainpart = fromCache.domainpart; + resourcepart = fromCache.resourcepart; + return; + } + // Hackish Android way to count the number of chars in a string... should work everywhere. final int atCount = jid.length() - jid.replace("@", "").length(); final int slashCount = jid.length() - jid.replace("/", "").length(); @@ -90,7 +108,7 @@ public final class Jid { } else { final String lp = jid.substring(0, atLoc); try { - localpart = Stringprep.nodeprep(lp); + localpart = Config.DISABLE_STRING_PREP || safe ? lp : Stringprep.nodeprep(lp); } catch (final StringprepException e) { throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); } @@ -105,7 +123,7 @@ public final class Jid { if (slashCount > 0) { final String rp = jid.substring(slashLoc + 1, jid.length()); try { - resourcepart = Stringprep.resourceprep(rp); + resourcepart = Config.DISABLE_STRING_PREP || safe ? rp : Stringprep.resourceprep(rp); } catch (final StringprepException e) { throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); } @@ -141,6 +159,8 @@ public final class Jid { throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); } + Jid.cache.put(jid, this); + this.displayjid = finaljid; } diff --git a/src/main/res/drawable-hdpi/ic_room_white_24dp.png b/src/main/res/drawable-hdpi/ic_room_white_24dp.png Binary files differnew file mode 100644 index 00000000..c2ccd510 --- /dev/null +++ b/src/main/res/drawable-hdpi/ic_room_white_24dp.png diff --git a/src/main/res/drawable-mdpi/ic_room_white_24dp.png b/src/main/res/drawable-mdpi/ic_room_white_24dp.png Binary files differnew file mode 100644 index 00000000..a4fcd770 --- /dev/null +++ b/src/main/res/drawable-mdpi/ic_room_white_24dp.png diff --git a/src/main/res/drawable-xhdpi/ic_room_white_24dp.png b/src/main/res/drawable-xhdpi/ic_room_white_24dp.png Binary files differnew file mode 100644 index 00000000..e1e60a5c --- /dev/null +++ b/src/main/res/drawable-xhdpi/ic_room_white_24dp.png diff --git a/src/main/res/drawable-xxhdpi/ic_room_white_24dp.png b/src/main/res/drawable-xxhdpi/ic_room_white_24dp.png Binary files differnew file mode 100644 index 00000000..00b15508 --- /dev/null +++ b/src/main/res/drawable-xxhdpi/ic_room_white_24dp.png diff --git a/src/main/res/drawable-xxxhdpi/ic_room_white_24dp.png b/src/main/res/drawable-xxxhdpi/ic_room_white_24dp.png Binary files differnew file mode 100644 index 00000000..a5dde3b9 --- /dev/null +++ b/src/main/res/drawable-xxxhdpi/ic_room_white_24dp.png diff --git a/src/main/res/menu/attachment_choices.xml b/src/main/res/menu/attachment_choices.xml index 5139272c..6e8fc51d 100644 --- a/src/main/res/menu/attachment_choices.xml +++ b/src/main/res/menu/attachment_choices.xml @@ -2,14 +2,21 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item - android:id="@+id/attach_choose_picture" - android:title="@string/attach_choose_picture"/> + android:id="@+id/attach_location" + android:title="@string/send_location"/> + + <item + android:id="@+id/attach_record_voice" + android:title="@string/attach_record_voice"/> + <item android:id="@+id/attach_take_picture" android:title="@string/attach_take_picture"/> - <item - android:id="@+id/attach_record_voice" - android:title="@string/attach_record_voice"/> + + <item + android:id="@+id/attach_choose_picture" + android:title="@string/attach_choose_picture"/> + <item android:id="@+id/attach_choose_file" android:title="@string/choose_file"/> diff --git a/src/main/res/values-bg/strings.xml b/src/main/res/values-bg/strings.xml index 9b2e7012..3715e820 100644 --- a/src/main/res/values-bg/strings.xml +++ b/src/main/res/values-bg/strings.xml @@ -28,7 +28,7 @@ <string name="minutes_ago">преди %d минути</string> <string name="unread_conversations">непрочетени разговори</string> <string name="sending">изпращане...</string> - <string name="encrypted_message">Дешифриране на съобщението. Моля, изчакайте...</string> + <string name="encrypted_message">Дешифроване на съобщението. Моля, изчакайте...</string> <string name="nick_in_use">Псевдонимът вече се използва</string> <string name="admin">Администратор</string> <string name="owner">Собственик</string> @@ -82,48 +82,306 @@ <string name="your_nick_has_been_changed">Псевдонимът Ви беше променен</string> <string name="download_image">Изтегляне на изображението</string> <string name="send_unencrypted">Изпращане нешифровано</string> - <string name="decryption_failed">Неуспешно дешифриране. Възможно е да нямате правилния частен ключ.</string> - <string name="contacts_have_no_pgp_keys">Conversations не може да шифрира съобщенията Ви, тъй като контактите Ви не обявяват публичния си ключ.\n\n<small>Моля, помолете контактите си да настроят OpenPGP.</small></string> + <string name="decryption_failed">Неуспешно дешифроване. Възможно е да нямате правилния частен ключ.</string> + <string name="openkeychain_required">OpenKeychain</string> + <string name="openkeychain_required_long">Conversations използва външно приложение с име <b>OpenKeychain</b>, за да шифрова и дешифрова съобщенията и да управлява публичните Ви ключове.\n\nOpenKeychain е лицензирано под условията на GPLv3 и е налично в F-Droid и Google Play.\n\n<small>(Моля, рестартирайте Conversations след това.)</small></string> + <string name="restart">Рестартиране</string> + <string name="install">Инсталиране</string> + <string name="offering">предлагане...</string> + <string name="waiting">изчакване...</string> + <string name="no_pgp_key">Не е открит OpenPGP ключ</string> + <string name="contact_has_no_pgp_key">Conversations не може да шифрова съобщенията Ви, тъй като Вашият контакт не обявява публичния си ключ.\n\n<small>Моля, помолете го/я да инсталира и настрои OpenPGP.</small></string> + <string name="no_pgp_keys">Не са открити OpenPGP ключове</string> + <string name="contacts_have_no_pgp_keys">Conversations не може да шифрова съобщенията Ви, тъй като Вашите контакти не обявяват публичните си ключове.\n\n<small>Моля, помолете го да инсталират и настроят OpenPGP.</small></string> + <string name="encrypted_message_received"><i>Получено е шифровано съобщение. Докоснете, за да го прегледате и дешифровате.</i></string> + <string name="pref_general">Общи</string> + <string name="pref_xmpp_resource">XMPP ресурс</string> + <string name="pref_xmpp_resource_summary">Името, с което се определя този клиент</string> + <string name="pref_accept_files">Приемане на файлове</string> + <string name="pref_accept_files_summary">Автоматично приемане на файлове с размер, по-малък от...</string> + <string name="pref_notification_settings">Настройки за известията</string> + <string name="pref_notifications">Известия</string> + <string name="pref_notifications_summary">Известяване при получаване на ново съобщение</string> + <string name="pref_vibrate">Вибрация</string> + <string name="pref_vibrate_summary">Също така да има и вибрация при получаване на ново съобщение</string> + <string name="pref_sound">Звук</string> + <string name="pref_sound_summary">Изпълнение на звук с известието</string> <string name="pref_conference_notifications">Известия за беседите</string> + <string name="pref_conference_notifications_summary">Известяване винаги, когато пристигне ново съобщение в беседа, а не само когато тя е отбелязана</string> + <string name="pref_notification_grace_period">Продължителност на отсрочване на известията</string> + <string name="pref_notification_grace_period_summary">Изключва известията за кратко, след като бъде получено копие на съобщение</string> + <string name="pref_advanced_options">Разширени настройки</string> + <string name="pref_never_send_crash">Никога да не се изпращат доклади за сривове</string> <string name="pref_never_send_crash_summary">Изпращайки проследявания на стека, Вие помагате за непрекъснатото развитие на Conversations</string> + <string name="pref_confirm_messages">Потвърждаване на съобщенията</string> + <string name="pref_confirm_messages_summary">Уведомява контакта Ви, че сте приели и прочели съобщението му</string> + <string name="pref_ui_options">Настройки на интерфейса</string> + <string name="openpgp_error">OpenKeychain докладва за грешка</string> + <string name="error_decrypting_file">В/И грешка при дешифроването на файла</string> + <string name="accept">Приемане</string> + <string name="error">Възникна грешка</string> <string name="pref_grant_presence_updates">Позволяване на актуализации на присъствието</string> <string name="pref_grant_presence_updates_summary">Предварително позволяване и изискване на абониране за актуализации на присъствието за контакти, създадено от Вас</string> + <string name="subscriptions">Абонаменти</string> + <string name="your_account">Вашият профил</string> + <string name="keys">Ключове</string> <string name="send_presence_updates">Изпращане на актуализации за присъствието</string> <string name="receive_presence_updates">Получаване на актуализации за присъствието</string> <string name="ask_for_presence_updates">Питане за актуализации за присъствието</string> + <string name="attach_choose_picture">Изберете снимка</string> + <string name="attach_take_picture">Заснемане</string> + <string name="preemptively_grant">Предварително позволяване на абониране при заявка</string> + <string name="error_not_an_image_file">Избраният файл не е изображение</string> + <string name="error_compressing_image">Грешка при преобразуването на изображението</string> + <string name="error_file_not_found">Файлът не е открит</string> + <string name="error_io_exception">Обща В/И грешка. Може би нямате достатъчно свободно място?</string> + <string name="error_security_exception_during_image_copy">Приложението, което използвахте, за да изберете това изображение, не ни осигури нужните права за прочитането му.\n\n<small>Използвайте друг диспечер на файлове, за да изберете изображение.</small></string> + <string name="account_status_unknown">Непознат</string> + <string name="account_status_disabled">Временно деактивиран</string> + <string name="account_status_online">На линия</string> + <string name="account_status_connecting">Свързване\u2026</string> + <string name="account_status_offline">Извън линия</string> + <string name="account_status_unauthorized">Неупълномощен</string> + <string name="account_status_not_found">Сървърът не е открит</string> + <string name="account_status_no_internet">Няма връзка</string> + <string name="account_status_regis_fail">Неуспешна регистрация</string> + <string name="account_status_regis_conflict">Потребителското име е заето</string> + <string name="account_status_regis_success">Регистрацията е завършена</string> + <string name="account_status_regis_not_sup">Сървърът не поддържа регистриране</string> + <string name="account_status_security_error">Грешка в сигурността</string> + <string name="account_status_incompatible_server">Несъвместим сървър</string> + <string name="encryption_choice_none">Обикновен текст</string> + <string name="encryption_choice_otr">OTR</string> + <string name="encryption_choice_pgp">OpenPGP</string> + <string name="mgmt_account_edit">Редактиране на профила</string> + <string name="mgmt_account_delete">Изтриване на профила</string> + <string name="mgmt_account_disable">Временно деактивиране</string> + <string name="mgmt_account_publish_avatar">Публикуване на аватар</string> + <string name="mgmt_account_publish_pgp">Публикуване на публичния OpenPGP ключ</string> + <string name="mgmt_account_enable">Активиране на профила</string> + <string name="mgmt_account_are_you_sure">Сигурни ли сте?</string> + <string name="mgmt_account_delete_confirm_text">Ако изтриете профила, цялата история на разговорите Ви ще бъде изтрита.</string> + <string name="attach_record_voice">Запис на глас</string> + <string name="account_settings_jabber_id">Jabber идентификатор</string> + <string name="account_settings_password">Парола</string> + <string name="account_settings_example_jabber_id">username@example.com</string> + <string name="account_settings_confirm_password">Потвърдете паролата</string> + <string name="password">Парола</string> + <string name="confirm_password">Потвърдете паролата</string> + <string name="passwords_do_not_match">Паролите са различни</string> + <string name="invalid_jid">Това не е правилен Jabber идентификатор</string> + <string name="error_out_of_memory">Няма достатъчно памет. Изображението е твърде голямо.</string> + <string name="add_phone_book_text">Искате ли да добавите %s в списъка си от телефонни контакти?</string> + <string name="contact_status_online">на линия</string> + <string name="contact_status_free_to_chat">свободен за разговор</string> + <string name="contact_status_away">отсъстващ</string> + <string name="contact_status_extended_away">разширено отсъстващ</string> + <string name="contact_status_do_not_disturb">отпочиващ</string> + <string name="contact_status_offline">извън линия</string> <string name="muc_details_conference">Беседа</string> + <string name="muc_details_other_members">Други членове</string> + <string name="server_info_show_more">Инф. за сървъра</string> + <string name="server_info_mam">XEP-0313: Управление на архива на съобщенията</string> + <string name="server_info_carbon_messages">XEP-0280: Копия на съобщенията</string> + <string name="server_info_csi">XEP-0352: Показания за състоянието на клиента</string> <string name="server_info_blocking">XEP-0191: Команда за блокиране</string> - <string name="decrypt">Дешифриране</string> + <string name="server_info_roster_version">XEP-0237: Поддържане на версия на списъка</string> + <string name="server_info_stream_management">XEP-0198: Управление на потоците</string> + <string name="server_info_pep">XEP-0163: PEP (Аватари)</string> + <string name="server_info_available">налично</string> + <string name="server_info_unavailable">не е налично</string> + <string name="missing_public_keys">Липсват обявления за публичен ключ</string> + <string name="last_seen_now">последно видян току-що</string> + <string name="last_seen_min">последно видян преди 1 минута</string> + <string name="last_seen_mins">последно видян преди %d минути</string> + <string name="last_seen_hour">последно видян преди 1 час</string> + <string name="last_seen_hours">последно видян преди %d часа</string> + <string name="last_seen_day">последно видян преди 1 ден</string> + <string name="last_seen_days">последно видян преди %d дни</string> + <string name="never_seen">не е виждан никога</string> + <string name="install_openkeychain">Шифровано съобщение. Моля, инсталирайте OpenKeychain, за да го дешифровате.</string> + <string name="unknown_otr_fingerprint">Непознат OTR отпечатък</string> + <string name="openpgp_messages_found">Открити са съобщения, шифровани чрез OpenPGP</string> + <string name="reception_failed">Неуспешно получаване</string> + <string name="your_fingerprint">Вашият отпечатък</string> + <string name="otr_fingerprint">OTR отпечатък</string> + <string name="verify">Потвърждаване</string> + <string name="decrypt">Дешифроване</string> <string name="conferences">Беседи</string> + <string name="search">Търсене</string> + <string name="create_contact">Създаване на контакт</string> <string name="join_conference">Присъединяване към беседа</string> + <string name="delete_contact">Изтриване на контакт</string> + <string name="view_contact_details">Преглед на подр. за контакта</string> <string name="block_contact">Блокиране на контакт</string> <string name="unblock_contact">Деблокиране на контакт</string> + <string name="create">Създаване</string> + <string name="contact_already_exists">Контактът вече съществува</string> + <string name="join">Присъединяване</string> <string name="conference_address">Адрес на беседата</string> <string name="conference_address_example">room@conference.example.com</string> <string name="save_as_bookmark">Запазване като отметка</string> <string name="delete_bookmark">Изтриване на отметка</string> <string name="bookmark_already_exists">Вече съществува такава отметка</string> + <string name="you">Вие</string> <string name="action_edit_subject">Редактиране на темата на беседата</string> <string name="conference_not_found">Беседата не е открита</string> + <string name="leave">Напускане</string> + <string name="contact_added_you">Контактът е добавен във Вашия списък от контакти</string> + <string name="add_back">Добавяне обратно</string> + <string name="contact_has_read_up_to_this_point">%s е прочел до тук</string> + <string name="publish">Публикуване</string> + <string name="touch_to_choose_picture">Докоснете аватара, за да изберете изображение от галерията</string> <string name="publish_avatar_explanation">Забележка: Всеки, абониран за актуализации на присъствието Ви, ще може да вижда тази снимка.</string> + <string name="publishing">Публикуване...</string> + <string name="error_publish_avatar_server_reject">Сървърът отказа Вашето публикуване</string> + <string name="error_publish_avatar_converting">Нещо се обърка при преобразуването на снимката Ви</string> + <string name="error_saving_avatar">Неуспешно запазване на аватара на диска</string> + <string name="or_long_press_for_default">(Или задръжте, за да върнете началното)</string> + <string name="error_publish_avatar_no_server_support">Сървърът Ви не поддържа публикуване на аватари</string> + <string name="private_message">прошепна</string> + <string name="private_message_to">на %s</string> + <string name="send_private_message_to">Изпращане на лично съобщение до %s</string> + <string name="connect">Свързване</string> + <string name="account_already_exists">Този профил вече съществува</string> + <string name="next">Следващо</string> + <string name="server_info_session_established">Установена е текуща сесия</string> + <string name="additional_information">Допълнителна информация</string> + <string name="skip">Пропускане</string> + <string name="disable_notifications">Изключване на известията</string> + <string name="disable_notifications_for_this_conversation">Изключване на известията за този разговор</string> + <string name="notifications_disabled">Известията са изключени</string> + <string name="enable">Включване</string> <string name="conference_requires_password">Беседата изисква парола</string> + <string name="enter_password">Въведете парола</string> <string name="missing_presence_updates">Липсват актуализации за присъствието на контакта</string> <string name="request_presence_updates">Моля, първо помолете контакта за актуализации на присъствието му.\n\n<small>Това ще бъде използвано, за да се провери какъв клиент (или клиенти) използва контакта.</small></string> + <string name="request_now">Поискване сега</string> + <string name="delete_fingerprint">Изтриване на отпечатъка</string> + <string name="sure_delete_fingerprint">Сигурни ли сте, че искате да изтриете този отпечатък?</string> + <string name="ignore">Пренебрегване</string> <string name="without_mutual_presence_updates"><b>Внимание:</b> Изпращането на това без съвместни актуализации на присъствието може да доведе до неочаквани проблеми.\n\n<small>Погледнете подробностите за контакта, за да проверите дали сте абониран за актуализации на присъствието.</small></string> <string name="pref_encryption_settings">Настройки за шифроване</string> + <string name="pref_force_encryption">Налагане на шифроване в двете посоки</string> <string name="pref_force_encryption_summary">Съобщенията да се изпращат винаги шифровани (освен в беседите)</string> <string name="pref_dont_save_encrypted">Шифрованите съобщения да не се запазват</string> + <string name="pref_dont_save_encrypted_summary">Внимание: Това може да доведе до загуба на съобщения</string> + <string name="pref_expert_options">Настройки за напреднали</string> + <string name="pref_expert_options_summary">Моля, бъдете внимателни с тези</string> + <string name="title_activity_about">Относно Conversations</string> + <string name="pref_about_conversations_summary">Информация за версията и лицензите</string> + <string name="title_pref_quiet_hours">Тихи часове</string> + <string name="title_pref_quiet_hours_start_time">Начало</string> + <string name="title_pref_quiet_hours_end_time">Край</string> + <string name="title_pref_enable_quiet_hours">Включване на тихите часове</string> + <string name="pref_quiet_hours_summary">Известията ще бъдат заглушени по време на тихите часове</string> + <string name="pref_use_larger_font">Голям размер на шрифта</string> + <string name="pref_use_larger_font_summary">Използване на по-голям размер на шрифтовете в цялото приложение</string> + <string name="pref_use_send_button_to_indicate_status">Бутонът за изпращане показва състоянието</string> + <string name="pref_use_indicate_received">Изискване на отчет за съобщенията</string> + <string name="pref_use_indicate_received_summary">Получените съобщения ще бъдат отбелязани със зелена отметка, ако това се поддържа</string> + <string name="pref_use_send_button_to_indicate_status_summary">Оцветяване на бутона за изпращане в зависимост от състоянието на контакта</string> + <string name="pref_expert_options_other">Други</string> <string name="pref_conference_name">Име на беседата</string> + <string name="pref_conference_name_summary">Използване на темата на стаята вместо JID идентификатора за беседите</string> + <string name="toast_message_otr_fingerprint">OTR отпечатъкът е копиран!</string> <string name="conference_banned">Достъпът Ви до тази беседа беше забранен</string> <string name="conference_members_only">Тази беседа е само за членове</string> <string name="conference_kicked">Бяхте изритан от тази конференция</string> + <string name="using_account">използвайки профила %s</string> + <string name="checking_image">Проверяване на изображението на HTTP сървъра</string> + <string name="image_file_deleted">Изображението е изтрито</string> + <string name="not_connected_try_again">Не сте свързани. Опитайте отново по-късно</string> + <string name="check_image_filesize">Проверка на размера на файла с изображението</string> + <string name="message_options">Настройки за съобщенята</string> + <string name="copy_text">Копиране на текста</string> + <string name="copy_original_url">Копиране на оригиналния адрес</string> + <string name="send_again">Повторно изпращане</string> + <string name="image_url">Адрес на изображението</string> + <string name="message_text">Текст на съобщението</string> + <string name="url_copied_to_clipboard">Адресът е копиран</string> + <string name="message_copied_to_clipboard">Съобщението е копирано</string> + <string name="image_transmission_failed">Неуспешно прехвърляне на изображението</string> + <string name="scan_qr_code">Сканиране на QR кода</string> + <string name="show_qr_code">Показване на QR кода</string> <string name="show_block_list">Показване на списъка с блокирани</string> + <string name="account_details">Подробности за профила</string> + <string name="verify_otr">Проверка на OTR</string> + <string name="remote_fingerprint">Отдалечен отпечатък</string> + <string name="scan">сканиране</string> + <string name="or_touch_phones">(или докоснете телефоните)</string> + <string name="smp">Протокол „Socialist Millionaire“</string> + <string name="shared_secret_hint">Подсказка или въпрос</string> + <string name="shared_secret_secret">Обща тайна</string> + <string name="confirm">Потвърждаване</string> + <string name="in_progress">В процес</string> + <string name="respond">Отговаряне</string> + <string name="failed">Неуспешно</string> + <string name="secrets_do_not_match">Тайната информация не съвпада</string> + <string name="try_again">Повторен опит</string> + <string name="finish">Край</string> + <string name="verified">Проверено!</string> + <string name="smp_requested">Контактът изиска SMP проверка</string> + <string name="no_otr_session_found">Няма открита OTR сесия!</string> + <string name="conversations_foreground_service">Conversations</string> + <string name="pref_keep_foreground_service">Услугата да е на преден план</string> + <string name="pref_keep_foreground_service_summary">Предотвратява прекъсването на връзката Ви от операционната система</string> + <string name="choose_file">Изберете файл</string> + <string name="receiving_x_file">Получаване на %1$s (%2$d%% завършено)</string> + <string name="download_x_file">Изтегляне на %s</string> + <string name="file">файл</string> + <string name="open_x_file">Отваряне на %s</string> + <string name="sending_file">изпращане (%1$d%% завършено)</string> + <string name="preparing_file">Подготовка на файла за прехвърляне</string> + <string name="x_file_offered_for_download">%s е предложен за сваляне</string> + <string name="cancel_transmission">Отказ на прехвърлянето</string> + <string name="file_transmission_failed">неуспешно прехвърляне на файл</string> + <string name="file_deleted">Файлът беше изтрит</string> + <string name="no_application_found_to_open_file">Няма намерено приложение за отваряне на файла</string> + <string name="could_not_verify_fingerprint">Неуспешна проверка на отпечатъка</string> + <string name="manually_verify">Ръчна проверка</string> + <string name="are_you_sure_verify_fingerprint">Сигурни ли сте, че искате да проверите OTR отпечатъка на контактите си?</string> + <string name="pref_show_dynamic_tags">Динамични етикети</string> + <string name="pref_show_dynamic_tags_summary">Показване на етикети, предназначени само за четене под контактите</string> + <string name="enable_notifications">Включване на известията</string> <string name="conference_with">Започване на беседа с...</string> <string name="no_conference_server_found">Не е открит сървър за беседата</string> <string name="conference_creation_failed">Неуспешно създаване на беседа!</string> <string name="conference_created">Беседата беше създадена!</string> + <string name="secret_accepted">Тайната е приета!</string> + <string name="reset">Възстановяване</string> + <string name="account_image_description">Аватар на профила</string> + <string name="copy_otr_clipboard_description">Копиране на OTR отпечатъка</string> + <string name="fetching_history_from_server">Получаване на историята от сървъра</string> + <string name="no_more_history_on_server">Няма повече история на сървъра</string> + <string name="updating">Актуализиране...</string> + <string name="password_changed">Паролата е променена!</string> + <string name="could_not_change_password">Неуспешна промяна на паролата</string> <string name="otr_session_not_started">Изпратете съобщение, за да започнете нешифрован разговор</string> + <string name="ask_question">Задаване на въпрос</string> + <string name="smp_explain_question">Ако Вие и контакта Ви имате някаква тайна информация, която никой друг не знае (като някаква шега или пък просто какво сте обядвали, когато сте се срещнали за последно), можете да я използвате, за да проверите отпечатъците си един на друг.\n\nМожете да подсигурите подсказка или въпрос, на който контакта Ви да отговори, като има предвид, че главните и малките букви се броят за различни.</string> + <string name="smp_explain_answer">Вашият контакт би искал да провери отпечатъка Ви, като Ви попита за обща тайна информация. Контактът Ви предостави следната подсказка или въпрос, който да Ви насочи към тази тайна.</string> + <string name="shared_secret_hint_should_not_be_empty">Подсказката Ви не трябва да е празна</string> + <string name="shared_secret_can_not_be_empty">Общата Ви тайна не може да е празна</string> + <string name="manual_verification_explanation">Внимателно сравнете отпечатъка по-долу с този на Вашия контакт.\nМожете да използвате всякакъв начин на сигурна комуникация, като шифрована е-поща или телефонен разговор, за да размените отпечатъците.</string> + <string name="change_password">Промяна на паролата</string> + <string name="current_password">Текуща парола</string> + <string name="new_password">Нова парола</string> + <string name="password_should_not_be_empty">Паролата не трябва да е празна</string> + <string name="enable_all_accounts">Активиране на всички профили</string> + <string name="disable_all_accounts">Деактивиране на всички профили</string> + <string name="perform_action_with">Изпълнение на действието с</string> + <string name="no_affiliation">Няма принадлежност</string> + <string name="no_role">Няма роля</string> + <string name="outcast">Отхвърлен</string> + <string name="member">Член</string> + <string name="advanced_mode">Разширен режим</string> + <string name="grant_membership">Даване на членство</string> + <string name="remove_membership">Отмяна на членството</string> + <string name="grant_admin_privileges">Даване на администраторски права</string> + <string name="remove_admin_privileges">Отмяна на администраторските права</string> <string name="remove_from_room">Премахване от беседата</string> + <string name="could_not_change_affiliation">Неуспешна промяна на принадлежността на %s</string> <string name="ban_from_conference">Забраняване на достъпа до беседата</string> <string name="removing_from_public_conference">Вие се опитвате да премахнете %s от публична беседа. Единственият начин да направите това, е да забраните достъпа на този потребител завинаги.</string> <string name="ban_now">Забраняване на достъпа сега</string> @@ -144,9 +402,29 @@ <string name="pref_input_options">Настройки за въвеждане</string> <string name="pref_enter_is_send">Enter изпраща</string> <string name="pref_enter_is_send_summary">Натискането на клавиша Enter изпраща съобщението</string> + <string name="pref_display_enter_key">Показване на клавиша Enter</string> + <string name="pref_display_enter_key_summary">Смяна на клавиша за емотикони с клавиша Enter</string> <string name="audio">аудио</string> <string name="video">видео</string> <string name="image">изображение</string> <string name="pdf_document">PDF документ</string> <string name="apk">Приложение за Андроид</string> + <string name="vcard">Контакт</string> + <string name="received_x_file">Получи %s</string> + <string name="disable_foreground_service">Изключване на услугата на преден план</string> + <string name="touch_to_open_conversations">Докоснете, за да отворите Conversations</string> + <string name="avatar_has_been_published">Аватарът беше публикуван!</string> + <string name="sending_x_file">Изпращане на %s</string> + <string name="offering_x_file">Предлагане на %s</string> + <string name="hide_offline">Скриване на тези извън линия</string> + <string name="disable_account">Деактивиране на профила</string> + <string name="contact_is_typing">%s пише...</string> + <string name="contact_has_stopped_typing">%s спря да пише</string> + <string name="pref_chat_states">Известия за писането</string> + <string name="pref_chat_states_summary">Позволяване на контакта Ви да вижда, когато пишете ново съобщение</string> + <string name="send_location">Изпращане на местоположението</string> + <string name="show_location">Показване на местоположението</string> + <string name="no_application_found_to_display_location">Няма намерено приложение за показване на местоположението</string> + <string name="location">Местоположение</string> + <string name="received_location">Получено местоположение</string> </resources> diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index 84c7437b..55311aee 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -422,4 +422,9 @@ <string name="contact_has_stopped_typing">%s přestal(a) psát</string> <string name="pref_chat_states">Upozornění při psaní</string> <string name="pref_chat_states_summary">Oznamovat kontaktům že píšete novou zprávu</string> + <string name="send_location">Poslat pozici</string> + <string name="show_location">Zobrazit pozici</string> + <string name="no_application_found_to_display_location">Nebyla nalezena aplikace pro zobrazení pozice</string> + <string name="location">Pozice</string> + <string name="received_location">Přijmout pozici</string> </resources> diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index d266a99d..2e2f4fe7 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -422,4 +422,9 @@ <string name="contact_has_stopped_typing">%s schreibt nicht mehr</string> <string name="pref_chat_states">Tipp-Benachrichtigung</string> <string name="pref_chat_states_summary">Informiere deine Kontakte, wenn du eine Nachricht eintippst.</string> + <string name="send_location">Standort senden</string> + <string name="show_location">Standort anzeigen</string> + <string name="no_application_found_to_display_location">Keine App für die Standort-Anzeige gefunden</string> + <string name="location">Standort</string> + <string name="received_location">Standort empfangen</string> </resources> diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml index 06ab989e..48dc4034 100644 --- a/src/main/res/values-el/strings.xml +++ b/src/main/res/values-el/strings.xml @@ -422,4 +422,9 @@ <string name="contact_has_stopped_typing">Ο χρήστης %s σταμάτησε να γράφει</string> <string name="pref_chat_states">Ειδοποιήσεις πληκτρολόγησης</string> <string name="pref_chat_states_summary">Επιτρέψτε στην επαφή σας να γνωρίζει πότε γράφετε ένα νέο μήνυμα</string> + <string name="send_location">Αποστολή τοποθεσίας</string> + <string name="show_location">Εμφάνιση τοποθεσίας</string> + <string name="no_application_found_to_display_location">Δεν βρέθηκε εφαρμογή για την απεικόνιση τοποθεσίας</string> + <string name="location">Τοποθεσία</string> + <string name="received_location">Ελήφθη τοποθεσία</string> </resources> diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 2f74fd7a..639eddfa 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -422,4 +422,9 @@ <string name="contact_has_stopped_typing">%s ha dejado de escribir</string> <string name="pref_chat_states">Notificación de escritura</string> <string name="pref_chat_states_summary">Permite a tus contactos saber cuando estás escribiendo un nuevo mensaje</string> + <string name="send_location">Enviar ubicación</string> + <string name="show_location">Mostrar ubicación</string> + <string name="no_application_found_to_display_location">No se ha encontrado ninguna aplicación para mostrar la ubicación</string> + <string name="location">Ubicación</string> + <string name="received_location">Ubicación recibida</string> </resources> diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml index 2f19afd0..a7a5b871 100644 --- a/src/main/res/values-eu/strings.xml +++ b/src/main/res/values-eu/strings.xml @@ -419,7 +419,7 @@ <string name="hide_offline">Lineaz kanpokoak ezkutatu</string> <string name="disable_account">Kontua ezgaitu</string> <string name="contact_is_typing">%s idazten ari da...</string> - <string name="contact_has_stopped_typing">%s idazteari utzi dio</string> + <string name="contact_has_stopped_typing">%s(e)k idazteari utzi dio</string> <string name="pref_chat_states">Idazketa jakinarazpenak</string> <string name="pref_chat_states_summary">Zure kontaktuak mezu berri bat noiz idazten ari zaren jakin dezan baimendu</string> </resources> diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index dc3ae4a6..69440362 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -325,7 +325,7 @@ <string name="no_otr_session_found">Aucune session valide d\'OTR n\'a été trouvée!</string> <string name="conversations_foreground_service">Conversations</string> <string name="pref_keep_foreground_service">Garder le service au premier-plan</string> - <string name="pref_keep_foreground_service_summary">Evite que le système ferme votre connexion</string> + <string name="pref_keep_foreground_service_summary">Évite que le système ferme votre connexion</string> <string name="choose_file">Choix d\'un fichier</string> <string name="receiving_x_file">Réception %1$s (%2$d%% complété)</string> <string name="download_x_file">Télecharger %s</string> @@ -400,11 +400,31 @@ <string name="eight_hours">8 heures</string> <string name="until_further_notice">Jusqu\'à nouvel ordre</string> <string name="pref_input_options">Options de saisie</string> + <string name="pref_enter_is_send">Entrée permet d\'envoyer</string> + <string name="pref_enter_is_send_summary">Utiliser la touche Entrée pour envoyer un message</string> + <string name="pref_display_enter_key">Afficher la touche Entrée</string> + <string name="pref_display_enter_key_summary">Remplacer le bouton Émoticônes par un bouton Entrée</string> <string name="audio">audio</string> <string name="video">video</string> <string name="image">image</string> <string name="pdf_document">document PDF</string> + <string name="apk">Application Android</string> <string name="vcard">Contact</string> <string name="received_x_file">%s reçu</string> + <string name="disable_foreground_service">Cesser de garder le service au premier plan</string> + <string name="touch_to_open_conversations">Cliquez pour ouvrir Conversations</string> + <string name="avatar_has_been_published">L\'avatar a été envoyé !</string> + <string name="sending_x_file">Envoi de %s</string> + <string name="offering_x_file">Proposition pour %s</string> + <string name="hide_offline">Cacher hors-ligne</string> <string name="disable_account">Désactiver le compte</string> + <string name="contact_is_typing">%s écrit un message...</string> + <string name="contact_has_stopped_typing">%s a arrêté d\'écrire</string> + <string name="pref_chat_states">Notifications d\'écriture</string> + <string name="pref_chat_states_summary">Permettre à votre contact de savoir que vous écrivez un message</string> + <string name="send_location">Envoyer la position</string> + <string name="show_location">Afficher la position</string> + <string name="no_application_found_to_display_location">Aucune application trouvée pour afficher la position</string> + <string name="location">Position</string> + <string name="received_location">Position reçue</string> </resources> diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index ccb14613..7d6f31e5 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -422,4 +422,9 @@ <string name="contact_has_stopped_typing">%s is gestopt met typen</string> <string name="pref_chat_states">Type-meldingen</string> <string name="pref_chat_states_summary">Laat je contacten weten wanneer je een nieuw bericht aan het schrijven bent</string> + <string name="send_location">Locatie versturen</string> + <string name="show_location">Locatie weergeven</string> + <string name="no_application_found_to_display_location">Geen applicatie gevonden om locatie weer te geven</string> + <string name="location">Locatie</string> + <string name="received_location">Locatie ontvangen</string> </resources> diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml index aef34aef..479889b7 100644 --- a/src/main/res/values-sr/strings.xml +++ b/src/main/res/values-sr/strings.xml @@ -418,4 +418,13 @@ <string name="offering_x_file">Нудим %s</string> <string name="hide_offline">Сакриј неповезане</string> <string name="disable_account">Онемогући налог</string> + <string name="contact_is_typing">%s куца...</string> + <string name="contact_has_stopped_typing">%s престаде да куца</string> + <string name="pref_chat_states">Обавештења о куцању</string> + <string name="pref_chat_states_summary">Обзнаните контакту кад куцате нову поруку</string> + <string name="send_location">Пошаљи локацију</string> + <string name="show_location">Прикажи локацију</string> + <string name="no_application_found_to_display_location">Нема апликације за приказ локације</string> + <string name="location">Локација</string> + <string name="received_location">Примљена локација</string> </resources> diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml index f894bdc7..03485920 100644 --- a/src/main/res/values-sv/strings.xml +++ b/src/main/res/values-sv/strings.xml @@ -247,7 +247,7 @@ <string name="next">Nästa</string> <string name="server_info_session_established">Nuvarande session upprättad</string> <string name="additional_information">Ytterligare information</string> - <string name="skip">skippa</string> + <string name="skip">Hoppa över</string> <string name="disable_notifications">Inaktivera notifieringar</string> <string name="disable_notifications_for_this_conversation">Inaktivera notifieringar för denna konversation</string> <string name="notifications_disabled">Notifieringar är inaktiverade</string> @@ -264,7 +264,7 @@ <string name="pref_encryption_settings">Krypteringsinställningar</string> <string name="pref_force_encryption">Tvinga kryptering</string> <string name="pref_force_encryption_summary">Sänd alltid krypterade meddelanden (utom för konferenser)</string> - <string name="pref_dont_save_encrypted">Spara in krypterade meddelanden</string> + <string name="pref_dont_save_encrypted">Spara inte krypterade meddelanden</string> <string name="pref_dont_save_encrypted_summary">Varning: Detta kan leda till att meddelanden förloras</string> <string name="pref_expert_options">Expertinställningar</string> <string name="pref_expert_options_summary">Var försiktig med dem</string> @@ -411,15 +411,20 @@ <string name="apk">Android App</string> <string name="vcard">Kontakt</string> <string name="received_x_file">Tagit emot %s</string> - <string name="disable_foreground_service">Deaktivera fögrundstjänst</string> + <string name="disable_foreground_service">Deaktivera förgrundstjänst</string> <string name="touch_to_open_conversations">Tryck för att öppna Conversations</string> <string name="avatar_has_been_published">Avatarbild har publicerats!</string> <string name="sending_x_file">Skickar %s</string> <string name="offering_x_file">Erbjuder %s</string> <string name="hide_offline">Dölj ej anslutna</string> <string name="disable_account">Deaktivera konton</string> - <string name="contact_is_typing">%s är att skriva...</string> + <string name="contact_is_typing">%s skriver...</string> <string name="contact_has_stopped_typing">%s har slutat skriva</string> <string name="pref_chat_states">Skriv-notifieringar</string> - <string name="pref_chat_states_summary">Låter dina kontakter veta när du är att skriva ett nytt meddelande</string> + <string name="pref_chat_states_summary">Låter dina kontakter veta när du skriver ett nytt meddelande</string> + <string name="send_location">Skicka position</string> + <string name="show_location">Visa position</string> + <string name="no_application_found_to_display_location">Kunde inte hitta applikation för att visa position</string> + <string name="location">Position</string> + <string name="received_location">Mottog position</string> </resources> diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index a17859fc..8ebe58ca 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -449,4 +449,9 @@ <string name="contact_has_stopped_typing">%s has stopped typing</string> <string name="pref_chat_states">Typing notifications</string> <string name="pref_chat_states_summary">Let your contact know when you are writing a new message</string> + <string name="send_location">Send location</string> + <string name="show_location">Show location</string> + <string name="no_application_found_to_display_location">No application found to display location</string> + <string name="location">Location</string> + <string name="received_location">Received location</string> </resources> diff --git a/todo.md b/todo.md new file mode 100644 index 00000000..bace5987 --- /dev/null +++ b/todo.md @@ -0,0 +1,23 @@ +##GSOC teaser tasks + +####update Contacts last seen for muc messages as well +The contact class (entities/Contact) has the ability to save the last time that Conversations + received a message from that contact. Currently this time only gets updated for one-on-one + messages. In non-anonymous mucs messages from a contact should also update the last seen + time. + +####Select multiple Contact in Choose Contact Activity +Currently the choose Contact activity allows only for one contact to be selected. A long +press on one contact should bring the activity in a mode where the user can select multiple +contacts. +The Activity should then return an array of contacts instead of just one + +####Request and respond to message receipts in MUC PNs +Private MUC messages either dont request message receipts or dont respond to them. The source +of error should be determined and eliminated. A rather small tasks that just teaches you a bit +about the stanza parser and generator in Conversations + +####Edit dynamic tags / groups +The context menu for the contact list (StartConversationActivity) should offer the ability to +edit groups. (Any UI decissions are left to you) Quick suggestion though: Dialog with +checkboxes for existing groups and some way to enter new tags. |