Fix story splitting in multishare flow.

This commit is contained in:
Alex Hart 2023-01-06 15:19:11 -04:00
parent bdbeefe08e
commit af0fbdd2b2
4 changed files with 98 additions and 9 deletions

View file

@ -0,0 +1,38 @@
package org.thoughtcrime.securesms.sharing
import androidx.annotation.Discouraged
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
/**
* Timestamp provider for distribution lists, which will reuse previous
* timestamps for identical indices.
*/
class DistributionListMultiShareTimestampProvider(
getCurrentTimeMillis: () -> Duration = { System.currentTimeMillis().milliseconds },
sleepTimeout: Duration = 5.milliseconds
) : MultiShareTimestampProvider(getCurrentTimeMillis, sleepTimeout) {
private val timestamps = mutableListOf(getCurrentTimeMillis())
override fun getMillis(index: Int): Long {
fillToIndex(index)
return timestamps[index].inWholeMilliseconds
}
private fun fillToIndex(index: Int) {
if (index in timestamps.indices) {
return
}
(timestamps.size..index).forEach {
timestamps.add(it, waitForTime())
}
}
companion object {
@JvmStatic
@Discouraged(message = "This only exists because of Java.")
fun create(): DistributionListMultiShareTimestampProvider = DistributionListMultiShareTimestampProvider()
}
}

View file

@ -101,7 +101,7 @@ public final class MultiShareSender {
return new MultiShareSendResultCollection(results);
}
long distributionListSentTimestamp = System.currentTimeMillis();
DistributionListMultiShareTimestampProvider distributionListSentTimestamps = DistributionListMultiShareTimestampProvider.create();
for (ContactSearchKey.RecipientSearchKey recipientSearchKey : multiShareArgs.getRecipientSearchKeys()) {
Recipient recipient = Recipient.resolved(recipientSearchKey.getRecipientId());
@ -123,8 +123,9 @@ public final class MultiShareSender {
multiShareArgs.getLinkPreview() != null ||
!mentions.isEmpty() ||
needsSplit;
long sentTimestamp = recipient.isDistributionList() ? distributionListSentTimestamp : System.currentTimeMillis();
boolean canSendAsTextStory = recipientSearchKey.isStory() && multiShareArgs.isValidForTextStoryGeneration();
MultiShareTimestampProvider sentTimestamp = recipient.isDistributionList() ? distributionListSentTimestamps : MultiShareTimestampProvider.create();
boolean canSendAsTextStory = recipientSearchKey.isStory() && multiShareArgs.isValidForTextStoryGeneration();
if ((recipient.isMmsGroup() || recipient.getEmail().isPresent()) && !isMmsEnabled) {
results.add(new MultiShareSendResult(recipientSearchKey, MultiShareSendResult.Type.MMS_NOT_ENABLED));
@ -209,7 +210,7 @@ public final class MultiShareSender {
int subscriptionId,
@NonNull List<Mention> validatedMentions,
boolean isStory,
long sentTimestamp,
@NonNull MultiShareTimestampProvider sentTimestamps,
boolean canSendAsTextStory,
@NonNull List<OutgoingMessage> storiesToBatchSend,
@NonNull ChatColors generatedTextStoryBackgroundColor)
@ -242,7 +243,7 @@ public final class MultiShareSender {
OutgoingMessage outgoingMessage = new OutgoingMessage(recipient,
new SlideDeck(),
body,
sentTimestamp,
sentTimestamps.getMillis(0),
subscriptionId,
0L,
false,
@ -253,7 +254,7 @@ public final class MultiShareSender {
outgoingMessages.add(outgoingMessage);
} else if (canSendAsTextStory) {
outgoingMessages.add(generateTextStory(context, recipient, multiShareArgs, sentTimestamp, storyType, generatedTextStoryBackgroundColor));
outgoingMessages.add(generateTextStory(context, recipient, multiShareArgs, sentTimestamps.getMillis(0), storyType, generatedTextStoryBackgroundColor));
} else {
List<Slide> storySupportedSlides = slideDeck.getSlides()
.stream()
@ -269,14 +270,16 @@ public final class MultiShareSender {
.filter(it -> MediaUtil.isStorySupportedType(it.getContentType()))
.collect(Collectors.toList());
for (final Slide slide : storySupportedSlides) {
for (int i = 0; i < storySupportedSlides.size(); i++) {
Slide slide = storySupportedSlides.get(i);
SlideDeck singletonDeck = new SlideDeck();
singletonDeck.addSlide(slide);
OutgoingMessage outgoingMessage = new OutgoingMessage(recipient,
singletonDeck,
body,
sentTimestamp,
sentTimestamps.getMillis(i),
subscriptionId,
0L,
false,
@ -292,7 +295,7 @@ public final class MultiShareSender {
OutgoingMessage outgoingMessage = new OutgoingMessage(recipient,
slideDeck,
body,
sentTimestamp,
sentTimestamps.getMillis(0),
subscriptionId,
expiresIn,
isViewOnce,

View file

@ -0,0 +1,30 @@
package org.thoughtcrime.securesms.sharing
import androidx.annotation.Discouraged
import org.signal.core.util.ThreadUtil
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
/**
* Default multi-share timestamp provider, which will return a different timestamp on each invocation.
*/
open class MultiShareTimestampProvider(
private val getCurrentTime: () -> Duration = { System.currentTimeMillis().milliseconds },
private val sleepTimeout: Duration = 5.milliseconds
) {
open fun getMillis(index: Int): Long {
return waitForTime().inWholeMilliseconds
}
protected fun waitForTime(): Duration {
ThreadUtil.sleep(sleepTimeout.inWholeMilliseconds)
return getCurrentTime()
}
companion object {
@JvmStatic
@Discouraged(message = "This only exists because of Java.")
fun create(): MultiShareTimestampProvider = MultiShareTimestampProvider()
}
}

View file

@ -0,0 +1,18 @@
package org.thoughtcrime.securesms.sharing
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
class DistributionListMultiShareTimestampProviderTest {
@Test
fun `When I ask for index 4, then I expect to fill 4 new items`() {
val generator = mutableListOf(1L, 2, 3, 4, 5).map { it.seconds }.toMutableList()
val testSubject = DistributionListMultiShareTimestampProvider(getCurrentTimeMillis = { generator.removeAt(0) }, sleepTimeout = 0.seconds)
val actual = testSubject.getMillis(4).milliseconds
assertEquals(5.seconds, actual)
}
}