diff options
Diffstat (limited to 'src/main')
18 files changed, 587 insertions, 513 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 95663a872..225091f9d 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -19,10 +19,10 @@ android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/ConversationsTheme" - tools:replace="android:label"> - <service android:name="eu.siacs.conversations.services.XmppConnectionService" /> + tools:replace="android:label" > + <service android:name=".services.XmppConnectionService" /> - <receiver android:name="eu.siacs.conversations.services.EventReceiver"> + <receiver android:name=".services.EventReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> @@ -31,10 +31,10 @@ </receiver> <activity - android:name="eu.siacs.conversations.ui.ConversationActivity" + android:name=".ui.ConversationActivity" android:label="@string/title_activity_conversations" android:launchMode="singleTask" - android:windowSoftInputMode="stateHidden"> + android:windowSoftInputMode="stateHidden" > <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -42,9 +42,9 @@ </intent-filter> </activity> <activity - android:name="eu.siacs.conversations.ui.StartConversationActivity" + android:name=".ui.StartConversationActivity" android:configChanges="orientation|screenSize" - android:label="@string/title_activity_start_conversation"> + android:label="@string/title_activity_start_conversation" > <intent-filter> <action android:name="android.intent.action.SENDTO" /> @@ -63,38 +63,40 @@ </intent-filter> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:scheme="xmpp" /> </intent-filter> </activity> <activity - android:name="eu.siacs.conversations.ui.SettingsActivity" - android:label="@string/title_activity_settings"></activity> + android:name=".ui.SettingsActivity" + android:label="@string/title_activity_settings" /> <activity - android:name="eu.siacs.conversations.ui.ChooseContactActivity" - android:label="@string/title_activity_choose_contact"></activity> + android:name=".ui.ChooseContactActivity" + android:label="@string/title_activity_choose_contact" /> <activity - android:name="eu.siacs.conversations.ui.ManageAccountActivity" + android:name=".ui.ManageAccountActivity" android:configChanges="orientation|screenSize" - android:label="@string/title_activity_manage_accounts"></activity> + android:label="@string/title_activity_manage_accounts" /> <activity - android:name="eu.siacs.conversations.ui.EditAccountActivity" - android:windowSoftInputMode="stateHidden|adjustResize"></activity> + android:name=".ui.EditAccountActivity" + android:windowSoftInputMode="stateHidden|adjustResize" /> <activity - android:name="eu.siacs.conversations.ui.ConferenceDetailsActivity" + android:name=".ui.ConferenceDetailsActivity" android:label="@string/title_activity_conference_details" - android:windowSoftInputMode="stateHidden"></activity> + android:windowSoftInputMode="stateHidden" /> <activity - android:name="eu.siacs.conversations.ui.ContactDetailsActivity" + android:name=".ui.ContactDetailsActivity" android:label="@string/title_activity_contact_details" - android:windowSoftInputMode="stateHidden"></activity> + android:windowSoftInputMode="stateHidden" /> <activity - android:name="eu.siacs.conversations.ui.PublishProfilePictureActivity" + android:name=".ui.PublishProfilePictureActivity" android:label="@string/mgmt_account_publish_avatar" - android:windowSoftInputMode="stateHidden"></activity> + android:windowSoftInputMode="stateHidden" /> <activity - android:name="eu.siacs.conversations.ui.ShareWithActivity" - android:label="@string/title_activity_conversations"> + android:name=".ui.ShareWithActivity" + android:label="@string/title_activity_conversations" > <intent-filter> <action android:name="android.intent.action.SEND" /> @@ -111,6 +113,14 @@ </intent-filter> </activity> <activity android:name="de.duenndns.ssl.MemorizingActivity" /> + <activity + android:name=".ui.AboutActivity" + android:label="@string/title_activity_about" + android:parentActivityName=".ui.SettingsActivity" > + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value="eu.siacs.conversations.ui.SettingsActivity" /> + </activity> </application> </manifest> diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 60c31a424..af5172d36 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -24,6 +24,8 @@ public class Contact implements ListItem { public static final String KEYS = "pgpkey"; public static final String ACCOUNT = "accountUuid"; public static final String AVATAR = "avatar"; + public static final String LAST_PRESENCE = "last_presence"; + public static final String LAST_TIME = "last_time"; protected String accountUuid; protected String systemName; @@ -43,9 +45,18 @@ public class Contact implements ListItem { public Lastseen lastseen = new Lastseen(); - public Contact(String account, String systemName, String serverName, - String jid, int subscription, String photoUri, - String systemAccount, String keys, String avatar) { + public Contact(final String account, final String systemName, final String serverName, + final String jid, final int subscription, final String photoUri, + final String systemAccount, final String keys, final String avatar, + final Lastseen lastseen) { + this(account, systemName, serverName, jid, subscription, photoUri, systemAccount, keys, + avatar); + this.lastseen = lastseen; + } + + public Contact(final String account, final String systemName, final String serverName, + final String jid, final int subscription, final String photoUri, + final String systemAccount, final String keys, final String avatar) { this.accountUuid = account; this.systemName = systemName; this.serverName = serverName; @@ -53,18 +64,15 @@ public class Contact implements ListItem { this.subscription = subscription; this.photoUri = photoUri; this.systemAccount = systemAccount; - if (keys == null) { - keys = ""; - } try { - this.keys = new JSONObject(keys); + this.keys = (keys == null ? new JSONObject("") : new JSONObject(keys)); } catch (JSONException e) { this.keys = new JSONObject(); } this.avatar = avatar; } - public Contact(String jid) { + public Contact(final String jid) { this.jid = jid; } @@ -106,10 +114,15 @@ public class Contact implements ListItem { values.put(PHOTOURI, photoUri); values.put(KEYS, keys.toString()); values.put(AVATAR, avatar); + values.put(LAST_PRESENCE, lastseen.presence); + values.put(LAST_TIME, lastseen.time); return values; } - public static Contact fromCursor(Cursor cursor) { + public static Contact fromCursor(final Cursor cursor) { + final Lastseen lastseen = new Lastseen( + cursor.getString(cursor.getColumnIndex(LAST_PRESENCE)), + cursor.getLong(cursor.getColumnIndex(LAST_TIME))); return new Contact(cursor.getString(cursor.getColumnIndex(ACCOUNT)), cursor.getString(cursor.getColumnIndex(SYSTEMNAME)), cursor.getString(cursor.getColumnIndex(SERVERNAME)), @@ -118,7 +131,8 @@ public class Contact implements ListItem { cursor.getString(cursor.getColumnIndex(PHOTOURI)), cursor.getString(cursor.getColumnIndex(SYSTEMACCOUNT)), cursor.getString(cursor.getColumnIndex(KEYS)), - cursor.getString(cursor.getColumnIndex(AVATAR))); + cursor.getString(cursor.getColumnIndex(AVATAR)), + lastseen); } public int getSubscription() { @@ -306,9 +320,18 @@ public class Contact implements ListItem { public static final int DIRTY_DELETE = 7; } - public class Lastseen { - public long time = 0; - public String presence = null; + public static class Lastseen { + public long time; + public String presence; + + public Lastseen() { + time = 0; + presence = null; + } + public Lastseen(final String presence, final long time) { + this.time = time; + this.presence = presence; + } } @Override diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java index b8454d5e5..dde017897 100644 --- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java @@ -20,7 +20,7 @@ public abstract class AbstractGenerator { "http://jabber.org/protocol/disco#info", "urn:xmpp:avatar:metadata+notify", "urn:xmpp:ping"}; - public final String IDENTITY_NAME = "Conversations 0.8.1"; + public final String IDENTITY_NAME = "Conversations 0.8.2"; public final String IDENTITY_TYPE = "phone"; protected XmppConnectionService mXmppConnectionService; diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 5b22ad61b..472a2e461 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -401,12 +401,6 @@ public class MessageParser extends AbstractParser implements @Override public void onMessagePacketReceived(Account account, MessagePacket packet) { Message message = null; - boolean notify = mXmppConnectionService.getPreferences().getBoolean( - "show_notification", true); - boolean alwaysNotifyInConference = notify - && mXmppConnectionService.getPreferences().getBoolean( - "always_notify_in_conference", false); - this.parseNick(packet, account); if ((packet.getType() == MessagePacket.TYPE_CHAT || packet.getType() == MessagePacket.TYPE_NORMAL)) { @@ -429,7 +423,6 @@ public class MessageParser extends AbstractParser implements if (message != null) { if (message.getStatus() == Message.STATUS_SEND) { account.activateGracePeriod(); - notify = false; mXmppConnectionService.markRead( message.getConversation(), false); } else { @@ -444,14 +437,10 @@ public class MessageParser extends AbstractParser implements if (message != null) { if (message.getStatus() == Message.STATUS_RECEIVED) { message.markUnread(); - notify = alwaysNotifyInConference - || NotificationService - .wasHighlightedOrPrivate(message); } else { mXmppConnectionService.markRead(message.getConversation(), false); account.activateGracePeriod(); - notify = false; } } } else if (packet.getType() == MessagePacket.TYPE_ERROR) { @@ -498,10 +487,7 @@ public class MessageParser extends AbstractParser implements if (message.trusted() && message.bodyContainsDownloadable()) { this.mXmppConnectionService.getHttpConnectionManager() .createNewConnection(message); - notify = false; - } - notify = notify && !conversation.isMuted(); - if (notify) { + } else { mXmppConnectionService.getNotificationService().push(message); } mXmppConnectionService.updateConversationUi(); diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 12e5e2510..ef045546b 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -20,7 +20,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 8; + private static final int DATABASE_VERSION = 9; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -28,6 +28,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + Contact.JID + " TEXT," + Contact.KEYS + " TEXT," + Contact.PHOTOURI + " TEXT," + Contact.OPTIONS + " NUMBER," + Contact.SYSTEMACCOUNT + " NUMBER, " + Contact.AVATAR + " TEXT, " + + Contact.LAST_PRESENCE + " TEXT, " + Contact.LAST_TIME + " NUMBER, " + "FOREIGN KEY(" + Contact.ACCOUNT + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, UNIQUE(" + Contact.ACCOUNT + ", " @@ -101,6 +102,12 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("ALTER TABLE " + Conversation.TABLENAME + " ADD COLUMN " + Conversation.ATTRIBUTES + " TEXT"); } + if (oldVersion < 9 && newVersion >= 9) { + db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + + Contact.LAST_TIME + " NUMBER"); + db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + + Contact.LAST_PRESENCE + " TEXT"); + } } public static synchronized DatabaseBackend getInstance(Context context) { diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index bd27b5557..778fd4dd1 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -1,5 +1,12 @@ package eu.siacs.conversations.services; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.net.Uri; + import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -10,12 +17,6 @@ import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.entities.MucOptions; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.Typeface; -import android.net.Uri; public class AvatarService { @@ -41,19 +42,14 @@ public class AvatarService { if (avatar != null) { return avatar; } - avatar = mXmppConnectionService.getFileBackend().getAvatar( - contact.getAvatar(), size); + if (contact.getProfilePhoto() != null) { + avatar = mXmppConnectionService.getFileBackend().cropCenterSquare(Uri.parse(contact.getProfilePhoto()), size); + } + if (avatar == null && contact.getAvatar() != null) { + avatar = mXmppConnectionService.getFileBackend().getAvatar(contact.getAvatar(), size); + } if (avatar == null) { - if (contact.getProfilePhoto() != null) { - avatar = mXmppConnectionService.getFileBackend() - .cropCenterSquare(Uri.parse(contact.getProfilePhoto()), - size); - if (avatar == null) { - avatar = get(contact.getDisplayName(), size); - } - } else { - avatar = get(contact.getDisplayName(), size); - } + avatar = get(contact.getDisplayName(), size); } this.mXmppConnectionService.getBitmapCache().put(KEY, avatar); return avatar; @@ -225,7 +221,7 @@ public class AvatarService { } private void drawTile(Canvas canvas, String letter, int tileColor, - int left, int top, int right, int bottom) { + int left, int top, int right, int bottom) { letter = letter.toUpperCase(Locale.getDefault()); Paint tilePaint = new Paint(), textPaint = new Paint(); tilePaint.setColor(tileColor); @@ -244,15 +240,15 @@ public class AvatarService { } private void drawTile(Canvas canvas, MucOptions.User user, int left, - int top, int right, int bottom) { + int top, int right, int bottom) { Contact contact = user.getContact(); if (contact != null) { Uri uri = null; - if (contact.getAvatar() != null) { + if (contact.getProfilePhoto() != null) { + uri = Uri.parse(contact.getProfilePhoto()); + } else if (contact.getAvatar() != null) { uri = mXmppConnectionService.getFileBackend().getAvatarUri( contact.getAvatar()); - } else if (contact.getProfilePhoto() != null) { - uri = Uri.parse(contact.getProfilePhoto()); } if (uri != null) { Bitmap bitmap = mXmppConnectionService.getFileBackend() @@ -277,15 +273,15 @@ public class AvatarService { } private void drawTile(Canvas canvas, Bitmap bm, int dstleft, int dsttop, - int dstright, int dstbottom) { + int dstright, int dstbottom) { Rect dst = new Rect(dstleft, dsttop, dstright, dstbottom); canvas.drawBitmap(bm, null, dst, null); } private int getColorForName(String name) { - int holoColors[] = { 0xFFe91e63, 0xFF9c27b0, 0xFF673ab7, 0xFF3f51b5, + int holoColors[] = {0xFFe91e63, 0xFF9c27b0, 0xFF673ab7, 0xFF3f51b5, 0xFF5677fc, 0xFF03a9f4, 0xFF00bcd4, 0xFF009688, 0xFFff5722, - 0xFF795548, 0xFF607d8b }; + 0xFF795548, 0xFF607d8b}; return holoColors[(int) ((name.hashCode() & 0xffffffffl) % holoColors.length)]; } diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 7b2e16df5..4cb28145c 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -1,11 +1,5 @@ package eu.siacs.conversations.services; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -23,6 +17,12 @@ import android.support.v4.app.TaskStackBuilder; import android.text.Html; import android.util.DisplayMetrics; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; @@ -46,7 +46,28 @@ public class NotificationService { this.mXmppConnectionService = service; } + public boolean notify(Message message) { + return (message.getStatus() == Message.STATUS_RECEIVED) + && notificationsEnabled() + && !message.getConversation().isMuted() + && (message.getConversation().getMode() == Conversation.MODE_SINGLE + || conferenceNotificationsEnabled() + || wasHighlightedOrPrivate(message) + ); + } + + public boolean notificationsEnabled() { + return mXmppConnectionService.getPreferences().getBoolean("show_notification", true); + } + + public boolean conferenceNotificationsEnabled() { + return mXmppConnectionService.getPreferences().getBoolean("always_notify_in_conference", false); + } + public void push(Message message) { + if (!notify(message)) { + return; + } PowerManager pm = (PowerManager) mXmppConnectionService .getSystemService(Context.POWER_SERVICE); boolean isScreenOn = pm.isScreenOn(); @@ -110,7 +131,7 @@ public class NotificationService { if (notify) { if (vibrate) { int dat = 70; - long[] pattern = { 0, 3 * dat, dat, dat }; + long[] pattern = {0, 3 * dat, dat, dat}; mBuilder.setVibrate(pattern); } if (ringtone != null) { @@ -132,7 +153,7 @@ public class NotificationService { style.setBigContentTitle(notifications.size() + " " + mXmppConnectionService - .getString(R.string.unread_conversations)); + .getString(R.string.unread_conversations)); StringBuilder names = new StringBuilder(); Conversation conversation = null; for (ArrayList<Message> messages : notifications.values()) { @@ -151,7 +172,7 @@ public class NotificationService { mBuilder.setContentTitle(notifications.size() + " " + mXmppConnectionService - .getString(R.string.unread_conversations)); + .getString(R.string.unread_conversations)); mBuilder.setContentText(names.toString()); mBuilder.setStyle(style); if (conversation != null) { @@ -184,7 +205,7 @@ public class NotificationService { } private void modifyForImage(Builder builder, Message message, - ArrayList<Message> messages, boolean notify) { + ArrayList<Message> messages, boolean notify) { try { Bitmap bitmap = mXmppConnectionService.getFileBackend() .getThumbnail(message, getPixel(288), false); @@ -210,7 +231,7 @@ public class NotificationService { } private void modifyForTextOnly(Builder builder, - ArrayList<Message> messages, boolean notify) { + ArrayList<Message> messages, boolean notify) { builder.setStyle(new NotificationCompat.BigTextStyle() .bigText(getMergedBodies(messages))); builder.setContentText(getReadableBody(messages.get(0))); @@ -244,7 +265,7 @@ public class NotificationService { private String getReadableBody(Message message) { if (message.getDownloadable() != null && (message.getDownloadable().getStatus() == Downloadable.STATUS_OFFER || message - .getDownloadable().getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE)) { + .getDownloadable().getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE)) { return mXmppConnectionService.getText( R.string.image_offered_for_download).toString(); } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { @@ -287,7 +308,7 @@ public class NotificationService { return PendingIntent.getService(mXmppConnectionService, 0, intent, 0); } - public static boolean wasHighlightedOrPrivate(Message message) { + private boolean wasHighlightedOrPrivate(Message message) { String nick = message.getConversation().getMucOptions().getActualNick(); Pattern highlight = generateNickHighlightPattern(nick); if (message.getBody() == null || nick == null) { diff --git a/src/main/java/eu/siacs/conversations/ui/AboutActivity.java b/src/main/java/eu/siacs/conversations/ui/AboutActivity.java new file mode 100644 index 000000000..a61b872ae --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/AboutActivity.java @@ -0,0 +1,15 @@ +package eu.siacs.conversations.ui; + +import android.app.Activity; +import android.os.Bundle; + +import eu.siacs.conversations.R; + +public class AboutActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_about); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/AboutPreference.java b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java new file mode 100644 index 000000000..804b4e230 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java @@ -0,0 +1,41 @@ +package eu.siacs.conversations.ui; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.preference.Preference; +import android.util.AttributeSet; + +public class AboutPreference extends Preference { + public AboutPreference(final Context context, final AttributeSet attrs, final int defStyle) { + super(context, attrs, defStyle); + setSummary(); + } + + public AboutPreference(final Context context, final AttributeSet attrs) { + super(context, attrs); + setSummary(); + } + + @Override + protected void onClick() { + super.onClick(); + final Intent intent = new Intent(getContext(), AboutActivity.class); + getContext().startActivity(intent); + } + + private void setSummary() { + if (getContext() != null && getContext().getPackageManager() != null) { + final String packageName = getContext().getPackageName(); + final String versionName; + try { + versionName = getContext().getPackageManager().getPackageInfo(packageName, 0).versionName; + setSummary("Conversations " + versionName); + } catch (final PackageManager.NameNotFoundException e) { + // Using try/catch as part of the logic is sort of like this: + // https://xkcd.com/292/ + } + } + } +} + diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 6c3dff877..2a4ddd2b6 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -10,10 +10,6 @@ import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.IntentSender.SendIntentException; import android.net.Uri; -import android.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.NfcAdapter; -import android.nfc.NfcEvent; import android.os.Bundle; import android.os.SystemClock; import android.provider.MediaStore; @@ -35,6 +31,7 @@ import android.widget.Toast; import java.util.ArrayList; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; @@ -55,33 +52,33 @@ public class ConversationActivity extends XmppActivity implements public static final int REQUEST_SEND_MESSAGE = 0x0201; public static final int REQUEST_DECRYPT_PGP = 0x0202; + public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207; private static final int REQUEST_ATTACH_FILE_DIALOG = 0x0203; private static final int REQUEST_IMAGE_CAPTURE = 0x0204; private static final int REQUEST_RECORD_AUDIO = 0x0205; private static final int REQUEST_SEND_PGP_IMAGE = 0x0206; - public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207; - private static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301; private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302; private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0303; 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"; private String mOpenConverstaion = null; private boolean mPanelOpen = true; + private Uri mPendingImageUri = null; private View mContentView; private List<Conversation> conversationList = new ArrayList<Conversation>(); private Conversation selectedConversation = null; private ListView listView; + private ConversationFragment mConversationFragment; - private boolean paneShouldBeOpen = true; private ArrayAdapter<Conversation> listAdapter; private Toast prepareImageToast; - private Uri pendingImageUri = null; public List<Conversation> getConversationList() { return this.conversationList; @@ -99,10 +96,6 @@ public class ConversationActivity extends XmppActivity implements return this.listView; } - public boolean shouldPaneBeOpen() { - return paneShouldBeOpen; - } - public void showConversationsOverview() { if (mContentView instanceof SlidingPaneLayout) { SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; @@ -113,8 +106,8 @@ public class ConversationActivity extends XmppActivity implements @Override protected String getShareableUri() { Conversation conversation = getSelectedConversation(); - if (conversation!=null) { - return "xmpp:"+conversation.getAccount().getJid(); + if (conversation != null) { + return "xmpp:" + conversation.getAccount().getJid(); } else { return ""; } @@ -148,34 +141,39 @@ public class ConversationActivity extends XmppActivity implements @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - if (savedInstanceState != null) { - mOpenConverstaion = savedInstanceState.getString( + 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); + } } setContentView(R.layout.fragment_conversations_overview); + this.mConversationFragment = new ConversationFragment(); + FragmentTransaction transaction = getFragmentManager().beginTransaction(); + transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation"); + transaction.commit(); + listView = (ListView) findViewById(R.id.list); + this.listAdapter = new ConversationAdapter(this, conversationList); + listView.setAdapter(this.listAdapter); getActionBar().setDisplayHomeAsUpEnabled(false); getActionBar().setHomeButtonEnabled(false); - this.listAdapter = new ConversationAdapter(this, conversationList); - listView.setAdapter(this.listAdapter); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View clickedView, int position, long arg3) { - paneShouldBeOpen = false; if (getSelectedConversation() != conversationList.get(position)) { setSelectedConversation(conversationList.get(position)); - swapConversationFragment(); - } else { - hideConversationsOverview(); + ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation()); } + hideConversationsOverview(); } }); mContentView = findViewById(R.id.content_view_spl); @@ -192,7 +190,6 @@ public class ConversationActivity extends XmppActivity implements @Override public void onPanelOpened(View arg0) { - paneShouldBeOpen = true; ActionBar ab = getActionBar(); if (ab != null) { ab.setDisplayHomeAsUpEnabled(false); @@ -210,16 +207,7 @@ public class ConversationActivity extends XmppActivity implements @Override public void onPanelClosed(View arg0) { - paneShouldBeOpen = false; - if ((conversationList.size() > 0) - && (getSelectedConversation() != null)) { - openConversation(getSelectedConversation()); - if (!getSelectedConversation().isRead()) { - xmppConnectionService.markRead( - getSelectedConversation(), true); - listView.invalidateViews(); - } - } + openConversation(); } @Override @@ -231,7 +219,7 @@ public class ConversationActivity extends XmppActivity implements } } - public void openConversation(Conversation conversation) { + public void openConversation() { ActionBar ab = getActionBar(); if (ab != null) { ab.setDisplayHomeAsUpEnabled(true); @@ -247,8 +235,11 @@ public class ConversationActivity extends XmppActivity implements } invalidateOptionsMenu(); if (xmppConnectionServiceBound) { - xmppConnectionService.getNotificationService().setOpenConversation( - conversation); + xmppConnectionService.getNotificationService().setOpenConversation(getSelectedConversation()); + if (!getSelectedConversation().isRead()) { + xmppConnectionService.markRead(getSelectedConversation(), true); + listView.invalidateViews(); + } } } @@ -301,12 +292,12 @@ public class ConversationActivity extends XmppActivity implements @Override public void onPresenceSelected() { if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) { - pendingImageUri = xmppConnectionService.getFileBackend() + mPendingImageUri = xmppConnectionService.getFileBackend() .getTakePhotoUri(); Intent takePictureIntent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, - pendingImageUri); + mPendingImageUri); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); @@ -437,11 +428,11 @@ public class ConversationActivity extends XmppActivity implements public void endConversation(Conversation conversation) { conversation.setStatus(Conversation.STATUS_ARCHIVED); - paneShouldBeOpen = true; showConversationsOverview(); xmppConnectionService.archiveConversation(conversation); if (conversationList.size() > 0) { setSelectedConversation(conversationList.get(0)); + this.mConversationFragment.reInit(getSelectedConversation()); } else { setSelectedConversation(null); } @@ -609,23 +600,6 @@ public class ConversationActivity extends XmppActivity implements builder.create().show(); } - protected ConversationFragment swapConversationFragment() { - ConversationFragment selectedFragment = new ConversationFragment(); - if (!isFinishing()) { - - FragmentTransaction transaction = getFragmentManager() - .beginTransaction(); - transaction.replace(R.id.selected_conversation, selectedFragment, - "conversation"); - try { - transaction.commitAllowingStateLoss(); - } catch (IllegalStateException e) { - return selectedFragment; - } - } - return selectedFragment; - } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { @@ -680,6 +654,9 @@ public class ConversationActivity extends XmppActivity implements } savedInstanceState.putBoolean(STATE_PANEL_OPEN, isConversationsOverviewVisable()); + if (this.mPendingImageUri != null) { + savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUri.toString()); + } super.onSaveInstanceState(savedInstanceState); } @@ -696,42 +673,43 @@ public class ConversationActivity extends XmppActivity implements } else if (getIntent() != null && VIEW_CONVERSATION.equals(getIntent().getType())) { handleViewConversationIntent(getIntent()); - setIntent(null); } else if (mOpenConverstaion != null) { selectConversationByUuid(mOpenConverstaion); - paneShouldBeOpen = mPanelOpen; - if (paneShouldBeOpen) { + if (mPanelOpen) { showConversationsOverview(); + } else { + if (isConversationsOverviewHideable()) { + openConversation(); + } } - swapConversationFragment(); + this.mConversationFragment.reInit(getSelectedConversation()); mOpenConverstaion = null; - } else { + } else if (getSelectedConversation() == null) { showConversationsOverview(); - ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() - .findFragmentByTag("conversation"); - if (selectedFragment != null) { - selectedFragment.onBackendConnected(); - } else { - pendingImageUri = null; - setSelectedConversation(conversationList.get(0)); - swapConversationFragment(); - } + mPendingImageUri = null; + setSelectedConversation(conversationList.get(0)); + this.mConversationFragment.reInit(getSelectedConversation()); } - if (pendingImageUri != null) { + if (mPendingImageUri != null) { attachImageToConversation(getSelectedConversation(), - pendingImageUri); - pendingImageUri = null; + mPendingImageUri); + mPendingImageUri = null; } ExceptionHelper.checkForCrash(this, this.xmppConnectionService); + setIntent(new Intent()); } private void handleViewConversationIntent(Intent intent) { String uuid = (String) intent.getExtras().get(CONVERSATION); - String text = intent.getExtras().getString(TEXT, null); + String text = intent.getExtras().getString(TEXT, ""); selectConversationByUuid(uuid); - paneShouldBeOpen = false; - swapConversationFragment().setText(text); + this.mConversationFragment.reInit(getSelectedConversation()); + this.mConversationFragment.appendText(text); + hideConversationsOverview(); + if (mContentView instanceof SlidingPaneLayout) { + openConversation(); + } } private void selectConversationByUuid(String uuid) { @@ -761,11 +739,11 @@ public class ConversationActivity extends XmppActivity implements selectedFragment.updateMessages(); } } else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) { - pendingImageUri = data.getData(); + mPendingImageUri = data.getData(); if (xmppConnectionServiceBound) { attachImageToConversation(getSelectedConversation(), - pendingImageUri); - pendingImageUri = null; + mPendingImageUri); + mPendingImageUri = null; } } else if (requestCode == REQUEST_SEND_PGP_IMAGE) { @@ -778,15 +756,15 @@ public class ConversationActivity extends XmppActivity implements getSelectedConversation()); } else if (requestCode == REQUEST_ENCRYPT_MESSAGE) { // encryptTextMessage(); - } else if (requestCode == REQUEST_IMAGE_CAPTURE) { + } else if (requestCode == REQUEST_IMAGE_CAPTURE && mPendingImageUri != null) { if (xmppConnectionServiceBound) { attachImageToConversation(getSelectedConversation(), - pendingImageUri); - pendingImageUri = null; + mPendingImageUri); + mPendingImageUri = null; } Intent intent = new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); - intent.setData(pendingImageUri); + intent.setData(mPendingImageUri); sendBroadcast(intent); } else if (requestCode == REQUEST_RECORD_AUDIO) { attachAudioToConversation(getSelectedConversation(), @@ -794,7 +772,7 @@ public class ConversationActivity extends XmppActivity implements } } else { if (requestCode == REQUEST_IMAGE_CAPTURE) { - pendingImageUri = null; + mPendingImageUri = null; } } } @@ -915,19 +893,12 @@ public class ConversationActivity extends XmppActivity implements @Override public void run() { updateConversationList(); - if (paneShouldBeOpen) { - if (conversationList.size() >= 1) { - swapConversationFragment(); - } else { + if (conversationList.size() == 0) { startActivity(new Intent(getApplicationContext(), StartConversationActivity.class)); finish(); - } - } - ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() - .findFragmentByTag("conversation"); - if (selectedFragment != null) { - selectedFragment.updateMessages(); + } else { + ConversationActivity.this.mConversationFragment.updateMessages(); } } }); @@ -935,16 +906,12 @@ public class ConversationActivity extends XmppActivity implements @Override public void onRosterUpdate() { - final ConversationFragment fragment = (ConversationFragment) getFragmentManager() - .findFragmentByTag("conversation"); - if (fragment != null) { - runOnUiThread(new Runnable() { + runOnUiThread(new Runnable() { @Override public void run() { - fragment.updateMessages(); + ConversationActivity.this.mConversationFragment.updateMessages(); } }); - } } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 20eeeb300..8754b9537 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1,27 +1,5 @@ package eu.siacs.conversations.ui; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; - -import net.java.otr4j.session.SessionStatus; -import eu.siacs.conversations.R; -import eu.siacs.conversations.crypto.PgpEngine; -import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.entities.Contact; -import eu.siacs.conversations.entities.Conversation; -import eu.siacs.conversations.entities.Message; -import eu.siacs.conversations.entities.MucOptions; -import eu.siacs.conversations.entities.Presences; -import eu.siacs.conversations.services.XmppConnectionService; -import eu.siacs.conversations.ui.EditMessage.OnEnterPressed; -import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected; -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.UIHelper; import android.app.AlertDialog; import android.app.Fragment; import android.app.PendingIntent; @@ -31,8 +9,6 @@ import android.content.Intent; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.os.Bundle; -import android.text.Editable; -import android.text.Selection; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity; @@ -44,95 +20,44 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; -import android.widget.AbsListView.OnScrollListener; -import android.widget.TextView.OnEditorActionListener; import android.widget.AbsListView; - +import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.ListView; import android.widget.ImageButton; +import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; -public class ConversationFragment extends Fragment { - - protected Conversation conversation; - protected ListView messagesView; - protected LayoutInflater inflater; - protected List<Message> messageList = new ArrayList<Message>(); - protected MessageAdapter messageListAdapter; - protected Contact contact; - - protected String queuedPqpMessage = null; - - private EditMessage mEditMessage; - private ImageButton mSendButton; - private String pastedText = null; - private RelativeLayout snackbar; - private TextView snackbarMessage; - private TextView snackbarAction; - - private boolean messagesLoaded = false; - - private IntentSender askForPassphraseIntent = null; - - private ConcurrentLinkedQueue<Message> mEncryptedMessages = new ConcurrentLinkedQueue<Message>(); - private boolean mDecryptJobRunning = false; - - private OnEditorActionListener mEditorActionListener = new OnEditorActionListener() { - - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_SEND) { - InputMethodManager imm = (InputMethodManager) v.getContext() - .getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(v.getWindowToken(), 0); - sendMessage(); - return true; - } else { - return false; - } - } - }; - - private OnClickListener mSendButtonListener = new OnClickListener() { - - @Override - public void onClick(View v) { - sendMessage(); - } - }; - protected OnClickListener clickToDecryptListener = new OnClickListener() { +import net.java.otr4j.session.SessionStatus; - @Override - public void onClick(View v) { - if (activity.hasPgp() && askForPassphraseIntent != null) { - try { - getActivity().startIntentSenderForResult( - askForPassphraseIntent, - ConversationActivity.REQUEST_DECRYPT_PGP, null, 0, - 0, 0); - } catch (SendIntentException e) { - // - } - } - } - }; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; - private OnClickListener clickToMuc = new OnClickListener() { +import eu.siacs.conversations.R; +import eu.siacs.conversations.crypto.PgpEngine; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Contact; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.entities.MucOptions; +import eu.siacs.conversations.entities.Presences; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.ui.EditMessage.OnEnterPressed; +import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected; +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.UIHelper; - @Override - public void onClick(View v) { - Intent intent = new Intent(getActivity(), - ConferenceDetailsActivity.class); - intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC); - intent.putExtra("uuid", conversation.getUuid()); - startActivity(intent); - } - }; +public class ConversationFragment extends Fragment { + protected Conversation conversation; private OnClickListener leaveMuc = new OnClickListener() { @Override @@ -140,7 +65,6 @@ public class ConversationFragment extends Fragment { activity.endConversation(conversation); } }; - private OnClickListener joinMuc = new OnClickListener() { @Override @@ -148,7 +72,6 @@ public class ConversationFragment extends Fragment { activity.xmppConnectionService.joinMuc(conversation); } }; - private OnClickListener enterPassword = new OnClickListener() { @Override @@ -168,7 +91,18 @@ public class ConversationFragment extends Fragment { }); } }; - + protected ListView messagesView; + protected LayoutInflater inflater; + protected List<Message> messageList = new ArrayList<Message>(); + protected MessageAdapter messageListAdapter; + protected Contact contact; + protected String queuedPqpMessage = null; + private EditMessage mEditMessage; + private ImageButton mSendButton; + private RelativeLayout snackbar; + private TextView snackbarMessage; + private TextView snackbarAction; + private boolean messagesLoaded = false; private OnScrollListener mOnScrollListener = new OnScrollListener() { @Override @@ -179,7 +113,7 @@ public class ConversationFragment extends Fragment { @Override public void onScroll(AbsListView view, int firstVisibleItem, - int visibleItemCount, int totalItemCount) { + int visibleItemCount, int totalItemCount) { if (firstVisibleItem == 0 && messagesLoaded) { long timestamp = messageList.get(0).getTimeSent(); messagesLoaded = false; @@ -196,7 +130,58 @@ public class ConversationFragment extends Fragment { } } }; + private IntentSender askForPassphraseIntent = null; + protected OnClickListener clickToDecryptListener = new OnClickListener() { + + @Override + public void onClick(View v) { + if (activity.hasPgp() && askForPassphraseIntent != null) { + try { + getActivity().startIntentSenderForResult( + askForPassphraseIntent, + ConversationActivity.REQUEST_DECRYPT_PGP, null, 0, + 0, 0); + } catch (SendIntentException e) { + // + } + } + } + }; + private ConcurrentLinkedQueue<Message> mEncryptedMessages = new ConcurrentLinkedQueue<Message>(); + private boolean mDecryptJobRunning = false; + private OnEditorActionListener mEditorActionListener = new OnEditorActionListener() { + + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_SEND) { + InputMethodManager imm = (InputMethodManager) v.getContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(v.getWindowToken(), 0); + sendMessage(); + return true; + } else { + return false; + } + } + }; + private OnClickListener mSendButtonListener = new OnClickListener() { + + @Override + public void onClick(View v) { + sendMessage(); + } + }; + private OnClickListener clickToMuc = new OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(getActivity(), + ConferenceDetailsActivity.class); + intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC); + intent.putExtra("uuid", conversation.getUuid()); + startActivity(intent); + } + }; private ConversationActivity activity; private Message selectedMessage; @@ -238,25 +223,25 @@ public class ConversationFragment extends Fragment { conversation.getNextPresence())); } else { switch (conversation.getNextEncryption(activity.forceEncryption())) { - case Message.ENCRYPTION_NONE: - mEditMessage - .setHint(getString(R.string.send_plain_text_message)); - break; - case Message.ENCRYPTION_OTR: - mEditMessage.setHint(getString(R.string.send_otr_message)); - break; - case Message.ENCRYPTION_PGP: - mEditMessage.setHint(getString(R.string.send_pgp_message)); - break; - default: - break; + case Message.ENCRYPTION_NONE: + mEditMessage + .setHint(getString(R.string.send_plain_text_message)); + break; + case Message.ENCRYPTION_OTR: + mEditMessage.setHint(getString(R.string.send_otr_message)); + break; + case Message.ENCRYPTION_PGP: + mEditMessage.setHint(getString(R.string.send_pgp_message)); + break; + default: + break; } } } @Override public View onCreateView(final LayoutInflater inflater, - ViewGroup container, Bundle savedInstanceState) { + ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment_conversation, container, false); mEditMessage = (EditMessage) view.findViewById(R.id.textinput); @@ -311,6 +296,11 @@ public class ConversationFragment extends Fragment { .getConversation()); } } + } else { + Account account = message.getConversation().getAccount(); + Intent intent = new Intent(activity, EditAccountActivity.class); + intent.putExtra("jid", account.getJid()); + startActivity(intent); } } }); @@ -339,7 +329,7 @@ public class ConversationFragment extends Fragment { @Override public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; this.selectedMessage = this.messageList.get(acmi.position); @@ -383,23 +373,23 @@ public class ConversationFragment extends Fragment { @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.share_image: - shareImage(selectedMessage); - return true; - case R.id.copy_text: - copyText(selectedMessage); - return true; - case R.id.send_again: - resendMessage(selectedMessage); - return true; - case R.id.copy_url: - copyUrl(selectedMessage); - return true; - case R.id.download_image: - downloadImage(selectedMessage); - return true; - default: - return super.onContextItemSelected(item); + case R.id.share_image: + shareImage(selectedMessage); + return true; + case R.id.copy_text: + copyText(selectedMessage); + return true; + case R.id.send_again: + resendMessage(selectedMessage); + return true; + case R.id.copy_url: + copyUrl(selectedMessage); + return true; + case R.id.download_image: + downloadImage(selectedMessage); + return true; + default: + return super.onContextItemSelected(item); } } @@ -461,15 +451,6 @@ public class ConversationFragment extends Fragment { } @Override - public void onStart() { - super.onStart(); - this.activity = (ConversationActivity) getActivity(); - if (activity.xmppConnectionServiceBound) { - this.onBackendConnected(); - } - } - - @Override public void onStop() { mDecryptJobRunning = false; super.onStop(); @@ -478,36 +459,18 @@ public class ConversationFragment extends Fragment { } } - public void onBackendConnected() { - this.activity = (ConversationActivity) getActivity(); - this.conversation = activity.getSelectedConversation(); - if (this.conversation == null) { - return; - } - String oldString = conversation.getNextMessage().trim(); - if (this.pastedText == null) { - this.mEditMessage.setText(oldString); - } else { - - if (oldString.isEmpty()) { - mEditMessage.setText(pastedText); - } else { - mEditMessage.setText(oldString + " " + pastedText); - } - pastedText = null; - } - int position = mEditMessage.length(); - Editable etext = mEditMessage.getText(); - Selection.setSelection(etext, position); - if (activity.isConversationsOverviewHideable()) { - if (!activity.shouldPaneBeOpen()) { - activity.hideConversationsOverview(); - activity.openConversation(conversation); - } + public void reInit(Conversation conversation) { + if (this.conversation != null) { + this.conversation.setNextMessage(mEditMessage.getText().toString()); } + this.activity = (ConversationActivity) getActivity(); + this.conversation = conversation; if (this.conversation.getMode() == Conversation.MODE_MULTI) { - conversation.setNextPresence(null); + this.conversation.setNextPresence(null); } + this.mEditMessage.setText(""); + this.mEditMessage.append(this.conversation.getNextMessage()); + this.messagesView.invalidate(); updateMessages(); } @@ -533,7 +496,7 @@ public class ConversationFragment extends Fragment { }); } else if (!contact.showInRoster() && contact - .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { + .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { showSnackbar(R.string.contact_added_you, R.string.add_back, new OnClickListener() { @@ -548,7 +511,7 @@ public class ConversationFragment extends Fragment { for (Message message : this.conversation.getMessages()) { if (message.getEncryption() == Message.ENCRYPTION_PGP && (message.getStatus() == Message.STATUS_RECEIVED || message - .getStatus() >= Message.STATUS_SEND) + .getStatus() >= Message.STATUS_SEND) && message.getDownloadable() == null) { if (!mEncryptedMessages.contains(message)) { mEncryptedMessages.add(message); @@ -574,38 +537,37 @@ public class ConversationFragment extends Fragment { && conversation.getAccount().getStatus() == Account.STATUS_ONLINE) { int error = conversation.getMucOptions().getError(); switch (error) { - case MucOptions.ERROR_NICK_IN_USE: - showSnackbar(R.string.nick_in_use, R.string.edit, - clickToMuc); - break; - case MucOptions.ERROR_ROOM_NOT_FOUND: - showSnackbar(R.string.conference_not_found, - R.string.leave, leaveMuc); - break; - case MucOptions.ERROR_PASSWORD_REQUIRED: - showSnackbar(R.string.conference_requires_password, - R.string.enter_password, enterPassword); - break; - case MucOptions.ERROR_BANNED: - showSnackbar(R.string.conference_banned, - R.string.leave, leaveMuc); - break; - case MucOptions.ERROR_MEMBERS_ONLY: - showSnackbar(R.string.conference_members_only, - R.string.leave, leaveMuc); - break; - case MucOptions.KICKED_FROM_ROOM: - showSnackbar(R.string.conference_kicked, R.string.join, - joinMuc); - break; - default: - break; + case MucOptions.ERROR_NICK_IN_USE: + showSnackbar(R.string.nick_in_use, R.string.edit, + clickToMuc); + break; + case MucOptions.ERROR_ROOM_NOT_FOUND: + showSnackbar(R.string.conference_not_found, + R.string.leave, leaveMuc); + break; + case MucOptions.ERROR_PASSWORD_REQUIRED: + showSnackbar(R.string.conference_requires_password, + R.string.enter_password, enterPassword); + break; + case MucOptions.ERROR_BANNED: + showSnackbar(R.string.conference_banned, + R.string.leave, leaveMuc); + break; + case MucOptions.ERROR_MEMBERS_ONLY: + showSnackbar(R.string.conference_members_only, + R.string.leave, leaveMuc); + break; + case MucOptions.KICKED_FROM_ROOM: + showSnackbar(R.string.conference_kicked, R.string.join, + joinMuc); + break; + default: + break; } } } - getActivity().invalidateOptionsMenu(); updateChatMsgHint(); - if (!activity.shouldPaneBeOpen()) { + if (!activity.isConversationsOverviewVisable() || !activity.isConversationsOverviewHideable()) { activity.xmppConnectionService.markRead(conversation, true); activity.updateConversationList(); } @@ -660,30 +622,30 @@ public class ConversationFragment extends Fragment { && c.getAccount().getStatus() == Account.STATUS_ONLINE) { if (c.getMode() == Conversation.MODE_SINGLE) { switch (c.getContact().getMostAvailableStatus()) { - case Presences.CHAT: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_online); - break; - case Presences.ONLINE: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_online); - break; - case Presences.AWAY: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_away); - break; - case Presences.XA: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_away); - break; - case Presences.DND: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_dnd); - break; - default: - this.mSendButton - .setImageResource(R.drawable.ic_action_send_now_offline); - break; + case Presences.CHAT: + this.mSendButton + .setImageResource(R.drawable.ic_action_send_now_online); + break; + case Presences.ONLINE: + this.mSendButton + .setImageResource(R.drawable.ic_action_send_now_online); + break; + case Presences.AWAY: + this.mSendButton + .setImageResource(R.drawable.ic_action_send_now_away); + break; + case Presences.XA: + this.mSendButton + .setImageResource(R.drawable.ic_action_send_now_away); + break; + case Presences.DND: + this.mSendButton + .setImageResource(R.drawable.ic_action_send_now_dnd); + break; + default: + this.mSendButton + .setImageResource(R.drawable.ic_action_send_now_offline); + break; } } else if (c.getMode() == Conversation.MODE_MULTI) { if (c.getMucOptions().online()) { @@ -723,9 +685,9 @@ public class ConversationFragment extends Fragment { Set<String> knownFingerprints = conversation.getContact() .getOtrFingerprints(); if (conversation.hasValidOtrSession() - && (!conversation.isMuted()) - && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints - .contains(conversation.getOtrFingerprint()))) { + && (!conversation.isMuted()) + && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints + .contains(conversation.getOtrFingerprint()))) { showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, new OnClickListener() { @@ -744,7 +706,7 @@ public class ConversationFragment extends Fragment { } protected void showSnackbar(int message, int action, - OnClickListener clickListener) { + OnClickListener clickListener) { snackbar.setVisibility(View.VISIBLE); snackbar.setOnClickListener(null); snackbarMessage.setText(message); @@ -775,7 +737,7 @@ public class ConversationFragment extends Fragment { @Override public void userInputRequried(PendingIntent pi, - Contact contact) { + Contact contact) { activity.runIntent( pi, ConversationActivity.REQUEST_ENCRYPT_MESSAGE); @@ -799,7 +761,7 @@ public class ConversationFragment extends Fragment { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { conversation .setNextEncryption(Message.ENCRYPTION_NONE); xmppService.databaseBackend @@ -828,7 +790,7 @@ public class ConversationFragment extends Fragment { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { conversation .setNextEncryption(Message.ENCRYPTION_NONE); message.setEncryption(Message.ENCRYPTION_NONE); @@ -846,7 +808,7 @@ public class ConversationFragment extends Fragment { } public void showNoPGPKeyDialog(boolean plural, - DialogInterface.OnClickListener listener) { + DialogInterface.OnClickListener listener) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setIconAttribute(android.R.attr.alertDialogIcon); if (plural) { @@ -882,8 +844,12 @@ public class ConversationFragment extends Fragment { } } - public void setText(String text) { - this.pastedText = text; + public void appendText(String text) { + String previous = this.mEditMessage.getText().toString(); + if (previous.length() != 0 && !previous.endsWith(" ")) { + text = " " + text; + } + this.mEditMessage.append(text); } public void clearInputField() { diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index e0ec2899c..c1da35f51 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -400,8 +400,10 @@ public class EditAccountActivity extends XmppActivity { private void updateAccountInformation() { this.mAccountJid.setText(this.mAccount.getJid()); this.mPassword.setText(this.mAccount.getPassword()); - this.mAvatar.setVisibility(View.VISIBLE); - this.mAvatar.setImageBitmap(avatarService().get(this.mAccount,getPixel(72))); + if (this.jidToEdit != null) { + this.mAvatar.setVisibility(View.VISIBLE); + this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(72))); + } if (this.mAccount.isOptionSet(Account.OPTION_REGISTER)) { this.mRegisterNew.setVisibility(View.VISIBLE); this.mRegisterNew.setChecked(true); 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 a24f90d7b..f2227308b 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -1,16 +1,5 @@ package eu.siacs.conversations.ui.adapter; -import java.util.List; - -import eu.siacs.conversations.Config; -import eu.siacs.conversations.R; -import eu.siacs.conversations.entities.Contact; -import eu.siacs.conversations.entities.Conversation; -import eu.siacs.conversations.entities.Downloadable; -import eu.siacs.conversations.entities.Message; -import eu.siacs.conversations.entities.Message.ImageParams; -import eu.siacs.conversations.ui.ConversationActivity; -import eu.siacs.conversations.utils.UIHelper; import android.content.Intent; import android.graphics.Typeface; import android.text.Spannable; @@ -19,9 +8,9 @@ import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.util.DisplayMetrics; import android.view.View; -import android.view.ViewGroup; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; +import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ImageView; @@ -29,6 +18,18 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import java.util.List; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Contact; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Downloadable; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.entities.Message.ImageParams; +import eu.siacs.conversations.ui.ConversationActivity; +import eu.siacs.conversations.utils.UIHelper; + public class MessageAdapter extends ArrayAdapter<Message> { private static final int SENT = 0; @@ -323,10 +324,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.message_box); viewHolder.contact_picture = (ImageView) view .findViewById(R.id.message_photo); - viewHolder.contact_picture.setImageBitmap(activity - .avatarService().get( - item.getConversation().getAccount(), - activity.getPixel(48))); viewHolder.download_button = (Button) view .findViewById(R.id.download_button); viewHolder.indicator = (ImageView) view @@ -350,11 +347,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.message_photo); viewHolder.download_button = (Button) view .findViewById(R.id.download_button); - if (item.getConversation().getMode() == Conversation.MODE_SINGLE) { - viewHolder.contact_picture.setImageBitmap(activity - .avatarService().get(item.getContact(), - activity.getPixel(48))); - } viewHolder.indicator = (ImageView) view .findViewById(R.id.security_indicator); viewHolder.image = (ImageView) view @@ -363,6 +355,8 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.message_body); viewHolder.time = (TextView) view .findViewById(R.id.message_time); + viewHolder.indicatorReceived = (ImageView) view + .findViewById(R.id.indicator_received); view.setTag(viewHolder); break; case STATUS: @@ -370,30 +364,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { R.layout.message_status, parent, false); viewHolder.contact_picture = (ImageView) view .findViewById(R.id.message_photo); - if (item.getConversation().getMode() == Conversation.MODE_SINGLE) { - - viewHolder.contact_picture.setImageBitmap(activity - .avatarService().get( - item.getConversation().getContact(), - activity.getPixel(32))); - viewHolder.contact_picture.setAlpha(0.5f); - viewHolder.contact_picture - .setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - String name = item.getConversation() - .getName(); - String read = getContext() - .getString( - R.string.contact_has_read_up_to_this_point, - name); - Toast.makeText(getContext(), read, - Toast.LENGTH_SHORT).show(); - } - }); - - } + view.setTag(viewHolder); break; default: viewHolder = null; @@ -404,9 +375,31 @@ public class MessageAdapter extends ArrayAdapter<Message> { } if (type == STATUS) { + if (item.getConversation().getMode() == Conversation.MODE_SINGLE) { + viewHolder.contact_picture.setImageBitmap(activity + .avatarService().get( + item.getConversation().getContact(), + activity.getPixel(32))); + viewHolder.contact_picture.setAlpha(0.5f); + viewHolder.contact_picture + .setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + String name = item.getConversation() + .getName(); + String read = getContext() + .getString( + R.string.contact_has_read_up_to_this_point, + name); + Toast.makeText(getContext(), read, + Toast.LENGTH_SHORT).show(); + } + }); + + } return view; - } - if (type == NULL) { + } else if (type == NULL) { if (position == getCount() - 1) { view.getLayoutParams().height = 1; } else { @@ -415,6 +408,19 @@ public class MessageAdapter extends ArrayAdapter<Message> { } view.setLayoutParams(view.getLayoutParams()); return view; + } else if (type == RECEIVED) { + Contact contact = item.getContact(); + if (contact != null) { + viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(contact, activity.getPixel(48))); + } else if (item.getConversation().getMode() == Conversation.MODE_MULTI) { + String name = item.getPresence(); + if (name == null) { + name = item.getCounterpart(); + } + viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(name, activity.getPixel(48))); + } + } else if (type == SENT) { + viewHolder.contact_picture.setImageBitmap(activity.avatarService().get(item.getConversation().getAccount(), activity.getPixel(48))); } if (viewHolder.contact_picture != null) { @@ -426,7 +432,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { if (MessageAdapter.this.mOnContactPictureClickedListener != null) { MessageAdapter.this.mOnContactPictureClickedListener .onContactPictureClicked(item); - ; } } @@ -447,24 +452,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { }); } - if (type == RECEIVED) { - if (item.getConversation().getMode() == Conversation.MODE_MULTI) { - Contact contact = item.getContact(); - if (contact != null) { - viewHolder.contact_picture.setImageBitmap(activity - .avatarService() - .get(contact, activity.getPixel(48))); - } else { - String name = item.getPresence(); - if (name == null) { - name = item.getCounterpart(); - } - viewHolder.contact_picture.setImageBitmap(activity - .avatarService().get(name, activity.getPixel(48))); - } - } - } - if (item.getType() == Message.TYPE_IMAGE || item.getDownloadable() != null) { Downloadable d = item.getDownloadable(); @@ -532,6 +519,14 @@ public class MessageAdapter extends ArrayAdapter<Message> { } } + public interface OnContactPictureClicked { + public void onContactPictureClicked(Message message); + } + + public interface OnContactPictureLongClicked { + public void onContactPictureLongClicked(Message message); + } + private static class ViewHolder { protected LinearLayout message_box; @@ -544,12 +539,4 @@ public class MessageAdapter extends ArrayAdapter<Message> { protected ImageView contact_picture; } - - public interface OnContactPictureClicked { - public void onContactPictureClicked(Message message); - } - - public interface OnContactPictureLongClicked { - public void onContactPictureLongClicked(Message message); - } } diff --git a/src/main/res/layout/activity_about.xml b/src/main/res/layout/activity_about.xml new file mode 100644 index 000000000..bd76457f8 --- /dev/null +++ b/src/main/res/layout/activity_about.xml @@ -0,0 +1,21 @@ +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:context="eu.siacs.conversations.ui.AboutActivity" + android:background="@color/primarybackground" + android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + android:paddingBottom="@dimen/activity_vertical_margin" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <TextView + android:text="@string/pref_about_message" + android:autoLink="web" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:linksClickable="true" + android:textColor="@color/primarytext" + android:textSize="?attr/TextSizeBody" + android:typeface="monospace"/> +</ScrollView> diff --git a/src/main/res/values-w820dp/dimens.xml b/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 000000000..3aeac9e75 --- /dev/null +++ b/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,7 @@ +<resources> + <!-- Customization of dimensions originally defined in res/values/dimens.xml + (such as screen margins) for screens with more than 820dp of available + width. This would include 7" and 10" devices in landscape (~960dp and + ~1280dp respectively). --> + <dimen name="activity_horizontal_margin">64dp</dimen> +</resources> diff --git a/src/main/res/values/dimens.xml b/src/main/res/values/dimens.xml new file mode 100644 index 000000000..47c822467 --- /dev/null +++ b/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ +<resources> + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> +</resources> diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 0dbb49adb..28a1e326a 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -25,8 +25,8 @@ <string name="minute_ago">1 min ago</string> <string name="minutes_ago">%d mins ago</string> <string name="unread_conversations">unread Conversations</string> - <string name="sending">sending…</string> - <string name="encrypted_message">Decrypting message. Please wait…</string> + <string name="sending">sending…</string> + <string name="encrypted_message">Decrypting message. Please wait…</string> <string name="nick_in_use">Nickname is already in use</string> <string name="admin">Admin</string> <string name="owner">Owner</string> @@ -58,7 +58,7 @@ <string name="add_contact">Add contact</string> <string name="send_failed">delivery failed</string> <string name="send_rejected">rejected</string> - <string name="receiving_image">Receiving image file. Please wait…</string> + <string name="receiving_image">Receiving image file. Please wait…</string> <string name="preparing_image">Preparing image for transmission</string> <string name="action_clear_history">Clear history</string> <string name="clear_conversation_history">Clear Conversation History</string> @@ -78,8 +78,8 @@ <string name="openkeychain_required_long">Conversations utilizes a third party app called <b>OpenKeychain</b> to encrypt and decrypt messages and to manage your public keys.\n\nOpenKeychain is licensed under GPLv3 and available on F-Droid and Google Play.\n\n<small>(Please restart Conversations afterwards.)</small></string> <string name="restart">Restart</string> <string name="install">Install</string> - <string name="offering">offering…</string> - <string name="waiting">waiting…</string> + <string name="offering">offering…</string> + <string name="waiting">waiting…</string> <string name="no_pgp_key">No OpenPGP Key found</string> <string name="contact_has_no_pgp_key">Conversations is unable to encrypt your messages because your contact is not announcing his or hers public key.\n\n<small>Please ask your contact to setup OpenPGP.</small></string> <string name="no_pgp_keys">No OpenPGP Keys found</string> @@ -91,7 +91,7 @@ <string name="pref_xmpp_resource">XMPP resource</string> <string name="pref_xmpp_resource_summary">The name this client identifies itself with</string> <string name="pref_accept_files">Accept files</string> - <string name="pref_accept_files_summary">Automatically accept files smaller than…</string> + <string name="pref_accept_files_summary">Automatically accept files smaller than…</string> <string name="pref_notification_settings">Notification Settings</string> <string name="pref_notifications">Notifications</string> <string name="pref_notifications_summary">Notify when a new message arrives</string> @@ -217,7 +217,7 @@ <string name="publish">Publish</string> <string name="touch_to_choose_picture">Touch avatar to select picture from gallery</string> <string name="publish_avatar_explanation">Please note: Everyone subscribed to your presence updates will be allowed to see this picture.</string> - <string name="publishing">Publishing…</string> + <string name="publishing">Publishing…</string> <string name="error_publish_avatar_server_reject">The server rejected your publication</string> <string name="error_publish_avatar_converting">Something went wrong while converting your picture</string> <string name="error_saving_avatar">Could not save avatar to disk</string> @@ -254,6 +254,23 @@ <string name="pref_enable_legacy_ssl_summary">Enables SSLv3 support for legacy servers. Warning: SSLv3 is considered insecure.</string> <string name="pref_expert_options">Expert options</string> <string name="pref_expert_options_summary">Please be careful with these</string> + <string name="title_activity_about">About Conversations</string> + <string name="pref_about_conversations_summary">Build and licensing information</string> + <string name="pref_about_message">Conversations © 2014 Daniel Gultsch\n + \nThis program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License version 3 as published + by the Free Software Foundation. + \nhttps://www.gnu.org/licenses/gpl-3.0.html\n + \nOpenPGP API is licensed under the Apache License, Version 2.0 + \nhttps://www.apache.org/licenses/LICENSE-2.0\n + \nMinidns © 2014 Rene Treffer and is provided under the WTFPL + \nhttp://wtfpl.org\n + \nMemorizingTrustManager © 2010 Georg Lukas under the terms of the MIT + License + \nhttp://opensource.org/licenses/MIT\n + \nDownload the full source code at + \nhttps://github.com/siacs/Conversations + </string> <string name="pref_use_larger_font">Increase font size</string> <string name="pref_use_larger_font_summary">Use larger font sizes across the entire app</string> <string name="pref_use_send_button_to_indicate_status">Send button indicates status</string> @@ -285,4 +302,4 @@ <string name="scan_qr_code">Scan QR code</string> <string name="show_qr_code">Show QR code</string> <string name="account_details">Account details</string> -</resources>
\ No newline at end of file +</resources> diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index 06ab7560e..15a61e879 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -110,5 +110,8 @@ android:summary="@string/pref_never_send_crash_summary" android:title="@string/pref_never_send_crash" /> </PreferenceCategory> + <eu.siacs.conversations.ui.AboutPreference + android:summary="@string/pref_about_conversations_summary" + android:title="@string/title_activity_about" /> </PreferenceScreen> |