Compare commits

...

67 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
96 changed files with 1851 additions and 1312 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 393
versionName "0.0.2"
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: 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>
-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"
+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 -14
View File
@@ -36,11 +36,10 @@
android:weightSum="1"
android:orientation="horizontal">
<LinearLayout
<RelativeLayout
android:id="@+id/from"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
@@ -49,28 +48,37 @@
<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"
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_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="2dp"
android:drawablePadding="5dp"/>
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:src="@drawable/ic_verified"
android:id="@+id/verified_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="5dp"
android:paddingStart="5dp"
android:visibility="gone"/>
android:src="@drawable/ic_verified"
android:visibility="gone"
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" />
</LinearLayout>
</RelativeLayout>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/subject"
+20 -13
View File
@@ -39,9 +39,9 @@
tools:src="@drawable/ic_contact_picture"
android:contentDescription="@string/conversation_list_item_view__contact_photo_image"/>
<android.support.constraint.ConstraintLayout
<RelativeLayout
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/contact_photo_image"
@@ -50,25 +50,32 @@
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/title"
style="@style/TextSecure.TitleTextStyle"
android:layout_width="0dp"
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" />
android:transitionName="recipient_name"
tools:text="Jules Bonnot" />
<ImageView
android:id="@+id/verified_indicator"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_verified"
android:visibility="visible"
android:layout_marginLeft="5dp"
app:layout_constraintBottom_toBottomOf="@id/title"
app:layout_constraintStart_toEndOf="@id/title"
app:layout_constraintTop_toTopOf="@id/title"
android:layout_marginStart="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"
@@ -79,9 +86,9 @@
android:maxLines="1"
android:textDirection="ltr"
android:textSize="13dp"
app:layout_constraintTop_toBottomOf="@id/title"
android:layout_below="@id/title"
tools:text="(123) 123-1234" />
</android.support.constraint.ConstraintLayout>
</RelativeLayout>
</org.thoughtcrime.securesms.ConversationTitleView>
+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 -57
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,44 +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:gravity="top|left"
android:maxLines="3"
android:inputType="textMultiLine" />
</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"
@@ -80,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>
@@ -100,14 +97,18 @@
android:clipChildren="false"
android:clipToPadding="false">
<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"
@@ -120,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>
+1 -1
View File
@@ -5,5 +5,5 @@
android:id="@+id/menu_create_profile"
android:title="@string/profile_create_activity__finish"
app:showAsAction="always"
android:icon="@drawable/check"/>
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
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"/>
+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())); }
-2
View File
@@ -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);
@@ -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;
@@ -345,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
@@ -390,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();
@@ -438,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:
@@ -450,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:
@@ -491,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;
@@ -544,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;
@@ -595,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);
@@ -660,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() {
@@ -763,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());
@@ -850,7 +671,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
calculateCharactersRemaining();
supportInvalidateOptionsMenu();
setBlockedUserState(recipient, isSecureText, isDefaultSms);
}
///// Initializers
@@ -989,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);
@@ -997,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);
@@ -1025,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);
@@ -1042,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() {
@@ -1055,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);
@@ -1071,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() {
@@ -1211,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
@@ -1220,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(),
@@ -1244,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);
@@ -1411,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;
}
@@ -1823,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);
}
@@ -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,6 +39,8 @@ 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;
@@ -45,14 +48,13 @@ 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;
@@ -61,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();
@@ -74,6 +75,7 @@ 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;
@@ -118,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,
@@ -139,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 {
@@ -188,8 +192,6 @@ 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("");
@@ -212,8 +214,6 @@ 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));
@@ -229,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) {
@@ -244,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() {
@@ -305,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())));
// }
}
}
@@ -365,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);
}
});
}
}
}
@@ -94,7 +94,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
private InputAwareLayout container;
private ImageView avatar;
private EditText name;
private EmojiToggle emojiToggle;
private EmojiDrawer emojiDrawer;
private TextInputEditText statusView;
private View reveal;
@@ -240,8 +239,7 @@ 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.reveal = ViewUtil.findById(this, R.id.reveal);
@@ -356,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
@@ -382,7 +371,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
}
});
this.container.addOnKeyboardShownListener(() -> emojiToggle.setToEmoji());
this.name.setOnClickListener(v -> container.showSoftkey(name));
}
@@ -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()));
}
}
@@ -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) {}
@@ -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) {
@@ -22,6 +22,7 @@ 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;
@@ -51,11 +52,19 @@ 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) {
@@ -148,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
@@ -394,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) {
@@ -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;
}
}
@@ -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;
}
}
@@ -0,0 +1,194 @@
package org.thoughtcrime.securesms.preferences;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.view.Display;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.BaseActionBarActivity;
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.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.concurrent.ExecutionException;
public class ChatBackgroundActivity extends BaseActionBarActivity {
Button galleryButton;
Button defaultButton;
MenuItem acceptMenuItem;
ImageView preview;
String tempDestinationPath;
Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_chat_background);
defaultButton = findViewById(R.id.set_default_button);
galleryButton = findViewById(R.id.from_gallery_button);
preview = findViewById(R.id.preview);
defaultButton.setOnClickListener(new DefaultClickListener());
galleryButton.setOnClickListener(new GalleryClickListener());
String backgroundImagePath = TextSecurePreferences.getBackgroundImagePath(this);
setLayoutBackgroundImage(backgroundImagePath);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
}
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuInflater inflater = this.getMenuInflater();
menu.clear();
inflater.inflate(R.menu.group_create, menu);
acceptMenuItem = menu.findItem(R.id.menu_create_group);
acceptMenuItem.setEnabled(false);
super.onPrepareOptionsMenu(menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.menu_create_group) {
// handle confirmation button click here
Context context = getApplicationContext();
if(imageUri != null){
Thread thread = new Thread(){
@Override
public void run() {
String destination = context.getFilesDir().getAbsolutePath() + "/background";
TextSecurePreferences.setBackgroundImagePath(context, destination);
scaleAndSaveImage(context, destination);
}
};
thread.start();
}
else {
TextSecurePreferences.setBackgroundImagePath(context, "");
}
finish();
return true;
} else if (id == android.R.id.home) {
// handle close button click here
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
private void scaleAndSaveImage(Context context, String destinationPath) {
try{
Display display = ServiceUtil.getWindowManager(context).getDefaultDisplay();
Point size = new Point();
display.getSize(size);
Bitmap scaledBitmap = GlideApp.with(context)
.asBitmap()
.load(imageUri)
.centerCrop()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.submit(size.x, size.y)
.get();
FileOutputStream outStream = new FileOutputStream(destinationPath);
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 85, outStream);
} catch (InterruptedException e) {
e.printStackTrace();
TextSecurePreferences.setBackgroundImagePath(context, "");
showBackgroundSaveError();
} catch (ExecutionException e) {
e.printStackTrace();
TextSecurePreferences.setBackgroundImagePath(context, "");
showBackgroundSaveError();
} catch (FileNotFoundException e) {
e.printStackTrace();
TextSecurePreferences.setBackgroundImagePath(context, "");
showBackgroundSaveError();
}
}
private void setLayoutBackgroundImage(String backgroundImagePath) {
Drawable image = Drawable.createFromPath(backgroundImagePath);
preview.setImageDrawable(image);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
final Context context = getApplicationContext();
if (data != null && context != null && resultCode == RESULT_OK && requestCode == ApplicationPreferencesActivity.REQUEST_CODE_SET_BACKGROUND) {
imageUri = data.getData();
if (imageUri != null) {
acceptMenuItem.setEnabled(true);
Thread thread = new Thread(){
@Override
public void run() {
tempDestinationPath = context.getFilesDir().getAbsolutePath() + "/background-temp";
scaleAndSaveImage(context, tempDestinationPath);
runOnUiThread(() -> {
// Stuff that updates the UI
setLayoutBackgroundImage(tempDestinationPath);
});
}
};
thread.start();
}
}
}
private void showBackgroundSaveError() {
Toast.makeText(this, R.string.AppearancePreferencesFragment_background_save_error, Toast.LENGTH_LONG).show();
}
private void enableMenuItem() {
acceptMenuItem.setEnabled(true);
}
private class DefaultClickListener implements View.OnClickListener {
@Override
public void onClick(View view) {
imageUri = null;
tempDestinationPath = "";
setLayoutBackgroundImage("");
enableMenuItem();
}
}
private class GalleryClickListener implements View.OnClickListener {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, ApplicationPreferencesActivity.REQUEST_CODE_SET_BACKGROUND);
}
}
}
@@ -0,0 +1,220 @@
package org.thoughtcrime.securesms.qr;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.StringRes;
import android.text.Html;
import android.widget.Toast;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
import com.b44t.messenger.DcLot;
import com.google.zxing.integration.android.IntentResult;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.util.IntentUtils;
import org.thoughtcrime.securesms.util.Util;
public class QrScanHandler implements DcEventCenter.DcEventDelegate {
private Activity activity;
ProgressDialog progressDialog;
private ApplicationDcContext dcContext;
public QrScanHandler(Activity activity) {
this.activity = activity;
dcContext = DcHelper.getContext(activity);
}
public void onScanPerformed(IntentResult scanResult) {
if (scanResult == null || scanResult.getFormatName() == null) {
return; // Should not happen!
}
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final String qrRawString = scanResult.getContents();
final DcLot qrParsed = dcContext.checkQr(qrRawString);
String nameAndAddress = dcContext.getContact(qrParsed.getId()).getNameNAddr();
switch (qrParsed.getState()) {
case DcContext.DC_QR_ASK_VERIFYCONTACT:
case DcContext.DC_QR_ASK_VERIFYGROUP:
showVerifyContactOrGroup(activity, builder, qrRawString, qrParsed, nameAndAddress);
break;
case DcContext.DC_QR_FPR_WITHOUT_ADDR:
showVerifyFingerprintWithoutAddress(builder, qrParsed);
break;
case DcContext.DC_QR_FPR_MISMATCH:
showFingerPrintError(builder, nameAndAddress);
break;
case DcContext.DC_QR_FPR_OK:
case DcContext.DC_QR_ADDR:
showFingerprintOrQrSuccess(builder, qrParsed, nameAndAddress);
break;
case DcContext.DC_QR_URL:
showQrUrl(builder, qrParsed);
break;
default:
handleDefault(builder, qrRawString, qrParsed);
break;
}
builder.create().show();
}
private void handleDefault(AlertDialog.Builder builder, String qrRawString, DcLot qrParsed) {
String msg;
final String scannedText;
switch (qrParsed.getState()) {
case DcContext.DC_QR_ERROR:
scannedText = qrRawString;
msg = qrParsed.getText1() + "<br><br><c#808080>" + String.format(activity.getString(R.string.qr_scan_handler_Scan_contains_text), scannedText) + "</c>";
break;
case DcContext.DC_QR_TEXT:
scannedText = qrParsed.getText1();
msg = String.format(activity.getString(R.string.qr_scan_handler_Scan_contains_text), scannedText);
break;
default:
scannedText = qrRawString;
msg = String.format(activity.getString(R.string.qr_scan_handler_Scan_contains_text), scannedText);
break;
}
builder.setMessage(Html.fromHtml(msg));
builder.setPositiveButton(android.R.string.ok, null);
builder.setNeutralButton(R.string.copy_to_clipboard, (dialog, which) -> {
Util.writeTextToClipboard(activity, scannedText);
showDoneToast(activity);
});
}
private void showQrUrl(AlertDialog.Builder builder, DcLot qrParsed) {
final String url = qrParsed.getText1();
String msg = String.format(activity.getString(R.string.qr_scan_handler_qr_scan_contains_url), url);
builder.setMessage(msg);
builder.setPositiveButton(R.string.open, (dialog, which) -> IntentUtils.showBrowserIntent(activity, url));
builder.setNegativeButton(android.R.string.cancel, null);
builder.setNeutralButton(R.string.copy_to_clipboard, (dialog, which) -> {
Util.writeTextToClipboard(activity, url);
showDoneToast(activity);
});
}
private void showDoneToast(Activity activity) {
Toast.makeText(activity, activity.getString(R.string.done), Toast.LENGTH_SHORT).show();
}
private void showFingerprintOrQrSuccess(AlertDialog.Builder builder, DcLot qrParsed, String nameAndAddress) {
@StringRes int resId = qrParsed.getState() == DcContext.DC_QR_ADDR ? R.string.qr_scan_handler_ask_start_chat_with : R.string.qr_scan_handler_fingerprint_ok;
builder.setMessage(Html.fromHtml(String.format(activity.getString(resId, nameAndAddress))));
builder.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
Bundle bundle = new Bundle();
bundle.putInt(ConversationActivity.THREAD_ID_EXTRA, dcContext.createChatByContactId(qrParsed.getId()));
Intent intent = new Intent(activity, ConversationActivity.class);
//TODO how to we get the contact ID here? We need it to avoid crashing when starting the ConversationActivity
activity.startActivity(intent, bundle);
});
builder.setNegativeButton(android.R.string.cancel, null);
}
private void showFingerPrintError(AlertDialog.Builder builder, String nameAndAddress) {
builder.setMessage(Html.fromHtml(String.format(activity.getString(R.string.qr_scan_handler_fingerprint_mismatch), nameAndAddress)));
builder.setPositiveButton(android.R.string.ok, null);
}
private void showVerifyFingerprintWithoutAddress(AlertDialog.Builder builder, DcLot qrParsed) {
builder.setMessage(Html.fromHtml(activity.getString(R.string.qr_scan_handler_fingerprint_without_address) + "<br><br><c#808080>" + activity.getString(R.string.qr_scan_handler_fingerprint) + ":<br>" + qrParsed.getText1() + "</c>"));
builder.setPositiveButton(android.R.string.ok, null);
builder.setNeutralButton(R.string.copy_to_clipboard, (dialog, which) -> {
Util.writeTextToClipboard(activity, qrParsed.getText1());
showDoneToast(activity);
});
}
private void showVerifyContactOrGroup(Activity activity, AlertDialog.Builder builder, String qrRawString, DcLot qrParsed, String nameNAddr) {
if (progressDialog != null) {
progressDialog.dismiss();
progressDialog = null;
}
String msg;
switch (qrParsed.getState()) {
case DcContext.DC_QR_ASK_VERIFYGROUP:
msg = String.format(activity.getString(R.string.qr_scan_handler_join_verified_group), qrParsed.getText1());
break;
default:
msg = String.format(activity.getString(R.string.qr_scan_handler_fingerprint_ask_oob), nameNAddr);
break;
}
builder.setMessage(Html.fromHtml(msg));
builder.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage(activity.getString(R.string.one_moment));
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setCancelable(false);
progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, activity.getString(android.R.string.cancel), (dialog, which) -> dcContext.stopOngoingProcess());
progressDialog.show();
dcContext.captureNextError();
new Thread(() -> {
dcContext.eventCenter.addObserver(this, DcContext.DC_EVENT_SECUREJOIN_JOINER_PROGRESS);
int newChatId = dcContext.joinSecurejoin(qrRawString); // joinSecurejoin() runs until all needed messages are sent+received!
dcContext.eventCenter.removeObservers(this);
Util.runOnMain(() -> {
if (progressDialog != null) {
progressDialog.dismiss();
progressDialog = null;
}
String errorString = dcContext.getCapturedError();
dcContext.endCaptureNextError();
if (newChatId != 0) {
Intent intent = new Intent(activity, ConversationActivity.class);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)newChatId);
activity.startActivity(intent);
} else if (!errorString.isEmpty()) {
AlertDialog.Builder builder1 = new AlertDialog.Builder(activity);
builder1.setMessage(errorString);
builder1.setPositiveButton(android.R.string.ok, null);
builder1.create().show();
}
});
}
).start();
});
builder.setNegativeButton(android.R.string.cancel, null);
}
@Override
public void handleEvent(int eventId, Object data1, Object data2) {
if (eventId == DcContext.DC_EVENT_SECUREJOIN_JOINER_PROGRESS) {
long contact_id = (Long)data1;
long progress = (Long)data2;
String msg = null;
if( progress == 400) {
msg = activity.getString(R.string.qr_scan_handler_verfied_introduce_myself, dcContext.getContact((int)contact_id).getNameNAddr());
}
if( progressDialog != null && msg != null ) {
progressDialog.setMessage(msg);
}
}
}
}
@@ -137,8 +137,6 @@ public class SearchFragment extends Fragment implements SearchListAdapter.EventL
if (conversationList != null) {
conversationList.onCreateConversation(threadRecord.getThreadId(),
threadRecord.getRecipient(),
threadRecord.getDistributionType(),
threadRecord.getLastSeen());
}
}
@@ -146,12 +144,10 @@ public class SearchFragment extends Fragment implements SearchListAdapter.EventL
@Override
public void onContactClicked(@NonNull Recipient contact) {
Intent intent = new Intent(getContext(), ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, contact.getAddress());
long existingThread = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdIfExistsFor(contact);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, existingThread);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
startActivity(intent);
}
@@ -172,8 +168,6 @@ public class SearchFragment extends Fragment implements SearchListAdapter.EventL
ConversationListActivity conversationList = (ConversationListActivity) getActivity();
if (conversationList != null) {
conversationList.openConversation(message.threadId,
message.recipient,
ThreadDatabase.DistributionTypes.DEFAULT,
-1,
startingPosition);
}
@@ -57,7 +57,7 @@ class SearchListAdapter extends RecyclerView.Adapter<SearchListAdapter.Search
ThreadRecord conversationResult = getConversationResult(position);
if (conversationResult != null) {
holder.bind(conversationResult, new DcLot(0), glideRequests, eventListener, locale, searchResult.getQuery());
holder.bind(conversationResult, 0, new DcLot(0), glideRequests, eventListener, locale, searchResult.getQuery());
return;
}
@@ -160,13 +160,14 @@ class SearchListAdapter extends RecyclerView.Adapter<SearchListAdapter.Search
}
void bind(@NonNull ThreadRecord conversationResult,
int msgId,
@NonNull DcLot summary,
@NonNull GlideRequests glideRequests,
@NonNull EventListener eventListener,
@NonNull Locale locale,
@Nullable String query)
{
root.bind(conversationResult, summary, glideRequests, locale, Collections.emptySet(), false, query);
root.bind(conversationResult, msgId, summary, glideRequests, locale, Collections.emptySet(), false, query);
root.setOnClickListener(view -> eventListener.onConversationClicked(conversationResult));
}
@@ -56,9 +56,7 @@ public class CommunicationActions {
@Override
protected void onPostExecute(Long threadId) {
Intent intent = new Intent(context, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis());
if (!TextUtils.isEmpty(text)) {
intent.putExtra(ConversationActivity.TEXT_EXTRA, text);
@@ -4,6 +4,7 @@ package org.thoughtcrime.securesms.util;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.support.annotation.NonNull;
import java.util.List;
@@ -15,4 +16,9 @@ public class IntentUtils {
return resolveInfoList != null && resolveInfoList.size() > 1;
}
public static void showBrowserIntent(Context context, String url) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
context.startActivity(browserIntent);
}
}
@@ -13,6 +13,7 @@ import android.util.Log;
import android.util.Pair;
import android.webkit.MimeTypeMap;
import com.b44t.messenger.DcMsg;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.gif.GifDrawable;
@@ -47,6 +48,25 @@ public class MediaUtil {
public static final String VCARD = "text/x-vcard";
public static Slide getSlideForMsg(Context context, DcMsg dcMsg) {
Slide slide = null;
if (isGif(dcMsg.getFilemime())) {
slide = new GifSlide(context, dcMsg);
} else if (isImageType(dcMsg.getFilemime())) {
slide = new ImageSlide(context, dcMsg);
} else if (isVideoType(dcMsg.getFilemime())) {
slide = new VideoSlide(context, dcMsg);
} else if (isAudioType(dcMsg.getFilemime())) {
slide = new AudioSlide(context, dcMsg);
} else if (isMms(dcMsg.getFilemime())) {
slide = new MmsSlide(context, dcMsg);
} else if (dcMsg.getFilemime() != null) {
slide = new DocumentSlide(context, dcMsg);
}
return slide;
}
public static Slide getSlideForAttachment(Context context, Attachment attachment) {
Slide slide = null;
if (isGif(attachment.getContentType())) {
@@ -127,7 +127,7 @@ public class SelectedRecipientsAdapter extends BaseAdapter {
private static List<RecipientWrapper> wrapExistingMembers(Collection<Recipient> recipients) {
final LinkedList<RecipientWrapper> wrapperList = new LinkedList<>();
for (Recipient recipient : recipients) {
wrapperList.add(new RecipientWrapper(recipient, false, true));
wrapperList.add(new RecipientWrapper(recipient, true, true));
}
return wrapperList;
}
-2
View File
@@ -35,9 +35,7 @@ rm -r jni/messenger-backend/.??*
cd ..
ln --symbolic `pwd`/deltachat-core/src deltachat-android-ii/jni/messenger-backend/src
ln --symbolic `pwd`/deltachat-core/libs deltachat-android-ii/jni/messenger-backend/libs
ln --symbolic `pwd`/deltachat-core/cmdline deltachat-android-ii/jni/messenger-backend/cmdline
cd deltachat-android-ii
ndk-build
# back to tools directory
cd tools