mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 16:57:50 +00:00
Added support for multi-image receive.
This commit is contained in:
parent
e665252b86
commit
47a10a0288
BIN
res/drawable-hdpi/ic_caption.png
Normal file
BIN
res/drawable-hdpi/ic_caption.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 661 B |
BIN
res/drawable-mdpi/ic_caption.png
Normal file
BIN
res/drawable-mdpi/ic_caption.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 336 B |
BIN
res/drawable-xhdpi/ic_caption.png
Normal file
BIN
res/drawable-xhdpi/ic_caption.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 725 B |
BIN
res/drawable-xxhdpi/ic_caption.png
Normal file
BIN
res/drawable-xxhdpi/ic_caption.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
res/drawable-xxxhdpi/ic_caption.png
Normal file
BIN
res/drawable-xxxhdpi/ic_caption.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
5
res/drawable/album_rail_item_background.xml
Normal file
5
res/drawable/album_rail_item_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="rectangle" >
|
||||
<solid android:color="@color/signal_primary"/>
|
||||
<corners android:radius="2dp"/>
|
||||
</shape>
|
@ -1,14 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.exoplayer2.ui.PlayerView
|
||||
android:id="@+id/video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"/>
|
||||
android:id="@+id/video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
app:player_layout_id="@layout/media_preview_exoplayer_layout"/>
|
||||
|
||||
</FrameLayout>
|
23
res/layout/album_thumbnail_2.xml
Normal file
23
res/layout/album_thumbnail_2.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/album_thumbnail_root"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="150dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_1"
|
||||
android:layout_height="150dp"
|
||||
android:layout_width="149dp"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_2"
|
||||
android:layout_height="150dp"
|
||||
android:layout_width="149dp"
|
||||
android:layout_gravity="right|end"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
</FrameLayout>
|
29
res/layout/album_thumbnail_3.xml
Normal file
29
res/layout/album_thumbnail_3.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/album_thumbnail_root"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="200dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_1"
|
||||
android:layout_height="200dp"
|
||||
android:layout_width="199dp"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_2"
|
||||
android:layout_height="99dp"
|
||||
android:layout_width="99dp"
|
||||
android:layout_gravity="right|end|top"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_3"
|
||||
android:layout_height="99dp"
|
||||
android:layout_width="99dp"
|
||||
android:layout_gravity="right|end|bottom"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
</FrameLayout>
|
36
res/layout/album_thumbnail_4.xml
Normal file
36
res/layout/album_thumbnail_4.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/album_thumbnail_root"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="300dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_1"
|
||||
android:layout_height="149dp"
|
||||
android:layout_width="149dp"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_2"
|
||||
android:layout_height="149dp"
|
||||
android:layout_width="149dp"
|
||||
android:layout_gravity="right|end|top"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_3"
|
||||
android:layout_height="149dp"
|
||||
android:layout_width="149dp"
|
||||
android:layout_gravity="left|start|bottom"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_4"
|
||||
android:layout_height="149dp"
|
||||
android:layout_width="149dp"
|
||||
android:layout_gravity="right|end|bottom"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
</FrameLayout>
|
43
res/layout/album_thumbnail_5.xml
Normal file
43
res/layout/album_thumbnail_5.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/album_thumbnail_root"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="250dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_1"
|
||||
android:layout_height="149dp"
|
||||
android:layout_width="149dp"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_2"
|
||||
android:layout_height="149dp"
|
||||
android:layout_width="149dp"
|
||||
android:layout_gravity="right|end|top"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_3"
|
||||
android:layout_height="99dp"
|
||||
android:layout_width="99dp"
|
||||
android:layout_gravity="left|start|bottom"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_4"
|
||||
android:layout_height="99dp"
|
||||
android:layout_width="99dp"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_5"
|
||||
android:layout_height="99dp"
|
||||
android:layout_width="99dp"
|
||||
android:layout_gravity="right|end|bottom"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
</FrameLayout>
|
61
res/layout/album_thumbnail_many.xml
Normal file
61
res/layout/album_thumbnail_many.xml
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
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/album_thumbnail_root"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="250dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_1"
|
||||
android:layout_height="149dp"
|
||||
android:layout_width="149dp"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_2"
|
||||
android:layout_height="149dp"
|
||||
android:layout_width="149dp"
|
||||
android:layout_gravity="right|end|top"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_3"
|
||||
android:layout_height="99dp"
|
||||
android:layout_width="99dp"
|
||||
android:layout_gravity="left|start|bottom"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_4"
|
||||
android:layout_height="99dp"
|
||||
android:layout_width="99dp"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="99dp"
|
||||
android:layout_height="99dp"
|
||||
android:layout_gravity="right|end|bottom">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/album_cell_5"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
app:thumbnail_radius="0dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/album_cell_overflow_text"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:gravity="center"
|
||||
android:textSize="28dp"
|
||||
android:textColor="@color/core_white"
|
||||
android:background="@color/transparent_black_40"
|
||||
tools:text="+2" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
21
res/layout/album_thumbnail_view.xml
Normal file
21
res/layout/album_thumbnail_view.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/album_cell_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?conversation_background"/>
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/album_transfer_controls_stub"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout="@layout/transfer_controls_stub" />
|
||||
|
||||
</merge>
|
@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
android:id="@+id/conversation_thumbnail_image"
|
||||
@ -12,8 +13,19 @@
|
||||
android:longClickable="false"
|
||||
android:scaleType="fitCenter"
|
||||
android:contentDescription="@string/conversation_item__mms_image_description"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
app:thumbnail_radius="1dp"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.AlbumThumbnailView
|
||||
android:id="@+id/conversation_thumbnail_album"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="false"
|
||||
android:longClickable="false"
|
||||
android:contentDescription="@string/conversation_item__mms_image_description"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/conversation_thumbnail_shade"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -1,13 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/gray95">
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/gray95">
|
||||
|
||||
<org.thoughtcrime.securesms.components.viewpager.HackyViewPager
|
||||
android:id="@+id/media_pager"
|
||||
android:id="@+id/media_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/media_preview_details_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/image_shade"
|
||||
android:gravity="bottom"
|
||||
android:visibility="gone"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<org.thoughtcrime.securesms.components.MaxHeightScrollView
|
||||
android:id="@+id/media_preview_caption_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="32dp"
|
||||
android:animateLayoutChanges="true"
|
||||
app:scrollView_maxHeight="120dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/media_preview_caption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:textColor="@color/core_white"
|
||||
android:gravity="bottom"
|
||||
tools:text="With great power comes great responsibility." />
|
||||
|
||||
</org.thoughtcrime.securesms.components.MaxHeightScrollView>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/media_preview_album_rail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
tools:layout_height="64dp"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/media_preview_playback_controls_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
12
res/layout/media_preview_album_rail_item.xml
Normal file
12
res/layout/media_preview_album_rail_item.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ThumbnailView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/rail_item_image"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48sp"
|
||||
android:layout_margin="2dp"
|
||||
android:padding="2dp"
|
||||
android:background="@drawable/album_rail_item_background"
|
||||
app:thumbnail_radius="2dp"/>
|
13
res/layout/media_preview_exoplayer_layout.xml
Normal file
13
res/layout/media_preview_exoplayer_layout.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||
android:id="@+id/exo_content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</FrameLayout>
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
@ -8,6 +9,7 @@
|
||||
android:id="@+id/image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="false"
|
||||
android:contentDescription="@string/media_preview_activity__media_content_description" />
|
||||
|
||||
<ViewStub android:id="@+id/video_player_stub"
|
||||
|
@ -14,6 +14,14 @@
|
||||
android:scaleType="fitCenter"
|
||||
android:contentDescription="@string/conversation_item__mms_image_description" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail_caption_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="6dp"
|
||||
android:src="@drawable/ic_caption"
|
||||
android:visibility="gone" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/play_overlay"
|
||||
android:layout_width="48dp"
|
||||
|
@ -12,15 +12,30 @@
|
||||
app:matProg_linearProgress="true"
|
||||
app:matProg_spinSpeed="0.333" />
|
||||
|
||||
<TextView android:id="@+id/download_details"
|
||||
android:layout_width="@dimen/transfer_controls_expanded_width"
|
||||
android:layout_height="@dimen/transfer_controls_contracted_width"
|
||||
android:padding="15dp"
|
||||
android:gravity="center"
|
||||
android:longClickable="false"
|
||||
android:textColor="?conversation_item_received_text_primary_color"
|
||||
android:drawableLeft="@drawable/ic_file_download_white_36dp"
|
||||
android:textSize="16dp"
|
||||
android:visibility="gone"
|
||||
android:textStyle="bold" />
|
||||
<LinearLayout
|
||||
android:id="@+id/download_details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_file_download_white_36dp"/>
|
||||
|
||||
<TextView android:id="@+id/download_details_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="15dp"
|
||||
android:gravity="center"
|
||||
android:longClickable="false"
|
||||
android:textColor="?conversation_item_received_text_primary_color"
|
||||
android:textSize="16dp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
||||
|
@ -86,6 +86,7 @@
|
||||
<attr name="conversation_item_quote_text_color" format="reference"/>
|
||||
<attr name="conversation_item_sticky_date_background" format="reference" />
|
||||
<attr name="conversation_item_sticky_date_text_color" format="color" />
|
||||
<attr name="conversation_item_image_outline_color" format="color" />
|
||||
|
||||
<attr name="dialog_info_icon" format="reference" />
|
||||
<attr name="dialog_alert_icon" format="reference" />
|
||||
@ -300,4 +301,8 @@
|
||||
<attr name="typingIndicator_tint" format="color" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="MaxHeightScrollView">
|
||||
<attr name="scrollView_maxHeight" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
@ -10,6 +10,9 @@
|
||||
<!-- AbstractNotificationBuilder -->
|
||||
<string name="AbstractNotificationBuilder_new_message">New message</string>
|
||||
|
||||
<!-- AlbumThumbnailView -->
|
||||
<string name="AlbumThumbnailView_plus">\+%d</string>
|
||||
|
||||
<!-- ApplicationPreferencesActivity -->
|
||||
<string name="ApplicationPreferencesActivity_currently_s">Currently: %s</string>
|
||||
<string name="ApplicationPreferenceActivity_you_havent_set_a_passphrase_yet">You haven\'t set a passphrase yet!</string>
|
||||
@ -734,6 +737,12 @@
|
||||
<string name="SingleRecipientNotificationBuilder_signal">Signal</string>
|
||||
<string name="SingleRecipientNotificationBuilder_new_message">New message</string>
|
||||
|
||||
<!-- TransferControlView -->
|
||||
<plurals name="TransferControlView_n_items">
|
||||
<item quantity="one">%d Item</item>
|
||||
<item quantity="other">%d Items</item>
|
||||
</plurals>
|
||||
|
||||
<!-- UnauthorizedReminder -->
|
||||
<string name="UnauthorizedReminder_device_no_longer_registered">Device no longer registered</string>
|
||||
<string name="UnauthorizedReminder_this_is_likely_because_you_registered_your_phone_number_with_Signal_on_a_different_device">This is likely because you registered your phone number with Signal on a different device. Tap to re-register.</string>
|
||||
|
@ -204,6 +204,7 @@
|
||||
<item name="conversation_item_quote_text_color">@color/core_grey_90</item>
|
||||
<item name="conversation_item_sticky_date_background">@drawable/sticky_date_header_background_light</item>
|
||||
<item name="conversation_item_sticky_date_text_color">@color/core_grey_60</item>
|
||||
<item name="conversation_item_image_outline_color">@color/transparent_black_30</item>
|
||||
|
||||
<item name="quick_camera_icon">@drawable/quick_camera_light</item>
|
||||
<item name="quick_mic_icon">@drawable/ic_mic_grey600_24dp</item>
|
||||
@ -311,6 +312,7 @@
|
||||
<item name="conversation_item_quote_text_color">@color/core_grey_05</item>
|
||||
<item name="conversation_item_sticky_date_background">@drawable/sticky_date_header_background_dark</item>
|
||||
<item name="conversation_item_sticky_date_text_color">@color/core_grey_25</item>
|
||||
<item name="conversation_item_image_outline_color">@color/transparent_white_30</item>
|
||||
|
||||
<item name="contact_list_divider">@drawable/contact_list_divider_dark</item>
|
||||
|
||||
|
@ -42,7 +42,6 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
import org.thoughtcrime.securesms.components.AlertView;
|
||||
import org.thoughtcrime.securesms.components.AudioView;
|
||||
@ -53,7 +52,6 @@ import org.thoughtcrime.securesms.components.DocumentView;
|
||||
import org.thoughtcrime.securesms.components.QuoteView;
|
||||
import org.thoughtcrime.securesms.components.SharedContactView;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
@ -71,6 +69,7 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideClickListener;
|
||||
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
@ -83,6 +82,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.views.Stub;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -132,10 +132,11 @@ public class ConversationItem extends LinearLayout
|
||||
private int defaultBubbleColor;
|
||||
private int measureCalls;
|
||||
|
||||
private final PassthroughClickListener passthroughClickListener = new PassthroughClickListener();
|
||||
private final AttachmentDownloadClickListener downloadClickListener = new AttachmentDownloadClickListener();
|
||||
private final SharedContactEventListener sharedContactEventListener = new SharedContactEventListener();
|
||||
private final SharedContactClickListener sharedContactClickListener = new SharedContactClickListener();
|
||||
private final PassthroughClickListener passthroughClickListener = new PassthroughClickListener();
|
||||
private final AttachmentDownloadClickListener downloadClickListener = new AttachmentDownloadClickListener();
|
||||
private final SlideClickPassthroughListener singleDownloadClickListener = new SlideClickPassthroughListener(downloadClickListener);
|
||||
private final SharedContactEventListener sharedContactEventListener = new SharedContactEventListener();
|
||||
private final SharedContactClickListener sharedContactClickListener = new SharedContactClickListener();
|
||||
|
||||
private final Context context;
|
||||
|
||||
@ -427,7 +428,7 @@ public class ConversationItem extends LinearLayout
|
||||
|
||||
//noinspection ConstantConditions
|
||||
audioViewStub.get().setAudio(((MediaMmsMessageRecord) messageRecord).getSlideDeck().getAudioSlide(), showControls);
|
||||
audioViewStub.get().setDownloadClickListener(downloadClickListener);
|
||||
audioViewStub.get().setDownloadClickListener(singleDownloadClickListener);
|
||||
audioViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@ -442,7 +443,7 @@ public class ConversationItem extends LinearLayout
|
||||
//noinspection ConstantConditions
|
||||
documentViewStub.get().setDocument(((MediaMmsMessageRecord)messageRecord).getSlideDeck().getDocumentSlide(), showControls);
|
||||
documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
|
||||
documentViewStub.get().setDownloadClickListener(downloadClickListener);
|
||||
documentViewStub.get().setDownloadClickListener(singleDownloadClickListener);
|
||||
documentViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@ -455,19 +456,18 @@ public class ConversationItem extends LinearLayout
|
||||
if (sharedContactStub.resolved()) sharedContactStub.get().setVisibility(GONE);
|
||||
|
||||
//noinspection ConstantConditions
|
||||
Slide thumbnailSlide = ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlide();
|
||||
Attachment attachment = thumbnailSlide.asAttachment();
|
||||
List<Slide> thumbnailSlides = ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlides();
|
||||
mediaThumbnailStub.get().setImageResource(glideRequests,
|
||||
thumbnailSlide,
|
||||
thumbnailSlides,
|
||||
showControls,
|
||||
false,
|
||||
attachment.getWidth(),
|
||||
attachment.getHeight());
|
||||
false);
|
||||
mediaThumbnailStub.get().setThumbnailClickListener(new ThumbnailClickListener());
|
||||
mediaThumbnailStub.get().setDownloadClickListener(downloadClickListener);
|
||||
mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getDisplayBody()));
|
||||
mediaThumbnailStub.get().setConversationColor(messageRecord.isOutgoing() ? defaultBubbleColor
|
||||
: messageRecord.getRecipient().getColor().toConversationColor(context));
|
||||
|
||||
setThumbnailOutlineCorners(messageRecord, previousRecord, nextRecord, isGroupThread);
|
||||
|
||||
@ -847,9 +847,9 @@ public class ConversationItem extends LinearLayout
|
||||
}
|
||||
}
|
||||
|
||||
private class AttachmentDownloadClickListener implements SlideClickListener {
|
||||
private class AttachmentDownloadClickListener implements SlidesClickedListener {
|
||||
@Override
|
||||
public void onClick(View v, final Slide slide) {
|
||||
public void onClick(View v, final List<Slide> slides) {
|
||||
Log.i(TAG, "onClick() for attachment download");
|
||||
if (messageRecord.isMmsNotification()) {
|
||||
Log.i(TAG, "Scheduling MMS attachment download");
|
||||
@ -858,19 +858,32 @@ public class ConversationItem extends LinearLayout
|
||||
.add(new MmsDownloadJob(context, messageRecord.getId(),
|
||||
messageRecord.getThreadId(), false));
|
||||
} else {
|
||||
Log.i(TAG, "Scheduling push attachment download");
|
||||
DatabaseFactory.getAttachmentDatabase(context).setTransferState(messageRecord.getId(),
|
||||
slide.asAttachment(),
|
||||
AttachmentDatabase.TRANSFER_PROGRESS_STARTED);
|
||||
Log.i(TAG, "Scheduling push attachment downloads for " + slides.size() + " items");
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(context, messageRecord.getId(),
|
||||
((DatabaseAttachment)slide.asAttachment()).getAttachmentId(), true));
|
||||
for (Slide slide : slides) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(context, messageRecord.getId(),
|
||||
((DatabaseAttachment)slide.asAttachment()).getAttachmentId(), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SlideClickPassthroughListener implements SlideClickListener {
|
||||
|
||||
private final SlidesClickedListener original;
|
||||
|
||||
private SlideClickPassthroughListener(@NonNull SlidesClickedListener original) {
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v, Slide slide) {
|
||||
original.onClick(v, Collections.singletonList(slide));
|
||||
}
|
||||
}
|
||||
|
||||
private class ThumbnailClickListener implements SlideClickListener {
|
||||
public void onClick(final View v, final Slide slide) {
|
||||
if (shouldInterceptClicks(messageRecord) || !batchSelected.isEmpty()) {
|
||||
@ -883,6 +896,7 @@ public class ConversationItem extends LinearLayout
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, messageRecord.isOutgoing());
|
||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, messageRecord.getTimestamp());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize());
|
||||
intent.putExtra(MediaPreviewActivity.CAPTION_EXTRA, slide.getCaption().orNull());
|
||||
intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, false);
|
||||
|
||||
context.startActivity(intent);
|
||||
|
@ -19,6 +19,7 @@ package org.thoughtcrime.securesms;
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.arch.lifecycle.ViewModelProviders;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
@ -36,15 +37,21 @@ import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
@ -53,6 +60,8 @@ import org.thoughtcrime.securesms.components.viewpager.ExtendedOnPageChangedList
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||
import org.thoughtcrime.securesms.database.loaders.PagingMediaLoader;
|
||||
import org.thoughtcrime.securesms.mediapreview.AlbumRailAdapter;
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaPreviewViewModel;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
@ -71,33 +80,49 @@ import java.util.WeakHashMap;
|
||||
/**
|
||||
* Activity for displaying media attachments in-app
|
||||
*/
|
||||
public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener, LoaderManager.LoaderCallbacks<Pair<Cursor, Integer>> {
|
||||
public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener,
|
||||
LoaderManager.LoaderCallbacks<Pair<Cursor, Integer>>,
|
||||
AlbumRailAdapter.RailItemClickedListener
|
||||
{
|
||||
|
||||
private final static String TAG = MediaPreviewActivity.class.getSimpleName();
|
||||
|
||||
public static final String ADDRESS_EXTRA = "address";
|
||||
public static final String DATE_EXTRA = "date";
|
||||
public static final String SIZE_EXTRA = "size";
|
||||
public static final String CAPTION_EXTRA = "caption";
|
||||
public static final String OUTGOING_EXTRA = "outgoing";
|
||||
public static final String LEFT_IS_RECENT_EXTRA = "left_is_recent";
|
||||
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
|
||||
private ViewPager mediaPager;
|
||||
private Uri initialMediaUri;
|
||||
private String initialMediaType;
|
||||
private long initialMediaSize;
|
||||
private Recipient conversationRecipient;
|
||||
private boolean leftIsRecent;
|
||||
private ViewPager mediaPager;
|
||||
private View detailsContainer;
|
||||
private TextView caption;
|
||||
private View captionContainer;
|
||||
private RecyclerView albumRail;
|
||||
private AlbumRailAdapter albumRailAdapter;
|
||||
private ViewGroup playbackControlsContainer;
|
||||
private Uri initialMediaUri;
|
||||
private String initialMediaType;
|
||||
private long initialMediaSize;
|
||||
private String initialCaption;
|
||||
private Recipient conversationRecipient;
|
||||
private boolean leftIsRecent;
|
||||
private GestureDetector clickDetector;
|
||||
private MediaPreviewViewModel viewModel;
|
||||
|
||||
private int restartItem = -1;
|
||||
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle, boolean ready) {
|
||||
this.setTheme(R.style.TextSecure_DarkTheme);
|
||||
dynamicLanguage.onCreate(this);
|
||||
|
||||
viewModel = ViewModelProviders.of(this).get(MediaPreviewViewModel.class);
|
||||
|
||||
setFullscreenIfPossible();
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
@ -107,6 +132,13 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
|
||||
initializeViews();
|
||||
initializeResources();
|
||||
initializeObservers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
clickDetector.onTouchEvent(ev);
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,6 +158,11 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
Util.runOnMain(this::initializeActionBar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRailItemClicked(int distanceFromActive) {
|
||||
mediaPager.setCurrentItem(mediaPager.getCurrentItem() + distanceFromActive);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private void initializeActionBar() {
|
||||
MediaItem mediaItem = getCurrentMediaItem();
|
||||
@ -172,6 +209,17 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
mediaPager = findViewById(R.id.media_pager);
|
||||
mediaPager.setOffscreenPageLimit(1);
|
||||
mediaPager.addOnPageChangeListener(new ViewPagerListener());
|
||||
|
||||
albumRail = findViewById(R.id.media_preview_album_rail);
|
||||
albumRailAdapter = new AlbumRailAdapter(GlideApp.with(this), this);
|
||||
|
||||
albumRail.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
|
||||
albumRail.setAdapter(albumRailAdapter);
|
||||
|
||||
detailsContainer = findViewById(R.id.media_preview_details_container);
|
||||
caption = findViewById(R.id.media_preview_caption);
|
||||
captionContainer = findViewById(R.id.media_preview_caption_container);
|
||||
playbackControlsContainer = findViewById(R.id.media_preview_playback_controls_container);
|
||||
}
|
||||
|
||||
private void initializeResources() {
|
||||
@ -180,6 +228,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
initialMediaUri = getIntent().getData();
|
||||
initialMediaType = getIntent().getType();
|
||||
initialMediaSize = getIntent().getLongExtra(SIZE_EXTRA, 0);
|
||||
initialCaption = getIntent().getStringExtra(CAPTION_EXTRA);
|
||||
leftIsRecent = getIntent().getBooleanExtra(LEFT_IS_RECENT_EXTRA, false);
|
||||
restartItem = -1;
|
||||
|
||||
@ -190,6 +239,49 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeObservers() {
|
||||
viewModel.getPreviewData().observe(this, previewData -> {
|
||||
if (previewData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
View playbackControls = ((MediaItemAdapter) mediaPager.getAdapter()).getPlaybackControls(mediaPager.getCurrentItem());
|
||||
|
||||
if (previewData.getAlbumThumbnails().isEmpty() && previewData.getCaption() == null && playbackControls == null) {
|
||||
detailsContainer.setVisibility(View.GONE);
|
||||
} else {
|
||||
detailsContainer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
albumRail.setVisibility(previewData.getAlbumThumbnails().isEmpty() ? View.GONE : View.VISIBLE);
|
||||
albumRailAdapter.setRecords(previewData.getAlbumThumbnails(), previewData.getActivePosition());
|
||||
albumRail.smoothScrollToPosition(previewData.getActivePosition());
|
||||
|
||||
captionContainer.setVisibility(previewData.getCaption() == null ? View.GONE : View.VISIBLE);
|
||||
caption.setText(previewData.getCaption());
|
||||
|
||||
if (playbackControls != null) {
|
||||
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
playbackControls.setLayoutParams(params);
|
||||
|
||||
playbackControlsContainer.removeAllViews();
|
||||
playbackControlsContainer.addView(playbackControls);
|
||||
} else {
|
||||
playbackControlsContainer.removeAllViews();
|
||||
}
|
||||
});
|
||||
|
||||
clickDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
if (e.getY() < detailsContainer.getTop()) {
|
||||
detailsContainer.setVisibility(detailsContainer.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
return super.onSingleTapUp(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeMedia() {
|
||||
if (!isContentTypeSupported(initialMediaType)) {
|
||||
Log.w(TAG, "Unsupported media type sent to MediaPreviewActivity, finishing.");
|
||||
@ -203,6 +295,12 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
getSupportLoaderManager().restartLoader(0, null, this);
|
||||
} else {
|
||||
mediaPager.setAdapter(new SingleItemPagerAdapter(this, GlideApp.with(this), getWindow(), initialMediaUri, initialMediaType, initialMediaSize));
|
||||
|
||||
if (initialCaption != null) {
|
||||
detailsContainer.setVisibility(View.VISIBLE);
|
||||
captionContainer.setVisibility(View.VISIBLE);
|
||||
caption.setText(initialCaption);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,6 +446,8 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
mediaPager.setAdapter(adapter);
|
||||
adapter.setActive(true);
|
||||
|
||||
viewModel.setCursor(data.first, leftIsRecent);
|
||||
|
||||
if (restartItem < 0) mediaPager.setCurrentItem(data.second);
|
||||
else mediaPager.setCurrentItem(restartItem);
|
||||
}
|
||||
@ -369,7 +469,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
if (adapter != null) {
|
||||
MediaItem item = adapter.getMediaItemFor(position);
|
||||
if (item.recipient != null) item.recipient.addListener(MediaPreviewActivity.this);
|
||||
|
||||
viewModel.setActiveAlbumRailItem(MediaPreviewActivity.this, position);
|
||||
initializeActionBar();
|
||||
}
|
||||
}
|
||||
@ -453,6 +553,11 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
public void pause(int position) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable View getPlaybackControls(int position) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CursorPagerAdapter extends PagerAdapter implements MediaItemAdapter {
|
||||
@ -511,7 +616,8 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
|
||||
try {
|
||||
//noinspection ConstantConditions
|
||||
mediaView.set(glideRequests, window, mediaRecord.getAttachment().getDataUri(), mediaRecord.getAttachment().getContentType(), mediaRecord.getAttachment().getSize(), autoplay);
|
||||
mediaView.set(glideRequests, window, mediaRecord.getAttachment().getDataUri(),
|
||||
mediaRecord.getAttachment().getContentType(), mediaRecord.getAttachment().getSize(), autoplay);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
@ -552,6 +658,13 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
if (mediaView != null) mediaView.pause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable View getPlaybackControls(int position) {
|
||||
MediaView mediaView = mediaViews.get(position);
|
||||
if (mediaView != null) return mediaView.getPlaybackControls();
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getCursorPosition(int position) {
|
||||
if (leftIsRecent) return position;
|
||||
else return cursor.getCount() - 1 - position;
|
||||
@ -585,5 +698,6 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
||||
interface MediaItemAdapter {
|
||||
MediaItem getMediaItemFor(int position);
|
||||
void pause(int position);
|
||||
@Nullable View getPlaybackControls(int position);
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, mediaRecord.isOutgoing());
|
||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate());
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
|
||||
intent.putExtra(MediaPreviewActivity.CAPTION_EXTRA, mediaRecord.getAttachment().getCaption());
|
||||
intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, ViewCompat.getLayoutDirection(threadPhotoRailView) == ViewCompat.LAYOUT_DIRECTION_LTR);
|
||||
intent.setDataAndType(mediaRecord.getAttachment().getDataUri(), mediaRecord.getContentType());
|
||||
startActivity(intent);
|
||||
|
@ -37,10 +37,13 @@ public abstract class Attachment {
|
||||
|
||||
private final boolean quote;
|
||||
|
||||
@Nullable
|
||||
private final String caption;
|
||||
|
||||
public Attachment(@NonNull String contentType, int transferState, long size, @Nullable String fileName,
|
||||
@Nullable String location, @Nullable String key, @Nullable String relay,
|
||||
@Nullable byte[] digest, @Nullable String fastPreflightId, boolean voiceNote,
|
||||
int width, int height, boolean quote)
|
||||
int width, int height, boolean quote, @Nullable String caption)
|
||||
{
|
||||
this.contentType = contentType;
|
||||
this.transferState = transferState;
|
||||
@ -55,6 +58,7 @@ public abstract class Attachment {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.quote = quote;
|
||||
this.caption = caption;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -126,4 +130,8 @@ public abstract class Attachment {
|
||||
public boolean isQuote() {
|
||||
return quote;
|
||||
}
|
||||
|
||||
public @Nullable String getCaption() {
|
||||
return caption;
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ public class DatabaseAttachment extends Attachment {
|
||||
String contentType, int transferProgress, long size,
|
||||
String fileName, String location, String key, String relay,
|
||||
byte[] digest, String fastPreflightId, boolean voiceNote,
|
||||
int width, int height, boolean quote)
|
||||
int width, int height, boolean quote, @Nullable String caption)
|
||||
{
|
||||
super(contentType, transferProgress, size, fileName, location, key, relay, digest, fastPreflightId, voiceNote, width, height, quote);
|
||||
super(contentType, transferProgress, size, fileName, location, key, relay, digest, fastPreflightId, voiceNote, width, height, quote, caption);
|
||||
this.attachmentId = attachmentId;
|
||||
this.hasData = hasData;
|
||||
this.hasThumbnail = hasThumbnail;
|
||||
|
@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
public class MmsNotificationAttachment extends Attachment {
|
||||
|
||||
public MmsNotificationAttachment(int status, long size) {
|
||||
super("application/mms", getTransferStateFromStatus(status), size, null, null, null, null, null, null, false, 0, 0, false);
|
||||
super("application/mms", getTransferStateFromStatus(status), size, null, null, null, null, null, null, false, 0, 0, false, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -19,9 +19,9 @@ public class PointerAttachment extends Attachment {
|
||||
@Nullable String fileName, @NonNull String location,
|
||||
@Nullable String key, @Nullable String relay,
|
||||
@Nullable byte[] digest, boolean voiceNote,
|
||||
int width, int height)
|
||||
int width, int height, @Nullable String caption)
|
||||
{
|
||||
super(contentType, transferState, size, fileName, location, key, relay, digest, null, voiceNote, width, height, false);
|
||||
super(contentType, transferState, size, fileName, location, key, relay, digest, null, voiceNote, width, height, false, caption);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -87,7 +87,8 @@ public class PointerAttachment extends Attachment {
|
||||
pointer.get().asPointer().getDigest().orNull(),
|
||||
pointer.get().asPointer().getVoiceNote(),
|
||||
pointer.get().asPointer().getWidth(),
|
||||
pointer.get().asPointer().getHeight()));
|
||||
pointer.get().asPointer().getHeight(),
|
||||
pointer.get().asPointer().getCaption().orNull()));
|
||||
|
||||
}
|
||||
|
||||
@ -104,6 +105,7 @@ public class PointerAttachment extends Attachment {
|
||||
thumbnail != null ? thumbnail.asPointer().getDigest().orNull() : null,
|
||||
false,
|
||||
thumbnail != null ? thumbnail.asPointer().getWidth() : 0,
|
||||
thumbnail != null ? thumbnail.asPointer().getHeight() : 0));
|
||||
thumbnail != null ? thumbnail.asPointer().getHeight() : 0,
|
||||
thumbnail != null ? thumbnail.asPointer().getCaption().orNull() : null));
|
||||
}
|
||||
}
|
||||
|
@ -10,17 +10,17 @@ public class UriAttachment extends Attachment {
|
||||
private final @Nullable Uri thumbnailUri;
|
||||
|
||||
public UriAttachment(@NonNull Uri uri, @NonNull String contentType, int transferState, long size,
|
||||
@Nullable String fileName, boolean voiceNote, boolean quote)
|
||||
@Nullable String fileName, boolean voiceNote, boolean quote, @Nullable String caption)
|
||||
{
|
||||
this(uri, uri, contentType, transferState, size, 0, 0, fileName, null, voiceNote, quote);
|
||||
this(uri, uri, contentType, transferState, size, 0, 0, fileName, null, voiceNote, quote, caption);
|
||||
}
|
||||
|
||||
public UriAttachment(@NonNull Uri dataUri, @Nullable Uri thumbnailUri,
|
||||
@NonNull String contentType, int transferState, long size, int width, int height,
|
||||
@Nullable String fileName, @Nullable String fastPreflightId,
|
||||
boolean voiceNote, boolean quote)
|
||||
boolean voiceNote, boolean quote, @Nullable String caption)
|
||||
{
|
||||
super(contentType, transferState, size, fileName, null, null, null, null, fastPreflightId, voiceNote, width, height, quote);
|
||||
super(contentType, transferState, size, fileName, null, null, null, null, fastPreflightId, voiceNote, width, height, quote, caption);
|
||||
this.dataUri = dataUri;
|
||||
this.thumbnailUri = thumbnailUri;
|
||||
}
|
||||
|
@ -0,0 +1,159 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideClickListener;
|
||||
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
|
||||
import org.thoughtcrime.securesms.util.views.Stub;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class AlbumThumbnailView extends FrameLayout {
|
||||
|
||||
private @Nullable SlideClickListener thumbnailClickListener;
|
||||
private @Nullable SlidesClickedListener downloadClickListener;
|
||||
|
||||
private int currentSizeClass;
|
||||
|
||||
private ViewGroup albumCellContainer;
|
||||
private Stub<TransferControlView> transferControls;
|
||||
|
||||
private final SlideClickListener defaultThumbnailClickListener = (v, slide) -> {
|
||||
if (thumbnailClickListener != null) {
|
||||
thumbnailClickListener.onClick(v, slide);
|
||||
}
|
||||
};
|
||||
|
||||
private final OnLongClickListener defaultLongClickListener = v -> this.performLongClick();
|
||||
|
||||
public AlbumThumbnailView(@NonNull @android.support.annotation.NonNull Context context) {
|
||||
super(context);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public AlbumThumbnailView(@NonNull @android.support.annotation.NonNull Context context, @Nullable @android.support.annotation.Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
inflate(getContext(), R.layout.album_thumbnail_view, this);
|
||||
|
||||
albumCellContainer = findViewById(R.id.album_cell_container);
|
||||
transferControls = new Stub<>(findViewById(R.id.album_transfer_controls_stub));
|
||||
}
|
||||
|
||||
public void setSlides(@NonNull GlideRequests glideRequests, @NonNull List<Slide> slides, boolean showControls) {
|
||||
if (slides.size() < 2) {
|
||||
throw new IllegalStateException("Provided less than two slides.");
|
||||
}
|
||||
|
||||
if (showControls) {
|
||||
transferControls.get().setShowDownloadText(true);
|
||||
transferControls.get().setSlides(slides);
|
||||
transferControls.get().setDownloadClickListener(v -> {
|
||||
if (downloadClickListener != null) {
|
||||
downloadClickListener.onClick(v, slides);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (transferControls.resolved()) {
|
||||
transferControls.get().setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
int sizeClass = sizeClass(slides.size());
|
||||
|
||||
if (sizeClass != currentSizeClass) {
|
||||
inflateLayout(sizeClass);
|
||||
currentSizeClass = sizeClass;
|
||||
}
|
||||
|
||||
showSlides(glideRequests, slides);
|
||||
}
|
||||
|
||||
public void setCellBackgroundColor(@ColorInt int color) {
|
||||
ViewGroup cellRoot = findViewById(R.id.album_thumbnail_root);
|
||||
|
||||
if (cellRoot != null) {
|
||||
for (int i = 0; i < cellRoot.getChildCount(); i++) {
|
||||
cellRoot.getChildAt(i).setBackgroundColor(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setThumbnailClickListener(@Nullable SlideClickListener listener) {
|
||||
thumbnailClickListener = listener;
|
||||
}
|
||||
|
||||
public void setDownloadClickListener(@Nullable SlidesClickedListener listener) {
|
||||
downloadClickListener = listener;
|
||||
}
|
||||
|
||||
private void inflateLayout(int sizeClass) {
|
||||
albumCellContainer.removeAllViews();
|
||||
|
||||
switch (sizeClass) {
|
||||
case 2:
|
||||
inflate(getContext(), R.layout.album_thumbnail_2, albumCellContainer);
|
||||
break;
|
||||
case 3:
|
||||
inflate(getContext(), R.layout.album_thumbnail_3, albumCellContainer);
|
||||
break;
|
||||
case 4:
|
||||
inflate(getContext(), R.layout.album_thumbnail_4, albumCellContainer);
|
||||
break;
|
||||
case 5:
|
||||
inflate(getContext(), R.layout.album_thumbnail_5, albumCellContainer);
|
||||
break;
|
||||
default:
|
||||
inflate(getContext(), R.layout.album_thumbnail_many, albumCellContainer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void showSlides(@NonNull GlideRequests glideRequests, @NonNull List<Slide> slides) {
|
||||
setSlide(glideRequests, slides.get(0), R.id.album_cell_1);
|
||||
setSlide(glideRequests, slides.get(1), R.id.album_cell_2);
|
||||
|
||||
if (slides.size() >= 3) {
|
||||
setSlide(glideRequests, slides.get(2), R.id.album_cell_3);
|
||||
}
|
||||
|
||||
if (slides.size() >= 4) {
|
||||
setSlide(glideRequests, slides.get(3), R.id.album_cell_4);
|
||||
}
|
||||
|
||||
if (slides.size() >= 5) {
|
||||
setSlide(glideRequests, slides.get(4), R.id.album_cell_5);
|
||||
}
|
||||
|
||||
if (slides.size() > 5) {
|
||||
TextView text = findViewById(R.id.album_cell_overflow_text);
|
||||
text.setText(getContext().getString(R.string.AlbumThumbnailView_plus, slides.size() - 5));
|
||||
}
|
||||
}
|
||||
|
||||
private void setSlide(@NonNull GlideRequests glideRequests, @NonNull Slide slide, @IdRes int id) {
|
||||
ThumbnailView cell = findViewById(id);
|
||||
cell.setImageResource(glideRequests, slide, false, false);
|
||||
cell.setThumbnailClickListener(defaultThumbnailClickListener);
|
||||
cell.setOnLongClickListener(defaultLongClickListener);
|
||||
}
|
||||
|
||||
private int sizeClass(int size) {
|
||||
return Math.min(size, 6);
|
||||
}
|
||||
}
|
@ -3,11 +3,10 @@ package org.thoughtcrime.securesms.components;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
@ -16,40 +15,36 @@ import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideClickListener;
|
||||
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ConversationItemThumbnail extends FrameLayout {
|
||||
|
||||
private static final String TAG = ConversationItemThumbnail.class.getSimpleName();
|
||||
|
||||
private static final Paint LIGHT_THEME_OUTLINE_PAINT = new Paint();
|
||||
private static final Paint DARK_THEME_OUTLINE_PAINT = new Paint();
|
||||
|
||||
static {
|
||||
LIGHT_THEME_OUTLINE_PAINT.setColor(Color.argb((int) (255 * 0.2), 0, 0, 0));
|
||||
LIGHT_THEME_OUTLINE_PAINT.setStyle(Paint.Style.STROKE);
|
||||
LIGHT_THEME_OUTLINE_PAINT.setStrokeWidth(1f);
|
||||
LIGHT_THEME_OUTLINE_PAINT.setAntiAlias(true);
|
||||
|
||||
DARK_THEME_OUTLINE_PAINT.setColor(Color.argb((int) (255 * 0.2), 255, 255, 255));
|
||||
DARK_THEME_OUTLINE_PAINT.setStyle(Paint.Style.STROKE);
|
||||
DARK_THEME_OUTLINE_PAINT.setStrokeWidth(1f);
|
||||
DARK_THEME_OUTLINE_PAINT.setAntiAlias(true);
|
||||
}
|
||||
|
||||
private final float[] radii = new float[8];
|
||||
private final RectF bounds = new RectF();
|
||||
private final Path corners = new Path();
|
||||
private final float[] radii = new float[8];
|
||||
private final RectF bounds = new RectF();
|
||||
private final Path corners = new Path();
|
||||
|
||||
private ThumbnailView thumbnail;
|
||||
private AlbumThumbnailView album;
|
||||
private ImageView shade;
|
||||
private ConversationItemFooter footer;
|
||||
private Paint outlinePaint;
|
||||
private CornerMask cornerMask;
|
||||
|
||||
private final Paint outlinePaint = new Paint();
|
||||
{
|
||||
outlinePaint.setStyle(Paint.Style.STROKE);
|
||||
outlinePaint.setStrokeWidth(1f);
|
||||
outlinePaint.setAntiAlias(true);
|
||||
}
|
||||
|
||||
public ConversationItemThumbnail(Context context) {
|
||||
super(context);
|
||||
init(null);
|
||||
@ -68,13 +63,13 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
private void init(@Nullable AttributeSet attrs) {
|
||||
inflate(getContext(), R.layout.conversation_item_thumbnail, this);
|
||||
|
||||
this.thumbnail = findViewById(R.id.conversation_thumbnail_image);
|
||||
this.shade = findViewById(R.id.conversation_thumbnail_shade);
|
||||
this.footer = findViewById(R.id.conversation_thumbnail_footer);
|
||||
this.outlinePaint = ThemeUtil.isDarkTheme(getContext()) ? DARK_THEME_OUTLINE_PAINT : LIGHT_THEME_OUTLINE_PAINT;
|
||||
this.cornerMask = new CornerMask(this);
|
||||
outlinePaint.setColor(ThemeUtil.getThemedColor(getContext(), R.attr.conversation_item_image_outline_color));
|
||||
|
||||
setTouchDelegate(thumbnail.getTouchDelegate());
|
||||
this.thumbnail = findViewById(R.id.conversation_thumbnail_image);
|
||||
this.album = findViewById(R.id.conversation_thumbnail_album);
|
||||
this.shade = findViewById(R.id.conversation_thumbnail_shade);
|
||||
this.footer = findViewById(R.id.conversation_thumbnail_footer);
|
||||
this.cornerMask = new CornerMask(this);
|
||||
|
||||
if (attrs != null) {
|
||||
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.ConversationItemThumbnail, 0, 0);
|
||||
@ -99,32 +94,37 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
cornerMask.mask(canvas);
|
||||
}
|
||||
|
||||
final float halfStrokeWidth = outlinePaint.getStrokeWidth() / 2;
|
||||
if (album.getVisibility() != VISIBLE) {
|
||||
final float halfStrokeWidth = outlinePaint.getStrokeWidth() / 2;
|
||||
|
||||
bounds.left = halfStrokeWidth;
|
||||
bounds.top = halfStrokeWidth;
|
||||
bounds.right = canvas.getWidth() - halfStrokeWidth;
|
||||
bounds.bottom = canvas.getHeight() - halfStrokeWidth;
|
||||
bounds.left = halfStrokeWidth;
|
||||
bounds.top = halfStrokeWidth;
|
||||
bounds.right = canvas.getWidth() - halfStrokeWidth;
|
||||
bounds.bottom = canvas.getHeight() - halfStrokeWidth;
|
||||
|
||||
corners.reset();
|
||||
corners.addRoundRect(bounds, radii, Path.Direction.CW);
|
||||
corners.reset();
|
||||
corners.addRoundRect(bounds, radii, Path.Direction.CW);
|
||||
|
||||
canvas.drawPath(corners, outlinePaint);
|
||||
canvas.drawPath(corners, outlinePaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFocusable(boolean focusable) {
|
||||
thumbnail.setFocusable(focusable);
|
||||
album.setFocusable(focusable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClickable(boolean clickable) {
|
||||
thumbnail.setClickable(clickable);
|
||||
album.setClickable(clickable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnLongClickListener(@Nullable OnLongClickListener l) {
|
||||
thumbnail.setOnLongClickListener(l);
|
||||
album.setOnLongClickListener(l);
|
||||
}
|
||||
|
||||
public void showShade(boolean show) {
|
||||
@ -146,37 +146,38 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
|
||||
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull List<Slide> slides,
|
||||
boolean showControls, boolean isPreview)
|
||||
{
|
||||
thumbnail.setImageResource(glideRequests, slide, showControls, isPreview);
|
||||
if (slides.size() == 1) {
|
||||
thumbnail.setVisibility(VISIBLE);
|
||||
album.setVisibility(GONE);
|
||||
|
||||
Attachment attachment = slides.get(0).asAttachment();
|
||||
thumbnail.setImageResource(glideRequests, slides.get(0), showControls, isPreview, attachment.getWidth(), attachment.getHeight());
|
||||
setTouchDelegate(thumbnail.getTouchDelegate());
|
||||
} else {
|
||||
thumbnail.setVisibility(GONE);
|
||||
album.setVisibility(VISIBLE);
|
||||
|
||||
album.setSlides(glideRequests, slides, showControls);
|
||||
setTouchDelegate(album.getTouchDelegate());
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
|
||||
boolean showControls, boolean isPreview, int naturalWidth,
|
||||
int naturalHeight)
|
||||
{
|
||||
thumbnail.setImageResource(glideRequests, slide, showControls, isPreview, naturalWidth, naturalHeight);
|
||||
}
|
||||
|
||||
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Uri uri) {
|
||||
thumbnail.setImageResource(glideRequests, uri);
|
||||
public void setConversationColor(@ColorInt int color) {
|
||||
if (album.getVisibility() == VISIBLE) {
|
||||
album.setCellBackgroundColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
public void setThumbnailClickListener(SlideClickListener listener) {
|
||||
thumbnail.setThumbnailClickListener(listener);
|
||||
album.setThumbnailClickListener(listener);
|
||||
}
|
||||
|
||||
public void setDownloadClickListener(SlideClickListener listener) {
|
||||
public void setDownloadClickListener(SlidesClickedListener listener) {
|
||||
thumbnail.setDownloadClickListener(listener);
|
||||
}
|
||||
|
||||
public void clear(GlideRequests glideRequests) {
|
||||
thumbnail.clear(glideRequests);
|
||||
}
|
||||
|
||||
public void showProgressSpinner() {
|
||||
thumbnail.showProgressSpinner();
|
||||
album.setDownloadClickListener(listener);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class MaxHeightScrollView extends ScrollView {
|
||||
|
||||
private int maxHeight = -1;
|
||||
|
||||
public MaxHeightScrollView(Context context) {
|
||||
super(context);
|
||||
initialize(null);
|
||||
}
|
||||
|
||||
public MaxHeightScrollView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initialize(attrs);
|
||||
}
|
||||
|
||||
private void initialize(@Nullable AttributeSet attrs) {
|
||||
if (attrs != null) {
|
||||
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView, 0, 0);
|
||||
|
||||
maxHeight = typedArray.getDimensionPixelOffset(R.styleable.MaxHeightScrollView_scrollView_maxHeight, -1);
|
||||
|
||||
typedArray.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (maxHeight >= 0) {
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
@ -81,6 +82,19 @@ public class MediaView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void hideControls() {
|
||||
if (this.videoView.resolved()){
|
||||
this.videoView.get().hideControls();
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable View getPlaybackControls() {
|
||||
if (this.videoView.resolved()){
|
||||
return this.videoView.get().getControlView();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
this.imageView.cleanup();
|
||||
if (this.videoView.resolved()) {
|
||||
|
@ -27,12 +27,14 @@ import org.thoughtcrime.securesms.mms.GlideRequest;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideClickListener;
|
||||
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
|
||||
@ -49,6 +51,7 @@ public class ThumbnailView extends FrameLayout {
|
||||
|
||||
private ImageView image;
|
||||
private View playOverlay;
|
||||
private View captionIcon;
|
||||
private OnClickListener parentClickListener;
|
||||
|
||||
private final int[] dimens = new int[2];
|
||||
@ -57,7 +60,7 @@ public class ThumbnailView extends FrameLayout {
|
||||
|
||||
private Optional<TransferControlView> transferControls = Optional.absent();
|
||||
private SlideClickListener thumbnailClickListener = null;
|
||||
private SlideClickListener downloadClickListener = null;
|
||||
private SlidesClickedListener downloadClickListener = null;
|
||||
private Slide slide = null;
|
||||
|
||||
private int radius;
|
||||
@ -77,6 +80,7 @@ public class ThumbnailView extends FrameLayout {
|
||||
|
||||
this.image = findViewById(R.id.thumbnail_image);
|
||||
this.playOverlay = findViewById(R.id.play_overlay);
|
||||
this.captionIcon = findViewById(R.id.thumbnail_caption_icon);
|
||||
super.setOnClickListener(new ThumbnailClickDispatcher());
|
||||
|
||||
if (attrs != null) {
|
||||
@ -230,8 +234,8 @@ public class ThumbnailView extends FrameLayout {
|
||||
|
||||
@UiThread
|
||||
public ListenableFuture<Boolean> setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
|
||||
boolean showControls, boolean isPreview, int naturalWidth,
|
||||
int naturalHeight)
|
||||
boolean showControls, boolean isPreview,
|
||||
int naturalWidth, int naturalHeight)
|
||||
{
|
||||
if (showControls) {
|
||||
getTransferControls().setSlide(slide);
|
||||
@ -267,6 +271,8 @@ public class ThumbnailView extends FrameLayout {
|
||||
|
||||
this.slide = slide;
|
||||
|
||||
this.captionIcon.setVisibility(slide.getCaption().isPresent() ? VISIBLE : GONE);
|
||||
|
||||
dimens[WIDTH] = naturalWidth;
|
||||
dimens[HEIGHT] = naturalHeight;
|
||||
invalidate();
|
||||
@ -302,7 +308,7 @@ public class ThumbnailView extends FrameLayout {
|
||||
this.thumbnailClickListener = listener;
|
||||
}
|
||||
|
||||
public void setDownloadClickListener(SlideClickListener listener) {
|
||||
public void setDownloadClickListener(SlidesClickedListener listener) {
|
||||
this.downloadClickListener = listener;
|
||||
}
|
||||
|
||||
@ -342,8 +348,14 @@ public class ThumbnailView extends FrameLayout {
|
||||
size[WIDTH] = getDefaultWidth();
|
||||
size[HEIGHT] = getDefaultHeight();
|
||||
}
|
||||
return request.override(size[WIDTH], size[HEIGHT])
|
||||
.transforms(fitting, new RoundedCorners(radius));
|
||||
|
||||
request = request.override(size[WIDTH], size[HEIGHT]);
|
||||
|
||||
if (radius > 0) {
|
||||
return request.transforms(fitting, new RoundedCorners(radius));
|
||||
} else {
|
||||
return request.transforms(fitting);
|
||||
}
|
||||
}
|
||||
|
||||
private int getDefaultWidth() {
|
||||
@ -382,7 +394,7 @@ public class ThumbnailView extends FrameLayout {
|
||||
public void onClick(View view) {
|
||||
Log.i(TAG, "onClick() for download button");
|
||||
if (downloadClickListener != null && slide != null) {
|
||||
downloadClickListener.onClick(view, slide);
|
||||
downloadClickListener.onClick(view, Collections.singletonList(slide));
|
||||
} else {
|
||||
Log.w(TAG, "Received a download button click, but unable to execute it. slide: " + String.valueOf(slide) + " downloadClickListener: " + String.valueOf(downloadClickListener));
|
||||
}
|
||||
|
@ -15,32 +15,42 @@ import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.ValueAnimator;
|
||||
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import com.pnikosis.materialishprogress.ProgressWheel;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.events.PartProgressEvent;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TransferControlView extends FrameLayout {
|
||||
private static final int TRANSITION_MS = 300;
|
||||
|
||||
@Nullable private Slide slide;
|
||||
@Nullable private View current;
|
||||
@Nullable private List<Slide> slides;
|
||||
@Nullable private View current;
|
||||
|
||||
private final ProgressWheel progressWheel;
|
||||
private final TextView downloadDetails;
|
||||
private final View downloadDetails;
|
||||
private final TextView downloadDetailsText;
|
||||
private final int contractedWidth;
|
||||
private final int expandedWidth;
|
||||
|
||||
private final Map<Attachment, Float> downloadProgress;
|
||||
|
||||
public TransferControlView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@ -61,10 +71,12 @@ public class TransferControlView extends FrameLayout {
|
||||
ViewUtil.setBackground(this, background);
|
||||
setVisibility(GONE);
|
||||
|
||||
this.progressWheel = ViewUtil.findById(this, R.id.progress_wheel);
|
||||
this.downloadDetails = ViewUtil.findById(this, R.id.download_details);
|
||||
this.contractedWidth = getResources().getDimensionPixelSize(R.dimen.transfer_controls_contracted_width);
|
||||
this.expandedWidth = getResources().getDimensionPixelSize(R.dimen.transfer_controls_expanded_width);
|
||||
this.downloadProgress = new HashMap<>();
|
||||
this.progressWheel = ViewUtil.findById(this, R.id.progress_wheel);
|
||||
this.downloadDetails = ViewUtil.findById(this, R.id.download_details);
|
||||
this.downloadDetailsText = ViewUtil.findById(this, R.id.download_details_text);
|
||||
this.contractedWidth = getResources().getDimensionPixelSize(R.dimen.transfer_controls_contracted_width);
|
||||
this.expandedWidth = getResources().getDimensionPixelSize(R.dimen.transfer_controls_expanded_width);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -91,20 +103,54 @@ public class TransferControlView extends FrameLayout {
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
public void setSlide(final @NonNull Slide slide) {
|
||||
this.slide = slide;
|
||||
if (slide.getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_STARTED) {
|
||||
showProgressSpinner();
|
||||
} else if (slide.isPendingDownload()) {
|
||||
downloadDetails.setText(slide.getContentDescription());
|
||||
display(downloadDetails);
|
||||
public void setSlide(final @NonNull Slide slides) {
|
||||
setSlides(Collections.singletonList(slides));
|
||||
}
|
||||
|
||||
public void setSlides(final @NonNull List<Slide> slides) {
|
||||
if (slides.isEmpty()) {
|
||||
throw new IllegalArgumentException("Must provide at least one slide.");
|
||||
}
|
||||
|
||||
this.slides = slides;
|
||||
|
||||
if (!isUpdateToExistingSet(slides)) {
|
||||
downloadProgress.clear();
|
||||
Stream.of(slides).forEach(s -> downloadProgress.put(s.asAttachment(), 0f));
|
||||
} else {
|
||||
display(null);
|
||||
for (Slide slide : slides) {
|
||||
if (slide.asAttachment().getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_DONE) {
|
||||
downloadProgress.put(slide.asAttachment(), 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (getTransferState(slides)) {
|
||||
case AttachmentDatabase.TRANSFER_PROGRESS_STARTED:
|
||||
showProgressSpinner(calculateProgress(downloadProgress));
|
||||
break;
|
||||
case AttachmentDatabase.TRANSFER_PROGRESS_PENDING:
|
||||
case AttachmentDatabase.TRANSFER_PROGRESS_FAILED:
|
||||
downloadDetailsText.setText(getDownloadText(this.slides));
|
||||
display(downloadDetails);
|
||||
break;
|
||||
default:
|
||||
display(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void showProgressSpinner() {
|
||||
progressWheel.spin();
|
||||
showProgressSpinner(calculateProgress(downloadProgress));
|
||||
}
|
||||
|
||||
public void showProgressSpinner(float progress) {
|
||||
if (progress == 0) {
|
||||
progressWheel.spin();
|
||||
} else {
|
||||
progressWheel.setInstantProgress(progress);
|
||||
}
|
||||
|
||||
display(progressWheel);
|
||||
}
|
||||
|
||||
@ -120,12 +166,51 @@ public class TransferControlView extends FrameLayout {
|
||||
current.setVisibility(GONE);
|
||||
}
|
||||
current = null;
|
||||
slide = null;
|
||||
slides = null;
|
||||
}
|
||||
|
||||
public void setShowDownloadText(boolean showDownloadText) {
|
||||
downloadDetailsText.setVisibility(showDownloadText ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
private boolean isUpdateToExistingSet(@NonNull List<Slide> slides) {
|
||||
if (slides.size() != downloadProgress.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Slide slide : slides) {
|
||||
if (!downloadProgress.containsKey(slide.asAttachment())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getTransferState(@NonNull List<Slide> slides) {
|
||||
int transferState = AttachmentDatabase.TRANSFER_PROGRESS_DONE;
|
||||
for (Slide slide : slides) {
|
||||
if (slide.getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_PENDING && transferState == AttachmentDatabase.TRANSFER_PROGRESS_DONE) {
|
||||
transferState = slide.getTransferState();
|
||||
} else {
|
||||
transferState = Math.max(transferState, slide.getTransferState());
|
||||
}
|
||||
}
|
||||
return transferState;
|
||||
}
|
||||
|
||||
private String getDownloadText(@NonNull List<Slide> slides) {
|
||||
if (slides.size() == 1) {
|
||||
return slides.get(0).getContentDescription();
|
||||
} else {
|
||||
int downloadCount = Stream.of(slides).reduce(0, (count, slide) -> slide.getTransferState() != AttachmentDatabase.TRANSFER_PROGRESS_DONE ? count + 1 : count);
|
||||
return getContext().getResources().getQuantityString(R.plurals.TransferControlView_n_items, downloadCount, downloadCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void display(@Nullable final View view) {
|
||||
final int sourceWidth = current == downloadDetails ? expandedWidth : contractedWidth;
|
||||
final int targetWidth = view == downloadDetails ? expandedWidth : contractedWidth;
|
||||
final int sourceWidth = (current == downloadDetails && downloadDetailsText.getVisibility() == VISIBLE) ? expandedWidth : contractedWidth;
|
||||
final int targetWidth = (view == downloadDetails && downloadDetailsText.getVisibility() == VISIBLE) ? expandedWidth : contractedWidth;
|
||||
|
||||
if (current == view || current == null) {
|
||||
ViewGroup.LayoutParams layoutParams = getLayoutParams();
|
||||
@ -149,28 +234,31 @@ public class TransferControlView extends FrameLayout {
|
||||
|
||||
private Animator getWidthAnimator(final int from, final int to) {
|
||||
final ValueAnimator anim = ValueAnimator.ofInt(from, to);
|
||||
anim.addUpdateListener(new AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
final int val = (Integer)animation.getAnimatedValue();
|
||||
final ViewGroup.LayoutParams layoutParams = getLayoutParams();
|
||||
layoutParams.width = val;
|
||||
setLayoutParams(layoutParams);
|
||||
}
|
||||
anim.addUpdateListener(animation -> {
|
||||
final int val = (Integer)animation.getAnimatedValue();
|
||||
final ViewGroup.LayoutParams layoutParams = getLayoutParams();
|
||||
layoutParams.width = val;
|
||||
setLayoutParams(layoutParams);
|
||||
});
|
||||
anim.setInterpolator(new FastOutSlowInInterpolator());
|
||||
anim.setDuration(TRANSITION_MS);
|
||||
return anim;
|
||||
}
|
||||
|
||||
private float calculateProgress(@NonNull Map<Attachment, Float> downloadProgress) {
|
||||
float totalProgress = 0;
|
||||
for (float progress : downloadProgress.values()) {
|
||||
totalProgress += progress / downloadProgress.size();
|
||||
}
|
||||
return totalProgress;
|
||||
}
|
||||
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
||||
public void onEventAsync(final PartProgressEvent event) {
|
||||
if (this.slide != null && event.attachment.equals(this.slide.asAttachment())) {
|
||||
Util.runOnMain(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
progressWheel.setInstantProgress(((float)event.progress) / event.total);
|
||||
}
|
||||
if (downloadProgress.containsKey(event.attachment)) {
|
||||
Util.runOnMain(() -> {
|
||||
downloadProgress.put(event.attachment, ((float)event.progress) / event.total);
|
||||
progressWheel.setInstantProgress(calculateProgress(downloadProgress));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -642,7 +642,7 @@ public class Contact implements Parcelable {
|
||||
|
||||
private static Attachment attachmentFromUri(@Nullable Uri uri) {
|
||||
if (uri == null) return null;
|
||||
return new UriAttachment(uri, MediaUtil.IMAGE_JPEG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, 0, null, false, false);
|
||||
return new UriAttachment(uri, MediaUtil.IMAGE_JPEG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, 0, null, false, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -98,6 +98,7 @@ public class AttachmentDatabase extends Database {
|
||||
private static final String THUMBNAIL_RANDOM = "thumbnail_random";
|
||||
static final String WIDTH = "width";
|
||||
static final String HEIGHT = "height";
|
||||
static final String CAPTION = "caption";
|
||||
|
||||
public static final String DIRECTORY = "parts";
|
||||
|
||||
@ -113,7 +114,8 @@ public class AttachmentDatabase extends Database {
|
||||
CONTENT_LOCATION, DATA, THUMBNAIL, TRANSFER_STATE,
|
||||
SIZE, FILE_NAME, THUMBNAIL, THUMBNAIL_ASPECT_RATIO,
|
||||
UNIQUE_ID, DIGEST, FAST_PREFLIGHT_ID, VOICE_NOTE,
|
||||
QUOTE, DATA_RANDOM, THUMBNAIL_RANDOM, WIDTH, HEIGHT};
|
||||
QUOTE, DATA_RANDOM, THUMBNAIL_RANDOM, WIDTH, HEIGHT,
|
||||
CAPTION };
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ROW_ID + " INTEGER PRIMARY KEY, " +
|
||||
MMS_ID + " INTEGER, " + "seq" + " INTEGER DEFAULT 0, " +
|
||||
@ -125,7 +127,8 @@ public class AttachmentDatabase extends Database {
|
||||
FILE_NAME + " TEXT, " + THUMBNAIL + " TEXT, " + THUMBNAIL_ASPECT_RATIO + " REAL, " +
|
||||
UNIQUE_ID + " INTEGER NOT NULL, " + DIGEST + " BLOB, " + FAST_PREFLIGHT_ID + " TEXT, " +
|
||||
VOICE_NOTE + " INTEGER DEFAULT 0, " + DATA_RANDOM + " BLOB, " + THUMBNAIL_RANDOM + " BLOB, " +
|
||||
QUOTE + " INTEGER DEFAULT 0, " + WIDTH + " INTEGER DEFAULT 0, " + HEIGHT + " INTEGER DEFAULT 0);";
|
||||
QUOTE + " INTEGER DEFAULT 0, " + WIDTH + " INTEGER DEFAULT 0, " + HEIGHT + " INTEGER DEFAULT 0, " +
|
||||
CAPTION + " TEXT DEFAULT NULL);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS part_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");",
|
||||
@ -416,7 +419,8 @@ public class AttachmentDatabase extends Database {
|
||||
databaseAttachment.isVoiceNote(),
|
||||
mediaStream.getWidth(),
|
||||
mediaStream.getHeight(),
|
||||
databaseAttachment.isQuote());
|
||||
databaseAttachment.isQuote(),
|
||||
databaseAttachment.getCaption());
|
||||
}
|
||||
|
||||
|
||||
@ -589,7 +593,8 @@ public class AttachmentDatabase extends Database {
|
||||
object.getInt(VOICE_NOTE) == 1,
|
||||
object.getInt(WIDTH),
|
||||
object.getInt(HEIGHT),
|
||||
object.getInt(QUOTE) == 1));
|
||||
object.getInt(QUOTE) == 1,
|
||||
object.getString(CAPTION)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,7 +617,8 @@ public class AttachmentDatabase extends Database {
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(VOICE_NOTE)) == 1,
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(WIDTH)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(HEIGHT)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(QUOTE)) == 1));
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(QUOTE)) == 1,
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(CAPTION))));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
throw new AssertionError(e);
|
||||
@ -650,6 +656,7 @@ public class AttachmentDatabase extends Database {
|
||||
contentValues.put(WIDTH, attachment.getWidth());
|
||||
contentValues.put(HEIGHT, attachment.getHeight());
|
||||
contentValues.put(QUOTE, quote);
|
||||
contentValues.put(CAPTION, attachment.getCaption());
|
||||
|
||||
if (dataInfo != null) {
|
||||
contentValues.put(DATA, dataInfo.file.getAbsolutePath());
|
||||
|
@ -35,6 +35,7 @@ public class MediaDatabase extends Database {
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.WIDTH + ", "
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.HEIGHT + ", "
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.QUOTE + ", "
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CAPTION + ", "
|
||||
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.NAME + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.MESSAGE_BOX + ", "
|
||||
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_SENT + ", "
|
||||
@ -84,7 +85,9 @@ public class MediaDatabase extends Database {
|
||||
private final long date;
|
||||
private final boolean outgoing;
|
||||
|
||||
private MediaRecord(DatabaseAttachment attachment, @Nullable Address address, long date, boolean outgoing) {
|
||||
// TODO: Make private again
|
||||
public MediaRecord(DatabaseAttachment attachment, @Nullable Address address, long date, boolean outgoing) {
|
||||
// private MediaRecord(DatabaseAttachment attachment, @Nullable Address address, long date, boolean outgoing) {
|
||||
this.attachment = attachment;
|
||||
this.address = address;
|
||||
this.date = date;
|
||||
|
@ -163,7 +163,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
"'" + AttachmentDatabase.QUOTE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.QUOTE + ", " +
|
||||
"'" + AttachmentDatabase.CONTENT_DISPOSITION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_DISPOSITION + ", " +
|
||||
"'" + AttachmentDatabase.NAME + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.NAME + ", " +
|
||||
"'" + AttachmentDatabase.TRANSFER_STATE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFER_STATE +
|
||||
"'" + AttachmentDatabase.TRANSFER_STATE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFER_STATE + ", " +
|
||||
"'" + AttachmentDatabase.CAPTION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CAPTION +
|
||||
")) AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS,
|
||||
};
|
||||
|
||||
@ -715,7 +716,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
databaseAttachment.isVoiceNote(),
|
||||
databaseAttachment.getWidth(),
|
||||
databaseAttachment.getHeight(),
|
||||
databaseAttachment.isQuote()));
|
||||
databaseAttachment.isQuote(),
|
||||
databaseAttachment.getCaption()));
|
||||
}
|
||||
|
||||
return insertMediaMessage(request.getBody(),
|
||||
|
@ -227,7 +227,8 @@ public class MmsSmsDatabase extends Database {
|
||||
"'" + AttachmentDatabase.QUOTE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.QUOTE + ", " +
|
||||
"'" + AttachmentDatabase.CONTENT_DISPOSITION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_DISPOSITION + ", " +
|
||||
"'" + AttachmentDatabase.NAME + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.NAME + ", " +
|
||||
"'" + AttachmentDatabase.TRANSFER_STATE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFER_STATE +
|
||||
"'" + AttachmentDatabase.TRANSFER_STATE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFER_STATE + ", " +
|
||||
"'" + AttachmentDatabase.CAPTION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CAPTION +
|
||||
")) AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS,
|
||||
SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
|
||||
SmsDatabase.TYPE, SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
|
||||
@ -326,6 +327,7 @@ public class MmsSmsDatabase extends Database {
|
||||
mmsColumnsPresent.add(AttachmentDatabase.WIDTH);
|
||||
mmsColumnsPresent.add(AttachmentDatabase.HEIGHT);
|
||||
mmsColumnsPresent.add(AttachmentDatabase.QUOTE);
|
||||
mmsColumnsPresent.add(AttachmentDatabase.CAPTION);
|
||||
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_DISPOSITION);
|
||||
mmsColumnsPresent.add(AttachmentDatabase.NAME);
|
||||
mmsColumnsPresent.add(AttachmentDatabase.TRANSFER_STATE);
|
||||
|
@ -57,8 +57,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
private static final int QUOTE_MISSING = 11;
|
||||
private static final int NOTIFICATION_CHANNELS = 12;
|
||||
private static final int SECRET_SENDER = 13;
|
||||
private static final int ATTACHMENT_CAPTIONS = 14;
|
||||
|
||||
private static final int DATABASE_VERSION = 13;
|
||||
private static final int DATABASE_VERSION = 14;
|
||||
private static final String DATABASE_NAME = "signal.db";
|
||||
|
||||
private final Context context;
|
||||
@ -294,6 +295,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL("ALTER TABLE sms ADD COLUMN unidentified INTEGER DEFAULT 0");
|
||||
}
|
||||
|
||||
if (oldVersion < ATTACHMENT_CAPTIONS) {
|
||||
db.execSQL("ALTER TABLE part ADD COLUMN caption TEXT DEFAULT NULL");
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
@ -112,7 +112,7 @@ public class GroupManager {
|
||||
|
||||
if (avatar != null) {
|
||||
Uri avatarUri = MemoryBlobProvider.getInstance().createSingleUseUri(avatar);
|
||||
avatarAttachment = new UriAttachment(avatarUri, MediaUtil.IMAGE_PNG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length, null, false, false);
|
||||
avatarAttachment = new UriAttachment(avatarUri, MediaUtil.IMAGE_PNG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length, null, false, false, null);
|
||||
}
|
||||
|
||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, null, Collections.emptyList());
|
||||
|
@ -92,6 +92,16 @@ public class AttachmentDownloadJob extends ContextJob implements InjectableType
|
||||
@Override
|
||||
public void onAdded() {
|
||||
Log.i(TAG, "onAdded() messageId: " + messageId + " partRowId: " + partRowId + " partUniqueId: " + partUniqueId + " manual: " + manual);
|
||||
|
||||
final AttachmentDatabase database = DatabaseFactory.getAttachmentDatabase(context);
|
||||
final AttachmentId attachmentId = new AttachmentId(partRowId, partUniqueId);
|
||||
final DatabaseAttachment attachment = database.getAttachment(attachmentId);
|
||||
final boolean pending = attachment != null && attachment.getTransferState() != AttachmentDatabase.TRANSFER_PROGRESS_DONE;
|
||||
|
||||
if (pending && (manual || AttachmentUtil.isAutoDownloadPermitted(context, attachment))) {
|
||||
Log.i(TAG, "onAdded() Marking attachment progress as 'started'");
|
||||
database.setTransferState(messageId, attachmentId, AttachmentDatabase.TRANSFER_PROGRESS_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -241,7 +241,7 @@ public class MmsDownloadJob extends ContextJob {
|
||||
|
||||
attachments.add(new UriAttachment(uri, Util.toIsoString(part.getContentType()),
|
||||
AttachmentDatabase.TRANSFER_PROGRESS_DONE,
|
||||
part.getData().length, name, false, false));
|
||||
part.getData().length, name, false, false, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class PushSendJob extends SendJob {
|
||||
@ -120,6 +121,7 @@ public abstract class PushSendJob extends SendJob {
|
||||
.withVoiceNote(attachment.isVoiceNote())
|
||||
.withWidth(attachment.getWidth())
|
||||
.withHeight(attachment.getHeight())
|
||||
.withCaption(attachment.getCaption())
|
||||
.withListener((total, progress) -> EventBus.getDefault().postSticky(new PartProgressEvent(attachment, total, progress)))
|
||||
.build();
|
||||
} catch (IOException ioe) {
|
||||
|
@ -0,0 +1,100 @@
|
||||
package org.thoughtcrime.securesms.mediapreview;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AlbumRailAdapter extends RecyclerView.Adapter<AlbumRailAdapter.AlbumRailViewHolder> {
|
||||
|
||||
private final GlideRequests glideRequests;
|
||||
private final List<MediaRecord> records;
|
||||
private final RailItemClickedListener listener;
|
||||
|
||||
private int activePosition;
|
||||
|
||||
public AlbumRailAdapter(@NonNull GlideRequests glideRequests, @NonNull RailItemClickedListener listener) {
|
||||
this.glideRequests = glideRequests;
|
||||
this.records = new ArrayList<>();
|
||||
this.listener = listener;
|
||||
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AlbumRailViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
||||
return new AlbumRailViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.media_preview_album_rail_item, viewGroup, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull AlbumRailViewHolder albumRailViewHolder, int i) {
|
||||
albumRailViewHolder.bind(records.get(i), i == activePosition, glideRequests, listener, i - activePosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(@NonNull AlbumRailViewHolder holder) {
|
||||
holder.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return records.get(position).getAttachment().getAttachmentId().getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return records.size();
|
||||
}
|
||||
|
||||
public void setRecords(@NonNull List<MediaRecord> records, int activePosition) {
|
||||
this.activePosition = activePosition;
|
||||
|
||||
this.records.clear();
|
||||
this.records.addAll(records);
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
static class AlbumRailViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final ThumbnailView image;
|
||||
|
||||
AlbumRailViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
image = (ThumbnailView) itemView;
|
||||
}
|
||||
|
||||
void bind(@NonNull MediaRecord record, boolean isActive, @NonNull GlideRequests glideRequests,
|
||||
@NonNull RailItemClickedListener railItemClickedListener, int distanceFromActive)
|
||||
{
|
||||
if (record.getAttachment().getThumbnailUri() != null) {
|
||||
image.setImageResource(glideRequests, record.getAttachment().getThumbnailUri());
|
||||
} else if (record.getAttachment().getDataUri() != null) {
|
||||
image.setImageResource(glideRequests, record.getAttachment().getDataUri());
|
||||
} else {
|
||||
image.clear(glideRequests);
|
||||
}
|
||||
|
||||
image.setBackgroundResource(isActive ? R.drawable.album_rail_item_background : 0);
|
||||
image.setOnClickListener(v -> railItemClickedListener.onRailItemClicked(distanceFromActive));
|
||||
}
|
||||
|
||||
void recycle() {
|
||||
image.setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
public interface RailItemClickedListener {
|
||||
void onRailItemClicked(int distanceFromActive);
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package org.thoughtcrime.securesms.mediapreview;
|
||||
|
||||
import android.arch.lifecycle.LiveData;
|
||||
import android.arch.lifecycle.MutableLiveData;
|
||||
import android.arch.lifecycle.ViewModel;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class MediaPreviewViewModel extends ViewModel {
|
||||
|
||||
private final MutableLiveData<PreviewData> previewData = new MutableLiveData<>();
|
||||
|
||||
private boolean leftIsRecent;
|
||||
|
||||
private @Nullable Cursor cursor;
|
||||
|
||||
public void setCursor(@Nullable Cursor cursor, boolean leftIsRecent) {
|
||||
this.cursor = cursor;
|
||||
this.leftIsRecent = leftIsRecent;
|
||||
}
|
||||
|
||||
public void setActiveAlbumRailItem(@NonNull Context context, int activePosition) {
|
||||
if (cursor == null) {
|
||||
previewData.postValue(new PreviewData(Collections.emptyList(), null, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
activePosition = getCursorPosition(activePosition);
|
||||
|
||||
cursor.moveToPosition(activePosition);
|
||||
|
||||
MediaRecord activeRecord = MediaRecord.from(context, cursor);
|
||||
LinkedList<MediaRecord> rail = new LinkedList<>();
|
||||
|
||||
rail.add(activeRecord);
|
||||
|
||||
while (cursor.moveToPrevious()) {
|
||||
MediaRecord record = MediaRecord.from(context, cursor);
|
||||
if (record.getAttachment().getMmsId() == activeRecord.getAttachment().getMmsId()) {
|
||||
rail.addFirst(record);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cursor.moveToPosition(activePosition);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
MediaRecord record = MediaRecord.from(context, cursor);
|
||||
if (record.getAttachment().getMmsId() == activeRecord.getAttachment().getMmsId()) {
|
||||
rail.addLast(record);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!leftIsRecent) {
|
||||
Collections.reverse(rail);
|
||||
}
|
||||
|
||||
previewData.postValue(new PreviewData(rail.size() > 1 ? rail : Collections.emptyList(),
|
||||
activeRecord.getAttachment().getCaption(),
|
||||
rail.indexOf(activeRecord)));
|
||||
}
|
||||
|
||||
private int getCursorPosition(int position) {
|
||||
if (cursor == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (leftIsRecent) return position;
|
||||
else return cursor.getCount() - 1 - position;
|
||||
}
|
||||
|
||||
public LiveData<PreviewData> getPreviewData() {
|
||||
return previewData;
|
||||
}
|
||||
|
||||
public static class PreviewData {
|
||||
private final List<MediaRecord> albumThumbnails;
|
||||
private final String caption;
|
||||
private final int activePosition;
|
||||
|
||||
public PreviewData(@NonNull List<MediaRecord> albumThumbnails, @Nullable String caption, int activePosition) {
|
||||
this.albumThumbnails = albumThumbnails;
|
||||
this.caption = caption;
|
||||
this.activePosition = activePosition;
|
||||
}
|
||||
|
||||
public @NonNull List<MediaRecord> getAlbumThumbnails() {
|
||||
return albumThumbnails;
|
||||
}
|
||||
|
||||
public @Nullable String getCaption() {
|
||||
return caption;
|
||||
}
|
||||
|
||||
public int getActivePosition() {
|
||||
return activePosition;
|
||||
}
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ import android.provider.OpenableColumns;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
@ -493,6 +494,7 @@ public class AttachmentManager {
|
||||
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize());
|
||||
intent.putExtra(MediaPreviewActivity.CAPTION_EXTRA, slide.getCaption().orNull());
|
||||
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, true);
|
||||
intent.setDataAndType(slide.getUri(), slide.getContentType());
|
||||
|
||||
|
@ -38,7 +38,7 @@ public class AudioSlide extends Slide {
|
||||
}
|
||||
|
||||
public AudioSlide(Context context, Uri uri, long dataSize, String contentType, boolean voiceNote) {
|
||||
super(context, new UriAttachment(uri, null, contentType, AttachmentDatabase.TRANSFER_PROGRESS_STARTED, dataSize, 0, 0, null, null, voiceNote, false));
|
||||
super(context, new UriAttachment(uri, null, contentType, AttachmentDatabase.TRANSFER_PROGRESS_STARTED, dataSize, 0, 0, null, null, voiceNote, false, null));
|
||||
}
|
||||
|
||||
public AudioSlide(Context context, Attachment attachment) {
|
||||
|
@ -41,7 +41,6 @@ public abstract class Slide {
|
||||
public Slide(@NonNull Context context, @NonNull Attachment attachment) {
|
||||
this.context = context;
|
||||
this.attachment = attachment;
|
||||
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
@ -63,6 +62,11 @@ public abstract class Slide {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Optional<String> getCaption() {
|
||||
return Optional.fromNullable(attachment.getCaption());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Optional<String> getFileName() {
|
||||
return Optional.fromNullable(attachment.getFileName());
|
||||
@ -112,7 +116,7 @@ public abstract class Slide {
|
||||
getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_PENDING;
|
||||
}
|
||||
|
||||
public long getTransferState() {
|
||||
public int getTransferState() {
|
||||
return attachment.getTransferState();
|
||||
}
|
||||
|
||||
@ -152,7 +156,8 @@ public abstract class Slide {
|
||||
fileName,
|
||||
fastPreflightId,
|
||||
voiceNote,
|
||||
quote);
|
||||
quote,
|
||||
null);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
@ -103,6 +105,10 @@ public class SlideDeck {
|
||||
return null;
|
||||
}
|
||||
|
||||
public @NonNull List<Slide> getThumbnailSlides() {
|
||||
return Stream.of(slides).filter(Slide::hasImage).toList();
|
||||
}
|
||||
|
||||
public @Nullable AudioSlide getAudioSlide() {
|
||||
for (Slide slide : slides) {
|
||||
if (slide.hasAudio()) {
|
||||
|
@ -0,0 +1,9 @@
|
||||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SlidesClickedListener {
|
||||
void onClick(View v, List<Slide> slides);
|
||||
}
|
@ -21,6 +21,7 @@ import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
@ -46,6 +47,7 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
@ -70,6 +72,7 @@ public class VideoPlayer extends FrameLayout {
|
||||
@Nullable private final PlayerView exoView;
|
||||
|
||||
@Nullable private SimpleExoPlayer exoPlayer;
|
||||
@Nullable private PlayerControlView exoControls;
|
||||
@Nullable private AttachmentServer attachmentServer;
|
||||
@Nullable private Window window;
|
||||
|
||||
@ -89,6 +92,8 @@ public class VideoPlayer extends FrameLayout {
|
||||
if (Build.VERSION.SDK_INT >= 16) {
|
||||
this.exoView = ViewUtil.findById(this, R.id.video_view);
|
||||
this.videoView = null;
|
||||
this.exoControls = new PlayerControlView(getContext());
|
||||
this.exoControls.setShowTimeoutMs(-1);
|
||||
} else {
|
||||
this.videoView = ViewUtil.findById(this, R.id.video_view);
|
||||
this.exoView = null;
|
||||
@ -111,6 +116,19 @@ public class VideoPlayer extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void hideControls() {
|
||||
if (this.exoView != null) {
|
||||
this.exoView.hideController();
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable View getControlView() {
|
||||
if (this.exoControls != null) {
|
||||
return this.exoControls;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
if (this.attachmentServer != null) {
|
||||
this.attachmentServer.stop();
|
||||
@ -137,6 +155,8 @@ public class VideoPlayer extends FrameLayout {
|
||||
exoPlayer.addListener(new ExoPlayerListener(window));
|
||||
//noinspection ConstantConditions
|
||||
exoView.setPlayer(exoPlayer);
|
||||
//noinspection ConstantConditions
|
||||
exoControls.setPlayer(exoPlayer);
|
||||
|
||||
DefaultDataSourceFactory defaultDataSourceFactory = new DefaultDataSourceFactory(getContext(), "GenericUserAgent", null);
|
||||
AttachmentDataSourceFactory attachmentDataSourceFactory = new AttachmentDataSourceFactory(getContext(), defaultDataSourceFactory, null);
|
||||
|
Loading…
x
Reference in New Issue
Block a user