Compare commits

...

78 Commits

Author SHA1 Message Date
B. Petersen c07a0dedd6 bump version 2018-10-22 23:52:25 +02:00
B. Petersen e5b906184d do not draw buggy deaddrop background for now 2018-10-22 23:50:09 +02:00
B. Petersen 2dbd12403f implement archive/unarchive/delete/leave from chat-activity 2018-10-22 23:14:15 +02:00
daniel.boehrs 9906608956 fix group create crash #103 2018-10-22 19:08:35 +02:00
B. Petersen 5870f0cd02 implement group leaving 2018-10-22 18:09:58 +02:00
B. Petersen 3dc6ea1c85 cleanup chat-menu 2018-10-22 17:47:18 +02:00
B. Petersen e66ae137fe make 'Edit group' a first-class action, tackles #92 2018-10-22 17:06:00 +02:00
B. Petersen 4d32f5746c no special click-handler for ConversationUpdateItem 2018-10-22 16:32:26 +02:00
daniel.boehrs 6e5c6e3d4d Merge branch 'master' of https://github.com/deltachat/deltachat-android-ii 2018-10-22 16:23:54 +02:00
daniel.boehrs c459aa4476 set group image #92 2018-10-22 16:23:42 +02:00
B. Petersen bf4bcba78c remove RecipientModifiedListener from ConversationActivity and ConversationListActivity 2018-10-22 16:21:59 +02:00
B. Petersen ccb5e3285f Update messenger-backend submodule. 2018-10-22 16:12:34 +02:00
daniel.boehrs 5424d56801 edit groups #92 2018-10-22 15:20:24 +02:00
B. Petersen 5c15784f66 hide unused controls in contact-requests, tackles #95 2018-10-22 01:21:15 +02:00
B. Petersen 0abecd74c9 remove unused code 2018-10-22 00:56:42 +02:00
B. Petersen aa3df42f71 ask 'Chat with NAME?' on clicks on a contact request and offer several options, tackles #95. 2018-10-22 00:29:45 +02:00
B. Petersen cfe6e023cb handle msg_id and contact_id in chatlist-items 2018-10-21 23:57:00 +02:00
B. Petersen 6140b2aab4 add a function to get the msg_id from a chatlist-index 2018-10-21 23:55:09 +02:00
B. Petersen cc95e1fa1f show contact request in chatlist with different background 2018-10-21 23:04:58 +02:00
B. Petersen 643e8d80f7 typo 2018-10-21 15:02:12 +02:00
B. Petersen 84cc1c124a show correct title for contact requests 2018-10-21 15:01:33 +02:00
B. Petersen 22d8f3177f remove unused parameters on opening/creating chats 2018-10-21 14:43:44 +02:00
B. Petersen 471f4480ac remove now unused ConversationActivity.DISTRIBUTION_TYPE_EXTRA 2018-10-21 14:36:29 +02:00
B. Petersen bc387096f5 remove dependency from this.distributionType on draft saving 2018-10-21 14:30:41 +02:00
B. Petersen 93b5a345ea remove unused group-options 2018-10-21 14:22:59 +02:00
B. Petersen 50b18b7d65 remove now redundant ConversationActivity.ADDRESS_EXTRA 2018-10-21 14:15:55 +02:00
B. Petersen 004319db64 remove dependency to ConversationActivity.ADDRESS_EXTRA from ConversationFragment 2018-10-21 14:09:33 +02:00
B. Petersen 90b52cebf1 remove TIMING_EXTRA 2018-10-21 13:58:58 +02:00
B. Petersen f4a01a2bae re-add accidentially removed advanced-preference click-handler 2018-10-21 01:28:56 +02:00
B. Petersen 77ed15125d move invite/help to settings 2018-10-21 00:59:11 +02:00
B. Petersen 15ef0271fc add contact-request (aka deaddrop) menu entry, tackles #95 2018-10-21 00:02:19 +02:00
B. Petersen 1dd2ad04ba a click on a deaddrop-message opens a new chat, tackles #95 2018-10-20 23:52:54 +02:00
B. Petersen 0a259d2277 bump version 2018-10-19 23:06:47 +02:00
B. Petersen 9f6a7cbf00 make create groups work again, tackles #92 2018-10-19 23:03:06 +02:00
B. Petersen 5c6e84b21b bump version 2018-10-19 15:30:59 +02:00
B. Petersen 00f0f143af send voice messages as such 2018-10-19 15:29:40 +02:00
B. Petersen 7bcfec2367 send images, audio, documents 2018-10-19 15:07:15 +02:00
daniel.boehrs 17e5fe5a89 Verify icon layout broken #93 2018-10-19 10:11:26 +02:00
Florian Haar 4b8fef6918 Merge branch 'master' of https://github.com/deltachat/deltachat-android-ii 2018-10-19 09:03:08 +02:00
Florian Haar 44afb50c81 Allow for customized Background image #50 2018-10-19 09:01:47 +02:00
B. Petersen 39f14a4a9a basically send media with URIs 2018-10-19 01:40:27 +02:00
B. Petersen d015f567da bump version 2018-10-18 18:55:15 +02:00
B. Petersen d98174b45b remove unused directory from update script 2018-10-18 16:35:23 +02:00
daniel.boehrs db92bb274b prefill groups form with exstiting data #92 2018-10-18 16:13:27 +02:00
B. Petersen c8d889da04 Update messenger-backend submodule. 2018-10-18 16:11:29 +02:00
B. Petersen 6da2a9fc87 remove ndk-buid call from update, if needed it should be called explicitly 2018-10-18 16:07:26 +02:00
Florian Haar 39b64bd9aa Merge branch 'master' of https://github.com/deltachat/deltachat-android-ii 2018-10-18 10:56:46 +02:00
Florian Haar ca55e21eb2 show "first message may take a while" in new chats #62 2018-10-18 10:55:59 +02:00
daniel.boehrs bf85918ed2 add qr show+scan activities #79 and adjust UI 2018-10-18 10:53:21 +02:00
björn petersen b0adddebfa Merge pull request #91 from deltachat/qr-verify-79
add verify-contact activities
2018-10-17 23:36:39 +02:00
B. Petersen f27f0b4305 show secure-join-events on joiner side 2018-10-17 23:26:58 +02:00
B. Petersen c441c11601 start activity after QR scanning from ui thread 2018-10-17 19:10:23 +02:00
daniel.boehrs 77d7f545d4 add qr show+scan activities #79 2018-10-17 16:57:10 +02:00
Angelo Fuchs 7d4add1b5e introduced DcAttachment and introduced its use where applicable. 2018-10-17 15:20:39 +02:00
Angelo Fuchs e72f2b4cb6 for #78 setting the attachment state to done when its displayed. 2018-10-17 15:18:20 +02:00
B. Petersen 264765917f adapt to new api 2018-10-17 14:08:55 +02:00
B. Petersen 9b6dcf955f adapt name and return value of dc_msg_get_filebytes() wrapper function 2018-10-17 14:06:36 +02:00
B. Petersen 6027072d78 remove download button from AudioView 2018-10-17 02:15:38 +02:00
B. Petersen af5fb87c06 Update messenger-backend submodule. 2018-10-17 01:14:11 +02:00
B. Petersen 96c4fd6835 adapt to new api 2018-10-17 01:13:56 +02:00
B. Petersen a0b7d41a7a Update messenger-backend submodule. 2018-10-17 00:02:41 +02:00
B. Petersen 3cd732f089 adapt to new api 2018-10-17 00:02:26 +02:00
B. Petersen e299eb26c2 Update messenger-backend submodule. 2018-10-16 16:50:46 +02:00
B. Petersen 1038de2cc5 cleanup 2018-10-16 16:50:30 +02:00
Florian Haar f02380fd52 Adjust the CreateProfileActivity UI #87 2018-10-16 14:25:55 +02:00
daniel.boehrs a02574dbbb Allow for customized Background image #50 2018-10-16 13:58:24 +02:00
B. Petersen 35521f5dfe force software layer to allow larger items in ConversationList, closes #88 2018-10-16 10:39:30 +02:00
B. Petersen a1e6c14443 use different app name for X-Mailer header 2018-10-15 15:31:39 +02:00
Florian Haar 58ada319bb Merge branch 'master' of https://github.com/deltachat/deltachat-android-ii 2018-10-15 11:38:05 +02:00
Florian Haar 45bfab9fbd Adjust the CreateProfileActivity UI #87 2018-10-15 11:36:09 +02:00
B. Petersen e5d8a2bc28 update error indicator 2018-10-14 23:25:32 +02:00
B. Petersen 99b1e2ba43 harden getConfigInt() 2018-10-14 12:11:07 +02:00
B. Petersen 27d632f17c show sender names in groups, closes #85 2018-10-13 22:34:24 +02:00
B. Petersen fbd53b3767 make opened chat as being noticed, closes #66 2018-10-13 16:56:29 +02:00
B. Petersen 8f56d5872a adding SELF to the list of contacts so that one can easily create a self-chat 2018-10-13 15:33:34 +02:00
daniel.boehrs 0e75880c24 show "verified" icon in contact list and in chat title #80 2018-10-12 15:54:58 +02:00
B. Petersen 0e55a4ad5e Merge branch 'master' of https://github.com/deltachat/deltachat-android-ii 2018-10-12 13:56:11 +02:00
B. Petersen 6eed72a4d2 bump version 2018-10-12 13:56:08 +02:00
109 changed files with 1996 additions and 1659 deletions
+12
View File
@@ -300,6 +300,14 @@
android:windowSoftInputMode="stateVisible"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".QrScanActivity"
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".QrShowActivity"
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ClearProfileAvatarActivity"
android:theme="@style/Theme.AppCompat.Dialog.Alert"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
@@ -324,6 +332,10 @@
android:theme="@style/TextSecure.LightNoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".preferences.ChatBackgroundActivity"
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<service android:enabled="true" android:name="org.thoughtcrime.securesms.service.WebRtcCallService"/>
<service android:enabled="true" android:exported="false" android:name=".service.KeyCachingService"/>
<service android:enabled="true" android:name=".service.MessageRetrievalService"/>
+4 -4
View File
@@ -83,6 +83,8 @@ dependencies {
compile 'org.whispersystems:signal-service-android:2.7.6'
compile 'org.whispersystems:webrtc-android:M68'
compile 'com.journeyapps:zxing-android-embedded:3.4.0'
compile "me.leolin:ShortcutBadger:1.1.16"
compile 'se.emilsjolander:stickylistheaders:2.7.0'
compile 'com.jpardogo.materialtabstrip:library:1.0.9'
@@ -96,7 +98,6 @@ dependencies {
compile 'pl.tajchert:waitingdots:0.1.0'
compile 'com.soundcloud.android:android-crop:0.9.10@aar'
compile 'com.melnykov:floatingactionbutton:1.3.0'
compile 'com.google.zxing:android-integration:3.1.0'
compile 'com.squareup.dagger:dagger:1.2.2'
annotationProcessor 'com.squareup.dagger:dagger-compiler:1.2.2'
compile 'mobi.upod:time-duration-picker:1.1.3'
@@ -185,7 +186,6 @@ dependencyVerification {
'com.makeramen:roundedimageview:1f5a1865796b308c6cdd114acc6e78408b110f0a62fc63553278fbeacd489cd1',
'org.greenrobot:eventbus:180d4212467df06f2fbc9c8d8a2984533ac79c87769ad883bc421612f0b4e17c',
'com.soundcloud.android:android-crop:ffd4b973cf6e97f7d64118a0dc088df50e9066fd5634fe6911dd0c0c5d346177',
'com.google.zxing:android-integration:89e56aadf1164bd71e57949163c53abf90af368b51669c0d4a47a163335f95c4',
'com.squareup.dagger:dagger:789aca24537022e49f91fc6444078d9de8f1dd99e1bfb090f18491b186967883',
'com.amulyakhare:com.amulyakhare.textdrawable:54c92b5fba38cfd316a07e5a30528068f45ce8515a6890f1297df4c401af5dcb',
'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259',
@@ -255,8 +255,8 @@ android {
}
defaultConfig {
versionCode 392
versionName "0.0.1"
versionCode 397
versionName "0.0.7"
applicationId "chat.delta.androidii"
minSdkVersion 14
-1
View File
@@ -927,7 +927,6 @@ messenger-backend/src/dc_strbuilder.c \
messenger-backend/src/dc_strencode.c \
messenger-backend/src/dc_token.c \
messenger-backend/src/dc_tools.c \
messenger-backend/src/dc_uudecode.c \
dc_wrapper.c
include $(BUILD_SHARED_LIBRARY)
+8 -46
View File
@@ -547,34 +547,6 @@ JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendTextMsg(JNIEnv *env, jobjec
}
JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendVcardMsg(JNIEnv *env, jobject obj, jint chat_id, jint contact_id)
{
return dc_send_vcard_msg(get_dc_context(env, obj), chat_id, contact_id);
}
JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendMediaMsg(JNIEnv *env, jobject obj, jint chat_id, jint type, jstring file, jstring mime, jint w, jint h, jint ms, jstring author, jstring trackname)
{
jint msg_id = 0;
CHAR_REF(file);
CHAR_REF(mime);
CHAR_REF(author);
CHAR_REF(trackname);
switch (type) {
case DC_MSG_IMAGE: msg_id = (jint)dc_send_image_msg(get_dc_context(env, obj), chat_id, filePtr, mimePtr, w, h); break;
case DC_MSG_VIDEO: msg_id = (jint)dc_send_video_msg(get_dc_context(env, obj), chat_id, filePtr, mimePtr, w, h, ms); break;
case DC_MSG_VOICE: msg_id = (jint)dc_send_voice_msg(get_dc_context(env, obj), chat_id, filePtr, mimePtr, ms); break;
case DC_MSG_AUDIO: msg_id = (jint)dc_send_audio_msg(get_dc_context(env, obj), chat_id, filePtr, mimePtr, ms, authorPtr, tracknamePtr); break;
default: msg_id = (jint)dc_send_file_msg (get_dc_context(env, obj), chat_id, filePtr, mimePtr); break;
}
CHAR_UNREF(trackname);
CHAR_UNREF(author);
CHAR_UNREF(mime);
CHAR_UNREF(file);
return msg_id;
}
/* DcContext - handle config */
JNIEXPORT void Java_com_b44t_messenger_DcContext_setConfig(JNIEnv *env, jobject obj, jstring key, jstring value /*may be NULL*/)
@@ -754,6 +726,12 @@ JNIEXPORT jlong Java_com_b44t_messenger_DcChatlist_getChatCPtr(JNIEnv *env, jobj
}
JNIEXPORT jint Java_com_b44t_messenger_DcChatlist_getMsgId(JNIEnv *env, jobject obj, jint index)
{
return dc_chatlist_get_msg_id(get_dc_chatlist(env, obj), index);
}
JNIEXPORT jlong Java_com_b44t_messenger_DcChatlist_getMsgCPtr(JNIEnv *env, jobject obj, jint index)
{
dc_chatlist_t* chatlist = get_dc_chatlist(env, obj);
@@ -1010,9 +988,9 @@ JNIEXPORT void Java_com_b44t_messenger_DcMsg_lateFilingMediaSize(JNIEnv *env, jo
}
JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getBytes(JNIEnv *env, jobject obj)
JNIEXPORT jlong Java_com_b44t_messenger_DcMsg_getFilebytes(JNIEnv *env, jobject obj)
{
return (jint)dc_msg_get_filebytes(get_dc_msg(env, obj));
return (jlong)dc_msg_get_filebytes(get_dc_msg(env, obj));
}
@@ -1064,12 +1042,6 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getFilename(JNIEnv *env, jobject
}
JNIEXPORT jlong Java_com_b44t_messenger_DcMsg_getMediainfoCPtr(JNIEnv *env, jobject obj)
{
return (jlong)dc_msg_get_mediainfo(get_dc_msg(env, obj));
}
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isForwarded(JNIEnv *env, jobject obj)
{
return dc_msg_is_forwarded(get_dc_msg(env, obj))!=0;
@@ -1133,16 +1105,6 @@ JNIEXPORT void Java_com_b44t_messenger_DcMsg_setDuration(JNIEnv *env, jobject ob
}
JNIEXPORT void Java_com_b44t_messenger_DcMsg_setMediainfo(JNIEnv *env, jobject obj, jstring author, jstring trackname)
{
CHAR_REF(author);
CHAR_REF(trackname);
dc_msg_set_mediainfo(get_dc_msg(env, obj), authorPtr, tracknamePtr);
CHAR_UNREF(trackname);
CHAR_UNREF(author);
}
/*******************************************************************************
* DcContact
******************************************************************************/
Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_help_white_24dp"
android:tint="?attr/pref_icon_tint"/>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_mood_white_24dp"
android:tint="?attr/pref_icon_tint"/>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#8000" />
<padding
android:left="1dp"
android:right="1dp"
android:bottom="1dp"
android:top="1dp" />
<corners android:radius="8dp" />
</shape>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.journeyapps.barcodescanner.CompoundBarcodeView
android:id="@+id/zxing_barcode_scanner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true" />
</RelativeLayout>
+26
View File
@@ -0,0 +1,26 @@
<?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">
<ImageView
android:id="@+id/qrImage"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:contentDescription="@string/qr_scan_activity__title" />
<TextView
android:id="@+id/qrShowHint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text=""
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat"
android:textSize="16sp" />
</LinearLayout>
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/preview"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="bottom">
<Button
android:id="@+id/set_default_button"
android:theme="@style/Button.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="Set default" />
<Button
android:id="@+id/from_gallery_button"
android:theme="@style/Button.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="From gallery" />
</LinearLayout>
</FrameLayout>
-26
View File
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:id="@+id/sms_failed_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_error"
android:visibility="gone"
android:tint="@color/core_red"
tools:visibility="visible"
android:contentDescription="@string/conversation_item_sent__send_failed_indicator_description" />
<ImageView
android:id="@+id/pending_approval_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_error"
android:tint="@color/core_light_60"
android:visibility="gone"
tools:visibility="visible"
android:layout_gravity="center_vertical"
android:contentDescription="@string/conversation_item_sent__pending_approval_description" />
</merge>
-10
View File
@@ -45,16 +45,6 @@
android:scaleType="centerInside"
android:contentDescription="@string/audio_view__pause_accessibility_description"/>
<ImageView android:id="@+id/download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:clickable="true"
android:visibility="gone"
android:background="@drawable/circle_touch_highlight_background"
android:src="@drawable/ic_download_circle_fill_white_48dp"
android:contentDescription="@string/audio_view__download_accessibility_description"/>
</org.thoughtcrime.securesms.components.AnimatingToggle>
<SeekBar android:id="@+id/seek"
+10 -9
View File
@@ -32,15 +32,16 @@
android:orientation="vertical">
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="16sp"
tools:text="Frieeeeeeedrich Nieeeeeeeeeetzsche" />
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
android:drawablePadding="5dp"
android:ellipsize="marquee"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="16sp"
tools:text="Frieeeeeeedrich Nieeeeeeeeeetzsche" />
<LinearLayout android:id="@+id/number_container"
android:orientation="horizontal"
+81 -81
View File
@@ -1,98 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.components.InputAwareLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer
android:id="@+id/quick_attachment_drawer"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent" android:layout_width="match_parent">
<ImageView
android:id="@+id/background_imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:scaleType="centerCrop"/>
<org.thoughtcrime.securesms.components.InputAwareLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:id="@+id/conversation_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="?attr/actionBarSize"
android:gravity="bottom"
android:clipToPadding="false"
android:clipChildren="false">
<org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer
android:id="@+id/quick_attachment_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub android:id="@+id/group_share_profile_view_stub"
android:layout="@layout/conversation_activity_group_share_profile_stub"
android:inflatedId="@+id/group_share_profile_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout android:id="@+id/conversation_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="?attr/actionBarSize"
android:gravity="bottom"
android:clipToPadding="false"
android:clipChildren="false">
<ViewStub android:id="@+id/unverified_banner_stub"
android:layout="@layout/conversation_activity_unverified_banner_stub"
android:inflatedId="@+id/unverified_banner"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ViewStub android:id="@+id/group_share_profile_view_stub"
android:layout="@layout/conversation_activity_group_share_profile_stub"
android:inflatedId="@+id/group_share_profile_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ViewStub
android:id="@+id/reminder_stub"
android:layout="@layout/conversation_activity_reminderview_stub"
android:inflatedId="@+id/reminder"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ViewStub android:id="@+id/unverified_banner_stub"
android:layout="@layout/conversation_activity_unverified_banner_stub"
android:inflatedId="@+id/unverified_banner"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<FrameLayout android:id="@+id/fragment_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<ViewStub
android:id="@+id/reminder_stub"
android:layout="@layout/conversation_activity_reminderview_stub"
android:inflatedId="@+id/reminder"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ViewStub
android:id="@+id/attachment_editor_stub"
android:inflatedId="@+id/attachment_editor"
android:layout="@layout/conversation_activity_attachment_editor_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<FrameLayout android:id="@+id/fragment_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<include layout="@layout/conversation_input_panel"/>
<ViewStub
android:id="@+id/attachment_editor_stub"
android:inflatedId="@+id/attachment_editor"
android:layout="@layout/conversation_activity_attachment_editor_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button android:id="@+id/register_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="@string/conversation_activity__enable_signal_messages"
android:visibility="gone"/>
<include layout="@layout/conversation_input_panel"/>
<Button android:id="@+id/unblock_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="@string/ConversationActivity_unblock"
android:visibility="gone"/>
<Button android:id="@+id/register_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="@string/conversation_activity__enable_signal_messages"
android:visibility="gone"/>
<Button android:id="@+id/make_default_sms_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="@string/conversation_activity__enable_signal_for_sms"
android:visibility="gone"/>
<Button android:id="@+id/make_default_sms_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="@string/conversation_activity__enable_signal_for_sms"
android:visibility="gone"/>
<TextView android:id="@+id/space_left"
android:paddingLeft="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:background="?android:windowBackground"
android:text="160/160 (1)" />
<TextView android:id="@+id/space_left"
android:paddingLeft="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:background="?android:windowBackground"
android:text="160/160 (1)" />
<ViewStub
android:id="@+id/emoji_drawer_stub"
android:layout="@layout/conversation_activity_emojidrawer_stub"
android:inflatedId="@+id/emoji_drawer"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ViewStub
android:id="@+id/emoji_drawer_stub"
android:layout="@layout/conversation_activity_emojidrawer_stub"
android:inflatedId="@+id/emoji_drawer"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer>
</org.thoughtcrime.securesms.components.InputAwareLayout>
</LinearLayout>
</org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer>
</org.thoughtcrime.securesms.components.InputAwareLayout>
</RelativeLayout>
+11 -1
View File
@@ -2,7 +2,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/conversation_container"
android:id="@+id/conversation_container"
android:layout_width="fill_parent"
android:layout_height="match_parent">
@@ -34,6 +34,16 @@
android:visibility="gone"
tools:text="March 1, 2015" />
<TextView
android:id="@+id/no_messages_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="visible"
style="@style/NoMessagesTextView"
tools:text="@string/ConversationActivity_NoMessagesHint"
/>
<View android:id="@+id/compose_divider"
android:layout_width="match_parent"
android:layout_height="2dp"
+2 -1
View File
@@ -14,7 +14,8 @@
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:clipChildren="false"
android:clipToPadding="false">
android:clipToPadding="false"
android:background="@color/white">
<FrameLayout
android:layout_width="0dp"
-22
View File
@@ -86,20 +86,6 @@
tools:visibility="visible"
tools:text="+14152222222"/>
<TextView
android:id="@+id/group_message_sender_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="4sp"
android:paddingLeft="4sp"
style="@style/Signal.Text.Preview"
android:fontFamily="sans-serif-regular"
android:textColor="?conversation_item_received_text_primary_color"
android:textStyle="italic"
android:maxLines="1"
android:ellipsize="end"
tools:text="~Clement Duval"/>
</LinearLayout>
<org.thoughtcrime.securesms.components.QuoteView
@@ -180,13 +166,5 @@
</LinearLayout>
<org.thoughtcrime.securesms.components.AlertView
android:id="@+id/indicators_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:orientation="vertical"
android:gravity="center_vertical"/>
</RelativeLayout>
</org.thoughtcrime.securesms.ConversationItem>
+4 -1
View File
@@ -133,7 +133,10 @@
</LinearLayout>
<org.thoughtcrime.securesms.components.AlertView
<!-- the following view is only left because it is used as a reference for positioning above.
removing would require some re-layouting, it's just not done yet.-->
<View
android:visibility="gone"
android:id="@+id/indicators_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+39 -29
View File
@@ -36,45 +36,55 @@
android:weightSum="1"
android:orientation="horizontal">
<org.thoughtcrime.securesms.components.FromTextView
android:id="@+id/from"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/thumbnail"
android:layout_toStartOf="@+id/thumbnail"
style="@style/Signal.Text.Body"
android:fontFamily="sans-serif-medium"
android:textColor="?attr/conversation_list_item_contact_color"
android:maxLines="1"
tools:text="Jules Bonnot"
android:ellipsize="end"
android:layout_marginBottom="2dp"
android:drawablePadding="5dp"/>
<RelativeLayout
android:id="@+id/from"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/thumbnail"
android:layout_toStartOf="@+id/thumbnail">
<org.thoughtcrime.securesms.components.AlertView
android:id="@+id/indicators_parent"
android:layout_width="18dp"
android:layout_height="18dp"
android:paddingTop="2dp"
android:layout_marginRight="2dp"
android:layout_marginEnd="2dp"
<org.thoughtcrime.securesms.components.FromTextView
android:id="@+id/from_text"
style="@style/Signal.Text.Body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@id/from"
app:useSmallIcon="true"
android:layout_marginBottom="2dp"
android:layout_toLeftOf="@id/verified_indicator"
android:layout_toStartOf="@id/verified_indicator"
android:drawablePadding="5dp"
android:ellipsize="end"
android:fontFamily="sans-serif-medium"
android:maxLines="1"
android:textColor="?attr/conversation_list_item_contact_color"
tools:text="Jules Bonnot" />
<ImageView
android:id="@+id/verified_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_verified"
android:visibility="gone"
tools:visibility="visible"/>
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="4dp"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/subject"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/from"
android:layout_toRightOf="@id/indicators_parent"
android:layout_toEndOf="@id/indicators_parent"
android:layout_toLeftOf="@+id/status"
android:layout_toStartOf="@+id/status"
android:paddingRight="1dp"
+44 -47
View File
@@ -39,58 +39,55 @@
tools:src="@drawable/ic_contact_picture"
android:contentDescription="@string/conversation_list_item_view__contact_photo_image"/>
<RelativeLayout android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/contact_photo_image"
android:layout_toEndOf="@id/contact_photo_image"
android:layout_centerVertical="true">
<RelativeLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/contact_photo_image"
android:layout_toRightOf="@id/contact_photo_image">
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="18dp"
android:transitionName="recipient_name"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
style="@style/TextSecure.TitleTextStyle"
tools:ignore="UnusedAttribute"/>
android:id="@+id/title"
style="@style/TextSecure.TitleTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@id/verified_indicator"
android:layout_toStartOf="@id/verified_indicator"
android:drawablePadding="5dp"
android:ellipsize="end"
android:maxLines="1"
android:textSize="18dp"
android:transitionName="recipient_name"
tools:text="Jules Bonnot" />
<ImageView android:id="@+id/verified_indicator"
android:src="@drawable/ic_check_circle_white_18dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:layout_marginEnd="3dp"
android:layout_gravity="bottom"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@id/title"
android:alpha="0.7"
android:visibility="gone"/>
<ImageView
android:id="@+id/verified_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:src="@drawable/ic_verified"
android:visibility="gone" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:layout_gravity="center_vertical|start"
android:gravity="center_vertical"
android:layout_toRightOf="@id/verified_indicator"
android:layout_toEndOf="@id/verified_indicator"
android:layout_below="@id/title"
android:textDirection="ltr"
android:textSize="13dp"
tools:text="(123) 123-1234"
style="@style/TextSecure.SubtitleTextStyle"/>
android:id="@+id/subtitle"
style="@style/TextSecure.SubtitleTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textDirection="ltr"
android:textSize="13dp"
android:layout_below="@id/title"
tools:text="(123) 123-1234" />
</RelativeLayout>
+41 -19
View File
@@ -68,25 +68,47 @@
</RelativeLayout>
<com.dd.CircularProgressButton
android:id="@+id/add_member_button"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="@color/signal_primary"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:layout_marginBottom="15dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
android:textColor="@color/white"
app:cpb_colorIndicator="@color/white"
app:cpb_colorProgress="@color/textsecure_primary"
app:cpb_cornerRadius="20dp"
app:cpb_selectorIdle="@drawable/progress_button_state"
app:cpb_textIdle="@string/recipients_panel__add_members"
app:layout_constraintBottom_toTopOf="@id/skip_button_bottom_spacer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.dd.CircularProgressButton
android:id="@+id/add_member_button"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="@color/signal_primary"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:layout_marginBottom="15dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
android:textColor="@color/white"
app:cpb_colorIndicator="@color/white"
app:cpb_colorProgress="@color/textsecure_primary"
app:cpb_cornerRadius="20dp"
app:cpb_selectorIdle="@drawable/progress_button_state"
app:cpb_textIdle="@string/recipients_panel__add_members"/>
<com.dd.CircularProgressButton
android:id="@+id/verify_button"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="@color/signal_primary"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:layout_marginBottom="15dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
android:textColor="@color/white"
app:cpb_colorIndicator="@color/white"
app:cpb_colorProgress="@color/textsecure_primary"
app:cpb_cornerRadius="20dp"
app:cpb_selectorIdle="@drawable/progress_button_state"
android:visibility="gone"
app:cpb_textIdle="@string/qr_show_activity__title"/>
</LinearLayout>
<ListView android:id="@+id/selected_contacts_list"
android:layout_width="match_parent"
+59 -72
View File
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:layout_width="match_parent"
<FrameLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
@@ -23,42 +24,39 @@
android:layout_height="64dp"
android:transitionName="avatar"/>
<org.thoughtcrime.securesms.components.emoji.EmojiEditText
android:id="@+id/name"
android:hint="@string/profile_create_activity__your_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:inputType="textCapWords"/>
<android.support.design.widget.TextInputLayout
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp">
<org.thoughtcrime.securesms.components.emoji.EmojiToggle
android:id="@+id/emoji_toggle"
android:layout_width="37dp"
android:layout_height="37dp"
android:layout_gravity="center_vertical"
android:background="@drawable/touch_highlight_background"
android:contentDescription="@string/conversation_activity__emoji_toggle_description" />
<android.support.design.widget.TextInputEditText
android:id="@+id/name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/profile_create_activity__your_name"
android:inputType="textCapWords" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/status"
android:layout_marginTop="4dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
<android.support.design.widget.TextInputLayout
android:id="@+id/status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp">
<android.support.design.widget.TextInputEditText
android:id="@+id/status_text"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="@+id/status_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/default_status_hint"
android:inputType="text" />
</android.support.design.widget.TextInputLayout>
android:layout_height="wrap_content"
android:gravity="top|left"
android:hint="@string/default_status_hint"
android:inputType="textMultiLine"
android:maxLines="3" />
</android.support.design.widget.TextInputLayout>
<LinearLayout android:id="@+id/information_link_container"
android:clickable="true"
@@ -78,16 +76,17 @@
android:src="@drawable/ic_info_white_18dp"
android:tint="#73B7F0"/>
<TextView style="@style/Registration.Description"
android:id="@+id/information_label"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="3dp"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:textColor="#73B7F0"
android:text="@string/profile_create_activity__who_can_see_this_information"/>
<TextView
android:id="@+id/information_label"
style="@style/Registration.Description"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginLeft="3dp"
android:clickable="true"
android:gravity="center_vertical"
android:text="@string/profile_create_activity__who_can_see_this_information"
android:textColor="#73B7F0" />
</LinearLayout>
@@ -98,31 +97,18 @@
android:clipChildren="false"
android:clipToPadding="false">
<com.dd.CircularProgressButton
android:id="@+id/finish_button"
app:cpb_textIdle="@string/profile_create_activity__finish"
app:cpb_selectorIdle="@drawable/progress_button_state"
app:cpb_colorIndicator="@color/white"
app:cpb_colorProgress="@color/textsecure_primary"
app:cpb_cornerRadius="50dp"
android:textAllCaps="true"
android:background="@color/signal_primary"
android:textColor="@color/white"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="20dp"
android:layout_gravity="center_horizontal"/>
<TextView android:id="@+id/password_account_settings_button"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="20dp"
android:textColor="@color/gray50"
android:text="@string/profile_create_activity__password_account"/>
<TextView
android:id="@+id/password_account_settings_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="20dp"
android:layout_marginTop="0dp"
android:text="@string/profile_create_activity__password_account"
android:textColor="#73B7F0"
android:textSize="16sp"
android:textStyle="normal"
android:typeface="sans" />
<org.thoughtcrime.securesms.components.emoji.EmojiDrawer
xmlns:android="http://schemas.android.com/apk/res/android"
@@ -135,10 +121,11 @@
</org.thoughtcrime.securesms.components.InputAwareLayout>
<View android:id="@+id/reveal"
android:background="@color/textsecure_primary"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"/>
<View
android:id="@+id/reveal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/textsecure_primary"
android:visibility="invisible" />
</FrameLayout>
+3 -3
View File
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="@string/conversation__menu_view_profile"
android:id="@+id/menu_conversation_settings"/>
<item android:title="@string/conversation__menu_add_attachment"
android:id="@+id/menu_add_attachment" />
<item android:title="@string/conversation__menu_view_all_media"
android:id="@+id/menu_view_media" />
<item android:title="@string/conversation__menu_conversation_settings"
android:id="@+id/menu_conversation_settings"/>
</menu>
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/menu_add_to_contacts"
android:title="@string/conversation_add_to_contacts__menu_add_to_contacts"
app:showAsAction="never" />
</menu>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="@string/conversation__menu_archive_chat"
android:id="@+id/menu_archive_chat"/>
</menu>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="@string/conversation_insecure__invite"
android:id="@+id/menu_invite"/>
<item android:title="@string/conversation__menu_delete_chat"
android:id="@+id/menu_delete_chat"/>
</menu>
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:title="@string/conversation_expiring_off__disappearing_messages"
android:id="@+id/menu_expiring_messages_off"
android:icon="@drawable/ic_timer_off_white_24dp"/>
</menu>
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/menu_expiring_messages"
app:actionLayout="@layout/expiration_timer_menu"
app:showAsAction="always"
android:title="@string/menu_conversation_expiring_on__messages_expiring"/>
</menu>
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:title="@string/convesation_group_options__recipients_list"
android:id="@+id/menu_group_recipients"
android:icon="?menu_group_icon"
app:showAsAction="ifRoom" />
</menu>
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:title="@string/conversation_group_options__delivery"
android:id="@+id/menu_group_delivery"
android:icon="?menu_split_icon"
app:showAsAction="ifRoom" >
<menu>
<group android:id="@+id/distribution_group"
android:checkableBehavior="single">
<item android:id="@+id/menu_distribution_conversation" android:title="@string/conversation_group_options__conversation" android:checked="true" />
<item android:id="@+id/menu_distribution_broadcast" android:title="@string/conversation_group_options__broadcast" />
</group>
</menu>
</item>
</menu>
+2 -1
View File
@@ -3,7 +3,8 @@
<item android:id="@+id/menu_edit_group"
android:title="@string/conversation__menu_edit_group"
app:showAsAction="collapseActionView" />
android:icon="?menu_group_icon"
app:showAsAction="ifRoom" />
<item android:id="@+id/menu_leave"
android:title="@string/conversation__menu_leave_group"
-5
View File
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="@string/conversation_secure_verified__menu_reset_secure_session"
android:id="@+id/menu_reset_secure_session"/>
</menu>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="@string/conversation__menu_unarchive_chat"
android:id="@+id/menu_archive_chat"/>
</menu>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_create_profile"
android:title="@string/profile_create_activity__finish"
app:showAsAction="always"
android:icon="?menu_accept_icon"/>
</menu>
+13 -7
View File
@@ -1,19 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:title="@string/qr_scan_activity__title"
android:id="@+id/menu_qr_scan"
android:icon="@drawable/ic_ab_qr"
app:showAsAction="always"/>
<item android:title="@string/qr_show_activity__title"
android:id="@+id/menu_qr_show" />
<item android:title="@string/text_secure_normal__menu_new_chat"
android:id="@+id/menu_new_chat" />
<item android:title="@string/menu_deaddrop"
android:id="@+id/menu_deaddrop" />
<item android:title="@string/text_secure_normal__menu_clear_passphrase"
android:id="@+id/menu_clear_passphrase" />
<item android:title="@string/text_secure_normal__invite_friends"
android:id="@+id/menu_invite" />
<item android:title="@string/text_secure_normal__menu_settings"
android:id="@+id/menu_settings" />
<item android:title="@string/text_secure_normal__help"
android:id="@+id/menu_help"/>
</menu>
+1 -4
View File
@@ -7,6 +7,7 @@
<attr name="attachment_document_icon_large" format="reference" />
<attr name="conversation_list_item_background" format="reference"/>
<attr name="conversation_list_deaddrop_bg_color" format="reference|color"/>
<attr name="conversation_list_item_contact_color" format="reference|color"/>
<attr name="conversation_list_item_subject_color" format="reference|color"/>
<attr name="conversation_list_item_delivery_icon_color" format="reference|color"/>
@@ -177,10 +178,6 @@
<attr name="iconColor" format="color" />
</declare-styleable>
<declare-styleable name="AlertView">
<attr name="useSmallIcon" format="boolean" />
</declare-styleable>
<declare-styleable name="AudioView">
<attr name="widgetBackground" format="color"/>
<attr name="foregroundTintColor" format="color" />
-2
View File
@@ -72,6 +72,4 @@
<dimen name="floating_action_button_margin">16dp</dimen>
<dimen name="alertview_small_icon_size">14dp</dimen>
</resources>
+48 -3
View File
@@ -41,8 +41,14 @@
<string name="ApplicationPreferencesActivity_sms_mms_summary">SMS %1$s, MMS %2$s</string>
<string name="ApplicationPreferencesActivity_privacy_summary">Screen lock %1$s, Read receipts %2$s</string>
<string name="ApplicationPreferencesActivity_appearance_summary">Theme %1$s, Language %2$s</string>
<string name="ApplicationPreferencesActivity_appearance_summary_new">Theme %1$s, Language %2$s, Background %3$s</string>
<string name="ApplicationPreferencesActivity_appearance_background_default">default</string>
<string name="ApplicationPreferencesActivity_appearance_background_custom">custom</string>
<!-- AppearancePreferenceFragment -->
<string name="AppearancePreferencesFragment_background_save_error">Background image could not be saved</string>
<string name="AppearancePreferencesFragment_background_custom_summary">Custom</string>
<string name="AppearancePreferencesFragment_background_default_summary">Default</string>
<!-- AppProtectionPreferenceFragment -->
<plurals name="AppProtectionPreferenceFragment_minutes">
@@ -164,6 +170,9 @@
<string name="ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video">Delta Chat needs Camera permissions to take photos or video</string>
<string name="ConversationActivity_quoted_contact_message">%1$s %2$s</string>
<string name="ConversationActivity_NoMessagesHint">Send message to %1$s:\n\n• It is okay if %2$s does not use Delta Chat.\n\n• Delivering the first message may take a while.</string>
<string name="ConversationActivity_MsgNewGroupDraftHint">Compose the first message, allowing others to reply within this group.\n\n• It is okay if not all members use Delta Chat.\n\n• Delivering the first message may take a while.</string>
<string name="ConversationActivity_ask_delete_chat">Delete this chat? It will no longer be shown in the chat list, its messages will remain on the server.</string>
<!-- ConversationAdapter -->
<plurals name="ConversationAdapter_n_unread_messages">
@@ -224,9 +233,9 @@
<item quantity="one">Delete selected chats?</item>
<item quantity="other">Delete selected chats?</item>
</plurals>
<plurals name="ConversationListFragment_this_will_permanently_delete_all_n_selected_conversations">
<item quantity="one">This will permanently delete the selected chats.</item>
<item quantity="other">This will permanently delete all %1$d selected chats.</item>
<plurals name="ConversationListFragment_ask_selected_chats">
<item quantity="one">Delete the selected chat? It will no longer be shown in the chat list, its messages will remain on the server.</item>
<item quantity="other">Delete %1%d selected chats? They will no longer be shown in the chat list, their messages will remain on the server.</item>
</plurals>
<string name="ConversationListFragment_deleting">Deleting</string>
<string name="ConversationListFragment_deleting_selected_conversations">Deleting selected chats...</string>
@@ -1312,6 +1321,32 @@
<string name="new_conversation_activity__refresh">Refresh</string>
<!-- redphone_audio_popup_menu -->
<!-- qr_scan_activity -->
<string name="qr_scan_activity__title">Scan QR code</string>
<string name="qr_scan_activity__hint">Place your camera over the QR code</string>
<!-- qr_scan_handler -->
<string name="qr_scan_handler_join_verified_group">Do you want to join the verified group <![CDATA[<b>]]>%1$s<![CDATA[</b>]]>?</string>
<string name="qr_scan_handler_fingerprint_ask_oob">Verify contact and start chatting with <![CDATA[<b>]]>%1$s<![CDATA[</b>]]>?</string>
<string name="qr_scan_handler_fingerprint_ok">Contact <![CDATA[<i>]]>%1$s<![CDATA[</i>]]> verified. Start chatting?</string>
<string name="qr_scan_handler_fingerprint_mismatch">The scanned fingerprint does <![CDATA[<b>]]>not match<![CDATA[</b>]]> the fingerprint last seen for <![CDATA[<i>]]>%1$s<![CDATA[</i>]]>.</string>
<string name="qr_scan_handler_fingerprint_without_address">This QR code contains a fingerprint but no email address.\n\nFor an out-of-band-verification, please establish an encrpyted connection to the recipient first.</string>
<string name="qr_scan_handler_Scan_contains_text">Scanned QR code text:\n\n%1$s</string>
<string name="qr_scan_handler_qr_scan_contains_url">Scanned QR code URL:\n\n%1$s</string>
<string name="qr_scan_handler_fingerprint">Fingerprint</string>
<string name="qr_scan_handler_ask_start_chat_with">Chat with <![CDATA[<b>]]>%1$s<![CDATA[</b>]]>?</string>
<string name="qr_scan_handler_verfied_introduce_myself">%1$s verified, introduce myself …</string>
<!-- qr_show_activity -->
<string name="qr_show_activity__title">Show QR verify code</string>
<string name="qr_show_activity__joining">%1$s joins.</string>
<string name="qr_show_activity__verified">%1$s verified.</string>
<string name="qr_show_activity__group_joined">%1$s securely joined the group.</string>
<string name="qr_show_activity__join_verified_group_hint">Scan this to join the verified group <![CDATA[<b>]]>%1$s<![CDATA[</b>]]>.</string>
<string name="qr_show_activity__join_verified_group_title">QR invite code</string>
<string name="qr_show_activity__join_contact_title">QR verify code</string>
<string name="qr_show_activity__join_contact_hint"><![CDATA[<b>]]>%1$s<![CDATA[</b><br>]]>Scan this to set up a verified contact.</string>
<!-- Trimmer -->
<string name="trimmer__deleting">Deleting</string>
<string name="trimmer__deleting_old_messages">Deleting old messages...</string>
@@ -1487,5 +1522,15 @@
<string name="default_status_hint">Status text</string>
<string name="registration_activity__login">Login</string>
<string name="preferences__chat_background">Chat-Background</string>
<string name="copy_to_clipboard">Copy to clipboard</string>
<string name="open">Open</string>
<string name="done">Done</string>
<string name="menu_deaddrop">Contact requests</string>
<string name="not_now">Not now</string>
<string name="never">Never</string>
<string name="conversation__menu_view_profile">View profile</string>
<string name="conversation__menu_archive_chat">Archive chat</string>
<string name="conversation__menu_unarchive_chat">Unarchive chat</string>
<string name="conversation__menu_delete_chat">Delete chat</string>
</resources>
+10
View File
@@ -182,6 +182,7 @@
<style name="Button.Primary" parent="Base.Widget.AppCompat.Button.Colored">
<item name="colorAccent">@color/signal_primary</item>
<item name="colorButtonNormal">@color/signal_primary</item>
<item name="android:textColor">@color/white</item>
</style>
@@ -230,4 +231,13 @@
<item name="colorControlActivated">@color/white</item>
</style>
<style name="NoMessagesTextView">
<item name="android:textColor">@color/white</item>
<item name="android:textSize">16sp</item>
<item name="android:background">@drawable/no_message_rounded_background</item>
<item name="android:layout_marginLeft">12dp</item>
<item name="android:layout_marginRight">12dp</item>
<item name="android:padding">12dp</item>
</style>
</resources>
+2
View File
@@ -132,6 +132,7 @@
<item name="attachment_document_icon_large">@drawable/ic_document_large_light</item>
<item name="conversation_list_item_background">@drawable/conversation_list_item_background</item>
<item name="conversation_list_deaddrop_bg_color">#ffcccccc</item>
<item name="conversation_list_item_contact_color">@color/core_light_90</item>
<item name="conversation_list_item_subject_color">@color/core_light_60</item>
<item name="conversation_list_item_delivery_icon_color">@color/core_light_35</item>
@@ -275,6 +276,7 @@
<item name="attachment_document_icon_large">@drawable/ic_document_large_dark</item>
<item name="conversation_list_item_background">@drawable/conversation_list_item_background_dark</item>
<item name="conversation_list_deaddrop_bg_color">#ff333333</item>
<item name="conversation_list_item_contact_color">#ffdddddd</item>
<item name="conversation_list_item_subject_color">#ffdddddd</item>
<item name="conversation_list_item_delivery_icon_color">@color/core_dark_55</item>
+8
View File
@@ -25,4 +25,12 @@
android:title="@string/preferences__advanced"
android:icon="@drawable/ic_advanced_24dp"/>
<Preference android:key="preference_category_invite"
android:title="@string/text_secure_normal__invite_friends"
android:icon="@drawable/ic_invite_24dp"/>
<Preference android:key="preference_category_help"
android:title="@string/text_secure_normal__help"
android:icon="@drawable/ic_help_24dp"/>
</PreferenceScreen>
+1 -1
View File
@@ -16,7 +16,7 @@
android:entryValues="@array/language_values"
android:defaultValue="zz"/>
<Preference
<org.thoughtcrime.securesms.preferences.widgets.SignalPreference
android:key="pref_chat_background"
android:title="@string/preferences__chat_background"
/>
+1
View File
@@ -40,6 +40,7 @@ public class DcChatlist {
public native int getCnt ();
public native int getChatId (int index);
public @NonNull DcChat getChat (int index) { return new DcChat(getChatCPtr(index)); }
public native int getMsgId (int index);
public @NonNull DcMsg getMsg (int index) { return new DcMsg(getMsgCPtr(index)); }
public @NonNull DcLot getSummary(int index, DcChat chat) { return new DcLot(getSummaryCPtr(index, chat==null? null : chat.getChatCPtr())); }
+1 -3
View File
@@ -96,7 +96,7 @@ public class DcContext {
public native void setConfig (String key, String value);
public void setConfigInt (String key, int value) { setConfig(key, Integer.toString(value)); }
public native String getConfig (String key, String def);
public int getConfigInt (String key, int def) { return Integer.parseInt(getConfig(key, Integer.toString(def))); }
public int getConfigInt (String key, int def) { try{return Integer.parseInt(getConfig(key, Integer.toString(def)));} catch(Exception e) {} return 0; }
public native String getInfo ();
public native String initiateKeyTransfer ();
public native boolean continueKeyTransfer (int msg_id, String setup_code);
@@ -145,8 +145,6 @@ public class DcContext {
public native void forwardMsgs (int msg_ids[], int chat_id);
public native int sendMsg (int chat_id, DcMsg msg);
public native int sendTextMsg (int chat_id, String text);
public native int sendVcardMsg (int chat_id, int contact_id);
public native int sendMediaMsg (int chat_id, int type, String file, String mime, int w, int h, int time_ms, String author, String trackname);
public native int checkQrCPtr (String qr);
public @NonNull DcLot checkQr (String qr) { return new DcLot(checkQrCPtr(qr)); }
public native String getSecurejoinQr (int chat_id);
+1 -4
View File
@@ -93,15 +93,14 @@ public class DcMsg {
public native int getHeight (int def);
public native int getDuration ();
public native void lateFilingMediaSize(int width, int height, int duration);
public native int getBytes ();
public @NonNull DcLot getSummary (DcChat chat) { return new DcLot(getSummaryCPtr(chat.getChatCPtr())); }
public native String getSummarytext (int approx_characters);
public native int showPadlock ();
public @NonNull DcLot getMediainfo () { return new DcLot(getMediainfoCPtr()); }
public boolean hasFile () { String file = getFile(); return file!=null && !file.isEmpty(); }
public native String getFile ();
public native String getFilemime ();
public native String getFilename ();
public native long getFilebytes ();
public native boolean isForwarded ();
public native boolean isInfo ();
public native boolean isSetupMessage ();
@@ -111,7 +110,6 @@ public class DcMsg {
public native void setFile (String file, String filemime);
public native void setDimension (int width, int height);
public native void setDuration (int duration);
public native void setMediainfo (String author, String trackname);
// aliases and higher-level tools
public static int[] msgSetToIds(final Set<DcMsg> dcMsgs) {
@@ -199,5 +197,4 @@ public class DcMsg {
private long msgCPtr; // CAVE: the name is referenced in the JNI
private native void unrefMsgCPtr ();
private native long getSummaryCPtr (long chatCPtr);
private native long getMediainfoCPtr();
};
@@ -18,11 +18,13 @@
package org.thoughtcrime.securesms;
import android.annotation.TargetApi;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Bundle;
@@ -33,6 +35,7 @@ import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.preference.Preference;
import android.widget.Toast;
import org.thoughtcrime.securesms.preferences.AdvancedPreferenceFragment;
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
@@ -65,6 +68,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
private static final String PREFERENCE_CATEGORY_APPEARANCE = "preference_category_appearance";
private static final String PREFERENCE_CATEGORY_CHATS = "preference_category_chats";
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
private static final String PREFERENCE_CATEGORY_INVITE = "preference_category_invite";
private static final String PREFERENCE_CATEGORY_HELP = "preference_category_help";
public static final int REQUEST_CODE_SET_BACKGROUND = 11;
@@ -147,6 +152,10 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_CHATS));
this.findPreference(PREFERENCE_CATEGORY_ADVANCED)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADVANCED));
this.findPreference(PREFERENCE_CATEGORY_INVITE)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_INVITE));
this.findPreference(PREFERENCE_CATEGORY_HELP)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_HELP));
if (VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
tintIcons(getActivity());
@@ -179,37 +188,36 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
.setSummary(ChatsPreferenceFragment.getSummary(getActivity()));
}
private void setCategoryVisibility() {
}
@TargetApi(11)
private void tintIcons(Context context) {
Drawable sms = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_textsms_white_24dp));
Drawable notifications = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_notifications_white_24dp));
Drawable privacy = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_security_white_24dp));
Drawable appearance = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_brightness_6_white_24dp));
Drawable chats = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_forum_white_24dp));
Drawable devices = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_laptop_white_24dp));
Drawable advanced = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_advanced_white_24dp));
Drawable invite = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_mood_white_24dp));
Drawable help = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_help_white_24dp));
int[] tintAttr = new int[]{R.attr.pref_icon_tint};
TypedArray typedArray = context.obtainStyledAttributes(tintAttr);
int color = typedArray.getColor(0, 0x0);
typedArray.recycle();
DrawableCompat.setTint(sms, color);
DrawableCompat.setTint(notifications, color);
DrawableCompat.setTint(privacy, color);
DrawableCompat.setTint(appearance, color);
DrawableCompat.setTint(chats, color);
DrawableCompat.setTint(devices, color);
DrawableCompat.setTint(advanced, color);
DrawableCompat.setTint(invite, color);
DrawableCompat.setTint(help, color);
this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS).setIcon(notifications);
this.findPreference(PREFERENCE_CATEGORY_APP_PROTECTION).setIcon(privacy);
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE).setIcon(appearance);
this.findPreference(PREFERENCE_CATEGORY_CHATS).setIcon(chats);
this.findPreference(PREFERENCE_CATEGORY_ADVANCED).setIcon(advanced);
this.findPreference(PREFERENCE_CATEGORY_INVITE).setIcon(invite);
this.findPreference(PREFERENCE_CATEGORY_HELP).setIcon(help);
}
private class CategoryClickListener implements Preference.OnPreferenceClickListener {
@@ -239,6 +247,16 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
case PREFERENCE_CATEGORY_ADVANCED:
fragment = new AdvancedPreferenceFragment();
break;
case PREFERENCE_CATEGORY_INVITE:
startActivity(new Intent(getActivity(), InviteActivity.class));
break;
case PREFERENCE_CATEGORY_HELP:
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.help_url))));
} catch (ActivityNotFoundException e) {
Toast.makeText(getActivity(), R.string.ConversationListActivity_there_is_no_browser_installed_on_your_device, Toast.LENGTH_LONG).show();
}
break;
default:
throw new AssertionError();
}
@@ -14,6 +14,7 @@ import java.util.Set;
public interface BindableConversationListItem extends Unbindable {
public void bind(@NonNull ThreadRecord thread,
int msgId,
@NonNull DcLot dcSummary,
@NonNull GlideRequests glideRequests, @NonNull Locale locale,
@NonNull Set<Long> selectedThreads, boolean batchMode);
@@ -268,7 +268,7 @@ public class ContactSelectionListFragment extends Fragment
@Override
public Loader<DcContactsLoader.Ret> onCreateLoader(int id, Bundle args) {
boolean addCreateGroupLinks = !isMulti();
int listflags = 0;
int listflags = DcContext.DC_GCL_ADD_SELF;
if(isSelectVerfied()) {
listflags = DcContext.DC_GCL_VERIFIED_ONLY;
}
@@ -27,6 +27,7 @@ import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
@@ -55,21 +56,25 @@ import android.view.View.OnFocusChangeListener;
import android.view.View.OnKeyListener;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.webkit.MimeTypeMap;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
import com.b44t.messenger.DcMsg;
import com.google.android.gms.location.places.ui.PlacePicker;
import com.google.protobuf.ByteString;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.audio.AudioRecorder;
import org.thoughtcrime.securesms.audio.AudioSlidePlayer;
import org.thoughtcrime.securesms.components.AnimatingToggle;
@@ -108,7 +113,6 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
import org.thoughtcrime.securesms.mms.AttachmentManager;
import org.thoughtcrime.securesms.mms.AttachmentManager.MediaType;
import org.thoughtcrime.securesms.mms.AudioSlide;
@@ -118,8 +122,7 @@ import org.thoughtcrime.securesms.mms.LocationSlide;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.QuoteId;
import org.thoughtcrime.securesms.mms.QuoteModel;
import org.thoughtcrime.securesms.mms.Slide;
@@ -131,12 +134,9 @@ import org.thoughtcrime.securesms.profiles.GroupShareProfileView;
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.scribbles.ScribbleActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
@@ -154,8 +154,14 @@ import org.thoughtcrime.securesms.util.views.Stub;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -175,7 +181,6 @@ import static org.whispersystems.signalservice.internal.push.SignalServiceProtos
public class ConversationActivity extends PassphraseRequiredActionBarActivity
implements ConversationFragment.ConversationFragmentListener,
AttachmentManager.AttachmentListener,
RecipientModifiedListener,
DcEventCenter.DcEventDelegate,
OnKeyboardShownListener,
AttachmentDrawerListener,
@@ -184,12 +189,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
{
private static final String TAG = ConversationActivity.class.getSimpleName();
public static final String ADDRESS_EXTRA = "address";
public static final String THREAD_ID_EXTRA = "thread_id";
public static final String IS_ARCHIVED_EXTRA = "is_archived";
public static final String TEXT_EXTRA = "draft_text";
public static final String DISTRIBUTION_TYPE_EXTRA = "distribution_type";
public static final String TIMING_EXTRA = "timing";
public static final String LAST_SEEN_EXTRA = "last_seen";
public static final String STARTING_POSITION_EXTRA = "starting_position";
@@ -213,7 +215,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
protected ConversationTitleView titleView;
private TextView charactersLeft;
private ConversationFragment fragment;
private Button unblockButton;
private InputAwareLayout container;
private View composePanel;
protected Stub<ReminderView> reminderView;
@@ -227,16 +228,15 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
protected HidingLinearLayout quickAttachmentToggle;
private QuickAttachmentDrawer quickAttachmentDrawer;
private InputPanel inputPanel;
private ImageView imageView;
private Recipient recipient;
private ApplicationDcContext dcContext;
private DcChat dcChat = new DcChat(0);
private long threadId;
private int distributionType;
private boolean archived;
private final boolean isSecureText = true;
private boolean isDefaultSms = true;
private boolean isMmsEnabled = true;
private boolean isSecurityInitialized = false;
@@ -292,6 +292,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
});
dcContext.marknoticedChat((int)threadId);
dcContext.eventCenter.addObserver(this, DcContext.DC_EVENT_CHAT_MODIFIED);
dcContext.eventCenter.addObserver(this, DcContext.DC_EVENT_CONTACTS_CHANGED);
}
@@ -343,14 +345,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
titleView.setTitle(glideRequests, dcChat);
titleView.setVerified(dcChat.isVerified());
setBlockedUserState(recipient, isSecureText, isDefaultSms);
setGroupShareProfileReminder(recipient);
calculateCharactersRemaining();
MessageNotifier.setVisibleThread(threadId);
markThreadAsRead();
Log.w(TAG, "onResume() Finished: " + (System.currentTimeMillis() - getIntent().getLongExtra(TIMING_EXTRA, 0)));
}
@Override
@@ -388,7 +387,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
protected void onDestroy() {
saveDraft();
if (recipient != null) recipient.removeListener(this);
if (securityUpdateReceiver != null) unregisterReceiver(securityUpdateReceiver);
dcContext.eventCenter.removeObservers(this);
super.onDestroy();
@@ -436,9 +434,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
break;
case GROUP_EDIT:
recipient = Recipient.from(this, data.getParcelableExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA), true);
recipient.addListener(this);
dcChat = dcContext.getChat((int)threadId);
titleView.setTitle(glideRequests, dcChat);
setBlockedUserState(recipient, isSecureText, isDefaultSms);
supportInvalidateOptionsMenu();
break;
case TAKE_PHOTO:
@@ -448,7 +445,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
break;
case ADD_CONTACT:
recipient = Recipient.from(this, recipient.getAddress(), true);
recipient.addListener(this);
fragment.reloadList();
break;
case PICK_LOCATION:
@@ -489,50 +485,33 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
MenuInflater inflater = this.getMenuInflater();
menu.clear();
if (isSecureText) {
if (recipient.getExpireMessages() > 0) {
inflater.inflate(R.menu.conversation_expiring_on, menu);
final MenuItem item = menu.findItem(R.id.menu_expiring_messages);
final View actionView = MenuItemCompat.getActionView(item);
final TextView badgeView = actionView.findViewById(R.id.expiration_badge);
badgeView.setText(ExpirationUtil.getExpirationAbbreviatedDisplayValue(this, recipient.getExpireMessages()));
actionView.setOnClickListener(v -> onOptionsItemSelected(item));
} else {
inflater.inflate(R.menu.conversation_expiring_off, menu);
}
if(threadId==DcChat.DC_CHAT_ID_DEADDROP) {
return true;
}
if (isGroupConversation()) {
inflater.inflate(R.menu.conversation_group_options, menu);
if (!isPushGroupConversation()) {
inflater.inflate(R.menu.conversation_mms_group_options, menu);
if (distributionType == ThreadDatabase.DistributionTypes.BROADCAST) {
menu.findItem(R.id.menu_distribution_broadcast).setChecked(true);
} else {
menu.findItem(R.id.menu_distribution_conversation).setChecked(true);
}
} else if (isActiveGroup()) {
inflater.inflate(R.menu.conversation_push_group_options, menu);
}
if (recipient != null && recipient.isMuted()) {
inflater.inflate(R.menu.conversation_muted, menu);
}
else {
inflater.inflate(R.menu.conversation_unmuted, menu);
}
inflater.inflate(R.menu.conversation, menu);
if (isSingleConversation() && isSecureText) {
inflater.inflate(R.menu.conversation_secure, menu);
} else if (isSingleConversation()) {
inflater.inflate(R.menu.conversation_insecure, menu);
if (isGroupConversation()) {
if (isActiveGroup()) {
inflater.inflate(R.menu.conversation_push_group_options, menu);
}
}
if (recipient != null && recipient.isMuted()) inflater.inflate(R.menu.conversation_muted, menu);
else inflater.inflate(R.menu.conversation_unmuted, menu);
if (isSingleConversation() && getRecipient().getContactUri() == null) {
inflater.inflate(R.menu.conversation_add_to_contacts, menu);
if( dcChat.getArchived()==0 ) {
inflater.inflate(R.menu.conversation_archive, menu);
}
else {
inflater.inflate(R.menu.conversation_unarchive, menu);
}
inflater.inflate(R.menu.conversation_delete, menu);
super.onPrepareOptionsMenu(menu);
return true;
@@ -542,21 +521,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.menu_add_attachment: handleAddAttachment(); return true;
case R.id.menu_view_media: handleViewMedia(); return true;
case R.id.menu_add_to_contacts: handleAddToContacts(); return true;
case R.id.menu_reset_secure_session: handleResetSecureSession(); return true;
case R.id.menu_group_recipients: handleDisplayGroupRecipients(); return true;
case R.id.menu_distribution_broadcast: handleDistributionBroadcastEnabled(item); return true;
case R.id.menu_distribution_conversation: handleDistributionConversationEnabled(item); return true;
case R.id.menu_edit_group: handleEditPushGroup(); return true;
case R.id.menu_leave: handleLeavePushGroup(); return true;
case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
case R.id.menu_unmute_notifications: handleUnmuteNotifications(); return true;
case R.id.menu_conversation_settings: handleConversationSettings(); return true;
case R.id.menu_expiring_messages_off:
case R.id.menu_expiring_messages: handleSelectMessageExpiration(); return true;
case android.R.id.home: handleReturnToConversationList(); return true;
case R.id.menu_add_attachment: handleAddAttachment(); return true;
case R.id.menu_view_media: handleViewMedia(); return true;
case R.id.menu_edit_group: handleEditPushGroup(); return true;
case R.id.menu_leave: handleLeaveGroup(); return true;
case R.id.menu_archive_chat: handleArchiveChat(); return true;
case R.id.menu_delete_chat: handleDeleteChat(); return true;
case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
case R.id.menu_unmute_notifications: handleUnmuteNotifications(); return true;
case R.id.menu_conversation_settings: handleConversationSettings(); return true;
case android.R.id.home: handleReturnToConversationList(); return true;
}
return false;
@@ -593,32 +567,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
finish();
}
private void handleSelectMessageExpiration() {
if (isPushGroupConversation() && !isActiveGroup()) {
return;
}
//noinspection CodeBlock2Expr
ExpirationDialog.show(this, recipient.getExpireMessages(), expirationTime -> {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(ConversationActivity.this).setExpireMessages(recipient, expirationTime);
OutgoingExpirationUpdateMessage outgoingMessage = new OutgoingExpirationUpdateMessage(getRecipient(), System.currentTimeMillis(), expirationTime * 1000L);
MessageSender.send(ConversationActivity.this, outgoingMessage, threadId, false, null);
return null;
}
@Override
protected void onPostExecute(Void result) {
invalidateOptionsMenu();
if (fragment != null) fragment.setLastSeen(0);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
});
}
private void handleMuteNotifications() {
MuteDialog.show(this, until -> {
recipient.setMuted(until);
@@ -658,101 +606,42 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void handleUnblock() {
//noinspection CodeBlock2Expr
new AlertDialog.Builder(this)
.setTitle(R.string.ConversationActivity_unblock_this_contact_question)
.setMessage(R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.ConversationActivity_unblock, (dialog, which) -> {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
.setBlocked(recipient, false);
ApplicationContext.getInstance(ConversationActivity.this)
.getJobManager()
.add(new MultiDeviceBlockedUpdateJob(ConversationActivity.this));
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}).show();
}
private void handleResetSecureSession() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.ConversationActivity_reset_secure_session_question);
builder.setIconAttribute(R.attr.dialog_alert_icon);
builder.setCancelable(true);
builder.setMessage(R.string.ConversationActivity_this_may_help_if_youre_having_encryption_problems);
builder.setPositiveButton(R.string.ConversationActivity_reset, (dialog, which) -> {
if (isSingleConversation()) {
final Context context = getApplicationContext();
OutgoingEndSessionMessage endSessionMessage =
new OutgoingEndSessionMessage(new OutgoingTextMessage(getRecipient(), "TERMINATE", 0, -1));
new AsyncTask<OutgoingEndSessionMessage, Void, Long>() {
@Override
protected Long doInBackground(OutgoingEndSessionMessage... messages) {
return MessageSender.send(context, messages[0], threadId, false, null);
}
@Override
protected void onPostExecute(Long result) {
sendComplete(result);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, endSessionMessage);
}
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
}
private void handleViewMedia() {
Intent intent = new Intent(this, MediaOverviewActivity.class);
intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, recipient.getAddress());
startActivity(intent);
}
private void handleLeavePushGroup() {
if (getRecipient() == null) {
Toast.makeText(this, getString(R.string.ConversationActivity_invalid_recipient),
Toast.LENGTH_LONG).show();
return;
private void handleLeaveGroup() {
new AlertDialog.Builder(this)
.setMessage(getString(R.string.ConversationActivity_are_you_sure_you_want_to_leave_this_group))
.setPositiveButton(R.string.yes, (dialog, which) -> {
dcContext.removeContactFromChat((int)threadId, DcContact.DC_CONTACT_ID_SELF);
Toast.makeText(this, getString(R.string.done), Toast.LENGTH_SHORT).show();
})
.setNegativeButton(R.string.no, null)
.show();
}
private void handleArchiveChat() {
int doArchive = dcContext.getChat((int)threadId).getArchived()==0? 1: 0;
dcContext.archiveChat((int)threadId, doArchive);
Toast.makeText(this, getString(R.string.done), Toast.LENGTH_SHORT).show();
if( doArchive == 1 ) {
finish();
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.ConversationActivity_leave_group));
builder.setIconAttribute(R.attr.dialog_info_icon);
builder.setCancelable(true);
builder.setMessage(getString(R.string.ConversationActivity_are_you_sure_you_want_to_leave_this_group));
builder.setPositiveButton(R.string.yes, (dialog, which) -> {
Context self = ConversationActivity.this;
try {
String groupId = getRecipient().getAddress().toGroupString();
DatabaseFactory.getGroupDatabase(self).setActive(groupId, false);
GroupContext context = GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedId(groupId)))
.setType(GroupContext.Type.QUIT)
.build();
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipient(), context, null, System.currentTimeMillis(), 0, null, Collections.emptyList());
MessageSender.send(self, outgoingMessage, threadId, false, null);
DatabaseFactory.getGroupDatabase(self).remove(groupId, Address.fromSerialized(TextSecurePreferences.getLocalNumber(self)));
initializeEnabledCheck();
} catch (IOException e) {
Log.w(TAG, e);
Toast.makeText(self, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show();
}
});
builder.setNegativeButton(R.string.no, null);
builder.show();
private void handleDeleteChat() {
new AlertDialog.Builder(this)
.setMessage(getString(R.string.ConversationActivity_ask_delete_chat))
.setPositiveButton(R.string.yes, (dialog, which) -> {
dcContext.deleteChat((int)threadId);
Toast.makeText(this, getString(R.string.done), Toast.LENGTH_SHORT).show();
finish();
})
.setNegativeButton(R.string.no, null)
.show();
}
private void handleEditPushGroup() {
@@ -761,72 +650,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
startActivityForResult(intent, GROUP_EDIT);
}
private void handleDistributionBroadcastEnabled(MenuItem item) {
distributionType = ThreadDatabase.DistributionTypes.BROADCAST;
item.setChecked(true);
if (threadId != -1) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getThreadDatabase(ConversationActivity.this)
.setDistributionType(threadId, ThreadDatabase.DistributionTypes.BROADCAST);
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
private void handleDistributionConversationEnabled(MenuItem item) {
distributionType = ThreadDatabase.DistributionTypes.CONVERSATION;
item.setChecked(true);
if (threadId != -1) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getThreadDatabase(ConversationActivity.this)
.setDistributionType(threadId, ThreadDatabase.DistributionTypes.CONVERSATION);
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
private void handleDisplayGroupRecipients() {
//TODO: i think this button is not needed and the group options just go to the profile
//new GroupMembersDialog(this, getRecipient()).display();
}
private void handleAddToContacts() {
if (recipient.getAddress().isGroup()) return;
try {
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
if (recipient.getAddress().isEmail()) {
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, recipient.getAddress().toEmailString());
} else {
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getAddress().toPhoneString());
}
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
startActivityForResult(intent, ADD_CONTACT);
} catch (ActivityNotFoundException e) {
Log.w(TAG, e);
}
}
private boolean handleDisplayQuickContact() {
if (recipient.getAddress().isGroup()) return false;
if (recipient.getContactUri() != null) {
ContactsContract.QuickContact.showQuickContact(ConversationActivity.this, titleView, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
} else {
handleAddToContacts();
}
return true;
}
private void handleAddAttachment() {
if (attachmentTypeSelector == null) {
attachmentTypeSelector = new AttachmentTypeSelector(this, getSupportLoaderManager(), new AttachmentTypeListener());
@@ -848,7 +671,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
calculateCharactersRemaining();
supportInvalidateOptionsMenu();
setBlockedUserState(recipient, isSecureText, isDefaultSms);
}
///// Initializers
@@ -987,7 +809,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
composeText = ViewUtil.findById(this, R.id.embedded_text_editor);
charactersLeft = ViewUtil.findById(this, R.id.space_left);
emojiDrawerStub = ViewUtil.findStubById(this, R.id.emoji_drawer_stub);
unblockButton = ViewUtil.findById(this, R.id.unblock_button);
composePanel = ViewUtil.findById(this, R.id.bottom_panel);
container = ViewUtil.findById(this, R.id.layout_container);
reminderView = ViewUtil.findStubById(this, R.id.reminder_stub);
@@ -995,6 +816,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
quickAttachmentDrawer = ViewUtil.findById(this, R.id.quick_attachment_drawer);
quickAttachmentToggle = ViewUtil.findById(this, R.id.quick_attachment_toggle);
inputPanel = ViewUtil.findById(this, R.id.bottom_panel);
imageView = ViewUtil.findById(this, R.id.background_imageview);
ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
@@ -1023,9 +845,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
});
titleView.setOnClickListener(v -> handleConversationSettings());
titleView.setOnLongClickListener(v -> handleDisplayQuickContact());
titleView.setOnBackClickedListener(view -> super.onBackPressed());
unblockButton.setOnClickListener(v -> handleUnblock());
composeText.setOnKeyListener(composeKeyPressedListener);
composeText.addTextChangedListener(composeKeyPressedListener);
@@ -1040,6 +860,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
quickCameraToggle.setVisibility(View.GONE);
quickCameraToggle.setEnabled(false);
}
String backgroundImagePath = TextSecurePreferences.getBackgroundImagePath(this);
Drawable image = Drawable.createFromPath(backgroundImagePath);
imageView.setImageDrawable(image);
}
protected void initializeActionBar() {
@@ -1053,13 +877,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void initializeResources() {
if (recipient != null) recipient.removeListener(this);
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
dcChat = dcContext.getChat((int)threadId);
recipient = dcContext.getRecipient(dcChat);
archived = getIntent().getBooleanExtra(IS_ARCHIVED_EXTRA, false);
distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
glideRequests = GlideApp.with(this);
@@ -1069,20 +890,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
conversationContainer.setClipToPadding(true);
}
recipient.addListener(this);
}
public void onModified(final Recipient recipient) {
Log.w(TAG, "onModified(" + recipient.getAddress().serialize() + ")");
Util.runOnMain(() -> {
Log.w(TAG, "onModifiedRun(): " + recipient.getRegistered());
titleView.setTitle(glideRequests, dcChat);
setBlockedUserState(recipient, isSecureText, isDefaultSms);
setGroupShareProfileReminder(recipient);
updateReminders();
initializeSecurity(isSecureText, isDefaultSms);
invalidateOptionsMenu();
});
if(threadId==DcChat.DC_CHAT_ID_DEADDROP) {
composePanel.setVisibility(View.GONE);
titleView.hideAvatar();
}
}
private void initializeReceivers() {
@@ -1209,7 +1020,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
final Drafts drafts = getDraftsForCurrentState();
final long thisThreadId = this.threadId;
final int thisDistributionType = this.distributionType;
new AsyncTask<Long, Void, Long>() {
@Override
@@ -1218,9 +1028,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
DraftDatabase draftDatabase = DatabaseFactory.getDraftDatabase(ConversationActivity.this);
long threadId = params[0];
if (drafts.size() > 0) {
if (threadId == -1) threadId = threadDatabase.getThreadIdFor(getRecipient(), thisDistributionType);
if (drafts.size() > 0 && threadId>0) {
draftDatabase.insertDrafts(threadId, drafts);
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
drafts.getUriSnippet(),
@@ -1242,16 +1050,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
return future;
}
private void setBlockedUserState(Recipient recipient, boolean isSecureText, boolean isDefaultSms) {
if (false) { // TODO: do we need a unblock button here? typically, the chatlist is closed when blocked
unblockButton.setVisibility(View.VISIBLE);
composePanel.setVisibility(View.GONE);
} else {
composePanel.setVisibility(View.VISIBLE);
unblockButton.setVisibility(View.GONE);
}
}
private void setGroupShareProfileReminder(@NonNull Recipient recipient) {
if (recipient.isPushGroupRecipient() && !recipient.isProfileSharing()) {
groupShareProfileView.get().setRecipient(recipient);
@@ -1409,42 +1207,88 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
sendMediaMessage(forceSms, getMessage(), attachmentManager.buildSlideDeck(), Collections.emptyList(), expiresIn, subscriptionId, initiating);
}
private String getRealPathFromAttachment(Attachment attachment) {
try {
// get file in the blobdir as `<blobdir>/<name>[-<uniqueNumber>].<ext>`
String filename = attachment.getFileName();
String ext = "";
if(filename==null) {
filename = new SimpleDateFormat("yyyy-MM-dd-HH-mm").format(new Date());
ext = "."+MimeTypeMap.getSingleton().getExtensionFromMimeType(attachment.getContentType());
}
else {
int i = filename.lastIndexOf(".");
if(i>=0) {
ext = filename.substring(i);
filename = filename.substring(0, i);
}
}
String path = null;
for (int i=0; i<1000; i++) {
path = dcContext.getBlobdir()+"/"+filename+(i==0? "" : i<100? "-"+i : "-"+(new Date().getTime()+i))+ext;
if (!new File(path).exists()) {
break;
}
}
// copy content to this file
if(path!=null) {
InputStream inputStream = PartAuthority.getAttachmentStream(this, attachment.getDataUri());
OutputStream outputStream = new FileOutputStream(path);
Util.copy(inputStream, outputStream);
}
return path;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
private ListenableFuture<Void> sendMediaMessage(final boolean forceSms, String body, SlideDeck slideDeck, List<Contact> contacts, final long expiresIn, final int subscriptionId, final boolean initiating) {
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(recipient, slideDeck, body, System.currentTimeMillis(), subscriptionId, expiresIn, distributionType, inputPanel.getQuote().orNull(), contacts);
final SettableFuture<Void> future = new SettableFuture<>();
final Context context = getApplicationContext();
final OutgoingMediaMessage outgoingMessage;
if (isSecureText && !forceSms) {
outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessageCandidate);
} else {
outgoingMessage = outgoingMessageCandidate;
}
inputPanel.clearQuote();
attachmentManager.clear(glideRequests, false);
composeText.setText("");
final long id = fragment.stageOutgoingMessage(outgoingMessage);
new AsyncTask<Void, Void, Long>() {
@Override
protected Long doInBackground(Void... param) {
if (initiating) {
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
try {
DcMsg msg = null;
List<Attachment> attachments = slideDeck.asAttachments();
for (Attachment attachment : attachments) {
String contentType = attachment.getContentType();
if (MediaUtil.isImageType(contentType)) {
msg = new DcMsg(dcContext, DcMsg.DC_MSG_IMAGE);
msg.setDimension(attachment.getWidth(), attachment.getHeight());
}
else if (MediaUtil.isAudioType(contentType)) {
msg = new DcMsg(dcContext,
attachment.isVoiceNote()? DcMsg.DC_MSG_VOICE : DcMsg.DC_MSG_AUDIO);
}
else if (MediaUtil.isVideoType(contentType)) {
msg = new DcMsg(dcContext, DcMsg.DC_MSG_VIDEO);
}
else {
msg = new DcMsg(dcContext, DcMsg.DC_MSG_FILE);
}
return MessageSender.send(context, outgoingMessage, threadId, false, () -> fragment.releaseOutgoingMessage(id));
String path = getRealPathFromAttachment(attachment);
msg.setFile(path, null);
}
@Override
protected void onPostExecute(Long result) {
sendComplete(result);
future.set(null);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
msg.setText(body);
dcContext.sendMsg(dcChat.getId(), msg);
}
catch(Exception e) {
e.printStackTrace();
}
sendComplete(dcChat.getId());
future.set(null);
return future;
}
@@ -1821,7 +1665,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
public void handleEvent(int eventId, Object data1, Object data2) {
if (eventId==DcContext.DC_EVENT_CHAT_MODIFIED || eventId==DcContext.DC_EVENT_CONTACTS_CHANGED) {
onModified(recipient);
titleView.setTitle(glideRequests, dcChat);
setGroupShareProfileReminder(recipient);
updateReminders();
initializeSecurity(isSecureText, isDefaultSms);
invalidateOptionsMenu();
}
}
}
@@ -113,6 +113,14 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
return dcMsgList.length > 0;
}
public boolean isGroupChat(){
return dcChat.isGroup();
}
public String getChatName(){
return dcChat.getName();
}
@Override
public int getItemCount() {
return dcMsgList.length;
@@ -400,13 +408,5 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
recordCache.clear();
notifyDataSetChanged();
}
public void addFastRecord(@NonNull MessageRecord record) {
// TODO: i think this is not need, we simply should reload the view
}
public void releaseFastRecord(long id) {
// TODO: i think this is not need, we simply should reload the view
}
}
@@ -21,7 +21,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
@@ -41,10 +40,8 @@ import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.text.ClipboardManager;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -55,26 +52,26 @@ import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewSwitcher;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
import com.b44t.messenger.DcMsg;
import com.bumptech.glide.request.RequestOptions;
import org.thoughtcrime.securesms.ConversationAdapter.HeaderViewHolder;
import org.thoughtcrime.securesms.ConversationAdapter.ItemClickListener;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.connect.DcMsgListLoader;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.contactshare.ContactUtil;
import org.thoughtcrime.securesms.contactshare.SharedContactDetailsActivity;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
import org.thoughtcrime.securesms.mms.GlideApp;
@@ -82,12 +79,10 @@ import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
@@ -124,8 +119,7 @@ public class ConversationFragment extends Fragment
private RecyclerView.ItemDecoration lastSeenDecoration;
private View scrollToBottomButton;
private TextView scrollDateHeader;
private FrameLayout frameLayout;
private TextView noMessageTextView;
private ApplicationDcContext dcContext;
@Override
@@ -148,7 +142,7 @@ public class ConversationFragment extends Fragment
list = ViewUtil.findById(view, android.R.id.list);
scrollToBottomButton = ViewUtil.findById(view, R.id.scroll_to_bottom_button);
scrollDateHeader = ViewUtil.findById(view, R.id.scroll_date_header);
frameLayout = ViewUtil.findById(view, R.id.conversation_container);
noMessageTextView = ViewUtil.findById(view, R.id.no_messages_text_view);
scrollToBottomButton.setOnClickListener(v -> scrollToBottom());
@@ -157,9 +151,12 @@ public class ConversationFragment extends Fragment
list.setLayoutManager(layoutManager);
list.setItemAnimator(null);
String backgroundImagePath = TextSecurePreferences.getBackgroundImagePath(getContext());
Drawable image = Drawable.createFromPath(backgroundImagePath);
frameLayout.setBackground(image);
// setLayerType() is needed to allow larger items (long texts in our case)
// with hardware layers, drawing may result in errors as "OpenGLRenderer: Path too large to be rendered into a texture"
if (android.os.Build.VERSION.SDK_INT >= 11)
{
list.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
return view;
}
@@ -171,6 +168,19 @@ public class ConversationFragment extends Fragment
initializeListAdapter();
}
private void setNoMessageText() {
if(threadId==DcChat.DC_CHAT_ID_DEADDROP) {
noMessageTextView.setText(R.string.menu_deaddrop);
}
else if(getListAdapter().isGroupChat()){
noMessageTextView.setText(R.string.ConversationActivity_MsgNewGroupDraftHint);
}else{
String name = getListAdapter().getChatName();
String message = getString(R.string.ConversationActivity_NoMessagesHint, name, name);
noMessageTextView.setText(message);
}
}
@Override
public void onDestroy() {
dcContext.eventCenter.removeObservers(this);
@@ -221,8 +231,8 @@ public class ConversationFragment extends Fragment
}
private void initializeResources() {
this.recipient = Recipient.from(getActivity(), getActivity().getIntent().getParcelableExtra(ConversationActivity.ADDRESS_EXTRA), true);
this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1);
this.recipient = Recipient.from(getActivity(), Address.fromChat((int)this.threadId), true);
this.lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1);
this.startingPosition = this.getActivity().getIntent().getIntExtra(ConversationActivity.STARTING_POSITION_EXTRA, -1);
this.firstLoad = true;
@@ -533,6 +543,14 @@ public class ConversationFragment extends Fragment
previousOffset = 0;
}
if(!adapter.isActive()){
setNoMessageText();
noMessageTextView.setVisibility(View.VISIBLE);
}
else{
noMessageTextView.setVisibility(View.GONE);
}
if (lastSeenPosition <= 0) {
setLastSeen(0);
}
@@ -545,36 +563,6 @@ public class ConversationFragment extends Fragment
}
}
public long stageOutgoingMessage(OutgoingMediaMessage message) {
MessageRecord messageRecord = DatabaseFactory.getMmsDatabase(getContext()).readerFor(message, threadId).getCurrent();
if (getListAdapter() != null) {
//getListAdapter().setHeaderView(null);
setLastSeen(0);
getListAdapter().addFastRecord(messageRecord);
}
return messageRecord.getId();
}
public long stageOutgoingMessage(OutgoingTextMessage message) {
MessageRecord messageRecord = DatabaseFactory.getSmsDatabase(getContext()).readerFor(message, threadId).getCurrent();
if (getListAdapter() != null) {
//getListAdapter().setHeaderView(null);
setLastSeen(0);
getListAdapter().addFastRecord(messageRecord);
}
return messageRecord.getId();
}
public void releaseOutgoingMessage(long id) {
if (getListAdapter() != null) {
getListAdapter().releaseFastRecord(id);
}
}
private void scrollToStartingPosition(final int startingPosition) {
list.post(() -> {
list.getLayoutManager().scrollToPosition(startingPosition);
@@ -758,6 +746,21 @@ public class ConversationFragment extends Fragment
actionMode.setTitle(String.valueOf(getListAdapter().getSelectedItems().size()));
}
}
else if(threadId==DcChat.DC_CHAT_ID_DEADDROP) {
new AlertDialog.Builder(getActivity())
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
int chatId = dcContext.createChatByMsgId(messageRecord.getId());
if( chatId != 0 ) {
Intent intent = new Intent(getActivity(), ConversationActivity.class);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)chatId);
startActivity(intent);
}
})
.setNegativeButton(android.R.string.cancel, null)
.setMessage(getActivity().getString(R.string.new_conversation_activity__ask_start_chat_with, dcContext.getContact(messageRecord.getFromId()).getDisplayName()))
.show();
}
else if(messageRecord.isSetupMessage()) {
querySetupCode(messageRecord,null);
}
@@ -16,14 +16,11 @@
*/
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.support.annotation.DimenRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -39,13 +36,11 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.components.AlertView;
import org.thoughtcrime.securesms.components.AudioView;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.ConversationItemFooter;
@@ -56,18 +51,12 @@ import org.thoughtcrime.securesms.components.SharedContactView;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.mms.DocumentSlide;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.LongClickCopySpan;
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
@@ -75,7 +64,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.Stub;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.HashSet;
import java.util.List;
@@ -91,16 +79,17 @@ import java.util.Set;
*/
public class ConversationItem extends LinearLayout
implements RecipientModifiedListener, BindableConversationItem
implements BindableConversationItem
{
private static final String TAG = ConversationItem.class.getSimpleName();
private static final int MAX_MEASURE_CALLS = 3;
private DcMsg messageRecord;
private DcChat dcChat;
private DcContact dcContact;
private Locale locale;
private boolean groupThread;
private Recipient recipient;
private GlideRequests glideRequests;
protected ViewGroup bodyBubble;
@@ -108,11 +97,9 @@ public class ConversationItem extends LinearLayout
private TextView bodyText;
private ConversationItemFooter footer;
private TextView groupSender;
private TextView groupSenderProfileName;
private View groupSenderHolder;
private AvatarImageView contactPhoto;
private ViewGroup contactPhotoHolder;
private AlertView alertView;
private ViewGroup container;
private @NonNull Set<DcMsg> batchSelected = new HashSet<>();
@@ -157,8 +144,6 @@ public class ConversationItem extends LinearLayout
this.bodyText = findViewById(R.id.conversation_item_body);
this.footer = findViewById(R.id.conversation_item_footer);
this.groupSender = findViewById(R.id.group_message_sender);
this.groupSenderProfileName = findViewById(R.id.group_message_sender_profile);
this.alertView = findViewById(R.id.indicators_parent);
this.contactPhoto = findViewById(R.id.contact_photo);
this.contactPhotoHolder = findViewById(R.id.contact_photo_container);
this.bodyBubble = findViewById(R.id.body_bubble);
@@ -188,15 +173,16 @@ public class ConversationItem extends LinearLayout
boolean pulseHighlight)
{
this.messageRecord = messageRecord;
this.dcChat = dcChat;
this.locale = locale;
this.glideRequests = glideRequests;
this.batchSelected = batchSelected;
this.conversationRecipient = recipients;
this.groupThread = dcChat.isGroup();
this.recipient = dcContext.getRecipient(dcContext.getChat(messageRecord.getChatId()));
this.recipient.addListener(this);
this.conversationRecipient.addListener(this);
if (groupThread && !messageRecord.isOutgoing()) {
this.dcContact = dcContext.getContact(messageRecord.getFromId());
}
setGutterSizes(messageRecord, groupThread);
setMessageShape(messageRecord, groupThread);
@@ -204,9 +190,8 @@ public class ConversationItem extends LinearLayout
setInteractionState(messageRecord, pulseHighlight);
setBodyText(messageRecord);
setBubbleState(messageRecord);
setStatusIcons(messageRecord);
setContactPhoto(recipient);
setGroupMessageStatus(messageRecord, recipient);
setContactPhoto();
setGroupMessageStatus();
setAuthor(messageRecord, groupThread);
setQuote(messageRecord, groupThread);
setMessageSpacing(context, messageRecord, groupThread);
@@ -283,9 +268,6 @@ public class ConversationItem extends LinearLayout
@Override
public void unbind() {
if (recipient != null) {
recipient.removeListener(this);
}
}
public DcMsg getMessageRecord() {
@@ -299,7 +281,11 @@ public class ConversationItem extends LinearLayout
bodyBubble.getBackground().setColorFilter(defaultBubbleColor, PorterDuff.Mode.MULTIPLY);
} else {
bodyBubble.getBackground().setColorFilter(defaultBubbleColor, PorterDuff.Mode.MULTIPLY);
bodyBubble.getBackground().setColorFilter(dcContext.getRecipient(messageRecord.getChatId()).getColor().toConversationColor(context), PorterDuff.Mode.MULTIPLY);
if(groupThread && dcContact!=null) {
bodyBubble.getBackground().setColorFilter(dcContext.getRecipient(dcContact).getColor().toConversationColor(context), PorterDuff.Mode.MULTIPLY);
} else {
bodyBubble.getBackground().setColorFilter(dcContext.getRecipient(dcChat).getColor().toConversationColor(context), PorterDuff.Mode.MULTIPLY);
}
}
if (audioViewStub.resolved()) {
@@ -501,13 +487,13 @@ public class ConversationItem extends LinearLayout
sharedContactStub.get().setSingularStyle();
}
private void setContactPhoto(@NonNull Recipient recipient) {
private void setContactPhoto() {
if (contactPhoto == null) return;
if (messageRecord.isOutgoing() || !groupThread) {
if (messageRecord.isOutgoing() || !groupThread || dcContact ==null) {
contactPhoto.setVisibility(View.GONE);
} else {
contactPhoto.setAvatar(glideRequests, recipient, true);
contactPhoto.setAvatar(glideRequests, dcContext.getRecipient(dcContact), true);
contactPhoto.setVisibility(View.VISIBLE);
}
}
@@ -526,17 +512,6 @@ public class ConversationItem extends LinearLayout
return messageBody;
}
private void setStatusIcons(DcMsg messageRecord) {
// disable the icon for for, we should use the same ui on desktop/ios here, so, for now
//bodyText.setCompoundDrawablesWithIntrinsicBounds(0, 0, messageRecord.isSetupMessage() ? R.drawable.ic_menu_login : 0, 0);
if (messageRecord.isFailed()) {
alertView.setFailed();
} else {
alertView.setNone();
}
}
private void setQuote(@NonNull DcMsg current, boolean isGroupThread) {
// if (current.isMms() && !current.isMmsNotification() && ((MediaMmsDcMsg)current).getQuote() != null) {
// Quote quote = ((MediaMmsDcMsg)current).getQuote();
@@ -619,43 +594,21 @@ public class ConversationItem extends LinearLayout
return batchSelected.isEmpty() && (messageRecord.isFailed());
}
@SuppressLint("SetTextI18n")
private void setGroupMessageStatus(DcMsg messageRecord, Recipient recipient) {
if (groupThread && !messageRecord.isOutgoing()) {
this.groupSender.setText(recipient.toShortString());
if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) {
this.groupSenderProfileName.setText("~" + recipient.getProfileName());
this.groupSenderProfileName.setVisibility(View.VISIBLE);
} else {
this.groupSenderProfileName.setText(null);
this.groupSenderProfileName.setVisibility(View.GONE);
}
private void setGroupMessageStatus() {
if (groupThread && !messageRecord.isOutgoing() && dcContact !=null) {
this.groupSender.setText(dcContact.getDisplayName());
}
}
private void setAuthor(@NonNull DcMsg current, boolean isGroupThread) {
if (isGroupThread && !current.isOutgoing()) {
if (contactPhotoHolder != null) {
contactPhotoHolder.setVisibility(VISIBLE);
}
/*if (!previous.isPresent() || previous.get().isInfo() || current.getFromId() != previous.get().getFromId() ||
!DateUtils.isSameDay(previous.get().getTimestamp(), current.getTimestamp()))
{*/
groupSenderHolder.setVisibility(VISIBLE);
/*} else {
groupSenderHolder.setVisibility(GONE);
}*/
//if (!next.isPresent() || next.get().isInfo() || current.getFromId() != previous.get().getFromId()) {
contactPhoto.setVisibility(VISIBLE);
//} else {
// contactPhoto.setVisibility(GONE);
//}
groupSenderHolder.setVisibility(VISIBLE);
contactPhoto.setVisibility(VISIBLE);
} else {
groupSenderHolder.setVisibility(GONE);
if (contactPhotoHolder != null) {
contactPhotoHolder.setVisibility(GONE);
}
@@ -683,16 +636,6 @@ public class ConversationItem extends LinearLayout
/// Event handlers
@Override
public void onModified(final Recipient modified) {
Util.runOnMain(() -> {
setBubbleState(messageRecord);
setContactPhoto(recipient);
setGroupMessageStatus(messageRecord, recipient);
setAudioViewTint(messageRecord, conversationRecipient);
});
}
private class SharedContactEventListener implements SharedContactView.EventListener {
@Override
public void onAddToContactsClicked(@NonNull Contact contact) {
@@ -17,12 +17,9 @@
package org.thoughtcrime.securesms;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.support.v7.widget.TooltipCompat;
@@ -33,10 +30,16 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContact;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import org.thoughtcrime.securesms.components.SearchToolbar;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.qr.QrScanHandler;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.search.SearchFragment;
import org.thoughtcrime.securesms.service.KeyCachingService;
@@ -158,29 +161,36 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.menu_new_chat: createChat(); return true;
case R.id.menu_settings: handleDisplaySettings(); return true;
case R.id.menu_clear_passphrase: handleClearPassphrase(); return true;
case R.id.menu_invite: handleInvite(); return true;
case R.id.menu_help: handleHelp(); return true;
case R.id.menu_new_chat: createChat(); return true;
case R.id.menu_settings: handleDisplaySettings(); return true;
case R.id.menu_clear_passphrase: handleClearPassphrase(); return true;
case R.id.menu_qr_scan: handleQrScan(); return true;
case R.id.menu_qr_show: handleQrShow(); return true;
case R.id.menu_deaddrop: handleDeaddrop(); return true;
}
return false;
}
@Override
public void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeen) {
openConversation(threadId, recipient, distributionType, lastSeen, -1);
private void handleQrScan() {
new IntentIntegrator(this).setCaptureActivity(QrScanActivity.class).initiateScan();
}
public void openConversation(long threadId, Recipient recipient, int distributionType, long lastSeen, int startingPosition) {
private void handleQrShow() {
Intent qrIntent = new Intent(this, QrShowActivity.class);
startActivity(qrIntent);
}
@Override
public void onCreateConversation(long threadId, long lastSeen) {
openConversation(threadId, lastSeen, -1);
}
public void openConversation(long threadId, long lastSeen, int startingPosition) {
searchToolbar.clearFocus();
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis());
intent.putExtra(ConversationActivity.LAST_SEEN_EXTRA, lastSeen);
intent.putExtra(ConversationActivity.STARTING_POSITION_EXTRA, startingPosition);
@@ -205,6 +215,12 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
startActivity(intent);
}
private void handleDeaddrop() {
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)DcChat.DC_CHAT_ID_DEADDROP);
startActivity(intent);
}
private void handleDisplaySettings() {
Intent preferencesIntent = new Intent(this, ApplicationPreferencesActivity.class);
startActivity(preferencesIntent);
@@ -216,15 +232,12 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
startService(intent);
}
private void handleInvite() {
startActivity(new Intent(this, InviteActivity.class));
}
private void handleHelp() {
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.help_url))));
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.ConversationListActivity_there_is_no_browser_installed_on_your_device, Toast.LENGTH_LONG).show();
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == IntentIntegrator.REQUEST_CODE) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
QrScanHandler qrScanHandler = new QrScanHandler(this);
qrScanHandler.onScanPerformed(scanResult);
}
}
}
@@ -131,7 +131,7 @@ class ConversationListAdapter extends RecyclerView.Adapter {
ViewHolder holder = (ViewHolder)viewHolder;
DcChat chat = dcContext.getChat(dcChatlist.getChatId(i));
DcLot summary = dcChatlist.getSummary(i, chat);
holder.getItem().bind(dcContext.getThreadRecord(summary, chat), summary, glideRequests, locale, batchSet, batchMode);
holder.getItem().bind(dcContext.getThreadRecord(summary, chat), dcChatlist.getMsgId(i), summary, glideRequests, locale, batchSet, batchMode);
}
@Override
@@ -51,12 +51,10 @@ public class ConversationListArchiveActivity extends PassphraseRequiredActionBar
}
@Override
public void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeenTime) {
public void onCreateConversation(long threadId, long lastSeenTime) {
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.IS_ARCHIVED_EXTRA, true);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
intent.putExtra(ConversationActivity.LAST_SEEN_EXTRA, lastSeenTime);
startActivity(intent);
@@ -19,6 +19,7 @@ package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -50,7 +51,9 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcChatlist;
import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
@@ -270,10 +273,7 @@ public class ConversationListFragment extends Fragment
final DcContext dcContext = DcHelper.getContext(getActivity());
int conversationsCount = getListAdapter().getBatchSelections().size();
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setIconAttribute(R.attr.dialog_alert_icon);
alert.setTitle(getActivity().getResources().getQuantityString(R.plurals.ConversationListFragment_delete_selected_conversations,
conversationsCount, conversationsCount));
alert.setMessage(getActivity().getResources().getQuantityString(R.plurals.ConversationListFragment_this_will_permanently_delete_all_n_selected_conversations,
alert.setMessage(getActivity().getResources().getQuantityString(R.plurals.ConversationListFragment_ask_selected_chats,
conversationsCount, conversationsCount));
alert.setCancelable(true);
@@ -322,8 +322,8 @@ public class ConversationListFragment extends Fragment
actionMode.setTitle(String.valueOf(getListAdapter().getBatchSelections().size()));
}
private void handleCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeen) {
((ConversationSelectedListener)getActivity()).onCreateConversation(threadId, recipient, distributionType, lastSeen);
private void handleCreateConversation(long threadId, long lastSeen) {
((ConversationSelectedListener)getActivity()).onCreateConversation(threadId, lastSeen);
}
@Override
@@ -368,8 +368,30 @@ public class ConversationListFragment extends Fragment
@Override
public void onItemClick(ConversationListItem item) {
if (actionMode == null) {
handleCreateConversation(item.getThreadId(), item.getRecipient(),
item.getDistributionType(), item.getLastSeen());
long threadId = item.getThreadId();
if (threadId==DcChat.DC_CHAT_ID_DEADDROP) {
DcContext dcContext = DcHelper.getContext(getActivity());
int msgId = item.getMsgId();
int contactId = item.getContactId();
DcContact contact = dcContext.getContact(contactId);
new AlertDialog.Builder(getActivity())
.setMessage(getActivity().getString(R.string.new_conversation_activity__ask_start_chat_with, contact.getNameNAddr()))
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
int belongingChatId = dcContext.createChatByMsgId(msgId);
if( belongingChatId != 0 ) {
handleCreateConversation(belongingChatId, 0);
}
})
.setNegativeButton(R.string.not_now, null)
.setNeutralButton(R.string.never, (dialog, which) -> {
dcContext.blockContact(contactId, 1);
})
.show();
return;
}
handleCreateConversation(threadId, item.getLastSeen());
} else {
ConversationListAdapter adapter = (ConversationListAdapter)list.getAdapter();
adapter.toggleThreadInBatchSet(item.getThreadId());
@@ -399,7 +421,7 @@ public class ConversationListFragment extends Fragment
}
public interface ConversationSelectedListener {
void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeen);
void onCreateConversation(long threadId, long lastSeen);
void onSwitchToArchive();
}
@@ -506,6 +528,12 @@ public class ConversationListFragment extends Fragment
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, threadId);
} else {
if (threadId==DcChat.DC_CHAT_ID_DEADDROP) {
int contactId = ((ConversationListItem)viewHolder.itemView).getContactId();
dcContext.marknoticedContact(contactId);
return;
}
new SnackbarAsyncTask<Long>(getView(),
getResources().getQuantityString(R.plurals.ConversationListFragment_conversations_archived, 1, 1),
getString(R.string.ConversationListFragment_undo),
@@ -18,6 +18,7 @@ package org.thoughtcrime.securesms;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.RippleDrawable;
@@ -38,22 +39,22 @@ import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.annimon.stream.Stream;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcLot;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.components.AlertView;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.DeliveryStatusView;
import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.components.ThumbnailView;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.search.model.MessageResult;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.Collections;
@@ -62,8 +63,7 @@ import java.util.Locale;
import java.util.Set;
public class ConversationListItem extends RelativeLayout
implements RecipientModifiedListener,
BindableConversationListItem, Unbindable
implements BindableConversationListItem, Unbindable
{
@SuppressWarnings("unused")
private final static String TAG = ConversationListItem.class.getSimpleName();
@@ -75,14 +75,15 @@ public class ConversationListItem extends RelativeLayout
private Set<Long> selectedThreads;
private Recipient recipient;
private long threadId;
private int msgId;
private GlideRequests glideRequests;
private TextView subjectView;
private FromTextView fromView;
private TextView dateView;
private TextView archivedView;
private DeliveryStatusView deliveryStatusIndicator;
private AlertView alertView;
private ImageView unreadIndicator;
private ImageView verifiedIndicator;
private long lastSeen;
private int unreadCount;
@@ -103,14 +104,14 @@ public class ConversationListItem extends RelativeLayout
protected void onFinishInflate() {
super.onFinishInflate();
this.subjectView = findViewById(R.id.subject);
this.fromView = findViewById(R.id.from);
this.fromView = findViewById(R.id.from_text);
this.dateView = findViewById(R.id.date);
this.deliveryStatusIndicator = findViewById(R.id.delivery_status);
this.alertView = findViewById(R.id.indicators_parent);
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.thumbnailView = findViewById(R.id.thumbnail);
this.archivedView = findViewById(R.id.archived);
this.unreadIndicator = findViewById(R.id.unread_indicator);
this.verifiedIndicator = findViewById(R.id.verified_indicator);
thumbnailView.setClickable(false);
ViewUtil.setTextViewGravityStart(this.fromView, getContext());
@@ -119,16 +120,18 @@ public class ConversationListItem extends RelativeLayout
@Override
public void bind(@NonNull ThreadRecord thread,
int msgId,
@NonNull DcLot dcSummary,
@NonNull GlideRequests glideRequests,
@NonNull Locale locale,
@NonNull Set<Long> selectedThreads,
boolean batchMode)
{
bind(thread, dcSummary, glideRequests, locale, selectedThreads, batchMode, null);
bind(thread, msgId, dcSummary, glideRequests, locale, selectedThreads, batchMode, null);
}
public void bind(@NonNull ThreadRecord thread,
int msgId,
@NonNull DcLot dcSummary,
@NonNull GlideRequests glideRequests,
@NonNull Locale locale,
@@ -140,12 +143,12 @@ public class ConversationListItem extends RelativeLayout
this.selectedThreads = selectedThreads;
this.recipient = thread.getRecipient();
this.threadId = thread.getThreadId();
this.msgId = msgId;
this.glideRequests = glideRequests;
this.unreadCount = thread.getUnreadCount();
this.distributionType = thread.getDistributionType();
this.lastSeen = thread.getLastSeen();
this.recipient.addListener(this);
if (highlightSubstring != null) {
this.fromView.setText(getHighlightedSpan(locale, recipient.getName(), highlightSubstring));
} else {
@@ -177,6 +180,7 @@ public class ConversationListItem extends RelativeLayout
setRippleColor(recipient);
setUnreadIndicator(thread);
this.contactPhotoImage.setAvatar(glideRequests, recipient, true);
verifiedIndicator.setVisibility(thread.isVerified() ? VISIBLE : GONE);
}
public void bind(@NonNull Recipient contact,
@@ -188,15 +192,12 @@ public class ConversationListItem extends RelativeLayout
this.recipient = contact;
this.glideRequests = glideRequests;
this.recipient.addListener(this);
fromView.setText(getHighlightedSpan(locale, recipient.getName(), highlightSubstring));
subjectView.setText(getHighlightedSpan(locale, contact.getAddress().toPhoneString(), highlightSubstring));
dateView.setText("");
archivedView.setVisibility(GONE);
unreadIndicator.setVisibility(GONE);
deliveryStatusIndicator.setNone();
alertView.setNone();
thumbnailView.setVisibility(GONE);
setBatchState(false);
@@ -213,15 +214,12 @@ public class ConversationListItem extends RelativeLayout
this.recipient = messageResult.recipient;
this.glideRequests = glideRequests;
this.recipient.addListener(this);
fromView.setText(recipient, true);
subjectView.setText(getHighlightedSpan(locale, messageResult.bodySnippet, highlightSubstring));
dateView.setText(DateUtils.getBriefRelativeTimeSpanString(getContext(), locale, messageResult.receivedTimestampMs));
archivedView.setVisibility(GONE);
unreadIndicator.setVisibility(GONE);
deliveryStatusIndicator.setNone();
alertView.setNone();
thumbnailView.setVisibility(GONE);
setBatchState(false);
@@ -231,7 +229,6 @@ public class ConversationListItem extends RelativeLayout
@Override
public void unbind() {
if (this.recipient != null) this.recipient.removeListener(this);
}
private void setBatchState(boolean batch) {
@@ -246,12 +243,13 @@ public class ConversationListItem extends RelativeLayout
return threadId;
}
public int getUnreadCount() {
return unreadCount;
public int getMsgId() {
return msgId;
}
public int getDistributionType() {
return distributionType;
public int getContactId() {
DcContext dcContext = DcHelper.getContext(getContext());
return dcContext.getMsg(msgId).getFromId();
}
public long getLastSeen() {
@@ -287,12 +285,9 @@ public class ConversationListItem extends RelativeLayout
if (state==DcMsg.DC_STATE_IN_FRESH || state==DcMsg.DC_STATE_IN_NOTICED) {
deliveryStatusIndicator.setNone();
alertView.setNone();
} else if (state==DcMsg.DC_STATE_OUT_ERROR) {
deliveryStatusIndicator.setNone();
alertView.setFailed();
deliveryStatusIndicator.setFailed();
} else {
alertView.setNone();
if(state==DcMsg.DC_STATE_OUT_MDN_RCVD) {
deliveryStatusIndicator.setRead();
}
@@ -310,8 +305,21 @@ public class ConversationListItem extends RelativeLayout
private void setRippleColor(Recipient recipient) {
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
((RippleDrawable)(getBackground()).mutate())
.setColor(ColorStateList.valueOf(recipient.getColor().toConversationColor(getContext())));
// TODO: a different backgroupd for the deaddrop would be nice, however the following code collades with the selected state and should be fixex
// if(threadId==DcChat.DC_CHAT_ID_DEADDROP) {
// TypedArray ta = getContext().obtainStyledAttributes(new int[] { R.attr.conversation_list_deaddrop_bg_color});
// setBackgroundColor(ta.getColor(0, 0xffffffff));
// ta.recycle();
// }
// else {
// TypedArray ta = getContext().obtainStyledAttributes(new int[] { R.attr.conversation_list_item_background});
// setBackground(ta.getDrawable(0));
// ta.recycle();
((RippleDrawable)(getBackground()).mutate())
.setColor(ColorStateList.valueOf(recipient.getColor().toConversationColor(getContext())));
// }
}
}
@@ -370,15 +378,6 @@ public class ConversationListItem extends RelativeLayout
return spanned;
}
@Override
public void onModified(final Recipient recipient) {
Util.runOnMain(() -> {
fromView.setText(recipient, unreadCount == 0);
contactPhotoImage.setAvatar(glideRequests, recipient, true);
setRippleColor(recipient);
});
}
private static class ThumbnailPositioner implements Runnable {
private final View thumbnailView;
@@ -42,7 +42,7 @@ public class ConversationListItemAction extends LinearLayout implements Bindable
}
@Override
public void bind(@NonNull ThreadRecord thread, @NonNull DcLot dcSummary, @NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode) {
public void bind(@NonNull ThreadRecord thread, int msgId, @NonNull DcLot dcSummary, @NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode) {
this.description.setText(thread.getRecipient().getName());
}
@@ -41,7 +41,7 @@ public class ConversationListItemInboxZero extends LinearLayout implements Binda
}
@Override
public void bind(@NonNull ThreadRecord thread, @NonNull DcLot dcSummary, @NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode) {
public void bind(@NonNull ThreadRecord thread, int msgId, @NonNull DcLot dcSummary, @NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode) {
}
}
@@ -82,7 +82,6 @@ public class ConversationPopupActivity extends ConversationActivity {
public void onSuccess(Long result) {
ActivityOptionsCompat transition = ActivityOptionsCompat.makeScaleUpAnimation(getWindow().getDecorView(), 0, 0, getWindow().getAttributes().width, getWindow().getAttributes().height);
Intent intent = new Intent(ConversationPopupActivity.this, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, getRecipient().getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, result);
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
@@ -73,6 +73,10 @@ public class ConversationTitleView extends RelativeLayout {
this.verified.setVisibility(verified ? View.VISIBLE : View.GONE);
}
public void hideAvatar() {
avatar.setVisibility(View.GONE);
}
@Override
public void setOnClickListener(@Nullable OnClickListener listener) {
this.content.setOnClickListener(listener);
@@ -67,8 +67,6 @@ public class ConversationUpdateItem extends LinearLayout
this.title = findViewById(R.id.conversation_update_title);
this.body = findViewById(R.id.conversation_update_body);
this.date = findViewById(R.id.conversation_update_date);
this.setOnClickListener(new InternalClickListener(null));
}
@Override
@@ -202,58 +200,10 @@ public class ConversationUpdateItem extends LinearLayout
Util.runOnMain(() -> bind(messageRecord, locale));
}
@Override
public void setOnClickListener(View.OnClickListener l) {
super.setOnClickListener(new InternalClickListener(l));
}
@Override
public void unbind() {
if (sender != null) {
sender.removeListener(this);
}
}
private class InternalClickListener implements View.OnClickListener {
@Nullable private final View.OnClickListener parent;
InternalClickListener(@Nullable View.OnClickListener parent) {
this.parent = parent;
}
@Override
public void onClick(View v) {
if ((!messageRecord.isIdentityUpdate() &&
!messageRecord.isIdentityDefault() &&
!messageRecord.isIdentityVerified()) ||
!batchSelected.isEmpty())
{
if (parent != null) parent.onClick(v);
return;
}
final Recipient sender = ConversationUpdateItem.this.sender;
IdentityUtil.getRemoteIdentityKey(getContext(), sender).addListener(new ListenableFuture.Listener<Optional<IdentityRecord>>() {
@Override
public void onSuccess(Optional<IdentityRecord> result) {
if (result.isPresent()) {
Intent intent = new Intent(getContext(), VerifyIdentityActivity.class);
intent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, sender.getAddress());
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(result.get().getIdentityKey()));
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, result.get().getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
getContext().startActivity(intent);
}
}
@Override
public void onFailure(ExecutionException e) {
Log.w(TAG, e);
}
});
}
}
}
@@ -22,6 +22,8 @@ import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
@@ -32,7 +34,6 @@ import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.dd.CircularProgressButton;
import com.soundcloud.android.crop.Crop;
import org.thoughtcrime.securesms.components.InputAwareLayout;
@@ -92,17 +93,17 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
private InputAwareLayout container;
private ImageView avatar;
private CircularProgressButton finishButton;
private EditText name;
private EmojiToggle emojiToggle;
private EmojiDrawer emojiDrawer;
private TextInputEditText statusView;
private View reveal;
private MenuItem finishMenuItem;
private Intent nextIntent;
private byte[] avatarBytes;
private File captureFile;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
@@ -115,6 +116,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
getSupportActionBar().setTitle(R.string.CreateProfileActivity_your_profile_info);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
initializeResources();
initializeEmojiInput();
@@ -125,6 +127,14 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
ApplicationContext.getInstance(this).injectDependencies(this);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuInflater inflater = this.getMenuInflater();
inflater.inflate(R.menu.preferences_create_profile_menu, menu);
finishMenuItem = menu.findItem(R.id.menu_create_profile);
return true;
}
@Override
public void onResume() {
super.onResume();
@@ -139,6 +149,9 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
case android.R.id.home:
onBackPressed();
return true;
case R.id.menu_create_profile:
handleUpload();
break;
}
return false;
@@ -226,11 +239,9 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
TextView informationLabel = ViewUtil.findById(this, R.id.information_label);
this.avatar = ViewUtil.findById(this, R.id.avatar);
this.name = ViewUtil.findById(this, R.id.name);
this.emojiToggle = ViewUtil.findById(this, R.id.emoji_toggle);
this.name = ViewUtil.findById(this, R.id.name_text);
this.emojiDrawer = ViewUtil.findById(this, R.id.emoji_drawer);
this.container = ViewUtil.findById(this, R.id.container);
this.finishButton = ViewUtil.findById(this, R.id.finish_button);
this.reveal = ViewUtil.findById(this, R.id.reveal);
this.statusView = ViewUtil.findById(this, R.id.status_text);
this.nextIntent = getIntent().getParcelableExtra(NEXT_INTENT);
@@ -250,20 +261,15 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
if (s.toString().getBytes().length > ProfileCipher.NAME_PADDED_LENGTH) {
name.setError(getString(R.string.CreateProfileActivity_too_long));
finishButton.setEnabled(false);
} else if (name.getError() != null || !finishButton.isEnabled()) {
name.setError(null);
finishButton.setEnabled(true);
}
}
});
this.finishButton.setOnClickListener(view -> {
this.finishButton.setIndeterminateProgressMode(true);
this.finishButton.setProgress(50);
handleUpload();
if(finishMenuItem != null){
if (s.toString().getBytes().length > ProfileCipher.NAME_PADDED_LENGTH) {
name.setError(getString(R.string.CreateProfileActivity_too_long));
finishMenuItem.setEnabled(false);
} else if (name.getError() != null || !finishMenuItem.isEnabled()) {
name.setError(null);
finishMenuItem.setEnabled(true);
}
}}
});
passwordAccountSettings.setOnClickListener(view -> {
@@ -348,15 +354,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
}
private void initializeEmojiInput() {
this.emojiToggle.attach(emojiDrawer);
this.emojiToggle.setOnClickListener(v -> {
if (container.getCurrentInput() == emojiDrawer) {
container.showSoftkey(name);
} else {
container.show(name, emojiDrawer);
}
});
this.emojiDrawer.setEmojiEventListener(new EmojiDrawer.EmojiEventListener() {
@Override
@@ -374,7 +371,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
}
});
this.container.addOnKeyboardShownListener(() -> emojiToggle.setToEmoji());
this.name.setOnClickListener(v -> container.showSoftkey(name));
}
@@ -494,26 +490,17 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
}
private void handleFinishedLegacy() {
finishButton.setProgress(0);
if (nextIntent != null) startActivity(nextIntent);
finish();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void handleFinishedLollipop() {
int[] finishButtonLocation = new int[2];
int[] revealLocation = new int[2];
finishButton.getLocationInWindow(finishButtonLocation);
reveal.getLocationInWindow(revealLocation);
int finishX = finishButtonLocation[0] - revealLocation[0];
int finishY = finishButtonLocation[1] - revealLocation[1];
finishX += finishButton.getWidth() / 2;
finishY += finishButton.getHeight() / 2;
Animator animation = ViewAnimationUtils.createCircularReveal(reveal, finishX, finishY, 0f, (float) Math.max(reveal.getWidth(), reveal.getHeight()));
Animator animation = ViewAnimationUtils.createCircularReveal(reveal, reveal.getWidth(), 0, 0f, (float) Math.max(reveal.getWidth(), reveal.getHeight()));
animation.setDuration(500);
animation.addListener(new Animator.AnimatorListener() {
@Override
@@ -521,7 +508,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
@Override
public void onAnimationEnd(Animator animation) {
finishButton.setProgress(0);
if (nextIntent != null) startActivity(nextIntent);
finish();
}
@@ -25,6 +25,8 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -38,6 +40,7 @@ import android.widget.Toast;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.dd.CircularProgressButton;
import com.soundcloud.android.crop.Crop;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
@@ -46,13 +49,8 @@ import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter;
@@ -62,12 +60,14 @@ import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import static com.b44t.messenger.DcContact.DC_CONTACT_ID_SELF;
/**
* Activity to create and update groups
*
@@ -97,8 +97,8 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
private ImageView avatar;
private TextView creatingText;
private Bitmap avatarBmp;
@NonNull private Optional<GroupData> groupToUpdate = Optional.absent();
private CircularProgressButton verifyButton;
private Integer editGroupChatId = null;
@Override
protected void onPreCreate() {
@@ -132,7 +132,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
groupName.setEnabled(true);
String title;
if(groupToUpdate.isPresent()) {
if(isEdit()) {
title = getString(R.string.GroupCreateActivity_actionbar_edit_title);
}
else if(createVerified) {
@@ -148,10 +148,6 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
new AddMembersTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipients);
}
private void addSelectedContacts(@NonNull Collection<Recipient> recipients) {
addSelectedContacts(recipients.toArray(new Recipient[recipients.size()]));
}
private static class AddMembersTask extends AsyncTask<Recipient,Void,List<AddMembersTask.Result>> {
static class Result {
Optional<Recipient> recipient;
@@ -182,8 +178,6 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
@Override
protected void onPostExecute(List<Result> results) {
if (activity.isFinishing()) return;
ApplicationDcContext dcContext = DcHelper.getContext(activity);
for (Result result : results) {
Recipient recipient = result.recipient.get();
Address address = recipient.getAddress();
@@ -200,20 +194,25 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
avatar = ViewUtil.findById(this, R.id.avatar);
groupName = ViewUtil.findById(this, R.id.group_name);
creatingText = ViewUtil.findById(this, R.id.creating_group_text);
verifyButton = ViewUtil.findById(this, R.id.verify_button);
SelectedRecipientsAdapter adapter = new SelectedRecipientsAdapter(this);
adapter.setOnRecipientDeletedListener(this);
lv.setAdapter(adapter);
findViewById(R.id.add_member_button).setOnClickListener(new AddRecipientButtonListener());
if (createVerified) {
verifyButton.setOnClickListener(new ShowQrButtonListener());
verifyButton.setVisibility(View.VISIBLE);
}
avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_group_white_24dp).asDrawable(this, ContactColors.UNKNOWN_COLOR.toConversationColor(this)));
avatar.setOnClickListener(view -> Crop.pickImage(GroupCreateActivity.this));
}
private void initializeExistingGroup() {
final Address groupAddress = getIntent().getParcelableExtra(GROUP_ADDRESS_EXTRA);
if (groupAddress != null) {
new FillExistingGroupInfoAsyncTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, groupAddress.toGroupString());
editGroupChatId = groupAddress.getDcChatId();
new FillExistingGroupInfoAsyncTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, editGroupChatId);
}
}
@@ -235,7 +234,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
finish();
return true;
case R.id.menu_create_group:
if (groupToUpdate.isPresent()) handleGroupUpdate();
if (isEdit()) handleGroupUpdate();
else handleGroupCreate();
return true;
}
@@ -251,49 +250,100 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
private void handleGroupCreate() {
String groupName = getGroupName();
if(groupName==null) {
Toast.makeText(this, getString(R.string.GroupCreateActivity_please_enter_group_name), Toast.LENGTH_LONG).show();
return;
}
if (showGroupNameEmptyToast(groupName)) return;
int chatId = dcContext.createGroupChat(createVerified, groupName);
Set<Recipient> members = getAdapter().getRecipients();
for(Recipient member : members) {
Address address = member.getAddress();
Set<Recipient> recipients = getAdapter().getRecipients();
for(Recipient recipient : recipients) {
Address address = recipient.getAddress();
if(address.isDcContact()) {
int contactId = address.getDcContactId();
dcContext.addContactToChat(chatId, contactId);
}
}
// TODO: handle avatarBmp
setGroupAvatar(chatId);
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)chatId);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, Address.fromChat(chatId));
startActivity(intent);
finish();
}
private void handleGroupUpdate() {
int chatId = 0;// TODO: get correct id from groupToUpdate.get().id; or so
String groupName = getGroupName();
if(groupName!=null) {
dcContext.setChatName(chatId, groupName);
@SuppressWarnings("ResultOfMethodCallIgnored")
private void setGroupAvatar(int chatId) {
if(avatarBmp == null) {
return;
}
String avatarPath = getFilesDir().getAbsolutePath() + "/chatAvatar_" + chatId + ".jpg";
File oldImage = new File(avatarPath);
if (oldImage.exists()) {
oldImage.delete();
}
FileOutputStream outStream;
try {
outStream = new FileOutputStream(avatarPath);
avatarBmp.compress(Bitmap.CompressFormat.JPEG, 85, outStream);
dcContext.setChatProfileImage(chatId, avatarPath);
Log.d("dboehrs", "setGroupAvatar: " + avatarPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
// TODO: compare dcContext.getChatContacts(chatId); against getAdapter().getRecipients();
// and add/remove contacts
private boolean showGroupNameEmptyToast(String groupName) {
if(groupName == null) {
Toast.makeText(this, getString(R.string.GroupCreateActivity_please_enter_group_name), Toast.LENGTH_LONG).show();
return true;
}
return false;
}
private void handleGroupUpdate() {
if(editGroupChatId == null) {
return;
}
String groupName = getGroupName();
if (showGroupNameEmptyToast(groupName)) {
return;
}
dcContext.setChatName(editGroupChatId, groupName);
updateGroupParticipants();
// TODO: handle avatarBmp
setGroupAvatar(editGroupChatId);
Intent intent = new Intent();
Recipient recipient = dcContext.getRecipient(ApplicationDcContext.RECIPIENT_TYPE_CHAT, editGroupChatId);
intent.putExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA, recipient.getAddress());
setResult(RESULT_OK, intent);
finish();
}
private void updateGroupParticipants() {
SparseBooleanArray currentChatContactIds = new SparseBooleanArray();
for(int chatContactId : dcContext.getChatContacts(editGroupChatId)) {
currentChatContactIds.put(chatContactId, chatContactId == DC_CONTACT_ID_SELF);
}
Set<Recipient> recipients = getAdapter().getRecipients();
for(Recipient recipient : recipients) {
Address address = recipient.getAddress();
if(address.isDcContact()) {
int contactId = address.getDcContactId();
if(currentChatContactIds.indexOfKey(contactId) < 0) {
dcContext.addContactToChat(editGroupChatId, contactId);
} else {
currentChatContactIds.put(contactId, true);
}
}
}
for(int index = 0; index < currentChatContactIds.size(); index++) {
if (!currentChatContactIds.valueAt(index)) {
dcContext.removeContactFromChat(editGroupChatId, currentChatContactIds.keyAt(index));
}
}
}
private SelectedRecipientsAdapter getAdapter() {
return (SelectedRecipientsAdapter)lv.getAdapter();
}
@@ -354,7 +404,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
public void onClick(View v) {
Intent intent = new Intent(GroupCreateActivity.this, ContactMultiSelectionActivity.class);
intent.putExtra(ContactSelectionListFragment.SELECT_VERIFIED_EXTRA, createVerified);
if (groupToUpdate.isPresent()) {
if (isEdit()) {
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_PUSH);
} else {
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_PUSH | DisplayMode.FLAG_SMS);
@@ -363,10 +413,20 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
}
private static class FillExistingGroupInfoAsyncTask extends ProgressDialogAsyncTask<String,Void,Optional<GroupData>> {
private GroupCreateActivity activity;
private class ShowQrButtonListener implements View.OnClickListener {
public FillExistingGroupInfoAsyncTask(GroupCreateActivity activity) {
@Override
public void onClick(View view) {
Intent qrIntent = new Intent(GroupCreateActivity.this, QrShowActivity.class);
startActivity(qrIntent);
}
}
private static class FillExistingGroupInfoAsyncTask extends ProgressDialogAsyncTask<Integer,Void,Recipient> {
GroupCreateActivity activity;
FillExistingGroupInfoAsyncTask(GroupCreateActivity activity) {
super(activity,
R.string.GroupCreateActivity_loading_group_details,
R.string.please_wait);
@@ -374,40 +434,37 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
@Override
protected Optional<GroupData> doInBackground(String... groupIds) {
final GroupDatabase db = DatabaseFactory.getGroupDatabase(activity);
final List<Recipient> recipients = db.getGroupMembers(groupIds[0], false);
final Optional<GroupRecord> group = db.getGroup(groupIds[0]);
final Set<Recipient> existingContacts = new HashSet<>(recipients.size());
existingContacts.addAll(recipients);
if (group.isPresent()) {
return Optional.of(new GroupData(groupIds[0],
existingContacts,
BitmapUtil.fromByteArray(group.get().getAvatar()),
group.get().getAvatar(),
group.get().getTitle()));
} else {
return Optional.absent();
}
protected Recipient doInBackground(Integer... recipientIds) {
Integer recipientsId = recipientIds[0];
return activity.dcContext.getRecipient(ApplicationDcContext.RECIPIENT_TYPE_CHAT, recipientsId);
}
@Override
protected void onPostExecute(Optional<GroupData> group) {
super.onPostExecute(group);
protected void onPostExecute(Recipient recipient) {
super.onPostExecute(recipient);
activity.fllExistingGroup(recipient);
}
}
if (group.isPresent() && !activity.isFinishing()) {
activity.groupToUpdate = group;
activity.groupName.setText(group.get().name);
if (group.get().avatarBmp != null) {
activity.setAvatar(group.get().avatarBytes, group.get().avatarBmp);
private void fllExistingGroup(Recipient recipient) {
List<Recipient> participants = recipient.getParticipants();
if (!isFinishing()) {
Recipient ownAddress = null;
for(Recipient participant : participants) {
if(participant.getAddress().getDcContactId() == DC_CONTACT_ID_SELF) {
ownAddress = participant;
} else {
addSelectedContacts(participant);
}
SelectedRecipientsAdapter adapter = new SelectedRecipientsAdapter(activity, group.get().recipients);
adapter.setOnRecipientDeletedListener(activity);
activity.lv.setAdapter(adapter);
activity.updateViewState();
}
if (ownAddress != null) {
participants.remove(ownAddress);
}
groupName.setText(recipient.getName());
SelectedRecipientsAdapter adapter = new SelectedRecipientsAdapter(this, participants);
adapter.setOnRecipientDeletedListener(this);
lv.setAdapter(adapter);
updateViewState();
}
}
@@ -421,19 +478,8 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
.into(avatar);
}
private static class GroupData {
String id;
Set<Recipient> recipients;
Bitmap avatarBmp;
byte[] avatarBytes;
String name;
public GroupData(String id, Set<Recipient> recipients, Bitmap avatarBmp, byte[] avatarBytes, String name) {
this.id = id;
this.recipients = recipients;
this.avatarBmp = avatarBmp;
this.avatarBytes = avatarBytes;
this.name = name;
}
private boolean isEdit() {
return editGroupChatId != null;
}
}
@@ -1,136 +0,0 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.provider.ContactsContract;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Util;
import java.util.LinkedList;
import java.util.List;
public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
private static final String TAG = GroupMembersDialog.class.getSimpleName();
private final Recipient recipient;
private final Context context;
public GroupMembersDialog(Context context, Recipient recipient) {
this.recipient = recipient;
this.context = context;
}
@Override
public void onPreExecute() {}
@Override
protected List<Recipient> doInBackground(Void... params) {
return DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), true);
}
@Override
public void onPostExecute(List<Recipient> members) {
GroupMembers groupMembers = new GroupMembers(members);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.ConversationActivity_group_members);
builder.setIconAttribute(R.attr.group_members_dialog_icon);
builder.setCancelable(true);
builder.setItems(groupMembers.getRecipientStrings(), new GroupMembersOnClickListener(context, groupMembers));
builder.setPositiveButton(android.R.string.ok, null);
builder.show();
}
public void display() {
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private static class GroupMembersOnClickListener implements DialogInterface.OnClickListener {
private final GroupMembers groupMembers;
private final Context context;
public GroupMembersOnClickListener(Context context, GroupMembers members) {
this.context = context;
this.groupMembers = members;
}
@Override
public void onClick(DialogInterface dialogInterface, int item) {
Recipient recipient = groupMembers.get(item);
if (recipient.getContactUri() != null) {
Intent intent = new Intent(context, RecipientPreferenceActivity.class);
intent.putExtra(RecipientPreferenceActivity.ADDRESS_EXTRA, recipient.getAddress());
context.startActivity(intent);
} else {
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
if (recipient.getAddress().isEmail()) {
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, recipient.getAddress().toEmailString());
} else {
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getAddress().toPhoneString());
}
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
context.startActivity(intent);
}
}
}
/**
* Wraps a List of Recipient (just like @class Recipients),
* but with focus on the order of the Recipients.
* So that the order of the RecipientStrings[] matches
* the internal order.
*
* @author Christoph Haefner
*/
private class GroupMembers {
private final String TAG = GroupMembers.class.getSimpleName();
private final LinkedList<Recipient> members = new LinkedList<>();
public GroupMembers(List<Recipient> recipients) {
for (Recipient recipient : recipients) {
if (isLocalNumber(recipient)) {
members.push(recipient);
} else {
members.add(recipient);
}
}
}
public String[] getRecipientStrings() {
List<String> recipientStrings = new LinkedList<>();
for (Recipient recipient : members) {
if (isLocalNumber(recipient)) {
recipientStrings.add(context.getString(R.string.GroupMembersDialog_me));
} else {
String name = recipient.toShortString();
if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) {
name += " ~" + recipient.getProfileName();
}
recipientStrings.add(name);
}
}
return recipientStrings.toArray(new String[members.size()]);
}
public Recipient get(int index) {
return members.get(index);
}
private boolean isLocalNumber(Recipient recipient) {
return Util.isOwnNumber(context, recipient.getAddress());
}
}
}
@@ -98,12 +98,10 @@ public class NewConversationActivity extends ContactSelectionActivity {
final DcContext dcContext = DcHelper.getContext(this);
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, Address.fromChat(chatId));
intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA));
intent.setDataAndType(getIntent().getData(), getIntent().getType());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)chatId);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
startActivity(intent);
finish();
}
@@ -0,0 +1,118 @@
package org.thoughtcrime.securesms;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.MenuItem;
import com.journeyapps.barcodescanner.CaptureManager;
import com.journeyapps.barcodescanner.CompoundBarcodeView;
import org.thoughtcrime.securesms.permissions.Permissions;
public class QrScanActivity extends AppCompatActivity {
private CaptureManager capture;
private CompoundBarcodeView barcodeScannerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qr_scan);
assert getSupportActionBar() != null;
getSupportActionBar().setTitle(R.string.qr_scan_activity__title);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
barcodeScannerView = findViewById(R.id.zxing_barcode_scanner);
barcodeScannerView.setStatusText(getString(R.string.qr_scan_activity__hint) + "\n ");
if (savedInstanceState != null) {
init(barcodeScannerView, getIntent(), savedInstanceState);
}
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.onAnyResult(this::handleQrScanWithPermissions)
.onAnyDenied(this::handleQrScanWithDeniedPermission)
.execute();
}
private void handleQrScanWithPermissions() {
init(barcodeScannerView, getIntent(), null);
}
private void handleQrScanWithDeniedPermission() {
setResult(Activity.RESULT_CANCELED);
finish();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return false;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
private void init(CompoundBarcodeView barcodeScannerView, Intent intent, Bundle savedInstanceState) {
capture = new CaptureManager(this, barcodeScannerView);
capture.initializeFromIntent(intent, savedInstanceState);
capture.decode();
}
@Override
protected void onResume() {
super.onResume();
if (capture != null) {
capture.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (capture != null) {
capture.onPause();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (capture != null) {
capture.onDestroy();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (capture != null) {
capture.onSaveInstanceState(outState);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return barcodeScannerView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
}
}
@@ -0,0 +1,188 @@
package org.thoughtcrime.securesms;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
public class QrShowActivity extends AppCompatActivity implements DcEventCenter.DcEventDelegate {
public final static int WHITE = 0xFFFFFFFF;
public final static int BLACK = 0xFF000000;
public final static int WIDTH = 400;
public final static int HEIGHT = 400;
public int numJoiners;
DcEventCenter dcEventCenter;
ApplicationDcContext dcContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qr_show);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // keeping the screen on also avoids falling back from IDLE to POLL
dcContext = DcHelper.getContext(this);
dcEventCenter = dcContext.eventCenter;
Bundle extras = getIntent().getExtras();
int chatId = 0;
if (extras != null) {
chatId = extras.getInt("chat_id");
}
ActionBar supportActionBar = getSupportActionBar();
assert supportActionBar != null;
supportActionBar.setDisplayHomeAsUpEnabled(true);
String hint;
if (chatId != 0) {
// verified-group
String groupName = dcContext.getChat(chatId).getName();
hint = String.format(this.getString(R.string.qr_show_activity__join_verified_group_hint), groupName);
supportActionBar.setTitle(groupName);
supportActionBar.setSubtitle(R.string.qr_show_activity__join_verified_group_title);
} else {
// verify-contact
String selfName = DcHelper.get(this, DcHelper.CONFIG_DISPLAY_NAME); // we cannot use MrContact.getDisplayName() as this would result in "Me" instead of
String nameAndAddress;
if (selfName.isEmpty()) {
selfName = DcHelper.get(this, DcHelper.CONFIG_ADDRESS, "unknown");
nameAndAddress = selfName;
} else {
nameAndAddress = String.format("%s (%s)", selfName, DcHelper.get(this, DcHelper.CONFIG_ADDRESS));
}
hint = String.format(this.getString(R.string.qr_show_activity__join_contact_hint), nameAndAddress);
supportActionBar.setTitle(selfName);
supportActionBar.setSubtitle(R.string.qr_show_activity__join_contact_title);
}
TextView hintBelowQr = findViewById(R.id.qrShowHint);
hintBelowQr.setText(Html.fromHtml(hint));
numJoiners = 0;
ImageView imageView = findViewById(R.id.qrImage);
try {
Bitmap bitmap = encodeAsBitmap(dcContext.getSecurejoinQr(chatId));
imageView.setImageBitmap(bitmap);
} catch (WriterException e) {
e.printStackTrace();
}
dcEventCenter.addObserver(this, DcContext.DC_EVENT_SECUREJOIN_INVITER_PROGRESS);
}
@Override
protected void onDestroy() {
super.onDestroy();
dcEventCenter.removeObserver(this, DcContext.DC_EVENT_SECUREJOIN_INVITER_PROGRESS);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return false;
}
Bitmap encodeAsBitmap(String str) throws WriterException {
BitMatrix result;
try {
result = new MultiFormatWriter().encode(str,
BarcodeFormat.QR_CODE, WIDTH, HEIGHT, null);
} catch (IllegalArgumentException iae) {
// Unsupported format
return null;
}
int w = result.getWidth();
int h = result.getHeight();
int[] pixels = new int[w * h];
for (int y = 0; y < h; y++) {
int offset = y * w;
for (int x = 0; x < w; x++) {
pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
}
}
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, w, 0, 0, w, h);
int configQrOverlayLogo = DcHelper.getInt(this, DcHelper.CONFIG_QR_OVERLAY_LOGO, 1);
if (configQrOverlayLogo != 0) {
Bitmap overlay = BitmapFactory.decodeResource(this.getResources(), R.drawable.qr_overlay);
putOverlay(bitmap, overlay);
}
return bitmap;
}
public void putOverlay(Bitmap bitmap, Bitmap overlay) {
int bw = bitmap.getWidth();
int bh = bitmap.getHeight();
int ow = bw / 6;
int oh = bh / 6;
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(overlay, null, new Rect(bw / 2 - ow / 2, bh / 2 - oh / 2, bw / 2 + ow / 2, bh / 2 + oh / 2), paint);
}
@Override
public void handleEvent(int eventId, Object data1, Object data2) {
if (eventId == DcContext.DC_EVENT_SECUREJOIN_INVITER_PROGRESS) {
DcContext dcContext = DcHelper.getContext(this);
int contact_id = ((Long) data1).intValue();
long progress = (Long) data2;
String msg = null;
if (progress == 300) {
msg = String.format(getString(R.string.qr_show_activity__joining), dcContext.getContact(contact_id).getNameNAddr());
numJoiners++;
} else if (progress == 600) {
msg = String.format(getString(R.string.qr_show_activity__verified), dcContext.getContact(contact_id).getNameNAddr());
} else if (progress == 800) {
msg = String.format(getString(R.string.qr_show_activity__group_joined), dcContext.getContact(contact_id).getNameNAddr());
}
if (msg != null) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
if (progress == 1000) {
numJoiners--;
if (numJoiners <= 0) {
finish();
}
}
}
}
}
@@ -240,15 +240,13 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
contactsFragment.getView().setVisibility(View.VISIBLE);
progressWheel.setVisibility(View.GONE);
} else {
createConversation(threadId, address, distributionType);
createConversation(threadId);
}
}
private void createConversation(long threadId, Address address, int distributionType) {
private void createConversation(long threadId) {
final Intent intent = getBaseShareIntent(ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, address);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
isPassingAlongMedia = true;
startActivity(intent);
@@ -275,7 +273,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
public void onContactSelected(int specialId, String number) {
Recipient recipient = Recipient.from(this, Address.fromExternal(this, number), true);
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
createConversation(existingThread, recipient.getAddress(), ThreadDatabase.DistributionTypes.DEFAULT);
createConversation(existingThread);
}
@Override
@@ -10,7 +10,7 @@ public abstract class Attachment {
@NonNull
private final String contentType;
private final int transferState;
private int transferState;
private final long size;
@Nullable
@@ -63,6 +63,10 @@ public abstract class Attachment {
@Nullable
public abstract Uri getThumbnailUri();
public void setTransferState(int transferState) {
this.transferState = transferState;
}
public int getTransferState() {
return transferState;
}
@@ -0,0 +1,36 @@
package org.thoughtcrime.securesms.attachments;
import java.io.File;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
public class DcAttachment extends Attachment {
private final DcMsg dcMsg;
public DcAttachment(DcMsg dcMsg) {
// todo: width, height, quote
super(dcMsg.getFilemime(), AttachmentDatabase.TRANSFER_PROGRESS_DONE, dcMsg.getFilebytes(),
dcMsg.getFilename(),
Uri.fromFile(new File(dcMsg.getFile())).toString(), String.valueOf(dcMsg.getId()), null, null,
null, dcMsg.getType() == DcMsg.DC_MSG_VOICE,
0, 0, false);
this.dcMsg = dcMsg;
}
@Nullable
@Override
public Uri getDataUri() {
return Uri.fromFile(new File(dcMsg.getFile()));
}
@Nullable
@Override
public Uri getThumbnailUri() {
return Uri.fromFile(new File(dcMsg.getFile()));
}
}
@@ -1,72 +0,0 @@
package org.thoughtcrime.securesms.components;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build.VERSION_CODES;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.thoughtcrime.securesms.R;
public class AlertView extends LinearLayout {
private static final String TAG = AlertView.class.getSimpleName();
private ImageView approvalIndicator;
private ImageView failedIndicator;
public AlertView(Context context) {
this(context, null);
}
public AlertView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(attrs);
}
@TargetApi(VERSION_CODES.HONEYCOMB)
public AlertView(final Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize(attrs);
}
private void initialize(AttributeSet attrs) {
inflate(getContext(), R.layout.alert_view, this);
approvalIndicator = findViewById(R.id.pending_approval_indicator);
failedIndicator = findViewById(R.id.sms_failed_indicator);
if (attrs != null) {
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.AlertView, 0, 0);
boolean useSmallIcon = typedArray.getBoolean(R.styleable.AlertView_useSmallIcon, false);
typedArray.recycle();
if (useSmallIcon) {
int size = getResources().getDimensionPixelOffset(R.dimen.alertview_small_icon_size);
failedIndicator.getLayoutParams().width = size;
failedIndicator.getLayoutParams().height = size;
requestLayout();
}
}
}
public void setNone() {
this.setVisibility(View.GONE);
}
public void setPendingApproval() {
this.setVisibility(View.VISIBLE);
approvalIndicator.setVisibility(View.VISIBLE);
failedIndicator.setVisibility(View.GONE);
}
public void setFailed() {
this.setVisibility(View.VISIBLE);
approvalIndicator.setVisibility(View.GONE);
failedIndicator.setVisibility(View.VISIBLE);
}
}
@@ -20,18 +20,9 @@ import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import com.pnikosis.materialishprogress.ProgressWheel;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.audio.AudioSlidePlayer;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@@ -45,11 +36,9 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
private final @NonNull ViewGroup container;
private final @NonNull ImageView playButton;
private final @NonNull ImageView pauseButton;
private final @NonNull ImageView downloadButton;
private final @NonNull SeekBar seekBar;
private final @NonNull TextView timestamp;
private @Nullable SlideClickListener downloadListener;
private @Nullable AudioSlidePlayer audioSlidePlayer;
private int backwardsCounter;
@@ -69,7 +58,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
this.controlToggle = (AnimatingToggle) findViewById(R.id.control_toggle);
this.playButton = (ImageView) findViewById(R.id.play);
this.pauseButton = (ImageView) findViewById(R.id.pause);
this.downloadButton = (ImageView) findViewById(R.id.download);
this.seekBar = (SeekBar) findViewById(R.id.seek);
this.timestamp = (TextView) findViewById(R.id.timestamp);
@@ -134,7 +122,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
this.pauseButton.setFocusable(focusable);
this.seekBar.setFocusable(focusable);
this.seekBar.setFocusableInTouchMode(focusable);
this.downloadButton.setFocusable(focusable);
}
@Override
@@ -144,7 +131,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
this.pauseButton.setClickable(clickable);
this.seekBar.setClickable(clickable);
this.seekBar.setOnTouchListener(clickable ? null : new TouchIgnoringListener());
this.downloadButton.setClickable(clickable);
}
@Override
@@ -153,7 +139,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
this.playButton.setEnabled(enabled);
this.pauseButton.setEnabled(enabled);
this.seekBar.setEnabled(enabled);
this.downloadButton.setEnabled(enabled);
}
@Override
@@ -182,8 +167,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
this.pauseButton.setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
}
this.downloadButton.setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
this.timestamp.setTextColor(foregroundTint);
this.seekBar.getProgressDrawable().setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
@@ -248,19 +231,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
}
}
private class DownloadClickedListener implements View.OnClickListener {
private final @NonNull AudioSlide slide;
private DownloadClickedListener(@NonNull AudioSlide slide) {
this.slide = slide;
}
@Override
public void onClick(View v) {
if (downloadListener != null) downloadListener.onClick(v, slide);
}
}
private class SeekBarModifiedListener implements SeekBar.OnSeekBarChangeListener {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
@@ -75,12 +75,7 @@ public class ConversationItemFooter extends LinearLayout {
private void presentDate(@NonNull DcMsg messageRecord, @NonNull Locale locale) {
dateView.forceLayout();
if (messageRecord.isFailed()) {
dateView.setText(R.string.ConversationItem_error_not_delivered);
} else {
dateView.setText(DateUtils.getTimeOfDayTimeSpanString(getContext(), locale, messageRecord.getTimestamp()));
}
dateView.setText(DateUtils.getTimeOfDayTimeSpanString(getContext(), locale, messageRecord.getTimestamp()));
}
private void presentSecureIndicator(@NonNull DcMsg messageRecord) {
@@ -88,13 +83,10 @@ public class ConversationItemFooter extends LinearLayout {
}
private void presentDeliveryStatus(@NonNull DcMsg messageRecord) {
if (!messageRecord.isFailed()) {
if (!messageRecord.isOutgoing()) deliveryStatusView.setNone();
else if (messageRecord.isRemoteRead()) deliveryStatusView.setRead();
else if (messageRecord.isDelivered()) deliveryStatusView.setSent();
else deliveryStatusView.setPending();
} else {
deliveryStatusView.setNone();
}
if (!messageRecord.isOutgoing()) deliveryStatusView.setNone();
else if (messageRecord.isRemoteRead()) deliveryStatusView.setRead();
else if (messageRecord.isDelivered()) deliveryStatusView.setSent();
else if (messageRecord.isFailed()) deliveryStatusView.setFailed();
else deliveryStatusView.setPending();
}
}
@@ -16,10 +16,14 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import java.util.concurrent.ExecutionException;
public class ConversationItemThumbnail extends FrameLayout {
@@ -145,11 +149,25 @@ public class ConversationItemThumbnail extends FrameLayout {
return footer;
}
private void refreshSlideAttachmentState(ListenableFuture<Boolean> signal, Slide slide) {
signal.addListener(new ListenableFuture.Listener<Boolean>() {
@Override
public void onSuccess(Boolean result) {
slide.asAttachment().setTransferState(AttachmentDatabase.TRANSFER_PROGRESS_DONE);
}
@Override
public void onFailure(ExecutionException e) {
slide.asAttachment().setTransferState(AttachmentDatabase.TRANSFER_PROGRESS_FAILED);
}
});
}
@UiThread
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
boolean showControls, boolean isPreview)
{
thumbnail.setImageResource(glideRequests, slide, showControls, isPreview);
refreshSlideAttachmentState(thumbnail.setImageResource(glideRequests, slide, showControls, isPreview), slide);
}
@UiThread
@@ -157,7 +175,8 @@ public class ConversationItemThumbnail extends FrameLayout {
boolean showControls, boolean isPreview, int naturalWidth,
int naturalHeight)
{
thumbnail.setImageResource(glideRequests, slide, showControls, isPreview, naturalWidth, naturalHeight);
refreshSlideAttachmentState(thumbnail.setImageResource(glideRequests, slide, showControls, isPreview, naturalWidth, naturalHeight), slide);
}
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Uri uri) {
@@ -16,20 +16,19 @@
*/
package org.thoughtcrime.securesms.connect;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.PowerManager;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.v4.content.FileProvider;
import android.util.Log;
import android.widget.Toast;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcChatlist;
import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
@@ -40,16 +39,11 @@ import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientProvider;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
@@ -58,15 +52,23 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ApplicationDcContext extends DcContext {
@IntDef({RECIPIENT_TYPE_CHAT, RECIPIENT_TYPE_CONTACT})
public @interface RecipientType {}
public static final int RECIPIENT_TYPE_CHAT = 0;
public static final int RECIPIENT_TYPE_CONTACT = 1;
public Context context;
public ApplicationDcContext(Context context) {
super("Android");
super("android-dev");
this.context = context;
File dbfile = new File(context.getFilesDir(), "messenger.db");
@@ -155,13 +157,25 @@ public class ApplicationDcContext extends DcContext {
**********************************************************************************************/
@NonNull
public Recipient getRecipient(int chatId) {
return getRecipient(getChat(chatId));
public Recipient getRecipient(@RecipientType int recipientType, int id) {
switch (recipientType) {
case RECIPIENT_TYPE_CHAT:
return getRecipient(getChat(id));
case RECIPIENT_TYPE_CONTACT:
return getRecipient(getContact(id));
default:
throw new IllegalArgumentException("Wrong RecipientType");
}
}
@NonNull
public Recipient getRecipient(DcChat chat) {
RecipientProvider.RecipientDetails recipientDetails = new RecipientProvider.RecipientDetails(chat.getName(), null, false, null, null);
int[] contactIds = getChatContacts(chat.getId());
List<Recipient> participants = new ArrayList<>();
for(int contactId : contactIds) {
participants.add(getRecipient(RECIPIENT_TYPE_CONTACT, contactId));
}
RecipientProvider.RecipientDetails recipientDetails = new RecipientProvider.RecipientDetails(chat.getName(), null, false, null, participants);
return new Recipient(Address.fromChat(chat.getId()), recipientDetails);
}
@NonNull
@@ -189,10 +203,11 @@ public class ApplicationDcContext extends DcContext {
int status = 0;
long expiresIn = 0;
long lastSeen = 0;
boolean verified = chat.isVerified();
return new ThreadRecord(context, body, null, recipient, date, count,
unreadCount, chatId, 0, status, type,
distributionType, archived, expiresIn, lastSeen, 0);
distributionType, archived, expiresIn, lastSeen, 0, verified);
}
@@ -400,6 +415,7 @@ public class ApplicationDcContext extends DcContext {
case DC_EVENT_GET_STRING:
String s;
switch( (int)data1 ) { // the integers are defined in the core and used only here, an enum or sth. like that won't have a big benefit
case 8: s = context.getString(R.string.menu_deaddrop); break;
case 13: s = context.getString(R.string.default_status_text); break;
case 42: s = context.getString(R.string.autocrypt__asm_subject); break;
case 43: s = context.getString(R.string.autocrypt__asm_general_body); break;
@@ -22,6 +22,7 @@ public class DcHelper {
public static final String CONFIG_SELF_STATUS = "selfstatus";
public static final String CONFIG_SELF_AVATAR = "selfavatar";
public static final String CONFIG_E2EE_ENABLED = "e2ee_enabled";
public static final String CONFIG_QR_OVERLAY_LOGO = "qr_overlay_logo";
public static ApplicationDcContext getContext(Context context) {
return ApplicationContext.getInstance(context).dcContext;
@@ -32,9 +33,18 @@ public class DcHelper {
return dcContext.isConfigured() == 1;
}
public static String get(Context context, String key) {
public static int getInt(Context context, String key, int defaultValue) {
DcContext dcContext = getContext(context);
return dcContext.getConfig(key, "");
return dcContext.getConfigInt(key, defaultValue);
}
public static String get(Context context, String key, String defaultValue) {
DcContext dcContext = getContext(context);
return dcContext.getConfig(key, defaultValue);
}
public static String get(Context context, String key) {
return get(context, key, "");
}
public static void set(Context context, String key, String value) {
@@ -78,7 +78,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
this.numberView.setTextColor(color);
this.contactPhotoImage.setAvatar(glideRequests, recipient, false);
setText(name, number, label);
setText(name, number, label, contact);
if (multiSelect) this.checkBox.setVisibility(View.VISIBLE);
else this.checkBox.setVisibility(View.GONE);
@@ -97,7 +97,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
contactPhotoImage.clear(glideRequests);
}
private void setText(String name, String number, String label) {
private void setText(String name, String number, String label, DcContact contact) {
this.nameView.setEnabled(true);
this.nameView.setText(name==null? "#" : name);
@@ -109,6 +109,11 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
else {
this.numberContainer.setVisibility(View.GONE);
}
if (contact != null && contact.isVerified()) {
nameView.setCompoundDrawablesWithIntrinsicBounds(0,0,R.drawable.ic_verified,0);
} else {
nameView.setCompoundDrawablesWithIntrinsicBounds(0,0, 0,0);
}
}
public int getSpecialId() {
@@ -1,112 +0,0 @@
package org.thoughtcrime.securesms.database;
import android.content.Context;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public abstract class FastCursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder, T>
extends CursorRecyclerViewAdapter<VH>
{
private static final String TAG = FastCursorRecyclerViewAdapter.class.getSimpleName();
private final LinkedList<T> fastRecords = new LinkedList<>();
private final List<Long> releasedRecordIds = new LinkedList<>();
protected FastCursorRecyclerViewAdapter(Context context, Cursor cursor) {
super(context, cursor);
}
public void addFastRecord(@NonNull T record) {
fastRecords.addFirst(record);
notifyDataSetChanged();
}
public void releaseFastRecord(long id) {
synchronized (releasedRecordIds) {
releasedRecordIds.add(id);
}
}
protected void cleanFastRecords() {
synchronized (releasedRecordIds) {
Iterator<Long> releaseIdIterator = releasedRecordIds.iterator();
while (releaseIdIterator.hasNext()) {
long releasedId = releaseIdIterator.next();
Iterator<T> fastRecordIterator = fastRecords.iterator();
while (fastRecordIterator.hasNext()) {
if (isRecordForId(fastRecordIterator.next(), releasedId)) {
fastRecordIterator.remove();
releaseIdIterator.remove();
break;
}
}
}
}
}
protected abstract T getRecordFromCursor(@NonNull Cursor cursor);
protected abstract void onBindItemViewHolder(VH viewHolder, @NonNull T record);
protected abstract long getItemId(@NonNull T record);
protected abstract int getItemViewType(@NonNull T record);
protected abstract boolean isRecordForId(@NonNull T record, long id);
@Override
public int getItemViewType(@NonNull Cursor cursor) {
T record = getRecordFromCursor(cursor);
return getItemViewType(record);
}
@Override
public void onBindItemViewHolder(VH viewHolder, @NonNull Cursor cursor) {
T record = getRecordFromCursor(cursor);
onBindItemViewHolder(viewHolder, record);
}
@Override
public void onBindFastAccessItemViewHolder(VH viewHolder, int position) {
int calculatedPosition = getCalculatedPosition(position);
onBindItemViewHolder(viewHolder, fastRecords.get(calculatedPosition));
}
@Override
protected int getFastAccessSize() {
return fastRecords.size();
}
protected T getRecordForPositionOrThrow(int position) {
if (isFastAccessPosition(position)) {
return fastRecords.get(getCalculatedPosition(position));
} else {
Cursor cursor = getCursorAtPositionOrThrow(position);
return getRecordFromCursor(cursor);
}
}
protected int getFastAccessItemViewType(int position) {
return getItemViewType(fastRecords.get(getCalculatedPosition(position)));
}
protected boolean isFastAccessPosition(int position) {
position = getCalculatedPosition(position);
return position >= 0 && position < fastRecords.size();
}
protected long getFastAccessItemId(int position) {
return getItemId(fastRecords.get(getCalculatedPosition(position)));
}
private int getCalculatedPosition(int position) {
return hasHeaderView() ? position - 1 : position;
}
}
@@ -44,7 +44,6 @@ import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DelimiterUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -689,7 +688,7 @@ public class ThreadDatabase extends Database {
return new ThreadRecord(context, body, snippetUri, recipient, date, count,
unreadCount, threadId, deliveryReceiptCount, status, type,
distributionType, archived, expiresIn, lastSeen, readReceiptCount);
distributionType, archived, expiresIn, lastSeen, readReceiptCount, false);
}
private @Nullable Uri getSnippetUri(Cursor cursor) {
@@ -48,12 +48,13 @@ public class ThreadRecord extends DisplayRecord {
private final boolean archived;
private final long expiresIn;
private final long lastSeen;
private final boolean verified;
public ThreadRecord(@NonNull Context context, @NonNull String body, @Nullable Uri snippetUri,
@NonNull Recipient recipient, long date, long count, int unreadCount,
long threadId, int deliveryReceiptCount, int status, long snippetType,
int distributionType, boolean archived, long expiresIn, long lastSeen,
int readReceiptCount)
int readReceiptCount, boolean verified)
{
super(context, body, recipient, date, date, threadId, status, deliveryReceiptCount, snippetType, readReceiptCount);
this.context = context.getApplicationContext();
@@ -64,6 +65,7 @@ public class ThreadRecord extends DisplayRecord {
this.archived = archived;
this.expiresIn = expiresIn;
this.lastSeen = lastSeen;
this.verified = verified;
}
public @Nullable Uri getSnippetUri() {
@@ -158,4 +160,8 @@ public class ThreadRecord extends DisplayRecord {
public long getLastSeen() {
return lastSeen;
}
public boolean isVerified() {
return verified;
}
}
@@ -27,6 +27,7 @@ import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.DcAttachment;
import org.thoughtcrime.securesms.attachments.UriAttachment;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.util.MediaUtil;
@@ -38,7 +39,7 @@ import java.io.File;
public class AudioSlide extends Slide {
public AudioSlide(Context context, DcMsg dcMsg) {
this(context, Uri.fromFile(new File(dcMsg.getFile())), dcMsg.getBytes(), dcMsg.getType()==DcMsg.DC_MSG_VOICE);
super(context, new DcAttachment(dcMsg));
dcMsgId = dcMsg.getId();
}
@@ -9,6 +9,7 @@ import android.support.annotation.Nullable;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.DcAttachment;
import org.thoughtcrime.securesms.util.StorageUtil;
import java.io.File;
@@ -20,7 +21,7 @@ public class DocumentSlide extends Slide {
}
public DocumentSlide(Context context, DcMsg dcMsg) {
this(context, Uri.fromFile(new File(dcMsg.getFile())), dcMsg.getFilemime(), dcMsg.getBytes(), dcMsg.getFilename());
this(context, new DcAttachment(dcMsg));
dcMsgId = dcMsg.getId();
}
@@ -4,11 +4,17 @@ import android.content.Context;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.util.MediaUtil;
public class GifSlide extends ImageSlide {
public GifSlide(Context context, DcMsg dcMsg) {
super(context, dcMsg);
}
public GifSlide(Context context, Attachment attachment) {
super(context, attachment);
}
@@ -23,8 +23,11 @@ import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.DcAttachment;
import org.thoughtcrime.securesms.util.MediaUtil;
public class ImageSlide extends Slide {
@@ -32,6 +35,10 @@ public class ImageSlide extends Slide {
@SuppressWarnings("unused")
private static final String TAG = ImageSlide.class.getSimpleName();
public ImageSlide(@NonNull Context context, @NonNull DcMsg dcMsg) {
super(context, new DcAttachment(dcMsg));
}
public ImageSlide(@NonNull Context context, @NonNull Attachment attachment) {
super(context, attachment);
}
@@ -4,10 +4,16 @@ package org.thoughtcrime.securesms.mms;
import android.content.Context;
import android.support.annotation.NonNull;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.attachments.Attachment;
public class MmsSlide extends ImageSlide {
public MmsSlide(@NonNull Context context, @NonNull DcMsg dcMsg) {
super(context, dcMsg);
}
public MmsSlide(@NonNull Context context, @NonNull Attachment attachment) {
super(context, attachment);
}
@@ -22,8 +22,11 @@ import android.net.Uri;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.DcAttachment;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.ResUtil;
@@ -33,6 +36,10 @@ public class VideoSlide extends Slide {
super(context, constructAttachmentFromUri(context, uri, MediaUtil.VIDEO_UNSPECIFIED, dataSize, 0, 0, MediaUtil.hasVideoThumbnail(uri), null, false, false));
}
public VideoSlide(Context context, DcMsg dcMsg) {
super(context, new DcAttachment(dcMsg));
}
public VideoSlide(Context context, Attachment attachment) {
super(context, attachment);
}
@@ -107,7 +107,6 @@ public class MessageNotifier {
sendInThreadNotification(context, recipient);
} else {
Intent intent = new Intent(context, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.setData((Uri.parse("custom://" + System.currentTimeMillis())));
@@ -69,7 +69,6 @@ public class NotificationItem {
public PendingIntent getPendingIntent(Context context) {
Intent intent = new Intent(context, ConversationActivity.class);
Recipient notifyRecipients = threadRecipient != null ? threadRecipient : conversationRecipient;
if (notifyRecipients != null) intent.putExtra(ConversationActivity.ADDRESS_EXTRA, notifyRecipients.getAddress());
intent.putExtra("thread_id", threadId);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
@@ -164,7 +164,6 @@ public class NotificationState {
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications! " + threads.size());
Intent intent = new Intent(context, ConversationPopupActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
@@ -1,50 +1,18 @@
package org.thoughtcrime.securesms.preferences;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import static android.app.Activity.RESULT_OK;
public class AppearancePreferenceFragment extends ListSummaryPreferenceFragment {
@@ -74,6 +42,15 @@ public class AppearancePreferenceFragment extends ListSummaryPreferenceFragment
public void onResume() {
super.onResume();
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__appearance);
String imagePath = TextSecurePreferences.getBackgroundImagePath(getContext());
String backgroundString;
if(imagePath.isEmpty()){
backgroundString = this.getString(R.string.AppearancePreferencesFragment_background_default_summary);
}
else{
backgroundString = this.getString(R.string.AppearancePreferencesFragment_background_custom_summary);
}
this.findPreference(TextSecurePreferences.BACKGROUND_PREF).setSummary(backgroundString);
}
@Override
@@ -82,51 +59,6 @@ public class AppearancePreferenceFragment extends ListSummaryPreferenceFragment
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener((ApplicationPreferencesActivity) getActivity());
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (data != null && getContext() != null && resultCode == RESULT_OK && requestCode == ApplicationPreferencesActivity.REQUEST_CODE_SET_BACKGROUND) {
Uri imageUri = data.getData();
if (imageUri != null) {
Thread thread = new Thread(){
@Override
public void run() {
try {
Display display = ServiceUtil.getWindowManager(getContext()).getDefaultDisplay();
Point size = new Point();
display.getSize(size);
Bitmap scaledBitmap = GlideApp.with(getContext())
.asBitmap()
.load(imageUri)
.centerCrop()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.submit(size.x, size.y)
.get();
String destination = getContext().getFilesDir().getAbsolutePath() + "background";
FileOutputStream outStream = new FileOutputStream(destination);
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 85, outStream);
} catch (InterruptedException e) {
e.printStackTrace();
showBackgroundSaveError();
} catch (ExecutionException e) {
e.printStackTrace();
showBackgroundSaveError();
} catch (FileNotFoundException e) {
e.printStackTrace();
showBackgroundSaveError();
}
}
};
thread.start();
}
}
}
private void showBackgroundSaveError() {
Toast.makeText(getActivity(), R.string.AppearancePreferencesFragment_background_save_error, Toast.LENGTH_LONG).show();
}
public static CharSequence getSummary(Context context) {
String[] languageEntries = context.getResources().getStringArray(R.array.language_entries);
String[] languageEntryValues = context.getResources().getStringArray(R.array.language_values);
@@ -139,19 +71,25 @@ public class AppearancePreferenceFragment extends ListSummaryPreferenceFragment
if (langIndex == -1) langIndex = 0;
if (themeIndex == -1) themeIndex = 0;
return context.getString(R.string.ApplicationPreferencesActivity_appearance_summary,
String imagePath = TextSecurePreferences.getBackgroundImagePath(context);
String backgroundString;
if(imagePath.isEmpty()){
backgroundString = context.getString(R.string.ApplicationPreferencesActivity_appearance_background_default);
}
else{
backgroundString = context.getString(R.string.ApplicationPreferencesActivity_appearance_background_custom);
}
return context.getString(R.string.ApplicationPreferencesActivity_appearance_summary_new,
themeEntries[themeIndex],
languageEntries[langIndex]);
languageEntries[langIndex], backgroundString);
}
private class BackgroundClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
getActivity().startActivityForResult(intent, ApplicationPreferencesActivity.REQUEST_CODE_SET_BACKGROUND);
Intent intent = new Intent(getContext(), ChatBackgroundActivity.class);
getActivity().startActivity(intent);
return true;
}
}

Some files were not shown because too many files have changed in this diff Show More