mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-08-14 09:13:42 +01:00
Support streamable stories.
This commit is contained in:
committed by
Greyson Parrelli
parent
32fa56055e
commit
d40b4382e9
+15
-5
@@ -98,6 +98,7 @@ import org.thoughtcrime.securesms.util.DateUtils
|
||||
import org.thoughtcrime.securesms.util.LinkUtil
|
||||
import org.thoughtcrime.securesms.util.LongClickCopySpan
|
||||
import org.thoughtcrime.securesms.util.LongClickMovementMethod
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.Projection
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.fragments.requireListener
|
||||
@@ -850,7 +851,7 @@ class StoryViewerPageFragment :
|
||||
|
||||
private fun markViewedIfAble() {
|
||||
val post = viewModel.getPost() ?: return
|
||||
if (post.content.transferState == AttachmentTable.TRANSFER_PROGRESS_DONE) {
|
||||
if (post.content.transferState == AttachmentTable.TRANSFER_PROGRESS_DONE || post.content.transferState == AttachmentTable.TRANSFER_PROGRESS_STARTED) {
|
||||
if (isResumed) {
|
||||
viewModel.markViewed(post)
|
||||
}
|
||||
@@ -895,6 +896,7 @@ class StoryViewerPageFragment :
|
||||
|
||||
when (post.content.transferState) {
|
||||
AttachmentTable.TRANSFER_PROGRESS_DONE -> {
|
||||
Log.d(TAG, "Story content download is done.")
|
||||
storySlate.moveToState(StorySlateView.State.HIDDEN, post.id)
|
||||
viewModel.setIsDisplayingSlate(false)
|
||||
markViewedIfAble()
|
||||
@@ -908,10 +910,18 @@ class StoryViewerPageFragment :
|
||||
}
|
||||
|
||||
AttachmentTable.TRANSFER_PROGRESS_STARTED -> {
|
||||
Log.d(TAG, "Story content download is in progress.")
|
||||
storySlate.moveToState(StorySlateView.State.LOADING, post.id)
|
||||
sharedViewModel.setContentIsReady()
|
||||
viewModel.setIsDisplayingSlate(true)
|
||||
val isStreamable = post.content is StoryPost.Content.AttachmentContent && MediaUtil.isInstantVideoSupported(post.content.attachment)
|
||||
if (isStreamable) {
|
||||
Log.d(TAG, "Story content is streamable while download is in progress.")
|
||||
storySlate.moveToState(StorySlateView.State.HIDDEN, post.id)
|
||||
viewModel.setIsDisplayingSlate(false)
|
||||
markViewedIfAble()
|
||||
} else {
|
||||
Log.d(TAG, "Story content download is in progress.")
|
||||
storySlate.moveToState(StorySlateView.State.LOADING, post.id)
|
||||
sharedViewModel.setContentIsReady()
|
||||
viewModel.setIsDisplayingSlate(true)
|
||||
}
|
||||
}
|
||||
|
||||
AttachmentTable.TRANSFER_PROGRESS_FAILED -> {
|
||||
|
||||
@@ -554,10 +554,13 @@ public class MediaUtil {
|
||||
}
|
||||
|
||||
public static boolean isInstantVideoSupported(Slide slide) {
|
||||
final Attachment attachment = slide.asAttachment();
|
||||
final boolean isIncremental = attachment.getIncrementalDigest() != null;
|
||||
final boolean hasIncrementalMacChunkSizeDefined = attachment.incrementalMacChunkSize > 0;
|
||||
final boolean contentTypeSupported = isVideoType(slide.getContentType());
|
||||
return isInstantVideoSupported(slide.asAttachment());
|
||||
}
|
||||
|
||||
public static boolean isInstantVideoSupported(Attachment attachment) {
|
||||
final boolean isIncremental = attachment.getIncrementalDigest() != null;
|
||||
final boolean hasIncrementalMacChunkSizeDefined = attachment.incrementalMacChunkSize > 0;
|
||||
final boolean contentTypeSupported = isVideoType(attachment.contentType);
|
||||
return isIncremental && contentTypeSupported && hasIncrementalMacChunkSizeDefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,4 +17,13 @@
|
||||
app:shutter_background_color="@color/core_black"
|
||||
app:surface_type="texture_view" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:indeterminateTint="@color/signal_colorOnSurfaceVariant"
|
||||
android:indeterminate="true" />
|
||||
|
||||
</FrameLayout>
|
||||
+2
-2
@@ -35,7 +35,7 @@ class TransferControlsTest {
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockkStatic(MediaUtil::class)
|
||||
every { MediaUtil.isInstantVideoSupported(any()) } returns false
|
||||
every { MediaUtil.isInstantVideoSupported(any() as Attachment) } returns false
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -185,7 +185,7 @@ class TransferControlsTest {
|
||||
|
||||
@Test
|
||||
fun `gallery pending playable is corner without item count`() {
|
||||
every { MediaUtil.isInstantVideoSupported(any()) } returns true
|
||||
every { MediaUtil.isInstantVideoSupported(any() as Attachment) } returns true
|
||||
val state = stateOf(listOf(slide(AttachmentTable.TRANSFER_PROGRESS_PENDING), slide(AttachmentTable.TRANSFER_PROGRESS_PENDING)))
|
||||
val render = TransferControls.deriveRenderState(state) as TransferControlsRenderState.Pending
|
||||
assertEquals(TransferControls.Placement.CORNER, render.placement)
|
||||
|
||||
+21
@@ -58,6 +58,27 @@ class BetterCipherInputStream(
|
||||
|
||||
override fun markSupported(): Boolean = false
|
||||
|
||||
/**
|
||||
* Since AES/CBC decryption is sequential, we can't just skip bytes on the underlying ciphertext stream
|
||||
* so we must process every preceding ciphertext block to keep its internal chaining state correct.
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
override fun skip(byteCount: Long): Long {
|
||||
var totalSkipped = 0L
|
||||
val buffer = ByteArray(4096)
|
||||
|
||||
while (totalSkipped < byteCount) {
|
||||
val toRead = min(buffer.size.toLong(), byteCount - totalSkipped).toInt()
|
||||
val read = read(buffer, 0, toRead)
|
||||
if (read == -1) {
|
||||
break
|
||||
}
|
||||
totalSkipped += read
|
||||
}
|
||||
|
||||
return totalSkipped
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun readIncremental(outputBuffer: ByteArray, originalOffset: Int, originalLength: Int): Int {
|
||||
var offset = originalOffset
|
||||
|
||||
Reference in New Issue
Block a user