From dd934e0095197b30d760a4a12441381606f0d39f Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Fri, 7 May 2021 14:03:53 -0400 Subject: [PATCH] Add photo media quality selector when sending images. --- .../components/emoji/EmojiEditText.java | 4 +- .../components/emoji/EmojiTextView.java | 2 +- .../conversation/ConversationActivity.java | 3 +- .../database/AttachmentDatabase.java | 23 +++- .../jobs/AttachmentCompressionJob.java | 3 +- .../mediasend/CompositeMediaTransform.java | 28 +++++ .../mediasend/MediaSendActivity.java | 31 +++-- .../mediasend/MediaSendFragment.java | 2 +- .../mediasend/MediaSendViewModel.java | 52 +++++--- .../mediasend/MediaUploadRepository.java | 25 +++- .../QualitySelectorBottomSheetDialog.java | 87 ++++++++++++++ .../mediasend/SentMediaQualityTransform.java | 40 +++++++ .../mediasend/VideoTrimTransform.java | 3 +- .../securesms/mms/ImageSlide.java | 8 +- .../securesms/mms/MediaConstraints.java | 7 +- .../securesms/mms/PushMediaConstraints.java | 15 ++- .../securesms/mms/SentMediaQuality.java | 29 +++++ .../scribbles/ImageEditorFragment.java | 3 +- .../util/views/CheckedLinearLayout.java | 111 ++++++++++++++++++ .../main/res/color/checkable_stroke_color.xml | 5 + .../color/quality_selector_button_text.xml | 5 + .../res/drawable-hdpi/ic_view_infinite_32.png | Bin 3443 -> 0 bytes .../res/drawable-hdpi/ic_view_once_32.png | Bin 3407 -> 0 bytes .../res/drawable-mdpi/ic_view_infinite_32.png | Bin 1944 -> 0 bytes .../res/drawable-mdpi/ic_view_once_32.png | Bin 1926 -> 0 bytes .../checkable_outline_background.xml | 11 ++ .../drawable-xhdpi/ic_view_infinite_32.png | Bin 5156 -> 0 bytes .../res/drawable-xhdpi/ic_view_once_32.png | Bin 5042 -> 0 bytes .../drawable-xxhdpi/ic_view_infinite_32.png | Bin 9369 -> 0 bytes .../res/drawable-xxhdpi/ic_view_once_32.png | Bin 8850 -> 0 bytes .../drawable-xxxhdpi/ic_view_infinite_32.png | Bin 13850 -> 0 bytes .../res/drawable-xxxhdpi/ic_view_once_32.png | Bin 13141 -> 0 bytes .../main/res/drawable/checkable_outline.xml | 5 + .../drawable/checkable_outline_background.xml | 4 + .../main/res/drawable/ic_quality_high_32.xml | 13 ++ .../res/drawable/ic_quality_standard_32.xml | 17 +++ .../main/res/drawable/ic_view_infinite_28.xml | 4 + app/src/main/res/drawable/ic_view_once_28.xml | 4 + .../main/res/layout/mediasend_activity.xml | 24 +++- .../res/layout/quality_selector_dialog.xml | 78 ++++++++++++ app/src/main/res/values/strings.xml | 7 ++ app/src/main/res/values/text_styles.xml | 4 + ...chmentDatabaseTransformPropertiesTest.java | 28 +++++ 43 files changed, 630 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/mediasend/CompositeMediaTransform.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/mediasend/QualitySelectorBottomSheetDialog.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/mediasend/SentMediaQualityTransform.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/mms/SentMediaQuality.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/util/views/CheckedLinearLayout.java create mode 100644 app/src/main/res/color/checkable_stroke_color.xml create mode 100644 app/src/main/res/color/quality_selector_button_text.xml delete mode 100644 app/src/main/res/drawable-hdpi/ic_view_infinite_32.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_view_once_32.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_view_infinite_32.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_view_once_32.png create mode 100644 app/src/main/res/drawable-v21/checkable_outline_background.xml delete mode 100644 app/src/main/res/drawable-xhdpi/ic_view_infinite_32.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_view_once_32.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_view_infinite_32.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_view_once_32.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_view_infinite_32.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_view_once_32.png create mode 100644 app/src/main/res/drawable/checkable_outline.xml create mode 100644 app/src/main/res/drawable/checkable_outline_background.xml create mode 100644 app/src/main/res/drawable/ic_quality_high_32.xml create mode 100644 app/src/main/res/drawable/ic_quality_standard_32.xml create mode 100644 app/src/main/res/drawable/ic_view_infinite_28.xml create mode 100644 app/src/main/res/drawable/ic_view_once_28.xml create mode 100644 app/src/main/res/layout/quality_selector_dialog.xml create mode 100644 app/src/test/java/org/thoughtcrime/securesms/database/AttachmentDatabaseTransformPropertiesTest.java diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java index 1339e69705..dd7d52d7ce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiEditText.java @@ -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())); + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java index dad58459cf..5bcd296b8d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java @@ -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(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 8226e3364f..e9adcf81db 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -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."); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java index 15550b1efc..5ccb911c9e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java @@ -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 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); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java index 1e11f22ed1..eda39f61f6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java @@ -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); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CompositeMediaTransform.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CompositeMediaTransform.java new file mode 100644 index 0000000000..4b509a8923 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CompositeMediaTransform.java @@ -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; + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java index 0fcd422d8f..2c3a0d917a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java @@ -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 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 buildModelsToTransform(@NonNull MediaSendFragment fragment) { - List mediaList = fragment.getAllMedia(); - Map savedState = fragment.getSavedState(); + private static Map buildModelsToTransform(@NonNull MediaSendFragment fragment, @Nullable SentMediaQuality sentMediaQuality) { + List mediaList = fragment.getAllMedia(); + Map savedState = fragment.getSavedState(); Map 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); }); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java index cfb1b9f45a..98403d9580 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java @@ -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(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java index 96065b30c4..542aadadd5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java @@ -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; private final SingleLiveEvent error; private final SingleLiveEvent event; + private final MutableLiveData sentMediaQuality; private final Map 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 onSendClicked(Map modelsToTransform, @NonNull List recipients, @NonNull List 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 getSentMediaQuality() { + return sentMediaQuality; + } + @NonNull MediaConstraints getMediaConstraints() { return mediaConstraints; } @@ -583,10 +599,10 @@ class MediaSendViewModel extends ViewModel { } private HudState buildHudState() { - List 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 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() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaUploadRepository.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaUploadRepository.java index 808d581e03..baafe68a6a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaUploadRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaUploadRepository.java @@ -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 oldToNew, @Nullable Recipient recipient) { executor.execute(() -> { for (Map.Entry 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 { diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/QualitySelectorBottomSheetDialog.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/QualitySelectorBottomSheetDialog.java new file mode 100644 index 0000000000..30d09cd5f7 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/QualitySelectorBottomSheetDialog.java @@ -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); + } + +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/SentMediaQualityTransform.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/SentMediaQualityTransform.java new file mode 100644 index 0000000000..5009af3df7 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/SentMediaQualityTransform.java @@ -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))); + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/VideoTrimTransform.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/VideoTrimTransform.java index f2711f588d..5f1061a7cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/VideoTrimTransform.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/VideoTrimTransform.java @@ -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()))); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/ImageSlide.java b/app/src/main/java/org/thoughtcrime/securesms/mms/ImageSlide.java index c3f88b3f92..acd408ab06 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/ImageSlide.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/ImageSlide.java @@ -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; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/MediaConstraints.java b/app/src/main/java/org/thoughtcrime/securesms/mms/MediaConstraints.java index bd5b3dffd1..088058151e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/MediaConstraints.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/MediaConstraints.java @@ -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) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/PushMediaConstraints.java b/app/src/main/java/org/thoughtcrime/securesms/mms/PushMediaConstraints.java index 592bebc56e..b1cb5d5f74 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/PushMediaConstraints.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/PushMediaConstraints.java @@ -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; diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/SentMediaQuality.java b/app/src/main/java/org/thoughtcrime/securesms/mms/SentMediaQuality.java new file mode 100644 index 0000000000..f205ff4f54 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/SentMediaQuality.java @@ -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; + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java b/app/src/main/java/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java index 27355c3d0d..1959096267 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java @@ -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()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/views/CheckedLinearLayout.java b/app/src/main/java/org/thoughtcrime/securesms/util/views/CheckedLinearLayout.java new file mode 100644 index 0000000000..d76b398545 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/util/views/CheckedLinearLayout.java @@ -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 CREATOR = new Parcelable.Creator() { + public InstanceState createFromParcel(Parcel in) { + return new InstanceState(in); + } + + public InstanceState[] newArray(int size) { + return new InstanceState[size]; + } + }; + } +} diff --git a/app/src/main/res/color/checkable_stroke_color.xml b/app/src/main/res/color/checkable_stroke_color.xml new file mode 100644 index 0000000000..8d6362ee2b --- /dev/null +++ b/app/src/main/res/color/checkable_stroke_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/quality_selector_button_text.xml b/app/src/main/res/color/quality_selector_button_text.xml new file mode 100644 index 0000000000..9c24d635f3 --- /dev/null +++ b/app/src/main/res/color/quality_selector_button_text.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_view_infinite_32.png b/app/src/main/res/drawable-hdpi/ic_view_infinite_32.png deleted file mode 100644 index 983bee58d4fe6601ccbb0e70ec5b3f0bb8e7f4e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3443 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 VgH!Z;s22bL002ovPDHLkV1j14uYCXj diff --git a/app/src/main/res/drawable-hdpi/ic_view_once_32.png b/app/src/main/res/drawable-hdpi/ic_view_once_32.png deleted file mode 100644 index 16ddff5f92ac628f97f5d21ec2b802b14e5d25bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3407 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 M07*qoM6N<$f~2gy>i_@% diff --git a/app/src/main/res/drawable-v21/checkable_outline_background.xml b/app/src/main/res/drawable-v21/checkable_outline_background.xml new file mode 100644 index 0000000000..6593d5db90 --- /dev/null +++ b/app/src/main/res/drawable-v21/checkable_outline_background.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/ic_view_infinite_32.png b/app/src/main/res/drawable-xhdpi/ic_view_infinite_32.png deleted file mode 100644 index 4db9a007cb779edaaaef372bcad8b23e459f1a7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5156 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 IM6N<$f>FVoC;$Ke diff --git a/app/src/main/res/drawable-xxhdpi/ic_view_infinite_32.png b/app/src/main/res/drawable-xxhdpi/ic_view_infinite_32.png deleted file mode 100644 index 812c7a79d9750bee3bafa2a704191e75a893a25c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9369 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 Td1sbw00000NkvXXu0mjf$Cnw> diff --git a/app/src/main/res/drawable-xxhdpi/ic_view_once_32.png b/app/src/main/res/drawable-xxhdpi/ic_view_once_32.png deleted file mode 100644 index e77b837b8935836d92cb4370ec7cc86672fad311..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8850 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 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_view_infinite_32.png b/app/src/main/res/drawable-xxxhdpi/ic_view_infinite_32.png deleted file mode 100644 index f7ebc26695b0b23e9cf305fe1d4be8a7265f344c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13850 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 + + + + diff --git a/app/src/main/res/drawable/checkable_outline_background.xml b/app/src/main/res/drawable/checkable_outline_background.xml new file mode 100644 index 0000000000..2a7c3b7f9e --- /dev/null +++ b/app/src/main/res/drawable/checkable_outline_background.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_quality_high_32.xml b/app/src/main/res/drawable/ic_quality_high_32.xml new file mode 100644 index 0000000000..d36d3c1dd1 --- /dev/null +++ b/app/src/main/res/drawable/ic_quality_high_32.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_quality_standard_32.xml b/app/src/main/res/drawable/ic_quality_standard_32.xml new file mode 100644 index 0000000000..e1d2bc1080 --- /dev/null +++ b/app/src/main/res/drawable/ic_quality_standard_32.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_view_infinite_28.xml b/app/src/main/res/drawable/ic_view_infinite_28.xml new file mode 100644 index 0000000000..3eff20db72 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_infinite_28.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_once_28.xml b/app/src/main/res/drawable/ic_view_once_28.xml new file mode 100644 index 0000000000..af6b1276f7 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_once_28.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/layout/mediasend_activity.xml b/app/src/main/res/layout/mediasend_activity.xml index 1bed34e4d6..13897fb090 100644 --- a/app/src/main/res/layout/mediasend_activity.xml +++ b/app/src/main/res/layout/mediasend_activity.xml @@ -61,15 +61,31 @@ android:layout_marginEnd="16dp" android:layout_marginBottom="12dp" android:orientation="horizontal"> - - + + + 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" /> + android:layout="@layout/conversation_mention_suggestions_stub" /> diff --git a/app/src/main/res/layout/quality_selector_dialog.xml b/app/src/main/res/layout/quality_selector_dialog.xml new file mode 100644 index 0000000000..e538a5164b --- /dev/null +++ b/app/src/main/res/layout/quality_selector_dialog.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 975adbd3a1..b580051b37 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3375,6 +3375,13 @@ Group description + + Standard + Faster, less data + High + Slower, more data + Photo quality + diff --git a/app/src/main/res/values/text_styles.xml b/app/src/main/res/values/text_styles.xml index b2da32d425..be7b716f21 100644 --- a/app/src/main/res/values/text_styles.xml +++ b/app/src/main/res/values/text_styles.xml @@ -151,6 +151,10 @@ 13sp + + diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/AttachmentDatabaseTransformPropertiesTest.java b/app/src/test/java/org/thoughtcrime/securesms/database/AttachmentDatabaseTransformPropertiesTest.java new file mode 100644 index 0000000000..8907c217ae --- /dev/null +++ b/app/src/test/java/org/thoughtcrime/securesms/database/AttachmentDatabaseTransformPropertiesTest.java @@ -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())); + } + +} \ No newline at end of file