kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add ability to copy text slides in full.
rodzic
c4817ac017
commit
a44a105cbc
|
@ -69,8 +69,11 @@ import com.annimon.stream.Stream;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.signal.core.util.DimensionUnit;
|
import org.signal.core.util.DimensionUnit;
|
||||||
|
import org.signal.core.util.StreamUtil;
|
||||||
import org.signal.core.util.concurrent.SignalExecutors;
|
import org.signal.core.util.concurrent.SignalExecutors;
|
||||||
|
import org.signal.core.util.concurrent.SimpleTask;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.LoggingFragment;
|
import org.thoughtcrime.securesms.LoggingFragment;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
@ -133,6 +136,7 @@ import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
|
import org.thoughtcrime.securesms.mms.TextSlide;
|
||||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile;
|
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile;
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||||
|
@ -169,7 +173,6 @@ import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.WindowUtil;
|
import org.thoughtcrime.securesms.util.WindowUtil;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||||
import org.signal.core.util.concurrent.SimpleTask;
|
|
||||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.thoughtcrime.securesms.verify.VerifyIdentityActivity;
|
import org.thoughtcrime.securesms.verify.VerifyIdentityActivity;
|
||||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
||||||
|
@ -931,22 +934,44 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCopyMessage(final Set<MultiselectPart> multiselectParts) {
|
private void handleCopyMessage(final Set<MultiselectPart> multiselectParts) {
|
||||||
CharSequence bodies = Stream.of(multiselectParts)
|
SimpleTask.run(() -> extractBodies(multiselectParts),
|
||||||
|
bodies -> {
|
||||||
|
if (!Util.isEmpty(bodies)) {
|
||||||
|
Util.copyToClipboard(requireContext(), bodies);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NotNull CharSequence extractBodies(final Set<MultiselectPart> multiselectParts) {
|
||||||
|
return Stream.of(multiselectParts)
|
||||||
.sortBy(m -> m.getMessageRecord().getDateReceived())
|
.sortBy(m -> m.getMessageRecord().getDateReceived())
|
||||||
.map(MultiselectPart::getConversationMessage)
|
.map(MultiselectPart::getConversationMessage)
|
||||||
.distinct()
|
.distinct()
|
||||||
.map(m -> m.getDisplayBody(requireContext()))
|
.map(message -> {
|
||||||
.filterNot(TextUtils::isEmpty)
|
if (MessageRecordUtil.hasTextSlide(message.getMessageRecord())) {
|
||||||
|
TextSlide textSlide = MessageRecordUtil.requireTextSlide(message.getMessageRecord());
|
||||||
|
if (textSlide.getUri() == null) {
|
||||||
|
return message.getDisplayBody(requireContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream stream = PartAuthority.getAttachmentStream(requireContext(), textSlide.getUri())) {
|
||||||
|
String body = StreamUtil.readFullyAsString(stream);
|
||||||
|
return ConversationMessage.ConversationMessageFactory.createWithUnresolvedData(requireContext(), message.getMessageRecord(), body)
|
||||||
|
.getDisplayBody(requireContext());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to read text slide data.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return message.getDisplayBody(requireContext());
|
||||||
|
})
|
||||||
|
.filterNot(Util::isEmpty)
|
||||||
.collect(SpannableStringBuilder::new, (bodyBuilder, body) -> {
|
.collect(SpannableStringBuilder::new, (bodyBuilder, body) -> {
|
||||||
if (bodyBuilder.length() > 0) {
|
if (bodyBuilder.length() > 0) {
|
||||||
bodyBuilder.append('\n');
|
bodyBuilder.append('\n');
|
||||||
}
|
}
|
||||||
bodyBuilder.append(body);
|
bodyBuilder.append(body);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(bodies)) {
|
|
||||||
Util.copyToClipboard(requireContext(), bodies);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDeleteMessages(final Set<MultiselectPart> multiselectParts) {
|
private void handleDeleteMessages(final Set<MultiselectPart> multiselectParts) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.database.MmsSmsColumns
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
|
import org.thoughtcrime.securesms.mms.TextSlide
|
||||||
import org.thoughtcrime.securesms.stickers.StickerUrl
|
import org.thoughtcrime.securesms.stickers.StickerUrl
|
||||||
|
|
||||||
const val MAX_BODY_DISPLAY_LENGTH = 1000
|
const val MAX_BODY_DISPLAY_LENGTH = 1000
|
||||||
|
@ -78,6 +79,12 @@ fun MessageRecord.hasQuote(): Boolean =
|
||||||
fun MessageRecord.hasLinkPreview(): Boolean =
|
fun MessageRecord.hasLinkPreview(): Boolean =
|
||||||
isMms && (this as MmsMessageRecord).linkPreviews.isNotEmpty()
|
isMms && (this as MmsMessageRecord).linkPreviews.isNotEmpty()
|
||||||
|
|
||||||
|
fun MessageRecord.hasTextSlide(): Boolean =
|
||||||
|
isMms && (this as MmsMessageRecord).slideDeck.textSlide != null && this.slideDeck.textSlide?.uri != null
|
||||||
|
|
||||||
|
fun MessageRecord.requireTextSlide(): TextSlide =
|
||||||
|
requireNotNull((this as MmsMessageRecord).slideDeck.textSlide)
|
||||||
|
|
||||||
fun MessageRecord.hasBigImageLinkPreview(context: Context): Boolean {
|
fun MessageRecord.hasBigImageLinkPreview(context: Context): Boolean {
|
||||||
if (!hasLinkPreview()) {
|
if (!hasLinkPreview()) {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -153,8 +153,8 @@ public class Util {
|
||||||
return collection == null || collection.isEmpty();
|
return collection == null || collection.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isEmpty(@Nullable String value) {
|
public static boolean isEmpty(@Nullable CharSequence charSequence) {
|
||||||
return value == null || value.length() == 0;
|
return charSequence == null || charSequence.length() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasItems(@Nullable Collection<?> collection) {
|
public static boolean hasItems(@Nullable Collection<?> collection) {
|
||||||
|
|
Ładowanie…
Reference in New Issue