mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-01 12:47:43 +00:00
Updated reply-to UI.
All UI components are now properly styled and functioning according to spec.
This commit is contained in:
parent
d567534609
commit
fa99e8f0d0
@ -75,7 +75,7 @@ dependencies {
|
|||||||
compile('org.whispersystems:libpastelog:1.1.2') {
|
compile('org.whispersystems:libpastelog:1.1.2') {
|
||||||
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
|
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
|
||||||
}
|
}
|
||||||
compile 'org.whispersystems:signal-service-android:2.7.3'
|
compile 'org.whispersystems:signal-service-android:2.7.5'
|
||||||
compile 'org.whispersystems:webrtc-android:M64'
|
compile 'org.whispersystems:webrtc-android:M64'
|
||||||
|
|
||||||
compile "me.leolin:ShortcutBadger:1.1.16"
|
compile "me.leolin:ShortcutBadger:1.1.16"
|
||||||
@ -164,7 +164,7 @@ dependencyVerification {
|
|||||||
'com.google.android.exoplayer:exoplayer:955085aa611a8f7cf6c61b88ae03d1a392f4ad94c9bfbc153f3dedb9ffb14718',
|
'com.google.android.exoplayer:exoplayer:955085aa611a8f7cf6c61b88ae03d1a392f4ad94c9bfbc153f3dedb9ffb14718',
|
||||||
'org.whispersystems:jobmanager:506f679fc2fcf7bb6d10f00f41d6f6ea0abf75c70dc95b913398661ad538a181',
|
'org.whispersystems:jobmanager:506f679fc2fcf7bb6d10f00f41d6f6ea0abf75c70dc95b913398661ad538a181',
|
||||||
'org.whispersystems:libpastelog:fe56b4db9ec743c8b565e3e4caa9228fafe132dc0bf82000d6e359b97a81177c',
|
'org.whispersystems:libpastelog:fe56b4db9ec743c8b565e3e4caa9228fafe132dc0bf82000d6e359b97a81177c',
|
||||||
'org.whispersystems:signal-service-android:dd0c21b37b239ac9c3eaf0b290791a3708817daa13e82e24b0544631f948d8d3',
|
'org.whispersystems:signal-service-android:e0a3d55b21c1db483818ed459c500eba96dfb839e70d95dca4d8d4c1a7cd816b',
|
||||||
'org.whispersystems:webrtc-android:ed297e8b795dad9658cf306c2aa0f7d296c65f0997a2ac4353fd0157910acc12',
|
'org.whispersystems:webrtc-android:ed297e8b795dad9658cf306c2aa0f7d296c65f0997a2ac4353fd0157910acc12',
|
||||||
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
||||||
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
||||||
@ -203,7 +203,7 @@ dependencyVerification {
|
|||||||
'com.github.bumptech.glide:gifdecoder:59ccf3bb0cec11dab4b857382cbe0b171111b6fc62bf141adce4e1180889af15',
|
'com.github.bumptech.glide:gifdecoder:59ccf3bb0cec11dab4b857382cbe0b171111b6fc62bf141adce4e1180889af15',
|
||||||
'com.android.support:support-annotations:af05330d997eb92a066534dbe0a3ea24347d26d7001221092113ae02a8f233da',
|
'com.android.support:support-annotations:af05330d997eb92a066534dbe0a3ea24347d26d7001221092113ae02a8f233da',
|
||||||
'org.whispersystems:signal-protocol-android:5b8acded7f2a40178eb90ab8e8cbfec89d170d91b3ff5e78487d1098df6185a1',
|
'org.whispersystems:signal-protocol-android:5b8acded7f2a40178eb90ab8e8cbfec89d170d91b3ff5e78487d1098df6185a1',
|
||||||
'org.whispersystems:signal-service-java:6654e52469b77db5c720de9557abe41bf99a9034c170c8a09e00bd2487c86430',
|
'org.whispersystems:signal-service-java:7b4c34e3a346a236caebd5b81fb2985ed3c91a9974a8a8ddd36b6e1b8ae9350a',
|
||||||
'com.github.bumptech.glide:disklrucache:c1b1b6f5bbd01e2fcdc9d7f60913c8d338bdb65ed4a93bfa02b56f19daaade4b',
|
'com.github.bumptech.glide:disklrucache:c1b1b6f5bbd01e2fcdc9d7f60913c8d338bdb65ed4a93bfa02b56f19daaade4b',
|
||||||
'com.github.bumptech.glide:annotations:bede99ef9f71517a4274bac18fd3e483e9f2b6108d7d6fe8f4949be4aa4d9512',
|
'com.github.bumptech.glide:annotations:bede99ef9f71517a4274bac18fd3e483e9f2b6108d7d6fe8f4949be4aa4d9512',
|
||||||
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
||||||
|
BIN
res/drawable-hdpi/ic_play_arrow_white_24dp.png
Normal file
BIN
res/drawable-hdpi/ic_play_arrow_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 195 B |
BIN
res/drawable-mdpi/ic_play_arrow_white_24dp.png
Normal file
BIN
res/drawable-mdpi/ic_play_arrow_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 157 B |
BIN
res/drawable-xhdpi/ic_play_arrow_white_24dp.png
Normal file
BIN
res/drawable-xhdpi/ic_play_arrow_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 220 B |
BIN
res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
Normal file
BIN
res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 283 B |
BIN
res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png
Normal file
BIN
res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 343 B |
5
res/drawable/conversation_item_background_animated.xml
Normal file
5
res/drawable/conversation_item_background_animated.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="1000">
|
||||||
|
<item android:drawable="@color/textsecure_primary_alpha33" android:state_selected="true" />
|
||||||
|
<item android:drawable="@color/signal_primary_alpha_focus" android:state_focused="true" />
|
||||||
|
</selector>
|
5
res/drawable/dismiss_background.xml
Normal file
5
res/drawable/dismiss_background.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval" >
|
||||||
|
<solid android:color="#99ffffff" />
|
||||||
|
</shape>
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<solid android:color="@color/gray5"/>
|
<solid android:color="@color/gray5"/>
|
||||||
<stroke android:color="@color/gray10" android:width="1dp"/>
|
<stroke android:color="@color/grey_400_transparent" android:width="@dimen/quote_outline_width"/>
|
||||||
<corners android:radius="5dp" />
|
<corners android:radius="@dimen/quote_corner_radius" />
|
||||||
</shape>
|
</shape>
|
@ -34,7 +34,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:quote_dismissable="true"
|
app:message_type="preview"
|
||||||
tools:visibility="visible"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
<LinearLayout android:layout_width="match_parent"
|
<LinearLayout android:layout_width="match_parent"
|
||||||
|
@ -79,8 +79,9 @@
|
|||||||
android:id="@+id/quote_view"
|
android:id="@+id/quote_view"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="3dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:quote_dismissable="false"
|
app:message_type="incoming"
|
||||||
tools:visibility="visible"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
|
@ -42,8 +42,9 @@
|
|||||||
android:id="@+id/quote_view"
|
android:id="@+id/quote_view"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="3dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:quote_dismissable="false"
|
app:message_type="outgoing"
|
||||||
tools:visibility="visible"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
|
@ -1,101 +1,141 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
<merge
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/quote_container"
|
android:id="@+id/quote_container"
|
||||||
android:orientation="horizontal"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:orientation="horizontal"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:layout_margin="3dp"
|
android:layout_margin="3dp"
|
||||||
android:background="@drawable/quote_background"
|
tools:visibility="visible">
|
||||||
tools:visibility="visible"
|
|
||||||
tools:parentTag="android.widget.LinearLayout">
|
|
||||||
|
|
||||||
<ImageView android:id="@+id/quote_bar"
|
<FrameLayout
|
||||||
android:layout_width="5dp"
|
android:id="@+id/quote_root"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:src="@drawable/quote_bar"
|
android:layout_height="wrap_content"
|
||||||
tools:tint="@color/purple_400"/>
|
android:background="@drawable/quote_background">
|
||||||
|
|
||||||
<LinearLayout android:orientation="vertical"
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="10dp"
|
android:orientation="horizontal">
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
android:layout_marginEnd="10dp"
|
|
||||||
android:paddingBottom="10dp">
|
|
||||||
|
|
||||||
<TextView android:id="@+id/quote_author"
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/quote_bar"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="@dimen/quote_corner_radius"
|
||||||
android:layout_marginTop="5dp"
|
android:layout_height="match_parent"
|
||||||
android:maxLines="1"
|
android:src="@color/white"
|
||||||
tools:textColor="@color/purple_400"
|
tools:tint="@color/purple_400" />
|
||||||
tools:text="Riya"/>
|
|
||||||
|
|
||||||
<LinearLayout android:id="@+id/media_description"
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="7dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:orientation="horizontal"
|
android:layout_marginStart="8dp"
|
||||||
android:visibility="gone"
|
android:layout_marginRight="8dp"
|
||||||
tools:visibility="visible">
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
<ImageView android:id="@+id/media_icon"
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/quote_author"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:tint="@color/gray50"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_insert_photo_white_18dp"/>
|
android:fontFamily="sans-serif-medium"
|
||||||
|
android:maxLines="1"
|
||||||
|
tools:text="Peter Parker"
|
||||||
|
tools:textColor="@color/purple_400" />
|
||||||
|
|
||||||
<TextView android:id="@+id/media_name"
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/media_name"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="10dp"
|
android:layout_marginRight="8dp"
|
||||||
android:layout_marginStart="10dp"
|
android:paddingTop="4dp"
|
||||||
android:textSize="11sp"
|
android:textSize="12sp"
|
||||||
tools:text="Photo"/>
|
android:textStyle="italic"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="Photo"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/quote_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="3"
|
||||||
|
tools:text="With great power comes great responsibility."
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/quote_attachment"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/quote_video_overlay"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:padding="18dp"
|
||||||
|
android:src="@drawable/ic_play_arrow_white_24dp"
|
||||||
|
android:background="@color/transparent_black_30"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="gone"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/quote_attachment_icon_container"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/quote_attachment_icon_background"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/circle_tintable" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/quote_attachment_icon"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="15dp"
|
||||||
|
tools:src="@drawable/ic_insert_drive_file_white_24dp"
|
||||||
|
tools:tint="@color/purple_400" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView android:id="@+id/quote_text"
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/quote_dismiss"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginTop="3dp"
|
android:layout_height="wrap_content"
|
||||||
android:maxLines="3"
|
android:layout_marginEnd="4dp"
|
||||||
android:ellipsize="end"
|
android:layout_marginRight="4dp"
|
||||||
tools:text="Short text."
|
android:layout_marginTop="4dp"
|
||||||
/>
|
android:layout_gravity="top|end"
|
||||||
|
android:background="@drawable/dismiss_background"
|
||||||
|
android:src="@drawable/ic_close_white_18dp"
|
||||||
|
android:tint="@color/gray70" />
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<FrameLayout android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<com.makeramen.roundedimageview.RoundedImageView
|
|
||||||
android:id="@+id/quote_attachment"
|
|
||||||
android:layout_width="80dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:riv_corner_radius_top_right="5dp"
|
|
||||||
app:riv_corner_radius_bottom_right="5dp"
|
|
||||||
android:scaleType="centerCrop"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:src="@drawable/surfwalk2"
|
|
||||||
tools:visibility="visible"/>
|
|
||||||
|
|
||||||
<ImageView android:id="@+id/quote_dismiss"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="right"
|
|
||||||
android:src="@drawable/ic_close_white_18dp"
|
|
||||||
android:tint="@color/gray70"
|
|
||||||
android:background="@drawable/circle_alpha"
|
|
||||||
android:layout_marginTop="5dp"
|
|
||||||
android:layout_marginRight="5dp"
|
|
||||||
android:layout_marginEnd="5dp"/>
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
</merge>
|
</merge>
|
@ -243,7 +243,11 @@
|
|||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<declare-styleable name="QuoteView">
|
<declare-styleable name="QuoteView">
|
||||||
<attr name="quote_dismissable" format="boolean"/>
|
<attr name="message_type" format="enum">
|
||||||
|
<enum name="preview" value="0" />
|
||||||
|
<enum name="outgoing" value="1" />
|
||||||
|
<enum name="incoming" value="2" />
|
||||||
|
</attr>
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<color name="transparent_white_20">#20ffffff</color>
|
<color name="transparent_white_20">#20ffffff</color>
|
||||||
<color name="transparent_white_30">#30ffffff</color>
|
<color name="transparent_white_30">#30ffffff</color>
|
||||||
<color name="transparent_white_40">#40ffffff</color>
|
<color name="transparent_white_40">#40ffffff</color>
|
||||||
|
<color name="transparent_white_70">#70ffffff</color>
|
||||||
<color name="transparent_white_aa">#aaffffff</color>
|
<color name="transparent_white_aa">#aaffffff</color>
|
||||||
|
|
||||||
<color name="conversation_compose_divider">#32000000</color>
|
<color name="conversation_compose_divider">#32000000</color>
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
<dimen name="media_bubble_min_height">100dp</dimen>
|
<dimen name="media_bubble_min_height">100dp</dimen>
|
||||||
<dimen name="media_bubble_max_height">320dp</dimen>
|
<dimen name="media_bubble_max_height">320dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="quote_corner_radius">3dp</dimen>
|
||||||
|
<dimen name="quote_outline_width">1dp</dimen>
|
||||||
|
|
||||||
<integer name="media_overview_cols">3</integer>
|
<integer name="media_overview_cols">3</integer>
|
||||||
<dimen name="message_details_table_row_pad">10dp</dimen>
|
<dimen name="message_details_table_row_pad">10dp</dimen>
|
||||||
|
|
||||||
|
@ -194,6 +194,7 @@
|
|||||||
<string name="ConversationFragment_sms">SMS</string>
|
<string name="ConversationFragment_sms">SMS</string>
|
||||||
<string name="ConversationFragment_deleting">Deleting</string>
|
<string name="ConversationFragment_deleting">Deleting</string>
|
||||||
<string name="ConversationFragment_deleting_messages">Deleting messages...</string>
|
<string name="ConversationFragment_deleting_messages">Deleting messages...</string>
|
||||||
|
<string name="ConversationFragment_quoted_message_not_found">Quoted message not found</string>
|
||||||
|
|
||||||
<!-- ConversationListActivity -->
|
<!-- ConversationListActivity -->
|
||||||
<string name="ConversationListActivity_there_is_no_browser_installed_on_your_device">There is no browser installed on your device.</string>
|
<string name="ConversationListActivity_there_is_no_browser_installed_on_your_device">There is no browser installed on your device.</string>
|
||||||
@ -813,6 +814,13 @@
|
|||||||
<string name="audio_view__pause_accessibility_description">Pause</string>
|
<string name="audio_view__pause_accessibility_description">Pause</string>
|
||||||
<string name="audio_view__download_accessibility_description">Download</string>
|
<string name="audio_view__download_accessibility_description">Download</string>
|
||||||
|
|
||||||
|
<!-- QuoteView -->
|
||||||
|
<string name="QuoteView_audio">Audio</string>
|
||||||
|
<string name="QuoteView_video">Video</string>
|
||||||
|
<string name="QuoteView_photo">Photo</string>
|
||||||
|
<string name="QuoteView_document">Document</string>
|
||||||
|
<string name="QuoteView_you">You</string>
|
||||||
|
|
||||||
<!-- conversation_fragment_cab -->
|
<!-- conversation_fragment_cab -->
|
||||||
<string name="conversation_fragment_cab__batch_selection_mode">Batch selection mode</string>
|
<string name="conversation_fragment_cab__batch_selection_mode">Batch selection mode</string>
|
||||||
<string name="conversation_fragment_cab__batch_selection_amount">%s selected</string>
|
<string name="conversation_fragment_cab__batch_selection_amount">%s selected</string>
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package org.thoughtcrime.securesms;
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
|
||||||
@ -11,11 +13,18 @@ import java.util.Locale;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public interface BindableConversationItem extends Unbindable {
|
public interface BindableConversationItem extends Unbindable {
|
||||||
void bind(@NonNull MessageRecord messageRecord,
|
void bind(@NonNull MessageRecord messageRecord,
|
||||||
@NonNull GlideRequests glideRequests,
|
@NonNull GlideRequests glideRequests,
|
||||||
@NonNull Locale locale,
|
@NonNull Locale locale,
|
||||||
@NonNull Set<MessageRecord> batchSelected,
|
@NonNull Set<MessageRecord> batchSelected,
|
||||||
@NonNull Recipient recipients);
|
@NonNull Recipient recipients,
|
||||||
|
boolean pulseHighlight);
|
||||||
|
|
||||||
MessageRecord getMessageRecord();
|
MessageRecord getMessageRecord();
|
||||||
|
|
||||||
|
void setEventListener(@Nullable EventListener listener);
|
||||||
|
|
||||||
|
interface EventListener {
|
||||||
|
void onQuoteClicked(MmsMessageRecord messageRecord);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,6 @@ import android.widget.LinearLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
|
||||||
import com.google.android.gms.location.places.ui.PlacePicker;
|
import com.google.android.gms.location.places.ui.PlacePicker;
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
@ -2063,7 +2062,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
inputPanel.setQuote(GlideApp.with(this),
|
inputPanel.setQuote(GlideApp.with(this),
|
||||||
messageRecord.getTimestamp(),
|
messageRecord.getDateSent(),
|
||||||
author,
|
author,
|
||||||
messageRecord.getBody(),
|
messageRecord.getBody(),
|
||||||
messageRecord.isMms() ? ((MmsMessageRecord)messageRecord).getSlideDeck() : new SlideDeck());
|
messageRecord.isMms() ? ((MmsMessageRecord)messageRecord).getSlideDeck() : new SlideDeck());
|
||||||
|
@ -33,7 +33,6 @@ import com.annimon.stream.Stream;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.ConversationAdapter.HeaderViewHolder;
|
import org.thoughtcrime.securesms.ConversationAdapter.HeaderViewHolder;
|
||||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.FastCursorRecyclerViewAdapter;
|
import org.thoughtcrime.securesms.database.FastCursorRecyclerViewAdapter;
|
||||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||||
@ -101,6 +100,8 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
|||||||
private final @NonNull Calendar calendar;
|
private final @NonNull Calendar calendar;
|
||||||
private final @NonNull MessageDigest digest;
|
private final @NonNull MessageDigest digest;
|
||||||
|
|
||||||
|
private MessageRecord recordToPulseHighlight;
|
||||||
|
|
||||||
protected static class ViewHolder extends RecyclerView.ViewHolder {
|
protected static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
public <V extends View & BindableConversationItem> ViewHolder(final @NonNull V itemView) {
|
public <V extends View & BindableConversationItem> ViewHolder(final @NonNull V itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
@ -132,7 +133,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface ItemClickListener {
|
interface ItemClickListener extends BindableConversationItem.EventListener {
|
||||||
void onItemClick(MessageRecord item);
|
void onItemClick(MessageRecord item);
|
||||||
void onItemLongClick(MessageRecord item);
|
void onItemLongClick(MessageRecord item);
|
||||||
}
|
}
|
||||||
@ -190,7 +191,10 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
|||||||
@Override
|
@Override
|
||||||
protected void onBindItemViewHolder(ViewHolder viewHolder, @NonNull MessageRecord messageRecord) {
|
protected void onBindItemViewHolder(ViewHolder viewHolder, @NonNull MessageRecord messageRecord) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
viewHolder.getView().bind(messageRecord, glideRequests, locale, batchSelected, recipient);
|
viewHolder.getView().bind(messageRecord, glideRequests, locale, batchSelected, recipient, messageRecord == recordToPulseHighlight);
|
||||||
|
if (messageRecord == recordToPulseHighlight) {
|
||||||
|
recordToPulseHighlight = null;
|
||||||
|
}
|
||||||
Log.w(TAG, "Bind time: " + (System.currentTimeMillis() - start));
|
Log.w(TAG, "Bind time: " + (System.currentTimeMillis() - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,6 +213,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
itemView.setEventListener(clickListener);
|
||||||
Log.w(TAG, "Inflate time: " + (System.currentTimeMillis() - start));
|
Log.w(TAG, "Inflate time: " + (System.currentTimeMillis() - start));
|
||||||
return new ViewHolder(itemView);
|
return new ViewHolder(itemView);
|
||||||
}
|
}
|
||||||
@ -341,6 +346,13 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
|||||||
return Collections.unmodifiableSet(new HashSet<>(batchSelected));
|
return Collections.unmodifiableSet(new HashSet<>(batchSelected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void pulseHighlightItem(int position) {
|
||||||
|
if (position < getItemCount()) {
|
||||||
|
recordToPulseHighlight = getRecordForPositionOrThrow(position);
|
||||||
|
notifyItemChanged(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasAudio(MessageRecord messageRecord) {
|
private boolean hasAudio(MessageRecord messageRecord) {
|
||||||
return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getAudioSlide() != null;
|
return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getAudioSlide() != null;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.loaders.ConversationLoader;
|
import org.thoughtcrime.securesms.database.loaders.ConversationLoader;
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
@ -226,6 +227,7 @@ public class ConversationFragment extends Fragment
|
|||||||
|
|
||||||
if (messageRecords.size() > 1) {
|
if (messageRecords.size() > 1) {
|
||||||
menu.findItem(R.id.menu_context_forward).setVisible(false);
|
menu.findItem(R.id.menu_context_forward).setVisible(false);
|
||||||
|
menu.findItem(R.id.menu_context_reply).setVisible(false);
|
||||||
menu.findItem(R.id.menu_context_details).setVisible(false);
|
menu.findItem(R.id.menu_context_details).setVisible(false);
|
||||||
menu.findItem(R.id.menu_context_save_attachment).setVisible(false);
|
menu.findItem(R.id.menu_context_save_attachment).setVisible(false);
|
||||||
menu.findItem(R.id.menu_context_resend).setVisible(false);
|
menu.findItem(R.id.menu_context_resend).setVisible(false);
|
||||||
@ -240,6 +242,9 @@ public class ConversationFragment extends Fragment
|
|||||||
|
|
||||||
menu.findItem(R.id.menu_context_forward).setVisible(!actionMessage);
|
menu.findItem(R.id.menu_context_forward).setVisible(!actionMessage);
|
||||||
menu.findItem(R.id.menu_context_details).setVisible(!actionMessage);
|
menu.findItem(R.id.menu_context_details).setVisible(!actionMessage);
|
||||||
|
menu.findItem(R.id.menu_context_reply).setVisible(!messageRecord.isPending() &&
|
||||||
|
!messageRecord.isFailed() &&
|
||||||
|
messageRecord.isSecure());
|
||||||
}
|
}
|
||||||
menu.findItem(R.id.menu_context_copy).setVisible(!actionMessage && hasText);
|
menu.findItem(R.id.menu_context_copy).setVisible(!actionMessage && hasText);
|
||||||
}
|
}
|
||||||
@ -414,7 +419,6 @@ public class ConversationFragment extends Fragment
|
|||||||
return new ConversationLoader(getActivity(), threadId, args.getLong("limit", PARTIAL_CONVERSATION_LIMIT), lastSeen);
|
return new ConversationLoader(getActivity(), threadId, args.getLong("limit", PARTIAL_CONVERSATION_LIMIT), lastSeen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
|
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
|
||||||
Log.w(TAG, "onLoadFinished");
|
Log.w(TAG, "onLoadFinished");
|
||||||
@ -593,7 +597,6 @@ public class ConversationFragment extends Fragment
|
|||||||
setCorrectMenuVisibility(actionMode.getMenu());
|
setCorrectMenuVisibility(actionMode.getMenu());
|
||||||
actionMode.setTitle(String.valueOf(getListAdapter().getSelectedItems().size()));
|
actionMode.setTitle(String.valueOf(getListAdapter().getSelectedItems().size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,6 +609,37 @@ public class ConversationFragment extends Fragment
|
|||||||
actionMode = ((AppCompatActivity)getActivity()).startSupportActionMode(actionModeCallback);
|
actionMode = ((AppCompatActivity)getActivity()).startSupportActionMode(actionModeCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onQuoteClicked(MmsMessageRecord messageRecord) {
|
||||||
|
if (messageRecord.getQuote() == null) {
|
||||||
|
Log.w(TAG, "Received a 'quote clicked' event, but there's no quote...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new AsyncTask<Void, Void, Integer>() {
|
||||||
|
@Override
|
||||||
|
protected Integer doInBackground(Void... voids) {
|
||||||
|
return DatabaseFactory.getMmsSmsDatabase(getContext())
|
||||||
|
.getQuotedMessagePosition(threadId, messageRecord.getQuote().getId(), messageRecord.getQuote().getAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Integer position) {
|
||||||
|
if (position >= 0 && position < getListAdapter().getItemCount()) {
|
||||||
|
list.scrollToPosition(position);
|
||||||
|
getListAdapter().pulseHighlightItem(position);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), getResources().getText(R.string.ConversationFragment_quoted_message_not_found), Toast.LENGTH_SHORT).show();
|
||||||
|
if (position < 0) {
|
||||||
|
Log.w(TAG, "Tried to navigate to quoted message, but it was deleted.");
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Tried to navigate to quoted message, but it was out of the bounds of the adapter.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ActionModeCallback implements ActionMode.Callback {
|
private class ActionModeCallback implements ActionMode.Callback {
|
||||||
|
@ -22,6 +22,7 @@ import android.content.ActivityNotFoundException;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -126,17 +127,18 @@ public class ConversationItem extends LinearLayout
|
|||||||
private DeliveryStatusView deliveryStatusIndicator;
|
private DeliveryStatusView deliveryStatusIndicator;
|
||||||
private AlertView alertView;
|
private AlertView alertView;
|
||||||
|
|
||||||
private @NonNull Set<MessageRecord> batchSelected = new HashSet<>();
|
private @NonNull Set<MessageRecord> batchSelected = new HashSet<>();
|
||||||
private @NonNull Recipient conversationRecipient;
|
private @NonNull Recipient conversationRecipient;
|
||||||
private @NonNull Stub<ThumbnailView> mediaThumbnailStub;
|
private @NonNull Stub<ThumbnailView> mediaThumbnailStub;
|
||||||
private @NonNull Stub<AudioView> audioViewStub;
|
private @NonNull Stub<AudioView> audioViewStub;
|
||||||
private @NonNull Stub<DocumentView> documentViewStub;
|
private @NonNull Stub<DocumentView> documentViewStub;
|
||||||
private @NonNull ExpirationTimerView expirationTimer;
|
private @NonNull ExpirationTimerView expirationTimer;
|
||||||
|
private @Nullable EventListener eventListener;
|
||||||
|
|
||||||
private int defaultBubbleColor;
|
private int defaultBubbleColor;
|
||||||
|
|
||||||
private final PassthroughClickListener passthroughClickListener = new PassthroughClickListener();
|
private final PassthroughClickListener passthroughClickListener = new PassthroughClickListener();
|
||||||
private final AttachmentDownloadClickListener downloadClickListener = new AttachmentDownloadClickListener();
|
private final AttachmentDownloadClickListener downloadClickListener = new AttachmentDownloadClickListener();
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -191,7 +193,8 @@ public class ConversationItem extends LinearLayout
|
|||||||
@NonNull GlideRequests glideRequests,
|
@NonNull GlideRequests glideRequests,
|
||||||
@NonNull Locale locale,
|
@NonNull Locale locale,
|
||||||
@NonNull Set<MessageRecord> batchSelected,
|
@NonNull Set<MessageRecord> batchSelected,
|
||||||
@NonNull Recipient conversationRecipient)
|
@NonNull Recipient conversationRecipient,
|
||||||
|
boolean pulseHighlight)
|
||||||
{
|
{
|
||||||
this.messageRecord = messageRecord;
|
this.messageRecord = messageRecord;
|
||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
@ -205,7 +208,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
this.conversationRecipient.addListener(this);
|
this.conversationRecipient.addListener(this);
|
||||||
|
|
||||||
setMediaAttributes(messageRecord);
|
setMediaAttributes(messageRecord);
|
||||||
setInteractionState(messageRecord);
|
setInteractionState(messageRecord, pulseHighlight);
|
||||||
setBodyText(messageRecord);
|
setBodyText(messageRecord);
|
||||||
setBubbleState(messageRecord, recipient);
|
setBubbleState(messageRecord, recipient);
|
||||||
setStatusIcons(messageRecord);
|
setStatusIcons(messageRecord);
|
||||||
@ -217,6 +220,11 @@ public class ConversationItem extends LinearLayout
|
|||||||
setQuote(messageRecord);
|
setQuote(messageRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEventListener(@Nullable EventListener eventListener) {
|
||||||
|
this.eventListener = eventListener;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
super.onLayout(changed, left, top, right, bottom);
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
@ -243,6 +251,27 @@ public class ConversationItem extends LinearLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
|
||||||
|
if (hasQuote(messageRecord)) {
|
||||||
|
int quoteWidth = quoteView.getMeasuredWidth();
|
||||||
|
|
||||||
|
int availableWidth;
|
||||||
|
if (hasThumbnail(messageRecord)) {
|
||||||
|
availableWidth = mediaThumbnailStub.get().getMeasuredWidth();
|
||||||
|
} else {
|
||||||
|
availableWidth = bodyBubble.getMeasuredWidth() - bodyBubble.getPaddingLeft() - bodyBubble.getPaddingRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quoteWidth != availableWidth) {
|
||||||
|
quoteView.getLayoutParams().width = availableWidth;
|
||||||
|
measure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initializeAttributes() {
|
private void initializeAttributes() {
|
||||||
final int[] attributes = new int[] {R.attr.conversation_item_bubble_background};
|
final int[] attributes = new int[] {R.attr.conversation_item_bubble_background};
|
||||||
final TypedArray attrs = context.obtainStyledAttributes(attributes);
|
final TypedArray attrs = context.obtainStyledAttributes(attributes);
|
||||||
@ -309,8 +338,17 @@ public class ConversationItem extends LinearLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setInteractionState(MessageRecord messageRecord) {
|
private void setInteractionState(MessageRecord messageRecord, boolean pulseHighlight) {
|
||||||
setSelected(batchSelected.contains(messageRecord));
|
if (batchSelected.contains(messageRecord)) {
|
||||||
|
setBackgroundResource(R.drawable.conversation_item_background);
|
||||||
|
setSelected(true);
|
||||||
|
} else if (pulseHighlight) {
|
||||||
|
setBackgroundResource(R.drawable.conversation_item_background_animated);
|
||||||
|
setSelected(true);
|
||||||
|
postDelayed(() -> setSelected(false), 500);
|
||||||
|
} else {
|
||||||
|
setSelected(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (mediaThumbnailStub.resolved()) {
|
if (mediaThumbnailStub.resolved()) {
|
||||||
mediaThumbnailStub.get().setFocusable(!shouldInterceptClicks(messageRecord) && batchSelected.isEmpty());
|
mediaThumbnailStub.get().setFocusable(!shouldInterceptClicks(messageRecord) && batchSelected.isEmpty());
|
||||||
@ -346,6 +384,10 @@ public class ConversationItem extends LinearLayout
|
|||||||
return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getDocumentSlide() != null;
|
return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getDocumentSlide() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasQuote(MessageRecord messageRecord) {
|
||||||
|
return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getQuote() != null;
|
||||||
|
}
|
||||||
|
|
||||||
private void setBodyText(MessageRecord messageRecord) {
|
private void setBodyText(MessageRecord messageRecord) {
|
||||||
bodyText.setClickable(false);
|
bodyText.setClickable(false);
|
||||||
bodyText.setFocusable(false);
|
bodyText.setFocusable(false);
|
||||||
@ -517,6 +559,16 @@ public class ConversationItem extends LinearLayout
|
|||||||
assert quote != null;
|
assert quote != null;
|
||||||
quoteView.setQuote(glideRequests, quote.getId(), Recipient.from(context, quote.getAuthor(), true), quote.getText(), quote.getAttachment());
|
quoteView.setQuote(glideRequests, quote.getId(), Recipient.from(context, quote.getAuthor(), true), quote.getText(), quote.getAttachment());
|
||||||
quoteView.setVisibility(View.VISIBLE);
|
quoteView.setVisibility(View.VISIBLE);
|
||||||
|
quoteView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
|
||||||
|
quoteView.setOnClickListener(view -> {
|
||||||
|
if (eventListener != null && batchSelected.isEmpty()) {
|
||||||
|
eventListener.onQuoteClicked((MmsMessageRecord) messageRecord);
|
||||||
|
} else {
|
||||||
|
passthroughClickListener.onClick(view);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
quoteView.setOnLongClickListener(passthroughClickListener);
|
||||||
} else {
|
} else {
|
||||||
quoteView.dismiss();
|
quoteView.dismiss();
|
||||||
}
|
}
|
||||||
|
@ -66,17 +66,23 @@ public class ConversationUpdateItem extends LinearLayout
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind(@NonNull MessageRecord messageRecord,
|
public void bind(@NonNull MessageRecord messageRecord,
|
||||||
@NonNull GlideRequests glideRequests,
|
@NonNull GlideRequests glideRequests,
|
||||||
@NonNull Locale locale,
|
@NonNull Locale locale,
|
||||||
@NonNull Set<MessageRecord> batchSelected,
|
@NonNull Set<MessageRecord> batchSelected,
|
||||||
@NonNull Recipient conversationRecipient)
|
@NonNull Recipient conversationRecipient,
|
||||||
|
boolean pulseUpdate)
|
||||||
{
|
{
|
||||||
this.batchSelected = batchSelected;
|
this.batchSelected = batchSelected;
|
||||||
|
|
||||||
bind(messageRecord, locale);
|
bind(messageRecord, locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEventListener(@Nullable EventListener listener) {
|
||||||
|
// No events to report yet
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MessageRecord getMessageRecord() {
|
public MessageRecord getMessageRecord() {
|
||||||
return messageRecord;
|
return messageRecord;
|
||||||
|
@ -252,7 +252,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||||||
toFromRes = R.string.message_details_header__from;
|
toFromRes = R.string.message_details_header__from;
|
||||||
}
|
}
|
||||||
toFrom.setText(toFromRes);
|
toFrom.setText(toFromRes);
|
||||||
conversationItem.bind(messageRecord, glideRequests, dynamicLanguage.getCurrentLocale(), new HashSet<>(), recipient);
|
conversationItem.bind(messageRecord, glideRequests, dynamicLanguage.getCurrentLocale(), new HashSet<>(), recipient, false);
|
||||||
recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, glideRequests, messageRecord, recipients, isPushGroup));
|
recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, glideRequests, messageRecord, recipients, isPushGroup));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
|||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -16,7 +17,7 @@ public class PointerAttachment extends Attachment {
|
|||||||
|
|
||||||
private PointerAttachment(@NonNull String contentType, int transferState, long size,
|
private PointerAttachment(@NonNull String contentType, int transferState, long size,
|
||||||
@Nullable String fileName, @NonNull String location,
|
@Nullable String fileName, @NonNull String location,
|
||||||
@Nullable String key, @NonNull String relay,
|
@Nullable String key, @Nullable String relay,
|
||||||
@Nullable byte[] digest, boolean voiceNote,
|
@Nullable byte[] digest, boolean voiceNote,
|
||||||
int width, int height)
|
int width, int height)
|
||||||
{
|
{
|
||||||
@ -52,6 +53,22 @@ public class PointerAttachment extends Attachment {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Attachment> forPointers(List<SignalServiceDataMessage.Quote.QuotedAttachment> pointers) {
|
||||||
|
List<Attachment> results = new LinkedList<>();
|
||||||
|
|
||||||
|
if (pointers != null) {
|
||||||
|
for (SignalServiceDataMessage.Quote.QuotedAttachment pointer : pointers) {
|
||||||
|
Optional<Attachment> result = forPointer(pointer);
|
||||||
|
|
||||||
|
if (result.isPresent()) {
|
||||||
|
results.add(result.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
public static Optional<Attachment> forPointer(Optional<SignalServiceAttachment> pointer) {
|
public static Optional<Attachment> forPointer(Optional<SignalServiceAttachment> pointer) {
|
||||||
if (!pointer.isPresent() || !pointer.get().isPointer()) return Optional.absent();
|
if (!pointer.isPresent() || !pointer.get().isPointer()) return Optional.absent();
|
||||||
|
|
||||||
@ -73,4 +90,20 @@ public class PointerAttachment extends Attachment {
|
|||||||
pointer.get().asPointer().getHeight()));
|
pointer.get().asPointer().getHeight()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<Attachment> forPointer(SignalServiceDataMessage.Quote.QuotedAttachment pointer) {
|
||||||
|
SignalServiceAttachment thumbnail = pointer.getThumbnail();
|
||||||
|
|
||||||
|
return Optional.of(new PointerAttachment(pointer.getContentType(),
|
||||||
|
AttachmentDatabase.TRANSFER_PROGRESS_PENDING,
|
||||||
|
thumbnail != null ? thumbnail.asPointer().getSize().or(0) : 0,
|
||||||
|
pointer.getFileName(),
|
||||||
|
String.valueOf(thumbnail != null ? thumbnail.asPointer().getId() : 0),
|
||||||
|
thumbnail != null && thumbnail.asPointer().getKey() != null ? Base64.encodeBytes(thumbnail.asPointer().getKey()) : null,
|
||||||
|
null,
|
||||||
|
thumbnail != null ? thumbnail.asPointer().getDigest().orNull() : null,
|
||||||
|
false,
|
||||||
|
thumbnail != null ? thumbnail.asPointer().getWidth() : 0,
|
||||||
|
thumbnail != null ? thumbnail.asPointer().getHeight() : 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.thoughtcrime.securesms.color;
|
package org.thoughtcrime.securesms.color;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
|
|
||||||
@ -61,27 +62,57 @@ public enum MaterialColor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int toConversationColor(@NonNull Context context) {
|
public int toConversationColor(@NonNull Context context) {
|
||||||
if (getAttribute(context, R.attr.theme_type, "light").equals("dark")) {
|
return context.getResources().getColor(isDarkTheme(context) ? conversationColorDark
|
||||||
return context.getResources().getColor(conversationColorDark);
|
: conversationColorLight);
|
||||||
} else {
|
|
||||||
return context.getResources().getColor(conversationColorLight);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int toActionBarColor(@NonNull Context context) {
|
public int toActionBarColor(@NonNull Context context) {
|
||||||
if (getAttribute(context, R.attr.theme_type, "light").equals("dark")) {
|
return context.getResources().getColor(isDarkTheme(context) ? actionBarColorDark
|
||||||
return context.getResources().getColor(actionBarColorDark);
|
: actionBarColorLight);
|
||||||
} else {
|
|
||||||
return context.getResources().getColor(actionBarColorLight);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int toStatusBarColor(@NonNull Context context) {
|
public int toStatusBarColor(@NonNull Context context) {
|
||||||
if (getAttribute(context, R.attr.theme_type, "light").equals("dark")) {
|
return context.getResources().getColor(isDarkTheme(context) ? statusBarColorDark
|
||||||
return context.getResources().getColor(statusBarColorDark);
|
: statusBarColorLight);
|
||||||
} else {
|
}
|
||||||
return context.getResources().getColor(statusBarColorLight);
|
|
||||||
|
public int toQuoteTitleColor(@NonNull Context context) {
|
||||||
|
return context.getResources().getColor(conversationColorDark);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int toQuoteBarColorResource(@NonNull Context context, boolean outgoing) {
|
||||||
|
if (outgoing) {
|
||||||
|
return conversationColorDark;
|
||||||
}
|
}
|
||||||
|
return R.color.white;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int toQuoteBackgroundColor(@NonNull Context context, boolean outgoing) {
|
||||||
|
if (outgoing) {
|
||||||
|
int color = toConversationColor(context);
|
||||||
|
return Color.argb(0x44, Color.red(color), Color.green(color), Color.blue(color));
|
||||||
|
}
|
||||||
|
return context.getResources().getColor(isDarkTheme(context) ? R.color.transparent_white_70
|
||||||
|
: R.color.transparent_white_aa);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int toQuoteOutlineColor(@NonNull Context context, boolean outgoing) {
|
||||||
|
if (!outgoing) {
|
||||||
|
return context.getResources().getColor(R.color.transparent_white_70);
|
||||||
|
}
|
||||||
|
return context.getResources().getColor(isDarkTheme(context) ? R.color.transparent_white_40
|
||||||
|
: R.color.grey_400_transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int toQuoteIconForegroundColor(@NonNull Context context, boolean outgoing) {
|
||||||
|
if (outgoing) {
|
||||||
|
return context.getResources().getColor(R.color.white);
|
||||||
|
}
|
||||||
|
return toConversationColor(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int toQuoteIconBackgroundColor(@NonNull Context context, boolean outgoing) {
|
||||||
|
return context.getResources().getColor(toQuoteBarColorResource(context, outgoing));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean represents(Context context, int colorValue) {
|
public boolean represents(Context context, int colorValue) {
|
||||||
@ -107,6 +138,9 @@ public enum MaterialColor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isDarkTheme(@NonNull Context context) {
|
||||||
|
return getAttribute(context, R.attr.theme_type, "light").equals("dark");
|
||||||
|
}
|
||||||
|
|
||||||
public static MaterialColor fromSerialized(String serialized) throws UnknownColorException {
|
public static MaterialColor fromSerialized(String serialized) throws UnknownColorException {
|
||||||
for (MaterialColor color : MaterialColor.values()) {
|
for (MaterialColor color : MaterialColor.values()) {
|
||||||
|
@ -3,19 +3,22 @@ package org.thoughtcrime.securesms.components;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Path;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.RectF;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.graphics.drawable.GradientDrawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.RequiresApi;
|
import android.support.annotation.RequiresApi;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
@ -23,11 +26,14 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
import org.thoughtcrime.securesms.mms.AudioSlide;
|
||||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
||||||
|
import org.thoughtcrime.securesms.mms.DocumentSlide;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
|
import org.thoughtcrime.securesms.mms.ImageSlide;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
|
import org.thoughtcrime.securesms.mms.VideoSlide;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
@ -38,19 +44,31 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener
|
|||||||
|
|
||||||
private static final String TAG = QuoteView.class.getSimpleName();
|
private static final String TAG = QuoteView.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final int MESSAGE_TYPE_PREVIEW = 0;
|
||||||
|
private static final int MESSAGE_TYPE_OUTGOING = 1;
|
||||||
|
private static final int MESSAGE_TYPE_INCOMING = 2;
|
||||||
|
|
||||||
|
private View rootView;
|
||||||
private TextView authorView;
|
private TextView authorView;
|
||||||
private TextView bodyView;
|
private TextView bodyView;
|
||||||
private ImageView quoteBarView;
|
private ImageView quoteBarView;
|
||||||
private ImageView attachmentView;
|
private ImageView attachmentView;
|
||||||
|
private ImageView attachmentVideoOverlayView;
|
||||||
|
private ViewGroup attachmentIconContainerView;
|
||||||
|
private ImageView attachmentIconView;
|
||||||
|
private ImageView attachmentIconBackgroundView;
|
||||||
private ImageView dismissView;
|
private ImageView dismissView;
|
||||||
|
|
||||||
private long id;
|
private long id;
|
||||||
private Recipient author;
|
private Recipient author;
|
||||||
private String body;
|
private String body;
|
||||||
private View mediaDescription;
|
|
||||||
private ImageView mediaDescriptionIcon;
|
|
||||||
private TextView mediaDescriptionText;
|
private TextView mediaDescriptionText;
|
||||||
private SlideDeck attachments;
|
private SlideDeck attachments;
|
||||||
|
private int messageType;
|
||||||
|
private int roundedCornerRadiusPx;
|
||||||
|
|
||||||
|
private final Path clipPath = new Path();
|
||||||
|
private final RectF drawRect = new RectF();
|
||||||
|
|
||||||
public QuoteView(Context context) {
|
public QuoteView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@ -76,27 +94,47 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener
|
|||||||
private void initialize(@Nullable AttributeSet attrs) {
|
private void initialize(@Nullable AttributeSet attrs) {
|
||||||
inflate(getContext(), R.layout.quote_view, this);
|
inflate(getContext(), R.layout.quote_view, this);
|
||||||
|
|
||||||
this.authorView = findViewById(R.id.quote_author);
|
this.rootView = findViewById(R.id.quote_root);
|
||||||
this.bodyView = findViewById(R.id.quote_text);
|
this.authorView = findViewById(R.id.quote_author);
|
||||||
this.quoteBarView = findViewById(R.id.quote_bar);
|
this.bodyView = findViewById(R.id.quote_text);
|
||||||
this.attachmentView = findViewById(R.id.quote_attachment);
|
this.quoteBarView = findViewById(R.id.quote_bar);
|
||||||
this.dismissView = findViewById(R.id.quote_dismiss);
|
this.attachmentView = findViewById(R.id.quote_attachment);
|
||||||
this.mediaDescriptionIcon = findViewById(R.id.media_icon);
|
this.attachmentVideoOverlayView = findViewById(R.id.quote_video_overlay);
|
||||||
this.mediaDescriptionText = findViewById(R.id.media_name);
|
this.attachmentIconContainerView = findViewById(R.id.quote_attachment_icon_container);
|
||||||
this.mediaDescription = findViewById(R.id.media_description);
|
this.attachmentIconView = findViewById(R.id.quote_attachment_icon);
|
||||||
|
this.attachmentIconBackgroundView = findViewById(R.id.quote_attachment_icon_background);
|
||||||
|
this.dismissView = findViewById(R.id.quote_dismiss);
|
||||||
|
this.mediaDescriptionText = findViewById(R.id.media_name);
|
||||||
|
this.roundedCornerRadiusPx = getResources().getDimensionPixelSize(R.dimen.quote_corner_radius);
|
||||||
|
|
||||||
if (attrs != null) {
|
if (attrs != null) {
|
||||||
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.QuoteView, 0, 0);
|
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.QuoteView, 0, 0);
|
||||||
boolean dismissable = typedArray.getBoolean(R.styleable.QuoteView_quote_dismissable, true);
|
messageType = typedArray.getInt(R.styleable.QuoteView_message_type, 0);
|
||||||
typedArray.recycle();
|
typedArray.recycle();
|
||||||
|
|
||||||
if (!dismissable) dismissView.setVisibility(View.GONE);
|
dismissView.setVisibility(messageType == MESSAGE_TYPE_PREVIEW ? VISIBLE : GONE);
|
||||||
else dismissView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dismissView.setOnClickListener(view -> setVisibility(View.GONE));
|
dismissView.setOnClickListener(view -> setVisibility(GONE));
|
||||||
|
|
||||||
setBackgroundDrawable(getContext().getResources().getDrawable(R.drawable.quote_background));
|
setWillNotDraw(false);
|
||||||
|
if (Build.VERSION.SDK_INT < 18) {
|
||||||
|
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
drawRect.left = 0;
|
||||||
|
drawRect.top = 0;
|
||||||
|
drawRect.right = getWidth();
|
||||||
|
drawRect.bottom = getHeight();
|
||||||
|
|
||||||
|
clipPath.reset();
|
||||||
|
clipPath.addRoundRect(drawRect, roundedCornerRadiusPx, roundedCornerRadiusPx, Path.Direction.CW);
|
||||||
|
canvas.clipPath(clipPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setQuote(GlideRequests glideRequests, long id, @NonNull Recipient author, @Nullable String body, @NonNull SlideDeck attachments) {
|
public void setQuote(GlideRequests glideRequests, long id, @NonNull Recipient author, @Nullable String body, @NonNull SlideDeck attachments) {
|
||||||
@ -110,7 +148,7 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener
|
|||||||
author.addListener(this);
|
author.addListener(this);
|
||||||
setQuoteAuthor(author);
|
setQuoteAuthor(author);
|
||||||
setQuoteText(body, attachments);
|
setQuoteText(body, attachments);
|
||||||
setQuoteAttachment(glideRequests, attachments);
|
setQuoteAttachment(glideRequests, attachments, author);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dismiss() {
|
public void dismiss() {
|
||||||
@ -120,7 +158,7 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener
|
|||||||
this.author = null;
|
this.author = null;
|
||||||
this.body = null;
|
this.body = null;
|
||||||
|
|
||||||
setVisibility(View.GONE);
|
setVisibility(GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -133,54 +171,96 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setQuoteAuthor(@NonNull Recipient author) {
|
private void setQuoteAuthor(@NonNull Recipient author) {
|
||||||
this.authorView.setText(author.toShortString());
|
boolean outgoing = messageType != MESSAGE_TYPE_INCOMING;
|
||||||
this.authorView.setTextColor(author.getColor().toActionBarColor(getContext()));
|
boolean isOwnNumber = Util.isOwnNumber(getContext(), author.getAddress());
|
||||||
this.quoteBarView.setColorFilter(author.getColor().toActionBarColor(getContext()), PorterDuff.Mode.SRC_IN);
|
|
||||||
|
authorView.setText(isOwnNumber ? getContext().getString(R.string.QuoteView_you)
|
||||||
|
: author.toShortString());
|
||||||
|
authorView.setTextColor(author.getColor().toQuoteTitleColor(getContext()));
|
||||||
|
// We use the raw color resource because Android 4.x was struggling with tints here
|
||||||
|
quoteBarView.setImageResource(author.getColor().toQuoteBarColorResource(getContext(), outgoing));
|
||||||
|
|
||||||
|
GradientDrawable background = (GradientDrawable) rootView.getBackground();
|
||||||
|
background.setColor(author.getColor().toQuoteBackgroundColor(getContext(), outgoing));
|
||||||
|
background.setStroke(getResources().getDimensionPixelSize(R.dimen.quote_outline_width),
|
||||||
|
author.getColor().toQuoteOutlineColor(getContext(), outgoing));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setQuoteText(@Nullable String body, @NonNull SlideDeck attachments) {
|
private void setQuoteText(@Nullable String body, @NonNull SlideDeck attachments) {
|
||||||
if (TextUtils.isEmpty(body) && attachments.containsMediaSlide()) {
|
if (!TextUtils.isEmpty(body) || !attachments.containsMediaSlide()) {
|
||||||
mediaDescription.setVisibility(View.VISIBLE);
|
bodyView.setVisibility(VISIBLE);
|
||||||
bodyView.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
List<Slide> audioSlides = Stream.of(attachments.getSlides()).filter(Slide::hasAudio).limit(1).toList();
|
|
||||||
List<Slide> documentSlides = Stream.of(attachments.getSlides()).filter(Slide::hasDocument).limit(1).toList();
|
|
||||||
List<Slide> imageSlides = Stream.of(attachments.getSlides()).filter(Slide::hasImage).limit(1).toList();
|
|
||||||
List<Slide> videoSlides = Stream.of(attachments.getSlides()).filter(Slide::hasVideo).limit(1).toList();
|
|
||||||
|
|
||||||
if (!audioSlides.isEmpty()) {
|
|
||||||
mediaDescriptionIcon.setImageResource(R.drawable.ic_mic_white_24dp);
|
|
||||||
mediaDescriptionText.setText("Audio");
|
|
||||||
} else if (!documentSlides.isEmpty()) {
|
|
||||||
mediaDescriptionIcon.setImageResource(R.drawable.ic_insert_drive_file_white_24dp);
|
|
||||||
mediaDescriptionText.setText(String.format("%s (%s)", documentSlides.get(0).getFileName(), Util.getPrettyFileSize(documentSlides.get(0).getFileSize())));
|
|
||||||
} else if (!videoSlides.isEmpty()) {
|
|
||||||
mediaDescriptionIcon.setImageResource(R.drawable.ic_videocam_white_24dp);
|
|
||||||
mediaDescriptionText.setText("Video");
|
|
||||||
} else if (!imageSlides.isEmpty()) {
|
|
||||||
mediaDescriptionIcon.setImageResource(R.drawable.ic_camera_alt_white_24dp);
|
|
||||||
mediaDescriptionText.setText("Photo");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mediaDescription.setVisibility(View.GONE);
|
|
||||||
bodyView.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
bodyView.setText(body == null ? "" : body);
|
bodyView.setText(body == null ? "" : body);
|
||||||
|
mediaDescriptionText.setVisibility(GONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyView.setVisibility(GONE);
|
||||||
|
mediaDescriptionText.setVisibility(VISIBLE);
|
||||||
|
mediaDescriptionText.setTypeface(null, Typeface.ITALIC);
|
||||||
|
|
||||||
|
List<Slide> audioSlides = Stream.of(attachments.getSlides()).filter(Slide::hasAudio).limit(1).toList();
|
||||||
|
List<Slide> documentSlides = Stream.of(attachments.getSlides()).filter(Slide::hasDocument).limit(1).toList();
|
||||||
|
List<Slide> imageSlides = Stream.of(attachments.getSlides()).filter(Slide::hasImage).limit(1).toList();
|
||||||
|
List<Slide> videoSlides = Stream.of(attachments.getSlides()).filter(Slide::hasVideo).limit(1).toList();
|
||||||
|
|
||||||
|
// Given that most types have images, we specifically check images last
|
||||||
|
if (!audioSlides.isEmpty()) {
|
||||||
|
mediaDescriptionText.setText(R.string.QuoteView_audio);
|
||||||
|
} else if (!documentSlides.isEmpty()) {
|
||||||
|
String filename = documentSlides.get(0).getFileName().orNull();
|
||||||
|
if (!TextUtils.isEmpty(filename)) {
|
||||||
|
mediaDescriptionText.setTypeface(null, Typeface.NORMAL);
|
||||||
|
mediaDescriptionText.setText(filename);
|
||||||
|
} else {
|
||||||
|
mediaDescriptionText.setText(R.string.QuoteView_document);
|
||||||
|
}
|
||||||
|
} else if (!videoSlides.isEmpty()) {
|
||||||
|
mediaDescriptionText.setText(R.string.QuoteView_video);
|
||||||
|
} else if (!imageSlides.isEmpty()) {
|
||||||
|
mediaDescriptionText.setText(R.string.QuoteView_photo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setQuoteAttachment(@NonNull GlideRequests glideRequests, @NonNull SlideDeck slideDeck) {
|
private void setQuoteAttachment(@NonNull GlideRequests glideRequests,
|
||||||
|
@NonNull SlideDeck slideDeck,
|
||||||
|
@NonNull Recipient author)
|
||||||
|
{
|
||||||
List<Slide> imageVideoSlides = Stream.of(slideDeck.getSlides()).filter(s -> s.hasImage() || s.hasVideo()).limit(1).toList();
|
List<Slide> imageVideoSlides = Stream.of(slideDeck.getSlides()).filter(s -> s.hasImage() || s.hasVideo()).limit(1).toList();
|
||||||
|
List<Slide> audioSlides = Stream.of(attachments.getSlides()).filter(Slide::hasAudio).limit(1).toList();
|
||||||
|
List<Slide> documentSlides = Stream.of(attachments.getSlides()).filter(Slide::hasDocument).limit(1).toList();
|
||||||
|
|
||||||
|
attachmentVideoOverlayView.setVisibility(GONE);
|
||||||
|
|
||||||
if (!imageVideoSlides.isEmpty() && imageVideoSlides.get(0).getThumbnailUri() != null) {
|
if (!imageVideoSlides.isEmpty() && imageVideoSlides.get(0).getThumbnailUri() != null) {
|
||||||
attachmentView.setVisibility(View.VISIBLE);
|
attachmentView.setVisibility(VISIBLE);
|
||||||
dismissView.setBackgroundResource(R.drawable.circle_alpha);
|
attachmentIconContainerView.setVisibility(GONE);
|
||||||
|
dismissView.setBackgroundResource(R.drawable.dismiss_background);
|
||||||
|
if (imageVideoSlides.get(0).hasVideo()) {
|
||||||
|
attachmentVideoOverlayView.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
glideRequests.load(new DecryptableUri(imageVideoSlides.get(0).getThumbnailUri()))
|
glideRequests.load(new DecryptableUri(imageVideoSlides.get(0).getThumbnailUri()))
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.into(attachmentView);
|
.into(attachmentView);
|
||||||
|
} else if (!audioSlides.isEmpty() || !documentSlides.isEmpty()){
|
||||||
|
boolean outgoing = messageType != MESSAGE_TYPE_INCOMING;
|
||||||
|
|
||||||
|
dismissView.setBackgroundResource(R.drawable.circle_alpha);
|
||||||
|
attachmentView.setVisibility(GONE);
|
||||||
|
attachmentIconContainerView.setVisibility(VISIBLE);
|
||||||
|
|
||||||
|
if (!audioSlides.isEmpty()) {
|
||||||
|
attachmentIconView.setImageResource(R.drawable.ic_mic_white_48dp);
|
||||||
|
} else {
|
||||||
|
attachmentIconView.setImageResource(R.drawable.ic_insert_drive_file_white_24dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentIconView.setColorFilter(author.getColor().toQuoteIconForegroundColor(getContext(), outgoing), PorterDuff.Mode.SRC_IN);
|
||||||
|
attachmentIconBackgroundView.setColorFilter(author.getColor().toQuoteIconBackgroundColor(getContext(), outgoing), PorterDuff.Mode.SRC_IN);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
attachmentView.setVisibility(View.GONE);
|
attachmentView.setVisibility(GONE);
|
||||||
|
attachmentIconContainerView.setVisibility(GONE);
|
||||||
dismissView.setBackgroundDrawable(null);
|
dismissView.setBackgroundDrawable(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,8 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
|||||||
import org.thoughtcrime.securesms.mms.MediaStream;
|
import org.thoughtcrime.securesms.mms.MediaStream;
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||||
|
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||||
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil.ThumbnailData;
|
import org.thoughtcrime.securesms.util.MediaUtil.ThumbnailData;
|
||||||
@ -313,13 +315,20 @@ public class AttachmentDatabase extends Database {
|
|||||||
public void insertAttachmentsForPlaceholder(long mmsId, @NonNull AttachmentId attachmentId, @NonNull InputStream inputStream)
|
public void insertAttachmentsForPlaceholder(long mmsId, @NonNull AttachmentId attachmentId, @NonNull InputStream inputStream)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
DatabaseAttachment placeholder = getAttachment(attachmentId);
|
||||||
DataInfo dataInfo = setAttachmentData(inputStream);
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
DataInfo dataInfo = setAttachmentData(inputStream);
|
||||||
|
|
||||||
|
if (placeholder != null && placeholder.isQuote() && !placeholder.getContentType().startsWith("image")) {
|
||||||
|
values.put(THUMBNAIL, dataInfo.file.getAbsolutePath());
|
||||||
|
values.put(THUMBNAIL_RANDOM, dataInfo.random);
|
||||||
|
} else {
|
||||||
|
values.put(DATA, dataInfo.file.getAbsolutePath());
|
||||||
|
values.put(SIZE, dataInfo.length);
|
||||||
|
values.put(DATA_RANDOM, dataInfo.random);
|
||||||
|
}
|
||||||
|
|
||||||
values.put(DATA, dataInfo.file.getAbsolutePath());
|
|
||||||
values.put(SIZE, dataInfo.length);
|
|
||||||
values.put(DATA_RANDOM, dataInfo.random);
|
|
||||||
values.put(TRANSFER_STATE, TRANSFER_PROGRESS_DONE);
|
values.put(TRANSFER_STATE, TRANSFER_PROGRESS_DONE);
|
||||||
values.put(CONTENT_LOCATION, (String)null);
|
values.put(CONTENT_LOCATION, (String)null);
|
||||||
values.put(CONTENT_DISPOSITION, (String)null);
|
values.put(CONTENT_DISPOSITION, (String)null);
|
||||||
@ -635,8 +644,22 @@ public class AttachmentDatabase extends Database {
|
|||||||
|
|
||||||
long rowId = database.insert(TABLE_NAME, null, contentValues);
|
long rowId = database.insert(TABLE_NAME, null, contentValues);
|
||||||
AttachmentId attachmentId = new AttachmentId(rowId, uniqueId);
|
AttachmentId attachmentId = new AttachmentId(rowId, uniqueId);
|
||||||
|
Uri thumbnailUri = attachment.getThumbnailUri();
|
||||||
|
boolean hasThumbnail = false;
|
||||||
|
|
||||||
if (dataInfo != null) {
|
if (thumbnailUri != null) {
|
||||||
|
try (InputStream attachmentStream = PartAuthority.getAttachmentStream(context, thumbnailUri)) {
|
||||||
|
Pair<Integer, Integer> dimens = BitmapUtil.getDimensions(attachmentStream);
|
||||||
|
updateAttachmentThumbnail(attachmentId,
|
||||||
|
PartAuthority.getAttachmentStream(context, thumbnailUri),
|
||||||
|
(float) dimens.first / (float) dimens.second);
|
||||||
|
hasThumbnail = true;
|
||||||
|
} catch (IOException | BitmapDecodingException e) {
|
||||||
|
Log.w(TAG, "Failed to save existing thumbnail.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasThumbnail && dataInfo != null) {
|
||||||
if (MediaUtil.hasVideoThumbnail(attachment.getDataUri())) {
|
if (MediaUtil.hasVideoThumbnail(attachment.getDataUri())) {
|
||||||
Bitmap bitmap = MediaUtil.getVideoThumbnail(context, attachment.getDataUri());
|
Bitmap bitmap = MediaUtil.getVideoThumbnail(context, attachment.getDataUri());
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import net.sqlcipher.database.SQLiteQueryBuilder;
|
|||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -140,6 +141,26 @@ public class MmsSmsDatabase extends Database {
|
|||||||
DatabaseFactory.getMmsDatabase(context).incrementReceiptCount(syncMessageId, timestamp, false, true);
|
DatabaseFactory.getMmsDatabase(context).incrementReceiptCount(syncMessageId, timestamp, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getQuotedMessagePosition(long threadId, long quoteId, @NonNull Address address) {
|
||||||
|
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||||
|
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
|
||||||
|
|
||||||
|
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_SENT, MmsSmsColumns.ADDRESS }, selection, order, null)) {
|
||||||
|
String serializedAddress = address.serialize();
|
||||||
|
boolean isOwnNumber = Util.isOwnNumber(context, address);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
boolean quoteIdMatches = cursor.getLong(0) == quoteId;
|
||||||
|
boolean addressMatches = serializedAddress.equals(cursor.getString(1));
|
||||||
|
|
||||||
|
if (quoteIdMatches && (addressMatches || isOwnNumber)) {
|
||||||
|
return cursor.getPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
private Cursor queryTables(String[] projection, String selection, String order, String limit) {
|
private Cursor queryTables(String[] projection, String selection, String order, String limit) {
|
||||||
String[] mmsProjection = {MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
String[] mmsProjection = {MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||||
MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||||
|
@ -43,8 +43,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
private static final int MIGRATE_SESSIONS_VERSION = 4;
|
private static final int MIGRATE_SESSIONS_VERSION = 4;
|
||||||
private static final int NO_MORE_IMAGE_THUMBNAILS_VERSION = 5;
|
private static final int NO_MORE_IMAGE_THUMBNAILS_VERSION = 5;
|
||||||
private static final int ATTACHMENT_DIMENSIONS = 6;
|
private static final int ATTACHMENT_DIMENSIONS = 6;
|
||||||
|
private static final int QUOTED_REPLIES = 7;
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = 6;
|
private static final int DATABASE_VERSION = 7;
|
||||||
private static final String DATABASE_NAME = "signal.db";
|
private static final String DATABASE_NAME = "signal.db";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@ -167,6 +168,15 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL("ALTER TABLE part ADD COLUMN height INTEGER DEFAULT 0");
|
db.execSQL("ALTER TABLE part ADD COLUMN height INTEGER DEFAULT 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < QUOTED_REPLIES) {
|
||||||
|
db.execSQL("ALTER TABLE mms ADD COLUMN quote_id INTEGER DEFAULT 0");
|
||||||
|
db.execSQL("ALTER TABLE mms ADD COLUMN quote_author TEXT");
|
||||||
|
db.execSQL("ALTER TABLE mms ADD COLUMN quote_body TEXT");
|
||||||
|
db.execSQL("ALTER TABLE mms ADD COLUMN quote_attachment INTEGER DEFAULT -1");
|
||||||
|
|
||||||
|
db.execSQL("ALTER TABLE part ADD COLUMN quote INTEGER DEFAULT 0");
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
@ -38,11 +38,11 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
|||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
|
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
|
||||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.QuoteModel;
|
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
||||||
|
import org.thoughtcrime.securesms.mms.QuoteModel;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
@ -894,7 +894,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
return Optional.of(new QuoteModel(quote.get().getId(),
|
return Optional.of(new QuoteModel(quote.get().getId(),
|
||||||
author,
|
author,
|
||||||
quote.get().getText(),
|
quote.get().getText(),
|
||||||
PointerAttachment.forPointers(Optional.of(quote.get().getAttachments()))));
|
PointerAttachment.forPointers(quote.get().getAttachments())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<InsertResult> insertPlaceholder(@NonNull SignalServiceEnvelope envelope) {
|
private Optional<InsertResult> insertPlaceholder(@NonNull SignalServiceEnvelope envelope) {
|
||||||
|
@ -28,6 +28,7 @@ import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
|||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
||||||
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
|
||||||
@ -120,34 +121,35 @@ public abstract class PushSendJob extends SendJob {
|
|||||||
protected Optional<SignalServiceDataMessage.Quote> getQuoteFor(OutgoingMediaMessage message) {
|
protected Optional<SignalServiceDataMessage.Quote> getQuoteFor(OutgoingMediaMessage message) {
|
||||||
if (message.getOutgoingQuote() == null) return Optional.absent();
|
if (message.getOutgoingQuote() == null) return Optional.absent();
|
||||||
|
|
||||||
long quoteId = message.getOutgoingQuote().getId();
|
long quoteId = message.getOutgoingQuote().getId();
|
||||||
String quoteBody = message.getOutgoingQuote().getText();
|
String quoteBody = message.getOutgoingQuote().getText();
|
||||||
Address quoteAuthor = message.getOutgoingQuote().getAuthor();
|
Address quoteAuthor = message.getOutgoingQuote().getAuthor();
|
||||||
List<SignalServiceAttachment> quoteAttachments = new LinkedList<>();
|
List<SignalServiceDataMessage.Quote.QuotedAttachment> quoteAttachments = new LinkedList<>();
|
||||||
|
|
||||||
for (Attachment attachment : message.getOutgoingQuote().getAttachments()) {
|
for (Attachment attachment : message.getOutgoingQuote().getAttachments()) {
|
||||||
BitmapUtil.ScaleResult attachmentData = null;
|
BitmapUtil.ScaleResult thumbnailData = null;
|
||||||
|
SignalServiceAttachment thumbnail = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (MediaUtil.isImageType(attachment.getContentType()) && attachment.getDataUri() != null) {
|
if (MediaUtil.isImageType(attachment.getContentType()) && attachment.getDataUri() != null) {
|
||||||
attachmentData = BitmapUtil.createScaledBytes(context, new DecryptableStreamUriLoader.DecryptableUri(attachment.getDataUri()), 100, 100, 500 * 1024);
|
thumbnailData = BitmapUtil.createScaledBytes(context, new DecryptableStreamUriLoader.DecryptableUri(attachment.getDataUri()), 100, 100, 500 * 1024);
|
||||||
} else if (MediaUtil.isVideoType(attachment.getContentType()) && attachment.getThumbnailUri() != null) {
|
} else if (MediaUtil.isVideoType(attachment.getContentType()) && attachment.getThumbnailUri() != null) {
|
||||||
attachmentData = BitmapUtil.createScaledBytes(context, new DecryptableStreamUriLoader.DecryptableUri(attachment.getThumbnailUri()), 100, 100, 500 * 1024);
|
thumbnailData = BitmapUtil.createScaledBytes(context, new DecryptableStreamUriLoader.DecryptableUri(attachment.getThumbnailUri()), 100, 100, 500 * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachmentData != null) {
|
if (thumbnailData != null) {
|
||||||
quoteAttachments.add(SignalServiceAttachment.newStreamBuilder()
|
thumbnail = SignalServiceAttachment.newStreamBuilder()
|
||||||
.withContentType("image/jpeg")
|
.withContentType("image/jpeg")
|
||||||
.withFileName(attachment.getFileName())
|
.withWidth(thumbnailData.getWidth())
|
||||||
.withHeight(attachmentData.getHeight())
|
.withHeight(thumbnailData.getHeight())
|
||||||
.withWidth(attachmentData.getWidth())
|
.withLength(thumbnailData.getBitmap().length)
|
||||||
.withLength(attachmentData.getBitmap().length)
|
.withStream(new ByteArrayInputStream(thumbnailData.getBitmap()))
|
||||||
.withStream(new ByteArrayInputStream(attachmentData.getBitmap()))
|
.build();
|
||||||
.build());
|
|
||||||
} else {
|
|
||||||
quoteAttachments.add(new SignalServiceAttachmentPointer(0, attachment.getContentType(), null, null, Optional.absent(), Optional.absent(), 0, 0, Optional.absent(), Optional.fromNullable(attachment.getFileName()), attachment.isVoiceNote()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quoteAttachments.add(new SignalServiceDataMessage.Quote.QuotedAttachment(attachment.getContentType(),
|
||||||
|
attachment.getFileName(),
|
||||||
|
thumbnail));
|
||||||
} catch (BitmapDecodingException e) {
|
} catch (BitmapDecodingException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user