That fuck shit the fascists are using
at master 413 lines 13 kB view raw
1package org.tm.archive.sharing; 2 3import android.net.Uri; 4import android.os.Parcel; 5import android.os.Parcelable; 6import android.text.TextUtils; 7 8import androidx.annotation.NonNull; 9import androidx.annotation.Nullable; 10 11import com.annimon.stream.Stream; 12 13import org.signal.core.util.BreakIteratorCompat; 14import org.signal.core.util.logging.Log; 15import org.tm.archive.contacts.paged.ContactSearchKey; 16import org.tm.archive.contactshare.Contact; 17import org.tm.archive.database.model.Mention; 18import org.tm.archive.database.model.databaseprotos.BodyRangeList; 19import org.tm.archive.linkpreview.LinkPreview; 20import org.tm.archive.mediasend.Media; 21import org.tm.archive.stickers.StickerLocator; 22import org.tm.archive.stories.Stories; 23import org.tm.archive.util.MediaUtil; 24import org.tm.archive.util.ParcelUtil; 25import org.tm.archive.util.Util; 26 27import java.io.IOException; 28import java.util.ArrayList; 29import java.util.Collections; 30import java.util.HashSet; 31import java.util.List; 32import java.util.Set; 33import java.util.stream.Collectors; 34 35public final class MultiShareArgs implements Parcelable { 36 37 private static final String TAG = Log.tag(MultiShareArgs.class); 38 39 private final Set<ContactSearchKey> contactSearchKeys; 40 private final List<Media> media; 41 private final String draftText; 42 private final StickerLocator stickerLocator; 43 private final boolean borderless; 44 private final Uri dataUri; 45 private final String dataType; 46 private final boolean viewOnce; 47 private final LinkPreview linkPreview; 48 private final List<Mention> mentions; 49 private final long timestamp; 50 private final long expiresAt; 51 private final boolean isTextStory; 52 private final BodyRangeList bodyRanges; 53 private final List<Contact> sharedContacts; 54 55 private MultiShareArgs(@NonNull Builder builder) { 56 contactSearchKeys = builder.contactSearchKeys; 57 media = builder.media == null ? new ArrayList<>() : new ArrayList<>(builder.media); 58 draftText = builder.draftText; 59 stickerLocator = builder.stickerLocator; 60 borderless = builder.borderless; 61 dataUri = builder.dataUri; 62 dataType = builder.dataType; 63 viewOnce = builder.viewOnce; 64 linkPreview = builder.linkPreview; 65 mentions = builder.mentions == null ? new ArrayList<>() : new ArrayList<>(builder.mentions); 66 timestamp = builder.timestamp; 67 expiresAt = builder.expiresAt; 68 isTextStory = builder.isTextStory; 69 bodyRanges = builder.bodyRanges; 70 sharedContacts = builder.sharedContacts == null ? new ArrayList<>() : new ArrayList<>(builder.sharedContacts); 71 } 72 73 protected MultiShareArgs(Parcel in) { 74 List<ContactSearchKey.RecipientSearchKey> parcelableRecipientSearchKeys = in.createTypedArrayList(ContactSearchKey.RecipientSearchKey.CREATOR); 75 76 contactSearchKeys = new HashSet<>(parcelableRecipientSearchKeys); 77 media = in.createTypedArrayList(Media.CREATOR); 78 draftText = in.readString(); 79 stickerLocator = in.readParcelable(StickerLocator.class.getClassLoader()); 80 borderless = in.readByte() != 0; 81 dataUri = in.readParcelable(Uri.class.getClassLoader()); 82 dataType = in.readString(); 83 viewOnce = in.readByte() != 0; 84 mentions = in.createTypedArrayList(Mention.CREATOR); 85 timestamp = in.readLong(); 86 expiresAt = in.readLong(); 87 isTextStory = ParcelUtil.readBoolean(in); 88 89 String linkedPreviewString = in.readString(); 90 LinkPreview preview; 91 try { 92 preview = linkedPreviewString != null ? LinkPreview.deserialize(linkedPreviewString) : null; 93 } catch (IOException e) { 94 preview = null; 95 } 96 97 linkPreview = preview; 98 99 BodyRangeList bodyRanges = null; 100 try { 101 byte[] data = ParcelUtil.readByteArray(in); 102 if (data != null) { 103 bodyRanges = BodyRangeList.ADAPTER.decode(data); 104 } 105 } catch (IOException e) { 106 Log.w(TAG, "Invalid body range", e); 107 } 108 this.bodyRanges = bodyRanges; 109 sharedContacts = in.createTypedArrayList(Contact.CREATOR); 110 } 111 112 public Set<ContactSearchKey> getContactSearchKeys() { 113 return contactSearchKeys; 114 } 115 116 public Set<ContactSearchKey.RecipientSearchKey> getRecipientSearchKeys() { 117 return contactSearchKeys.stream() 118 .filter(key -> key instanceof ContactSearchKey.RecipientSearchKey) 119 .map(key -> (ContactSearchKey.RecipientSearchKey) key) 120 .collect(Collectors.toSet()); 121 } 122 123 public @NonNull List<Media> getMedia() { 124 return media; 125 } 126 127 public StickerLocator getStickerLocator() { 128 return stickerLocator; 129 } 130 131 public String getDataType() { 132 return dataType; 133 } 134 135 public @Nullable String getDraftText() { 136 return draftText; 137 } 138 139 public Uri getDataUri() { 140 return dataUri; 141 } 142 143 public boolean isBorderless() { 144 return borderless; 145 } 146 147 public boolean isViewOnce() { 148 return viewOnce; 149 } 150 151 public boolean isTextStory() { 152 return isTextStory; 153 } 154 155 public @Nullable LinkPreview getLinkPreview() { 156 return linkPreview; 157 } 158 159 public @NonNull List<Mention> getMentions() { 160 return mentions; 161 } 162 163 public long getTimestamp() { 164 return timestamp; 165 } 166 167 public long getExpiresAt() { 168 return expiresAt; 169 } 170 171 public @Nullable BodyRangeList getBodyRanges() { 172 return bodyRanges; 173 } 174 175 public @NonNull List<Contact> getSharedContacts() { 176 return sharedContacts; 177 } 178 179 public boolean isValidForStories() { 180 if (isViewOnce() || stickerLocator != null) { 181 return false; 182 } 183 184 return isTextStory || 185 (!media.isEmpty() && media.stream().allMatch(m -> MediaUtil.isStorySupportedType(m.getMimeType()))) || 186 MediaUtil.isStorySupportedType(dataType) || 187 isValidForTextStoryGeneration(); 188 } 189 190 public boolean isValidForNonStories() { 191 return !isTextStory; 192 } 193 194 public boolean isValidForTextStoryGeneration() { 195 if (isTextStory || !media.isEmpty()) { 196 return false; 197 } 198 199 if (!Util.isEmpty(getDraftText())) { 200 BreakIteratorCompat breakIteratorCompat = BreakIteratorCompat.getInstance(); 201 breakIteratorCompat.setText(getDraftText()); 202 203 if (breakIteratorCompat.countBreaks() > Stories.MAX_TEXT_STORY_SIZE) { 204 return false; 205 } 206 } 207 208 return linkPreview != null || !Util.isEmpty(draftText); 209 } 210 211 public @NonNull InterstitialContentType getInterstitialContentType() { 212 if (!requiresInterstitial()) { 213 return InterstitialContentType.NONE; 214 } else if (!this.getMedia().isEmpty() || 215 (this.getDataUri() != null && this.getDataUri() != Uri.EMPTY && this.getDataType() != null && MediaUtil.isImageOrVideoType(this.getDataType()))) 216 { 217 return InterstitialContentType.MEDIA; 218 } else if (!TextUtils.isEmpty(this.getDraftText()) && allRecipientsAreStories()) { 219 return InterstitialContentType.MEDIA; 220 } else if (!TextUtils.isEmpty(this.getDraftText())) { 221 return InterstitialContentType.TEXT; 222 } else { 223 return InterstitialContentType.NONE; 224 } 225 } 226 227 public boolean allRecipientsAreStories() { 228 return !contactSearchKeys.isEmpty() && contactSearchKeys.stream() 229 .allMatch(key -> key.requireRecipientSearchKey().isStory()); 230 } 231 232 public static final Creator<MultiShareArgs> CREATOR = new Creator<MultiShareArgs>() { 233 @Override 234 public MultiShareArgs createFromParcel(Parcel in) { 235 return new MultiShareArgs(in); 236 } 237 238 @Override 239 public MultiShareArgs[] newArray(int size) { 240 return new MultiShareArgs[size]; 241 } 242 }; 243 244 @Override 245 public int describeContents() { 246 return 0; 247 } 248 249 @Override 250 public void writeToParcel(Parcel dest, int flags) { 251 dest.writeTypedList(Stream.of(contactSearchKeys).map(ContactSearchKey::requireRecipientSearchKey).toList()); 252 dest.writeTypedList(media); 253 dest.writeString(draftText); 254 dest.writeParcelable(stickerLocator, flags); 255 dest.writeByte((byte) (borderless ? 1 : 0)); 256 dest.writeParcelable(dataUri, flags); 257 dest.writeString(dataType); 258 dest.writeByte((byte) (viewOnce ? 1 : 0)); 259 dest.writeTypedList(mentions); 260 dest.writeLong(timestamp); 261 dest.writeLong(expiresAt); 262 ParcelUtil.writeBoolean(dest, isTextStory); 263 264 if (linkPreview != null) { 265 try { 266 dest.writeString(linkPreview.serialize()); 267 } catch (IOException e) { 268 dest.writeString(""); 269 } 270 } else { 271 dest.writeString(""); 272 } 273 274 if (bodyRanges != null) { 275 ParcelUtil.writeByteArray(dest, bodyRanges.encode()); 276 } else { 277 ParcelUtil.writeByteArray(dest, null); 278 } 279 280 dest.writeTypedList(sharedContacts); 281 } 282 283 public Builder buildUpon() { 284 return buildUpon(contactSearchKeys); 285 } 286 287 public Builder buildUpon(@NonNull Set<ContactSearchKey> recipientSearchKeys) { 288 return new Builder(recipientSearchKeys).asBorderless(borderless) 289 .asViewOnce(viewOnce) 290 .withDataType(dataType) 291 .withDataUri(dataUri) 292 .withDraftText(draftText) 293 .withLinkPreview(linkPreview) 294 .withMedia(media) 295 .withStickerLocator(stickerLocator) 296 .withMentions(mentions) 297 .withTimestamp(timestamp) 298 .withExpiration(expiresAt) 299 .asTextStory(isTextStory) 300 .withBodyRanges(bodyRanges) 301 .withSharedContacts(sharedContacts); 302 } 303 304 private boolean requiresInterstitial() { 305 return stickerLocator == null && 306 (!media.isEmpty() || 307 !TextUtils.isEmpty(draftText) || 308 MediaUtil.isImageOrVideoType(dataType) || 309 (!contactSearchKeys.isEmpty() && contactSearchKeys.stream().anyMatch(key -> key.requireRecipientSearchKey().isStory()))); 310 } 311 312 public static final class Builder { 313 314 private final Set<ContactSearchKey> contactSearchKeys; 315 316 private List<Media> media; 317 private String draftText; 318 private StickerLocator stickerLocator; 319 private boolean borderless; 320 private Uri dataUri; 321 private String dataType; 322 private LinkPreview linkPreview; 323 private boolean viewOnce; 324 private List<Mention> mentions; 325 private long timestamp; 326 private long expiresAt; 327 private boolean isTextStory; 328 private BodyRangeList bodyRanges; 329 private List<Contact> sharedContacts; 330 331 public Builder() { 332 this(Collections.emptySet()); 333 } 334 335 public Builder(@NonNull Set<ContactSearchKey> contactSearchKeys) { 336 this.contactSearchKeys = contactSearchKeys; 337 } 338 339 public @NonNull Builder withMedia(@Nullable List<Media> media) { 340 this.media = media != null ? new ArrayList<>(media) : null; 341 return this; 342 } 343 344 public @NonNull Builder withDraftText(@Nullable String draftText) { 345 this.draftText = draftText; 346 return this; 347 } 348 349 public @NonNull Builder withStickerLocator(@Nullable StickerLocator stickerLocator) { 350 this.stickerLocator = stickerLocator; 351 return this; 352 } 353 354 public @NonNull Builder asBorderless(boolean borderless) { 355 this.borderless = borderless; 356 return this; 357 } 358 359 public @NonNull Builder withDataUri(@Nullable Uri dataUri) { 360 this.dataUri = dataUri; 361 return this; 362 } 363 364 public @NonNull Builder withDataType(@Nullable String dataType) { 365 this.dataType = dataType; 366 return this; 367 } 368 369 public @NonNull Builder withLinkPreview(@Nullable LinkPreview linkPreview) { 370 this.linkPreview = linkPreview; 371 return this; 372 } 373 374 public @NonNull Builder asViewOnce(boolean viewOnce) { 375 this.viewOnce = viewOnce; 376 return this; 377 } 378 379 public @NonNull Builder withMentions(@Nullable List<Mention> mentions) { 380 this.mentions = mentions != null ? new ArrayList<>(mentions) : null; 381 return this; 382 } 383 384 public @NonNull Builder withTimestamp(long timestamp) { 385 this.timestamp = timestamp; 386 return this; 387 } 388 389 public @NonNull Builder withExpiration(long expiresAt) { 390 this.expiresAt = expiresAt; 391 return this; 392 } 393 394 public @NonNull Builder asTextStory(boolean isTextStory) { 395 this.isTextStory = isTextStory; 396 return this; 397 } 398 399 public @NonNull Builder withBodyRanges(@Nullable BodyRangeList bodyRanges) { 400 this.bodyRanges = bodyRanges; 401 return this; 402 } 403 404 public @NonNull Builder withSharedContacts(List<Contact> sharedContacts) { 405 this.sharedContacts = new ArrayList<>(sharedContacts); 406 return this; 407 } 408 409 public @NonNull MultiShareArgs build() { 410 return new MultiShareArgs(this); 411 } 412 } 413}