remove com.annimon:stream dependency

This commit is contained in:
adbenitez 2025-08-07 17:45:01 +02:00
parent a68f3a7024
commit fd057485db
7 changed files with 61 additions and 86 deletions

View file

@ -187,7 +187,6 @@ dependencies {
implementation ('com.davemorrissey.labs:subsampling-scale-image-view:3.10.0') { // for the zooming on photos / media implementation ('com.davemorrissey.labs:subsampling-scale-image-view:3.10.0') { // for the zooming on photos / media
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'
} }
implementation 'com.annimon:stream:1.1.8' // brings future java streams api to SDK Version < 24
// Replacement for ContentResolver // Replacement for ContentResolver
// that protects against the Surreptitious Sharing attack. // that protects against the Surreptitious Sharing attack.

View file

@ -35,7 +35,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.annimon.stream.Stream;
import com.b44t.messenger.DcChat; import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcContext; import com.b44t.messenger.DcContext;
@ -55,7 +54,6 @@ import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Set; import java.util.Set;
public class ConversationListItem extends RelativeLayout public class ConversationListItem extends RelativeLayout
@ -318,15 +316,12 @@ public class ConversationListItem extends RelativeLayout
String normalizedValue = value.toLowerCase(Util.getLocale()); String normalizedValue = value.toLowerCase(Util.getLocale());
String normalizedTest = highlight.toLowerCase(Util.getLocale()); String normalizedTest = highlight.toLowerCase(Util.getLocale());
List<String> testTokens;
try (Stream<String> stream = Stream.of(normalizedTest.split(" "))) {
testTokens = stream.filter(s -> !s.trim().isEmpty()).toList();
}
Spannable spanned = new SpannableString(value); Spannable spanned = new SpannableString(value);
int searchStartIndex = 0; int searchStartIndex = 0;
for (String token : testTokens) { for (String token : normalizedTest.split(" ")) {
if (token.trim().isEmpty()) continue;
if (searchStartIndex >= spanned.length()) { if (searchStartIndex >= spanned.length()) {
break; break;
} }

View file

@ -16,7 +16,6 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcMsg; import com.b44t.messenger.DcMsg;
import com.b44t.messenger.rpc.RpcException; import com.b44t.messenger.rpc.RpcException;
@ -194,18 +193,17 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
} }
private void setQuoteAttachment(@NonNull GlideRequests glideRequests, @NonNull SlideDeck slideDeck) { private void setQuoteAttachment(@NonNull GlideRequests glideRequests, @NonNull SlideDeck slideDeck) {
List<Slide> thumbnailSlides = Stream.of(slideDeck.getSlides()).filter(s -> s.hasImage() || s.hasVideo() || s.hasSticker() || s.isWebxdcDocument() || s.isVcard()).limit(1).toList(); List<Slide> slides = slideDeck.getSlides();
List<Slide> audioSlides = Stream.of(slideDeck.getSlides()).filter(s -> s.hasAudio()).limit(1).toList(); Slide slide = slides.isEmpty()? null : slides.get(0);
List<Slide> documentSlides = Stream.of(attachments.getSlides()).filter(Slide::hasDocument).limit(1).toList();
attachmentVideoOverlayView.setVisibility(GONE); attachmentVideoOverlayView.setVisibility(GONE);
if (!thumbnailSlides.isEmpty() && thumbnailSlides.get(0).getUri() != null) { if (slide != null && slide.hasQuoteThumbnail()) {
thumbnailView.setVisibility(VISIBLE); thumbnailView.setVisibility(VISIBLE);
attachmentContainerView.setVisibility(GONE); attachmentContainerView.setVisibility(GONE);
dismissView.setBackgroundResource(R.drawable.dismiss_background); dismissView.setBackgroundResource(R.drawable.dismiss_background);
if (thumbnailSlides.get(0).isWebxdcDocument()) { if (slide.isWebxdcDocument()) {
try { try {
JSONObject info = quotedMsg.getWebxdcInfo(); JSONObject info = quotedMsg.getWebxdcInfo();
byte[] blob = quotedMsg.getWebxdcBlob(info.getString("icon")); byte[] blob = quotedMsg.getWebxdcBlob(info.getString("icon"));
@ -218,7 +216,7 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
Log.e(TAG, "failed to get webxdc icon", e); Log.e(TAG, "failed to get webxdc icon", e);
thumbnailView.setVisibility(GONE); thumbnailView.setVisibility(GONE);
} }
} else if (thumbnailSlides.get(0).isVcard()) { } else if (slide.isVcard()) {
try { try {
VcardContact vcardContact = DcHelper.getRpc(getContext()).parseVcard(quotedMsg.getFile()).get(0); VcardContact vcardContact = DcHelper.getRpc(getContext()).parseVcard(quotedMsg.getFile()).get(0);
Recipient recipient = new Recipient(getContext(), vcardContact); Recipient recipient = new Recipient(getContext(), vcardContact);
@ -233,11 +231,11 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
thumbnailView.setVisibility(GONE); thumbnailView.setVisibility(GONE);
} }
} else { } else {
Uri thumbnailUri = thumbnailSlides.get(0).getUri(); Uri thumbnailUri = slide.getUri();
if (thumbnailSlides.get(0).hasVideo()) { if (slide.hasVideo()) {
attachmentVideoOverlayView.setVisibility(VISIBLE); attachmentVideoOverlayView.setVisibility(VISIBLE);
MediaUtil.createVideoThumbnailIfNeeded(getContext(), thumbnailSlides.get(0).getUri(), thumbnailSlides.get(0).getThumbnailUri(), null); MediaUtil.createVideoThumbnailIfNeeded(getContext(), slide.getUri(), slide.getThumbnailUri(), null);
thumbnailUri = thumbnailSlides.get(0).getThumbnailUri(); thumbnailUri = slide.getThumbnailUri();
} }
glideRequests.load(new DecryptableUri(thumbnailUri)) glideRequests.load(new DecryptableUri(thumbnailUri))
.centerCrop() .centerCrop()
@ -245,10 +243,10 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(thumbnailView); .into(thumbnailView);
} }
} else if(!audioSlides.isEmpty()) { } else if(slide != null && slide.hasAudio()) {
thumbnailView.setVisibility(GONE); thumbnailView.setVisibility(GONE);
attachmentContainerView.setVisibility(GONE); attachmentContainerView.setVisibility(GONE);
} else if (!documentSlides.isEmpty()) { } else if (slide != null && slide.hasDocument()) {
thumbnailView.setVisibility(GONE); thumbnailView.setVisibility(GONE);
attachmentContainerView.setVisibility(VISIBLE); attachmentContainerView.setVisibility(VISIBLE);
} else { } else {

View file

@ -6,7 +6,6 @@ import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.loader.content.AsyncTaskLoader; import androidx.loader.content.AsyncTaskLoader;
import com.annimon.stream.Stream;
import com.b44t.messenger.DcContext; import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcMsg; import com.b44t.messenger.DcMsg;
@ -128,28 +127,38 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
} }
public int getSectionCount() { public int getSectionCount() {
return (int)Stream.of(TIME_SECTIONS) int count = 0;
.filter(timeBucket -> !timeBucket.isEmpty()) for (TimeBucket section : TIME_SECTIONS) {
.count() + if (!section.isEmpty()) count++;
OLDER.getSectionCount(); }
return count + OLDER.getSectionCount();
} }
public int getSectionItemCount(int section) { public int getSectionItemCount(int section) {
List<TimeBucket> activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList(); List<TimeBucket> activeTimeBuckets = new ArrayList<>();
for (TimeBucket bucket : TIME_SECTIONS) {
if (!bucket.isEmpty()) activeTimeBuckets.add(bucket);
}
if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getItemCount(); if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getItemCount();
else return OLDER.getSectionItemCount(section - activeTimeBuckets.size()); else return OLDER.getSectionItemCount(section - activeTimeBuckets.size());
} }
public DcMsg get(int section, int item) { public DcMsg get(int section, int item) {
List<TimeBucket> activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList(); List<TimeBucket> activeTimeBuckets = new ArrayList<>();
for (TimeBucket bucket : TIME_SECTIONS) {
if (!bucket.isEmpty()) activeTimeBuckets.add(bucket);
}
if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getItem(item); if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getItem(item);
else return OLDER.getItem(section - activeTimeBuckets.size(), item); else return OLDER.getItem(section - activeTimeBuckets.size(), item);
} }
public String getName(int section) { public String getName(int section) {
List<TimeBucket> activeTimeBuckets = Stream.of(TIME_SECTIONS).filter(timeBucket -> !timeBucket.isEmpty()).toList(); List<TimeBucket> activeTimeBuckets = new ArrayList<>();
for (TimeBucket bucket : TIME_SECTIONS) {
if (!bucket.isEmpty()) activeTimeBuckets.add(bucket);
}
if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getName(); if (section < activeTimeBuckets.size()) return activeTimeBuckets.get(section).getName();
else return OLDER.getName(section - activeTimeBuckets.size()); else return OLDER.getName(section - activeTimeBuckets.size());

View file

@ -76,6 +76,11 @@ public abstract class Slide {
return attachment.getSize(); return attachment.getSize();
} }
/* Return true if this slide has a thumbnail when being quoted, false otherwise */
public boolean hasQuoteThumbnail() {
return (hasImage() || hasVideo() || hasSticker() || isWebxdcDocument() || isVcard()) && getUri() != null;
}
public boolean hasImage() { public boolean hasImage() {
return false; return false;
} }

View file

@ -21,15 +21,13 @@ import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.annimon.stream.Stream;
import com.annimon.stream.function.Consumer;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.LRUCache; import org.thoughtcrime.securesms.util.LRUCache;
import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.ServiceUtil;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -70,10 +68,6 @@ public class Permissions {
private Runnable anyPermanentlyDeniedListener; private Runnable anyPermanentlyDeniedListener;
private Runnable anyResultListener; private Runnable anyResultListener;
private Consumer<List<String>> someGrantedListener;
private Consumer<List<String>> someDeniedListener;
private Consumer<List<String>> somePermanentlyDeniedListener;
private @DrawableRes int[] rationalDialogHeader; private @DrawableRes int[] rationalDialogHeader;
private String rationaleDialogMessage; private String rationaleDialogMessage;
@ -148,29 +142,13 @@ public class Permissions {
return this; return this;
} }
public PermissionsBuilder onSomeGranted(Consumer<List<String>> someGrantedListener) {
this.someGrantedListener = someGrantedListener;
return this;
}
public PermissionsBuilder onSomeDenied(Consumer<List<String>> someDeniedListener) {
this.someDeniedListener = someDeniedListener;
return this;
}
public PermissionsBuilder onSomePermanentlyDenied(Consumer<List<String>> somePermanentlyDeniedListener) {
this.somePermanentlyDeniedListener = somePermanentlyDeniedListener;
return this;
}
public void execute() { public void execute() {
if (alwaysGranted) { if (alwaysGranted) {
allGrantedListener.run(); allGrantedListener.run();
return; return;
} }
PermissionsRequest request = new PermissionsRequest(allGrantedListener, anyDeniedListener, anyPermanentlyDeniedListener, anyResultListener, PermissionsRequest request = new PermissionsRequest(allGrantedListener, anyDeniedListener, anyPermanentlyDeniedListener, anyResultListener);
someGrantedListener, someDeniedListener, somePermanentlyDeniedListener);
if (ifNecesary && (permissionObject.hasAll(requestedPermissions) || !condition)) { if (ifNecesary && (permissionObject.hasAll(requestedPermissions) || !condition)) {
executePreGrantedPermissionsRequest(request); executePreGrantedPermissionsRequest(request);
@ -183,7 +161,7 @@ public class Permissions {
private void executePreGrantedPermissionsRequest(PermissionsRequest request) { private void executePreGrantedPermissionsRequest(PermissionsRequest request) {
int[] grantResults = new int[requestedPermissions.length]; int[] grantResults = new int[requestedPermissions.length];
for (int i=0;i<grantResults.length;i++) grantResults[i] = PackageManager.PERMISSION_GRANTED; Arrays.fill(grantResults, PackageManager.PERMISSION_GRANTED);
request.onResult(requestedPermissions, grantResults, new boolean[requestedPermissions.length]); request.onResult(requestedPermissions, grantResults, new boolean[requestedPermissions.length]);
} }
@ -218,7 +196,8 @@ public class Permissions {
} }
String[] permissions = filterNotGranted(permissionObject.getContext(), requestedPermissions); String[] permissions = filterNotGranted(permissionObject.getContext(), requestedPermissions);
int[] grantResults = Stream.of(permissions).mapToInt(permission -> PackageManager.PERMISSION_DENIED).toArray(); int[] grantResults = new int[permissions.length];
Arrays.fill(grantResults, PackageManager.PERMISSION_DENIED);
boolean[] showDialog = new boolean[permissions.length]; boolean[] showDialog = new boolean[permissions.length];
Arrays.fill(showDialog, true); Arrays.fill(showDialog, true);
@ -236,22 +215,29 @@ public class Permissions {
} }
private static String[] filterNotGranted(@NonNull Context context, String... permissions) { private static String[] filterNotGranted(@NonNull Context context, String... permissions) {
return Stream.of(permissions) List<String> notGranted = new ArrayList<>();
.filter(permission -> ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) for (String permission : permissions) {
.toList() if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
.toArray(new String[0]); notGranted.add(permission);
}
}
return notGranted.toArray(new String[0]);
} }
public static boolean hasAny(@NonNull Context context, String... permissions) { public static boolean hasAny(@NonNull Context context, String... permissions) {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true;
Stream.of(permissions).anyMatch(permission -> ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED); for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) return true;
}
return false;
} }
public static boolean hasAll(@NonNull Context context, String... permissions) { public static boolean hasAll(@NonNull Context context, String... permissions) {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true;
Stream.of(permissions).allMatch(permission -> ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED); for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) return false;
}
return true;
} }
public static void onRequestPermissionsResult(Fragment fragment, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { public static void onRequestPermissionsResult(Fragment fragment, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

View file

@ -5,8 +5,6 @@ import android.content.pm.PackageManager;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.annimon.stream.function.Consumer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -22,27 +20,16 @@ class PermissionsRequest {
private final @Nullable Runnable anyPermanentlyDeniedListener; private final @Nullable Runnable anyPermanentlyDeniedListener;
private final @Nullable Runnable anyResultListener; private final @Nullable Runnable anyResultListener;
private final @Nullable Consumer<List<String>> someGrantedListener;
private final @Nullable Consumer<List<String>> someDeniedListener;
private final @Nullable Consumer<List<String>> somePermanentlyDeniedListener;
PermissionsRequest(@Nullable Runnable allGrantedListener, PermissionsRequest(@Nullable Runnable allGrantedListener,
@Nullable Runnable anyDeniedListener, @Nullable Runnable anyDeniedListener,
@Nullable Runnable anyPermanentlyDeniedListener, @Nullable Runnable anyPermanentlyDeniedListener,
@Nullable Runnable anyResultListener, @Nullable Runnable anyResultListener)
@Nullable Consumer<List<String>> someGrantedListener,
@Nullable Consumer<List<String>> someDeniedListener,
@Nullable Consumer<List<String>> somePermanentlyDeniedListener)
{ {
this.allGrantedListener = allGrantedListener; this.allGrantedListener = allGrantedListener;
this.anyDeniedListener = anyDeniedListener; this.anyDeniedListener = anyDeniedListener;
this.anyPermanentlyDeniedListener = anyPermanentlyDeniedListener; this.anyPermanentlyDeniedListener = anyPermanentlyDeniedListener;
this.anyResultListener = anyResultListener; this.anyResultListener = anyResultListener;
this.someGrantedListener = someGrantedListener;
this.someDeniedListener = someDeniedListener;
this.somePermanentlyDeniedListener = somePermanentlyDeniedListener;
} }
void onResult(String[] permissions, int[] grantResults, boolean[] shouldShowRationaleDialog) { void onResult(String[] permissions, int[] grantResults, boolean[] shouldShowRationaleDialog) {
@ -56,9 +43,9 @@ class PermissionsRequest {
} else { } else {
boolean preRequestShouldShowRationaleDialog = PRE_REQUEST_MAPPING.get(permissions[i]); boolean preRequestShouldShowRationaleDialog = PRE_REQUEST_MAPPING.get(permissions[i]);
if ((somePermanentlyDeniedListener != null || anyPermanentlyDeniedListener != null) && if (anyPermanentlyDeniedListener != null
!preRequestShouldShowRationaleDialog && !shouldShowRationaleDialog[i]) && !preRequestShouldShowRationaleDialog
{ && !shouldShowRationaleDialog[i]) {
permanentlyDenied.add(permissions[i]); permanentlyDenied.add(permissions[i]);
} else { } else {
denied.add(permissions[i]); denied.add(permissions[i]);
@ -68,18 +55,14 @@ class PermissionsRequest {
if (allGrantedListener != null && !granted.isEmpty() && (denied.isEmpty() && permanentlyDenied.isEmpty())) { if (allGrantedListener != null && !granted.isEmpty() && (denied.isEmpty() && permanentlyDenied.isEmpty())) {
allGrantedListener.run(); allGrantedListener.run();
} else if (someGrantedListener != null && !granted.isEmpty()) {
someGrantedListener.accept(granted);
} }
if (!denied.isEmpty()) { if (!denied.isEmpty()) {
if (anyDeniedListener != null) anyDeniedListener.run(); if (anyDeniedListener != null) anyDeniedListener.run();
if (someDeniedListener != null) someDeniedListener.accept(denied);
} }
if (!permanentlyDenied.isEmpty()) { if (!permanentlyDenied.isEmpty()) {
if (anyPermanentlyDeniedListener != null) anyPermanentlyDeniedListener.run(); if (anyPermanentlyDeniedListener != null) anyPermanentlyDeniedListener.run();
if (somePermanentlyDeniedListener != null) somePermanentlyDeniedListener.accept(permanentlyDenied);
} }
if (anyResultListener != null) { if (anyResultListener != null) {