Add photo media quality selector when sending images.

fork-5.53.8
Cody Henthorne 2021-05-07 14:03:53 -04:00 zatwierdzone przez Greyson Parrelli
rodzic 8c9df8d3be
commit dd934e0095
43 zmienionych plików z 630 dodań i 55 usunięć

Wyświetl plik

@ -35,7 +35,9 @@ public class EmojiEditText extends AppCompatEditText {
a.recycle();
if (forceCustom || !TextSecurePreferences.isSystemEmojiPreferred(getContext())) {
setFilters(appendEmojiFilter(this.getFilters()));
if (!isInEditMode()) {
setFilters(appendEmojiFilter(this.getFilters()));
}
}
}

Wyświetl plik

@ -92,7 +92,7 @@ public class EmojiTextView extends AppCompatTextView {
@Override public void setText(@Nullable CharSequence text, BufferType type) {
EmojiProvider provider = EmojiProvider.getInstance(getContext());
EmojiParser.CandidateList candidates = provider.getCandidates(text);
EmojiParser.CandidateList candidates = !isInEditMode() ? provider.getCandidates(text) : null;
if (scaleEmojis && candidates != null && candidates.allEmojis) {
int emojis = candidates.size();

Wyświetl plik

@ -228,7 +228,6 @@ import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.profiles.spoofing.ReviewBannerView;
import org.thoughtcrime.securesms.profiles.spoofing.ReviewCardDialogFragment;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.ratelimit.RecaptchaProofActivity;
import org.thoughtcrime.securesms.ratelimit.RecaptchaProofBottomSheetFragment;
import org.thoughtcrime.securesms.reactions.ReactionsBottomSheetDialogFragment;
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment;
@ -730,7 +729,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
} else if (MediaUtil.isGif(mediaItem.getMimeType())) {
slideDeck.addSlide(new GifSlide(this, mediaItem.getUri(), mediaItem.getSize(), mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.isBorderless(), mediaItem.getCaption().orNull()));
} else if (MediaUtil.isImageType(mediaItem.getMimeType())) {
slideDeck.addSlide(new ImageSlide(this, mediaItem.getUri(), mediaItem.getMimeType(), mediaItem.getSize(), mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.isBorderless(), mediaItem.getCaption().orNull(), null));
slideDeck.addSlide(new ImageSlide(this, mediaItem.getUri(), mediaItem.getMimeType(), mediaItem.getSize(), mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.isBorderless(), mediaItem.getCaption().orNull(), null, mediaItem.getTransformProperties().orNull()));
} else {
Log.w(TAG, "Asked to send an unexpected mimeType: '" + mediaItem.getMimeType() + "'. Skipping.");
}

Wyświetl plik

@ -52,6 +52,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.AudioWaveFormDat
import org.thoughtcrime.securesms.mms.MediaStream;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.CursorUtil;
@ -1393,33 +1394,43 @@ public class AttachmentDatabase extends Database {
public static final class TransformProperties {
private static final int DEFAULT_MEDIA_QUALITY = SentMediaQuality.STANDARD.getCode();
@JsonProperty private final boolean skipTransform;
@JsonProperty private final boolean videoTrim;
@JsonProperty private final long videoTrimStartTimeUs;
@JsonProperty private final long videoTrimEndTimeUs;
@JsonProperty private final int sentMediaQuality;
@JsonCreator
public TransformProperties(@JsonProperty("skipTransform") boolean skipTransform,
@JsonProperty("videoTrim") boolean videoTrim,
@JsonProperty("videoTrimStartTimeUs") long videoTrimStartTimeUs,
@JsonProperty("videoTrimEndTimeUs") long videoTrimEndTimeUs)
@JsonProperty("videoTrimEndTimeUs") long videoTrimEndTimeUs,
@JsonProperty("sentMediaQuality") int sentMediaQuality)
{
this.skipTransform = skipTransform;
this.videoTrim = videoTrim;
this.videoTrimStartTimeUs = videoTrimStartTimeUs;
this.videoTrimEndTimeUs = videoTrimEndTimeUs;
this.sentMediaQuality = sentMediaQuality;
}
public static @NonNull TransformProperties empty() {
return new TransformProperties(false, false, 0, 0);
return new TransformProperties(false, false, 0, 0, DEFAULT_MEDIA_QUALITY);
}
public static @NonNull TransformProperties forSkipTransform() {
return new TransformProperties(true, false, 0, 0);
return new TransformProperties(true, false, 0, 0, DEFAULT_MEDIA_QUALITY);
}
public static @NonNull TransformProperties forVideoTrim(long videoTrimStartTimeUs, long videoTrimEndTimeUs) {
return new TransformProperties(false, true, videoTrimStartTimeUs, videoTrimEndTimeUs);
return new TransformProperties(false, true, videoTrimStartTimeUs, videoTrimEndTimeUs, DEFAULT_MEDIA_QUALITY);
}
public static @NonNull TransformProperties forSentMediaQuality(@NonNull Optional<TransformProperties> currentProperties, @NonNull SentMediaQuality sentMediaQuality) {
TransformProperties existing = currentProperties.or(empty());
return new TransformProperties(existing.skipTransform, existing.videoTrim, existing.videoTrimStartTimeUs, existing.videoTrimEndTimeUs, sentMediaQuality.getCode());
}
public boolean shouldSkipTransform() {
@ -1442,6 +1453,10 @@ public class AttachmentDatabase extends Database {
return videoTrimEndTimeUs;
}
public int getSentMediaQuality() {
return sentMediaQuality;
}
@NonNull String serialize() {
return JsonUtil.toJson(this);
}

Wyświetl plik

@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.MediaStream;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import org.thoughtcrime.securesms.service.GenericForegroundService;
import org.thoughtcrime.securesms.service.NotificationController;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
@ -141,7 +142,7 @@ public final class AttachmentCompressionJob extends BaseJob {
}
MediaConstraints mediaConstraints = mms ? MediaConstraints.getMmsMediaConstraints(mmsSubscriptionId)
: MediaConstraints.getPushMediaConstraints();
: MediaConstraints.getPushMediaConstraints(SentMediaQuality.fromCode(databaseAttachment.getTransformProperties().getSentMediaQuality()));
compress(database, mediaConstraints, databaseAttachment);
}

Wyświetl plik

@ -0,0 +1,28 @@
package org.thoughtcrime.securesms.mediasend;
import android.content.Context;
import androidx.annotation.NonNull;
/**
* Allow multiple transforms to operate on {@link Media}. Care should
* be taken on the order and implementation of combined transformers to prevent
* one undoing the work of the other.
*/
public final class CompositeMediaTransform implements MediaTransform {
private final MediaTransform[] transforms;
CompositeMediaTransform(MediaTransform ...transforms) {
this.transforms = transforms;
}
@Override
public @NonNull Media transform(@NonNull Context context, @NonNull Media media) {
Media updatedMedia = media;
for (MediaTransform transform : transforms) {
updatedMedia = transform.transform(context, updatedMedia);
}
return updatedMedia;
}
}

Wyświetl plik

@ -22,6 +22,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.util.Pair;
import androidx.core.util.Supplier;
import androidx.fragment.app.Fragment;
@ -56,6 +57,7 @@ import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.HudState;
import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.ViewOnceState;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
@ -141,6 +143,7 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
private TextView countButtonText;
private View continueButton;
private ImageView revealButton;
private AppCompatImageView qualityButton;
private EmojiEditText captionText;
private EmojiToggle emojiToggle;
private Stub<MediaKeyboard> emojiDrawer;
@ -236,6 +239,7 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
countButtonText = findViewById(R.id.mediasend_count_button_text);
continueButton = findViewById(R.id.mediasend_continue_button);
revealButton = findViewById(R.id.mediasend_reveal_toggle);
qualityButton = findViewById(R.id.mediasend_quality_toggle);
captionText = findViewById(R.id.mediasend_caption);
emojiToggle = findViewById(R.id.mediasend_emoji_toggle);
charactersLeft = findViewById(R.id.mediasend_characters_left);
@ -355,6 +359,9 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
revealButton.setOnClickListener(v -> viewModel.onRevealButtonToggled());
qualityButton.setVisibility(Util.isLowMemory(this) ? View.GONE : View.VISIBLE);
qualityButton.setOnClickListener(v -> QualitySelectorBottomSheetDialog.show(getSupportFragmentManager()));
continueButton.setOnClickListener(v -> {
continueButton.setEnabled(false);
if (recipientIds == null || recipientIds.isEmpty()) {
@ -599,7 +606,7 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
fragment.pausePlayback();
SimpleProgressDialog.DismissibleDialog dialog = SimpleProgressDialog.showDelayed(this, 300, 0);
viewModel.onSendClicked(buildModelsToTransform(fragment), recipients, composeText.getMentions())
viewModel.onSendClicked(buildModelsToTransform(fragment, viewModel.getSentMediaQuality().getValue()), recipients, composeText.getMentions())
.observe(this, result -> {
dialog.dismiss();
if (recipients.size() > 1) {
@ -610,9 +617,9 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
});
}
private static Map<Media, MediaTransform> buildModelsToTransform(@NonNull MediaSendFragment fragment) {
List<Media> mediaList = fragment.getAllMedia();
Map<Uri, Object> savedState = fragment.getSavedState();
private static Map<Media, MediaTransform> buildModelsToTransform(@NonNull MediaSendFragment fragment, @Nullable SentMediaQuality sentMediaQuality) {
List<Media> mediaList = fragment.getAllMedia();
Map<Uri, Object> savedState = fragment.getSavedState();
Map<Media, MediaTransform> modelsToRender = new HashMap<>();
for (Media media : mediaList) {
@ -631,12 +638,20 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
modelsToRender.put(media, new VideoTrimTransform(data));
}
}
if (sentMediaQuality == SentMediaQuality.HIGH) {
MediaTransform existingTransform = modelsToRender.get(media);
if (existingTransform == null) {
modelsToRender.put(media, new SentMediaQualityTransform(sentMediaQuality));
} else {
modelsToRender.put(media, new CompositeMediaTransform(existingTransform, new SentMediaQualityTransform(sentMediaQuality)));
}
}
}
return modelsToRender;
}
private void onAddMediaClicked(@NonNull String bucketId) {
Permissions.with(this)
.request(Manifest.permission.READ_EXTERNAL_STORAGE)
@ -730,11 +745,11 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
switch (state.getViewOnceState()) {
case ENABLED:
revealButton.setVisibility(View.VISIBLE);
revealButton.setImageResource(R.drawable.ic_view_once_32);
revealButton.setImageResource(R.drawable.ic_view_once_28);
break;
case DISABLED:
revealButton.setVisibility(View.VISIBLE);
revealButton.setImageResource(R.drawable.ic_view_infinite_32);
revealButton.setImageResource(R.drawable.ic_view_infinite_28);
break;
case GONE:
revealButton.setVisibility(View.GONE);
@ -764,6 +779,8 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
}
});
viewModel.getSentMediaQuality().observe(this, q -> qualityButton.setImageResource(q == SentMediaQuality.STANDARD ? R.drawable.ic_quality_standard_32 : R.drawable.ic_quality_high_32));
viewModel.getSelectedMedia().observe(this, media -> {
mediaRailAdapter.setMedia(media);
});

Wyświetl plik

@ -55,7 +55,7 @@ public class MediaSendFragment extends Fragment {
fragmentPager = view.findViewById(R.id.mediasend_pager);
playbackControlsContainer = view.findViewById(R.id.mediasend_playback_controls_container);
fragmentPagerAdapter = new MediaSendFragmentPagerAdapter(getChildFragmentManager(), viewModel.isSms() ? MediaConstraints.getMmsMediaConstraints(-1) : MediaConstraints.getPushMediaConstraints());
fragmentPagerAdapter = new MediaSendFragmentPagerAdapter(getChildFragmentManager(), viewModel.isSms() ? MediaConstraints.getMmsMediaConstraints(-1) : MediaConstraints.getPushMediaConstraints(null));
fragmentPager.setAdapter(fragmentPagerAdapter);
FragmentPageChangeListener pageChangeListener = new FragmentPageChangeListener();

Wyświetl plik

@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -65,6 +66,7 @@ class MediaSendViewModel extends ViewModel {
private final MutableLiveData<HudState> hudState;
private final SingleLiveEvent<Error> error;
private final SingleLiveEvent<Event> event;
private final MutableLiveData<SentMediaQuality> sentMediaQuality;
private final Map<Uri, Object> savedDrawState;
private TransportOption transport;
@ -85,7 +87,6 @@ class MediaSendViewModel extends ViewModel {
private RailState railState;
private ViewOnceState viewOnceState;
private @Nullable Recipient recipient;
private MediaSendViewModel(@NonNull Application application,
@ -104,6 +105,7 @@ class MediaSendViewModel extends ViewModel {
this.hudState = new MutableLiveData<>();
this.error = new SingleLiveEvent<>();
this.event = new SingleLiveEvent<>();
this.sentMediaQuality = new MutableLiveData<>(SentMediaQuality.STANDARD);
this.savedDrawState = new HashMap<>();
this.lastCameraCapture = Optional.absent();
this.body = "";
@ -455,6 +457,16 @@ class MediaSendViewModel extends ViewModel {
savedDrawState.putAll(state);
}
public void setSentMediaQuality(@NonNull SentMediaQuality newQuality) {
if (newQuality == sentMediaQuality.getValue()) {
return;
}
sentMediaQuality.setValue(newQuality);
preUploadEnabled = false;
uploadRepository.cancelAllUploads();
}
@NonNull LiveData<MediaSendActivityResult> onSendClicked(Map<Media, MediaTransform> modelsToTransform, @NonNull List<Recipient> recipients, @NonNull List<Mention> mentions) {
if (isSms && recipients.size() > 0) {
throw new IllegalStateException("Provided recipients to send to, but this is SMS!");
@ -561,6 +573,10 @@ class MediaSendViewModel extends ViewModel {
return viewOnceState == ViewOnceState.ENABLED;
}
@NonNull LiveData<SentMediaQuality> getSentMediaQuality() {
return sentMediaQuality;
}
@NonNull MediaConstraints getMediaConstraints() {
return mediaConstraints;
}
@ -583,10 +599,10 @@ class MediaSendViewModel extends ViewModel {
}
private HudState buildHudState() {
List<Media> selectedMedia = getSelectedMediaOrDefault();
int selectionCount = selectedMedia.size();
ButtonState updatedButtonState = buttonState == ButtonState.COUNT && selectionCount == 0 ? ButtonState.GONE : buttonState;
boolean updatedCaptionVisible = captionVisible && (selectedMedia.size() > 1 || (selectedMedia.size() > 0 && selectedMedia.get(0).getCaption().isPresent()));
List<Media> selectedMedia = getSelectedMediaOrDefault();
int selectionCount = selectedMedia.size();
ButtonState updatedButtonState = buttonState == ButtonState.COUNT && selectionCount == 0 ? ButtonState.GONE : buttonState;
boolean updatedCaptionVisible = captionVisible && (selectedMedia.size() > 1 || (selectedMedia.size() > 0 && selectedMedia.get(0).getCaption().isPresent()));
return new HudState(hudVisible, composeVisible, updatedCaptionVisible, selectionCount, updatedButtonState, railState, viewOnceState);
}
@ -704,12 +720,12 @@ class MediaSendViewModel extends ViewModel {
static class HudState {
private final boolean hudVisible;
private final boolean composeVisible;
private final boolean captionVisible;
private final int selectionCount;
private final ButtonState buttonState;
private final RailState railState;
private final boolean hudVisible;
private final boolean composeVisible;
private final boolean captionVisible;
private final int selectionCount;
private final ButtonState buttonState;
private final RailState railState;
private final ViewOnceState viewOnceState;
HudState(boolean hudVisible,
@ -720,13 +736,13 @@ class MediaSendViewModel extends ViewModel {
@NonNull RailState railState,
@NonNull ViewOnceState viewOnceState)
{
this.hudVisible = hudVisible;
this.composeVisible = composeVisible;
this.captionVisible = captionVisible;
this.selectionCount = selectionCount;
this.buttonState = buttonState;
this.railState = railState;
this.viewOnceState = viewOnceState;
this.hudVisible = hudVisible;
this.composeVisible = composeVisible;
this.captionVisible = captionVisible;
this.selectionCount = selectionCount;
this.buttonState = buttonState;
this.railState = railState;
this.viewOnceState = viewOnceState;
}
public boolean isHudVisible() {

Wyświetl plik

@ -13,6 +13,7 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.AttachmentDatabase.TransformProperties;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.JobManager;
@ -78,16 +79,28 @@ class MediaUploadRepository {
void applyMediaUpdates(@NonNull Map<Media, Media> oldToNew, @Nullable Recipient recipient) {
executor.execute(() -> {
for (Map.Entry<Media, Media> entry : oldToNew.entrySet()) {
boolean same = entry.getKey().equals(entry.getValue()) && (!entry.getValue().getTransformProperties().isPresent() || !entry.getValue().getTransformProperties().get().isVideoEdited());
if (!same || !uploadResults.containsKey(entry.getValue())) {
cancelUploadInternal(entry.getKey());
uploadMediaInternal(entry.getValue(), recipient);
Media oldMedia = entry.getKey();
Media newMedia = entry.getValue();
boolean same = oldMedia.equals(newMedia) && hasSameTransformProperties(oldMedia, newMedia);
if (!same || !uploadResults.containsKey(newMedia)) {
cancelUploadInternal(oldMedia);
uploadMediaInternal(newMedia, recipient);
}
}
});
}
private boolean hasSameTransformProperties(@NonNull Media oldMedia, @NonNull Media newMedia) {
TransformProperties oldProperties = oldMedia.getTransformProperties().orNull();
TransformProperties newProperties = newMedia.getTransformProperties().orNull();
if (oldProperties == null || newProperties == null) {
return oldProperties == newProperties;
}
return !newProperties.isVideoEdited() && oldProperties.getSentMediaQuality() == newProperties.getSentMediaQuality();
}
void cancelUpload(@NonNull Media media) {
executor.execute(() -> cancelUploadInternal(media));
}
@ -195,7 +208,7 @@ class MediaUploadRepository {
} else if (MediaUtil.isGif(media.getMimeType())) {
return new GifSlide(context, media.getUri(), media.getSize(), media.getWidth(), media.getHeight(), media.isBorderless(), media.getCaption().orNull()).asAttachment();
} else if (MediaUtil.isImageType(media.getMimeType())) {
return new ImageSlide(context, media.getUri(), media.getMimeType(), media.getSize(), media.getWidth(), media.getHeight(), media.isBorderless(), media.getCaption().orNull(), null).asAttachment();
return new ImageSlide(context, media.getUri(), media.getMimeType(), media.getSize(), media.getWidth(), media.getHeight(), media.isBorderless(), media.getCaption().orNull(), null, media.getTransformProperties().orNull()).asAttachment();
} else if (MediaUtil.isTextType(media.getMimeType())) {
return new TextSlide(context, media.getUri(), null, media.getSize()).asAttachment();
} else {

Wyświetl plik

@ -0,0 +1,87 @@
package org.thoughtcrime.securesms.mediasend;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProviders;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import org.thoughtcrime.securesms.util.BottomSheetUtil;
import org.thoughtcrime.securesms.util.views.CheckedLinearLayout;
/**
* Dialog for selecting media quality, tightly coupled with {@link MediaSendViewModel}.
*/
public final class QualitySelectorBottomSheetDialog extends BottomSheetDialogFragment {
private MediaSendViewModel viewModel;
private CheckedLinearLayout standard;
private CheckedLinearLayout high;
public static void show(@NonNull FragmentManager manager) {
QualitySelectorBottomSheetDialog fragment = new QualitySelectorBottomSheetDialog();
fragment.show(manager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
setStyle(DialogFragment.STYLE_NORMAL, R.style.Theme_Signal_RoundedBottomSheet);
super.onCreate(savedInstanceState);
}
@Override
public @NonNull View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(inflater.getContext(), R.style.TextSecure_DarkTheme);
LayoutInflater themedInflater = LayoutInflater.from(contextThemeWrapper);
return themedInflater.inflate(R.layout.quality_selector_dialog, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
standard = view.findViewById(R.id.quality_selector_dialog_standard);
high = view.findViewById(R.id.quality_selector_dialog_high);
View.OnClickListener listener = v -> {
select(v);
view.postDelayed(this::dismissAllowingStateLoss, 250);
};
standard.setOnClickListener(listener);
high.setOnClickListener(listener);
}
@Override
public void onActivityCreated(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
viewModel = ViewModelProviders.of(requireActivity()).get(MediaSendViewModel.class);
viewModel.getSentMediaQuality().observe(getViewLifecycleOwner(), this::updateQuality);
}
private void updateQuality(@NonNull SentMediaQuality sentMediaQuality) {
select(sentMediaQuality == SentMediaQuality.STANDARD ? standard : high);
}
private void select(@NonNull View view) {
standard.setChecked(view == standard);
high.setChecked(view == high);
viewModel.setSentMediaQuality(standard == view ? SentMediaQuality.STANDARD : SentMediaQuality.HIGH);
}
@Override
public void show(@NonNull FragmentManager manager, @Nullable String tag) {
BottomSheetUtil.show(manager, tag, this);
}
}

Wyświetl plik

@ -0,0 +1,40 @@
package org.thoughtcrime.securesms.mediasend;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import org.whispersystems.libsignal.util.guava.Optional;
/**
* Add a {@link SentMediaQuality} value for {@link AttachmentDatabase.TransformProperties#getSentMediaQuality()} on the
* transformed media. Safe to use in a pipeline with other transforms.
*/
public final class SentMediaQualityTransform implements MediaTransform {
private final SentMediaQuality sentMediaQuality;
SentMediaQualityTransform(@NonNull SentMediaQuality sentMediaQuality) {
this.sentMediaQuality = sentMediaQuality;
}
@WorkerThread
@Override
public @NonNull Media transform(@NonNull Context context, @NonNull Media media) {
return new Media(media.getUri(),
media.getMimeType(),
media.getDate(),
media.getWidth(),
media.getHeight(),
media.getSize(),
media.getDuration(),
media.isBorderless(),
media.isVideoGif(),
media.getBucketId(),
media.getCaption(),
Optional.of(AttachmentDatabase.TransformProperties.forSentMediaQuality(media.getTransformProperties(), sentMediaQuality)));
}
}

Wyświetl plik

@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import org.whispersystems.libsignal.util.guava.Optional;
public final class VideoTrimTransform implements MediaTransform {
@ -30,6 +31,6 @@ public final class VideoTrimTransform implements MediaTransform {
media.isVideoGif(),
media.getBucketId(),
media.getCaption(),
Optional.of(new AttachmentDatabase.TransformProperties(false, data.durationEdited, data.startTimeUs, data.endTimeUs)));
Optional.of(new AttachmentDatabase.TransformProperties(false, data.durationEdited, data.startTimeUs, data.endTimeUs, SentMediaQuality.STANDARD.getCode())));
}
}

Wyświetl plik

@ -28,6 +28,8 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.blurhash.BlurHash;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.AttachmentDatabase.TransformProperties;
import org.thoughtcrime.securesms.util.MediaUtil;
public class ImageSlide extends Slide {
@ -47,7 +49,11 @@ public class ImageSlide extends Slide {
}
public ImageSlide(Context context, Uri uri, String contentType, long size, int width, int height, boolean borderless, @Nullable String caption, @Nullable BlurHash blurHash) {
super(context, constructAttachmentFromUri(context, uri, contentType, size, width, height, true, null, caption, null, blurHash, null, false, borderless, false, false));
this(context, uri, contentType, size, width, height, borderless, caption, blurHash, null);
}
public ImageSlide(Context context, Uri uri, String contentType, long size, int width, int height, boolean borderless, @Nullable String caption, @Nullable BlurHash blurHash, @Nullable TransformProperties transformProperties) {
super(context, constructAttachmentFromUri(context, uri, contentType, size, width, height, true, null, caption, null, blurHash, null, false, borderless, false, false, transformProperties));
this.borderless = borderless;
}

Wyświetl plik

@ -7,6 +7,7 @@ import android.util.Pair;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.attachments.Attachment;
@ -23,7 +24,11 @@ public abstract class MediaConstraints {
private static final String TAG = Log.tag(MediaConstraints.class);
public static MediaConstraints getPushMediaConstraints() {
return new PushMediaConstraints();
return getPushMediaConstraints(null);
}
public static MediaConstraints getPushMediaConstraints(@Nullable SentMediaQuality sentMediaQuality) {
return new PushMediaConstraints(sentMediaQuality);
}
public static MediaConstraints getMmsMediaConstraints(int subscriptionId) {

Wyświetl plik

@ -14,13 +14,13 @@ import java.util.Arrays;
public class PushMediaConstraints extends MediaConstraints {
private static final int KB = 1024;
private static final int MB = 1024 * KB;
private static final int KB = 1024;
private static final int MB = 1024 * KB;
private final MediaConfig currentConfig;
public PushMediaConstraints() {
currentConfig = getCurrentConfig(ApplicationDependencies.getApplication());
public PushMediaConstraints(@Nullable SentMediaQuality sentMediaQuality) {
currentConfig = getCurrentConfig(ApplicationDependencies.getApplication(), sentMediaQuality);
}
@Override
@ -80,11 +80,14 @@ public class PushMediaConstraints extends MediaConstraints {
return currentConfig.qualitySetting;
}
private static @NonNull MediaConfig getCurrentConfig(@NonNull Context context) {
private static @NonNull MediaConfig getCurrentConfig(@NonNull Context context, @Nullable SentMediaQuality sentMediaQuality) {
if (Util.isLowMemory(context)) {
return MediaConfig.LEVEL_1_LOW_MEMORY;
}
if (sentMediaQuality == SentMediaQuality.HIGH) {
return MediaConfig.LEVEL_3;
}
return LocaleFeatureFlags.getMediaQualityLevel().orElse(MediaConfig.getDefault(context));
}
@ -93,7 +96,7 @@ public class PushMediaConstraints extends MediaConstraints {
LEVEL_1(false, 1, MB, new int[] { 1600, 1024, 768, 512 }, 70),
LEVEL_2(false, 2, (int) (1.5 * MB), new int[] { 2048, 1600, 1024, 768, 512 }, 75),
LEVEL_3(false, 3, (int) (2.5 * MB), new int[] { 3072, 2048, 1600, 1024, 768, 512 }, 80);
LEVEL_3(false, 3, (int) (3 * MB), new int[] { 4096, 3072, 2048, 1600, 1024, 768, 512 }, 75);
private final boolean isLowMemory;
private final int level;

Wyświetl plik

@ -0,0 +1,29 @@
package org.thoughtcrime.securesms.mms;
import androidx.annotation.NonNull;
/**
* Quality levels to send media at.
*/
public enum SentMediaQuality {
STANDARD(0),
HIGH(1);
private final int code;
SentMediaQuality(int code) {
this.code = code;
}
public static @NonNull SentMediaQuality fromCode(int code) {
if (HIGH.code == code) {
return HIGH;
}
return STANDARD;
}
public int getCode() {
return code;
}
}

Wyświetl plik

@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mediasend.MediaSendPageFragment;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.PushMediaConstraints;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.scribbles.widget.VerticalSlideColorPicker;
@ -135,7 +136,7 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu
throw new AssertionError("No KEY_IMAGE_URI supplied");
}
MediaConstraints mediaConstraints = new PushMediaConstraints();
MediaConstraints mediaConstraints = new PushMediaConstraints(SentMediaQuality.HIGH);
imageMaxWidth = mediaConstraints.getImageMaxWidth(requireContext());
imageMaxHeight = mediaConstraints.getImageMaxHeight(requireContext());

Wyświetl plik

@ -0,0 +1,111 @@
package org.thoughtcrime.securesms.util.views;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.Objects;
/**
* LinearLayout that supports being checkable, useful for complicated "selectedable"
* buttons that aren't really buttons.
*/
public final class CheckedLinearLayout extends LinearLayout implements Checkable {
private static final int[] CHECKED_STATE = { android.R.attr.state_checked };
private boolean checked = false;
public CheckedLinearLayout(Context context) {
super(context);
}
public CheckedLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public CheckedLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected @NonNull Parcelable onSaveInstanceState() {
return new InstanceState(Objects.requireNonNull(super.onSaveInstanceState()), checked);
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
InstanceState instanceState = (InstanceState) state;
super.onRestoreInstanceState(instanceState.getSuperState());
setChecked(instanceState.checked);
}
@Override
public void setChecked(boolean checked) {
if (this.checked != checked) {
toggle();
}
}
@Override
public boolean isChecked() {
return checked;
}
@Override
public void toggle() {
checked = !checked;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child instanceof Checkable) {
((Checkable) child).setChecked(checked);
}
}
refreshDrawableState();
}
@Override
protected int[] onCreateDrawableState(final int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE);
}
return drawableState;
}
private static class InstanceState extends BaseSavedState {
private final boolean checked;
InstanceState(@NonNull Parcelable superState, boolean checked) {
super(superState);
this.checked = checked;
}
private InstanceState(@NonNull Parcel in) {
super(in);
checked = in.readInt() > 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(checked ? 1 : 0);
}
public static final Parcelable.Creator<InstanceState> CREATOR = new Parcelable.Creator<InstanceState>() {
public InstanceState createFromParcel(Parcel in) {
return new InstanceState(in);
}
public InstanceState[] newArray(int size) {
return new InstanceState[size];
}
};
}
}

Wyświetl plik

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/signal_text_primary" android:state_checked="true" />
<item android:color="@color/transparent" />
</selector>

Wyświetl plik

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/signal_text_primary" android:state_checked="true" />
<item android:color="@color/signal_text_secondary" />
</selector>

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.3 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.9 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.9 KiB

Wyświetl plik

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/signal_inverse_transparent_40">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="#000000" />
<corners android:radius="18dp" />
</shape>
</item>
<item android:drawable="@drawable/checkable_outline" />
</ripple>

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 5.0 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 4.9 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 9.1 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 8.6 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 14 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 13 KiB

Wyświetl plik

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="18dp" />
<stroke android:color="@color/checkable_stroke_color" android:width="1dp" />
</shape>

Wyświetl plik

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/checkable_outline" android:state_checked="true" />
</selector>

Wyświetl plik

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:fillColor="#FF000000"
android:pathData="M14.9,21l3.9,-5l5,6.7H8.2l3.9,-5L14.9,21z"/>
<path
android:fillColor="#FF000000"
android:pathData="M27.5,4.5h-23v23h23V4.5zM3,3v26h26V3H3z"
android:fillType="evenOdd"/>
</vector>

Wyświetl plik

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:fillColor="#FF000000"
android:pathData="M12.1,21.9l3.2,-4.4l4.2,5.9h-13L9.8,19L12.1,21.9z"/>
<path
android:fillColor="#FF000000"
android:pathData="M27.5,4.5H3V3h26v26h-1.5V4.5z"
android:fillType="evenOdd"/>
<path
android:fillColor="#FF000000"
android:pathData="M21.5,10.5h-17v17h17V10.5zM3,9v20h20V9H3z"
android:fillType="evenOdd"/>
</vector>

Wyświetl plik

@ -0,0 +1,4 @@
<vector android:height="28dp" android:viewportHeight="28"
android:viewportWidth="28" android:width="28dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M14,1a13,13 0,1 0,9.046 22.3l-0.3,1.232L22.75,26.5h1.5L24.241,21L18.775,21v1.5h1.491l1.858,-0.378A11.587,11.587 0,1 1,24.34 19L26,19A12.994,12.994 0,0 0,14 1ZM13.178,11.565a8.783,8.783 0,0 1,0.836 0.917,5.774 5.774,0 0,1 0.809,-0.917 4.692,4.692 0,0 1,3.345 -1.484,3.71 3.71,0 0,1 0,7.419 4.785,4.785 0,0 1,-3.345 -1.457,7.813 7.813,0 0,1 -0.809,-0.944 12.411,12.411 0,0 1,-0.836 0.944A4.775,4.775 0,0 1,9.859 17.5a3.71,3.71 0,1 1,0 -7.419A4.683,4.683 0,0 1,13.178 11.565ZM9.859,15.965A3.253,3.253 0,0 0,12.1 14.91a8.024,8.024 0,0 0,0.943 -1.133,7.663 7.663,0 0,0 -0.943,-1.106 3.205,3.205 0,0 0,-2.24 -1.052,2.172 2.172,0 1,0 0,4.343ZM18.168,11.622A3.211,3.211 0,0 0,15.9 12.671a9.093,9.093 0,0 0,-0.944 1.106A7.969,7.969 0,0 0,15.9 14.91a3.258,3.258 0,0 0,2.266 1.052,2.172 2.172,0 0,0 0,-4.343Z"/>
</vector>

Wyświetl plik

@ -0,0 +1,4 @@
<vector android:height="28dp" android:viewportHeight="28"
android:viewportWidth="28" android:width="28dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M11.165,19L9.627,19L9.627,10.912L9.543,10.912a2.687,2.687 0,0 1,-2.117 0.754v-1.26a2.546,2.546 0,0 0,2.31 -1.562h1.429ZM16.785,14.348 L18.485,11.383L20.1,11.383l-2.376,3.808L20.122,19L18.5,19l-1.716,-2.847L15.074,19L13.447,19l2.37,-3.809 -2.339,-3.808L15.1,11.383ZM14,1a13,13 0,1 0,9.046 22.3l-0.3,1.232L22.75,26.5h1.5L24.241,21L18.775,21v1.5h1.491l1.858,-0.378A11.587,11.587 0,1 1,24.34 19L26,19A12.994,12.994 0,0 0,14 1Z"/>
</vector>

Wyświetl plik

@ -61,15 +61,31 @@
android:layout_marginEnd="16dp"
android:layout_marginBottom="12dp"
android:orientation="horizontal">
<ImageView
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/mediasend_reveal_toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginEnd="12dp"
android:layout_marginBottom="4dp"
android:foreground="?attr/selectableItemBackground"
android:padding="2dp"
app:tint="@color/core_white"
tools:ignore="UnusedAttribute"
tools:src="@drawable/ic_view_once_28" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/mediasend_quality_toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
tools:src="@drawable/ic_view_infinite_32" />
android:layout_marginEnd="12dp"
android:layout_marginBottom="4dp"
android:foreground="?attr/selectableItemBackground"
app:srcCompat="@drawable/ic_quality_standard_32"
app:tint="@color/core_white"
tools:ignore="UnusedAttribute" />
<LinearLayout
android:id="@+id/mediasend_compose_container"
@ -194,7 +210,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:layout="@layout/conversation_mention_suggestions_stub"/>
android:layout="@layout/conversation_mention_suggestions_stub" />
</FrameLayout>

Wyświetl plik

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="?attr/dialogPreferredPadding">
<org.thoughtcrime.securesms.util.views.CheckedLinearLayout
android:id="@+id/quality_selector_dialog_standard"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:background="@drawable/checkable_outline_background"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="8dp"
app:layout_constraintEnd_toStartOf="@+id/quality_selector_dialog_high"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CheckedTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/QualitySelectorBottomSheetDialog__standard"
android:textAppearance="@style/TextAppearance.Signal.Body2.Bold"
android:textColor="@color/quality_selector_button_text" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/QualitySelectorBottomSheetDialog__faster_less_data"
android:textAppearance="@style/TextAppearance.Signal.Subtitle"
android:textColor="@color/signal_text_secondary" />
</org.thoughtcrime.securesms.util.views.CheckedLinearLayout>
<org.thoughtcrime.securesms.util.views.CheckedLinearLayout
android:id="@+id/quality_selector_dialog_high"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:background="@drawable/checkable_outline_background"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/quality_selector_dialog_standard"
app:layout_constraintTop_toTopOf="parent">
<CheckedTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/QualitySelectorBottomSheetDialog__high"
android:textAppearance="@style/TextAppearance.Signal.Body2.Bold"
android:textColor="@color/quality_selector_button_text" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/QualitySelectorBottomSheetDialog__slower_more_data"
android:textAppearance="@style/TextAppearance.Signal.Subtitle"
android:textColor="@color/signal_text_secondary" />
</org.thoughtcrime.securesms.util.views.CheckedLinearLayout>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/QualitySelectorBottomSheetDialog__photo_quality"
android:textAppearance="@style/TextAppearance.Signal.Body2"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/quality_selector_dialog_standard" />
</androidx.constraintlayout.widget.ConstraintLayout>

Wyświetl plik

@ -3375,6 +3375,13 @@
<!-- GroupDescriptionDialog -->
<string name="GroupDescriptionDialog__group_description">Group description</string>
<!-- QualitySelectorBottomSheetDialog -->
<string name="QualitySelectorBottomSheetDialog__standard">Standard</string>
<string name="QualitySelectorBottomSheetDialog__faster_less_data">Faster, less data</string>
<string name="QualitySelectorBottomSheetDialog__high">High</string>
<string name="QualitySelectorBottomSheetDialog__slower_more_data">Slower, more data</string>
<string name="QualitySelectorBottomSheetDialog__photo_quality">Photo quality</string>
<!-- EOF -->
</resources>

Wyświetl plik

@ -151,6 +151,10 @@
<item name="android:textSize">13sp</item>
</style>
<style name="TextAppearance.Signal.Subtitle.Bold">
<item name="android:textStyle">bold</item>
</style>
<style name="TextAppearance.Signal.Subtitle2" parent="@style/TextAppearance.MaterialComponents.Subtitle2">
</style>

Wyświetl plik

@ -0,0 +1,28 @@
package org.thoughtcrime.securesms.database;
import org.junit.Test;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import static org.junit.Assert.assertEquals;
public class AttachmentDatabaseTransformPropertiesTest {
@Test
public void transformProperties_verifyStructure() {
AttachmentDatabase.TransformProperties properties = AttachmentDatabase.TransformProperties.empty();
assertEquals("Added transform property, need to confirm default behavior for pre-existing payloads in database",
"{\"skipTransform\":false,\"videoTrim\":false,\"videoTrimStartTimeUs\":0,\"videoTrimEndTimeUs\":0,\"sentMediaQuality\":0,\"videoEdited\":false}",
properties.serialize());
}
@Test
public void transformProperties_verifyMissingSentMediaQualityDefaultBehavior() {
String json = "{\"skipTransform\":false,\"videoTrim\":false,\"videoTrimStartTimeUs\":0,\"videoTrimEndTimeUs\":0,\"videoEdited\":false}";
AttachmentDatabase.TransformProperties properties = AttachmentDatabase.TransformProperties.parse(json);
assertEquals(0, properties.getSentMediaQuality());
assertEquals(SentMediaQuality.STANDARD, SentMediaQuality.fromCode(properties.getSentMediaQuality()));
}
}