aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--AndroidManifest.xml16
-rw-r--r--CHANGELOG.md5
-rw-r--r--README.md28
-rw-r--r--docs/MISSION.md4
m---------libs/MemorizingTrustManager0
-rw-r--r--project.properties1
-rw-r--r--res/drawable-hdpi/ic_action_edit_dark.pngbin0 -> 884 bytes
-rw-r--r--res/drawable-mdpi/ic_action_edit_dark.pngbin0 -> 587 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_edit_dark.pngbin0 -> 1179 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_edit_dark.pngbin0 -> 1670 bytes
-rw-r--r--res/layout/activity_choose_contact.xml13
-rw-r--r--res/layout/activity_muc_details.xml237
-rw-r--r--res/layout/cert_warning.xml41
-rw-r--r--res/layout/edit_contact_name.xml28
-rw-r--r--res/layout/fragment_conversation.xml3
-rw-r--r--res/layout/quickedit.xml18
-rw-r--r--res/menu/choose_contact.xml10
-rw-r--r--res/menu/conversations.xml45
-rw-r--r--res/menu/muc_details.xml6
-rw-r--r--res/values-ca/strings.xml12
-rw-r--r--res/values-de/strings.xml21
-rw-r--r--res/values-es/strings.xml29
-rw-r--r--res/values-eu/strings.xml62
-rw-r--r--res/values-fr/strings.xml16
-rw-r--r--res/values-gl/strings.xml15
-rw-r--r--res/values-nl/arrays.xml22
-rw-r--r--res/values-nl/strings.xml240
-rw-r--r--res/values-nl/styles.xml19
-rw-r--r--res/values-ru/strings.xml15
-rw-r--r--res/values/colors.xml2
-rw-r--r--res/values/strings.xml27
-rw-r--r--res/values/styles.xml4
-rw-r--r--res/values/themes.xml4
-rw-r--r--src/eu/siacs/conversations/entities/AbstractEntity.java5
-rw-r--r--src/eu/siacs/conversations/entities/Account.java7
-rw-r--r--src/eu/siacs/conversations/entities/Bookmark.java6
-rw-r--r--src/eu/siacs/conversations/entities/Conversation.java19
-rw-r--r--src/eu/siacs/conversations/entities/Message.java2
-rw-r--r--src/eu/siacs/conversations/entities/MucOptions.java58
-rw-r--r--src/eu/siacs/conversations/generator/AbstractGenerator.java49
-rw-r--r--src/eu/siacs/conversations/generator/IqGenerator.java31
-rw-r--r--src/eu/siacs/conversations/generator/MessageGenerator.java33
-rw-r--r--src/eu/siacs/conversations/generator/PresenceGenerator.java10
-rw-r--r--src/eu/siacs/conversations/parser/AbstractParser.java15
-rw-r--r--src/eu/siacs/conversations/parser/IqParser.java20
-rw-r--r--src/eu/siacs/conversations/parser/MessageParser.java55
-rw-r--r--src/eu/siacs/conversations/parser/PresenceParser.java14
-rw-r--r--src/eu/siacs/conversations/services/XmppConnectionService.java294
-rw-r--r--src/eu/siacs/conversations/ui/ChooseContactActivity.java140
-rw-r--r--src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java268
-rw-r--r--src/eu/siacs/conversations/ui/ContactDetailsActivity.java244
-rw-r--r--src/eu/siacs/conversations/ui/ConversationActivity.java29
-rw-r--r--src/eu/siacs/conversations/ui/ConversationFragment.java562
-rw-r--r--src/eu/siacs/conversations/ui/EditAccountDialog.java (renamed from src/eu/siacs/conversations/ui/EditAccount.java)4
-rw-r--r--src/eu/siacs/conversations/ui/ManageAccountActivity.java73
-rw-r--r--src/eu/siacs/conversations/ui/MucDetailsActivity.java214
-rw-r--r--src/eu/siacs/conversations/ui/OnPresenceSelected.java5
-rw-r--r--src/eu/siacs/conversations/ui/StartConversationActivity.java (renamed from src/eu/siacs/conversations/ui/StartConversation.java)180
-rw-r--r--src/eu/siacs/conversations/ui/XmppActivity.java69
-rw-r--r--src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java (renamed from src/eu/siacs/conversations/utils/KnownHostsAdapter.java)4
-rw-r--r--src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java39
-rw-r--r--src/eu/siacs/conversations/ui/adapter/MessageAdapter.java478
-rw-r--r--src/eu/siacs/conversations/utils/UIHelper.java7
-rw-r--r--src/eu/siacs/conversations/utils/Validator.java2
-rw-r--r--src/eu/siacs/conversations/xmpp/OnTLSExceptionReceived.java7
-rw-r--r--src/eu/siacs/conversations/xmpp/XmppConnection.java85
67 files changed, 2313 insertions, 1661 deletions
diff --git a/.gitmodules b/.gitmodules
index 17cbe617..d0f56166 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -5,3 +5,6 @@
[submodule "libs/openpgp-api-lib"]
path = libs/openpgp-api-lib
url = https://github.com/open-keychain/openpgp-api-lib.git
+[submodule "libs/MemorizingTrustManager"]
+ path = libs/MemorizingTrustManager
+ url = https://github.com/ge0rg/MemorizingTrustManager
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a7bfbbe4..44bfd18d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="eu.siacs.conversations"
- android:versionCode="19"
- android:versionName="0.4.1" >
+ android:versionCode="20"
+ android:versionName="0.5-beta" >
<uses-sdk
android:minSdkVersion="14"
@@ -49,11 +49,11 @@
</intent-filter>
</activity>
<activity
- android:name="eu.siacs.conversations.ui.StartConversation"
+ android:name="eu.siacs.conversations.ui.StartConversationActivity"
android:configChanges="orientation|screenSize"
android:label="@string/title_activity_start_conversation"
android:logo="@drawable/ic_activity"
- android:parentActivityName="eu.siacs.conversations.ui.ConversationActivity">
+ android:parentActivityName="eu.siacs.conversations.ui.ConversationActivity" >
<intent-filter>
<action android:name="android.intent.action.SENDTO" />
@@ -68,6 +68,9 @@
android:label="@string/title_activity_settings"
android:parentActivityName="eu.siacs.conversations.ui.ConversationActivity" >
</activity>
+ <activity android:name="eu.siacs.conversations.ui.ChooseContactActivity"
+ android:label="@string/title_activity_choose_contact">
+ </activity>
<activity
android:name="eu.siacs.conversations.ui.ManageAccountActivity"
android:configChanges="orientation|screenSize"
@@ -75,7 +78,7 @@
android:parentActivityName="eu.siacs.conversations.ui.ConversationActivity" >
</activity>
<activity
- android:name="eu.siacs.conversations.ui.MucDetailsActivity"
+ android:name="eu.siacs.conversations.ui.ConferenceDetailsActivity"
android:label="@string/title_activity_conference_details"
android:windowSoftInputMode="stateHidden" >
</activity>
@@ -102,6 +105,7 @@
<data android:mimeType="image/*" />
</intent-filter>
</activity>
+ <activity android:name="de.duenndns.ssl.MemorizingActivity" />
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5a7d9c63..433b580f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
###Changelog
+####Version 0.5
+* UI overhaul
+* MUC / Conference bookmarks
+* A lot of bug fixes
+
####Version 0.4
* OTR file encryption
* keep OTR messages and files on device until both parties or online at the same time
diff --git a/README.md b/README.md
index 53af9d6c..6692974d 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ your friends.
These XEPs are - as of now:
* XEP-0065: SOCKS5 Bytestreams - or rather mod_proxy65. Will be used to tranfer files if both parties are behind a firewall (NAT).
* XEP-0138: Stream Compression saves bandwith
-* XEP-0198: Stream Management allows XMPP to surive small network outages and changes of the underlying TCP connection.
+* XEP-0198: Stream Management allows XMPP to survive small network outages and changes of the underlying TCP connection.
* XEP-0280: Message Carbons which automatically syncs the messages you send to
your desktop client and thus allows you to switch seamlessly from your mobile
client to your desktop client and back within one conversation.
@@ -54,6 +54,8 @@ These XEPs are - as of now:
* [Benoit Bouvarel](https://github.com/BenoitBouvarel) (French)
* [Daniel Gultsch](https://github.com/iNPUTmice) (German)
* [Aitor Beriain](https://github.com/beriain) (Basque)
+* [Ilia Rostovtsev](https://github.com/rostovtsev) (Russian)
+* [Jelmer Vernooij](https://github.com/jelmer) (Dutch)
##FAQ
###General
@@ -85,7 +87,7 @@ Or ask a friend to run one. Once you found one you can use Conversations to
create an account. Just select 'register new account on server' within the
create account dialog.
-####Conversations dosen't work for me. Where can I get help?
+####Conversations doesn't work for me. Where can I get help?
You can join our conference room on conversations@conference.siacs.eu A lot of
people in there are able to answer basic questions about the usage of
Conversations or can provide you with tips on running your own XMPP server. If
@@ -102,7 +104,7 @@ address book with unnecessary contacts from your online roster. If you manually
add a Jabber ID to your phones address book Conversations will use the name and
the profile picture of this contact. To make the process of adding Jabber IDs to
your address book easier you can click on the profile picture in the contact
-detais within Conversations. This will start an add to address book intent with the jabber ID
+details within Conversations. This will start an add to address book intent with the jabber ID
as payload. This doesn’t require Conversations to have write permissions on your
address book but also doesn’t require you to copy past Jabber ID from one app to
another.
@@ -110,7 +112,7 @@ another.
Status are a horrible metric. Setting them manually to a proper value rarly
works because users are either lazy or just forget about them. Setting them
automatically does not provide quality results either. Keyboard or mouse
-activity as indicator for example fails when the users is just looking at
+activity as indicator for example fails when the user is just looking at
something (reading an article, watching a movie). Furthermore automatic setting
of status always implies an impact on your privacy. (Are you sure you want
everybody in your contact list to know that you have been using your computer at
@@ -127,8 +129,8 @@ longer necessary. Using priorities to route OTR messages isn't pratical either
because they are not changeable on the fly. Metrics like last active client
(the client which sent the last message) are much better.
-Unfortunatly these modern replacement for legacy XMPP featurs are not widely
-adopted. However Conversations should be an instant messanger for the future and
+Unfortunatly these modern replacements for legacy XMPP features are not widely
+adopted. However Conversations should be an instant messenger for the future and
instead of making Conversations compatible with the past we should work on
implementing new, improved technologies into other XMPP clients as well.
@@ -140,14 +142,14 @@ other clients.
I'm open for new feature suggestions. You can use the issue tracker on github.
Please take some time to browse through the issues to see if someone else
already suggested it. Be assured that I read each and every ticket. If I like it
-I will leave it open untill it's implemented. If I don't like it I will close
+I will leave it open until it's implemented. If I don't like it I will close
it. (Usually with a short comment). If I don't comment on an feature request
-thats probably a good sign because this means I agree with you. Commenting with
-+1 on either open or closed issues wont change my mind nor will it accelerate the
+that's probably a good sign because this means I agree with you. Commenting with
++1 on either open or closed issues won't change my mind nor will it accelerate the
development.
####You closed my feature request but I want it really really badly
-Just write it yourself and send my a pull request. If I like it I will happily
+Just write it yourself and send me a pull request. If I like it I will happily
merge it if I don't at least you and like minded people get to enjoy it.
####I need a feature and I need it now!
@@ -162,21 +164,21 @@ more flexible.
Before you continue reading you should notice that the openPGP support in
Conversations is marked as experimental. This is not because it will make the app
unstable but because the fundamental concepts of PGP aren't ready for a
-widespread use. The way PGP works is that you trust Key IDs instead of XMPP- or email addresses. So in theory your contact list should consist of Public-Key-IDs instead of email addresses. But of course no email or xmpp client out there implements these concepts. Plus PGP in the context of instant messaging has a couple of downsides. It is vulnerable to replay attacks, it is rather verbose, and decryping and encrypting takes longer than OTR. It is however asynchronous and works well with carbonated messages.
+widespread use. The way PGP works is that you trust Key IDs instead of XMPP- or email addresses. So in theory your contact list should consist of Public-Key-IDs instead of email addresses. But of course no email or xmpp client out there implements these concepts. Plus PGP in the context of instant messaging has a couple of downsides. It is vulnerable to replay attacks, it is rather verbose, and decrypting and encrypting takes longer than OTR. It is however asynchronous and works well with carbonated messages.
To use openpgp you have to install the opensource app OpenKeychain (www.openkeychain.org) and then long press on the account in manage accounts and choose renew PGP announcement from the contextual menu.
####How does the encryption for conferences work?
For conferences the only supported encryption method is OpenPGP. (OTR does not
work with multiple participents.) Every participant has to announce their
OpenPGP key. (See answer above). If you would like to send encrypted messages to
-a conference you have to make sure that you have every participants public key
+a conference you have to make sure that you have every participant's public key
in your OpenKeychain. Right now there is no check in Conversations to ensure
that. You have to take care of that yourself. Go to the conference details and
touch every key id (The hexadecimal number below a contact). This will send you
to OpenKeychain which will assist you on adding the key.
This works best in very small conferences with contacts you are already using
OpenPGP with. This feature is regarded experimental. Conversations is the only
-client that uses XEP-0027 with confercenes. (The XEP neither specifically allows
+client that uses XEP-0027 with conferences. (The XEP neither specifically allows
nor disallows this.)
###Development
####How do I build Conversations
diff --git a/docs/MISSION.md b/docs/MISSION.md
index 269ea85b..74399e74 100644
--- a/docs/MISSION.md
+++ b/docs/MISSION.md
@@ -1,6 +1,6 @@
-Conversations is a messanger for the next decade. Based on already established
+Conversations is a messenger for the next decade. Based on already established
internet standards that have been around for over ten years Coversations isn’t
-trying to replace current commercial messangers. It will simply outlive them.
+trying to replace current commercial messengers. It will simply outlive them.
Commercial, closed source products are coming and going. 15 years ago we had
ICQ which was replaced by Skype. MySpace was replaced by Facebook. WhatsApp and
Hangouts will disapear soon. Internet standards however stick around. People are
diff --git a/libs/MemorizingTrustManager b/libs/MemorizingTrustManager
new file mode 160000
+Subproject 452f70208f0dd5f9e56376944e96f5c10704245
diff --git a/project.properties b/project.properties
index 86ae5d0c..7276fb94 100644
--- a/project.properties
+++ b/project.properties
@@ -14,3 +14,4 @@
target=android-19
android.library.reference.1=libs/minidns
android.library.reference.2=libs/openpgp-api-lib
+android.library.reference.3=libs/MemorizingTrustManager
diff --git a/res/drawable-hdpi/ic_action_edit_dark.png b/res/drawable-hdpi/ic_action_edit_dark.png
new file mode 100644
index 00000000..5f7c6eff
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_edit_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_edit_dark.png b/res/drawable-mdpi/ic_action_edit_dark.png
new file mode 100644
index 00000000..650b4d89
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_edit_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_edit_dark.png b/res/drawable-xhdpi/ic_action_edit_dark.png
new file mode 100644
index 00000000..8ab436d8
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_edit_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_edit_dark.png b/res/drawable-xxhdpi/ic_action_edit_dark.png
new file mode 100644
index 00000000..f2b2078b
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_edit_dark.png
Binary files differ
diff --git a/res/layout/activity_choose_contact.xml b/res/layout/activity_choose_contact.xml
new file mode 100644
index 00000000..248a7822
--- /dev/null
+++ b/res/layout/activity_choose_contact.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <ListView
+ android:id="@+id/choose_contact_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:listitem="@layout/contact" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/activity_muc_details.xml b/res/layout/activity_muc_details.xml
index 15f09c7c..49b4cef3 100644
--- a/res/layout/activity_muc_details.xml
+++ b/res/layout/activity_muc_details.xml
@@ -2,147 +2,126 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/secondarybackground">
-
-<LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
- <TextView
- style="@style/sectionHeader"
+ android:background="@color/primarybackground" >
+
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="8dp"
- android:text="@string/muc_details_conference"
- android:textColor="@color/primarytext"/>
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@color/primarybackground" >
-
+ android:orientation="vertical" >
- <EditText
- android:id="@+id/muc_subject"
+ <TextView
+ style="@style/sectionHeader"
android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@+id/muc_edit_subject"
- android:background="@color/primarybackground"
- android:ems="10"
- android:hint="@string/muc_details_conference_subject"
- android:inputType="textAutoComplete"
- android:paddingBottom="12dp"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:paddingTop="12dp" />
-
- <ImageButton
- android:id="@+id/muc_edit_subject"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
- android:background="?android:selectableItemBackground"
+ android:layout_height="wrap_content"
android:padding="8dp"
- android:src="@drawable/ic_action_edit" />
- </RelativeLayout>
- <TextView
- android:id="@+id/muc_jabberid"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="8dp"
- android:singleLine="true"
- android:textSize="14sp"
- android:textColor="@color/primarytext"/>
+ android:text="@string/muc_details_conference" />
- <TextView
- style="@style/sectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:paddingTop="8dp"
- android:text="@string/muc_details_your_nickname"
- android:textColor="@color/primarytext"/>
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@color/primarybackground" >
-
+ <TextView
+ android:id="@+id/muc_jabberid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:singleLine="true"
+ android:text="@string/account_settings_example_jabber_id"
+ android:textColor="@color/primarytext"
+ android:textSize="14sp"/>
- <EditText
- android:id="@+id/muc_your_nick"
+ <TextView
+ style="@style/sectionHeader"
android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@+id/muc_edit_nick"
- android:background="@color/primarybackground"
- android:ems="10"
- android:hint="@string/muc_details_your_nickname"
- android:inputType="textEmailAddress"
- android:paddingBottom="12dp"
+ android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
- android:paddingTop="12dp" />
-
- <ImageButton
- android:id="@+id/muc_edit_nick"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
- android:background="?android:selectableItemBackground"
+ android:paddingTop="8dp"
+ android:text="@string/you" />
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/activatedBackgroundIndicator"
android:padding="8dp"
- android:src="@drawable/ic_action_edit" />
- </RelativeLayout>
- <TextView
- android:id="@+id/muc_role"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="8dp"
- android:singleLine="true"
- android:textSize="14sp"
- android:textColor="@color/primarytext"/>
-
- <LinearLayout
- android:id="@+id/muc_more_details"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/muc_participants_header"
- style="@style/sectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:paddingTop="8dp"
- android:text="@string/muc_details_other_members"
- android:textColor="@color/primarytext"/>
+ android:paddingBottom="8dp" >
- <LinearLayout
- android:id="@+id/muc_members"
- android:layout_width="fill_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:orientation="vertical"
- android:divider="?android:dividerHorizontal"
- android:showDividers="middle"
- >
- </LinearLayout>
+ <ImageView
+ android:id="@+id/your_photo"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentLeft="true"
+ android:src="@drawable/ic_profile" >
+ </ImageView>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@+id/your_photo"
+ android:orientation="vertical"
+ android:paddingLeft="8dp" >
+
+ <TextView
+ android:id="@+id/muc_your_nick"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textColor="@color/primarytext"
+ android:textSize="18sp" />
+
+ <TextView
+ android:id="@+id/muc_role"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textColor="@color/primarytext"
+ android:textSize="14sp" />
+ </LinearLayout>
+
+ <ImageButton
+ android:id="@+id/edit_nick_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:background="?android:selectableItemBackground"
+ android:src="@drawable/ic_action_edit_dark"
+ android:padding="8dp"/>
+
+ </RelativeLayout>
+
+ <LinearLayout
+ android:id="@+id/muc_more_details"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/muc_participants_header"
+ style="@style/sectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:paddingTop="8dp"
+ android:text="@string/muc_details_other_members" />
+
+ <LinearLayout
+ android:id="@+id/muc_members"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:divider="?android:dividerHorizontal"
+ android:orientation="vertical"
+ android:showDividers="middle" >
+ </LinearLayout>
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/invite"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="24dp"
+ android:text="@string/invite_contact" />
</LinearLayout>
- <Button
- android:layout_marginTop="24dp"
- android:id="@+id/invite"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/invite_contacts"
- android:layout_gravity="center_horizontal"/>
-</LinearLayout>
</ScrollView> \ No newline at end of file
diff --git a/res/layout/cert_warning.xml b/res/layout/cert_warning.xml
deleted file mode 100644
index fffe3266..00000000
--- a/res/layout/cert_warning.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="8dp">
-
- <TextView
- android:id="@+id/hint"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="14sp"/>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="#FFe92727"
- android:textStyle="bold"
- android:textSize="14sp"
- android:text="Do not connect unless you know exactly what you are doing"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"/>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="14sp"
- android:text="The SHA1 fingerprint is:" />
-
- <TextView
- android:layout_gravity="center_horizontal"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:id="@+id/sha"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:typeface="monospace"
- android:textStyle="bold"
- android:textSize="18sp"/>
-
-</LinearLayout>
diff --git a/res/layout/edit_contact_name.xml b/res/layout/edit_contact_name.xml
deleted file mode 100644
index 42f0fb88..00000000
--- a/res/layout/edit_contact_name.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="8dp">
-
- <TextView
- android:id="@+id/textView1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/enter_new_name"
- android:textColor="@color/primarytext"
- android:textSize="18sp" />
-
- <EditText
- android:paddingTop="16dp"
- android:paddingBottom="8dp"
- android:id="@+id/editText1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:ems="10"
- android:inputType="textPersonName" >
-
- <requestFocus />
- </EditText>
-
-</LinearLayout>
diff --git a/res/layout/fragment_conversation.xml b/res/layout/fragment_conversation.xml
index b712c304..2d612984 100644
--- a/res/layout/fragment_conversation.xml
+++ b/res/layout/fragment_conversation.xml
@@ -81,7 +81,8 @@
android:layout_centerVertical="true"
android:paddingLeft="24dp"
android:textColor="@color/ondarktext"
- android:textSize="14sp" />
+ android:textSize="14sp"
+ android:layout_toLeftOf="@+id/snackbar_action"/>
<TextView
android:id="@+id/snackbar_action"
diff --git a/res/layout/quickedit.xml b/res/layout/quickedit.xml
new file mode 100644
index 00000000..07a7ac3b
--- /dev/null
+++ b/res/layout/quickedit.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="16dp">
+ <EditText
+ android:id="@+id/editor"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ems="10"
+ android:inputType="textPersonName"
+ android:textColor="@color/primarytext">
+
+ <requestFocus />
+ </EditText>
+
+</LinearLayout>
diff --git a/res/menu/choose_contact.xml b/res/menu/choose_contact.xml
new file mode 100644
index 00000000..3f402664
--- /dev/null
+++ b/res/menu/choose_contact.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item
+ android:id="@+id/action_search"
+ android:actionLayout="@layout/actionview_search"
+ android:icon="@drawable/ic_action_search"
+ android:showAsAction="collapseActionView|always"
+ android:title="@string/search"/>
+</menu> \ No newline at end of file
diff --git a/res/menu/conversations.xml b/res/menu/conversations.xml
index 710a552e..215bbb66 100644
--- a/res/menu/conversations.xml
+++ b/res/menu/conversations.xml
@@ -2,62 +2,57 @@
<item
android:id="@+id/action_add"
- android:orderInCategory="10"
android:icon="@drawable/ic_action_new"
+ android:orderInCategory="10"
android:showAsAction="always"
- android:title="@string/action_add" />
-
+ android:title="@string/action_add"/>
<item
android:id="@+id/action_security"
+ android:icon="@drawable/ic_action_not_secure"
android:orderInCategory="20"
android:showAsAction="always"
- android:icon="@drawable/ic_action_not_secure"
- android:title="@string/action_secure" />
-
+ android:title="@string/action_secure"/>
<item
android:id="@+id/action_attach_file"
+ android:icon="@drawable/ic_action_new_attachment"
android:orderInCategory="30"
android:showAsAction="always"
- android:icon="@drawable/ic_action_new_attachment"
- android:title="@string/attach_file" />
-
+ android:title="@string/attach_file"/>
<item
android:id="@+id/action_contact_details"
android:orderInCategory="40"
android:showAsAction="never"
- android:title="@string/action_contact_details" />
- <item
+ android:title="@string/action_contact_details"/>
+ <item
android:id="@+id/action_muc_details"
+ android:icon="@drawable/ic_action_group"
android:orderInCategory="40"
android:showAsAction="ifRoom"
- android:icon="@drawable/ic_action_group"
- android:title="@string/action_muc_details" />
- <item
+ android:title="@string/action_muc_details"/>
+ <item
android:id="@+id/action_invite"
+ android:orderInCategory="45"
android:showAsAction="never"
- android:title="@string/invite_contacts" />
-
+ android:title="@string/invite_contact"/>
<item
- android:id="@+id/action_archive"
+ android:id="@+id/action_clear_history"
android:orderInCategory="50"
android:showAsAction="never"
- android:title="@string/action_end_conversation"/>
- <item
- android:id="@+id/action_clear_history"
+ android:title="@string/action_clear_history"/>
+ <item
+ android:id="@+id/action_archive"
android:orderInCategory="60"
android:showAsAction="never"
- android:title="@string/action_clear_history"/>
+ android:title="@string/action_end_conversation"/>
<item
android:id="@+id/action_accounts"
android:orderInCategory="90"
android:showAsAction="never"
- android:title="@string/action_accounts"
- />
-
+ android:title="@string/action_accounts"/>
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
-</menu>
+</menu> \ No newline at end of file
diff --git a/res/menu/muc_details.xml b/res/menu/muc_details.xml
index 4f9b6da0..685109cd 100644
--- a/res/menu/muc_details.xml
+++ b/res/menu/muc_details.xml
@@ -1,6 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
+ android:id="@+id/action_edit_subject"
+ android:orderInCategory="10"
+ android:showAsAction="always"
+ android:icon="@drawable/ic_action_edit"
+ android:title="@string/action_edit_subject" />
+ <item
android:id="@+id/action_accounts"
android:orderInCategory="90"
android:showAsAction="never"
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 76e32e7d..41dffc6e 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -30,13 +30,7 @@
<string name="show_otr_key">Emprempta dactilar OTR</string>
<string name="no_otr_fingerprint">No s\'ha generat una emprempta dactilar OTR. Simplement continua i comença una conversa xifrada.</string>
<string name="start_conversation">Començar conversa</string>
- <string name="invite_contacts">Convidar contactes</string>
- <string name="invite_contacts_to_existing">Convidar a conferència existent</string>
- <string name="new_conference">Crear nova conferència</string>
<string name="cancel">Cancel·lar</string>
- <string name="create_invite">Crear \u0026 Convidar</string>
- <string name="new_conference_explained">Vols crear una nova conferència amb una adreça generada aleatòriament i convidar als contactes seleccionats a ella?</string>
- <string name="no_open_mucs">No hi ha conferències existents</string>
<string name="invitation_sent">Invitació enviada</string>
<string name="account_offline">Compte desconnectat</string>
<string name="cant_invite_while_offline">Has d\'estar connectat per convidar contactes a la conferència</string>
@@ -60,7 +54,6 @@
<string name="delete_messages">Esborrar missatges</string>
<string name="also_end_conversation">Finalitzar aquesta conversa més tard</string>
<string name="choose_presence">Selecciona recurs del contacte</string>
- <string name="send_message_to_conference">Enviar missatge a conferència</string>
<string name="send_plain_text_message">Enviar missatge de text</string>
<string name="send_otr_message">Enviar missatge xifrat amb OTR</string>
<string name="send_pgp_message">Enviar missatge xifrat amb OpenPGP</string>
@@ -69,9 +62,6 @@
<string name="error_loading_image">Error carregant imatge (Fitxer no trobat)</string>
<string name="image_offered_for_download"><i>Fitxer d\'imatge ofert per a descàrrega</i></string>
<string name="not_connected">No connectat</string>
- <string name="you_are_offline">Has d\'estar connectat per enviar %s però el teu compte associat a aquesta conversa està desconnectat.</string>
- <string name="you_are_offline_blank">No pots executar aquesta acció estant desconnectat.</string>
- <string name="files">fitxers</string>
<string name="otr_messages">Missatges xifrats amb OTR</string>
<string name="manage_account">Gestionar compte</string>
<string name="contact_offline">El teu contacte està desconnectat</string>
@@ -94,8 +84,6 @@
<string name="use_pgp_encryption">Usa xifratge amb OpenPGP</string>
<string name="pref_xmpp_resource">Recursos XMPP</string>
<string name="pref_xmpp_resource_summary">El nom que identifica aquest client amb</string>
- <string name="pref_accept_files">Acceptar fitxers</string>
- <string name="pref_accept_files_summary">Accepta fitxers automàticament amb una mida menor a&#8230;</string>
<string name="pref_notification_settings">Ajustos de notificacions</string>
<string name="pref_notifications">Notificacions</string>
<string name="pref_notifications_summary">Notifica quan arriba un nou missatge</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index e4ad7817..8af1c066 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -45,10 +45,6 @@
<string name="show_otr_key">OTR Fingerabdruck</string>
<string name="no_otr_fingerprint">Es wurde noch kein OTR-Fingerabdruck erzeugt. Beginne einfach eine verschlüsselte Unterhaltung um einen Fingerabdruck zu erzeugen.</string>
<string name="start_conversation">Beginne Unterhaltung</string>
- <string name="invite_contacts">Kontakte einladen</string>
- <string name="invite_contacts_to_existing">Lade zu bestehender Konferenz ein</string>
- <string name="new_conference">Erzeuge neue Konferenz</string>
- <string name="new_contact">Neuen Kontakt erstellen</string>
<string name="contacts">Kontakte</string>
<string name="search_jabber_id">Jabber ID eingeben oder suchen</string>
<string name="choose_account">Account auswählen</string>
@@ -64,9 +60,6 @@
<string name="ok">OK</string>
<string name="done">Erledigt</string>
<string name="hide">Verstecken</string>
- <string name="create_invite">Erzeugen \u0026 Einladen</string>
- <string name="new_conference_explained">Möchtest du eine neue Konferenz mit einer zufälligen Adresse erstellen und die ausgewählten Kontakte zu dieser einladen?</string>
- <string name="no_open_mucs">Keine bestehende Konferenz</string>
<string name="invitation_sent">Einladung wurde versandt</string>
<string name="account_offline">Account offline</string>
<string name="cant_invite_while_offline">Du musst online sein um andere Leute zu einer Konferenz einzuladen</string>
@@ -90,7 +83,6 @@
<string name="delete_messages">Nachrichten löschen</string>
<string name="also_end_conversation">Diese Unterhaltung danach beenden</string>
<string name="choose_presence">Choose presence to contact</string>
- <string name="send_message_to_conference">Nachricht an Konferenz schicken</string>
<string name="send_plain_text_message">Unverschlüsselt schreiben</string>
<string name="send_otr_message">OTR-verschlüsselt schreiben</string>
<string name="send_pgp_message">OpenPGP-verschlüsselt schreiben</string>
@@ -99,9 +91,6 @@
<string name="error_loading_image">Fehler beim laden des Bildes. (Datei wurde nicht gefunden)</string>
<string name="image_offered_for_download"><i>Bild Datei zum Download angeboten</i></string>
<string name="not_connected">Nicht verbunden</string>
- <string name="you_are_offline">Du musst online sein um %s zu verschicken. Das mit dieser Unterhaltung verbundene Konto ist gerade offline.</string>
- <string name="you_are_offline_blank">Du kannst diese Aktion nicht ausführen so lange du offline bist.</string>
- <string name="files">Dateien</string>
<string name="otr_messages">OTR-verschlüsselte Nachrichten</string>
<string name="manage_account">Konto verwalten</string>
<string name="contact_offline">Dein Kontakt ist offline</string>
@@ -116,7 +105,6 @@
<string name="offering">angeboten&#8230;</string>
<string name="waiting">warten&#8230;</string>
<string name="no_pgp_key">Kein OpenPGP Schlüssel gefunden</string>
- <string name="no_pgp_keys">Keine OpenPGP-Schlüssel gefunden</string>
<string name="contact_has_no_pgp_key">Conversations ist nicht in der Lage deine Nachrichten zu verschlüsseln weil dein Kontakt sein oder ihren Schlüssel nicht preis gibt.\n\n<small>Bitte sag deinem Kontakt er oder sie möge bitte OpenPGP einrichten.</small></string>
<string name="contact_has_no_pgp_keys">Conversations ist nicht in der Lage deine Nachrichten zu verschlüsseln weil dein Kontakt sein oder ihren Schlüssel nicht preis gibt.\n\n<small>Bitte sag deinem Kontakt er oder sie möge bitte OpenPGP einrichten.</small></string>
<string name="encrypted_message_received"><i>Verschlüsselte Nachricht erhalten. Drücke hier um sie anzuzeigen und zu entschlüsseln.</i></string>
@@ -127,8 +115,6 @@
<string name="use_pgp_encryption">OpenPGP verwenden</string>
<string name="pref_xmpp_resource">XMPP resource</string>
<string name="pref_xmpp_resource_summary">Der Name mit dem sich der Client selber identifiziert</string>
- <string name="pref_accept_files">Dateiannahme</string>
- <string name="pref_accept_files_summary">Datein die kleiner sind als &#8230; automatisch annehmen</string>
<string name="pref_notification_settings">Benachrichtigungseinstellung</string>
<string name="pref_notifications">Benachrichtigungen</string>
<string name="pref_notifications_summary">Benachrichtige mich wenn eine neu Nachricht ankommt</string>
@@ -156,7 +142,6 @@
<string name="pref_grant_presence_updates">Online Status</string>
<string name="pref_grant_presence_updates_summary">Erlaube Kontakten die von Dir erstellt wurden deinen Status zu sehen und frage um Erlaubnis ihren zu sehen.</string>
<string name="subscriptions">Abonnements</string>
- <string name="subscription_updated">Abonnements aktualisiert</string>
<string name="your_account">Dein Account</string>
<string name="keys">Schlüssel</string>
<string name="send_presence_updates">Anwesenheitsbenachrichtigungen senden</string>
@@ -181,13 +166,10 @@
<string name="account_status_not_found">Server nicht gefunden</string>
<string name="account_status_no_internet">Keine Internetverbindung</string>
<string name="account_status_requires_tls">Server benötigt TLS</string>
- <string name="account_status_error">Unbekanntes Zertifikat</string>
<string name="account_status_regis_fail">Registrierung fehlgeschlagen</string>
<string name="account_status_regis_conflict">Benutzername wird bereits verwendet</string>
<string name="account_status_regis_success">Registrierung abgeschlossen</string>
<string name="account_status_regis_not_sup">Der Server unterstützt keine Registrierung</string>
- <string name="certif_no_trust">Nicht verbinden</string>
- <string name="certif_trust">Dem Zertifikat vertrauen</string>
<string name="encryption_choice_none">Klartext</string>
<string name="encryption_choice_otr">OTR</string>
<string name="encryption_choice_pgp">OpenPGP</string>
@@ -206,7 +188,6 @@
<string name="mgmt_account_are_you_sure">Bist du dir sicher?</string>
<string name="mgmt_account_delete_confirm_text">Wenn du dein Konto löscht, gehen alle Gesprächsverläufe verloren</string>
<string name="mgmt_account_account_offline">Das Konto ist offline</string>
- <string name="attach_record_voice">Audio aufnehmen</string>
<string name="account_settings_jabber_id">Jabber ID:</string>
<string name="account_settings_password">Passwort:</string>
<string name="account_settings_example_jabber_id">benutzer@domain.de</string>
@@ -255,4 +236,4 @@
<string name="openpgp_click_to_decrypt">Hier klicken, um das Passwort einzugeben und die Nachricht zu entschlüsseln</string>
<string name="reception_failed">Empfang ist fehlgeschlagen</string>
<string name="no_muc_server_found">Es wurde kein Konferenzserver gefunden</string>
-</resources> \ No newline at end of file
+</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index c8877534..bd8f84e2 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -22,6 +22,7 @@
<string name="title_activity_conversations">Conversations</string>
<string name="title_activity_sharewith">Compartir con Conversación</string>
<string name="title_activity_start_conversation">Nueva Conversación</string>
+ <string name="title_activity_choose_contact">Elegir Contacto</string>
<string name="just_now">ahora</string>
<string name="minute_ago">hace 1 min</string>
<string name="minutes_ago">hace %d min</string>
@@ -38,6 +39,7 @@
<string name="visitor">Visitante</string>
<string name="enter_new_name">Introduce un nuevo nombre:</string>
<string name="remove_contact_text">¿Quieres eliminar a %s de tu lista? La conversación asociada a esta cuenta no se eliminará.</string>
+ <string name="remove_bookmark_text">¿Quieres eliminar %s de tus marcadores? La conversación de la conferencia asociada con este marcador no se eliminará.</string>
<string name="untrusted_cert_hint">El servidor %s presenta un certificado no confiable, posiblemente auto firmado.</string>
<string name="account_info">Información del servidor</string>
<string name="register_account">Registrar nueva cuenta en servidor</string>
@@ -46,10 +48,7 @@
<string name="show_otr_key">Clave OTR</string>
<string name="no_otr_fingerprint">No se ha generado una clave OTR. Continúa y comienza una conversación encriptada</string>
<string name="start_conversation">Comenzar conversación</string>
- <string name="invite_contacts">Invitar contactos</string>
- <string name="invite_contacts_to_existing">Invitar a conferencia existente</string>
- <string name="new_conference">Crear nueva conferencia</string>
- <string name="new_contact">Crear nuevo contacto</string>
+ <string name="invite_contact">Invitar contactos</string>
<string name="contacts">Contactos</string>
<string name="search_jabber_id">Busca o escribe identificador Jabber</string>
<string name="choose_account">Seleccionar cuenta</string>
@@ -65,9 +64,6 @@
<string name="ok">OK</string>
<string name="done">Hecho</string>
<string name="hide">Ocultar</string>
- <string name="create_invite">Crear \u0026 Invitar</string>
- <string name="new_conference_explained">¿Quieres crear una nueva conferencia con una dirección generada aleatoriamente e invitar a los contactos seleccionados a ella?</string>
- <string name="no_open_mucs">No hay conferencias existentes</string>
<string name="invitation_sent">Invitación enviada</string>
<string name="account_offline">Cuenta desconectada</string>
<string name="cant_invite_while_offline">Debes estar conectado para invitar a contactos a la conferencia</string>
@@ -79,7 +75,7 @@
<string name="problem_connecting_to_accounts">No se ha podido conectar a múltiples cuentas</string>
<string name="touch_to_fix">Pulsa aquí para gestionar tus cuentas</string>
<string name="attach_file">Adjuntar</string>
- <string name="not_in_roster">El contacto no está en tu lista. ¿Quieres añadirlo?</string>
+ <string name="not_in_roster">El contacto no está en tu lista. ¿Te gustaría añadirlo?</string>
<string name="add_contact">Añadir contacto</string>
<string name="send_failed">Error al enviar</string>
<string name="send_rejected">rechazado</string>
@@ -124,8 +120,6 @@
<string name="use_pgp_encryption">Usa encriptación con OpenPGP</string>
<string name="pref_xmpp_resource">Recurso</string>
<string name="pref_xmpp_resource_summary">El nombre que identifica el cliente que estás utilizando</string>
- <string name="pref_accept_files">Aceptar archivos</string>
- <string name="pref_accept_files_summary">De forma automática aceptar archivos menores que&#8230;</string>
<string name="pref_notification_settings">Ajustes de notificación</string>
<string name="pref_notifications">Notificaciones</string>
<string name="pref_notifications_summary">Notifica cuando llega un nuevo mensaje</string>
@@ -157,7 +151,6 @@
<string name="pref_grant_presence_updates">Suscripción de presencia</string>
<string name="pref_grant_presence_updates_summary">De forma automática solicitar y conceder suscripciones de presencia de los contactos que has creado</string>
<string name="subscriptions">Suscripciones</string>
- <string name="subscription_updated">Suscripción actualizada</string>
<string name="your_account">Tu cuenta</string>
<string name="keys">Claves</string>
<string name="send_presence_updates">Enviar actualizaciones de presencia</string>
@@ -182,13 +175,10 @@
<string name="account_status_not_found">Servidor no encontrado</string>
<string name="account_status_no_internet">Sin conectividad</string>
<string name="account_status_requires_tls">El servidor requiere TLS</string>
- <string name="account_status_error">Certificado no confiable</string>
<string name="account_status_regis_fail">Error en el registro</string>
<string name="account_status_regis_conflict">El identificador ya está en uso</string>
<string name="account_status_regis_success">Registro completado</string>
<string name="account_status_regis_not_sup">El servidor no soporta registros</string>
- <string name="certif_no_trust">No conectar</string>
- <string name="certif_trust">Confiar en el certificado</string>
<string name="encryption_choice_none">Texto plano</string>
<string name="encryption_choice_otr">OTR</string>
<string name="encryption_choice_pgp">OpenPGP</string>
@@ -267,4 +257,13 @@
<string name="conference_address">Dirección de la Conferencia</string>
<string name="conference_address_example">nombre@conferencia.ejemplo.com</string>
<string name="save_as_bookmark">Guardar en marcadores</string>
-</resources> \ No newline at end of file
+ <string name="delete_bookmark">Eliminar marcador</string>
+ <string name="bookmark_already_exists">Este marcador ya exsite</string>
+ <string name="you">Tú</string>
+ <string name="action_edit_subject">Editar asunto de la conferencia</string>
+ <string name="conference_not_found">Conferencia no encontrada</string>
+ <string name="leave">Salir</string>
+ <string name="contact_added_you">El contacto te ha añadido a su lista de contactos</string>
+ <string name="add_back">Añadir contacto</string>
+ <string name="contact_has_read_up_to_this_point">Tu contacto ha leído hasta aquí</string>
+</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index df793735..d317e871 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -19,8 +19,10 @@
<string name="title_activity_settings">Ezarpenak</string>
<string name="title_activity_conference_details">Konferentziaren xehetasunak</string>
<string name="title_activity_contact_details">Kontaktuaren xehetasunak</string>
- <string name="title_activity_conversations">Conversations</string>
+ <string name="title_activity_conversations">Elkarrizketak</string>
<string name="title_activity_sharewith">Elkarrizketa batekin partekatu</string>
+ <string name="title_activity_start_conversation">Elkarrizketa hasi</string>
+ <string name="title_activity_choose_contact">Kontaktua hautatu</string>
<string name="just_now">orain</string>
<string name="minute_ago">min 1 lehenago</string>
<string name="minutes_ago">%d min lehenago</string>
@@ -37,6 +39,7 @@
<string name="visitor">Bisitaria</string>
<string name="enter_new_name">Sartu izen berri bat:</string>
<string name="remove_contact_text">%s zure zerrendatik ezabatu nahi duzu? Kontu honekin lotutako elkarrizketa ez da ezabatuko.</string>
+ <string name="remove_bookmark_text">%s laster marka bezala ezabatu nahi duzu? Laster-marka honekin lotutako elkarrizketa ez da ezabatuko.</string>
<string name="untrusted_cert_hint">%s zerbitzariak konfiantzarik gabeko, agian bere buruak izenpetutako, ziurtagiri batekin aurkeztu zaitu.</string>
<string name="account_info">Zerbitzariaren informazioa</string>
<string name="register_account">Kontu berria zerbitzarian erregistratu</string>
@@ -45,10 +48,7 @@
<string name="show_otr_key">OTR hatz-marka</string>
<string name="no_otr_fingerprint">Ez da OTR hatz-markarik sortu. Aurrera joan eta enkriptatutako elkarrizketa hasi</string>
<string name="start_conversation">Elkarrizketa hasi</string>
- <string name="invite_contacts">Kontaktuak gonbidatu</string>
- <string name="invite_contacts_to_existing">Existitzen den konferentzia batera gonbidatu</string>
- <string name="new_conference">Konferentzia berria sortu</string>
- <string name="new_contact">Kontaktu berria sortu</string>
+ <string name="invite_contact">Kontaktu bat gonbidatu</string>
<string name="contacts">Kontaktuak</string>
<string name="search_jabber_id">Bilatu edo sartu Jabber ID bat</string>
<string name="choose_account">Kontua hautatu</string>
@@ -64,9 +64,6 @@
<string name="ok">Ados</string>
<string name="done">Eginda</string>
<string name="hide">Ezkutatu</string>
- <string name="create_invite">Sortu \u0026 Gonbidatu</string>
- <string name="new_conference_explained">Ausazki sortutako helbide batekin konferentzia berri bat sortu eta hautatutako kontaktuak bertara gonbidatu nahi al dituzu?</string>
- <string name="no_open_mucs">Ez da konferentziarik existitzen</string>
<string name="invitation_sent">Gonbidapena bidali da</string>
<string name="account_offline">Kontua lineaz kanpo</string>
<string name="cant_invite_while_offline">Konektatuta egon behar zara jendea konferentzietara gonbidatzeko</string>
@@ -123,8 +120,6 @@
<string name="use_pgp_encryption">OpenPGP enkriptazioa erabili</string>
<string name="pref_xmpp_resource">XMPP baliabidea</string>
<string name="pref_xmpp_resource_summary">Bezero honek bere burua aurkezteko erabiltzen duen izena</string>
- <string name="pref_accept_files">Fitxategiak onartu</string>
- <string name="pref_accept_files_summary">Hurrengo tamaina baino fitxategi txikiagoak automatikoki onartu&#8230;</string>
<string name="pref_notification_settings">Jakinarazpenen ezarpenak</string>
<string name="pref_notifications">Jakinarazpenak</string>
<string name="pref_notifications_summary">Mezu berri bat heltzerakoan jakinarazi</string>
@@ -156,7 +151,6 @@
<string name="pref_grant_presence_updates">Presentzia eguneraketak eman</string>
<string name="pref_grant_presence_updates_summary">Prebentiboki presentzia eguneraketak eman eta eskatu sortu dituzun kontaktuetarako</string>
<string name="subscriptions">Harpidetzak</string>
- <string name="subscription_updated">Herpidetza eguneratuta</string>
<string name="your_account">Zure kontua</string>
<string name="keys">Gakoak</string>
<string name="send_presence_updates">Presentzia eguneraketak bidali</string>
@@ -181,13 +175,10 @@
<string name="account_status_not_found">Zerbitzaria ez da aurkitu</string>
<string name="account_status_no_internet">Konektagarritasunik ez</string>
<string name="account_status_requires_tls">Zerbitzariak TLS behar du</string>
- <string name="account_status_error">Konfiantzarik gabeko ziurtagiria</string>
<string name="account_status_regis_fail">Erregistroak huts egin du</string>
<string name="account_status_regis_conflict">Erabiltzaile izena dagoeneko erabilita</string>
<string name="account_status_regis_success">Erregistroa burutu da</string>
<string name="account_status_regis_not_sup">Zerbitzariak ez du erregistratzea onartzen</string>
- <string name="certif_no_trust">Ez konektatu</string>
- <string name="certif_trust">Ziurtagiriaz fidatu</string>
<string name="encryption_choice_none">Testu laua</string>
<string name="encryption_choice_otr">OTR</string>
<string name="encryption_choice_pgp">OpenPGP</string>
@@ -200,10 +191,10 @@
<string name="mgmt_account_account_offline">Kontua lineaz kanpo dago</string>
<string name="attach_record_voice">Ahotsa grabatu</string>
<string name="account_settings">Kontuaren ezarpenak</string>
- <string name="account_settings_jabber_id">Jabber IDa:</string>
- <string name="account_settings_password">Pasahitza:</string>
+ <string name="account_settings_jabber_id">Jabber IDa</string>
+ <string name="account_settings_password">Pasahitza</string>
<string name="account_settings_example_jabber_id">erabiltzailea@adibidea.com</string>
- <string name="account_settings_confirm_password">Pasahitza egiaztatu:</string>
+ <string name="account_settings_confirm_password">Pasahitza egiaztatu</string>
<string name="password">Pasahitza</string>
<string name="confirm_password">Pasahitza egiaztatu</string>
<string name="passwords_do_not_match">Pasahitzak ez dute bat egiten</string>
@@ -232,7 +223,7 @@
<string name="server_info_roster_versioning">Roster Versioning</string>
<string name="server_info_carbon_messages">Carbon Messages</string>
<string name="server_info_stream_management">Stream Management</string>
- <string name="hours">orduak</string>
+ <string name="hours">ordu</string>
<string name="mins">minutu</string>
<string name="missing_public_keys">Gako publikoen iragarpenak faltan</string>
<string name="last_seen_now">azkenegoz ikusia orain</string>
@@ -245,10 +236,35 @@
<string name="last_seen_day">azkenengoz ikusia egun 1 lehenago</string>
<string name="install_openkeychain">Mezu enkriptatua. Mesedez instalatu OpenKeychain desenkriptatzeko.</string>
<string name="unknown_otr_fingerprint">OTR hatz-marka ezezaguna</string>
- <string name="edit_conference_details">Ukitu konferentziaren xehetasunak editatzeko</string>
- <string name="openpgp_messages_found">OpenPGPz enkriptatutako mezuak aurkitu dira</string>
- <string name="openpgp_click_to_decrypt">Sakatu hemen pasahitza sartu eta mezuak desenkriptatzeko</string>
- <string name="reception_failed">Jasotzeak huts egin du</string>
- <string name="no_muc_server_found">Ez da aurkitu konferentzia zerbitzari egokirik</string>
+ <string name="edit_conference_details">Ukitu konferentziaren xehetasunak editatzeko</string>
+ <string name="openpgp_messages_found">OpenPGPz enkriptatutako mezuak aurkitu dira</string>
+ <string name="openpgp_click_to_decrypt">Sakatu hemen pasahitza sartu eta mezuak desenkriptatzeko</string>
+ <string name="reception_failed">Jasotzeak huts egin du</string>
+ <string name="no_muc_server_found">Ez da aurkitu konferentzia zerbitzari egokirik</string>
+ <string name="your_fingerprint">Zure hatz-marka</string>
+ <string name="otr_fingerprint">OTR hatz-marka</string>
+ <string name="verify">Egiaztatu</string>
+ <string name="decrypt">Desenkriptatu</string>
+ <string name="conferences">Konferentziak</string>
+ <string name="search">Bilatu</string>
+ <string name="create_contact">Kontaktua sortu</string>
+ <string name="join_conference">Konferentziara batu</string>
+ <string name="delete_contact">Kontaktua ezabatu</string>
+ <string name="view_contact_details">Kontaktuaren xehetasunak ikusi</string>
+ <string name="create">Sortu</string>
+ <string name="contact_already_exists">Kontaktua existitzen da dagoeneko</string>
+ <string name="join">Batu</string>
+ <string name="conference_address">Konferentziaren helbidea</string>
+ <string name="conference_address_example">gela@conference.example.com</string>
+ <string name="save_as_bookmark">Gorde laster-marka bezala</string>
+ <string name="delete_bookmark">Laster-marka ezbatu</string>
+ <string name="bookmark_already_exists">Laster-marka hau existitzen da dagoeneko</string>
+ <string name="you">Zu</string>
+ <string name="action_edit_subject">Konferentziaren gaia editatu</string>
+ <string name="conference_not_found">Konferentzia ez da aurkitu</string>
+ <string name="leave">Alde egin</string>
+ <string name="contact_added_you">Kontaktua zure kontaktu zerrendara gehitu da</string>
+ <string name="add_back">Berriz gehitu</string>
+ <string name="contact_has_read_up_to_this_point">Zure kontaktuak puntu honetaraino irakurri du</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 1e21e9f5..e383ef22 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -45,10 +45,6 @@
<string name="show_otr_key">Empreinte OTR</string>
<string name="no_otr_fingerprint">Empreinte OTR non générée. Essayez de démarrer une conversation sécurisée.</string>
<string name="start_conversation">Démarrer une conversation</string>
- <string name="invite_contacts">Inviter des contacts</string>
- <string name="invite_contacts_to_existing">Inviter à une conférence</string>
- <string name="new_conference">Créer une nouvelle conférence</string>
- <string name="new_contact">Ajouter ce contact</string>
<string name="contacts">Contacts</string>
<string name="search_jabber_id">Rechercher un identifiant</string>
<string name="choose_account">Choix du compte</string>
@@ -64,9 +60,6 @@
<string name="ok">OK</string>
<string name="done">Terminé</string>
<string name="hide">Cacher</string>
- <string name="create_invite">Créer \u0026 invitation</string>
- <string name="new_conference_explained">Voulez-vous créer une nouvelle conférence avec une adresse générée aléatoirement et inviter les contacts sélectionnés à la rejoindre?</string>
- <string name="no_open_mucs">Conférences non existantes</string>
<string name="invitation_sent">Invitation envoyée</string>
<string name="account_offline">Compte hors-ligne</string>
<string name="cant_invite_while_offline">Vous devez être en ligne pour inviter des participants à une conférence.</string>
@@ -98,9 +91,6 @@
<string name="error_loading_image">Impossible de télécharger l\'image (Fichier non trouvé)</string>
<string name="image_offered_for_download"><i>Image proposée au téléchargement.</i></string>
<string name="not_connected">Non connecté</string>
- <string name="you_are_offline">Vous devez être en ligne pour envoyer %s mais votre compte utilisé dans cette conversation est hors-ligne.</string>
- <string name="you_are_offline_blank">Vous devez être en ligne pour réaliser cette action.</string>
- <string name="files">Fichiers</string>
<string name="otr_messages">Messages chiffrés par OTR</string>
<string name="manage_account">Gérer les comptes</string>
<string name="contact_offline">Votre correspondant est hors-ligne.</string>
@@ -126,8 +116,6 @@
<string name="use_pgp_encryption">Utiliser le chiffrement OpenPGP</string>
<string name="pref_xmpp_resource">Ressource XMPP</string>
<string name="pref_xmpp_resource_summary">Nom permettant d\'identifier ce client XMPP</string>
- <string name="pref_accept_files">Accepter les fichiers</string>
- <string name="pref_accept_files_summary">Accepter automatiquement les fichiers plus petits que&#8230;</string>
<string name="pref_notification_settings">Paramètres de notification</string>
<string name="pref_notifications">Notifications</string>
<string name="pref_notifications_summary">Notifier l\'arrivée d\'un message</string>
@@ -159,7 +147,6 @@
<string name="pref_grant_presence_updates">Accepter les mises à jour de présence</string>
<string name="pref_grant_presence_updates_summary">Demander et accepter par avance les mises à jour de présence des contacts créés.</string>
<string name="subscriptions">Publications</string>
- <string name="subscription_updated">Publication mise à jour</string>
<string name="your_account">Votre compte</string>
<string name="keys">Clefs</string>
<string name="send_presence_updates">Envoyer les mises à jour de présence</string>
@@ -184,13 +171,10 @@
<string name="account_status_not_found">Serveur non trouvé</string>
<string name="account_status_no_internet">Aucune connectivité</string>
<string name="account_status_requires_tls">Le serveur requiert TLS</string>
- <string name="account_status_error">Certificat non certifié</string>
<string name="account_status_regis_fail">Enregistrement échoué</string>
<string name="account_status_regis_conflict">Identifiant déjà utilisé</string>
<string name="account_status_regis_success">Enregistrement réussi</string>
<string name="account_status_regis_not_sup">Le serveur ne permet pas l\'enregistrement</string>
- <string name="certif_no_trust">Annuler</string>
- <string name="certif_trust">Croire ce certificat</string>
<string name="encryption_choice_none">Texte clair</string>
<string name="encryption_choice_otr">OTR</string>
<string name="encryption_choice_pgp">OpenPGP</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index bbfa6017..a2064025 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -35,13 +35,7 @@
<string name="show_otr_key">Pegada dactilar OTR</string>
<string name="no_otr_fingerprint">Non hai pegadas dactilares OTR. Continúa e comeza unha conversación cifrada</string>
<string name="start_conversation">Comeza conversa</string>
- <string name="invite_contacts">Invitar contactos</string>
- <string name="invite_contacts_to_existing">Invitar a conferencia existente</string>
- <string name="new_conference">Crear nova conferencia</string>
<string name="cancel">Cancelar</string>
- <string name="create_invite">Crear \u0026 Invitar</string>
- <string name="new_conference_explained">¿Queres crear unha nueva conferencia con unha dirección xerada aleatoriamente e invitar aos contactos seleccionados a ela?</string>
- <string name="no_open_mucs">Non hai conferencias existentes</string>
<string name="invitation_sent">Invitación enviada</string>
<string name="account_offline">Conta desconectada</string>
<string name="cant_invite_while_offline">Debes estar conectado para invitar contactos á conferencia</string>
@@ -65,7 +59,6 @@
<string name="delete_messages">Borrar mensaxes</string>
<string name="also_end_conversation">Terminar esta conversa máis tarde</string>
<string name="choose_presence">Selecciona recurso del contacto</string>
- <string name="send_message_to_conference">Enviar mensaxe a conferencia</string>
<string name="send_plain_text_message">Enviar mensaxe de texto</string>
<string name="send_otr_message">Enviar mensaxe cifrado con OTR</string>
<string name="send_pgp_message">Enviar mensaxe cifrado con OpenPGP</string>
@@ -74,9 +67,6 @@
<string name="error_loading_image">Erro na carga da imaxen (Arquivo non atopado)</string>
<string name="image_offered_for_download"><i>Arquivo de imaxe ofrecido para descarga</i></string>
<string name="not_connected">Non conectado</string>
- <string name="you_are_offline">Debes estar conectado para enviar %s pero a túa conta asociada a esta conversa está desconectada.</string>
- <string name="you_are_offline_blank">Non podes executar esta acción estando desconectado</string>
- <string name="files">arquivos</string>
<string name="otr_messages">Mensaxes cifrados con OTR</string>
<string name="manage_account">Xestionar conta</string>
<string name="contact_offline">O teu contacto está desconectado</string>
@@ -99,8 +89,6 @@
<string name="use_pgp_encryption">Usa cifrado con OpenPGP</string>
<string name="pref_xmpp_resource">Recurso</string>
<string name="pref_xmpp_resource_summary">O nome que identifica o cliente que estás a empregar</string>
- <string name="pref_accept_files">Aceptar arquivos</string>
- <string name="pref_accept_files_summary">De forma automática aceptar arquivos menores de&#8230;</string>
<string name="pref_notification_settings">Axustes de notificación</string>
<string name="pref_notifications">Notificacións</string>
<string name="pref_notifications_summary">Notifica cuando chega unha nova mensaxe</string>
@@ -151,13 +139,10 @@
<string name="account_status_not_found">Servidor non atopado</string>
<string name="account_status_no_internet">Sen conectividade</string>
<string name="account_status_requires_tls">O servidor require TLS</string>
- <string name="account_status_error">Certificado non confiable</string>
<string name="account_status_regis_fail">Erro no rexistro</string>
<string name="account_status_regis_conflict">O identificador xa está en uso</string>
<string name="account_status_regis_success">Rexistro completado</string>
<string name="account_status_regis_not_sup">O servidor non soporta rexistros</string>
- <string name="certif_no_trust">Non conectar</string>
- <string name="certif_trust">Confiar no certificado</string>
<string name="encryption_choice_none">Texto plano</string>
<string name="encryption_choice_otr">OTR</string>
<string name="encryption_choice_pgp">OpenPGP</string>
diff --git a/res/values-nl/arrays.xml b/res/values-nl/arrays.xml
new file mode 100644
index 00000000..1a464a5a
--- /dev/null
+++ b/res/values-nl/arrays.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string-array name="resources">
+ <item>Mobiel</item>
+ <item>Telefoon</item>
+ <item>Tablet</item>
+ <item>Conversaties</item>
+ <item>Android</item>
+ </string-array>
+ <string-array name="filesizes">
+ <item>nooit</item>
+ <item>256 KB</item>
+ <item>512 KB</item>
+ <item>1 MB</item>
+ </string-array>
+ <string-array name="filesizes_values">
+ <item>0</item>
+ <item>262144</item>
+ <item>524288</item>
+ <item>1048576</item>
+ </string-array>
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
new file mode 100644
index 00000000..104cb4b8
--- /dev/null
+++ b/res/values-nl/strings.xml
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">Conversaties</string>
+ <string name="action_settings">Instellingen</string>
+ <string name="action_add">Nieuwe conversatie</string>
+ <string name="action_accounts">Beheer account</string>
+ <string name="action_refresh">Ververs contactenlijst</string>
+ <string name="action_end_conversation">Beëindig conversatie</string>
+ <string name="action_contact_details">Contact details</string>
+ <string name="action_muc_details">Gesprek details</string>
+ <string name="action_secure">Beveiligde conversatie</string>
+ <string name="action_add_account">Voeg account toe</string>
+ <string name="action_edit_contact">Verander naam</string>
+ <string name="action_add_phone_book">Voeg aan telefoonboek toe</string>
+ <string name="action_delete_contact">Verwijder uit lijst</string>
+ <string name="title_activity_contacts">Contacten</string>
+ <string name="title_activity_manage_accounts">Beheer Accounts</string>
+ <string name="title_activity_settings">Instellingen</string>
+ <string name="title_activity_conference_details">Groepsconversatie Details</string>
+ <string name="title_activity_contact_details">Contact Details</string>
+ <string name="title_activity_conversations">Conversaties</string>
+ <string name="title_activity_sharewith">Delen met Conversatie</string>
+ <string name="just_now">net</string>
+ <string name="minute_ago">1 min geleden</string>
+ <string name="minutes_ago">%d min geleden</string>
+ <string name="unread_conversations">ongelezen Conversaties</string>
+ <string name="sending">versturen&#8230;</string>
+ <string name="announce_pgp">Vernieuw PGP aankondiging</string>
+ <string name="encrypted_message">Bericht aan het ontsleutelen. Een moment geduld a.u.b.&#8230;</string>
+ <string name="conference_details">Groepsgesprek Details</string>
+ <string name="nick_in_use">Naam is al in gebruik</string>
+ <string name="admin">Beheerder</string>
+ <string name="owner">Eigenaar</string>
+ <string name="moderator">Moderator</string>
+ <string name="participant">Deelnemer</string>
+ <string name="visitor">Bezoeker</string>
+ <string name="enter_new_name">Voer een nieuwe naam in:</string>
+ <string name="remove_contact_text">Wilt u %s uit uw lijst verwijderen? De conversatie met deze account zal niet worden verwijderd.</string>
+ <string name="untrusted_cert_hint">De server %s gebruikte een onvertrouwd, mogelijk zelfgetekend, certificaat.</string>
+ <string name="account_info">Server Informatie</string>
+ <string name="register_account">Registreer nieuwe account op server</string>
+ <string name="share_with">Deel met</string>
+ <string name="ask_again"><u>Klik om opnieuw te vragen</u></string>
+ <string name="show_otr_key">OTR vingerafdruk</string>
+ <string name="no_otr_fingerprint">Geen OTR vingerafdruk gegenereerd. Start simpelweg een versleutelde conversatie</string>
+ <string name="start_conversation">Start Conversatie</string>
+ <string name="contacts">Contacten</string>
+ <string name="search_jabber_id">Zoek of voer Jabber ID in</string>
+ <string name="choose_account">Kies account</string>
+ <string name="multi_user_conference">Groepsconversatie met meerdere gebruikers</string>
+ <string name="trying_join_conference">Probeert U aan een groepsconversatie deel te nemen?</string>
+ <string name="cancel">Annuleer</string>
+ <string name="add">Voeg toe</string>
+ <string name="edit">Bewerk</string>
+ <string name="delete">Verwijder</string>
+ <string name="save">Sla op</string>
+ <string name="yes">Ja</string>
+ <string name="no">Nee</string>
+ <string name="ok">OK</string>
+ <string name="done">Klaar</string>
+ <string name="hide">Verberg</string>
+ <string name="invitation_sent">Uitnodiging verstuurd</string>
+ <string name="account_offline">Account niet verbonden</string>
+ <string name="cant_invite_while_offline">U moet online zijn om mensen uit te nodigen tot een groepsconversatie</string>
+ <string name="crash_report_title">Conversaties is gecrashed</string>
+ <string name="crash_report_message">Door het versturen van crash rapportages helpt u mee met de ontwikkeling van Conversaties.\n<b>Waarschuwing:</b> Deze app zal uw XMPP account gebruiken om de crash rapportages te versturen naar de ontwikkelaars.</string>
+ <string name="send_now">Nu versturen</string>
+ <string name="send_never">Niet opnieuw vragen</string>
+ <string name="problem_connecting_to_account">Account verbinden mislukt</string>
+ <string name="problem_connecting_to_accounts">Verbinden met meerdere accounts mislukt</string>
+ <string name="touch_to_fix">Raak hier aan om accounts te beheren</string>
+ <string name="attach_file">Voeg bestand bij</string>
+ <string name="not_in_roster">Het contact is geen onderdeel van uw lijst. Wilt u het toevoegen?</string>
+ <string name="add_contact">Voeg contact toe</string>
+ <string name="send_failed">afleveren mislukt</string>
+ <string name="send_rejected">geweigerd</string>
+ <string name="receiving_image">Bezig met ontvangen van afbeelding. Een moment geduld a.u.b.&#8230;</string>
+ <string name="preparing_image">Bezig met voorbereiden van het versturen van afbeelding</string>
+ <string name="action_clear_history">Wis geschiedenis</string>
+ <string name="clear_conversation_history">Wis conversatie geschiedenis</string>
+ <string name="clear_histor_msg">Wilt U alle berichten in deze Conversatie verwijderen?\n\n<b>Waarschuwing:</b> Dit zal geen invloed hebben op de berichten opgeslagen op andere apparaten of servers.</string>
+ <string name="delete_messages">Verwijder berichten</string>
+ <string name="also_end_conversation">Beëindig deze conversatie na afloop</string>
+ <string name="choose_presence">Kies aanwezigheid om te tonen aan contact</string>
+ <string name="send_plain_text_message">Verstuur eenvoudig tekst bericht</string>
+ <string name="send_otr_message">Verstuur OTR versleuteld bericht</string>
+ <string name="send_pgp_message">Verstuur OpenPGP versleuteld bericht</string>
+ <string name="your_nick_has_been_changed">Uw naam is veranderd</string>
+ <string name="download_image">Download Afbeelding</string>
+ <string name="error_loading_image">Fout tijdens laden van afbeelding (Bestand niet gevonden)</string>
+ <string name="image_offered_for_download"><i>Afbeelding aangeboden voor downloaden</i></string>
+ <string name="not_connected">Niet Verbonden</string>
+ <string name="otr_messages">OTR versleutelde berichten</string>
+ <string name="manage_account">Beheer account</string>
+ <string name="contact_offline">Uw Contact is Offline</string>
+ <string name="contact_offline_otr">Het versturen van OTR versleutelde berichten aan offline contacten wordt helaas niet ondersteund.\nWilt u het bericht onversleuteld versturen?</string>
+ <string name="contact_offline_file">Het versturen van breichten aan offline contacten wordt helaas niet ondersteund.</string>
+ <string name="send_unencrypted">Verstuur onversleuteld</string>
+ <string name="decryption_failed">Ontsleutelen mislukt. Misschien hebt U niet de juiste private sleutel.</string>
+ <string name="openkeychain_required">OpenKeychain</string>
+ <string name="openkeychain_required_long">Conversaties gebruikt een derde partij app genaamd <b>OpenKeychain</b> om berichten te versleutelen en ontsleutelen, en om publieke sleutels te beheren.\n\nOpenKeychain is beschikbaar onder de GPLv3 en beschikbaar op F-Droid en Google Play.\n\n<small>(Herstart Conversaties na installatie.)</small></string>
+ <string name="restart">Herstart</string>
+ <string name="install">Installeer</string>
+ <string name="offering">offering&#8230;</string>
+ <string name="waiting">wachten&#8230;</string>
+ <string name="no_pgp_key">Geen OpenPGP sleutel gevonden</string>
+ <string name="contact_has_no_pgp_key">Conversaties kan Uw berichten niet versleutelen omdat uw contact geen publieke sleutel heeft ingesteld.\n\n<small>Vraag uw contact om OpenPGP te configureren.</small></string>
+ <string name="no_pgp_keys">Geen OpenPGP sleutels gevonden</string>
+ <string name="contacts_have_no_pgp_keys">Conversaties kan uw berichten niet versleutelen omdat uw contacten geen publieke sleutel hebben ingesteld.\n\n<small>Vraag uw contacten om OpenPGP te configureren.</small></string>
+ <string name="encrypted_message_received"><i>Versleuteld bericht ontvangen. Raak aan om te bekijken en te ontsleutelen.</i></string>
+ <string name="encrypted_image_received"><i>Versleutelde afbeelding ontvangen. Raak aan om te bekijken en te ontsleutelen.</i></string>
+ <string name="image_file"><i>Afbeelding ontvangen. Raak aan om te bekijken.</i></string>
+ <string name="otr_file_transfer">OTR versleuteling niet beschikbaar.</string>
+ <string name="otr_file_transfer_msg">Helaas is OTR versleuteling niet beschikbaar voor bestandsoverdracht. Kies OpenPGP versleuteling of geen versleuteling.</string>
+ <string name="use_pgp_encryption">Gebruik OpenPGP versleuteling</string>
+ <string name="pref_xmpp_resource">XMPP resource</string>
+ <string name="pref_xmpp_resource_summary">De naam waarmee deze client zich identificeert</string>
+ <string name="pref_notification_settings">Notificatie Instellingen</string>
+ <string name="pref_notifications">Notificaties</string>
+ <string name="pref_notifications_summary">Notificatie als een nieuw bericht arriveert</string>
+ <string name="pref_vibrate">Trillen</string>
+ <string name="pref_vibrate_summary">Tril ook wanneer een nieuw bericht arriveert</string>
+ <string name="pref_sound">Geluid</string>
+ <string name="pref_sound_summary">Speel ringtone af bij notificatie</string>
+ <string name="pref_conference_notifications">Groepsconversatie notificaties</string>
+ <string name="pref_conference_notifications_summary">Toon altijd notificaties als er nieuwe berichten arriveren in groepsconversaties in plaats van alleen bij highlighting</string>
+ <string name="pref_notification_grace_period">Notificatie uitstel periode</string>
+ <string name="pref_notification_grace_period_summary">Zet notificaties voor korte tijd uit als er een carbon copy wordt ontvangen</string>
+ <string name="pref_ui_options">UI Opties</string>
+ <string name="pref_use_phone_self_picture">Gebruik eigen afbeelding van telefoon</string>
+ <string name="pref_use_phone_self_picture_summary">Het is mogelijk niet meer duidelijk welke account U gebruikt in conversaties</string>
+ <string name="pref_conference_name">Groepsconversatie naam</string>
+ <string name="pref_conference_name_summary">Gebruik onderwerp van kamer om groepsconversaties te identificeren</string>
+ <string name="pref_advanced_options">Geadvanceerde Opties</string>
+ <string name="pref_never_send_crash">Verstuur nooit crash rapportages</string>
+ <string name="pref_never_send_crash_summary">Door crash rapportages te versturen helpt U mee aan de ontwikkeling van Conversaties</string>
+ <string name="pref_confirm_messages">Bevestig Berichten</string>
+ <string name="pref_confirm_messages_summary">Laat uw contacten weten waneer U berichten hebt ontvangen en gelezen</string>
+ <string name="pref_show_last_seen">Toon voor het laatst gezien</string>
+ <string name="pref_show_last_seen_summary">Laat de tijd zien dat uw contact voor het laatst online gezien is</string>
+ <string name="openpgp_error">OpenKeychain rapporteerde een fout</string>
+ <string name="error_decrypting_file">I/O Fout tijdens ontsleutelen bestand</string>
+ <string name="error_copying_image_file">Fout tijdens kopiëren van afbeelding.</string>
+ <string name="accept">Accepteer</string>
+ <string name="error">Er is een fout opgetreden</string>
+ <string name="pref_grant_presence_updates">Verleen toestemming voor aanwezigheid updates</string>
+ <string name="pref_grant_presence_updates_summary">Vantevoren toestemming verlenen en vragen aan contacten die U hebt aangemaakt</string>
+ <string name="subscriptions">Abonnementen</string>
+ <string name="your_account">Uw account</string>
+ <string name="keys">Sleutels</string>
+ <string name="send_presence_updates">Verstuur aanwezigheid updates</string>
+ <string name="receive_presence_updates">Ontvang aanwezigheid updates</string>
+ <string name="ask_for_presence_updates">Vraag naar aanwezigheid updates</string>
+ <string name="asked_for_presence_updates">Gevraagd om aanwezigheid updates</string>
+ <string name="attach_choose_picture">Kies afbeelding</string>
+ <string name="attach_take_picture">Neem foto</string>
+ <string name="preemptively_grant">Vantevoren toestemming verlenen voor abonneren</string>
+ <string name="error_not_an_image_file">Het bestand dat U gekozen hebt is geen afbeelding</string>
+ <string name="error_compressing_image">Fout tijdens converteren van afbeelding</string>
+ <string name="error_file_not_found">Bestand niet gevonden</string>
+ <string name="error_io_exception">Generieke I/O fout. Misschien is er geen opslagruimte meer beschikbaar?</string>
+ <string name="error_security_exception_during_image_copy">De app die U gebruikte om de afbeelding te selecteren heeft niet voldoende toegang geleverd om het bestand te lezen.\n\n<small>Gebruik een andere app om een afbeelding te kiezen</small></string>
+ <string name="account_status">Status:</string>
+ <string name="account_status_unknown">Onbekend</string>
+ <string name="account_status_disabled">Tijdelijk uitgezet</string>
+ <string name="account_status_online">Online</string>
+ <string name="account_status_connecting">Verbinden\u2026</string>
+ <string name="account_status_offline">Offline</string>
+ <string name="account_status_unauthorized">Niet gemachtigd</string>
+ <string name="account_status_not_found">Server niet gevonden</string>
+ <string name="account_status_no_internet">Geen verbinding</string>
+ <string name="account_status_requires_tls">Server vereist TLS</string>
+ <string name="account_status_regis_fail">Registratie mislukt</string>
+ <string name="account_status_regis_conflict">Gebruikersnaam bezet</string>
+ <string name="account_status_regis_success">Registratie compleet</string>
+ <string name="account_status_regis_not_sup">Server ondersteunt geen registratie</string>
+ <string name="encryption_choice_none">Onversleuteld</string>
+ <string name="encryption_choice_otr">OTR</string>
+ <string name="encryption_choice_pgp">OpenPGP</string>
+ <string name="mgmt_account_edit">Bewerk account</string>
+ <string name="mgmt_account_delete">Verwijder</string>
+ <string name="mgmt_account_disable">Tijdelijk uitzetten</string>
+ <string name="mgmt_account_enable">Aanzetten</string>
+ <string name="mgmt_account_are_you_sure">Weet U het zeker?</string>
+ <string name="mgmt_account_delete_confirm_text">Als U uw account verwijderd wordt Uw volledige conversatie geschiedenis gewist</string>
+ <string name="mgmt_account_account_offline">Account is offline</string>
+ <string name="attach_record_voice">Neem stem op</string>
+ <string name="account_settings">Account Instellingen</string>
+ <string name="account_settings_jabber_id">Jabber ID:</string>
+ <string name="account_settings_password">Wachtwoord:</string>
+ <string name="account_settings_example_jabber_id">gebruikersnaam@voorbeeld.nl</string>
+ <string name="account_settings_confirm_password">Bevestig wachtwoord:</string>
+ <string name="password">Wachtwoord</string>
+ <string name="confirm_password">Bevestig wachtwoord</string>
+ <string name="passwords_do_not_match">Wachtwoorden komen niet overeen</string>
+ <string name="invalid_jid">Dit is geen geldig Jabber ID</string>
+ <string name="error_out_of_memory">Geen geheugen beschikbaar. Afbeelding is te groot</string>
+ <string name="add_phone_book_text">Wilt U %s toevoegen aan de contactenlijst op uw telefoon?</string>
+ <string name="contact_status_online">online</string>
+ <string name="contact_status_free_to_chat">beschikbaar</string>
+ <string name="contact_status_away">weg</string>
+ <string name="contact_status_extended_away">langdurig weg</string>
+ <string name="contact_status_do_not_disturb">niet storen</string>
+ <string name="contact_status_offline">offline</string>
+ <string name="muc_details_conference">groepsconversatie</string>
+ <string name="muc_details_conference_subject">Groepsconversatie Onderwerp</string>
+ <string name="muc_details_your_nickname">Uw naam</string>
+ <string name="muc_details_other_members">Andere Leden</string>
+ <string name="subscription_not_updated_offline">Account offline. Kon abonnement niet vernieuwen</string>
+ <string name="share_with_active_conversations">Actieve Conversaties</string>
+ <string name="server_info_statistics">Statistieken</string>
+ <string name="server_info_connection_age">Verbindingsduur</string>
+ <string name="server_info_session_age">Sessieduur</string>
+ <string name="server_info_packets_sent">Paketten verstuurd</string>
+ <string name="server_info_packets_received">Paketten ontvangen</string>
+ <string name="server_info_connected_accounts">Verbonden accounts</string>
+ <string name="server_info_server_features">Server Kenmerken</string>
+ <string name="server_info_roster_versioning">Roster Versioning</string>
+ <string name="server_info_carbon_messages">Carbon Berichten</string>
+ <string name="server_info_stream_management">Stream Management</string>
+ <string name="hours">uren</string>
+ <string name="mins">min</string>
+ <string name="missing_public_keys">Ontbrekende publieke sleutel aankondigingen</string>
+ <string name="last_seen_now">zonet voor het laatst gezien</string>
+ <string name="last_seen_min">1 minuut geleden voor het laatst gezien</string>
+ <string name="last_seen_mins">%d minuten geleden voor het laatst gezien</string>
+ <string name="last_seen_hour">1 uur geleden voor het laatst gezien</string>
+ <string name="last_seen_hours">%d uur geleden voor het laatst gezien</string>
+ <string name="last_seen_day">1 dag geleden voor het laatst gezien</string>
+ <string name="last_seen_days">%d dagen geleden voor het laatst gezien</string>
+ <string name="never_seen">nog nooit gezien</string>
+ <string name="install_openkeychain">Versleuteld bericht. Installeer OpenKeychain om te ontsleutelen.</string>
+ <string name="unknown_otr_fingerprint">Onbekende OTR vingerafdruk</string>
+ <string name="edit_conference_details">Touch to edit conference details</string>
+ <string name="openpgp_messages_found">OpenPGP encrypted messages found</string>
+ <string name="openpgp_click_to_decrypt">Raak hier aan om het wachtwoord in te voeren het bericht te ontsleutelen</string>
+ <string name="reception_failed">Ontvangen mislukt</string>
+ <string name="no_muc_server_found">Geen geschikte Groepsconversatie Server gevonden</string>
+</resources>
diff --git a/res/values-nl/styles.xml b/res/values-nl/styles.xml
new file mode 100644
index 00000000..1468283e
--- /dev/null
+++ b/res/values-nl/styles.xml
@@ -0,0 +1,19 @@
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <style name="sectionHeader" parent="android:Widget.Holo.Light.TextView">
+ <item name="android:drawableBottom">@drawable/section_header</item>
+ <item name="android:drawablePadding">4dp</item>
+ <item name="android:layout_marginTop">8dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textAllCaps">true</item>
+ <item name="android:textColor">#5b5b5b</item>
+ <item name="android:textStyle">bold</item>
+ </style>
+
+ <style name="Divider">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">1.5dp</item>
+ <item name="android:background">#b7b7b7</item>
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 7ef9f67c..c6d954dc 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
-
<string name="invite_contact">Пригласить собеседника</string>
<string name="you">Вы</string>
<string name="conference_not_found">Конференция не найдена</string>
@@ -13,7 +12,6 @@
<string name="leave">Покинуть</string>
<string name="add_back">Добавить в ответ</string>
<string name="contact_has_read_up_to_this_point">%s видела сообщения до этого момента</string>
-
<string name="app_name">Conversations</string>
<string name="action_settings">Настройки</string>
<string name="action_add">Новая беседа</string>
@@ -59,10 +57,6 @@
<string name="show_otr_key">Контрольная сумма криптографического протокола OTR</string>
<string name="no_otr_fingerprint">Нет созданных контрольных сумм криптографического протокола OTR. Просто начните новую зашифрованную беседу</string>
<string name="start_conversation">Начать Беседу</string>
- <string name="invite_contacts">Пригласить Пользователя</string>
- <string name="invite_contacts_to_existing">Пригласить пользователя в существующую конференцию</string>
- <string name="new_conference">Создать новую конференцию</string>
- <string name="new_contact">Создать новый контакт</string>
<string name="contacts">Контакты</string>
<string name="search_jabber_id">Укажите уникальный идентификатор пользователя JID (Джаббер ID)</string>
<string name="choose_account">Выберите аккаунт</string>
@@ -78,9 +72,6 @@
<string name="ok">ОК</string>
<string name="done">Готово</string>
<string name="hide">Спрятать</string>
- <string name="create_invite">Создать \u0026 Пригласить</string>
- <string name="new_conference_explained">Вы хотите создать новую конференцию со случайным адресом и пригласить туда выбранных пользователей?</string>
- <string name="no_open_mucs">Нет существующих конференций</string>
<string name="invitation_sent">Приглашение отправлено</string>
<string name="account_offline">Аккаунт не в сети</string>
<string name="cant_invite_while_offline">Вы должны быть в сети, чтобы пригласить пользователей в конференцию</string>
@@ -137,8 +128,6 @@
<string name="use_pgp_encryption">Использовать OpenPGP шифрование</string>
<string name="pref_xmpp_resource">XMPP ресурс</string>
<string name="pref_xmpp_resource_summary">Имя, которым Conversations идентифицирует себя</string>
- <string name="pref_accept_files">Принимать файлы</string>
- <string name="pref_accept_files_summary">Автоматически принимать файлы размером меньше&#8230;</string>
<string name="pref_notification_settings">Настройки Уведомлений</string>
<string name="pref_notifications">Уведомление</string>
<string name="pref_notifications_summary">Уведомлять когда приходят новые сообщения</string>
@@ -170,7 +159,6 @@
<string name="pref_grant_presence_updates">Предоставлять обновления присутствия</string>
<string name="pref_grant_presence_updates_summary">Разрешить и запрашивать статус присутствия для созданных вами контактов</string>
<string name="subscriptions">Подписки</string>
- <string name="subscription_updated">Подписка обновлена</string>
<string name="your_account">Ваш аккаунт</string>
<string name="keys">Ключи</string>
<string name="send_presence_updates">Анонсировать статус присутствия</string>
@@ -195,13 +183,10 @@
<string name="account_status_not_found">Сервер не найден</string>
<string name="account_status_no_internet">Нет соединения</string>
<string name="account_status_requires_tls">Сервер требует использования криптографического протокола TLS</string>
- <string name="account_status_error">Неподтвержденный сертификат</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="certif_no_trust">Не подключаться</string>
- <string name="certif_trust">Принять сертификат</string>
<string name="encryption_choice_none">Без шифрования</string>
<string name="encryption_choice_otr">OTR</string>
<string name="encryption_choice_pgp">OpenPGP</string>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 4ede1c10..b6477939 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
+ <color name="primary" type="color">#ff259b24</color>
+ <color name="primarydark" type="color">#ff0a7e07</color>
<color name="primarytext" type="color">#de000000</color>
<color name="secondarytext" type="color">#8a000000</color>
<color name="ondarktext" type="color">#fffafafa</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 10a3f0e2..c636be79 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -22,6 +22,7 @@
<string name="title_activity_conversations">Conversations</string>
<string name="title_activity_sharewith">Share with Conversation</string>
<string name="title_activity_start_conversation">Start Conversation</string>
+ <string name="title_activity_choose_contact">Choose contact</string>
<string name="just_now">just now</string>
<string name="minute_ago">1 min ago</string>
<string name="minutes_ago">%d mins ago</string>
@@ -37,19 +38,17 @@
<string name="participant">Participant</string>
<string name="visitor">Visitor</string>
<string name="enter_new_name">Enter a new name:</string>
- <string name="remove_contact_text">Do you want to delete %s from your roster? The conversation associated with this account will not be removed.</string>
+ <string name="remove_contact_text">Would you like to remove %s from your roster? The conversation associated with this contact will not be removed.</string>
+ <string name="remove_bookmark_text">Would you like to remove %s as a bookmark? The conversation associated with this bookmark will not be removed.</string>
<string name="untrusted_cert_hint">The server %s presented you with an untrusted, possible self signed, certificate.</string>
<string name="account_info">Server Info</string>
<string name="register_account">Register new account on server</string>
<string name="share_with">Share with</string>
<string name="ask_again"><u>Click to ask again</u></string>
<string name="show_otr_key">OTR fingerprint</string>
- <string name="no_otr_fingerprint">No OTR Fingerprint generated. Just go ahead an start an encrypted conversation</string>
+ <string name="no_otr_fingerprint">No OTR Fingerprint generated. Just go ahead and start an encrypted conversation</string>
<string name="start_conversation">Start Conversation</string>
- <string name="invite_contacts">Invite Contacts</string>
- <string name="invite_contacts_to_existing">Invite to existing conference</string>
- <string name="new_conference">Create new conference</string>
- <string name="new_contact">Create new contact</string>
+ <string name="invite_contact">Invite Contact</string>
<string name="contacts">Contacts</string>
<string name="search_jabber_id">Search or enter Jabber ID</string>
<string name="choose_account">Choose account</string>
@@ -65,9 +64,6 @@
<string name="ok">OK</string>
<string name="done">Done</string>
<string name="hide">Hide</string>
- <string name="create_invite">Create \u0026 Invite</string>
- <string name="new_conference_explained">Do you want to create a new conference with a randomly generated address and invite the selected contacts to it?</string>
- <string name="no_open_mucs">No existing conferences</string>
<string name="invitation_sent">Invitation sent</string>
<string name="account_offline">Account offline</string>
<string name="cant_invite_while_offline">You have to be online to invite people to conferences</string>
@@ -149,7 +145,7 @@
<string name="pref_confirm_messages_summary">Let your contact know when you have received and read a message</string>
<string name="pref_show_last_seen">Display last seen</string>
<string name="pref_show_last_seen_summary">Display the latest time a contact has been seen online</string>
- <string name="openpgp_error">OpenKeychain reporeted an error</string>
+ <string name="openpgp_error">OpenKeychain reported an error</string>
<string name="error_decrypting_file">I/O Error decrypting file</string>
<string name="error_copying_image_file">Error copying image file.</string>
<string name="accept">Accept</string>
@@ -157,7 +153,6 @@
<string name="pref_grant_presence_updates">Grant presence updates</string>
<string name="pref_grant_presence_updates_summary">Preemptively grant and ask for presence subscription for contacts you created</string>
<string name="subscriptions">Subscriptions</string>
- <string name="subscription_updated">Subscription updated</string>
<string name="your_account">Your account</string>
<string name="keys">Keys</string>
<string name="send_presence_updates">Send presence updates</string>
@@ -182,13 +177,10 @@
<string name="account_status_not_found">Server not found</string>
<string name="account_status_no_internet">No connectivity</string>
<string name="account_status_requires_tls">Server requires TLS</string>
- <string name="account_status_error">Untrusted cerficate</string>
<string name="account_status_regis_fail">Registration failed</string>
<string name="account_status_regis_conflict">Username already in use</string>
<string name="account_status_regis_success">Registration completed</string>
<string name="account_status_regis_not_sup">Server does not support registration</string>
- <string name="certif_no_trust">Don\'t connect</string>
- <string name="certif_trust">Trust certificate</string>
<string name="encryption_choice_none">Plain text</string>
<string name="encryption_choice_otr">OTR</string>
<string name="encryption_choice_pgp">OpenPGP</string>
@@ -269,4 +261,11 @@
<string name="save_as_bookmark">Save as bookmark</string>
<string name="delete_bookmark">Delete bookmark</string>
<string name="bookmark_already_exists">This bookmark already exists</string>
+ <string name="you">You</string>
+ <string name="action_edit_subject">Edit conference subject</string>
+ <string name="conference_not_found">Conference not found</string>
+ <string name="leave">Leave</string>
+ <string name="contact_added_you">Contact added you to contact list</string>
+ <string name="add_back">Add back</string>
+ <string name="contact_has_read_up_to_this_point">%s has read up to this point</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 1468283e..a827fe36 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -6,14 +6,14 @@
<item name="android:layout_marginTop">8dp</item>
<item name="android:textSize">14sp</item>
<item name="android:textAllCaps">true</item>
- <item name="android:textColor">#5b5b5b</item>
+ <item name="android:textColor">@color/primarytext</item>
<item name="android:textStyle">bold</item>
</style>
<style name="Divider">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">1.5dp</item>
- <item name="android:background">#b7b7b7</item>
+ <item name="android:background">@color/divider</item>
</style>
</resources> \ No newline at end of file
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 0c4ddc39..97f1db8f 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -8,8 +8,8 @@
</style>
<style name="ConversationsActionBar" parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
- <item name="android:background">#259b24</item>
- <item name="android:backgroundStacked">#0a7e07</item>
+ <item name="android:background">@color/primary</item>
+ <item name="android:backgroundStacked">@color/primarydark</item>
<item name="android:displayOptions">showHome|homeAsUp|showTitle</item>
<item name="android:icon">@android:color/transparent</item>
</style>
diff --git a/src/eu/siacs/conversations/entities/AbstractEntity.java b/src/eu/siacs/conversations/entities/AbstractEntity.java
index 0297fa66..4891723e 100644
--- a/src/eu/siacs/conversations/entities/AbstractEntity.java
+++ b/src/eu/siacs/conversations/entities/AbstractEntity.java
@@ -1,12 +1,9 @@
package eu.siacs.conversations.entities;
-import java.io.Serializable;
-
import android.content.ContentValues;
-public abstract class AbstractEntity implements Serializable {
+public abstract class AbstractEntity {
- private static final long serialVersionUID = -1895605706690653719L;
public static final String UUID = "uuid";
diff --git a/src/eu/siacs/conversations/entities/Account.java b/src/eu/siacs/conversations/entities/Account.java
index ac62cf7b..b19889bf 100644
--- a/src/eu/siacs/conversations/entities/Account.java
+++ b/src/eu/siacs/conversations/entities/Account.java
@@ -4,6 +4,7 @@ import java.security.interfaces.DSAPublicKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.CopyOnWriteArrayList;
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
import net.java.otr4j.crypto.OtrCryptoException;
@@ -18,8 +19,6 @@ import android.content.Context;
import android.database.Cursor;
public class Account extends AbstractEntity{
-
- private static final long serialVersionUID = 6174825093869578035L;
public static final String TABLENAME = "accounts";
@@ -41,7 +40,6 @@ public class Account extends AbstractEntity{
public static final int STATUS_ONLINE = 1;
public static final int STATUS_NO_INTERNET = 2;
public static final int STATUS_UNAUTHORIZED = 3;
- public static final int STATUS_TLS_ERROR = 4;
public static final int STATUS_SERVER_NOT_FOUND = 5;
public static final int STATUS_SERVER_REQUIRES_TLS = 6;
@@ -72,6 +70,9 @@ public class Account extends AbstractEntity{
private List<Bookmark> bookmarks = new ArrayList<Bookmark>();
+ public List<Conversation> pendingConferenceJoins = new CopyOnWriteArrayList<Conversation>();
+ public List<Conversation> pendingConferenceLeaves = new CopyOnWriteArrayList<Conversation>();
+
public Account() {
this.uuid = "0";
}
diff --git a/src/eu/siacs/conversations/entities/Bookmark.java b/src/eu/siacs/conversations/entities/Bookmark.java
index c4e151cb..38c03410 100644
--- a/src/eu/siacs/conversations/entities/Bookmark.java
+++ b/src/eu/siacs/conversations/entities/Bookmark.java
@@ -122,4 +122,10 @@ public class Bookmark implements ListItem {
}
return element;
}
+
+ public void unregisterConversation() {
+ if (this.mJoinedConversation != null) {
+ this.mJoinedConversation.deregisterWithBookmark();
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java
index 70752adc..76fe84cf 100644
--- a/src/eu/siacs/conversations/entities/Conversation.java
+++ b/src/eu/siacs/conversations/entities/Conversation.java
@@ -16,9 +16,6 @@ import android.database.Cursor;
import android.net.Uri;
public class Conversation extends AbstractEntity {
-
- private static final long serialVersionUID = -6727528868973996739L;
-
public static final String TABLENAME = "conversations";
public static final int STATUS_AVAILABLE = 0;
@@ -117,7 +114,7 @@ public class Conversation extends AbstractEntity {
this.messages.get(i).markRead();
}
}
-
+
public String popLatestMarkableMessageId() {
String id = this.latestMarkableMessageId;
this.latestMarkableMessageId = null;
@@ -144,7 +141,8 @@ public class Conversation extends AbstractEntity {
if ((getMode() == MODE_MULTI) && (getMucOptions().getSubject() != null)
&& useSubject) {
return getMucOptions().getSubject();
- } else if (getMode() == MODE_MULTI && bookmark!=null && bookmark.getName() != null) {
+ } else if (getMode() == MODE_MULTI && bookmark != null
+ && bookmark.getName() != null) {
return bookmark.getName();
} else {
return this.getContact().getDisplayName();
@@ -241,7 +239,7 @@ public class Conversation extends AbstractEntity {
this.otrSessionNeedsStarting = false;
return this.otrSession;
} else {
- this.otrSessionNeedsStarting = true;
+ this.otrSessionNeedsStarting = true;
}
return this.otrSession;
} catch (OtrException e) {
@@ -270,7 +268,7 @@ public class Conversation extends AbstractEntity {
}
}
}
-
+
public void endOtrIfNeeded() {
if (this.otrSession != null) {
if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
@@ -293,6 +291,9 @@ public class Conversation extends AbstractEntity {
public String getOtrFingerprint() {
if (this.otrFingerprint == null) {
try {
+ if (getOtrSession()== null) {
+ return "";
+ }
DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
.getRemotePublicKey();
StringBuilder builder = new StringBuilder(
@@ -375,7 +376,7 @@ public class Conversation extends AbstractEntity {
public void setSymmetricKey(byte[] key) {
this.symmetricKey = key;
}
-
+
public byte[] getSymmetricKey() {
return this.symmetricKey;
}
@@ -384,7 +385,7 @@ public class Conversation extends AbstractEntity {
this.bookmark = bookmark;
this.bookmark.setConversation(this);
}
-
+
public void deregisterWithBookmark() {
if (this.bookmark != null) {
this.bookmark.setConversation(null);
diff --git a/src/eu/siacs/conversations/entities/Message.java b/src/eu/siacs/conversations/entities/Message.java
index 8e669c65..49c5ce58 100644
--- a/src/eu/siacs/conversations/entities/Message.java
+++ b/src/eu/siacs/conversations/entities/Message.java
@@ -7,8 +7,6 @@ import android.content.Context;
import android.database.Cursor;
public class Message extends AbstractEntity {
-
- private static final long serialVersionUID = 7222081895167103025L;
public static final String TABLENAME = "messages";
diff --git a/src/eu/siacs/conversations/entities/MucOptions.java b/src/eu/siacs/conversations/entities/MucOptions.java
index 0f8e3565..0bb9b295 100644
--- a/src/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/eu/siacs/conversations/entities/MucOptions.java
@@ -10,7 +10,9 @@ import android.annotation.SuppressLint;
@SuppressLint("DefaultLocale")
public class MucOptions {
+ public static final int ERROR_NO_ERROR = 0;
public static final int ERROR_NICK_IN_USE = 1;
+ public static final int ERROR_ROOM_NOT_FOUND = 2;
public interface OnRenameListener {
public void onRename(boolean success);
@@ -82,11 +84,12 @@ public class MucOptions {
private ArrayList<User> users = new ArrayList<User>();
private Conversation conversation;
private boolean isOnline = false;
- private int error = 0;
+ private int error = ERROR_ROOM_NOT_FOUND;
private OnRenameListener renameListener = null;
private boolean aboutToRename = false;
private User self = new User();
private String subject = null;
+ private String joinnick;
public MucOptions(Account account) {
this.account = account;
@@ -123,10 +126,16 @@ public class MucOptions {
user.setAffiliation(item.getAttribute("affiliation"));
user.setRole(item.getAttribute("role"));
user.setName(name);
- if (name.equals(getNick())) {
+ if (name.equals(this.joinnick)) {
this.isOnline = true;
- this.error = 0;
+ this.error = ERROR_NO_ERROR;
self = user;
+ if (aboutToRename) {
+ if (renameListener!=null) {
+ renameListener.onRename(true);
+ }
+ aboutToRename = false;
+ }
} else {
addUser(user);
}
@@ -145,17 +154,6 @@ public class MucOptions {
}
}
} else if (type.equals("unavailable")) {
- if (name.equals(getNick())) {
- Element item = packet.findChild("x","http://jabber.org/protocol/muc#user").findChild("item");
- String nick = item.getAttribute("nick");
- if (nick!=null) {
- aboutToRename = false;
- if (renameListener!=null) {
- renameListener.onRename(true);
- }
- this.setNick(nick);
- }
- }
deleteUser(packet.getAttribute("from").split("/")[1]);
} else if (type.equals("error")) {
Element error = packet.findChild("error");
@@ -165,6 +163,7 @@ public class MucOptions {
renameListener.onRename(false);
}
aboutToRename = false;
+ this.setJoinNick(getActualNick());
} else {
this.error = ERROR_NICK_IN_USE;
}
@@ -177,22 +176,29 @@ public class MucOptions {
return this.users;
}
- public String getNick() {
- String[] split = conversation.getContactJid().split("/");
- if (split.length == 2) {
- return split[1];
+ public String getProposedNick() {
+ String[] mucParts = conversation.getContactJid().split("/");
+ if (conversation.getBookmark() != null && conversation.getBookmark().getNick() != null) {
+ return conversation.getBookmark().getNick();
} else {
- if (conversation.getAccount()!=null) {
- return conversation.getAccount().getUsername();
+ if (mucParts.length == 2) {
+ return mucParts[1];
} else {
- return null;
+ return account.getUsername();
}
}
}
- public void setNick(String nick) {
- String jid = conversation.getContactJid().split("/")[0]+"/"+nick;
- conversation.setContactJid(jid);
+ public String getActualNick() {
+ if (this.self.getName()!=null) {
+ return this.self.getName();
+ } else {
+ return this.getProposedNick();
+ }
+ }
+
+ public void setJoinNick(String nick) {
+ this.joinnick = nick;
}
public void setConversation(Conversation conversation) {
@@ -268,4 +274,8 @@ public class MucOptions {
}
return true;
}
+
+ public String getJoinJid() {
+ return this.conversation.getContactJid().split("/")[0]+"/"+this.joinnick;
+ }
} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/generator/AbstractGenerator.java b/src/eu/siacs/conversations/generator/AbstractGenerator.java
new file mode 100644
index 00000000..49b5d614
--- /dev/null
+++ b/src/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -0,0 +1,49 @@
+package eu.siacs.conversations.generator;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import android.util.Base64;
+
+public abstract class AbstractGenerator {
+ public final String[] FEATURES = { "urn:xmpp:jingle:1",
+ "urn:xmpp:jingle:apps:file-transfer:3",
+ "urn:xmpp:jingle:transports:s5b:1",
+ "urn:xmpp:jingle:transports:ibb:1",
+ "urn:xmpp:receipts",
+ "urn:xmpp:chat-markers:0",
+ "http://jabber.org/protocol/muc",
+ "jabber:x:conference",
+ "http://jabber.org/protocol/caps",
+ "http://jabber.org/protocol/disco#info"};
+ //public final String[] FEATURES = { "http://jabber.org/protocol/muc","http://jabber.org/protocol/disco#info", "http://jabber.org/protocol/disco#items", "http://jabber.org/protocol/caps" };
+
+ //public final String IDENTITY_NAME = "Exodus 0.9.1";
+ //public final String IDENTITY_TYPE = "pc";
+
+
+ public final String IDENTITY_NAME = "Conversations 0.5";
+ public final String IDENTITY_TYPE = "phone";
+
+ public String getCapHash() {
+ StringBuilder s = new StringBuilder();
+ s.append("client/"+IDENTITY_TYPE+"//"+IDENTITY_NAME+"<");
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance("SHA-1");
+ }
+ catch(NoSuchAlgorithmException e) {
+ return null;
+ }
+ List<String> features = Arrays.asList(FEATURES);
+ Collections.sort(features);
+ for(String feature : features) {
+ s.append(feature+"<");
+ }
+ byte[] sha1 = md.digest(s.toString().getBytes());
+ return new String(Base64.encode(sha1, Base64.DEFAULT));
+ }
+}
diff --git a/src/eu/siacs/conversations/generator/IqGenerator.java b/src/eu/siacs/conversations/generator/IqGenerator.java
new file mode 100644
index 00000000..7b3350d4
--- /dev/null
+++ b/src/eu/siacs/conversations/generator/IqGenerator.java
@@ -0,0 +1,31 @@
+package eu.siacs.conversations.generator;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+
+public class IqGenerator extends AbstractGenerator {
+
+
+
+ public IqPacket discoResponse(IqPacket request) {
+ IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT);
+ packet.setId(request.getId());
+ packet.setTo(request.getFrom());
+ Element query = packet.addChild("query","http://jabber.org/protocol/disco#info");
+ query.setAttribute("node", request.query().getAttribute("node"));
+ Element identity = query.addChild("identity");
+ identity.setAttribute("category","client");
+ identity.setAttribute("type", this.IDENTITY_TYPE);
+ identity.setAttribute("name", IDENTITY_NAME);
+ List<String> features = Arrays.asList(FEATURES);
+ Collections.sort(features);
+ for(String feature : features) {
+ query.addChild("feature").setAttribute("var",feature);
+ }
+ return packet;
+ }
+}
diff --git a/src/eu/siacs/conversations/generator/MessageGenerator.java b/src/eu/siacs/conversations/generator/MessageGenerator.java
index 5a216a7e..4449a7ec 100644
--- a/src/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/eu/siacs/conversations/generator/MessageGenerator.java
@@ -128,4 +128,37 @@ public class MessageGenerator {
packet.setFrom(conversation.getAccount().getJid());
return packet;
}
+
+ public MessagePacket directInvite(Conversation conversation, String contact) {
+ MessagePacket packet = new MessagePacket();
+ packet.setType(MessagePacket.TYPE_NORMAL);
+ packet.setTo(contact);
+ packet.setFrom(conversation.getAccount().getFullJid());
+ Element x = packet.addChild("x", "jabber:x:conference");
+ x.setAttribute("jid", conversation.getContactJid().split("/")[0]);
+ return packet;
+ }
+
+ public MessagePacket invite(Conversation conversation, String contact) {
+ MessagePacket packet = new MessagePacket();
+ packet.setTo(conversation.getContactJid().split("/")[0]);
+ packet.setFrom(conversation.getAccount().getFullJid());
+ Element x = new Element("x");
+ x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
+ Element invite = new Element("invite");
+ invite.setAttribute("to", contact);
+ x.addChild(invite);
+ packet.addChild(x);
+ return packet;
+ }
+
+ public MessagePacket received(Account account, MessagePacket originalMessage, String namespace) {
+ MessagePacket receivedPacket = new MessagePacket();
+ receivedPacket.setType(MessagePacket.TYPE_NORMAL);
+ receivedPacket.setTo(originalMessage.getFrom());
+ receivedPacket.setFrom(account.getFullJid());
+ Element received = receivedPacket.addChild("received",namespace);
+ received.setAttribute("id", originalMessage.getId());
+ return receivedPacket;
+ }
}
diff --git a/src/eu/siacs/conversations/generator/PresenceGenerator.java b/src/eu/siacs/conversations/generator/PresenceGenerator.java
index a301392e..b3431568 100644
--- a/src/eu/siacs/conversations/generator/PresenceGenerator.java
+++ b/src/eu/siacs/conversations/generator/PresenceGenerator.java
@@ -2,9 +2,10 @@ package eu.siacs.conversations.generator;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
-public class PresenceGenerator {
+public class PresenceGenerator extends AbstractGenerator {
private PresencePacket subscription(String type, Contact contact) {
PresencePacket packet = new PresencePacket();
@@ -38,6 +39,13 @@ public class PresenceGenerator {
packet.addChild("status").setContent("online");
packet.addChild("x", "jabber:x:signed").setContent(sig);
}
+ String capHash = getCapHash();
+ if (capHash != null) {
+ Element cap = packet.addChild("c","http://jabber.org/protocol/caps");
+ cap.setAttribute("hash", "sha-1");
+ cap.setAttribute("node","http://conversions.siacs.eu");
+ cap.setAttribute("ver", capHash);
+ }
return packet;
}
} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/parser/AbstractParser.java b/src/eu/siacs/conversations/parser/AbstractParser.java
index f9a7b1c0..c4c6720a 100644
--- a/src/eu/siacs/conversations/parser/AbstractParser.java
+++ b/src/eu/siacs/conversations/parser/AbstractParser.java
@@ -2,6 +2,8 @@ package eu.siacs.conversations.parser;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.Locale;
@@ -20,11 +22,16 @@ public abstract class AbstractParser {
protected long getTimestamp(Element packet) {
long now = System.currentTimeMillis();
- if (packet.hasChild("delay")) {
+ ArrayList<String> stamps = new ArrayList<String>();
+ for(Element child : packet.getChildren()) {
+ if (child.getName().equals("delay")) {
+ stamps.add(child.getAttribute("stamp").replace("Z", "+0000"));
+ }
+ }
+ Collections.sort(stamps);
+ if (stamps.size() >= 1) {
try {
- String stamp = packet.findChild("delay").getAttribute(
- "stamp");
- stamp = stamp.replace("Z", "+0000");
+ String stamp = stamps.get(stamps.size() - 1);
if (stamp.contains(".")) {
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ",Locale.US)
.parse(stamp);
diff --git a/src/eu/siacs/conversations/parser/IqParser.java b/src/eu/siacs/conversations/parser/IqParser.java
index acbeee4d..023fb4df 100644
--- a/src/eu/siacs/conversations/parser/IqParser.java
+++ b/src/eu/siacs/conversations/parser/IqParser.java
@@ -38,6 +38,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
}
}
}
+ mXmppConnectionService.updateRosterUi();
}
@Override
@@ -55,23 +56,8 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
mXmppConnectionService.getJingleConnectionManager().deliverIbbPacket(account, packet);
} else if (packet.hasChild("query",
"http://jabber.org/protocol/disco#info")) {
- IqPacket iqResponse = packet
- .generateRespone(IqPacket.TYPE_RESULT);
- Element query = iqResponse.addChild("query",
- "http://jabber.org/protocol/disco#info");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:1");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:apps:file-transfer:3");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:transports:s5b:1");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:transports:ibb:1");
- if (mXmppConnectionService.confirmMessages()) {
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:receipts");
- }
- account.getXmppConnection().sendIqPacket(iqResponse, null);
+ IqPacket response = mXmppConnectionService.getIqGenerator().discoResponse(packet);
+ account.getXmppConnection().sendIqPacket(response, null);
} else {
if ((packet.getType() == IqPacket.TYPE_GET)
|| (packet.getType() == IqPacket.TYPE_SET)) {
diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java
index 1673fbf0..a4fcc810 100644
--- a/src/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/eu/siacs/conversations/parser/MessageParser.java
@@ -80,6 +80,7 @@ public class MessageParser extends AbstractParser implements
mXmppConnectionService.onOtrSessionEstablished(conversation);
} else if ((before != after) && (after == SessionStatus.FINISHED)) {
conversation.resetOtrSession();
+ mXmppConnectionService.updateConversationUi();
}
if ((body == null) || (body.isEmpty())) {
return null;
@@ -109,6 +110,9 @@ public class MessageParser extends AbstractParser implements
private Message parseGroupchat(MessagePacket packet, Account account) {
int status;
String[] fromParts = packet.getFrom().split("/");
+ if (mXmppConnectionService.find(account.pendingConferenceLeaves,account,fromParts[0]) != null) {
+ return null;
+ }
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, fromParts[0], true);
if (packet.hasChild("subject")) {
@@ -121,7 +125,7 @@ public class MessageParser extends AbstractParser implements
return null;
}
String counterPart = fromParts[1];
- if (counterPart.equals(conversation.getMucOptions().getNick())) {
+ if (counterPart.equals(conversation.getMucOptions().getActualNick())) {
if (mXmppConnectionService.markMessage(conversation,
packet.getId(), Message.STATUS_SEND)) {
return null;
@@ -174,6 +178,9 @@ public class MessageParser extends AbstractParser implements
} else {
fullJid = message.getAttribute("to");
}
+ if (fullJid==null) {
+ return null;
+ }
String[] parts = fullJid.split("/");
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, parts[0], false);
@@ -214,15 +221,29 @@ public class MessageParser extends AbstractParser implements
updateLastseen(packet, account, false);
mXmppConnectionService.markMessage(account, fromParts[0], id,
Message.STATUS_SEND_RECEIVED);
- } else if (packet.hasChild("x")) {
- Element x = packet.findChild("x");
+ } else if (packet.hasChild("x","http://jabber.org/protocol/muc#user")) {
+ Element x = packet.findChild("x","http://jabber.org/protocol/muc#user");
if (x.hasChild("invite")) {
- mXmppConnectionService
+ Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account,
packet.getAttribute("from"), true);
- mXmppConnectionService.updateConversationUi();
+ if (!conversation.getMucOptions().online()) {
+ mXmppConnectionService.joinMuc(conversation);
+ mXmppConnectionService.updateConversationUi();
+ }
}
+ } else if (packet.hasChild("x", "jabber:x:conference")) {
+ Element x = packet.findChild("x", "jabber:x:conference");
+ String jid = x.getAttribute("jid");
+ if (jid!=null) {
+ Conversation conversation = mXmppConnectionService
+ .findOrCreateConversation(account,jid, true);
+ if (!conversation.getMucOptions().online()) {
+ mXmppConnectionService.joinMuc(conversation);
+ mXmppConnectionService.updateConversationUi();
+ }
+ }
}
}
@@ -274,6 +295,8 @@ public class MessageParser extends AbstractParser implements
message.markUnread();
}
}
+ } else {
+ parseNormal(packet, account);
}
} else if (packet.getType() == MessagePacket.TYPE_GROUPCHAT) {
@@ -283,6 +306,8 @@ public class MessageParser extends AbstractParser implements
message.markUnread();
} else {
message.getConversation().markRead();
+ lastCarbonMessageReceived = SystemClock
+ .elapsedRealtime();
notify = false;
}
}
@@ -291,26 +316,20 @@ public class MessageParser extends AbstractParser implements
return;
} else if (packet.getType() == MessagePacket.TYPE_NORMAL) {
this.parseNormal(packet, account);
+ return;
}
if ((message == null) || (message.getBody() == null)) {
return;
}
if ((mXmppConnectionService.confirmMessages())
&& ((packet.getId() != null))) {
- MessagePacket receivedPacket = new MessagePacket();
- receivedPacket.setType(MessagePacket.TYPE_NORMAL);
- receivedPacket.setTo(message.getCounterpart());
- receivedPacket.setFrom(account.getFullJid());
if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
- Element received = receivedPacket.addChild("received",
- "urn:xmpp:chat-markers:0");
- received.setAttribute("id", packet.getId());
- account.getXmppConnection().sendMessagePacket(receivedPacket);
- } else if (packet.hasChild("request", "urn:xmpp:receipts")) {
- Element received = receivedPacket.addChild("received",
- "urn:xmpp:receipts");
- received.setAttribute("id", packet.getId());
- account.getXmppConnection().sendMessagePacket(receivedPacket);
+ MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account, packet, "urn:xmpp:chat-markers:0");
+ mXmppConnectionService.sendMessagePacket(account, receipt);
+ }
+ if (packet.hasChild("request", "urn:xmpp:receipts")) {
+ MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account, packet, "urn:xmpp:receipts");
+ mXmppConnectionService.sendMessagePacket(account, receipt);
}
}
Conversation conversation = message.getConversation();
diff --git a/src/eu/siacs/conversations/parser/PresenceParser.java b/src/eu/siacs/conversations/parser/PresenceParser.java
index bd2aa636..33f4185f 100644
--- a/src/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/eu/siacs/conversations/parser/PresenceParser.java
@@ -21,22 +21,19 @@ public class PresenceParser extends AbstractParser implements
public void parseConferencePresence(PresencePacket packet, Account account) {
PgpEngine mPgpEngine = mXmppConnectionService.getPgpEngine();
if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) {
- Conversation muc = mXmppConnectionService.findMuc(packet
- .getAttribute("from").split("/")[0], account);
+ Conversation muc = mXmppConnectionService.find(account,packet
+ .getAttribute("from").split("/")[0]);
if (muc != null) {
muc.getMucOptions().processPacket(packet, mPgpEngine);
}
} else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) {
- Conversation muc = mXmppConnectionService.findMuc(packet
- .getAttribute("from").split("/")[0], account);
+ Conversation muc = mXmppConnectionService.find(account,packet
+ .getAttribute("from").split("/")[0]);
if (muc != null) {
- int error = muc.getMucOptions().getError();
muc.getMucOptions().processPacket(packet, mPgpEngine);
- if (muc.getMucOptions().getError() != error) {
- mXmppConnectionService.updateConversationUi();
- }
}
}
+ mXmppConnectionService.updateConversationUi();
}
public void parseContactPresence(PresencePacket packet, Account account) {
@@ -99,6 +96,7 @@ public class PresenceParser extends AbstractParser implements
}
}
}
+ mXmppConnectionService.updateRosterUi();
}
@Override
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index c43a34b7..de0658d4 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -15,6 +15,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection;
+import de.duenndns.ssl.MemorizingTrustManager;
+
import net.java.otr4j.OtrException;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
@@ -27,6 +29,7 @@ import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
import eu.siacs.conversations.entities.Presences;
+import eu.siacs.conversations.generator.IqGenerator;
import eu.siacs.conversations.generator.MessageGenerator;
import eu.siacs.conversations.generator.PresenceGenerator;
import eu.siacs.conversations.parser.IqParser;
@@ -46,7 +49,6 @@ import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.OnStatusChanged;
-import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived;
@@ -90,6 +92,8 @@ public class XmppConnectionService extends Service {
public static final long CARBON_GRACE_PERIOD = 60000L;
private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
+
+ private MemorizingTrustManager mMemorizingTrustManager;
private MessageParser mMessageParser = new MessageParser(this);
private PresenceParser mPresenceParser = new PresenceParser(this);
@@ -105,12 +109,12 @@ public class XmppConnectionService extends Service {
private OnConversationUpdate mOnConversationUpdate = null;
private int convChangedListenerCount = 0;
private OnAccountUpdate mOnAccountUpdate = null;
- private OnTLSExceptionReceived tlsException = null;
+ private OnRosterUpdate mOnRosterUpdate = null;
public OnContactStatusChanged onContactStatusChanged = new OnContactStatusChanged() {
@Override
public void onContactStatusChanged(Contact contact, boolean online) {
- Conversation conversation = findActiveConversation(contact);
+ Conversation conversation = find(getConversations(),contact);
if (conversation != null) {
conversation.endOtrIfNeeded();
if (online && (contact.getPresences().size() == 1)) {
@@ -120,11 +124,6 @@ public class XmppConnectionService extends Service {
}
};
- public void setOnTLSExceptionReceivedListener(
- OnTLSExceptionReceived listener) {
- tlsException = listener;
- }
-
private SecureRandom mRandom;
private ContentObserver contactObserver = new ContentObserver(null) {
@@ -147,6 +146,12 @@ public class XmppConnectionService extends Service {
mOnAccountUpdate.onAccountUpdate();;
}
if (account.getStatus() == Account.STATUS_ONLINE) {
+ for(Conversation conversation : account.pendingConferenceLeaves) {
+ leaveMuc(conversation);
+ }
+ for(Conversation conversation : account.pendingConferenceJoins) {
+ joinMuc(conversation);
+ }
mJingleConnectionManager.cancelInTransmission();
List<Conversation> conversations = getConversations();
for (int i = 0; i < conversations.size(); ++i) {
@@ -195,6 +200,21 @@ public class XmppConnectionService extends Service {
private PendingIntent pendingPingIntent = null;
private WakeLock wakeLock;
private PowerManager pm;
+ private OnBindListener mOnBindListener = new OnBindListener() {
+
+ @Override
+ public void onBind(final Account account) {
+ account.getRoster().clearPresences();
+ account.clearPresences(); // self presences
+ account.pendingConferenceJoins.clear();
+ account.pendingConferenceLeaves.clear();
+ fetchRosterFromServer(account);
+ fetchBookmarks(account);
+ sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
+ connectMultiModeConversations(account);
+ updateConversationUi();
+ }
+ };
public PgpEngine getPgpEngine() {
if (pgpServiceConnection.isBound()) {
@@ -246,18 +266,12 @@ public class XmppConnectionService extends Service {
return message;
}
- public Conversation findMuc(Bookmark bookmark) {
- return findMuc(bookmark.getJid(), bookmark.getAccount());
+ public Conversation find(Bookmark bookmark) {
+ return find(bookmark.getAccount(),bookmark.getJid());
}
- public Conversation findMuc(String jid, Account account) {
- for (Conversation conversation : this.conversations) {
- if (conversation.getContactJid().split("/")[0].equals(jid)
- && (conversation.getAccount() == account)) {
- return conversation;
- }
- }
- return null;
+ public Conversation find(Account account, String jid) {
+ return find(getConversations(),account,jid);
}
public class XmppConnectionBinder extends Binder {
@@ -352,6 +366,7 @@ public class XmppConnectionService extends Service {
ExceptionHelper.init(getApplicationContext());
PRNGFixes.apply();
this.mRandom = new SecureRandom();
+ this.mMemorizingTrustManager = new MemorizingTrustManager(getApplicationContext());
this.databaseBackend = DatabaseBackend
.getInstance(getApplicationContext());
this.fileBackend = new FileBackend(getApplicationContext());
@@ -451,32 +466,7 @@ public class XmppConnectionService extends Service {
connection
.setOnUnregisteredIqPacketReceivedListener(this.mIqParser);
connection.setOnJinglePacketReceivedListener(this.jingleListener);
- connection
- .setOnTLSExceptionReceivedListener(new OnTLSExceptionReceived() {
-
- @Override
- public void onTLSExceptionReceived(String fingerprint,
- Account account) {
- Log.d(LOGTAG, "tls exception arrived in service");
- if (tlsException != null) {
- tlsException.onTLSExceptionReceived(fingerprint,
- account);
- }
- }
- });
- connection.setOnBindListener(new OnBindListener() {
-
- @Override
- public void onBind(final Account account) {
- account.getRoster().clearPresences();
- account.clearPresences(); // self presences
- fetchRosterFromServer(account);
- fetchBookmarks(account);
- sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
- connectMultiModeConversations(account);
- updateConversationUi();
- }
- });
+ connection.setOnBindListener(this.mOnBindListener);
return connection;
}
@@ -528,11 +518,13 @@ public class XmppConnectionService extends Service {
}
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
message.getConversation().endOtrIfNeeded();
+ failWaitingOtrMessages(message.getConversation());
packet = mMessageGenerator.generatePgpChat(message);
message.setStatus(Message.STATUS_SEND);
send = true;
} else {
message.getConversation().endOtrIfNeeded();
+ failWaitingOtrMessages(message.getConversation());
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
message.setStatus(Message.STATUS_SEND);
}
@@ -681,16 +673,16 @@ public class XmppConnectionService extends Service {
if (storage!=null) {
for(Element item : storage.getChildren()) {
if (item.getName().equals("conference")) {
- Log.d(LOGTAG,item.toString());
Bookmark bookmark = Bookmark.parse(item,account);
bookmarks.add(bookmark);
- Conversation conversation = findMuc(bookmark);
+ Conversation conversation = find(bookmark);
if (conversation!=null) {
conversation.setBookmark(bookmark);
} else {
if (bookmark.autojoin()) {
conversation = findOrCreateConversation(account, bookmark.getJid(), true);
conversation.setBookmark(bookmark);
+ joinMuc(conversation);
}
}
}
@@ -792,8 +784,8 @@ public class XmppConnectionService extends Service {
return this.accounts;
}
- public Conversation findActiveConversation(Contact contact) {
- for (Conversation conversation : this.getConversations()) {
+ public Conversation find(List<Conversation> haystack, Contact contact) {
+ for (Conversation conversation : haystack) {
if (conversation.getContact() == contact) {
return conversation;
}
@@ -801,16 +793,24 @@ public class XmppConnectionService extends Service {
return null;
}
+ public Conversation find(List<Conversation> haystack, Account account, String jid) {
+ for (Conversation conversation : haystack) {
+ if ((conversation.getAccount().equals(account))
+ && (conversation.getContactJid().split("/")[0].equals(jid))) {
+ return conversation;
+ }
+ }
+ return null;
+ }
+
+
public Conversation findOrCreateConversation(Account account, String jid,
boolean muc) {
- for (Conversation conv : this.getConversations()) {
- if ((conv.getAccount().equals(account))
- && (conv.getContactJid().split("/")[0].equals(jid))) {
- return conv;
- }
+ Conversation conversation = find(account, jid);
+ if (conversation != null) {
+ return conversation;
}
- Conversation conversation = databaseBackend.findConversation(account,
- jid);
+ conversation = databaseBackend.findConversation(account,jid);
if (conversation != null) {
conversation.setStatus(Conversation.STATUS_AVAILABLE);
conversation.setAccount(account);
@@ -840,10 +840,6 @@ public class XmppConnectionService extends Service {
this.databaseBackend.createConversation(conversation);
}
this.conversations.add(conversation);
- if ((account.getStatus() == Account.STATUS_ONLINE)
- && (conversation.getMode() == Conversation.MODE_MULTI)) {
- joinMuc(conversation);
- }
updateConversationUi();
return conversation;
}
@@ -891,6 +887,16 @@ public class XmppConnectionService extends Service {
}
public void deleteAccount(Account account) {
+ for(Conversation conversation : conversations) {
+ if (conversation.getAccount() == account) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ leaveMuc(conversation);
+ } else if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ conversation.endOtrIfNeeded();
+ }
+ conversations.remove(conversation);
+ }
+ }
if (account.getXmppConnection() != null) {
this.disconnect(account, true);
}
@@ -920,6 +926,14 @@ public class XmppConnectionService extends Service {
public void removeOnAccountListChangedListener() {
this.mOnAccountUpdate = null;
}
+
+ public void setOnRosterUpdateListener(OnRosterUpdate listener) {
+ this.mOnRosterUpdate = listener;
+ }
+
+ public void removeOnRosterUpdateListener() {
+ this.mOnRosterUpdate = null;
+ }
public void connectMultiModeConversations(Account account) {
List<Conversation> conversations = getConversations();
@@ -934,39 +948,44 @@ public class XmppConnectionService extends Service {
public void joinMuc(Conversation conversation) {
Account account = conversation.getAccount();
- String[] mucParts = conversation.getContactJid().split("/");
- String muc;
- String nick;
- if (mucParts.length == 2) {
- muc = mucParts[0];
- nick = mucParts[1];
+ account.pendingConferenceJoins.remove(conversation);
+ account.pendingConferenceLeaves.remove(conversation);
+ if (account.getStatus() == Account.STATUS_ONLINE) {
+ Log.d(LOGTAG,"joining conversation "+conversation.getContactJid());
+ String nick = conversation.getMucOptions().getProposedNick();
+ conversation.getMucOptions().setJoinNick(nick);
+ PresencePacket packet = new PresencePacket();
+ String joinJid = conversation.getMucOptions().getJoinJid();
+ packet.setAttribute("to",conversation.getMucOptions().getJoinJid());
+ Element x = new Element("x");
+ x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
+ String sig = account.getPgpSignature();
+ if (sig != null) {
+ packet.addChild("status").setContent("online");
+ packet.addChild("x", "jabber:x:signed").setContent(sig);
+ }
+ if (conversation.getMessages().size() != 0) {
+ final SimpleDateFormat mDateFormat = new SimpleDateFormat(
+ "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
+ mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ Date date = new Date(
+ conversation.getLatestMessage().getTimeSent() + 1000);
+ x.addChild("history").setAttribute("since",
+ mDateFormat.format(date));
+ }
+ packet.addChild(x);
+ sendPresencePacket(account, packet);
+ if (!joinJid.equals(conversation.getContactJid())) {
+ conversation.setContactJid(joinJid);
+ databaseBackend.updateConversation(conversation);
+ }
} else {
- muc = mucParts[0];
- nick = account.getUsername();
- }
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("to", muc + "/" + nick);
- Element x = new Element("x");
- x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
- String sig = account.getPgpSignature();
- if (sig != null) {
- packet.addChild("status").setContent("online");
- packet.addChild("x", "jabber:x:signed").setContent(sig);
+ account.pendingConferenceJoins.add(conversation);
}
- if (conversation.getMessages().size() != 0) {
- final SimpleDateFormat mDateFormat = new SimpleDateFormat(
- "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
- mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- Date date = new Date(
- conversation.getLatestMessage().getTimeSent() + 1000);
- x.addChild("history").setAttribute("since",
- mDateFormat.format(date));
- }
- packet.addChild(x);
- sendPresencePacket(account, packet);
}
private OnRenameListener renameListener = null;
+ private IqGenerator mIqGenerator = new IqGenerator();
public void setOnRenameListener(OnRenameListener listener) {
this.renameListener = listener;
@@ -974,6 +993,7 @@ public class XmppConnectionService extends Service {
public void renameInMuc(final Conversation conversation, final String nick) {
final MucOptions options = conversation.getMucOptions();
+ options.setJoinNick(nick);
if (options.online()) {
Account account = conversation.getAccount();
options.setOnRenameListener(new OnRenameListener() {
@@ -984,17 +1004,19 @@ public class XmppConnectionService extends Service {
renameListener.onRename(success);
}
if (success) {
- String jid = conversation.getContactJid().split("/")[0]
- + "/" + nick;
- conversation.setContactJid(jid);
+ conversation.setContactJid(conversation.getMucOptions().getJoinJid());
databaseBackend.updateConversation(conversation);
+ Bookmark bookmark = conversation.getBookmark();
+ if (bookmark!=null) {
+ bookmark.setNick(nick);
+ pushBookmarks(bookmark.getAccount());
+ }
}
}
});
options.flagAboutToRename();
PresencePacket packet = new PresencePacket();
- packet.setAttribute("to",
- conversation.getContactJid().split("/")[0] + "/" + nick);
+ packet.setAttribute("to",options.getJoinJid());
packet.setAttribute("from", conversation.getAccount().getFullJid());
String sig = account.getPgpSignature();
@@ -1004,26 +1026,35 @@ public class XmppConnectionService extends Service {
}
sendPresencePacket(account,packet);
} else {
- String jid = conversation.getContactJid().split("/")[0] + "/"
- + nick;
- conversation.setContactJid(jid);
+ conversation.setContactJid(options.getJoinJid());
databaseBackend.updateConversation(conversation);
if (conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
+ Bookmark bookmark = conversation.getBookmark();
+ if (bookmark!=null) {
+ bookmark.setNick(nick);
+ pushBookmarks(bookmark.getAccount());
+ }
joinMuc(conversation);
}
}
}
public void leaveMuc(Conversation conversation) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("to", conversation.getContactJid().split("/")[0]
- + "/" + conversation.getMucOptions().getNick());
- packet.setAttribute("from", conversation.getAccount().getFullJid());
- packet.setAttribute("type", "unavailable");
- sendPresencePacket(conversation.getAccount(),packet);
- conversation.getMucOptions().setOffline();
- conversation.deregisterWithBookmark();
- Log.d(LOGTAG,conversation.getAccount().getJid()+" leaving muc "+conversation.getContactJid());
+ Account account = conversation.getAccount();
+ account.pendingConferenceJoins.remove(conversation);
+ account.pendingConferenceLeaves.remove(conversation);
+ if (account.getStatus() == Account.STATUS_ONLINE) {
+ PresencePacket packet = new PresencePacket();
+ packet.setAttribute("to", conversation.getMucOptions().getJoinJid());
+ packet.setAttribute("from", conversation.getAccount().getFullJid());
+ packet.setAttribute("type", "unavailable");
+ sendPresencePacket(conversation.getAccount(),packet);
+ conversation.getMucOptions().setOffline();
+ conversation.deregisterWithBookmark();
+ Log.d(LOGTAG,conversation.getAccount().getJid()+" leaving muc "+conversation.getContactJid());
+ } else {
+ account.pendingConferenceLeaves.add(conversation);
+ }
}
public void disconnect(Account account, boolean force) {
@@ -1170,10 +1201,6 @@ public class XmppConnectionService extends Service {
this.databaseBackend.updateConversation(conversation);
}
- public void removeOnTLSExceptionReceivedListener() {
- this.tlsException = null;
- }
-
public void reconnectAccount(final Account account, final boolean force) {
new Thread(new Runnable() {
@@ -1194,22 +1221,9 @@ public class XmppConnectionService extends Service {
}).start();
}
- public void inviteToConference(Conversation conversation,
- List<Contact> contacts) {
- for (Contact contact : contacts) {
- MessagePacket packet = new MessagePacket();
- packet.setTo(conversation.getContactJid().split("/")[0]);
- packet.setFrom(conversation.getAccount().getFullJid());
- Element x = new Element("x");
- x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
- Element invite = new Element("invite");
- invite.setAttribute("to", contact.getJid());
- x.addChild(invite);
- packet.addChild(x);
- Log.d(LOGTAG, packet.toString());
- sendMessagePacket(conversation.getAccount(),packet);
- }
-
+ public void invite(Conversation conversation, String contact) {
+ MessagePacket packet = mMessageGenerator.invite(conversation, contact);
+ sendMessagePacket(conversation.getAccount(),packet);
}
public boolean markMessage(Account account, String recipient, String uuid,
@@ -1269,6 +1283,12 @@ public class XmppConnectionService extends Service {
mOnAccountUpdate.onAccountUpdate();
}
}
+
+ public void updateRosterUi() {
+ if (mOnRosterUpdate != null) {
+ mOnRosterUpdate.onRosterUpdate();
+ }
+ }
public Account findAccountByJid(String accountJid) {
for (Account account : this.accounts) {
@@ -1278,6 +1298,15 @@ public class XmppConnectionService extends Service {
}
return null;
}
+
+ public Conversation findConversationByUuid(String uuid) {
+ for (Conversation conversation : getConversations()) {
+ if (conversation.getUuid().equals(uuid)) {
+ return conversation;
+ }
+ }
+ return null;
+ }
public void markRead(Conversation conversation) {
conversation.markRead();
@@ -1288,10 +1317,23 @@ public class XmppConnectionService extends Service {
this.sendMessagePacket(conversation.getAccount(), mMessageGenerator.confirm(account, to, id));
}
}
+
+ public void failWaitingOtrMessages(Conversation conversation) {
+ for (Message message : conversation.getMessages()) {
+ if (message.getEncryption() == Message.ENCRYPTION_OTR
+ && message.getStatus() == Message.STATUS_WAITING) {
+ markMessage(message, Message.STATUS_SEND_FAILED);
+ }
+ }
+ }
public SecureRandom getRNG() {
return this.mRandom;
}
+
+ public MemorizingTrustManager getMemorizingTrustManager() {
+ return this.mMemorizingTrustManager;
+ }
public PowerManager getPowerManager() {
return this.pm;
@@ -1367,6 +1409,10 @@ public class XmppConnectionService extends Service {
return this.mPresenceGenerator;
}
+ public IqGenerator getIqGenerator() {
+ return this.mIqGenerator ;
+ }
+
public JingleConnectionManager getJingleConnectionManager() {
return this.mJingleConnectionManager;
}
diff --git a/src/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/eu/siacs/conversations/ui/ChooseContactActivity.java
new file mode 100644
index 00000000..4236ea70
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/ChooseContactActivity.java
@@ -0,0 +1,140 @@
+package eu.siacs.conversations.ui;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.ui.adapter.ListItemAdapter;
+
+public class ChooseContactActivity extends XmppActivity {
+
+ private ListView mListView;
+ private ArrayList<ListItem> contacts = new ArrayList<ListItem>();
+ private ArrayAdapter<ListItem> mContactsAdapter;
+
+ private EditText mSearchEditText;
+
+ private TextWatcher mSearchTextWatcher = new TextWatcher() {
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ filterContacts(editable.toString());
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before,
+ int count) {
+ }
+ };
+
+ private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
+
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ mSearchEditText.post(new Runnable() {
+
+ @Override
+ public void run() {
+ mSearchEditText.requestFocus();
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mSearchEditText,
+ InputMethodManager.SHOW_IMPLICIT);
+ }
+ });
+
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
+ InputMethodManager.HIDE_IMPLICIT_ONLY);
+ mSearchEditText.setText("");
+ filterContacts(null);
+ return true;
+ }
+ };
+
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_choose_contact);
+ mListView = (ListView) findViewById(R.id.choose_contact_list);
+ mContactsAdapter = new ListItemAdapter(getApplicationContext(), contacts);
+ mListView.setAdapter(mContactsAdapter);
+ mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1, int position,
+ long arg3) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
+ InputMethodManager.HIDE_IMPLICIT_ONLY);
+ Intent request = getIntent();
+ Intent data = new Intent();
+ data.putExtra("contact",contacts.get(position).getJid());
+ data.putExtra("account",request.getStringExtra("account"));
+ data.putExtra("conversation",request.getStringExtra("conversation"));
+ setResult(RESULT_OK, data);
+ finish();
+ }
+ });
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.choose_contact, menu);
+ MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
+ View mSearchView = menuSearchView.getActionView();
+ mSearchEditText = (EditText) mSearchView
+ .findViewById(R.id.search_field);
+ mSearchEditText.addTextChangedListener(mSearchTextWatcher);
+ menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
+ return true;
+ }
+
+ @Override
+ void onBackendConnected() {
+ filterContacts(null);
+ }
+
+ protected void filterContacts(String needle) {
+ this.contacts.clear();
+ for (Account account : xmppConnectionService.getAccounts()) {
+ if (account.getStatus() != Account.STATUS_DISABLED) {
+ for (Contact contact : account.getRoster().getContacts()) {
+ if (contact.showInRoster() && contact.match(needle)) {
+ this.contacts.add(contact);
+ }
+ }
+ }
+ }
+ Collections.sort(this.contacts);
+ mContactsAdapter.notifyDataSetChanged();
+ }
+
+}
diff --git a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
new file mode 100644
index 00000000..56903da8
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -0,0 +1,268 @@
+package eu.siacs.conversations.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openintents.openpgp.util.OpenPgpUtils;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.crypto.PgpEngine;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.MucOptions;
+import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
+import eu.siacs.conversations.entities.MucOptions.User;
+import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.IntentSender.SendIntentException;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class ConferenceDetailsActivity extends XmppActivity {
+ public static final String ACTION_VIEW_MUC = "view_muc";
+ private Conversation conversation;
+ private TextView mYourNick;
+ private ImageView mYourPhoto;
+ private ImageButton mEditNickButton;
+ private TextView mRoleAffiliaton;
+ private TextView mFullJid;
+ private LinearLayout membersView;
+ private LinearLayout mMoreDetails;
+ private Button mInviteButton;
+ private String uuid = null;
+
+ private OnClickListener inviteListener = new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ inviteToConversation(conversation);
+ }
+ };
+
+ private List<User> users = new ArrayList<MucOptions.User>();
+ private OnConversationUpdate onConvChanged = new OnConversationUpdate() {
+
+ @Override
+ public void onConversationUpdate() {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ populateView();
+ }
+ });
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_muc_details);
+ mYourNick = (TextView) findViewById(R.id.muc_your_nick);
+ mYourPhoto = (ImageView) findViewById(R.id.your_photo);
+ mEditNickButton = (ImageButton) findViewById(R.id.edit_nick_button);
+ mFullJid = (TextView) findViewById(R.id.muc_jabberid);
+ membersView = (LinearLayout) findViewById(R.id.muc_members);
+ mMoreDetails = (LinearLayout) findViewById(R.id.muc_more_details);
+ mMoreDetails.setVisibility(View.GONE);
+ mInviteButton = (Button) findViewById(R.id.invite);
+ mInviteButton.setOnClickListener(inviteListener);
+ getActionBar().setHomeButtonEnabled(true);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ mEditNickButton.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ quickEdit(conversation.getMucOptions().getActualNick(),
+ new OnValueEdited() {
+
+ @Override
+ public void onValueEdited(String value) {
+ xmppConnectionService.renameInMuc(conversation,
+ value);
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem menuItem) {
+ switch (menuItem.getItemId()) {
+ case android.R.id.home:
+ finish();
+ break;
+ case R.id.action_edit_subject:
+ if (conversation != null) {
+ quickEdit(conversation.getName(true), new OnValueEdited() {
+
+ @Override
+ public void onValueEdited(String value) {
+ MessagePacket packet = xmppConnectionService
+ .getMessageGenerator().conferenceSubject(
+ conversation, value);
+ xmppConnectionService.sendMessagePacket(
+ conversation.getAccount(), packet);
+ }
+ });
+ }
+ break;
+ }
+ return super.onOptionsItemSelected(menuItem);
+ }
+
+ public String getReadableRole(int role) {
+ switch (role) {
+ case User.ROLE_MODERATOR:
+ return getString(R.string.moderator);
+ case User.ROLE_PARTICIPANT:
+ return getString(R.string.participant);
+ case User.ROLE_VISITOR:
+ return getString(R.string.visitor);
+ default:
+ return "";
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.muc_details, menu);
+ return true;
+ }
+
+ @Override
+ void onBackendConnected() {
+ registerListener();
+ if (getIntent().getAction().equals(ACTION_VIEW_MUC)) {
+ this.uuid = getIntent().getExtras().getString("uuid");
+ }
+ if (uuid != null) {
+ this.conversation = xmppConnectionService.findConversationByUuid(uuid);
+ if (this.conversation != null) {
+ populateView();
+ }
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService.removeOnConversationListChangedListener();
+ }
+ super.onStop();
+ }
+
+ protected void registerListener() {
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService
+ .setOnConversationListChangedListener(this.onConvChanged);
+ xmppConnectionService.setOnRenameListener(new OnRenameListener() {
+
+ @Override
+ public void onRename(final boolean success) {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ populateView();
+ if (success) {
+ Toast.makeText(ConferenceDetailsActivity.this,
+ getString(R.string.your_nick_has_been_changed),
+ Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(ConferenceDetailsActivity.this,
+ getString(R.string.nick_in_use),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ }
+ });
+ }
+ }
+
+ private void populateView() {
+ mYourPhoto.setImageBitmap(UIHelper.getContactPicture(conversation
+ .getMucOptions().getActualNick(), 48, this, false));
+ setTitle(conversation.getName(true));
+ mFullJid.setText(conversation.getContactJid().split("/")[0]);
+ mYourNick.setText(conversation.getMucOptions().getActualNick());
+ mRoleAffiliaton = (TextView) findViewById(R.id.muc_role);
+ if (conversation.getMucOptions().online()) {
+ mMoreDetails.setVisibility(View.VISIBLE);
+ User self = conversation.getMucOptions().getSelf();
+ switch (self.getAffiliation()) {
+ case User.AFFILIATION_ADMIN:
+ mRoleAffiliaton.setText(getReadableRole(self.getRole()) + " ("
+ + getString(R.string.admin) + ")");
+ break;
+ case User.AFFILIATION_OWNER:
+ mRoleAffiliaton.setText(getReadableRole(self.getRole()) + " ("
+ + getString(R.string.owner) + ")");
+ break;
+ default:
+ mRoleAffiliaton.setText(getReadableRole(self.getRole()));
+ break;
+ }
+ }
+ this.users.clear();
+ this.users.addAll(conversation.getMucOptions().getUsers());
+ LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ membersView.removeAllViews();
+ for (final User contact : conversation.getMucOptions().getUsers()) {
+ View view = (View) inflater.inflate(R.layout.contact, null);
+ TextView displayName = (TextView) view
+ .findViewById(R.id.contact_display_name);
+ TextView key = (TextView) view.findViewById(R.id.key);
+ displayName.setText(contact.getName());
+ TextView role = (TextView) view.findViewById(R.id.contact_jid);
+ role.setText(getReadableRole(contact.getRole()));
+ if (contact.getPgpKeyId() != 0) {
+ key.setVisibility(View.VISIBLE);
+ key.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ viewPgpKey(contact);
+ }
+ });
+ key.setText(OpenPgpUtils.convertKeyIdToHex(contact
+ .getPgpKeyId()));
+ }
+ Bitmap bm = UIHelper.getContactPicture(contact.getName(), 48, this,
+ false);
+ ImageView iv = (ImageView) view.findViewById(R.id.contact_photo);
+ iv.setImageBitmap(bm);
+ membersView.addView(view);
+ }
+ }
+
+ private void viewPgpKey(User user) {
+ PgpEngine pgp = xmppConnectionService.getPgpEngine();
+ if (pgp != null) {
+ PendingIntent intent = pgp.getIntentForKey(
+ conversation.getAccount(), user.getPgpKeyId());
+ if (intent != null) {
+ try {
+ startIntentSenderForResult(intent.getIntentSender(), 0,
+ null, 0, 0, 0);
+ } catch (SendIntentException e) {
+
+ }
+ }
+ }
+ }
+}
diff --git a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
index 9321f229..7c13c518 100644
--- a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -21,19 +21,19 @@ import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
-import android.widget.EditText;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.QuickContactBadge;
import android.widget.TextView;
-import android.widget.Toast;
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.Presences;
-import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
+import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
public class ContactDetailsActivity extends XmppActivity {
public static final String ACTION_VIEW_CONTACT = "view_contact";
@@ -41,11 +41,10 @@ public class ContactDetailsActivity extends XmppActivity {
protected ContactDetailsActivity activity = this;
private Contact contact;
-
+
private String accountJid;
private String contactJid;
-
- private EditText name;
+
private TextView contactJidTv;
private TextView accountJidTv;
private TextView status;
@@ -63,16 +62,6 @@ public class ContactDetailsActivity extends XmppActivity {
}
};
- private DialogInterface.OnClickListener editContactNameListener = new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- contact.setServerName(name.getText().toString());
- activity.xmppConnectionService.pushContactToServer(contact);
- populateView();
- }
- };
-
private DialogInterface.OnClickListener addToPhonebook = new DialogInterface.OnClickListener() {
@Override
@@ -92,7 +81,8 @@ public class ContactDetailsActivity extends XmppActivity {
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(getString(R.string.action_add_phone_book));
- builder.setMessage(getString(R.string.add_phone_book_text, contact.getJid()));
+ builder.setMessage(getString(R.string.add_phone_book_text,
+ contact.getJid()));
builder.setNegativeButton(getString(R.string.cancel), null);
builder.setPositiveButton(getString(R.string.add), addToPhonebook);
builder.create().show();
@@ -101,6 +91,74 @@ public class ContactDetailsActivity extends XmppActivity {
private LinearLayout keys;
+ private OnRosterUpdate rosterUpdate = new OnRosterUpdate() {
+
+ @Override
+ public void onRosterUpdate() {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ populateView();
+ }
+ });
+ }
+ };
+
+ private OnCheckedChangeListener mOnSendCheckedChange = new OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView,
+ boolean isChecked) {
+ if (isChecked) {
+ if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
+ xmppConnectionService.sendPresencePacket(contact
+ .getAccount(),
+ xmppConnectionService.getPresenceGenerator()
+ .sendPresenceUpdatesTo(contact));
+ } else {
+ contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
+ }
+ } else {
+ contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
+ xmppConnectionService.sendPresencePacket(contact.getAccount(),
+ xmppConnectionService.getPresenceGenerator()
+ .stopPresenceUpdatesTo(contact));
+ }
+ }
+ };
+
+ private OnCheckedChangeListener mOnReceiveCheckedChange = new OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView,
+ boolean isChecked) {
+ if (isChecked) {
+ xmppConnectionService.sendPresencePacket(contact.getAccount(),
+ xmppConnectionService.getPresenceGenerator()
+ .requestPresenceUpdatesFrom(contact));
+ } else {
+ xmppConnectionService.sendPresencePacket(contact.getAccount(),
+ xmppConnectionService.getPresenceGenerator()
+ .stopPresenceUpdatesFrom(contact));
+ }
+ }
+ };
+
+ private OnAccountUpdate accountUpdate = new OnAccountUpdate() {
+
+ @Override
+ public void onAccountUpdate() {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ populateView();
+ }
+ });
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -136,20 +194,21 @@ public class ContactDetailsActivity extends XmppActivity {
.setMessage(
getString(R.string.remove_contact_text,
contact.getJid()))
- .setPositiveButton(getString(R.string.delete), removeFromRoster).create()
- .show();
+ .setPositiveButton(getString(R.string.delete),
+ removeFromRoster).create().show();
break;
case R.id.action_edit_contact:
if (contact.getSystemAccount() == null) {
+ quickEdit(contact.getDisplayName(), new OnValueEdited() {
- View view = (View) getLayoutInflater().inflate(
- R.layout.edit_contact_name, null);
- name = (EditText) view.findViewById(R.id.editText1);
- name.setText(contact.getDisplayName());
- builder.setView(view).setTitle(contact.getJid())
- .setPositiveButton(getString(R.string.edit), editContactNameListener)
- .create().show();
-
+ @Override
+ public void onValueEdited(String value) {
+ contact.setServerName(value);
+ activity.xmppConnectionService
+ .pushContactToServer(contact);
+ populateView();
+ }
+ });
} else {
Intent intent = new Intent(Intent.ACTION_EDIT);
String[] systemAccount = contact.getSystemAccount().split("#");
@@ -171,21 +230,26 @@ public class ContactDetailsActivity extends XmppActivity {
}
private void populateView() {
+ send.setOnCheckedChangeListener(null);
+ receive.setOnCheckedChangeListener(null);
setTitle(contact.getDisplayName());
if (contact.getOption(Contact.Options.FROM)) {
+ send.setText(R.string.send_presence_updates);
send.setChecked(true);
- } else if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)){
+ } else if (contact
+ .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
send.setChecked(false);
+ send.setText(R.string.send_presence_updates);
} else {
send.setText(R.string.preemptively_grant);
- if (contact
- .getOption(Contact.Options.PREEMPTIVE_GRANT)) {
+ if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
send.setChecked(true);
} else {
send.setChecked(false);
}
}
if (contact.getOption(Contact.Options.TO)) {
+ receive.setText(R.string.receive_presence_updates);
receive.setChecked(true);
} else {
receive.setText(R.string.ask_for_presence_updates);
@@ -195,8 +259,19 @@ public class ContactDetailsActivity extends XmppActivity {
receive.setChecked(false);
}
}
+ if (contact.getAccount().getStatus() == Account.STATUS_ONLINE) {
+ receive.setEnabled(true);
+ send.setEnabled(true);
+ } else {
+ receive.setEnabled(false);
+ send.setEnabled(false);
+ }
+
+ send.setOnCheckedChangeListener(this.mOnSendCheckedChange);
+ receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
- lastseen.setText(UIHelper.lastseen(getApplicationContext(),contact.lastseen.time));
+ lastseen.setText(UIHelper.lastseen(getApplicationContext(),
+ contact.lastseen.time));
switch (contact.getMostAvailableStatus()) {
case Presences.CHAT:
@@ -229,13 +304,15 @@ public class ContactDetailsActivity extends XmppActivity {
break;
}
if (contact.getPresences().size() > 1) {
- contactJidTv.setText(contact.getJid()+" ("+contact.getPresences().size()+")");
+ contactJidTv.setText(contact.getJid() + " ("
+ + contact.getPresences().size() + ")");
} else {
contactJidTv.setText(contact.getJid());
}
accountJidTv.setText(contact.getAccount().getJid());
- UIHelper.prepareContactBadge(this, badge, contact, getApplicationContext());
+ UIHelper.prepareContactBadge(this, badge, contact,
+ getApplicationContext());
if (contact.getSystemAccount() == null) {
badge.setOnClickListener(onBadgeClick);
@@ -260,17 +337,20 @@ public class ContactDetailsActivity extends XmppActivity {
keyType.setText("PGP Key ID");
key.setText(OpenPgpUtils.convertKeyIdToHex(contact.getPgpKeyId()));
view.setOnClickListener(new OnClickListener() {
-
+
@Override
public void onClick(View v) {
- PgpEngine pgp = activity.xmppConnectionService.getPgpEngine();
- if (pgp!=null) {
+ PgpEngine pgp = activity.xmppConnectionService
+ .getPgpEngine();
+ if (pgp != null) {
PendingIntent intent = pgp.getIntentForKey(contact);
- if (intent!=null) {
+ if (intent != null) {
try {
- startIntentSenderForResult(intent.getIntentSender(), 0, null, 0, 0, 0);
+ startIntentSenderForResult(
+ intent.getIntentSender(), 0, null, 0,
+ 0, 0);
} catch (SendIntentException e) {
-
+
}
}
}
@@ -282,9 +362,12 @@ public class ContactDetailsActivity extends XmppActivity {
@Override
public void onBackendConnected() {
- if ((accountJid != null)&&(contactJid != null)) {
- Account account = xmppConnectionService.findAccountByJid(accountJid);
- if (account==null) {
+ xmppConnectionService.setOnRosterUpdateListener(this.rosterUpdate);
+ xmppConnectionService.setOnAccountListChangedListener(this.accountUpdate );
+ if ((accountJid != null) && (contactJid != null)) {
+ Account account = xmppConnectionService
+ .findAccountByJid(accountJid);
+ if (account == null) {
return;
}
this.contact = account.getRoster().getContact(contactJid);
@@ -295,79 +378,8 @@ public class ContactDetailsActivity extends XmppActivity {
@Override
protected void onStop() {
super.onStop();
- XmppConnectionService xcs = activity.xmppConnectionService;
- PresencePacket packet = null;
- boolean updated = false;
- if (contact!=null) {
- boolean online = contact.getAccount().getStatus() == Account.STATUS_ONLINE;
- if (contact.getOption(Contact.Options.FROM)) {
- if (!send.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.FROM);
- contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
- packet = xcs.getPresenceGenerator().stopPresenceUpdatesTo(contact);
- }
- updated = true;
- }
- } else {
- if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
- if (!send.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
- }
- updated = true;
- }
- } else {
- if (send.isChecked()) {
- if (online) {
- if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
- packet = xcs.getPresenceGenerator().sendPresenceUpdatesTo(contact);
- } else {
- contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
- }
- }
- updated = true;
- }
- }
- }
- if (contact.getOption(Contact.Options.TO)) {
- if (!receive.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.TO);
- packet = xcs.getPresenceGenerator().stopPresenceUpdatesFrom(contact);
- }
- updated = true;
- }
- } else {
- if (contact.getOption(Contact.Options.ASKING)) {
- if (!receive.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.ASKING);
- packet = xcs.getPresenceGenerator().stopPresenceUpdatesFrom(contact);
- }
- updated = true;
- }
- } else {
- if (receive.isChecked()) {
- if (online) {
- contact.setOption(Contact.Options.ASKING);
- packet = xcs.getPresenceGenerator().requestPresenceUpdatesFrom(contact);
- }
- updated = true;
- }
- }
- }
- if (updated) {
- if (online) {
- if (packet!=null) {
- xcs.sendPresencePacket(contact.getAccount(), packet);
- }
- Toast.makeText(getApplicationContext(), getString(R.string.subscription_updated), Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(getApplicationContext(), getString(R.string.subscription_not_updated_offline), Toast.LENGTH_SHORT).show();
- }
- }
- }
+ xmppConnectionService.removeOnRosterUpdateListener();
+ xmppConnectionService.removeOnAccountListChangedListener();
}
}
diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java
index 66db353b..aa4fda4e 100644
--- a/src/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/eu/siacs/conversations/ui/ConversationActivity.java
@@ -98,7 +98,7 @@ public class ConversationActivity extends XmppActivity {
swapConversationFragment();
} else {
startActivity(new Intent(getApplicationContext(),
- StartConversation.class));
+ StartConversationActivity.class));
finish();
}
}
@@ -306,23 +306,22 @@ public class ConversationActivity extends XmppActivity {
.findItem(R.id.action_muc_details);
MenuItem menuContactDetails = (MenuItem) menu
.findItem(R.id.action_contact_details);
- MenuItem menuInviteContacts = (MenuItem) menu
- .findItem(R.id.action_invite);
MenuItem menuAttach = (MenuItem) menu.findItem(R.id.action_attach_file);
MenuItem menuClearHistory = (MenuItem) menu
.findItem(R.id.action_clear_history);
+ MenuItem menuAdd = (MenuItem) menu.findItem(R.id.action_add);
+ MenuItem menuInviteContact = (MenuItem) menu.findItem(R.id.action_invite);
if ((spl.isOpen() && (spl.isSlideable()))) {
menuArchive.setVisible(false);
menuMucDetails.setVisible(false);
menuContactDetails.setVisible(false);
menuSecure.setVisible(false);
- menuInviteContacts.setVisible(false);
+ menuInviteContact.setVisible(false);
menuAttach.setVisible(false);
menuClearHistory.setVisible(false);
} else {
- ((MenuItem) menu.findItem(R.id.action_add)).setVisible(!spl
- .isSlideable());
+ menuAdd.setVisible(!spl.isSlideable());
if (this.getSelectedConversation() != null) {
if (this.getSelectedConversation().getLatestMessage()
.getEncryption() != Message.ENCRYPTION_NONE) {
@@ -333,7 +332,7 @@ public class ConversationActivity extends XmppActivity {
menuAttach.setVisible(false);
} else {
menuMucDetails.setVisible(false);
- menuInviteContacts.setVisible(false);
+ menuInviteContact.setVisible(false);
}
}
}
@@ -458,7 +457,7 @@ public class ConversationActivity extends XmppActivity {
attachFilePopup.show();
break;
case R.id.action_add:
- startActivity(new Intent(this, StartConversation.class));
+ startActivity(new Intent(this, StartConversationActivity.class));
break;
case R.id.action_archive:
this.endConversation(getSelectedConversation());
@@ -472,17 +471,13 @@ public class ConversationActivity extends XmppActivity {
}
break;
case R.id.action_muc_details:
- Intent intent = new Intent(this, MucDetailsActivity.class);
- intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
+ Intent intent = new Intent(this, ConferenceDetailsActivity.class);
+ intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
intent.putExtra("uuid", getSelectedConversation().getUuid());
startActivity(intent);
break;
case R.id.action_invite:
- /*Intent inviteIntent = new Intent(getApplicationContext(),
- ContactsActivity.class);
- inviteIntent.setAction("invite");
- inviteIntent.putExtra("uuid", getSelectedConversation().getUuid());
- startActivity(inviteIntent);*/
+ inviteToConversation(getSelectedConversation());
break;
case R.id.action_security:
final Conversation conversation = getSelectedConversation();
@@ -569,7 +564,7 @@ public class ConversationActivity extends XmppActivity {
return super.onOptionsItemSelected(item);
}
- private void endConversation(Conversation conversation) {
+ public void endConversation(Conversation conversation) {
conversation.setStatus(Conversation.STATUS_ARCHIVED);
paneShouldBeOpen = true;
spl.openPane();
@@ -699,7 +694,7 @@ public class ConversationActivity extends XmppActivity {
finish();
} else if (conversationList.size() <= 0) {
// add no history
- startActivity(new Intent(this, StartConversation.class));
+ startActivity(new Intent(this, StartConversationActivity.class));
finish();
} else {
spl.openPane();
diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java
index 01bab773..1df59843 100644
--- a/src/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/eu/siacs/conversations/ui/ConversationFragment.java
@@ -1,53 +1,45 @@
package eu.siacs.conversations.ui;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Set;
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.MucOptions.OnRenameListener;
-import eu.siacs.conversations.services.ImageProvider;
import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected;
+import eu.siacs.conversations.ui.adapter.MessageAdapter;
+import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.jingle.JingleConnection;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.PendingIntent;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.IntentSender.SendIntentException;
-import android.graphics.Bitmap;
-import android.graphics.Typeface;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.Selection;
-import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AbsListView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
+
import android.widget.EditText;
-import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ImageButton;
-import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
@@ -58,12 +50,8 @@ public class ConversationFragment extends Fragment {
protected ListView messagesView;
protected LayoutInflater inflater;
protected List<Message> messageList = new ArrayList<Message>();
- protected ArrayAdapter<Message> messageListAdapter;
+ protected MessageAdapter messageListAdapter;
protected Contact contact;
- protected BitmapCache mBitmapCache = new BitmapCache();
-
- protected int mPrimaryTextColor;
- protected int mSecondaryTextColor;
protected String queuedPqpMessage = null;
@@ -73,8 +61,6 @@ public class ConversationFragment extends Fragment {
private TextView snackbarMessage;
private TextView snackbarAction;
- protected Bitmap selfBitmap;
-
private boolean useSubject = true;
private boolean messagesLoaded = false;
@@ -113,18 +99,27 @@ public class ConversationFragment extends Fragment {
}
}
};
-
+
private OnClickListener clickToMuc = new OnClickListener() {
@Override
public void onClick(View v) {
- Intent intent = new Intent(getActivity(), MucDetailsActivity.class);
- intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
+ Intent intent = new Intent(getActivity(),
+ ConferenceDetailsActivity.class);
+ intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
intent.putExtra("uuid", conversation.getUuid());
startActivity(intent);
}
};
+ private OnClickListener leaveMuc = new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ activity.endConversation(conversation);
+ }
+ };
+
private OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
@@ -172,17 +167,18 @@ public class ConversationFragment extends Fragment {
@Override
public View onCreateView(final LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
-
- final DisplayMetrics metrics = getResources().getDisplayMetrics();
-
- this.inflater = inflater;
-
- mPrimaryTextColor = getResources().getColor(R.color.primarytext);
- mSecondaryTextColor = getResources().getColor(R.color.secondarytext);
-
final View view = inflater.inflate(R.layout.fragment_conversation,
container, false);
chatMsg = (EditText) view.findViewById(R.id.textinput);
+ chatMsg.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ if (activity.getSlidingPaneLayout().isSlideable()) {
+ activity.getSlidingPaneLayout().closePane();
+ }
+ }
+ });
ImageButton sendButton = (ImageButton) view
.findViewById(R.id.textSendButton);
@@ -195,376 +191,16 @@ public class ConversationFragment extends Fragment {
messagesView = (ListView) view.findViewById(R.id.messages_view);
messagesView.setOnScrollListener(mOnScrollListener);
messagesView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
-
- messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
- .getApplicationContext(), R.layout.message_sent,
- this.messageList) {
-
- private static final int SENT = 0;
- private static final int RECIEVED = 1;
- private static final int STATUS = 2;
-
- @Override
- public int getViewTypeCount() {
- return 3;
- }
-
- @Override
- public int getItemViewType(int position) {
- if (getItem(position).getType() == Message.TYPE_STATUS) {
- return STATUS;
- } else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
- return RECIEVED;
- } else {
- return SENT;
- }
- }
-
- private void displayStatus(ViewHolder viewHolder, Message message) {
- String filesize = null;
- String info = null;
- boolean error = false;
- boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
- && message.getStatus() <= Message.STATUS_RECIEVED;
- if (message.getType() == Message.TYPE_IMAGE) {
- String[] fileParams = message.getBody().split(",");
- try {
- long size = Long.parseLong(fileParams[0]);
- filesize = size / 1024 + " KB";
- } catch (NumberFormatException e) {
- filesize = "0 KB";
- }
- }
- switch (message.getStatus()) {
- case Message.STATUS_WAITING:
- info = getString(R.string.waiting);
- break;
- case Message.STATUS_UNSEND:
- info = getString(R.string.sending);
- break;
- case Message.STATUS_OFFERED:
- info = getString(R.string.offering);
- break;
- case Message.STATUS_SEND_FAILED:
- info = getString(R.string.send_failed);
- error = true;
- break;
- case Message.STATUS_SEND_REJECTED:
- info = getString(R.string.send_rejected);
- error = true;
- break;
- case Message.STATUS_RECEPTION_FAILED:
- info = getString(R.string.reception_failed);
- error = true;
- default:
- if (multiReceived) {
- info = message.getCounterpart();
- }
- break;
- }
- if (error) {
- viewHolder.time.setTextColor(0xFFe92727);
- } else {
- viewHolder.time.setTextColor(mSecondaryTextColor);
- }
- if (message.getEncryption() == Message.ENCRYPTION_NONE) {
- viewHolder.indicator.setVisibility(View.GONE);
- } else {
- viewHolder.indicator.setVisibility(View.VISIBLE);
- }
-
- String formatedTime = UIHelper.readableTimeDifference(
- getContext(), message.getTimeSent());
- if (message.getStatus() <= Message.STATUS_RECIEVED) {
- if ((filesize != null) && (info != null)) {
- viewHolder.time.setText(filesize + " \u00B7 " + info);
- } else if ((filesize == null) && (info != null)) {
- viewHolder.time.setText(formatedTime + " \u00B7 "
- + info);
- } else if ((filesize != null) && (info == null)) {
- viewHolder.time.setText(formatedTime + " \u00B7 "
- + filesize);
- } else {
- viewHolder.time.setText(formatedTime);
- }
- } else {
- if ((filesize != null) && (info != null)) {
- viewHolder.time.setText(filesize + " \u00B7 " + info);
- } else if ((filesize == null) && (info != null)) {
- if (error) {
- viewHolder.time.setText(info + " \u00B7 "
- + formatedTime);
- } else {
- viewHolder.time.setText(info);
- }
- } else if ((filesize != null) && (info == null)) {
- viewHolder.time.setText(filesize + " \u00B7 "
- + formatedTime);
- } else {
- viewHolder.time.setText(formatedTime);
- }
- }
- }
-
- private void displayInfoMessage(ViewHolder viewHolder, int r) {
- if (viewHolder.download_button != null) {
- viewHolder.download_button.setVisibility(View.GONE);
- }
- viewHolder.image.setVisibility(View.GONE);
- viewHolder.messageBody.setVisibility(View.VISIBLE);
- viewHolder.messageBody.setText(getString(r));
- viewHolder.messageBody.setTextColor(0xff33B5E5);
- viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
- viewHolder.messageBody.setTextIsSelectable(false);
- }
-
- private void displayDecryptionFailed(ViewHolder viewHolder) {
- if (viewHolder.download_button != null) {
- viewHolder.download_button.setVisibility(View.GONE);
- }
- viewHolder.image.setVisibility(View.GONE);
- viewHolder.messageBody.setVisibility(View.VISIBLE);
- viewHolder.messageBody
- .setText(getString(R.string.decryption_failed));
- viewHolder.messageBody.setTextColor(0xFFe92727);
- viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
- viewHolder.messageBody.setTextIsSelectable(false);
- }
-
- private void displayTextMessage(ViewHolder viewHolder, String text) {
- if (viewHolder.download_button != null) {
- viewHolder.download_button.setVisibility(View.GONE);
- }
- viewHolder.image.setVisibility(View.GONE);
- viewHolder.messageBody.setVisibility(View.VISIBLE);
- if (text != null) {
- viewHolder.messageBody.setText(text.trim());
- } else {
- viewHolder.messageBody.setText("");
- }
- viewHolder.messageBody.setTextColor(mPrimaryTextColor);
- viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
- viewHolder.messageBody.setTextIsSelectable(true);
- }
-
- private void displayImageMessage(ViewHolder viewHolder,
- final Message message) {
- if (viewHolder.download_button != null) {
- viewHolder.download_button.setVisibility(View.GONE);
- }
- viewHolder.messageBody.setVisibility(View.GONE);
- viewHolder.image.setVisibility(View.VISIBLE);
- String[] fileParams = message.getBody().split(",");
- if (fileParams.length == 3) {
- double target = metrics.density * 288;
- int w = Integer.parseInt(fileParams[1]);
- int h = Integer.parseInt(fileParams[2]);
- int scalledW;
- int scalledH;
- if (w <= h) {
- scalledW = (int) (w / ((double) h / target));
- scalledH = (int) target;
- } else {
- scalledW = (int) target;
- scalledH = (int) (h / ((double) w / target));
- }
- viewHolder.image
- .setLayoutParams(new LinearLayout.LayoutParams(
- scalledW, scalledH));
- }
- activity.loadBitmap(message, viewHolder.image);
- viewHolder.image.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(
- ImageProvider.getContentUri(message), "image/*");
- startActivity(intent);
- }
- });
- viewHolder.image
- .setOnLongClickListener(new OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View v) {
- Intent shareIntent = new Intent();
- shareIntent.setAction(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_STREAM,
- ImageProvider.getContentUri(message));
- shareIntent.setType("image/webp");
- startActivity(Intent.createChooser(shareIntent,
- getText(R.string.share_with)));
- return true;
- }
- });
- }
-
+ messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList);
+ messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() {
+
@Override
- public View getView(int position, View view, ViewGroup parent) {
- final Message item = getItem(position);
- int type = getItemViewType(position);
- ViewHolder viewHolder;
- if (view == null) {
- viewHolder = new ViewHolder();
- switch (type) {
- case SENT:
- view = (View) inflater.inflate(R.layout.message_sent,
- null);
- viewHolder.message_box = (LinearLayout) view
- .findViewById(R.id.message_box);
- viewHolder.contact_picture = (ImageView) view
- .findViewById(R.id.message_photo);
- viewHolder.contact_picture.setImageBitmap(selfBitmap);
- viewHolder.indicator = (ImageView) view
- .findViewById(R.id.security_indicator);
- viewHolder.image = (ImageView) view
- .findViewById(R.id.message_image);
- viewHolder.messageBody = (TextView) view
- .findViewById(R.id.message_body);
- viewHolder.time = (TextView) view
- .findViewById(R.id.message_time);
- view.setTag(viewHolder);
- break;
- case RECIEVED:
- view = (View) inflater.inflate(
- R.layout.message_recieved, null);
- viewHolder.message_box = (LinearLayout) view
- .findViewById(R.id.message_box);
- viewHolder.contact_picture = (ImageView) view
- .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(mBitmapCache.get(
- item.getConversation().getName(
- useSubject), item
- .getConversation()
- .getContact(),
- getActivity()
- .getApplicationContext()));
-
- }
- viewHolder.indicator = (ImageView) view
- .findViewById(R.id.security_indicator);
- viewHolder.image = (ImageView) view
- .findViewById(R.id.message_image);
- viewHolder.messageBody = (TextView) view
- .findViewById(R.id.message_body);
- viewHolder.time = (TextView) view
- .findViewById(R.id.message_time);
- view.setTag(viewHolder);
- break;
- case STATUS:
- view = (View) inflater.inflate(R.layout.message_status,
- null);
- viewHolder.contact_picture = (ImageView) view
- .findViewById(R.id.message_photo);
- if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
-
- viewHolder.contact_picture
- .setImageBitmap(mBitmapCache.get(
- item.getConversation().getName(
- useSubject), item
- .getConversation()
- .getContact(),
- getActivity()
- .getApplicationContext()));
- viewHolder.contact_picture.setAlpha(128);
-
- }
- break;
- default:
- viewHolder = null;
- break;
- }
- } else {
- viewHolder = (ViewHolder) view.getTag();
- }
-
- if (type == STATUS) {
- return view;
- }
-
- if (type == RECIEVED) {
- if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
- viewHolder.contact_picture.setImageBitmap(mBitmapCache
- .get(item.getCounterpart(), null, getActivity()
- .getApplicationContext()));
- viewHolder.contact_picture
- .setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- highlightInConference(item
- .getCounterpart());
- }
- });
- }
+ public void onContactPictureClicked(Message message) {
+ if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
+ highlightInConference(message.getCounterpart());
}
-
- if (item.getType() == Message.TYPE_IMAGE) {
- if (item.getStatus() == Message.STATUS_RECIEVING) {
- displayInfoMessage(viewHolder, R.string.receiving_image);
- } else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
- viewHolder.image.setVisibility(View.GONE);
- viewHolder.messageBody.setVisibility(View.GONE);
- viewHolder.download_button.setVisibility(View.VISIBLE);
- viewHolder.download_button
- .setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- JingleConnection connection = item
- .getJingleConnection();
- if (connection != null) {
- connection.accept();
- }
- }
- });
- } else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
- || (item.getEncryption() == Message.ENCRYPTION_NONE)
- || (item.getEncryption() == Message.ENCRYPTION_OTR)) {
- displayImageMessage(viewHolder, item);
- } else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
- displayInfoMessage(viewHolder,
- R.string.encrypted_message);
- } else {
- displayDecryptionFailed(viewHolder);
- }
- } else {
- if (item.getEncryption() == Message.ENCRYPTION_PGP) {
- if (activity.hasPgp()) {
- displayInfoMessage(viewHolder,
- R.string.encrypted_message);
- } else {
- displayInfoMessage(viewHolder,
- R.string.install_openkeychain);
- viewHolder.message_box
- .setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- activity.showInstallPgpDialog();
- }
- });
- }
- } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
- displayDecryptionFailed(viewHolder);
- } else {
- displayTextMessage(viewHolder, item.getBody());
- }
- }
-
- displayStatus(viewHolder, item);
-
- return view;
}
- };
+ });
messagesView.setAdapter(messageListAdapter);
return view;
@@ -582,17 +218,6 @@ public class ConversationFragment extends Fragment {
Selection.setSelection(etext, position);
}
- protected Bitmap findSelfPicture() {
- SharedPreferences sharedPref = PreferenceManager
- .getDefaultSharedPreferences(getActivity()
- .getApplicationContext());
- boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
- "show_phone_selfcontact_picture", true);
-
- return UIHelper.getSelfContactPicture(conversation.getAccount(), 48,
- showPhoneSelfContactPicture, getActivity());
- }
-
@Override
public void onStart() {
super.onStart();
@@ -633,7 +258,6 @@ public class ConversationFragment extends Fragment {
int position = chatMsg.length();
Editable etext = chatMsg.getText();
Selection.setSelection(etext, position);
- this.selfBitmap = findSelfPicture();
updateMessages();
if (activity.getSlidingPaneLayout().isSlideable()) {
if (!activity.shouldPaneBeOpen()) {
@@ -645,34 +269,6 @@ public class ConversationFragment extends Fragment {
activity.invalidateOptionsMenu();
}
}
- if (conversation.getMode() == Conversation.MODE_MULTI) {
- activity.xmppConnectionService
- .setOnRenameListener(new OnRenameListener() {
-
- @Override
- public void onRename(final boolean success) {
- activity.xmppConnectionService
- .updateConversation(conversation);
- getActivity().runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- if (success) {
- Toast.makeText(
- getActivity(),
- getString(R.string.your_nick_has_been_changed),
- Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(
- getActivity(),
- getString(R.string.nick_in_use),
- Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
- });
- }
}
private void decryptMessage(Message message) {
@@ -683,7 +279,8 @@ public class ConversationFragment extends Fragment {
@Override
public void userInputRequried(PendingIntent pi, Message message) {
askForPassphraseIntent = pi.getIntentSender();
- showSnackbar(R.string.openpgp_messages_found,R.string.decrypt,clickToDecryptListener);
+ showSnackbar(R.string.openpgp_messages_found,
+ R.string.decrypt, clickToDecryptListener);
}
@Override
@@ -706,8 +303,20 @@ public class ConversationFragment extends Fragment {
if (getView() == null) {
return;
}
- ConversationActivity activity = (ConversationActivity) getActivity();
+ hideSnackbar();
+ final ConversationActivity activity = (ConversationActivity) getActivity();
if (this.conversation != null) {
+ final Contact contact = this.conversation.getContact();
+ if (!contact.showInRoster() && contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
+ showSnackbar(R.string.contact_added_you, R.string.add_back, new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ activity.xmppConnectionService.createContact(contact);
+ activity.switchToContactDetails(contact);
+ }
+ });
+ }
for (Message message : this.conversation.getMessages()) {
if ((message.getEncryption() == Message.ENCRYPTION_PGP)
&& ((message.getStatus() == Message.STATUS_RECIEVED) || (message
@@ -734,10 +343,14 @@ public class ConversationFragment extends Fragment {
makeFingerprintWarning(conversation.getLatestEncryption());
}
} else {
- if (conversation.getMucOptions().getError() != 0) {
- showSnackbar(R.string.nick_in_use, R.string.edit,clickToMuc);
+ if (!conversation.getMucOptions().online()
+ && conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
- showSnackbar(R.string.nick_in_use, R.string.edit,clickToMuc);
+ showSnackbar(R.string.nick_in_use, R.string.edit,
+ clickToMuc);
+ } else if (conversation.getMucOptions().getError() == MucOptions.ERROR_ROOM_NOT_FOUND) {
+ showSnackbar(R.string.conference_not_found,
+ R.string.leave, leaveMuc);
}
}
}
@@ -792,28 +405,31 @@ public class ConversationFragment extends Fragment {
&& (conversation.hasValidOtrSession()
&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
.contains(conversation.getOtrFingerprint())))) {
- showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, new OnClickListener() {
+ showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify,
+ new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (conversation.getOtrFingerprint() != null) {
- AlertDialog dialog = UIHelper.getVerifyFingerprintDialog(
- (ConversationActivity) getActivity(), conversation,
- snackbar);
- dialog.show();
- }
- }
- });
+ @Override
+ public void onClick(View v) {
+ if (conversation.getOtrFingerprint() != null) {
+ AlertDialog dialog = UIHelper
+ .getVerifyFingerprintDialog(
+ (ConversationActivity) getActivity(),
+ conversation, snackbar);
+ dialog.show();
+ }
+ }
+ });
}
}
-
- protected void showSnackbar(int message, int action, OnClickListener clickListener) {
+
+ protected void showSnackbar(int message, int action,
+ OnClickListener clickListener) {
snackbar.setVisibility(View.VISIBLE);
snackbarMessage.setText(message);
snackbarAction.setText(action);
snackbarAction.setOnClickListener(clickListener);
}
-
+
protected void hideSnackbar() {
snackbar.setVisibility(View.GONE);
}
@@ -939,38 +555,6 @@ public class ConversationFragment extends Fragment {
}
}
- private static class ViewHolder {
-
- protected LinearLayout message_box;
- protected Button download_button;
- protected ImageView image;
- protected ImageView indicator;
- protected TextView time;
- protected TextView messageBody;
- protected ImageView contact_picture;
-
- }
-
- private class BitmapCache {
- private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
-
- public Bitmap get(String name, Contact contact, Context context) {
- if (bitmaps.containsKey(name)) {
- return bitmaps.get(name);
- } else {
- Bitmap bm;
- if (contact != null) {
- bm = UIHelper
- .getContactPicture(contact, 48, context, false);
- } else {
- bm = UIHelper.getContactPicture(name, 48, context, false);
- }
- bitmaps.put(name, bm);
- return bm;
- }
- }
- }
-
public void setText(String text) {
this.pastedText = text;
}
diff --git a/src/eu/siacs/conversations/ui/EditAccount.java b/src/eu/siacs/conversations/ui/EditAccountDialog.java
index 9a0b8d84..7c135fc1 100644
--- a/src/eu/siacs/conversations/ui/EditAccount.java
+++ b/src/eu/siacs/conversations/ui/EditAccountDialog.java
@@ -4,7 +4,7 @@ import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.utils.KnownHostsAdapter;
+import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
import eu.siacs.conversations.utils.Validator;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -21,7 +21,7 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.TextView;
-public class EditAccount extends DialogFragment {
+public class EditAccountDialog extends DialogFragment {
protected Account account;
diff --git a/src/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
index c3f1e105..e56e2db9 100644
--- a/src/eu/siacs/conversations/ui/ManageAccountActivity.java
+++ b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
@@ -6,8 +6,7 @@ import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
-import eu.siacs.conversations.ui.EditAccount.EditAccountListener;
-import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
+import eu.siacs.conversations.ui.EditAccountDialog.EditAccountListener;
import eu.siacs.conversations.xmpp.XmppConnection;
import android.app.Activity;
import android.app.AlertDialog;
@@ -59,57 +58,6 @@ public class ManageAccountActivity extends XmppActivity {
}
};
- protected OnTLSExceptionReceived tlsExceptionReceived = new OnTLSExceptionReceived() {
-
- @Override
- public void onTLSExceptionReceived(final String fingerprint,
- final Account account) {
- activity.runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- AlertDialog.Builder builder = new AlertDialog.Builder(
- activity);
- builder.setTitle(getString(R.string.account_status_error));
- builder.setIconAttribute(android.R.attr.alertDialogIcon);
- View view = (View) getLayoutInflater().inflate(
- R.layout.cert_warning, null);
- TextView sha = (TextView) view.findViewById(R.id.sha);
- TextView hint = (TextView) view.findViewById(R.id.hint);
- StringBuilder humanReadableSha = new StringBuilder();
- humanReadableSha.append(fingerprint);
- for (int i = 2; i < 59; i += 3) {
- if ((i == 14) || (i == 29) || (i == 44)) {
- humanReadableSha.insert(i, "\n");
- } else {
- humanReadableSha.insert(i, ":");
- }
-
- }
- hint.setText(getString(R.string.untrusted_cert_hint,
- account.getServer()));
- sha.setText(humanReadableSha.toString());
- builder.setView(view);
- builder.setNegativeButton(
- getString(R.string.certif_no_trust), null);
- builder.setPositiveButton(getString(R.string.certif_trust),
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- account.setSSLCertFingerprint(fingerprint);
- activity.xmppConnectionService
- .updateAccount(account);
- }
- });
- builder.create().show();
- }
- });
-
- }
- };
-
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -172,11 +120,6 @@ public class ManageAccountActivity extends XmppActivity {
.setText(getString(R.string.account_status_requires_tls));
statusView.setTextColor(0xFFe92727);
break;
- case Account.STATUS_TLS_ERROR:
- statusView
- .setText(getString(R.string.account_status_error));
- statusView.setTextColor(0xFFe92727);
- break;
case Account.STATUS_REGISTRATION_FAILED:
statusView
.setText(getString(R.string.account_status_regis_fail));
@@ -214,14 +157,13 @@ public class ManageAccountActivity extends XmppActivity {
int position, long arg3) {
if (!isActionMode) {
Account account = accountList.get(position);
- if ((account.getStatus() == Account.STATUS_OFFLINE)
- || (account.getStatus() == Account.STATUS_TLS_ERROR)) {
+ if (account.getStatus() == Account.STATUS_OFFLINE) {
activity.xmppConnectionService.reconnectAccount(
accountList.get(position), true);
} else if (account.getStatus() == Account.STATUS_ONLINE) {
activity.startActivity(new Intent(activity
.getApplicationContext(),
- StartConversation.class));
+ StartConversationActivity.class));
} else if (account.getStatus() != Account.STATUS_DISABLED) {
editAccount(account);
}
@@ -471,7 +413,6 @@ public class ManageAccountActivity extends XmppActivity {
protected void onStop() {
if (xmppConnectionServiceBound) {
xmppConnectionService.removeOnAccountListChangedListener();
- xmppConnectionService.removeOnTLSExceptionReceivedListener();
}
super.onStop();
}
@@ -479,8 +420,6 @@ public class ManageAccountActivity extends XmppActivity {
@Override
void onBackendConnected() {
xmppConnectionService.setOnAccountListChangedListener(accountChanged);
- xmppConnectionService
- .setOnTLSExceptionReceivedListener(tlsExceptionReceived);
this.accountList.clear();
this.accountList.addAll(xmppConnectionService.getAccounts());
accountListViewAdapter.notifyDataSetChanged();
@@ -513,7 +452,7 @@ public class ManageAccountActivity extends XmppActivity {
@Override
public boolean onNavigateUp() {
if (xmppConnectionService.getConversations().size() == 0) {
- Intent contactsIntent = new Intent(this, StartConversation.class);
+ Intent contactsIntent = new Intent(this, StartConversationActivity.class);
contactsIntent.setFlags(
// if activity exists in stack, pop the stack and go back to it
Intent.FLAG_ACTIVITY_CLEAR_TOP |
@@ -531,7 +470,7 @@ public class ManageAccountActivity extends XmppActivity {
}
private void editAccount(Account account) {
- EditAccount dialog = new EditAccount();
+ EditAccountDialog dialog = new EditAccountDialog();
dialog.setAccount(account);
dialog.setEditAccountListener(new EditAccountListener() {
@@ -550,7 +489,7 @@ public class ManageAccountActivity extends XmppActivity {
protected void addAccount() {
final Activity activity = this;
- EditAccount dialog = new EditAccount();
+ EditAccountDialog dialog = new EditAccountDialog();
dialog.setEditAccountListener(new EditAccountListener() {
@Override
diff --git a/src/eu/siacs/conversations/ui/MucDetailsActivity.java b/src/eu/siacs/conversations/ui/MucDetailsActivity.java
deleted file mode 100644
index 8226e381..00000000
--- a/src/eu/siacs/conversations/ui/MucDetailsActivity.java
+++ /dev/null
@@ -1,214 +0,0 @@
-package eu.siacs.conversations.ui;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.openintents.openpgp.util.OpenPgpUtils;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.crypto.PgpEngine;
-import eu.siacs.conversations.entities.Conversation;
-import eu.siacs.conversations.entities.MucOptions;
-import eu.siacs.conversations.entities.MucOptions.User;
-import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.IntentSender.SendIntentException;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-public class MucDetailsActivity extends XmppActivity {
- public static final String ACTION_VIEW_MUC = "view_muc";
- private Conversation conversation;
- private EditText mYourNick;
- private EditText mSubject;
- private TextView mRoleAffiliaton;
- private TextView mFullJid;
- private LinearLayout membersView;
- private LinearLayout mMoreDetails;
- private Button mInviteButton;
- private String uuid = null;
- private OnClickListener changeNickListener = new OnClickListener() {
-
- @Override
- public void onClick(View arg0) {
- MucOptions options = conversation.getMucOptions();
- String nick = mYourNick.getText().toString();
- if (!options.getNick().equals(nick)) {
- xmppConnectionService.renameInMuc(conversation, nick);
- finish();
- }
- }
- };
-
- private OnClickListener changeSubjectListener = new OnClickListener() {
-
- @Override
- public void onClick(View arg0) {
- String subject = mSubject.getText().toString();
- MucOptions options = conversation.getMucOptions();
- if (!subject.equals(options.getSubject())) {
- MessagePacket packet = xmppConnectionService.getMessageGenerator().conferenceSubject(conversation, subject);
- xmppConnectionService.sendMessagePacket(conversation.getAccount(), packet);
- finish();
- }
- }
- };
-
- private OnClickListener inviteListener = new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- /*Intent intent = new Intent(getApplicationContext(),
- ContactsActivity.class);
- intent.setAction("invite");
- intent.putExtra("uuid",conversation.getUuid());
- startActivity(intent);*/
- }
- };
-
- private List<User> users = new ArrayList<MucOptions.User>();
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_muc_details);
- mYourNick = (EditText) findViewById(R.id.muc_your_nick);
- mFullJid = (TextView) findViewById(R.id.muc_jabberid);
- ImageButton editNickButton = (ImageButton) findViewById(R.id.muc_edit_nick);
- editNickButton.setOnClickListener(this.changeNickListener);
- ImageButton editSubjectButton = (ImageButton) findViewById(R.id.muc_edit_subject);
- editSubjectButton.setOnClickListener(this.changeSubjectListener);
- membersView = (LinearLayout) findViewById(R.id.muc_members);
- mMoreDetails = (LinearLayout) findViewById(R.id.muc_more_details);
- mMoreDetails.setVisibility(View.GONE);
- mSubject = (EditText) findViewById(R.id.muc_subject);
- mInviteButton = (Button) findViewById(R.id.invite);
- mInviteButton.setOnClickListener(inviteListener);
- getActionBar().setHomeButtonEnabled(true);
- getActionBar().setDisplayHomeAsUpEnabled(true);
-
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- switch (menuItem.getItemId()) {
- case android.R.id.home:
- finish();
- }
- return super.onOptionsItemSelected(menuItem);
- }
-
- public String getReadableRole(int role) {
- switch (role) {
- case User.ROLE_MODERATOR:
- return getString(R.string.moderator);
- case User.ROLE_PARTICIPANT:
- return getString(R.string.participant);
- case User.ROLE_VISITOR:
- return getString(R.string.visitor);
- default:
- return "";
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.muc_details, menu);
- return true;
- }
-
- @Override
- void onBackendConnected() {
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
- boolean useSubject = preferences.getBoolean("use_subject_in_muc", true);
- if (getIntent().getAction().equals(ACTION_VIEW_MUC)) {
- this.uuid = getIntent().getExtras().getString("uuid");
- }
- if (uuid != null) {
- for (Conversation mConv : xmppConnectionService.getConversations()) {
- if (mConv.getUuid().equals(uuid)) {
- this.conversation = mConv;
- }
- }
- if (this.conversation != null) {
- mSubject.setText(conversation.getMucOptions().getSubject());
- setTitle(conversation.getName(useSubject));
- mFullJid.setText(conversation.getContactJid().split("/")[0]);
- mYourNick.setText(conversation.getMucOptions().getNick());
- mRoleAffiliaton = (TextView) findViewById(R.id.muc_role);
- if (conversation.getMucOptions().online()) {
- mMoreDetails.setVisibility(View.VISIBLE);
- User self = conversation.getMucOptions().getSelf();
- switch (self.getAffiliation()) {
- case User.AFFILIATION_ADMIN:
- mRoleAffiliaton.setText(getReadableRole(self.getRole())
- + " (" + getString(R.string.admin) + ")");
- break;
- case User.AFFILIATION_OWNER:
- mRoleAffiliaton.setText(getReadableRole(self.getRole())
- + " (" + getString(R.string.owner) + ")");
- break;
- default:
- mRoleAffiliaton
- .setText(getReadableRole(self.getRole()));
- break;
- }
- }
- this.users.clear();
- this.users.addAll(conversation.getMucOptions().getUsers());
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- membersView.removeAllViews();
- for(final User contact : conversation.getMucOptions().getUsers()) {
- View view = (View) inflater.inflate(R.layout.contact, null);
- TextView displayName = (TextView) view.findViewById(R.id.contact_display_name);
- TextView key = (TextView) view.findViewById(R.id.key);
- displayName.setText(contact.getName());
- TextView role = (TextView) view.findViewById(R.id.contact_jid);
- role.setText(getReadableRole(contact.getRole()));
- if (contact.getPgpKeyId()!=0) {
- key.setVisibility(View.VISIBLE);
- key.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- PgpEngine pgp = xmppConnectionService.getPgpEngine();
- if (pgp!=null) {
- PendingIntent intent = pgp.getIntentForKey(conversation.getAccount(), contact.getPgpKeyId());
- if (intent!=null) {
- try {
- startIntentSenderForResult(intent.getIntentSender(), 0, null, 0, 0, 0);
- } catch (SendIntentException e) {
-
- }
- }
- }
- }
- });
- key.setText(OpenPgpUtils.convertKeyIdToHex(contact.getPgpKeyId()));
- }
- ImageView imageView = (ImageView) view
- .findViewById(R.id.contact_photo);
- imageView.setImageBitmap(UIHelper.getContactPicture(contact.getName(), 48,this.getApplicationContext(), false));
- membersView.addView(view);
- }
- }
- } else {
- Log.d("xmppService","uuid in muc details was null");
- }
- }
-}
diff --git a/src/eu/siacs/conversations/ui/OnPresenceSelected.java b/src/eu/siacs/conversations/ui/OnPresenceSelected.java
deleted file mode 100644
index 1c967224..00000000
--- a/src/eu/siacs/conversations/ui/OnPresenceSelected.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package eu.siacs.conversations.ui;
-
-public interface OnPresenceSelected {
- public void onPresenceSelected();
-}
diff --git a/src/eu/siacs/conversations/ui/StartConversation.java b/src/eu/siacs/conversations/ui/StartConversationActivity.java
index c9166c39..d12d2878 100644
--- a/src/eu/siacs/conversations/ui/StartConversation.java
+++ b/src/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -12,6 +12,8 @@ import android.app.Fragment;
import android.app.FragmentTransaction;
import android.app.ListFragment;
import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
@@ -19,11 +21,9 @@ import android.text.Editable;
import android.text.TextWatcher;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
@@ -32,21 +32,20 @@ import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.CheckBox;
import android.widget.EditText;
-import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Spinner;
-import android.widget.TextView;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.ListItem;
-import eu.siacs.conversations.utils.KnownHostsAdapter;
-import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
+import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
+import eu.siacs.conversations.ui.adapter.ListItemAdapter;
import eu.siacs.conversations.utils.Validator;
-public class StartConversation extends XmppActivity {
+public class StartConversationActivity extends XmppActivity {
private Tab mContactsTab;
private Tab mConferencesTab;
@@ -65,7 +64,7 @@ public class StartConversation extends XmppActivity {
private List<String> mKnownConferenceHosts;
private EditText mSearchEditText;
-
+
public int conference_context_id;
public int contact_context_id;
@@ -141,6 +140,19 @@ public class StartConversation extends XmppActivity {
int count) {
}
};
+ private OnRosterUpdate onRosterUpdate = new OnRosterUpdate() {
+
+ @Override
+ public void onRosterUpdate() {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ filter(mSearchEditText.getText().toString());
+ }
+ });
+ }
+ };
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -175,19 +187,20 @@ public class StartConversation extends XmppActivity {
}
});
- mConferenceAdapter = new ListItemAdapter(conferences);
+ mConferenceAdapter = new ListItemAdapter(getApplicationContext(),conferences);
mConferenceListFragment.setListAdapter(mConferenceAdapter);
mConferenceListFragment.setContextMenu(R.menu.conference_context);
- mConferenceListFragment.setOnListItemClickListener(new OnItemClickListener() {
+ mConferenceListFragment
+ .setOnListItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> arg0, View arg1,
- int position, long arg3) {
- openConversationForBookmark(position);
- }
- });
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1,
+ int position, long arg3) {
+ openConversationForBookmark(position);
+ }
+ });
- mContactsAdapter = new ListItemAdapter(contacts);
+ mContactsAdapter = new ListItemAdapter(getApplicationContext(),contacts);
mContactsListFragment.setListAdapter(mContactsAdapter);
mContactsListFragment.setContextMenu(R.menu.contact_context);
mContactsListFragment
@@ -201,6 +214,12 @@ public class StartConversation extends XmppActivity {
});
}
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ xmppConnectionService.removeOnRosterUpdateListener();
+ }
protected void openConversationForContact(int position) {
Contact contact = (Contact) contacts.get(position);
@@ -209,20 +228,25 @@ public class StartConversation extends XmppActivity {
contact.getJid(), false);
switchToConversation(conversation);
}
-
+
protected void openConversationForContact() {
int position = contact_context_id;
openConversationForContact(position);
}
-
+
protected void openConversationForBookmark() {
openConversationForBookmark(conference_context_id);
}
-
+
protected void openConversationForBookmark(int position) {
Bookmark bookmark = (Bookmark) conferences.get(position);
- Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), bookmark.getJid(), true);
+ Conversation conversation = xmppConnectionService
+ .findOrCreateConversation(bookmark.getAccount(),
+ bookmark.getJid(), true);
conversation.setBookmark(bookmark);
+ if (!conversation.getMucOptions().online()) {
+ xmppConnectionService.joinMuc(conversation);
+ }
if (!bookmark.autojoin()) {
bookmark.setAutojoin(true);
xmppConnectionService.pushBookmarks(bookmark.getAccount());
@@ -238,18 +262,48 @@ public class StartConversation extends XmppActivity {
protected void deleteContact() {
int position = contact_context_id;
- Contact contact = (Contact) contacts.get(position);
- xmppConnectionService.deleteContactOnServer(contact);
- filter(mSearchEditText.getText().toString());
+ final Contact contact = (Contact) contacts.get(position);
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setTitle(R.string.action_delete_contact);
+ builder.setMessage(
+ getString(R.string.remove_contact_text,
+ contact.getJid()));
+ builder.setPositiveButton(R.string.delete,new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ xmppConnectionService.deleteContactOnServer(contact);
+ filter(mSearchEditText.getText().toString());
+ }
+ });
+ builder.create().show();
+
}
-
+
protected void deleteConference() {
- int position = contact_context_id;
- Bookmark bookmark = (Bookmark) conferences.get(position);
- Account account = bookmark.getAccount();
- account.getBookmarks().remove(bookmark);
- xmppConnectionService.pushBookmarks(account);
- filter(mSearchEditText.getText().toString());
+ int position = conference_context_id;
+ final Bookmark bookmark = (Bookmark) conferences.get(position);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setTitle(R.string.delete_bookmark);
+ builder.setMessage(
+ getString(R.string.remove_bookmark_text,
+ bookmark.getJid()));
+ builder.setPositiveButton(R.string.delete,new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ bookmark.unregisterConversation();
+ Account account = bookmark.getAccount();
+ account.getBookmarks().remove(bookmark);
+ xmppConnectionService.pushBookmarks(account);
+ filter(mSearchEditText.getText().toString());
+ }
+ });
+ builder.create().show();
+
}
protected void showCreateContactDialog() {
@@ -307,7 +361,8 @@ public class StartConversation extends XmppActivity {
jid.setAdapter(new KnownHostsAdapter(this,
android.R.layout.simple_list_item_1, mKnownConferenceHosts));
populateAccountSpinner(spinner);
- final CheckBox bookmarkCheckBox = (CheckBox) dialogView.findViewById(R.id.bookmark);
+ final CheckBox bookmarkCheckBox = (CheckBox) dialogView
+ .findViewById(R.id.bookmark);
builder.setView(dialogView);
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(R.string.join, null);
@@ -328,20 +383,28 @@ public class StartConversation extends XmppActivity {
if (account.hasBookmarkFor(conferenceJid)) {
jid.setError(getString(R.string.bookmark_already_exists));
} else {
- Bookmark bookmark = new Bookmark(account, conferenceJid);
+ Bookmark bookmark = new Bookmark(account,
+ conferenceJid);
bookmark.setAutojoin(true);
account.getBookmarks().add(bookmark);
- xmppConnectionService.pushBookmarks(account);
+ xmppConnectionService
+ .pushBookmarks(account);
Conversation conversation = xmppConnectionService
.findOrCreateConversation(account,
conferenceJid, true);
conversation.setBookmark(bookmark);
- switchToConversation(conversation);
+ if (!conversation.getMucOptions().online()) {
+ xmppConnectionService.joinMuc(conversation);
+ }
+ switchToConversation(conversation);
}
} else {
Conversation conversation = xmppConnectionService
- .findOrCreateConversation(account,
- conferenceJid, true);
+ .findOrCreateConversation(account,
+ conferenceJid, true);
+ if (!conversation.getMucOptions().online()) {
+ xmppConnectionService.joinMuc(conversation);
+ }
switchToConversation(conversation);
}
} else {
@@ -401,6 +464,7 @@ public class StartConversation extends XmppActivity {
@Override
void onBackendConnected() {
+ xmppConnectionService.setOnRosterUpdateListener(this.onRosterUpdate );
if (mSearchEditText != null) {
filter(mSearchEditText.getText().toString());
} else {
@@ -416,7 +480,7 @@ public class StartConversation extends XmppActivity {
this.mKnownConferenceHosts = xmppConnectionService
.getKnownConferenceHosts();
}
-
+
protected void filter(String needle) {
this.filterContacts(needle);
this.filterConferences(needle);
@@ -436,12 +500,12 @@ public class StartConversation extends XmppActivity {
Collections.sort(this.contacts);
mContactsAdapter.notifyDataSetChanged();
}
-
+
protected void filterConferences(String needle) {
this.conferences.clear();
for (Account account : xmppConnectionService.getAccounts()) {
if (account.getStatus() != Account.STATUS_DISABLED) {
- for(Bookmark bookmark : account.getBookmarks()) {
+ for (Bookmark bookmark : account.getBookmarks()) {
if (bookmark.match(needle)) {
this.conferences.add(bookmark);
}
@@ -456,37 +520,10 @@ public class StartConversation extends XmppActivity {
invalidateOptionsMenu();
}
- private class ListItemAdapter extends ArrayAdapter<ListItem> {
-
- public ListItemAdapter(List<ListItem> objects) {
- super(getApplicationContext(), 0, objects);
- }
-
- @Override
- public View getView(int position, View view, ViewGroup parent) {
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- ListItem item = getItem(position);
- if (view == null) {
- view = (View) inflater.inflate(R.layout.contact, null);
- }
- TextView name = (TextView) view
- .findViewById(R.id.contact_display_name);
- TextView jid = (TextView) view.findViewById(R.id.contact_jid);
- ImageView picture = (ImageView) view
- .findViewById(R.id.contact_photo);
-
- jid.setText(item.getJid());
- name.setText(item.getDisplayName());
- picture.setImageBitmap(item.getImage(48, getApplicationContext()));
- return view;
- }
-
- }
-
public static class MyListFragment extends ListFragment {
private AdapterView.OnItemClickListener mOnItemClickListener;
private int mResContextMenu;
-
+
public void setContextMenu(int res) {
this.mResContextMenu = res;
}
@@ -512,9 +549,8 @@ public class StartConversation extends XmppActivity {
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
- StartConversation activity = (StartConversation) getActivity();
- activity.getMenuInflater().inflate(mResContextMenu,
- menu);
+ StartConversationActivity activity = (StartConversationActivity) getActivity();
+ activity.getMenuInflater().inflate(mResContextMenu, menu);
AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
if (mResContextMenu == R.menu.conference_context) {
activity.conference_context_id = acmi.position;
@@ -525,7 +561,7 @@ public class StartConversation extends XmppActivity {
@Override
public boolean onContextItemSelected(MenuItem item) {
- StartConversation activity = (StartConversation) getActivity();
+ StartConversationActivity activity = (StartConversationActivity) getActivity();
switch (item.getItemId()) {
case R.id.context_start_conversation:
activity.openConversationForContact();
diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java
index 217bae55..fad4d026 100644
--- a/src/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/eu/siacs/conversations/ui/XmppActivity.java
@@ -27,16 +27,29 @@ import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
public abstract class XmppActivity extends Activity {
public static final int REQUEST_ANNOUNCE_PGP = 0x73731;
+ protected static final int REQUEST_INVITE_TO_CONVERSATION = 0x341830;
protected final static String LOGTAG = "xmppService";
public XmppConnectionService xmppConnectionService;
public boolean xmppConnectionServiceBound = false;
protected boolean handledViewIntent = false;
+
+ protected int mPrimaryTextColor;
+ protected int mSecondaryTextColor;
+
+ protected interface OnValueEdited {
+ public void onValueEdited(String value);
+ }
+
+ public interface OnPresenceSelected {
+ public void onPresenceSelected();
+ }
protected ServiceConnection mConnection = new ServiceConnection() {
@@ -147,6 +160,8 @@ public abstract class XmppActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExceptionHelper.init(getApplicationContext());
+ mPrimaryTextColor = getResources().getColor(R.color.primarytext);
+ mSecondaryTextColor = getResources().getColor(R.color.secondarytext);
}
public void switchToConversation(Conversation conversation) {
@@ -183,6 +198,12 @@ public abstract class XmppActivity extends Activity {
startActivity(intent);
}
+ protected void inviteToConversation(Conversation conversation) {
+ Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class);
+ intent.putExtra("conversation",conversation.getUuid());
+ startActivityForResult(intent, REQUEST_INVITE_TO_CONVERSATION);
+ }
+
protected void announcePgp(Account account, final Conversation conversation) {
xmppConnectionService.getPgpEngine().generateSignature(account,
"online", new UiCallback<Account>() {
@@ -193,10 +214,7 @@ public abstract class XmppActivity extends Activity {
try {
startIntentSenderForResult(pi.getIntentSender(),
REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
- } catch (SendIntentException e) {
- Log.d("xmppService",
- "coulnd start intent for pgp anncouncment");
- }
+ } catch (SendIntentException e) {}
}
@Override
@@ -251,11 +269,32 @@ public abstract class XmppActivity extends Activity {
Account account = conversation.getAccount();
Contact contact = account.getRoster().getContact(jid);
xmppConnectionService.createContact(contact);
+ switchToContactDetails(contact);
}
});
builder.create().show();
}
+ protected void quickEdit(final String previousValue, final OnValueEdited callback) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ View view = (View) getLayoutInflater().inflate(R.layout.quickedit, null);
+ final EditText editor = (EditText) view.findViewById(R.id.editor);
+ editor.setText(previousValue);
+ builder.setView(view);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.edit, new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String value = editor.getText().toString();
+ if (!previousValue.equals(value) && value.trim().length() > 0) {
+ callback.onValueEdited(value);
+ }
+ }
+ });
+ builder.create().show();
+ }
+
public void selectPresence(final Conversation conversation,
final OnPresenceSelected listener) {
Contact contact = conversation.getContact();
@@ -307,4 +346,26 @@ public abstract class XmppActivity extends Activity {
}
}
}
+
+ protected void onActivityResult(int requestCode, int resultCode,
+ final Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) {
+ String contactJid = data.getStringExtra("contact");
+ String conversationUuid = data.getStringExtra("conversation");
+ Conversation conversation = xmppConnectionService.findConversationByUuid(conversationUuid);
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ xmppConnectionService.invite(conversation, contactJid);
+ }
+ Log.d("xmppService","inviting "+contactJid+" to "+conversation.getName(true));
+ }
+ }
+
+ public int getSecondaryTextColor() {
+ return this.mSecondaryTextColor;
+ }
+
+ public int getPrimaryTextColor() {
+ return this.mPrimaryTextColor;
+ }
}
diff --git a/src/eu/siacs/conversations/utils/KnownHostsAdapter.java b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
index a0a223dd..040e6266 100644
--- a/src/eu/siacs/conversations/utils/KnownHostsAdapter.java
+++ b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
@@ -1,4 +1,4 @@
-package eu.siacs.conversations.utils;
+package eu.siacs.conversations.ui.adapter;
import java.util.ArrayList;
import java.util.List;
@@ -42,7 +42,7 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
- ArrayList<String> filteredList = ((ArrayList<String>) results.values);
+ ArrayList<String> filteredList = (ArrayList<String>) results.values;
if (results != null && results.count > 0) {
clear();
for (String c : filteredList) {
diff --git a/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
new file mode 100644
index 00000000..9ef427fc
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
@@ -0,0 +1,39 @@
+package eu.siacs.conversations.ui.adapter;
+
+import java.util.List;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.ListItem;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class ListItemAdapter extends ArrayAdapter<ListItem> {
+
+ public ListItemAdapter(Context context, List<ListItem> objects) {
+ super(context, 0, objects);
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ ListItem item = getItem(position);
+ if (view == null) {
+ view = (View) inflater.inflate(R.layout.contact, null);
+ }
+ TextView name = (TextView) view.findViewById(R.id.contact_display_name);
+ TextView jid = (TextView) view.findViewById(R.id.contact_jid);
+ ImageView picture = (ImageView) view.findViewById(R.id.contact_photo);
+
+ jid.setText(item.getJid());
+ name.setText(item.getDisplayName());
+ picture.setImageBitmap(item.getImage(48, getContext()));
+ return view;
+ }
+
+} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
new file mode 100644
index 00000000..0a2857d2
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -0,0 +1,478 @@
+package eu.siacs.conversations.ui.adapter;
+
+import java.util.HashMap;
+import java.util.List;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.ImageProvider;
+import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.jingle.JingleConnection;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.Typeface;
+import android.preference.PreferenceManager;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class MessageAdapter extends ArrayAdapter<Message> {
+
+ private static final int SENT = 0;
+ private static final int RECIEVED = 1;
+ private static final int STATUS = 2;
+
+ private ConversationActivity activity;
+
+ private Bitmap selfBitmap2;
+
+ private BitmapCache mBitmapCache = new BitmapCache();
+ private DisplayMetrics metrics;
+
+ private boolean useSubject = true;
+
+ private OnContactPictureClicked mOnContactPictureClickedListener;
+
+ public MessageAdapter(ConversationActivity activity, List<Message> messages) {
+ super(activity, 0, messages);
+ this.activity = activity;
+ metrics = getContext().getResources().getDisplayMetrics();
+ SharedPreferences preferences = PreferenceManager
+ .getDefaultSharedPreferences(getContext());
+ useSubject = preferences.getBoolean("use_subject_in_muc", true);
+ }
+
+ private Bitmap getSelfBitmap() {
+ if (this.selfBitmap2 == null) {
+
+ if (getCount() > 0) {
+ SharedPreferences preferences = PreferenceManager
+ .getDefaultSharedPreferences(getContext());
+ boolean showPhoneSelfContactPicture = preferences.getBoolean(
+ "show_phone_selfcontact_picture", true);
+
+ this.selfBitmap2 = UIHelper.getSelfContactPicture(getItem(0)
+ .getConversation().getAccount(), 48,
+ showPhoneSelfContactPicture, getContext());
+ }
+ }
+ return this.selfBitmap2;
+ }
+
+ public void setOnContactPictureClicked(OnContactPictureClicked listener) {
+ this.mOnContactPictureClickedListener = listener;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 3;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (getItem(position).getType() == Message.TYPE_STATUS) {
+ return STATUS;
+ } else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
+ return RECIEVED;
+ } else {
+ return SENT;
+ }
+ }
+
+ private void displayStatus(ViewHolder viewHolder, Message message) {
+ String filesize = null;
+ String info = null;
+ boolean error = false;
+ boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
+ && message.getStatus() <= Message.STATUS_RECIEVED;
+ if (message.getType() == Message.TYPE_IMAGE) {
+ String[] fileParams = message.getBody().split(",");
+ try {
+ long size = Long.parseLong(fileParams[0]);
+ filesize = size / 1024 + " KB";
+ } catch (NumberFormatException e) {
+ filesize = "0 KB";
+ }
+ }
+ switch (message.getStatus()) {
+ case Message.STATUS_WAITING:
+ info = getContext().getString(R.string.waiting);
+ break;
+ case Message.STATUS_UNSEND:
+ info = getContext().getString(R.string.sending);
+ break;
+ case Message.STATUS_OFFERED:
+ info = getContext().getString(R.string.offering);
+ break;
+ case Message.STATUS_SEND_FAILED:
+ info = getContext().getString(R.string.send_failed);
+ error = true;
+ break;
+ case Message.STATUS_SEND_REJECTED:
+ info = getContext().getString(R.string.send_rejected);
+ error = true;
+ break;
+ case Message.STATUS_RECEPTION_FAILED:
+ info = getContext().getString(R.string.reception_failed);
+ error = true;
+ default:
+ if (multiReceived) {
+ info = message.getCounterpart();
+ }
+ break;
+ }
+ if (error) {
+ viewHolder.time.setTextColor(0xFFe92727);
+ } else {
+ viewHolder.time.setTextColor(activity.getSecondaryTextColor());
+ }
+ if (message.getEncryption() == Message.ENCRYPTION_NONE) {
+ viewHolder.indicator.setVisibility(View.GONE);
+ } else {
+ viewHolder.indicator.setVisibility(View.VISIBLE);
+ }
+
+ String formatedTime = UIHelper.readableTimeDifference(getContext(),
+ message.getTimeSent());
+ if (message.getStatus() <= Message.STATUS_RECIEVED) {
+ if ((filesize != null) && (info != null)) {
+ viewHolder.time.setText(filesize + " \u00B7 " + info);
+ } else if ((filesize == null) && (info != null)) {
+ viewHolder.time.setText(formatedTime + " \u00B7 " + info);
+ } else if ((filesize != null) && (info == null)) {
+ viewHolder.time.setText(formatedTime + " \u00B7 " + filesize);
+ } else {
+ viewHolder.time.setText(formatedTime);
+ }
+ } else {
+ if ((filesize != null) && (info != null)) {
+ viewHolder.time.setText(filesize + " \u00B7 " + info);
+ } else if ((filesize == null) && (info != null)) {
+ if (error) {
+ viewHolder.time.setText(info + " \u00B7 " + formatedTime);
+ } else {
+ viewHolder.time.setText(info);
+ }
+ } else if ((filesize != null) && (info == null)) {
+ viewHolder.time.setText(filesize + " \u00B7 " + formatedTime);
+ } else {
+ viewHolder.time.setText(formatedTime);
+ }
+ }
+ }
+
+ private void displayInfoMessage(ViewHolder viewHolder, int r) {
+ if (viewHolder.download_button != null) {
+ viewHolder.download_button.setVisibility(View.GONE);
+ }
+ viewHolder.image.setVisibility(View.GONE);
+ viewHolder.messageBody.setVisibility(View.VISIBLE);
+ viewHolder.messageBody.setText(getContext().getString(r));
+ viewHolder.messageBody.setTextColor(0xff33B5E5);
+ viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
+ viewHolder.messageBody.setTextIsSelectable(false);
+ }
+
+ private void displayDecryptionFailed(ViewHolder viewHolder) {
+ if (viewHolder.download_button != null) {
+ viewHolder.download_button.setVisibility(View.GONE);
+ }
+ viewHolder.image.setVisibility(View.GONE);
+ viewHolder.messageBody.setVisibility(View.VISIBLE);
+ viewHolder.messageBody.setText(getContext().getString(
+ R.string.decryption_failed));
+ viewHolder.messageBody.setTextColor(0xFFe92727);
+ viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
+ viewHolder.messageBody.setTextIsSelectable(false);
+ }
+
+ private void displayTextMessage(ViewHolder viewHolder, String text) {
+ if (viewHolder.download_button != null) {
+ viewHolder.download_button.setVisibility(View.GONE);
+ }
+ viewHolder.image.setVisibility(View.GONE);
+ viewHolder.messageBody.setVisibility(View.VISIBLE);
+ if (text != null) {
+ viewHolder.messageBody.setText(text.trim());
+ } else {
+ viewHolder.messageBody.setText("");
+ }
+ viewHolder.messageBody.setTextColor(activity.getPrimaryTextColor());
+ viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
+ viewHolder.messageBody.setTextIsSelectable(true);
+ }
+
+ private void displayImageMessage(ViewHolder viewHolder,
+ final Message message) {
+ if (viewHolder.download_button != null) {
+ viewHolder.download_button.setVisibility(View.GONE);
+ }
+ viewHolder.messageBody.setVisibility(View.GONE);
+ viewHolder.image.setVisibility(View.VISIBLE);
+ String[] fileParams = message.getBody().split(",");
+ if (fileParams.length == 3) {
+ double target = metrics.density * 288;
+ int w = Integer.parseInt(fileParams[1]);
+ int h = Integer.parseInt(fileParams[2]);
+ int scalledW;
+ int scalledH;
+ if (w <= h) {
+ scalledW = (int) (w / ((double) h / target));
+ scalledH = (int) target;
+ } else {
+ scalledW = (int) target;
+ scalledH = (int) (h / ((double) w / target));
+ }
+ viewHolder.image.setLayoutParams(new LinearLayout.LayoutParams(
+ scalledW, scalledH));
+ }
+ activity.loadBitmap(message, viewHolder.image);
+ viewHolder.image.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setDataAndType(ImageProvider.getContentUri(message),
+ "image/*");
+ getContext().startActivity(intent);
+ }
+ });
+ viewHolder.image.setOnLongClickListener(new OnLongClickListener() {
+
+ @Override
+ public boolean onLongClick(View v) {
+ Intent shareIntent = new Intent();
+ shareIntent.setAction(Intent.ACTION_SEND);
+ shareIntent.putExtra(Intent.EXTRA_STREAM,
+ ImageProvider.getContentUri(message));
+ shareIntent.setType("image/webp");
+ getContext().startActivity(
+ Intent.createChooser(shareIntent,
+ getContext().getText(R.string.share_with)));
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ final Message item = getItem(position);
+ int type = getItemViewType(position);
+ ViewHolder viewHolder;
+ if (view == null) {
+ viewHolder = new ViewHolder();
+ switch (type) {
+ case SENT:
+ view = (View) activity.getLayoutInflater().inflate(
+ R.layout.message_sent, null);
+ viewHolder.message_box = (LinearLayout) view
+ .findViewById(R.id.message_box);
+ viewHolder.contact_picture = (ImageView) view
+ .findViewById(R.id.message_photo);
+ viewHolder.contact_picture.setImageBitmap(getSelfBitmap());
+ viewHolder.indicator = (ImageView) view
+ .findViewById(R.id.security_indicator);
+ viewHolder.image = (ImageView) view
+ .findViewById(R.id.message_image);
+ viewHolder.messageBody = (TextView) view
+ .findViewById(R.id.message_body);
+ viewHolder.time = (TextView) view
+ .findViewById(R.id.message_time);
+ view.setTag(viewHolder);
+ break;
+ case RECIEVED:
+ view = (View) activity.getLayoutInflater().inflate(
+ R.layout.message_recieved, null);
+ viewHolder.message_box = (LinearLayout) view
+ .findViewById(R.id.message_box);
+ viewHolder.contact_picture = (ImageView) view
+ .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(mBitmapCache.get(
+ item.getConversation().getName(useSubject), item
+ .getConversation().getContact(),
+ getContext()));
+
+ }
+ viewHolder.indicator = (ImageView) view
+ .findViewById(R.id.security_indicator);
+ viewHolder.image = (ImageView) view
+ .findViewById(R.id.message_image);
+ viewHolder.messageBody = (TextView) view
+ .findViewById(R.id.message_body);
+ viewHolder.time = (TextView) view
+ .findViewById(R.id.message_time);
+ view.setTag(viewHolder);
+ break;
+ case STATUS:
+ view = (View) activity.getLayoutInflater().inflate(
+ R.layout.message_status, null);
+ viewHolder.contact_picture = (ImageView) view
+ .findViewById(R.id.message_photo);
+ if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
+
+ viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
+ item.getConversation().getName(useSubject), item
+ .getConversation().getContact(),
+ getContext()));
+ viewHolder.contact_picture.setAlpha(128);
+ viewHolder.contact_picture
+ .setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ String name = item.getConversation()
+ .getName(true);
+ String read = getContext()
+ .getString(
+ R.string.contact_has_read_up_to_this_point,
+ name);
+ Toast.makeText(getContext(), read,
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ }
+ break;
+ default:
+ viewHolder = null;
+ break;
+ }
+ } else {
+ viewHolder = (ViewHolder) view.getTag();
+ }
+
+ if (type == STATUS) {
+ return view;
+ }
+
+ if (type == RECIEVED) {
+ if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
+ viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
+ item.getCounterpart(), null, getContext()));
+ viewHolder.contact_picture
+ .setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ if (MessageAdapter.this.mOnContactPictureClickedListener != null) {
+ MessageAdapter.this.mOnContactPictureClickedListener
+ .onContactPictureClicked(item);
+ ;
+ }
+
+ }
+ });
+ }
+ }
+
+ if (item.getType() == Message.TYPE_IMAGE) {
+ if (item.getStatus() == Message.STATUS_RECIEVING) {
+ displayInfoMessage(viewHolder, R.string.receiving_image);
+ } else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
+ viewHolder.image.setVisibility(View.GONE);
+ viewHolder.messageBody.setVisibility(View.GONE);
+ viewHolder.download_button.setVisibility(View.VISIBLE);
+ viewHolder.download_button
+ .setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ JingleConnection connection = item
+ .getJingleConnection();
+ if (connection != null) {
+ connection.accept();
+ }
+ }
+ });
+ } else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
+ || (item.getEncryption() == Message.ENCRYPTION_NONE)
+ || (item.getEncryption() == Message.ENCRYPTION_OTR)) {
+ displayImageMessage(viewHolder, item);
+ } else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
+ displayInfoMessage(viewHolder, R.string.encrypted_message);
+ } else {
+ displayDecryptionFailed(viewHolder);
+ }
+ } else {
+ if (item.getEncryption() == Message.ENCRYPTION_PGP) {
+ if (activity.hasPgp()) {
+ displayInfoMessage(viewHolder, R.string.encrypted_message);
+ } else {
+ displayInfoMessage(viewHolder,
+ R.string.install_openkeychain);
+ viewHolder.message_box
+ .setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ activity.showInstallPgpDialog();
+ }
+ });
+ }
+ } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
+ displayDecryptionFailed(viewHolder);
+ } else {
+ displayTextMessage(viewHolder, item.getBody());
+ }
+ }
+
+ displayStatus(viewHolder, item);
+
+ return view;
+ }
+
+ private static class ViewHolder {
+
+ protected LinearLayout message_box;
+ protected Button download_button;
+ protected ImageView image;
+ protected ImageView indicator;
+ protected TextView time;
+ protected TextView messageBody;
+ protected ImageView contact_picture;
+
+ }
+
+ private class BitmapCache {
+ private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
+
+ public Bitmap get(String name, Contact contact, Context context) {
+ if (bitmaps.containsKey(name)) {
+ return bitmaps.get(name);
+ } else {
+ Bitmap bm;
+ if (contact != null) {
+ bm = UIHelper
+ .getContactPicture(contact, 48, context, false);
+ } else {
+ bm = UIHelper.getContactPicture(name, 48, context, false);
+ }
+ bitmaps.put(name, bm);
+ return bm;
+ }
+ }
+ }
+
+ public interface OnContactPictureClicked {
+ public void onContactPictureClicked(Message message);
+ }
+}
diff --git a/src/eu/siacs/conversations/utils/UIHelper.java b/src/eu/siacs/conversations/utils/UIHelper.java
index ede43830..1cd3403c 100644
--- a/src/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/eu/siacs/conversations/utils/UIHelper.java
@@ -13,7 +13,6 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
-import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions.User;
import eu.siacs.conversations.ui.ConversationActivity;
@@ -216,7 +215,7 @@ public class UIHelper {
bgColor, fgColor);
}
String[] names = new String[members.size() + 1];
- names[0] = conversation.getMucOptions().getNick();
+ names[0] = conversation.getMucOptions().getActualNick();
for (int i = 0; i < members.size(); ++i) {
names[i + 1] = members.get(i).getName();
}
@@ -343,7 +342,7 @@ public class UIHelper {
if ((currentCon != null)
&& (currentCon.getMode() == Conversation.MODE_MULTI)
&& (!alwaysNotify)) {
- String nick = currentCon.getMucOptions().getNick();
+ String nick = currentCon.getMucOptions().getActualNick();
Pattern highlight = generateNickHighlightPattern(nick);
Matcher m = highlight.matcher(currentCon.getLatestMessage()
.getBody());
@@ -463,7 +462,7 @@ public class UIHelper {
private static boolean wasHighlighted(Conversation conversation) {
List<Message> messages = conversation.getMessages();
- String nick = conversation.getMucOptions().getNick();
+ String nick = conversation.getMucOptions().getActualNick();
Pattern highlight = generateNickHighlightPattern(nick);
for (int i = messages.size() - 1; i >= 0; --i) {
if (messages.get(i).isRead()) {
diff --git a/src/eu/siacs/conversations/utils/Validator.java b/src/eu/siacs/conversations/utils/Validator.java
index 51d8b25c..9ca1e34f 100644
--- a/src/eu/siacs/conversations/utils/Validator.java
+++ b/src/eu/siacs/conversations/utils/Validator.java
@@ -5,7 +5,7 @@ import java.util.regex.Pattern;
public class Validator {
public static final Pattern VALID_JID =
- Pattern.compile("\\b^[A-Z0-9._%+-]+@([A-Z0-9.-]+\\.)?\\d{1,3}[.]\\d{1,3}[.]\\d{1,3}[.]\\d{1,3}\\b$|^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
+ Pattern.compile("\\b^[^@/<>'\"\\s]+@[^@/<>'\"\\s]+$", Pattern.CASE_INSENSITIVE);
public static boolean isValidJid(String jid) {
Matcher matcher = VALID_JID.matcher(jid);
diff --git a/src/eu/siacs/conversations/xmpp/OnTLSExceptionReceived.java b/src/eu/siacs/conversations/xmpp/OnTLSExceptionReceived.java
deleted file mode 100644
index 0e232ee4..00000000
--- a/src/eu/siacs/conversations/xmpp/OnTLSExceptionReceived.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package eu.siacs.conversations.xmpp;
-
-import eu.siacs.conversations.entities.Account;
-
-public interface OnTLSExceptionReceived {
- public void onTLSExceptionReceived(String fingerprint, Account account);
-}
diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java
index 72018394..45bac2f6 100644
--- a/src/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -21,6 +21,7 @@ import java.util.Hashtable;
import java.util.List;
import java.util.Map.Entry;
+import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
@@ -28,8 +29,12 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
+import org.bouncycastle.pqc.math.linearalgebra.GoppaCode.MaMaPe;
import org.xmlpull.v1.XmlPullParserException;
+import de.duenndns.ssl.MemorizingTrustManager;
+
+import android.content.Context;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
@@ -97,11 +102,12 @@ public class XmppConnection implements Runnable {
private OnIqPacketReceived unregisteredIqListener = null;
private OnMessagePacketReceived messageListener = null;
private OnStatusChanged statusListener = null;
- private OnTLSExceptionReceived tlsListener = null;
private OnBindListener bindListener = null;
+ private MemorizingTrustManager mMemorizingTrustManager;
public XmppConnection(Account account, XmppConnectionService service) {
this.mRandom = service.getRNG();
+ this.mMemorizingTrustManager = service.getMemorizingTrustManager();
this.account = account;
this.wakeLock = service.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
account.getJid());
@@ -186,9 +192,7 @@ public class XmppConnection implements Runnable {
}
return;
} catch (IOException e) {
- if (account.getStatus() != Account.STATUS_TLS_ERROR) {
- this.changeStatus(Account.STATUS_OFFLINE);
- }
+ this.changeStatus(Account.STATUS_OFFLINE);
if (wakeLock.isHeld()) {
try { wakeLock.release();} catch (RuntimeException re) {}
}
@@ -440,67 +444,19 @@ public class XmppConnection implements Runnable {
tagReader.readTag();
try {
SSLContext sc = SSLContext.getInstance("TLS");
- TrustManagerFactory tmf = TrustManagerFactory
- .getInstance(TrustManagerFactory.getDefaultAlgorithm());
- try {
- tmf.init((KeyStore) null);
- } catch (KeyStoreException e1) {
- e1.printStackTrace();
- }
-
- TrustManager[] trustManagers = tmf.getTrustManagers();
- final X509TrustManager origTrustmanager = (X509TrustManager) trustManagers[0];
-
- TrustManager[] wrappedTrustManagers = new TrustManager[] { new X509TrustManager() {
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
- origTrustmanager.checkClientTrusted(chain, authType);
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
- try {
- origTrustmanager.checkServerTrusted(chain, authType);
- } catch (CertificateException e) {
- if (e.getCause() instanceof CertPathValidatorException) {
- String sha;
- try {
- MessageDigest sha1 = MessageDigest
- .getInstance("SHA1");
- sha1.update(chain[0].getEncoded());
- sha = CryptoHelper.bytesToHex(sha1.digest());
- if (!sha.equals(account.getSSLFingerprint())) {
- changeStatus(Account.STATUS_TLS_ERROR);
- if (tlsListener != null) {
- tlsListener.onTLSExceptionReceived(sha,
- account);
- }
- throw new CertificateException();
- }
- } catch (NoSuchAlgorithmException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- } else {
- throw new CertificateException();
- }
- }
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return origTrustmanager.getAcceptedIssuers();
- }
-
- } };
- sc.init(null, wrappedTrustManagers, null);
+ sc.init(null, new X509TrustManager[] { this.mMemorizingTrustManager }, mRandom);
SSLSocketFactory factory = sc.getSocketFactory();
+
+ HostnameVerifier verifier = this.mMemorizingTrustManager.wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier());
SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket,
socket.getInetAddress().getHostAddress(), socket.getPort(),
true);
+
+ if (verifier != null && !verifier.verify(account.getServer(), sslSocket.getSession())) {
+ Log.d(LOGTAG, account.getJid() + ": host mismatch in TLS connection");
+ sslSocket.close();
+ throw new IOException();
+ }
tagReader.setInputStream(sslSocket.getInputStream());
tagWriter.setOutputStream(sslSocket.getOutputStream());
sendStartStream();
@@ -508,10 +464,8 @@ public class XmppConnection implements Runnable {
processStream(tagReader.readTag());
sslSocket.close();
} catch (NoSuchAlgorithmException e1) {
- // TODO Auto-generated catch block
e1.printStackTrace();
} catch (KeyManagementException e) {
- // TODO Auto-generated catch block
e.printStackTrace();
}
}
@@ -844,11 +798,6 @@ public class XmppConnection implements Runnable {
this.statusListener = listener;
}
- public void setOnTLSExceptionReceivedListener(
- OnTLSExceptionReceived listener) {
- this.tlsListener = listener;
- }
-
public void setOnBindListener(OnBindListener listener) {
this.bindListener = listener;
}