kopia lustrzana https://github.com/ryukoposting/Signal-Android
Allow forwarding of Text Stories.
rodzic
43ad0b2294
commit
e3c491860a
|
@ -130,13 +130,15 @@ class MultiselectForwardFragment :
|
|||
|
||||
container.addView(bottomBar)
|
||||
|
||||
contactSearchMediator.getSelectionState().observe(viewLifecycleOwner) {
|
||||
shareSelectionAdapter.submitList(it.mapIndexed { index, key -> ShareSelectionMappingModel(key.requireShareContact(), index == 0) })
|
||||
contactSearchMediator.getSelectionState().observe(viewLifecycleOwner) { contactSelection ->
|
||||
shareSelectionAdapter.submitList(contactSelection.mapIndexed { index, key -> ShareSelectionMappingModel(key.requireShareContact(), index == 0) })
|
||||
|
||||
if (it.isNotEmpty() && !bottomBar.isVisible) {
|
||||
addMessage.visible = contactSelection.any { key -> key !is ContactSearchKey.Story } && getMultiShareArgs().isNotEmpty()
|
||||
|
||||
if (contactSelection.isNotEmpty() && !bottomBar.isVisible) {
|
||||
bottomBar.animation = AnimationUtils.loadAnimation(requireContext(), R.anim.slide_fade_from_bottom)
|
||||
bottomBar.visible = true
|
||||
} else if (it.isEmpty() && bottomBar.isVisible) {
|
||||
} else if (contactSelection.isEmpty() && bottomBar.isVisible) {
|
||||
bottomBar.animation = AnimationUtils.loadAnimation(requireContext(), R.anim.slide_fade_to_bottom)
|
||||
bottomBar.visible = false
|
||||
}
|
||||
|
@ -162,8 +164,6 @@ class MultiselectForwardFragment :
|
|||
sendButton.isEnabled = it.stage == MultiselectForwardState.Stage.Selection
|
||||
}
|
||||
|
||||
addMessage.visible = getMultiShareArgs().isNotEmpty()
|
||||
|
||||
setFragmentResultListener(CreateStoryWithViewersFragment.REQUEST_KEY) { _, bundle ->
|
||||
val recipientId: RecipientId = bundle.getParcelable(CreateStoryWithViewersFragment.STORY_RECIPIENT)!!
|
||||
contactSearchMediator.setKeysSelected(setOf(ContactSearchKey.Story(recipientId)))
|
||||
|
@ -282,40 +282,48 @@ class MultiselectForwardFragment :
|
|||
query = contactSearchState.query
|
||||
|
||||
if (Stories.isFeatureEnabled() && isSelectedMediaValidForStories()) {
|
||||
val expandedConfig: ContactSearchConfiguration.ExpandConfig? = if (isSelectedMediaValidForNonStories()) {
|
||||
ContactSearchConfiguration.ExpandConfig(
|
||||
isExpanded = contactSearchState.expandedSections.contains(ContactSearchConfiguration.SectionKey.STORIES)
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
addSection(
|
||||
ContactSearchConfiguration.Section.Stories(
|
||||
groupStories = contactSearchState.groupStories,
|
||||
includeHeader = true,
|
||||
headerAction = getHeaderAction(childFragmentManager),
|
||||
expandConfig = ContactSearchConfiguration.ExpandConfig(
|
||||
isExpanded = contactSearchState.expandedSections.contains(ContactSearchConfiguration.SectionKey.STORIES)
|
||||
expandConfig = expandedConfig
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (isSelectedMediaValidForNonStories()) {
|
||||
if (query.isNullOrEmpty()) {
|
||||
addSection(
|
||||
ContactSearchConfiguration.Section.Recents(
|
||||
includeHeader = true
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (query.isNullOrEmpty()) {
|
||||
addSection(
|
||||
ContactSearchConfiguration.Section.Recents(
|
||||
includeHeader = true
|
||||
ContactSearchConfiguration.Section.Individuals(
|
||||
includeHeader = true,
|
||||
transportType = if (includeSms()) ContactSearchConfiguration.TransportType.ALL else ContactSearchConfiguration.TransportType.PUSH,
|
||||
includeSelf = true
|
||||
)
|
||||
)
|
||||
|
||||
addSection(
|
||||
ContactSearchConfiguration.Section.Groups(
|
||||
includeHeader = true,
|
||||
includeMms = includeSms()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
addSection(
|
||||
ContactSearchConfiguration.Section.Individuals(
|
||||
includeHeader = true,
|
||||
transportType = if (includeSms()) ContactSearchConfiguration.TransportType.ALL else ContactSearchConfiguration.TransportType.PUSH,
|
||||
includeSelf = true
|
||||
)
|
||||
)
|
||||
|
||||
addSection(
|
||||
ContactSearchConfiguration.Section.Groups(
|
||||
includeHeader = true,
|
||||
includeMms = includeSms()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,6 +335,10 @@ class MultiselectForwardFragment :
|
|||
return getMultiShareArgs().all { it.isValidForStories }
|
||||
}
|
||||
|
||||
private fun isSelectedMediaValidForNonStories(): Boolean {
|
||||
return getMultiShareArgs().all { it.isValidForNonStories }
|
||||
}
|
||||
|
||||
override fun onGroupStoryClicked() {
|
||||
ChooseGroupStoryBottomSheet().show(parentFragmentManager, ChooseGroupStoryBottomSheet.GROUP_STORY)
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ class MultiselectForwardFragmentArgs(
|
|||
|
||||
val linkPreview = mediaMessage?.linkPreviews?.firstOrNull()
|
||||
builder.withLinkPreview(linkPreview)
|
||||
builder.asTextStory(mediaMessage?.storyType?.isTextStory ?: false)
|
||||
}
|
||||
|
||||
if (conversationMessage.messageRecord.isMms && conversationMessage.multiselectCollection.isMediaSelected(selectedParts)) {
|
||||
|
|
|
@ -61,13 +61,17 @@ class MultiselectForwardRepository(context: Context) {
|
|||
val results = mappedArgs.sortedBy { it.timestamp }.map { MultiShareSender.sendSync(it) }
|
||||
|
||||
if (additionalMessage.isNotEmpty()) {
|
||||
val additional = MultiShareArgs.Builder(sharedContactsAndThreads)
|
||||
val additional = MultiShareArgs.Builder(sharedContactsAndThreads.filterNot { it.isStory }.toSet())
|
||||
.withDraftText(additionalMessage)
|
||||
.build()
|
||||
|
||||
val additionalResult: MultiShareSender.MultiShareSendResultCollection = MultiShareSender.sendSync(additional)
|
||||
if (additional.shareContactAndThreads.isNotEmpty()) {
|
||||
val additionalResult: MultiShareSender.MultiShareSendResultCollection = MultiShareSender.sendSync(additional)
|
||||
|
||||
handleResults(results + additionalResult, resultHandlers)
|
||||
handleResults(results + additionalResult, resultHandlers)
|
||||
} else {
|
||||
handleResults(results, resultHandlers)
|
||||
}
|
||||
} else {
|
||||
handleResults(results, resultHandlers)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
|||
import org.thoughtcrime.securesms.mediasend.Media;
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.ParcelUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -37,6 +38,7 @@ public final class MultiShareArgs implements Parcelable {
|
|||
private final List<Mention> mentions;
|
||||
private final long timestamp;
|
||||
private final long expiresAt;
|
||||
private final boolean isTextStory;
|
||||
|
||||
private MultiShareArgs(@NonNull Builder builder) {
|
||||
shareContactAndThreads = builder.shareContactAndThreads;
|
||||
|
@ -51,6 +53,7 @@ public final class MultiShareArgs implements Parcelable {
|
|||
mentions = builder.mentions == null ? new ArrayList<>() : new ArrayList<>(builder.mentions);
|
||||
timestamp = builder.timestamp;
|
||||
expiresAt = builder.expiresAt;
|
||||
isTextStory = builder.isTextStory;
|
||||
}
|
||||
|
||||
protected MultiShareArgs(Parcel in) {
|
||||
|
@ -65,6 +68,7 @@ public final class MultiShareArgs implements Parcelable {
|
|||
mentions = in.createTypedArrayList(Mention.CREATOR);
|
||||
timestamp = in.readLong();
|
||||
expiresAt = in.readLong();
|
||||
isTextStory = ParcelUtil.readBoolean(in);
|
||||
|
||||
String linkedPreviewString = in.readString();
|
||||
LinkPreview preview;
|
||||
|
@ -109,6 +113,10 @@ public final class MultiShareArgs implements Parcelable {
|
|||
return viewOnce;
|
||||
}
|
||||
|
||||
public boolean isTextStory() {
|
||||
return isTextStory;
|
||||
}
|
||||
|
||||
public @Nullable LinkPreview getLinkPreview() {
|
||||
return linkPreview;
|
||||
}
|
||||
|
@ -126,7 +134,11 @@ public final class MultiShareArgs implements Parcelable {
|
|||
}
|
||||
|
||||
public boolean isValidForStories() {
|
||||
return !media.isEmpty() && media.stream().allMatch(m -> MediaUtil.isImageOrVideoType(m.getMimeType()) && !MediaUtil.isGif(m.getMimeType()));
|
||||
return isTextStory || !media.isEmpty() && media.stream().allMatch(m -> MediaUtil.isImageOrVideoType(m.getMimeType()) && !MediaUtil.isGif(m.getMimeType()));
|
||||
}
|
||||
|
||||
public boolean isValidForNonStories() {
|
||||
return !isTextStory;
|
||||
}
|
||||
|
||||
public @NonNull InterstitialContentType getInterstitialContentType() {
|
||||
|
@ -174,6 +186,7 @@ public final class MultiShareArgs implements Parcelable {
|
|||
dest.writeTypedList(mentions);
|
||||
dest.writeLong(timestamp);
|
||||
dest.writeLong(expiresAt);
|
||||
ParcelUtil.writeBoolean(dest, isTextStory);
|
||||
|
||||
if (linkPreview != null) {
|
||||
try {
|
||||
|
@ -201,7 +214,8 @@ public final class MultiShareArgs implements Parcelable {
|
|||
.withStickerLocator(stickerLocator)
|
||||
.withMentions(mentions)
|
||||
.withTimestamp(timestamp)
|
||||
.withExpiration(expiresAt);
|
||||
.withExpiration(expiresAt)
|
||||
.asTextStory(isTextStory);
|
||||
}
|
||||
|
||||
private boolean requiresInterstitial() {
|
||||
|
@ -224,6 +238,7 @@ public final class MultiShareArgs implements Parcelable {
|
|||
private List<Mention> mentions;
|
||||
private long timestamp;
|
||||
private long expiresAt;
|
||||
private boolean isTextStory;
|
||||
|
||||
public Builder(@NonNull Set<ShareContactAndThread> shareContactAndThreads) {
|
||||
this.shareContactAndThreads = shareContactAndThreads;
|
||||
|
@ -284,6 +299,11 @@ public final class MultiShareArgs implements Parcelable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Builder asTextStory(boolean isTextStory) {
|
||||
this.isTextStory = isTextStory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull MultiShareArgs build() {
|
||||
return new MultiShareArgs(this);
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ public final class MultiShareSender {
|
|||
|
||||
if ((recipient.isMmsGroup() || recipient.getEmail().isPresent()) && !isMmsEnabled) {
|
||||
results.add(new MultiShareSendResult(shareContactAndThread, MultiShareSendResult.Type.MMS_NOT_ENABLED));
|
||||
} else if (hasMmsMedia && transport.isSms() || hasPushMedia && !transport.isSms()) {
|
||||
} else if (hasMmsMedia && transport.isSms() || hasPushMedia && !transport.isSms() || multiShareArgs.isTextStory()) {
|
||||
sendMediaMessage(context, multiShareArgs, recipient, slideDeck, transport, shareContactAndThread.getThreadId(), forceSms, expiresIn, multiShareArgs.isViewOnce(), subscriptionId, mentions, shareContactAndThread.isStory());
|
||||
results.add(new MultiShareSendResult(shareContactAndThread, MultiShareSendResult.Type.SUCCESS));
|
||||
} else if (shareContactAndThread.isStory()) {
|
||||
|
@ -184,32 +184,52 @@ public final class MultiShareSender {
|
|||
SignalDatabase.groups().markDisplayAsStory(recipient.requireGroupId());
|
||||
}
|
||||
|
||||
for (final Slide slide : slideDeck.getSlides()) {
|
||||
SlideDeck singletonDeck = new SlideDeck();
|
||||
singletonDeck.addSlide(slide);
|
||||
|
||||
if (multiShareArgs.isTextStory()) {
|
||||
OutgoingMediaMessage outgoingMediaMessage = new OutgoingMediaMessage(recipient,
|
||||
singletonDeck,
|
||||
new SlideDeck(),
|
||||
body,
|
||||
System.currentTimeMillis(),
|
||||
subscriptionId,
|
||||
expiresIn,
|
||||
isViewOnce,
|
||||
0L,
|
||||
false,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT,
|
||||
storyType,
|
||||
storyType.toTextStoryType(),
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
Collections.emptyList(),
|
||||
multiShareArgs.getLinkPreview() != null ? Collections.singletonList(multiShareArgs.getLinkPreview())
|
||||
: Collections.emptyList(),
|
||||
validatedMentions);
|
||||
Collections.emptyList());
|
||||
|
||||
outgoingMessages.add(outgoingMediaMessage);
|
||||
} else {
|
||||
for (final Slide slide : slideDeck.getSlides()) {
|
||||
SlideDeck singletonDeck = new SlideDeck();
|
||||
singletonDeck.addSlide(slide);
|
||||
|
||||
// XXX We must do this to avoid sending out messages to the same recipient with the same
|
||||
// sentTimestamp. If we do this, they'll be considered dupes by the receiver.
|
||||
ThreadUtil.sleep(5);
|
||||
OutgoingMediaMessage outgoingMediaMessage = new OutgoingMediaMessage(recipient,
|
||||
singletonDeck,
|
||||
body,
|
||||
System.currentTimeMillis(),
|
||||
subscriptionId,
|
||||
0L,
|
||||
false,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT,
|
||||
storyType,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
validatedMentions);
|
||||
|
||||
outgoingMessages.add(outgoingMediaMessage);
|
||||
|
||||
// XXX We must do this to avoid sending out messages to the same recipient with the same
|
||||
// sentTimestamp. If we do this, they'll be considered dupes by the receiver.
|
||||
ThreadUtil.sleep(5);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OutgoingMediaMessage outgoingMediaMessage = new OutgoingMediaMessage(recipient,
|
||||
|
|
Ładowanie…
Reference in New Issue