aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build.gradle1
-rw-r--r--src/main/AndroidManifest.xml7
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/OtrEngine.java38
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Account.java14
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Message.java28
-rw-r--r--src/main/java/eu/siacs/conversations/generator/MessageGenerator.java4
-rw-r--r--src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java7
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java6
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java213
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java1
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java14
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java8
-rw-r--r--src/main/java/eu/siacs/conversations/ui/SettingsActivity.java12
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java54
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java8
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java46
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java15
-rw-r--r--src/main/java/eu/siacs/conversations/utils/GeoHelper.java2
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java4
-rw-r--r--src/main/res/layout-w960dp/fragment_conversations_overview.xml2
-rw-r--r--src/main/res/layout/account_row.xml13
-rw-r--r--src/main/res/layout/conversation_list_row.xml138
-rw-r--r--src/main/res/layout/fragment_conversations_overview.xml2
-rw-r--r--src/main/res/values-de/strings.xml14
-rw-r--r--src/main/res/values-es/strings.xml4
-rw-r--r--src/main/res/values-eu/strings.xml4
-rw-r--r--src/main/res/values-fr/strings.xml4
-rw-r--r--src/main/res/values-ja/strings.xml433
-rw-r--r--src/main/res/values-sk/strings.xml5
-rw-r--r--src/main/res/values-sr/strings.xml9
-rw-r--r--src/main/res/values-sv/strings.xml14
-rw-r--r--src/main/res/values-v21/dimens.xml4
-rw-r--r--src/main/res/values/strings.xml7
33 files changed, 917 insertions, 218 deletions
diff --git a/build.gradle b/build.gradle
index 8f7bb914..cdbb5a98 100644
--- a/build.gradle
+++ b/build.gradle
@@ -34,6 +34,7 @@ dependencies {
compile 'com.google.zxing:core:3.1.0'
compile 'com.google.zxing:android-integration:3.1.0'
compile 'de.measite.minidns:minidns:0.1.3'
+ compile 'de.timroes.android:EnhancedListView:0.3.4'
}
android {
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index e4e91d80..9fe37017 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -122,6 +122,13 @@
<data android:mimeType="*/*" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.SEND_MULTIPLE" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+
+ <data android:mimeType="image/*" />
+ </intent-filter>
</activity>
<activity
android:name="de.duenndns.ssl.MemorizingActivity"
diff --git a/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java b/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java
index 20427d7b..263f6089 100644
--- a/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java
+++ b/src/main/java/eu/siacs/conversations/crypto/OtrEngine.java
@@ -202,20 +202,7 @@ public class OtrEngine extends OtrCryptoEngineImpl implements OtrEngineHost {
@Override
public void messageFromAnotherInstanceReceived(SessionID session) {
- try {
- Jid jid = Jid.fromSessionID(session);
- Conversation conversation = mXmppConnectionService.find(account, jid);
- String id = conversation == null ? null : conversation.getLastReceivedOtrMessageId();
- if (id != null) {
- MessagePacket packet = mXmppConnectionService.getMessageGenerator().generateOtrError(jid,id);
- packet.setFrom(account.getJid());
- mXmppConnectionService.sendMessagePacket(account,packet);
- Log.d(Config.LOGTAG,packet.toString());
- Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": unreadable OTR message in "+conversation.getName());
- }
- } catch (InvalidJidException e) {
- return;
- }
+ sendOtrErrorMessage(session, "Message from another OTR-instance received");
}
@Override
@@ -267,9 +254,28 @@ public class OtrEngine extends OtrCryptoEngineImpl implements OtrEngineHost {
}
@Override
- public void unreadableMessageReceived(SessionID arg0) throws OtrException {
+ public void unreadableMessageReceived(SessionID session) throws OtrException {
Log.d(Config.LOGTAG,"unreadable message received");
- throw new OtrException(new Exception("unreadable message received"));
+ sendOtrErrorMessage(session, "You sent me an unreadable OTR-encrypted message");
+ }
+
+ public void sendOtrErrorMessage(SessionID session, String errorText) {
+ try {
+ Jid jid = Jid.fromSessionID(session);
+ Conversation conversation = mXmppConnectionService.find(account, jid);
+ String id = conversation == null ? null : conversation.getLastReceivedOtrMessageId();
+ if (id != null) {
+ MessagePacket packet = mXmppConnectionService.getMessageGenerator()
+ .generateOtrError(jid, id, errorText);
+ packet.setFrom(account.getJid());
+ mXmppConnectionService.sendMessagePacket(account,packet);
+ Log.d(Config.LOGTAG,packet.toString());
+ Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()
+ +": unreadable OTR message in "+conversation.getName());
+ }
+ } catch (InvalidJidException e) {
+ return;
+ }
}
@Override
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java
index 2bc2c954..fe103094 100644
--- a/src/main/java/eu/siacs/conversations/entities/Account.java
+++ b/src/main/java/eu/siacs/conversations/entities/Account.java
@@ -229,11 +229,17 @@ public class Account extends AbstractEntity {
return jid.getResourcepart();
}
- public void setResource(final String resource) {
- try {
- jid = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), resource);
- } catch (final InvalidJidException ignored) {
+ public boolean setResource(final String resource) {
+ final String oldResource = jid.getResourcepart();
+ if (oldResource == null || !oldResource.equals(resource)) {
+ try {
+ jid = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), resource);
+ return true;
+ } catch (final InvalidJidException ignored) {
+ return true;
+ }
}
+ return false;
}
public Jid getJid() {
diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java
index 8015eead..7ea3d60b 100644
--- a/src/main/java/eu/siacs/conversations/entities/Message.java
+++ b/src/main/java/eu/siacs/conversations/entities/Message.java
@@ -430,23 +430,31 @@ public class Message extends AbstractEntity {
}
public boolean bodyContainsDownloadable() {
+ /**
+ * there are a few cases where spaces result in an unwanted behavior, e.g.
+ * "http://example.com/image.jpg text that will not be shown /abc.png"
+ * or more than one image link in one message.
+ */
+ if (body.contains(" ")) {
+ return false;
+ }
try {
- URL url = new URL(this.getBody());
+ URL url = new URL(body);
if (!url.getProtocol().equalsIgnoreCase("http")
&& !url.getProtocol().equalsIgnoreCase("https")) {
return false;
}
- if (url.getPath() == null) {
- return false;
- }
- String[] pathParts = url.getPath().split("/");
- String filename;
- if (pathParts.length > 0) {
- filename = pathParts[pathParts.length - 1].toLowerCase();
- } else {
+
+ String sUrlPath = url.getPath();
+ if (sUrlPath == null || sUrlPath.isEmpty()) {
return false;
}
- String[] extensionParts = filename.split("\\.");
+
+ int iSlashIndex = sUrlPath.lastIndexOf('/') + 1;
+
+ String sLastUrlPath = sUrlPath.substring(iSlashIndex).toLowerCase();
+
+ String[] extensionParts = sLastUrlPath.split("\\.");
if (extensionParts.length == 2
&& Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains(
extensionParts[extensionParts.length - 1])) {
diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
index 8f6a90b9..a60c5613 100644
--- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
@@ -172,7 +172,7 @@ public class MessageGenerator extends AbstractGenerator {
return receivedPacket;
}
- public MessagePacket generateOtrError(Jid to, String id) {
+ public MessagePacket generateOtrError(Jid to, String id, String errorText) {
MessagePacket packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_ERROR);
packet.setAttribute("id",id);
@@ -181,7 +181,7 @@ public class MessageGenerator extends AbstractGenerator {
error.setAttribute("code","406");
error.setAttribute("type","modify");
error.addChild("not-acceptable","urn:ietf:params:xml:ns:xmpp-stanzas");
- error.addChild("text").setContent("unreadable OTR message received");
+ error.addChild("text").setContent("?OTR Error:" + errorText);
return packet;
}
}
diff --git a/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java b/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java
index 1e896724..526005f3 100644
--- a/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/PresenceGenerator.java
@@ -54,4 +54,11 @@ public class PresenceGenerator extends AbstractGenerator {
}
return packet;
}
+
+ public PresencePacket sendOfflinePresence(Account account) {
+ PresencePacket packet = new PresencePacket();
+ packet.setFrom(account.getJid());
+ packet.setAttribute("type","unavailable");
+ return packet;
+ }
} \ No newline at end of file
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index f94e715e..3e8ce65f 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -1127,6 +1127,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public void archiveConversation(Conversation conversation) {
+ getNotificationService().clear(conversation);
conversation.setStatus(Conversation.STATUS_ARCHIVED);
conversation.setNextEncryption(-1);
synchronized (this.conversations) {
@@ -1698,6 +1699,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
}
+ sendOfflinePresence(account);
}
account.getXmppConnection().disconnect(force);
}
@@ -2273,6 +2275,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
}
+ public void sendOfflinePresence(final Account account) {
+ sendPresencePacket(account, mPresenceGenerator.sendOfflinePresence(account));
+ }
+
public MessageGenerator getMessageGenerator() {
return this.mMessageGenerator;
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index 82afda07..c8a1e6df 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -5,6 +5,7 @@ import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.FragmentTransaction;
import android.app.PendingIntent;
+import android.content.ClipData;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
@@ -22,14 +23,15 @@ import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
-import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.Toast;
import net.java.otr4j.session.SessionStatus;
+import de.timroes.android.listview.EnhancedListView;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import eu.siacs.conversations.R;
@@ -69,15 +71,16 @@ public class ConversationActivity extends XmppActivity
private String mOpenConverstaion = null;
private boolean mPanelOpen = true;
- private Uri mPendingImageUri = null;
- private Uri mPendingFileUri = null;
+ final private List<Uri> mPendingImageUris = new ArrayList<>();
+ final private List<Uri> mPendingFileUris = new ArrayList<>();
private Uri mPendingGeoUri = null;
private View mContentView;
private List<Conversation> conversationList = new ArrayList<>();
+ private Conversation swipedConversation = null;
private Conversation mSelectedConversation = null;
- private ListView listView;
+ private EnhancedListView listView;
private ConversationFragment mConversationFragment;
private ArrayAdapter<Conversation> listAdapter;
@@ -140,13 +143,14 @@ public class ConversationActivity extends XmppActivity
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (savedInstanceState != null) {mOpenConverstaion = savedInstanceState.getString(
- STATE_OPEN_CONVERSATION, null);
- mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
- String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
- if (pending != null) {
- mPendingImageUri = Uri.parse(pending);
- }
+ if (savedInstanceState != null) {
+ mOpenConverstaion = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null);
+ mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
+ String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
+ if (pending != null) {
+ mPendingImageUris.clear();
+ mPendingImageUris.add(Uri.parse(pending));
+ }
}
setContentView(R.layout.fragment_conversations_overview);
@@ -156,7 +160,7 @@ public class ConversationActivity extends XmppActivity
transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation");
transaction.commit();
- listView = (ListView) findViewById(R.id.list);
+ listView = (EnhancedListView) findViewById(R.id.list);
this.listAdapter = new ConversationAdapter(this, conversationList);
listView.setAdapter(this.listAdapter);
@@ -178,6 +182,73 @@ public class ConversationActivity extends XmppActivity
openConversation();
}
});
+
+ listView.setDismissCallback(new EnhancedListView.OnDismissCallback() {
+
+ @Override
+ public EnhancedListView.Undoable onDismiss(final EnhancedListView enhancedListView, final int position) {
+
+ final int index = listView.getFirstVisiblePosition();
+ View v = listView.getChildAt(0);
+ final int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop());
+
+ swipedConversation = listAdapter.getItem(position);
+ listAdapter.remove(swipedConversation);
+ swipedConversation.markRead();
+ xmppConnectionService.getNotificationService().clear(swipedConversation);
+
+ final boolean formerlySelected = (getSelectedConversation() == swipedConversation);
+ if (position == 0 && listAdapter.getCount() == 0) {
+ endConversation(swipedConversation, false, true);
+ return null;
+ } else if (formerlySelected) {
+ setSelectedConversation(listAdapter.getItem(0));
+ ConversationActivity.this.mConversationFragment
+ .reInit(getSelectedConversation());
+ }
+
+ return new EnhancedListView.Undoable() {
+
+ @Override
+ public void undo() {
+ listAdapter.insert(swipedConversation, position);
+ if (formerlySelected) {
+ setSelectedConversation(swipedConversation);
+ ConversationActivity.this.mConversationFragment
+ .reInit(getSelectedConversation());
+ }
+ swipedConversation = null;
+ listView.setSelectionFromTop(index + (listView.getChildCount() < position ? 1 : 0), top);
+ }
+
+ @Override
+ public void discard() {
+ if (!swipedConversation.isRead()
+ && swipedConversation.getMode() == Conversation.MODE_SINGLE) {
+ swipedConversation = null;
+ return;
+ }
+ endConversation(swipedConversation, false, false);
+ swipedConversation = null;
+ }
+
+ @Override
+ public String getTitle() {
+ if (swipedConversation.getMode() == Conversation.MODE_MULTI) {
+ return getResources().getString(R.string.title_undo_swipe_out_muc);
+ } else {
+ return getResources().getString(R.string.title_undo_swipe_out_conversation);
+ }
+ }
+ };
+ }
+ });
+ listView.enableSwipeToDismiss();
+ listView.setSwipingLayout(R.id.swipeable_item);
+ listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
+ listView.setUndoHideDelay(3000);
+ listView.setRequireTouchBeforeDismiss(false);
+
mContentView = findViewById(R.id.content_view_spl);
if (mContentView == null) {
mContentView = findViewById(R.id.content_view_ll);
@@ -204,6 +275,7 @@ public class ConversationActivity extends XmppActivity
@Override
public void onPanelClosed(View arg0) {
+ listView.discardUndo();
openConversation();
}
@@ -340,13 +412,18 @@ public class ConversationActivity extends XmppActivity
switch (attachmentChoice) {
case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
intent.setAction(Intent.ACTION_GET_CONTENT);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);
+ }
intent.setType("image/*");
chooser = true;
break;
case ATTACHMENT_CHOICE_TAKE_PHOTO:
- mPendingImageUri = xmppConnectionService.getFileBackend().getTakePhotoUri();
+ Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
- intent.putExtra(MediaStore.EXTRA_OUTPUT, mPendingImageUri);
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
+ mPendingImageUris.clear();
+ mPendingImageUris.add(uri);
break;
case ATTACHMENT_CHOICE_CHOOSE_FILE:
chooser = true;
@@ -485,13 +562,21 @@ public class ConversationActivity extends XmppActivity
}
public void endConversation(Conversation conversation) {
- showConversationsOverview();
+ endConversation(conversation, true, true);
+ }
+
+ public void endConversation(Conversation conversation, boolean showOverview, boolean reinit) {
+ if (showOverview) {
+ showConversationsOverview();
+ }
xmppConnectionService.archiveConversation(conversation);
- if (conversationList.size() > 0) {
- setSelectedConversation(conversationList.get(0));
- this.mConversationFragment.reInit(getSelectedConversation());
- } else {
- setSelectedConversation(null);
+ if (reinit) {
+ if (conversationList.size() > 0) {
+ setSelectedConversation(conversationList.get(0));
+ this.mConversationFragment.reInit(getSelectedConversation());
+ } else {
+ setSelectedConversation(null);
+ }
}
}
@@ -744,6 +829,7 @@ public class ConversationActivity extends XmppActivity
@Override
public void onPause() {
+ listView.discardUndo();
super.onPause();
this.mActivityPaused = true;
if (this.xmppConnectionServiceBound) {
@@ -779,8 +865,8 @@ public class ConversationActivity extends XmppActivity
}
savedInstanceState.putBoolean(STATE_PANEL_OPEN,
isConversationsOverviewVisable());
- if (this.mPendingImageUri != null) {
- savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUri.toString());
+ if (this.mPendingImageUris.size() >= 1) {
+ savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUris.get(0).toString());
}
super.onSaveInstanceState(savedInstanceState);
}
@@ -819,21 +905,23 @@ public class ConversationActivity extends XmppActivity
this.mConversationFragment.reInit(getSelectedConversation());
} else {
showConversationsOverview();
- mPendingImageUri = null;
- mPendingFileUri = null;
+ mPendingImageUris.clear();
+ mPendingFileUris.clear();
mPendingGeoUri = null;
setSelectedConversation(conversationList.get(0));
this.mConversationFragment.reInit(getSelectedConversation());
}
- if (mPendingImageUri != null) {
- attachImageToConversation(getSelectedConversation(),mPendingImageUri);
- mPendingImageUri = null;
- } else if (mPendingFileUri != null) {
- attachFileToConversation(getSelectedConversation(),mPendingFileUri);
- mPendingFileUri = null;
- } else if (mPendingGeoUri != null) {
- attachLocationToConversation(getSelectedConversation(),mPendingGeoUri);
+ for(Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
+ attachImageToConversation(getSelectedConversation(),i.next());
+ }
+
+ for(Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
+ attachFileToConversation(getSelectedConversation(),i.next());
+ }
+
+ if (mPendingGeoUri != null) {
+ attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
mPendingGeoUri = null;
}
ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
@@ -885,6 +973,21 @@ public class ConversationActivity extends XmppActivity
xmppConnectionService.getNotificationService().setOpenConversation(null);
}
+ @SuppressLint("NewApi")
+ private static List<Uri> extractUriFromIntent(final Intent intent) {
+ List<Uri> uris = new ArrayList<>();
+ Uri uri = intent.getData();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && uri == null) {
+ ClipData clipData = intent.getClipData();
+ for(int i = 0; i < clipData.getItemCount(); ++i) {
+ uris.add(clipData.getItemAt(i).getUri());
+ }
+ } else {
+ uris.add(uri);
+ }
+ return uris;
+ }
+
@Override
protected void onActivityResult(int requestCode, int resultCode,
final Intent data) {
@@ -894,25 +997,34 @@ public class ConversationActivity extends XmppActivity
mConversationFragment.hideSnackbar();
mConversationFragment.updateMessages();
} else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
- mPendingImageUri = data.getData();
+ mPendingImageUris.clear();
+ mPendingImageUris.addAll(extractUriFromIntent(data));
if (xmppConnectionServiceBound) {
- attachImageToConversation(getSelectedConversation(),mPendingImageUri);
- mPendingImageUri = null;
+ for(Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
+ attachImageToConversation(getSelectedConversation(),i.next());
+ }
}
} else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_FILE || requestCode == ATTACHMENT_CHOICE_RECORD_VOICE) {
- mPendingFileUri = data.getData();
+ mPendingFileUris.clear();
+ mPendingFileUris.addAll(extractUriFromIntent(data));
if (xmppConnectionServiceBound) {
- attachFileToConversation(getSelectedConversation(),mPendingFileUri);
- mPendingFileUri = null;
+ for(Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
+ attachFileToConversation(getSelectedConversation(), i.next());
+ }
}
- } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO && mPendingImageUri != null) {
- if (xmppConnectionServiceBound) {
- attachImageToConversation(getSelectedConversation(),mPendingImageUri);
- mPendingImageUri = null;
+ } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
+ if (mPendingImageUris.size() == 1) {
+ Uri uri = mPendingImageUris.get(0);
+ if (xmppConnectionServiceBound) {
+ attachImageToConversation(getSelectedConversation(), uri);
+ mPendingImageUris.clear();
+ }
+ Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ intent.setData(uri);
+ sendBroadcast(intent);
+ } else {
+ mPendingImageUris.clear();
}
- 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);
@@ -922,10 +1034,6 @@ public class ConversationActivity extends XmppActivity
this.mPendingGeoUri = null;
}
}
- } else {
- if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
- mPendingImageUri = null;
- }
}
}
@@ -1013,6 +1121,13 @@ public class ConversationActivity extends XmppActivity
public void updateConversationList() {
xmppConnectionService
.populateWithOrderedConversations(conversationList);
+ if (swipedConversation != null) {
+ if (swipedConversation.isRead()) {
+ conversationList.remove(swipedConversation);
+ } else {
+ listView.discardUndo();
+ }
+ }
listAdapter.notifyDataSetChanged();
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index d5f20e41..a3a02b27 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -268,7 +268,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (conversation.getNextCounterpart() != null) {
message.setCounterpart(conversation.getNextCounterpart());
message.setType(Message.TYPE_PRIVATE);
- conversation.setNextCounterpart(null);
}
}
if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_OTR) {
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index 27dfc492..dbad9e00 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -67,7 +67,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
@Override
public void onClick(final View v) {
- if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED) {
+ if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !accountInfoEdited()) {
mAccount.setOption(Account.OPTION_DISABLED, false);
xmppConnectionService.updateAccount(mAccount);
return;
@@ -237,7 +237,11 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
}
protected void updateSaveButton() {
- if (mAccount != null && (mAccount.getStatus() == Account.State.CONNECTING || mFetchingAvatar)) {
+ if (accountInfoEdited() && jidToEdit != null) {
+ this.mSaveButton.setText(R.string.save);
+ this.mSaveButton.setEnabled(true);
+ this.mSaveButton.setTextColor(getPrimaryTextColor());
+ } else if (mAccount != null && (mAccount.getStatus() == Account.State.CONNECTING || mFetchingAvatar)) {
this.mSaveButton.setEnabled(false);
this.mSaveButton.setTextColor(getSecondaryTextColor());
this.mSaveButton.setText(R.string.account_status_connecting);
@@ -265,9 +269,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
}
protected boolean accountInfoEdited() {
- return (!this.mAccount.getJid().toBareJid().toString().equals(
- this.mAccountJid.getText().toString()))
- || (!this.mAccount.getPassword().equals(
+ return this.mAccount != null && (!this.mAccount.getJid().toBareJid().toString().equals(
+ this.mAccountJid.getText().toString())
+ || !this.mAccount.getPassword().equals(
this.mPassword.getText().toString()));
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java
index b2d5ddfd..56dbc55e 100644
--- a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java
@@ -168,6 +168,14 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
}
}
+ public void onClickTglAccountState(Account account, boolean enable) {
+ if (enable) {
+ enableAccount(account);
+ } else {
+ disableAccount(account);
+ }
+ }
+
private void publishAvatar(Account account) {
Intent intent = new Intent(getApplicationContext(),
PublishProfilePictureActivity.class);
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
index 1bc59b13..d24cb52b 100644
--- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
@@ -5,6 +5,7 @@ import java.util.Arrays;
import java.util.Locale;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.xmpp.XmppConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
@@ -63,9 +64,14 @@ public class SettingsActivity extends XmppActivity implements
.toLowerCase(Locale.US);
if (xmppConnectionServiceBound) {
for (Account account : xmppConnectionService.getAccounts()) {
- account.setResource(resource);
- if (!account.isOptionSet(Account.OPTION_DISABLED)) {
- xmppConnectionService.reconnectAccountInBackground(account);
+ if (account.setResource(resource)) {
+ if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+ XmppConnection connection = account.getXmppConnection();
+ if (connection != null) {
+ connection.resetStreamId();
+ }
+ xmppConnectionService.reconnectAccountInBackground(account);
+ }
}
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
index 6be238dc..200a577e 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
@@ -18,6 +18,7 @@ import java.net.URLConnection;
import java.net.URLDecoder;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import eu.siacs.conversations.Config;
@@ -32,7 +33,7 @@ import eu.siacs.conversations.xmpp.jid.Jid;
public class ShareWithActivity extends XmppActivity {
private class Share {
- public Uri uri;
+ public List<Uri> uris = new ArrayList<>();
public boolean image;
public String account;
public String contact;
@@ -104,7 +105,7 @@ public class ShareWithActivity extends XmppActivity {
int position, long arg3) {
Conversation conversation = mConversations.get(position);
if (conversation.getMode() == Conversation.MODE_SINGLE
- || share.uri == null) {
+ || share.uris.size() == 0) {
share(mConversations.get(position));
}
}
@@ -133,18 +134,32 @@ public class ShareWithActivity extends XmppActivity {
@Override
public void onStart() {
- final String type = getIntent().getType();
- final Uri uri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
- if (type != null && uri != null && !type.equalsIgnoreCase("text/plain")) {
- this.share.uri = uri;
- this.share.image = type.startsWith("image/") || isImage(uri);
- } else {
- this.share.text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
+ super.onStart();
+ Intent intent = getIntent();
+ if (intent == null) {
+ return;
+ }
+ final String type = intent.getType();
+ if (Intent.ACTION_SEND.equals(intent.getAction())) {
+ final Uri uri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
+ if (type != null && uri != null && !type.equalsIgnoreCase("text/plain")) {
+ this.share.uris.add(uri);
+ this.share.image = type.startsWith("image/") || isImage(uri);
+ } else {
+ this.share.text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
+ }
+ } else if (Intent.ACTION_SEND_MULTIPLE.equals(intent.getAction())) {
+ this.share.image = type != null && type.startsWith("image/");
+ if (!this.share.image) {
+ return;
+ }
+
+ this.share.uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
}
if (xmppConnectionServiceBound) {
- xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uri == null);
+ xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.image);
}
- super.onStart();
+
}
protected boolean isImage(Uri uri) {
@@ -164,7 +179,7 @@ public class ShareWithActivity extends XmppActivity {
return;
}
xmppConnectionService.populateWithOrderedConversations(mConversations,
- this.share != null && this.share.uri == null);
+ this.share != null && this.share.uris.size() == 0);
}
private void share() {
@@ -188,7 +203,7 @@ public class ShareWithActivity extends XmppActivity {
}
private void share(final Conversation conversation) {
- if (share.uri != null) {
+ if (share.uris.size() != 0) {
selectPresence(conversation, new OnPresenceSelected() {
@Override
public void onPresenceSelected() {
@@ -196,22 +211,23 @@ public class ShareWithActivity extends XmppActivity {
Toast.makeText(getApplicationContext(),
getText(R.string.preparing_image),
Toast.LENGTH_LONG).show();
- ShareWithActivity.this.xmppConnectionService
- .attachImageToConversation(conversation, share.uri,
- attachFileCallback);
+ for (Iterator<Uri> i = share.uris.iterator(); i.hasNext(); i.remove()) {
+ ShareWithActivity.this.xmppConnectionService
+ .attachImageToConversation(conversation, i.next(),
+ attachFileCallback);
+ }
} else {
Toast.makeText(getApplicationContext(),
getText(R.string.preparing_file),
Toast.LENGTH_LONG).show();
ShareWithActivity.this.xmppConnectionService
- .attachFileToConversation(conversation, share.uri,
- attachFileCallback);
+ .attachFileToConversation(conversation, share.uris.get(0),
+ attachFileCallback);
}
switchToConversation(conversation, null, true);
finish();
}
});
-
} else {
switchToConversation(conversation, this.share.text, true);
finish();
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 7eaec10c..392e57a7 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -90,6 +90,7 @@ public abstract class XmppActivity extends Activity {
protected int mPrimaryTextColor;
protected int mSecondaryTextColor;
+ protected int mPrimaryBackgroundColor;
protected int mSecondaryBackgroundColor;
protected int mColorRed;
protected int mColorOrange;
@@ -331,6 +332,7 @@ public abstract class XmppActivity extends Activity {
mColorOrange = getResources().getColor(R.color.orange);
mColorGreen = getResources().getColor(R.color.green);
mPrimaryColor = getResources().getColor(R.color.primary);
+ mPrimaryBackgroundColor = getResources().getColor(R.color.primarybackground);
mSecondaryBackgroundColor = getResources().getColor(R.color.secondarybackground);
this.mTheme = findTheme();
setTheme(this.mTheme);
@@ -740,7 +742,11 @@ public abstract class XmppActivity extends Activity {
public int getOnlineColor() {
return this.mColorGreen;
}
-
+
+ public int getPrimaryBackgroundColor() {
+ return this.mPrimaryBackgroundColor;
+ }
+
public int getSecondaryBackgroundColor() {
return this.mSecondaryBackgroundColor;
}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
index 29730914..95c0524d 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
@@ -5,13 +5,16 @@ import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.ui.XmppActivity;
+import eu.siacs.conversations.ui.ManageAccountActivity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
+import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.Switch;
public class AccountAdapter extends ArrayAdapter<Account> {
@@ -24,7 +27,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
@Override
public View getView(int position, View view, ViewGroup parent) {
- Account account = getItem(position);
+ final Account account = getItem(position);
if (view == null) {
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -34,21 +37,32 @@ public class AccountAdapter extends ArrayAdapter<Account> {
jid.setText(account.getJid().toBareJid().toString());
TextView statusView = (TextView) view.findViewById(R.id.account_status);
ImageView imageView = (ImageView) view.findViewById(R.id.account_image);
- imageView.setImageBitmap(activity.avatarService().get(account,
- activity.getPixel(48)));
- statusView.setText(getContext().getString(account.getStatus().getReadableId()));
- switch (account.getStatus()) {
- case ONLINE:
- statusView.setTextColor(activity.getOnlineColor());
- break;
- case DISABLED:
- case CONNECTING:
- statusView.setTextColor(activity.getSecondaryTextColor());
- break;
- default:
- statusView.setTextColor(activity.getWarningTextColor());
- break;
- }
+ imageView.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48)));
+ statusView.setText(getContext().getString(account.getStatus().getReadableId()));
+ switch (account.getStatus()) {
+ case ONLINE:
+ statusView.setTextColor(activity.getOnlineColor());
+ break;
+ case DISABLED:
+ case CONNECTING:
+ statusView.setTextColor(activity.getSecondaryTextColor());
+ break;
+ default:
+ statusView.setTextColor(activity.getWarningTextColor());
+ break;
+ }
+ final Switch tglAccountState = (Switch) view.findViewById(R.id.tgl_account_status);
+ final boolean isDisabled = (account.getStatus() == Account.State.DISABLED) ? true : false;
+ tglAccountState.setOnCheckedChangeListener(null);
+ tglAccountState.setChecked(!isDisabled);
+ tglAccountState.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
+ if (b == isDisabled && activity instanceof ManageAccountActivity) {
+ ((ManageAccountActivity) activity).onClickTglAccountState(account,b);
+ }
+ }
+ });
return view;
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
index a48f6ae4..d5b7e4c0 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
@@ -46,17 +46,10 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
}
Conversation conversation = getItem(position);
if (this.activity instanceof ConversationActivity) {
- ConversationActivity activity = (ConversationActivity) this.activity;
- if (!activity.isConversationsOverviewHideable()) {
- if (conversation == activity.getSelectedConversation()) {
- view.setBackgroundColor(activity
- .getSecondaryBackgroundColor());
- } else {
- view.setBackgroundColor(Color.TRANSPARENT);
- }
- } else {
- view.setBackgroundColor(Color.TRANSPARENT);
- }
+ View swipeableItem = view.findViewById(R.id.swipeable_item);
+ ConversationActivity a = (ConversationActivity) this.activity;
+ int c = !a.isConversationsOverviewHideable() && conversation == a.getSelectedConversation() ? a.getSecondaryBackgroundColor() : a.getPrimaryBackgroundColor();
+ swipeableItem.setBackgroundColor(c);
}
TextView convName = (TextView) view.findViewById(R.id.conversation_name);
if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) {
diff --git a/src/main/java/eu/siacs/conversations/utils/GeoHelper.java b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java
index f7dda936..b31b9018 100644
--- a/src/main/java/eu/siacs/conversations/utils/GeoHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java
@@ -20,7 +20,7 @@ public class GeoHelper {
}
public static ArrayList<Intent> createGeoIntentsFromMessage(Message message) {
- final ArrayList<Intent> intents = new ArrayList();
+ final ArrayList<Intent> intents = new ArrayList<>();
Matcher matcher = GEO_URI.matcher(message.getBody());
if (!matcher.matches()) {
return intents;
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index 48dc2150..25db8ecc 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -981,6 +981,10 @@ public class XmppConnection implements Runnable {
}
}
+ public void resetStreamId() {
+ this.streamId = null;
+ }
+
public List<String> findDiscoItemsByFeature(final String feature) {
final List<String> items = new ArrayList<>();
for (final Entry<String, List<String>> cursor : disco.entrySet()) {
diff --git a/src/main/res/layout-w960dp/fragment_conversations_overview.xml b/src/main/res/layout-w960dp/fragment_conversations_overview.xml
index 2744f38e..50039c03 100644
--- a/src/main/res/layout-w960dp/fragment_conversations_overview.xml
+++ b/src/main/res/layout-w960dp/fragment_conversations_overview.xml
@@ -12,7 +12,7 @@
android:background="@color/primarybackground"
android:orientation="vertical" >
- <ListView
+ <de.timroes.android.listview.EnhancedListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
diff --git a/src/main/res/layout/account_row.xml b/src/main/res/layout/account_row.xml
index 60b69090..94c59111 100644
--- a/src/main/res/layout/account_row.xml
+++ b/src/main/res/layout/account_row.xml
@@ -20,7 +20,10 @@
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/account_image"
android:orientation="vertical"
- android:paddingLeft="8dp" >
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:layout_toLeftOf="@+id/tgl_account_status"
+ android:layout_toStartOf="@+id/tgl_account_status">
<TextView
android:id="@+id/account_jid"
@@ -41,4 +44,12 @@
android:textStyle="bold" />
</LinearLayout>
+ <Switch
+ android:id="@+id/tgl_account_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:focusable="false"/>
+
</RelativeLayout> \ No newline at end of file
diff --git a/src/main/res/layout/conversation_list_row.xml b/src/main/res/layout/conversation_list_row.xml
index 21147b4a..69abb225 100644
--- a/src/main/res/layout/conversation_list_row.xml
+++ b/src/main/res/layout/conversation_list_row.xml
@@ -1,68 +1,86 @@
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="8dp" >
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:descendantFocusability="blocksDescendants">
- <ImageView
- android:id="@+id/conversation_image"
- android:layout_width="56dp"
- android:layout_height="56dp"
- android:layout_alignParentLeft="true"
- android:scaleType="centerCrop" />
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/primary"/>
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@+id/conversation_image"
- android:paddingLeft="8dp" >
+ <FrameLayout
+ android:id="@+id/swipeable_item"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/primarybackground">
- <TextView
- android:id="@+id/conversation_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignLeft="@+id/conversation_lastwrapper"
- android:layout_toLeftOf="@+id/conversation_lastupdate"
- android:singleLine="true"
- android:textColor="@color/primarytext"
- android:textSize="?attr/TextSizeHeadline"
- android:typeface="sans" />
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:selectableItemBackground"
+ android:orientation="horizontal"
+ android:padding="8dp" >
- <LinearLayout
- android:id="@+id/conversation_lastwrapper"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/conversation_name"
- android:orientation="vertical"
- android:paddingTop="3dp" >
+ <ImageView
+ android:id="@+id/conversation_image"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:layout_alignParentLeft="true"
+ android:scaleType="centerCrop" />
- <TextView
- android:id="@+id/conversation_lastmsg"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:scrollHorizontally="false"
- android:singleLine="true"
- android:textColor="@color/primarytext"
- android:textSize="?attr/TextSizeBody" />
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@+id/conversation_image"
+ android:paddingLeft="8dp" >
- <ImageView
- android:id="@+id/conversation_lastimage"
- android:layout_width="fill_parent"
- android:layout_height="36dp"
- android:background="@color/primarytext"
- android:scaleType="centerCrop" />
- </LinearLayout>
+ <TextView
+ android:id="@+id/conversation_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@+id/conversation_lastwrapper"
+ android:layout_toLeftOf="@+id/conversation_lastupdate"
+ android:singleLine="true"
+ android:textColor="@color/primarytext"
+ android:textSize="?attr/TextSizeHeadline"
+ android:typeface="sans" />
- <TextView
- android:id="@+id/conversation_lastupdate"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/conversation_name"
- android:layout_alignParentRight="true"
- android:gravity="right"
- android:textColor="@color/secondarytext"
- android:textSize="?attr/TextSizeInfo" />
- </RelativeLayout>
+ <LinearLayout
+ android:id="@+id/conversation_lastwrapper"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/conversation_name"
+ android:orientation="vertical"
+ android:paddingTop="3dp" >
-</RelativeLayout> \ No newline at end of file
+ <TextView
+ android:id="@+id/conversation_lastmsg"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollHorizontally="false"
+ android:singleLine="true"
+ android:textColor="@color/primarytext"
+ android:textSize="?attr/TextSizeBody" />
+
+ <ImageView
+ android:id="@+id/conversation_lastimage"
+ android:layout_width="fill_parent"
+ android:layout_height="36dp"
+ android:background="@color/primarytext"
+ android:scaleType="centerCrop" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/conversation_lastupdate"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@+id/conversation_name"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:textColor="@color/secondarytext"
+ android:textSize="?attr/TextSizeInfo" />
+ </RelativeLayout>
+ </RelativeLayout>
+ </FrameLayout>
+</FrameLayout> \ No newline at end of file
diff --git a/src/main/res/layout/fragment_conversations_overview.xml b/src/main/res/layout/fragment_conversations_overview.xml
index 69570028..24c653ae 100644
--- a/src/main/res/layout/fragment_conversations_overview.xml
+++ b/src/main/res/layout/fragment_conversations_overview.xml
@@ -10,7 +10,7 @@
android:background="@color/primarybackground"
android:orientation="vertical" >
- <ListView
+ <de.timroes.android.listview.EnhancedListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index d5533061..addc55de 100644
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -121,13 +121,13 @@
<string name="accept">Annehmen</string>
<string name="error">Ein unbekannter Fehler ist aufgetreten</string>
<string name="pref_grant_presence_updates">Online-Status</string>
- <string name="pref_grant_presence_updates_summary">Erlaube neu hinzugefügten Kontakten deinen online-Status zu sehen und frage um Erlaubnis, ihren sehen zu dürfen</string>
+ <string name="pref_grant_presence_updates_summary">Erlaube neu hinzugefügten Kontakten meinen Online-Status zu sehen und frage um Erlaubnis, ihren sehen zu dürfen</string>
<string name="subscriptions">Abonnements</string>
<string name="your_account">Dein Konto</string>
<string name="keys">Schlüssel</string>
- <string name="send_presence_updates">Anwesenheitsbenachrichtigungen senden</string>
- <string name="receive_presence_updates">Empfange Anwesenheitsbenachrichtigungen</string>
- <string name="ask_for_presence_updates">Frage um Erlaubnis, Anwesenheitsbenachrichtigungen sehen zu dürfen</string>
+ <string name="send_presence_updates">Online-Status senden</string>
+ <string name="receive_presence_updates">Online-Status empfangen</string>
+ <string name="ask_for_presence_updates">Online-Status anfragen</string>
<string name="attach_choose_picture">Bild auswählen</string>
<string name="attach_take_picture">Bild aufnehmen</string>
<string name="preemptively_grant">Erlaube Statusanfrage vorab</string>
@@ -255,12 +255,12 @@
<string name="conference_requires_password">Konferenz ist passwortgeschützt</string>
<string name="enter_password">Passwort eingeben</string>
<string name="missing_presence_updates">Fehlender Online-Status vom Kontakt</string>
- <string name="request_presence_updates">Bitte erst Anwesenheitsbenachrichtigungen vom Kontakt anfordern.\n\n</string>
+ <string name="request_presence_updates">Bitte erst Online-Status vom Kontakt anfragen.\n\n<small>Dies wird verwendet, um festzustellen, welche Client(s) der Kontakt benutzt.</small></string>
<string name="request_now">Jetzt anfordern</string>
<string name="delete_fingerprint">Fingerabdruck löschen</string>
<string name="sure_delete_fingerprint">Soll dieser Fingerabdruck gelöscht werden?</string>
<string name="ignore">Ignorieren</string>
- <string name="without_mutual_presence_updates"><b>Achtung:</b> Es kann zu unerwarteten Problemen führen, dies ohne gegenseitige Anwesenheitsbenachrichtigungen abzusenden.\n\n<small>Bitte die Online-Status-Abonnements in den Kontaktdetails prüfen.</small></string>
+ <string name="without_mutual_presence_updates"><b>Achtung:</b> Ohne gegenseitig den Online-Status zu kennen, 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_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>
@@ -427,6 +427,8 @@
<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>
+ <string name="title_undo_swipe_out_conversation">Unterhaltung beendet</string>
+ <string name="title_undo_swipe_out_muc">Konferenz verlassen</string>
<string name="pref_dont_trust_system_cas_title">Misstraue Zertifizierungsstellen</string>
<string name="pref_dont_trust_system_cas_summary">Alle Zertifikate müssen manuell bestätigt werden</string>
<plurals name="select_contact">
diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml
index 639eddfa..44d8abb2 100644
--- a/src/main/res/values-es/strings.xml
+++ b/src/main/res/values-es/strings.xml
@@ -427,4 +427,8 @@
<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>
+ <plurals name="select_contact">
+ <item quantity="one">Seleccionado %d contacto</item>
+ <item quantity="other">Seleccionados %d contactos</item>
+ </plurals>
</resources>
diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml
index 4d81c1bf..b6d1fa3c 100644
--- a/src/main/res/values-eu/strings.xml
+++ b/src/main/res/values-eu/strings.xml
@@ -427,4 +427,8 @@
<string name="no_application_found_to_display_location">Kokapena erakutsi dezakeen aplikaziorik ez da aurkitu</string>
<string name="location">Kokapena</string>
<string name="received_location">Kokapena jaso da</string>
+ <plurals name="select_contact">
+ <item quantity="one">Hautatu kontaktu %d</item>
+ <item quantity="other">Hautatu %d kontaktu</item>
+ </plurals>
</resources>
diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml
index 69440362..47c28517 100644
--- a/src/main/res/values-fr/strings.xml
+++ b/src/main/res/values-fr/strings.xml
@@ -427,4 +427,8 @@
<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>
+ <plurals name="select_contact">
+ <item quantity="one">%d contact séléctionné</item>
+ <item quantity="other">%d contacts séléctionnés</item>
+ </plurals>
</resources>
diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml
new file mode 100644
index 00000000..baffa088
--- /dev/null
+++ b/src/main/res/values-ja/strings.xml
@@ -0,0 +1,433 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+ <string name="action_settings">設定</string>
+ <string name="action_add">新しい会話</string>
+ <string name="action_accounts">アカウントの管理</string>
+ <string name="action_end_conversation">この会話を終了</string>
+ <string name="action_contact_details">連絡先の詳細</string>
+ <string name="action_muc_details">会議の詳細</string>
+ <string name="action_secure">安全に会話</string>
+ <string name="action_add_account">アカウントを追加</string>
+ <string name="action_edit_contact">名前の編集</string>
+ <string name="action_add_phone_book">電話帳に追加</string>
+ <string name="action_delete_contact">名簿から削除</string>
+ <string name="action_block_contact">連絡先をブロック</string>
+ <string name="action_unblock_contact">連絡先のブロックを解除</string>
+ <string name="action_block_domain">ドメインをブロック</string>
+ <string name="action_unblock_domain">ドメインのブロックを解除</string>
+ <string name="title_activity_manage_accounts">アカウントの管理</string>
+ <string name="title_activity_settings">設定</string>
+ <string name="title_activity_conference_details">会議の詳細</string>
+ <string name="title_activity_contact_details">連絡先の詳細</string>
+ <string name="title_activity_sharewith">会話で共有</string>
+ <string name="title_activity_start_conversation">会話の開始</string>
+ <string name="title_activity_choose_contact">連絡先の選択</string>
+ <string name="title_activity_block_list">ブロックリスト</string>
+ <string name="just_now">ちょうど今</string>
+ <string name="minute_ago">1 分前</string>
+ <string name="minutes_ago">%d 分前</string>
+ <string name="unread_conversations">未読の会話</string>
+ <string name="sending">送信中…</string>
+ <string name="encrypted_message">メッセージを復号しています。しばらくお待ちください…</string>
+ <string name="nick_in_use">ニックネームは既に使用されています</string>
+ <string name="admin">管理者</string>
+ <string name="owner">オーナー</string>
+ <string name="moderator">モデレーター</string>
+ <string name="participant">参加者</string>
+ <string name="visitor">ビジター</string>
+ <string name="remove_contact_text">あなたの名簿から %s を削除しますか? この連絡先と関連した会話は削除されません。</string>
+ <string name="block_contact_text">%s からあなたに送信されるメッセージをブロックしますか?</string>
+ <string name="unblock_contact_text">%s のブロックを解除し、あなたにメッセージを送信できるようにしますか?</string>
+ <string name="block_domain_text">%s からの連絡をすべてブロックしますか?</string>
+ <string name="unblock_domain_text">%s からの連絡をすべてブロック解除しますか?</string>
+ <string name="contact_blocked">連絡先をブロックしました</string>
+ <string name="remove_bookmark_text">ブックマークとして %s を削除しますか? このブックマークに関連した会話は削除されません。</string>
+ <string name="register_account">サーバーに新しいアカウントを登録</string>
+ <string name="change_password_on_server">サーバーのパスワードを変更</string>
+ <string name="share_with">…で共有</string>
+ <string name="start_conversation">会話を開始</string>
+ <string name="invite_contact">連絡先を招待</string>
+ <string name="contacts">連絡先</string>
+ <string name="cancel">キャンセル</string>
+ <string name="set">設定</string>
+ <string name="add">追加</string>
+ <string name="edit">編集</string>
+ <string name="delete">削除</string>
+ <string name="block">ブロック</string>
+ <string name="unblock">ブロックを解除</string>
+ <string name="save">保存</string>
+ <string name="ok">OK</string>
+ <string name="crash_report_title">Conversations がクラッシュしました</string>
+ <string name="crash_report_message">Conversations の継続的な開発を支援するために、スタックトレースをお送りください。\n<b>警告:</b> あなたのXMPPアカウントを使用して、開発者にスタックトレースを送信します。</string>
+ <string name="send_now">今すぐ送信</string>
+ <string name="send_never">今後表示しない</string>
+ <string name="problem_connecting_to_account">アカウントに接続できません</string>
+ <string name="problem_connecting_to_accounts">複数のアカウントに接続できません</string>
+ <string name="touch_to_fix">ここをタッチして、アカウントの管理</string>
+ <string name="attach_file">添付ファイル</string>
+ <string name="not_in_roster">連絡先が名簿にありません。追加しますか?</string>
+ <string name="add_contact">連絡先を追加</string>
+ <string name="send_failed">配信に失敗しました</string>
+ <string name="send_rejected">拒否されました</string>
+ <string name="preparing_image">転送用画像の準備中</string>
+ <string name="action_clear_history">履歴をクリア</string>
+ <string name="clear_conversation_history">会話履歴をクリア</string>
+ <string name="clear_histor_msg">この会話のすべてのメッセージを削除しますか?\n\n<b>警告:</b> これは、他のデバイスやサーバーに保存されているメッセージには影響しません。</string>
+ <string name="delete_messages">メッセージを削除</string>
+ <string name="also_end_conversation">その後、この会話を終了</string>
+ <string name="choose_presence">連絡する参加を選択</string>
+ <string name="send_plain_text_message">プレーンテキストを送信</string>
+ <string name="send_otr_message">OTR 暗号化メッセージを送信</string>
+ <string name="send_pgp_message">OpenPGP 暗号化メッセージを送信</string>
+ <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="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">UI オプション</string>
+ <string name="openpgp_error">OpenKeychain がエラーを報告しました</string>
+ <string name="error_decrypting_file">ファイルの復号化中に I/O エラー</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">一般的な I/O エラー。おそらく空き容量がなくなっていませんか?</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 ID</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 ID ではありません</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="server_info_roster_version">XEP-0237: 名簿バージョニング</string>
+ <string name="server_info_stream_management">XEP-0198: ストリーム管理</string>
+ <string name="server_info_pep">XEP-0163: 個人イベントプロトコル (アバター)</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">元の URL をコピー</string>
+ <string name="send_again">再送</string>
+ <string name="image_url">画像 URL</string>
+ <string name="message_text">メッセージテキスト</string>
+ <string name="url_copied_to_clipboard">URL をクリップボードにコピーしました</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">ソーシャリスト ミリオネア プロトコル</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>
+ <string name="could_not_change_role">%s の役割を変更できません</string>
+ <string name="public_conference">公開アクセス可能な会議</string>
+ <string name="private_conference">プライベート、メンバーのみの会議</string>
+ <string name="conference_options">会議オプション</string>
+ <string name="members_only">プライベート (メンバーのみ)</string>
+ <string name="non_anonymous">匿名でない</string>
+ <string name="modified_conference_options">会議オプションを変更しました!</string>
+ <string name="could_not_modify_conference_options">会議オプションを変更できません</string>
+ <string name="never">なし</string>
+ <string name="thirty_minutes">30 分</string>
+ <string name="one_hour">1 時間</string>
+ <string name="two_hours">2 時間</string>
+ <string name="eight_hours">8 時間</string>
+ <string name="until_further_notice">通知があるまで</string>
+ <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">Android アプリ</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>
+ <plurals name="select_contact">
+ <item quantity="other">%d 連絡先を選択</item>
+ </plurals>
+</resources>
diff --git a/src/main/res/values-sk/strings.xml b/src/main/res/values-sk/strings.xml
index bca8d3d2..cb45b4aa 100644
--- a/src/main/res/values-sk/strings.xml
+++ b/src/main/res/values-sk/strings.xml
@@ -422,4 +422,9 @@
<string name="contact_has_stopped_typing">%s prestal písať</string>
<string name="pref_chat_states">Upozornenia pri písaní</string>
<string name="pref_chat_states_summary">Upozorniť kontakt, keď píšete novú správu</string>
+ <string name="send_location">Poslať polohu</string>
+ <string name="show_location">Zobraziť polohu</string>
+ <string name="no_application_found_to_display_location">Nenašla sa aplikácia na zobrazenie polohy</string>
+ <string name="location">Poloha</string>
+ <string name="received_location">Prijatá poloha</string>
</resources>
diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml
index 479889b7..052463c8 100644
--- a/src/main/res/values-sr/strings.xml
+++ b/src/main/res/values-sr/strings.xml
@@ -302,8 +302,8 @@
<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">Очитај бар-код</string>
- <string name="show_qr_code">Прикажи бар-код</string>
+ <string name="scan_qr_code">Очитај бар-кôд</string>
+ <string name="show_qr_code">Прикажи бар-кôд</string>
<string name="show_block_list">Прикажи списак блокираних</string>
<string name="account_details">Детаљи налога</string>
<string name="verify_otr">Овери ОТР</string>
@@ -427,4 +427,9 @@
<string name="no_application_found_to_display_location">Нема апликације за приказ локације</string>
<string name="location">Локација</string>
<string name="received_location">Примљена локација</string>
+ <plurals name="select_contact">
+ <item quantity="one">Изабери %d контакт</item>
+ <item quantity="few">Изабери %d контакта</item>
+ <item quantity="other">Изабери %d контаката</item>
+ </plurals>
</resources>
diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml
index 69a66808..874de244 100644
--- a/src/main/res/values-sv/strings.xml
+++ b/src/main/res/values-sv/strings.xml
@@ -36,10 +36,10 @@
<string name="participant">Deltagare</string>
<string name="visitor">Besökare</string>
<string name="remove_contact_text">Vill du ta bort %s från din kontaktlista? Konversationer associerade med denna kontakt kommer inte tas bort.</string>
- <string name="block_contact_text">Vill du blockera %s från att skicka dig meddelanden</string>
+ <string name="block_contact_text">Vill du blockera %s från att skicka dig meddelanden?</string>
<string name="unblock_contact_text">Vill du avblockera %s och tillåta denne att skicka dig meddelanden?</string>
- <string name="block_domain_text">Blockera alla kontakter från %s</string>
- <string name="unblock_domain_text">Avblockera alla kontakter från %s</string>
+ <string name="block_domain_text">Blockera alla kontakter från %s?</string>
+ <string name="unblock_domain_text">Avblockera alla kontakter från %s?</string>
<string name="contact_blocked">Kontakt blockerad</string>
<string name="remove_bookmark_text">Vill du ta bort %s som bokmärke? Konversationer associerade med detta bokmärke kommer inte tas bort.</string>
<string name="register_account">Registrera nytt konto på servern</string>
@@ -74,7 +74,7 @@
<string name="clear_conversation_history">Rensa konversationshistorik</string>
<string name="clear_histor_msg">Vill du ta bort alla meddelanden i denna konversation?\n\n<b>Varning:</b> Detta kommer inte påverka meddelanden lagrade på andra enheter eller servrar.</string>
<string name="delete_messages">Ta bort meddelanden</string>
- <string name="also_end_conversation">Avsluta denna konversation efter</string>
+ <string name="also_end_conversation">Avsluta sedan denna konversation</string>
<string name="choose_presence">Välj tillgänglighet till kontakt</string>
<string name="send_plain_text_message">Skicka meddelande i klartext</string>
<string name="send_otr_message">Skicka OTR-krypterat meddelande</string>
@@ -82,9 +82,9 @@
<string name="your_nick_has_been_changed">Ditt nick har ändrats</string>
<string name="download_image">Ladda ner bild</string>
<string name="send_unencrypted">Skicka okrypterat</string>
- <string name="decryption_failed">Avkryptering gick fel. Du kanske inte har rätt privat nyckel.</string>
+ <string name="decryption_failed">Avkryptering misslyckades. Du har kanske kanske inte rätt privat nyckel.</string>
<string name="openkeychain_required">OpenKeychain</string>
- <string name="openkeychain_required_long">Conversations använder en tredjeparts applikation som heter <b>OpenKeychain</b> för att kryptera och avkryptera meddelanden och hantera dina publika nycklar.\n\nOpenKeychain är licensierat under GPLv3 och tillgängligt på F-Droid och Google Play.\n\n<small>(Starta om Conversations efter.)</small></string>
+ <string name="openkeychain_required_long">Conversations använder en tredjeparts-applikation som heter <b>OpenKeychain</b> för att kryptera och avkryptera meddelanden och hantera dina publika nycklar.\n\nOpenKeychain är licensierad under GPLv3 och tillgänglig på F-Droid och Google Play.\n\n<small>(Starta om Conversations efter installation.)</small></string>
<string name="restart">Starta om</string>
<string name="install">Installera</string>
<string name="offering">erbjuder…</string>
@@ -229,7 +229,7 @@
<string name="leave">Lämna</string>
<string name="contact_added_you">Kontakten lade till dig i sin kontaktlista</string>
<string name="add_back">Addera tillbaka</string>
- <string name="contact_has_read_up_to_this_point">%s har läst fram hit</string>
+ <string name="contact_has_read_up_to_this_point">%s har läst hit</string>
<string name="publish">Publicera</string>
<string name="touch_to_choose_picture">Tryck på avatarbild för att välja en bild från bildgalleriet</string>
<string name="publish_avatar_explanation">Notera: Alla som kan se dina tillgänglighetsuppdateringar kommer se denna bild.</string>
diff --git a/src/main/res/values-v21/dimens.xml b/src/main/res/values-v21/dimens.xml
new file mode 100644
index 00000000..8bc8f3f7
--- /dev/null
+++ b/src/main/res/values-v21/dimens.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="elv_undo_bottom_offset">63dp</dimen> <!-- 48dp + 15dp -->
+</resources> \ No newline at end of file
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 28bb71e9..4a36163c 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -296,6 +296,7 @@
\n\nhttps://developer.android.com/tools/support-library\n(Apache License, Version 2.0)
\n\nhttps://github.com/zxing/zxing\n(Apache License, Version 2.0)
\n\nhttps://github.com/google/material-design-icons\n(CC BY 4.0)
+ \n\nhttps://github.com/timroes/EnhancedListView\n(Apache License, Version 2.0)
</string>
<string name="title_pref_quiet_hours">Quiet Hours</string>
<string name="title_pref_quiet_hours_start_time">Start time</string>
@@ -386,7 +387,7 @@
<string name="could_not_change_password">Could not change password</string>
<string name="otr_session_not_started">Send a message to start an encrypted chat</string>
<string name="ask_question">Ask question</string>
- <string name="smp_explain_question">If you and your contact have a secret in common that no one else knows (like an inside joke or simply what you had for lunch the last time you met) you can use that secret to verify each other\'s fingerprints.\n\nYou provide a hint or a question for your contact who will respond with a case-sensitive answer.</string>
+ <string name="smp_explain_question">If you and your contact have a secret in common that no one else knows (like an inside joke or simply what you had for lunch the last time you met) you can use that secret to verify each other’s fingerprints.\n\nYou provide a hint or a question for your contact who will respond with a case-sensitive answer.</string>
<string name="smp_explain_answer">Your contact would like to verify your fingerprint by challenging you with a shared secret. Your contact provided the following hint or question for that secret.</string>
<string name="shared_secret_hint_should_not_be_empty">Your hint should not be empty</string>
<string name="shared_secret_can_not_be_empty">Your shared secret can not be empty</string>
@@ -454,7 +455,9 @@
<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>
- <string name="pref_dont_trust_system_cas_title">Don\'t trust system CAs</string>
+ <string name="title_undo_swipe_out_conversation">Conversation closed</string>
+ <string name="title_undo_swipe_out_muc">Left conference</string>
+ <string name="pref_dont_trust_system_cas_title">Don’t trust system CAs</string>
<string name="pref_dont_trust_system_cas_summary">All certificates must be manually approved</string>
<plurals name="select_contact">
<item quantity="one">Select %d contact</item>