Compare commits

..

41 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
61 changed files with 523 additions and 914 deletions
+2 -2
View File
@@ -255,8 +255,8 @@ android {
}
defaultConfig {
versionCode 394
versionName "0.0.4"
versionCode 397
versionName "0.0.7"
applicationId "chat.delta.androidii"
minSdkVersion 14
+6
View File
@@ -726,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);
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: 634 B

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"/>
-7
View File
@@ -69,13 +69,6 @@
android:text="@string/conversation_activity__enable_signal_messages"
android:visibility="gone"/>
<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/make_default_sms_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+15 -18
View File
@@ -36,7 +36,7 @@
android:weightSum="1"
android:orientation="horizontal">
<android.support.constraint.ConstraintLayout
<RelativeLayout
android:id="@+id/from"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -49,39 +49,36 @@
<org.thoughtcrime.securesms.components.FromTextView
android:id="@+id/from_text"
style="@style/Signal.Text.Body"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="2dp"
android:layout_toLeftOf="@id/verified_indicator"
android:layout_toStartOf="@id/verified_indicator"
android:drawablePadding="5dp"
android:ellipsize="end"
android:fontFamily="sans-serif-medium"
android:maxLines="1"
android:textColor="?attr/conversation_list_item_contact_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/verified_indicator"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="0.9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
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:layout_gravity="center"
android:paddingLeft="5dp"
android:paddingStart="5dp"
android:src="@drawable/ic_verified"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="0.1"
app:layout_constraintStart_toEndOf="@id/from_text"
app:layout_constraintTop_toTopOf="parent" />
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" />
</android.support.constraint.ConstraintLayout>
</RelativeLayout>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/subject"
+18 -19
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,33 +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"
app:layout_constraintEnd_toStartOf="@id/verified_indicator"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="0.9"
app:layout_constraintStart_toStartOf="parent"
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="gone"
android:layout_marginLeft="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="0.1"
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"
@@ -87,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>
+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>
+3 -6
View File
@@ -13,16 +13,13 @@
<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"/>
+17 -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">
@@ -166,6 +172,7 @@
<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">
@@ -226,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>
@@ -1518,5 +1525,12 @@
<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>
+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())); }
@@ -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);
@@ -56,7 +56,7 @@ 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;
@@ -64,14 +64,17 @@ 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;
@@ -110,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;
@@ -120,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;
@@ -133,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;
@@ -156,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;
@@ -177,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,
@@ -186,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";
@@ -215,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;
@@ -235,11 +234,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
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;
@@ -348,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
@@ -393,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();
@@ -441,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:
@@ -453,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:
@@ -494,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;
@@ -547,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;
@@ -598,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);
@@ -663,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() {
@@ -766,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());
@@ -853,7 +671,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
calculateCharactersRemaining();
supportInvalidateOptionsMenu();
setBlockedUserState(recipient, isSecureText, isDefaultSms);
}
///// Initializers
@@ -992,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);
@@ -1029,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);
@@ -1063,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);
@@ -1079,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() {
@@ -1219,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
@@ -1228,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(),
@@ -1252,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);
@@ -1419,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;
}
@@ -1831,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();
}
}
}
@@ -408,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
}
}
@@ -55,6 +55,7 @@ import android.widget.EditText;
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;
@@ -68,7 +69,9 @@ 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.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;
@@ -166,7 +169,10 @@ public class ConversationFragment extends Fragment
}
private void setNoMessageText() {
if(getListAdapter().isGroupChat()){
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();
@@ -225,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;
@@ -557,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);
@@ -770,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);
}
@@ -30,10 +30,13 @@ 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.database.Address;
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.qr.QrScanHandler;
@@ -158,13 +161,12 @@ 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_qr_scan: handleQrScan(); return true;
case R.id.menu_qr_show: handleQrShow(); 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;
@@ -180,18 +182,15 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
}
@Override
public void onCreateConversation(long threadId, Recipient recipient, int distributionType, long lastSeen) {
openConversation(threadId, recipient, distributionType, lastSeen, -1);
public void onCreateConversation(long threadId, long lastSeen) {
openConversation(threadId, lastSeen, -1);
}
public void openConversation(long threadId, Recipient recipient, int distributionType, long lastSeen, int startingPosition) {
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);
@@ -216,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);
@@ -227,18 +232,6 @@ 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) {
@@ -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);
}
});
}
}
}
@@ -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;
@@ -47,7 +49,6 @@ 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.ThreadDatabase;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DynamicLanguage;
@@ -59,10 +60,14 @@ import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.File;
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
*
@@ -93,7 +98,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
private TextView creatingText;
private Bitmap avatarBmp;
private CircularProgressButton verifyButton;
private boolean editGroup;
private Integer editGroupChatId = null;
@Override
protected void onPreCreate() {
@@ -127,7 +132,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
groupName.setEnabled(true);
String title;
if(editGroup) {
if(isEdit()) {
title = getString(R.string.GroupCreateActivity_actionbar_edit_title);
}
else if(createVerified) {
@@ -173,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();
@@ -206,11 +209,10 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
private void initializeExistingGroup() {
editGroup = true;
final Address groupAddress = getIntent().getParcelableExtra(GROUP_ADDRESS_EXTRA);
if (groupAddress != null) {
int chatId = groupAddress.getDcChatId();
new FillExistingGroupInfoAsyncTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, chatId);
editGroupChatId = groupAddress.getDcChatId();
new FillExistingGroupInfoAsyncTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, editGroupChatId);
}
}
@@ -232,7 +234,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
finish();
return true;
case R.id.menu_create_group:
if (editGroup) handleGroupUpdate();
if (isEdit()) handleGroupUpdate();
else handleGroupCreate();
return true;
}
@@ -248,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();
}
@@ -351,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 (editGroup) {
if (isEdit()) {
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_PUSH);
} else {
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_PUSH | DisplayMode.FLAG_SMS);
@@ -383,8 +436,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
@Override
protected Recipient doInBackground(Integer... recipientIds) {
Integer recipientsId = recipientIds[0];
Recipient recipient = activity.dcContext.getRecipient(ApplicationDcContext.RECIPIENT_TYPE_CHAT, recipientsId);
return recipient;
return activity.dcContext.getRecipient(ApplicationDcContext.RECIPIENT_TYPE_CHAT, recipientsId);
}
@Override
@@ -397,6 +449,17 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
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);
}
}
if (ownAddress != null) {
participants.remove(ownAddress);
}
groupName.setText(recipient.getName());
SelectedRecipientsAdapter adapter = new SelectedRecipientsAdapter(this, participants);
adapter.setOnRecipientDeletedListener(this);
@@ -415,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();
}
@@ -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
@@ -415,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;
@@ -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;
}
}
@@ -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())));
@@ -6,6 +6,7 @@ import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R;
@@ -41,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
@@ -61,9 +71,18 @@ 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 {
@@ -86,8 +86,8 @@ public class ChatBackgroundActivity extends BaseActionBarActivity {
@Override
public void run() {
String destination = context.getFilesDir().getAbsolutePath() + "/background";
scaleAndSaveImage(context, destination);
TextSecurePreferences.setBackgroundImagePath(context, destination);
scaleAndSaveImage(context, destination);
}
};
thread.start();
@@ -123,12 +123,15 @@ public class ChatBackgroundActivity extends BaseActionBarActivity {
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();
}
}
@@ -184,7 +184,6 @@ public class QrScanHandler implements DcEventCenter.DcEventDelegate {
dcContext.endCaptureNextError();
if (newChatId != 0) {
Intent intent = new Intent(activity, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, Address.fromChat(newChatId));
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)newChatId);
activity.startActivity(intent);
} else if (!errorString.isEmpty()) {
@@ -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);